-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[IMP] connector_oxigesti: logic to mark general items as deprecated p…
…er customer
- Loading branch information
Showing
21 changed files
with
493 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
# Copyright NuoBiT Solutions - Eric Antones <[email protected]> | ||
# Copyright NuoBiT Solutions - Frank Cespedes <[email protected]> | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html) | ||
import hashlib | ||
|
||
from odoo import _ | ||
from odoo.exceptions import ValidationError | ||
from odoo.osv.expression import normalize_domain | ||
|
||
OP_MAP = { | ||
"&": "AND", | ||
"|": "OR", | ||
"!": "NOT", | ||
} | ||
|
||
|
||
def domain_prefix_to_infix(domain): | ||
stack = [] | ||
i = len(domain) - 1 | ||
while i >= 0: | ||
item = domain[i] | ||
if item in OP_MAP: | ||
if item == "!": | ||
stack.append((item, stack.pop())) | ||
else: | ||
stack.append((stack.pop(), item, stack.pop())) | ||
else: | ||
if not isinstance(item, (tuple, list)): | ||
raise ValidationError(_("Unexpected domain clause %s") % item) | ||
stack.append(item) | ||
i -= 1 | ||
return stack.pop() | ||
|
||
|
||
def domain_infix_to_where(domain): | ||
def _convert_operator(operator, value): | ||
if value is None: | ||
if operator == "=": | ||
operator = "is" | ||
elif operator == "!=": | ||
operator = "is not" | ||
else: | ||
raise ValidationError( | ||
_("Operator '%s' is not implemented on NULL values") % operator | ||
) | ||
return operator | ||
|
||
def _domain_infix_to_where_raw(domain, values): | ||
if not isinstance(domain, (list, tuple)): | ||
raise ValidationError(_("Invalid domain format %s") % domain) | ||
if len(domain) == 2: | ||
operator, expr = domain | ||
if operator not in OP_MAP: | ||
raise ValidationError( | ||
_("Invalid format, operator not supported %s on domain %s") | ||
% (operator, domain) | ||
) | ||
values_r, right = _domain_infix_to_where_raw(expr, values) | ||
return values_r, f"{OP_MAP[operator]} ({right})" | ||
elif len(domain) == 3: | ||
expr_l, operator, expr_r = domain | ||
if operator in OP_MAP: | ||
values_l, left = _domain_infix_to_where_raw(expr_l, values) | ||
values_r, right = _domain_infix_to_where_raw(expr_r, values) | ||
return {**values_l, **values_r}, f"({left} {OP_MAP[operator]} {right})" | ||
field, operator, value = domain | ||
# field and values | ||
if field not in values: | ||
values[field] = {"next": 1, "values": {}} | ||
field_n = f"{field}{values[field]['next']}" | ||
if field_n in values[field]["values"]: | ||
raise ValidationError(_("Unexpected!! Field %s already used") % field) | ||
values[field]["values"][field_n] = value | ||
values[field]["next"] += 1 | ||
# operator and nulls values | ||
operator = _convert_operator(operator, value) | ||
return values, f"{field} {operator} %({field_n})s" | ||
else: | ||
raise ValidationError(_("Invalid domain format %s") % domain) | ||
|
||
values, where = _domain_infix_to_where_raw(domain, {}) | ||
values_norm = {} | ||
for _k, v in values.items(): | ||
values_norm.update(v["values"]) | ||
return values_norm, where | ||
|
||
|
||
def domain_to_where(domain): | ||
domain_norm = normalize_domain(domain) | ||
domain_infix = domain_prefix_to_infix(domain_norm) | ||
return domain_infix_to_where(domain_infix) | ||
|
||
|
||
def idhash(external_id): | ||
if not isinstance(external_id, (tuple, list)): | ||
raise ValidationError(_("external id must be list or tuple")) | ||
external_id_hash = hashlib.sha256() | ||
for e in external_id: | ||
if isinstance(e, int): | ||
e9 = str(e) | ||
if int(e9) != e: | ||
raise Exception("Unexpected") | ||
elif isinstance(e, str): | ||
e9 = e | ||
elif e is None: | ||
pass | ||
else: | ||
raise Exception("Unexpected type for a key: type %s" % type(e)) | ||
|
||
external_id_hash.update(e9.encode("utf8")) | ||
|
||
return external_id_hash.hexdigest() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,4 @@ | |
from . import import_mapper | ||
from . import export_mapper | ||
from . import listener | ||
from . import deleter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# Copyright NuoBiT Solutions - Eric Antones <[email protected]> | ||
# Copyright NuoBiT Solutions - Frank Cespedes <[email protected]> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) | ||
|
||
import logging | ||
|
||
from odoo.addons.component.core import AbstractComponent | ||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
|
||
class OxigestiExportDeleter(AbstractComponent): | ||
"""Base Export Deleter for Oxigesti""" | ||
|
||
_name = "oxigesti.export.deleter" | ||
_inherit = ["base.deleter", "base.oxigesti.connector"] | ||
|
||
_usage = "record.export.deleter" | ||
|
||
def run(self, external_id): | ||
adapter = self.component(usage="backend.adapter") | ||
adapter.delete(external_id) | ||
|
||
|
||
class OxigestiBatchExportDeleter(AbstractComponent): | ||
_name = "oxigesti.batch.export.deleter" | ||
_inherit = ["base.exporter", "base.oxigesti.connector"] | ||
|
||
def run(self, external_ids=None): | ||
if not external_ids: | ||
return | ||
# Run the synchronization | ||
for ext_id in external_ids: | ||
self._export_delete_record(ext_id) | ||
|
||
def _export_delete_record(self, external_id): | ||
raise NotImplementedError | ||
|
||
|
||
class OxigestiDirectBatchExportDeleter(AbstractComponent): | ||
_name = "oxigesti.direct.batch.export.deleter" | ||
_inherit = "oxigesti.batch.export.deleter" | ||
|
||
_usage = "direct.batch.export.deleter" | ||
|
||
def _export_delete_record(self, external_id): | ||
self.model.export_delete_record(self.backend_record, external_id) | ||
|
||
|
||
class OxigestiDelayedBatchExportDeleter(AbstractComponent): | ||
_name = "oxigesti.delayed.batch.export.deleter" | ||
_inherit = "oxigesti.batch.export.deleter" | ||
|
||
_usage = "delayed.batch.export.deleter" | ||
|
||
def _export_delete_record(self, external_id, job_options=None): | ||
delayable = self.model.with_delay(**job_options or {}) | ||
delayable.export_delete_record(self.backend_record, external_id) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.