Skip to content
Open
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ select = C,E,F,W,B,B9
ignore = E203,E501,W503,B950,C901
per-file-ignores=
__init__.py:F401
**/__manifest__.py:B018
88 changes: 88 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
/.venv
/.pytest_cache
/.ruff_cache

# C extensions
*.so

# Distribution / packaging
.Python
env/
bin/
build/
develop-eggs/
dist/
eggs/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
*.eggs

# Windows installers
*.msi

# Debian packages
*.deb

# Redhat packages
*.rpm

# MacOS packages
*.dmg
*.pkg

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml

# Translations
*.mo

# Pycharm
.idea

# Eclipse
.settings

# Visual Studio cache/options directory
.vs/
.vscode

# OSX Files
.DS_Store

# Django stuff:
*.log

# Mr Developer
.mr.developer.cfg
.project
.pydevproject

# Rope
.ropeproject

# Sphinx documentation
docs/_build/

# Backup files
*~
*.swp

# OCA rules
!static/lib/
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ repos:
- id: mixed-line-ending
args: ["--fix=lf"]
- repo: https://github.com/OCA/pylint-odoo
rev: 7.0.2
rev: v9.1.3
hooks:
- id: pylint_odoo
name: pylint with optional checks
Expand All @@ -89,11 +89,11 @@ repos:
# - --header
# - "# generated from manifests external_dependencies"
- repo: https://github.com/pycqa/flake8
rev: 3.9.2
rev: 7.0.0
hooks:
- id: flake8
name: flake8
additional_dependencies: ["flake8-bugbear==21.9.2"]
additional_dependencies: ["flake8-bugbear==24.2.6"]
- repo: https://github.com/PyCQA/isort
rev: 5.12.0
hooks:
Expand Down
4 changes: 2 additions & 2 deletions partner_telegram/__manifest__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Copyright 2024 Ivan Yelizariev <https://twitter.com/yelizariev>
# Copyright 2026 Ivan Yelizariev <https://twitter.com/yelizariev>
# License MIT (https://opensource.org/licenses/MIT).

