Skip to content

Commit 8bc29f6

Browse files
authored
Merge pull request #479 from itpp-labs/16.0-sync-improvements2
commit is created by 👷‍♂️ Merge Bot: https://odoo-devops.readthedocs.io/en/latest/git/github-merge-bot.html
2 parents 193bc76 + dca7d59 commit 8bc29f6

20 files changed

+489
-152
lines changed

partner_telegram/models/res_partner.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ def _compute_telegram(self):
2929
def _inverse_telegram(self):
3030
for record in self:
3131
value = record.telegram
32-
if value.startswith("@"):
33-
value = value[1:]
34-
elif value.startswith("+"):
35-
value = value.replace("-", "").replace(" ", "")
32+
if not value:
33+
record.telegram_username = False
34+
record.telegram_mobile = False
35+
elif value.startswith("@"):
36+
record.telegram_username = value[1:]
3637
elif value.startswith("https://t.me/"):
37-
value = value[len("https://t.me/") :]
38-
record.telegram_mobile = value
38+
record.telegram_username = value[len("https://t.me/") :]
39+
elif value.startswith("+"):
40+
record.telegram_mobile = value.replace("-", "").replace(" ", "")

partner_telegram/tests/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# License MIT (https://opensource.org/licenses/MIT).
2+
from . import test_telegram
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright 2024 Ivan Yelizariev <https://twitter.com/yelizariev>
2+
# License MIT (https://opensource.org/licenses/MIT).
3+
from odoo.tests.common import TransactionCase
4+
5+
6+
class TestResPartnerTelegram(TransactionCase):
7+
def setUp(self):
8+
super(TestResPartnerTelegram, self).setUp()
9+
self.ResPartner = self.env["res.partner"]
10+
# Create a partner without telegram information
11+
self.partner = self.ResPartner.create({"name": "Test"})
12+
13+
def test_telegram_set_username(self):
14+
# Set the telegram field with a username
15+
self.partner.telegram = "@testuser"
16+
17+
# Check the computed fields
18+
self.assertEqual(self.partner.telegram_username, "testuser")
19+
self.assertEqual(self.partner.telegram_url, "https://t.me/testuser")
20+
self.assertEqual(self.partner.telegram, "testuser")
21+
22+
def test_telegram_set_mobile(self):
23+
# Set the telegram field with a mobile number
24+
self.partner.telegram = "+1234567890"
25+
26+
# Check the computed fields
27+
self.assertEqual(self.partner.telegram_mobile, "+1234567890")
28+
self.assertEqual(self.partner.telegram_url, "https://t.me/+1234567890")
29+
self.assertEqual(self.partner.telegram, "+1234567890")
30+
31+
def test_telegram_set_url(self):
32+
# Set the telegram field with a URL
33+
self.partner.telegram = "https://t.me/testuser"
34+
35+
# Check the computed fields
36+
self.assertEqual(self.partner.telegram_username, "testuser")
37+
self.assertEqual(self.partner.telegram_url, "https://t.me/testuser")
38+
self.assertEqual(self.partner.telegram, "testuser")
39+
40+
def test_telegram_clear(self):
41+
# Set the telegram field and then clear it
42+
self.partner.telegram = "@testuser"
43+
self.partner.telegram = ""
44+
45+
# Check the computed fields
46+
self.assertFalse(self.partner.telegram_username)
47+
self.assertFalse(self.partner.telegram_mobile)
48+
self.assertFalse(self.partner.telegram_url)
49+
self.assertFalse(self.partner.telegram)

sync/README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.. image:: https://itpp.dev/images/infinity-readme.png
22
:alt: Tested and maintained by IT Projects Labs
3-
:target: https://itpp.dev
3+
:target: https://odoomagic.com
44

55
.. image:: https://img.shields.io/badge/license-MIT-blue.svg
66
:target: https://opensource.org/licenses/MIT