{
"name": "Telegram Contact Field",
"summary": """Join the Amazing 😍 Community ⤵️""",
"category": "VooDoo ✨ Magic",
"version": "17.0.1.0.0",
"version": "18.0.1.0.0",
"author": "Ivan Kropotkin",
"support": "info@odoomagic.com",
"website": "https://sync_studio.t.me/",
Expand Down
4 changes: 2 additions & 2 deletions sync/__manifest__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2020-2021,2024-2025 Ivan Yelizariev <https://twitter.com/yelizariev>
# Copyright 2020-2021,2024-2026 Ivan Yelizariev <https://twitter.com/yelizariev>
# Copyright 2020-2021 Denis Mudarisov <https://github.com/trojikman>
# Copyright 2021 Ilya Ilchenko <https://github.com/mentalko>
# License MIT (https://opensource.org/licenses/MIT).
Expand All @@ -7,7 +7,7 @@
"name": "Sync 🪬 Studio",
"summary": """Join the Amazing 😍 Community ⤵️""",
"category": "VooDoo ✨ Magic",
"version": "17.0.14.0.0",
"version": "18.0.1.0.0",
"application": True,
"author": "Ivan Yelizariev",
"support": "info@odoomagic.com",
Expand Down
30 changes: 25 additions & 5 deletions sync/lib/tools/safe_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
from psycopg2 import OperationalError

import odoo
from odoo.tools.misc import ustr

unsafe_eval = eval

__all__ = ["test_expr", "safe_eval", "const_eval"]
Expand Down Expand Up @@ -71,7 +69,7 @@ def _import(name, globals=None, locals=None, fromlist=None, level=-1):
# Generators
"gi_code",
"gi_frame",
"g_yieldfrom"
"gi_yieldfrom",
# Coroutines
"cr_await",
"cr_code",
Expand Down Expand Up @@ -134,6 +132,10 @@ def to_opcodes(opnames, _opmap=opmap):
"SWAP",
# Added in 3.11 https://docs.python.org/3/whatsnew/3.11.html#new-opcodes
"RESUME",
# 3.12 https://docs.python.org/3/whatsnew/3.12.html#cpython-bytecode-changes
"RETURN_CONST",
# 3.13
"TO_BOOL",
]
)
)
Expand Down Expand Up @@ -182,6 +184,7 @@ def to_opcodes(opnames, _opmap=opmap):
"GEN_START", # added in 3.10 but already removed from 3.11.
# Added in 3.11, replacing all BINARY_* and INPLACE_*
"BINARY_OP",
"BINARY_SLICE",
]
)
)
Expand Down Expand Up @@ -266,6 +269,23 @@ def to_opcodes(opnames, _opmap=opmap):
"NOP",
"FORMAT_VALUE",
"BUILD_STRING",
# 3.12 https://docs.python.org/3/whatsnew/3.12.html#cpython-bytecode-changes
"END_FOR",
"LOAD_FAST_AND_CLEAR",
"LOAD_FAST_CHECK",
"POP_JUMP_IF_NOT_NONE",
"POP_JUMP_IF_NONE",
"CALL_INTRINSIC_1",
"STORE_SLICE",
# 3.13
"CALL_KW",
"LOAD_FAST_LOAD_FAST",
"STORE_FAST_STORE_FAST",
"STORE_FAST_LOAD_FAST",
"CONVERT_VALUE",
"FORMAT_SIMPLE",
"FORMAT_WITH_SPEC",
"SET_FUNCTION_ATTRIBUTE",
]
)
)
Expand Down Expand Up @@ -522,7 +542,7 @@ def safe_eval__MAGIC(
raise
except Exception as e:
raise ValueError(
'%s: "%s" while evaluating\n%r' % (ustr(type(e)), ustr(e), expr)
'%s: "%s" while evaluating\n%r' % (ustr(type(e))(e), expr)
)


Expand All @@ -545,7 +565,7 @@ def test_python_expr__MAGIC(expr, mode="eval"):
error["error_line"],
)
else:
msg = ustr(err)
msg = err
return msg
return False

Expand Down
2 changes: 1 addition & 1 deletion sync/models/sync_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ def magic_upgrade(self):
task_vals, task_technical_name, namespace=self.id
)

def create_trigger(model, data):
def create_trigger(model, data, task=task):
vals = dict(
{key: value for key, value in data.items() if value is not None},
sync_task_id=task.id,
Expand Down
2 changes: 1 addition & 1 deletion sync/models/sync_project_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def _trello(secrets):
if not getattr(secrets, key):
raise Exception("{} is not set".format(key))

# https://github.com/sarumont/py-trello/tree/master/trello
# https://github.com/sarumont/py-trello/list/master/trello
from trello import TrelloClient
from trello.exceptions import ResourceUnavailable

Expand Down
32 changes: 32 additions & 0 deletions sync/models/sync_trigger_automation.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,38 @@
_logger = logging.getLogger(__name__)


class BaseAutomationTriggerFix(models.Model):
"""Override _compute_trigger to preserve existing values.

Odoo 18's base.automation._compute_trigger depends on model_id and
unconditionally resets trigger to False. This breaks programmatic
creation/update where model_id and trigger are set together, because
the ORM recomputation overrides the explicit value at flush time.

The ORM invalidates the field cache before calling compute, so reading
record.trigger inside compute returns the default (False) instead of
the stored DB value. We must read directly from the database.
"""

_inherit = "base.automation"

@api.depends("model_id")
def _compute_trigger(self):
# Read stored trigger values directly from DB — the ORM cache is
# invalidated before compute runs, so record.trigger would return
# False even when the DB holds a valid value.
stored = {}
existing = self.filtered("id")
if existing:
self.env.cr.execute(
"SELECT id, trigger FROM base_automation WHERE id IN %s",
[tuple(existing.ids)],
)
stored = dict(self.env.cr.fetchall())
for record in self:
record.trigger = stored.get(record.id) or False


class SyncTriggerAutomation(models.Model):

_name = "sync.trigger.automation"
Expand Down
2 changes: 0 additions & 2 deletions sync/models/sync_trigger_cron.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,5 @@ def name_get(self):
r.interval_number,
r.interval_type,
)
if r.numbercall > 0:
name += " (%s times)" % r.numbercall
result.append((r.id, name))
return result
2 changes: 1 addition & 1 deletion sync/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def add_items(container, *args, **kwargs):
else:
raise Exception(
f"The container received a non-callable positional argument of type "
f"'{type(item).__name__}', which lacks an explicit name. "
f"{type(item).__name__!r}, which lacks an explicit name. "
f"Please pass a callable, a dictionary, or provide a key-value pair using keyword arguments."
)
container.update(kwargs)
Expand Down
22 changes: 11 additions & 11 deletions sync/views/ir_logging_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
License MIT (https://opensource.org/licenses/MIT). -->
<odoo>
<record id="ir_logging_view_tree" model="ir.ui.view">
<field name="name">ir.logging.tree</field>
<field name="name">ir.logging.list</field>
<field name="model">ir.logging</field>
<field name="arch" type="xml">
<tree
<list
decoration-muted="level == 'debug'"
decoration-danger="level in ['error', 'critical']"
decoration-warning="level == 'warning'"
Expand All @@ -17,7 +17,7 @@
<field name="message_short" />
<field name="sync_project_id" />
<field name="sync_task_id" />
</tree>
</list>
</field>
</record>
<record id="ir_logging_view_form" model="ir.ui.view">
Expand Down Expand Up @@ -88,13 +88,13 @@
<record id="ir_logging_action" model="ir.actions.act_window">
<field name="name">Logs</field>
<field name="res_model">ir.logging</field>
<field name="view_mode">tree,form</field>
<field name="view_mode">list,form</field>
<field name="domain">[('sync_job_id', '!=', False)]</field>
<field name="search_view_id" ref="ir_logging_view_search" />
<field
name="view_ids"
eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('ir_logging_view_tree')}),
(0, 0, {'view_mode': 'list', 'view_id': ref('ir_logging_view_tree')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('ir_logging_view_form')})]"
/>
</record>
Expand All @@ -108,37 +108,37 @@
<record id="ir_logging_action_from_project" model="ir.actions.act_window">
<field name="name">Project Logs</field>
<field name="res_model">ir.logging</field>
<field name="view_mode">tree,form</field>
<field name="view_mode">list,form</field>
<field name="domain">[('sync_project_id', '=', active_id)]</field>
<field
name="view_ids"
eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('ir_logging_view_tree')}),
(0, 0, {'view_mode': 'list', 'view_id': ref('ir_logging_view_tree')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('ir_logging_view_form')})]"
/>
</record>
<record id="ir_logging_action_from_task" model="ir.actions.act_window">
<field name="name">Task Logs</field>
<field name="res_model">ir.logging</field>
<field name="view_mode">tree,form</field>
<field name="view_mode">list,form</field>
<field name="domain">[('sync_task_id', '=', active_id)]</field>
<field
name="view_ids"
eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('ir_logging_view_tree')}),
(0, 0, {'view_mode': 'list', 'view_id': ref('ir_logging_view_tree')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('ir_logging_view_form')})]"
/>
</record>
<record id="ir_logging_action_from_job" model="ir.actions.act_window">
<field name="name">Job Logs</field>
<field name="res_model">ir.logging</field>
<field name="view_mode">tree,form</field>
<field name="view_mode">list,form</field>
<!-- TODO: use search filters instead -->
<field name="domain">[('sync_job_id', '=', active_id)]</field>
<field
name="view_ids"
eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('ir_logging_view_tree')}),
(0, 0, {'view_mode': 'list', 'view_id': ref('ir_logging_view_tree')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('ir_logging_view_form')})]"
/>
</record>
Expand Down
Loading