sync/__manifest__.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77
"name": "Sync 🪬 Studio",
88
"summary": """Join the Amazing 😍 Community ⤵️""",
99
"category": "VooDoo ✨ Magic",
10-
"version": "16.0.11.0.1",
10+
"version": "16.0.13.0.0",
1111
"application": True,
1212
"author": "Ivan Kropotkin",
1313
"support": "[email protected]",
1414
"website": "https://sync_studio.t.me/",
1515
"license": "Other OSI approved licence", # MIT
16-
"depends": ["base_automation", "mail", "queue_job"],
16+
# The `partner_telegram` dependency is not directly needed,
17+
# but it plays an important role in the **Sync 🪬 Studio** ecosystem
18+
# and is added for the quick onboarding of new **Cyber ✨ Pirates**.
19+
"depends": ["base_automation", "mail", "queue_job", "partner_telegram"],
1720
"external_dependencies": {"python": ["markdown", "pyyaml"], "bin": []},
1821
"data": [
1922
"security/sync_groups.xml",
@@ -25,6 +28,7 @@
2528
"views/sync_trigger_automation_views.xml",
2629
"views/sync_trigger_webhook_views.xml",
2730
"views/sync_trigger_button_views.xml",
31+
"views/sync_order_views.xml",
2832
"views/sync_task_views.xml",
2933
"views/sync_link_views.xml",
3034
"views/sync_project_views.xml",
@@ -37,12 +41,6 @@
3741
},
3842
"demo": [
3943
"data/sync_project_unittest_demo.xml",
40-
# Obsolete
41-
# "data/sync_project_context_demo.xml",
42-
# "data/sync_project_telegram_demo.xml",
43-
# "data/sync_project_odoo2odoo_demo.xml",
44-
# "data/sync_project_trello_github_demo.xml",
45-
# "data/sync_project_context_demo.xml",
4644
],
4745
"qweb": [],
4846
"post_load": None,

sync/doc/MAGIC.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ Libs
6969
* ``MAGIC.timezone``
7070
* ``MAGIC.b64encode``
7171
* ``MAGIC.b64decode``
72+
* ``MAGIC.sha256``
7273

7374
Tools
7475
=====
@@ -80,6 +81,8 @@ Tools
8081
* ``MAGIC.type2str``: get type of the given object
8182
* ``MAGIC.DEFAULT_SERVER_DATETIME_FORMAT``
8283
* ``MAGIC.AttrDict``: Extended dictionary that allows for attribute-style access
84+
* ``MAGIC.group_by_lang(partners, default_lang="en_US")``: yields `lang, partners` grouped by lang
85+
* ``MAGIC.gen2csv(generator)``: prepares csv as a string
8386

8487
Exceptions
8588
==========

sync/doc/changelog.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
`13.0.0`
2+
-------
3+
4+
- **Fix:** Use `__sync.` for xmlid namespace to avoid data loss on module update.
5+
- **Fix:** Use task ID in xmlid namespace for the task triggers.
6+
- **Fix:** Keep job records (and their logs) on task deletion.
7+
- **New:** Add *Sync Order* — advanced manual trigger with blackjack, partners list, text input, etc.
8+
- **New:** Support `data.markdown` for custom documentation in the `DATA.🐫` tab.
9+
- **New:** Add `MAGIC.group_by_lang` to eval context.
10+
- **New:** Add dynamic Setting update via `PARAMS._update_param`.
11+
- **New:** Add computed field `text` to the model `sync.data`. Usage example in dynamic code: `DATA.restaurant.text`.
12+
- **Improvement:** Add `DATA.*` to the library eval context.
13+
- **Improvement:** Update API for attaching dynamic values: `_set_sync_value`, `_get_sync_value`. No need to use `ir.property`.
14+
115
`11.0.1`
216
-------
317

sync/models/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
from . import sync_task
1212
from . import sync_job
1313
from . import sync_data
14+
from . import sync_order
1415
from . import ir_logging
1516
from . import ir_actions
1617
from . import ir_attachment
17-
from . import ir_fields
1818
from . import sync_link
1919
from . import base

sync/models/base.py

Lines changed: 26 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def search_links(self, relation_name, refs=None):
1919
._search_links_odoo(self, relation_name, refs)
2020
)
2121

22-
def _create_or_update_by_xmlid(self, vals, code, namespace="XXX", module="sync"):
22+
def _create_or_update_by_xmlid(self, vals, code, namespace="XXX", module="__sync"):
2323
"""
2424
Create or update a record by a dynamically generated XML ID.
2525
Warning! The field `noupdate` is ignored, i.e. existing records are always updated.
@@ -66,34 +66,35 @@ def _create_or_update_by_xmlid(self, vals, code, namespace="XXX", module="sync")
6666
"noupdate": False,
6767
}
6868
)
69-
7069
return record
7170

72-
def _set_sync_property(self, property_name, property_type, property_value):
73-
"""
74-
Set or create a property for the current record. If the property field
75-
does not exist, create it dynamically.
76-
77-
Args:
78-
property_name (str): Name of the property field to set.
79-
property_value (Any): The value to assign to the property.
80-
property_type (str): Type of the property field.
81-
"""
82-
Property = self.env["ir.property"]
71+
def _sync_field_name(self, property_name, property_type):
8372
sync_project_id = self.env.context.get("sync_project_id")
8473

8574
if not sync_project_id:
8675
raise exceptions.UserError(
8776
_("The 'sync_project_id' must be provided in the context.")
8877
)
8978

90-
field_name = "x_sync_%s_%s_%s" % (sync_project_id, property_name, property_type)
79+
return "x_sync_%s_%s_%s" % (sync_project_id, property_name, property_type)
80+
81+
def _set_sync_value(self, property_name, property_type, property_value):
82+
"""
83+
Set or create a property for the current record. If the field
84+
does not exist, create it dynamically.
85+
86+
Args:
87+
property_name (str): Name of the property field to set.
88+
property_type (str): Type of the property field.
89+
property_value (Any): The value to assign to the property.
90+
"""
91+
self.ensure_one()
92+
field_name = self._sync_field_name(property_name, property_type)
9193
field = self.env["ir.model.fields"].search(
9294
[
9395
("name", "=", field_name),
9496
("model", "=", self._name),
9597
("ttype", "=", property_type),
96-
("sync_project_id", "=", sync_project_id),
9798
],
9899
limit=1,
99100
)
@@ -104,73 +105,23 @@ def _set_sync_property(self, property_name, property_type, property_value):
104105
{
105106
"name": field_name,
106107
"ttype": property_type,
107-
"model_id": self.env["ir.model"]
108-
.search([("model", "=", self._name)], limit=1)
109-
.id,
108+
"model_id": self.env["ir.model"]._get_id(self._name),
110109
"field_description": property_name.capitalize().replace("_", " "),
111-
"sync_project_id": sync_project_id, # Link to the sync project
112110
}
113111
)
112+
self[field_name] = property_value
114113

115-
res_id = f"{self._name},{self.id}"
116-
prop = Property.search(
117-
[
118-
("name", "=", property_name),
119-
("res_id", "=", res_id),
120-
("fields_id", "=", field.id),
121-
],
122-
limit=1,
123-
)
124-
125-
vals = {"type": property_type, "value": property_value}
126-
if prop:
127-
prop.write(vals)
128-
else:
129-
vals.update(
130-
{
131-
"name": property_name,
132-
"fields_id": field.id,
133-
"res_id": res_id,
134-
}
135-
)
136-
Property.create(vals)
137-
138-
def _get_sync_property(self, property_name, property_type):
114+
def _get_sync_value(self, property_name, property_type):
139115
"""
140-
Get the value of a property for the current record.
116+
Get the value of a dynamic field for the current record.
141117
142118
Args:
143119
property_name (str): Name of the property field to get.
120+
property_type (str): Type of the property field.
144121
"""
145-
Property = self.env["ir.property"]
146-
sync_project_id = self.env.context.get("sync_project_id")
147-
148-
if not sync_project_id:
149-
raise exceptions.UserError(
150-
_("The 'sync_project_id' must be provided in the context.")
151-
)
152-
153-
field_name = "x_sync_%s_%s_%s" % (sync_project_id, property_name, property_type)
154-
field = self.env["ir.model.fields"].search(
155-
[
156-
("name", "=", field_name),
157-
("model", "=", self._name),
158-
("sync_project_id", "=", sync_project_id),
159-
],
160-
limit=1,
161-
)
162-
163-
if not field:
122+
self.ensure_one()
123+
field_name = self._sync_field_name(property_name, property_type)
124+
try:
125+
return self[field_name]
126+
except KeyError:
164127
return None
165-
166-
res_id = f"{self._name},{self.id}"
167-
prop = Property.search(
168-
[
169-
("name", "=", property_name),
170-
("res_id", "=", res_id),
171-
("fields_id", "=", field.id),
172-
],
173-
limit=1,
174-
)
175-
176-
return prop.get_by_record() if prop else None

sync/models/ir_fields.py

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)