Skip to content

Commit

Permalink
Merge PR #1123 into 14.0
Browse files Browse the repository at this point in the history
Signed-off-by simahawk
  • Loading branch information
OCA-git-bot committed Feb 13, 2025
2 parents 19b112e + de46bac commit 956570f
Show file tree
Hide file tree
Showing 11 changed files with 366 additions and 32 deletions.
3 changes: 2 additions & 1 deletion edi_exchange_template_oca/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
"name": "EDI Exchange Template",
"summary": """Allows definition of exchanges via templates.""",
"version": "14.0.1.5.2",
"version": "14.0.1.6.0",
"development_status": "Beta",
"license": "LGPL-3",
"author": "ACSONE,Camptocamp,Odoo Community Association (OCA)",
Expand All @@ -15,5 +15,6 @@
"data": [
"security/ir_model_access.xml",
"views/edi_exchange_template_output_views.xml",
"views/edi_exchange_type_views.xml",
],
}
60 changes: 60 additions & 0 deletions edi_exchange_template_oca/migrations/14.0.1.6.0/post-migrate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Copyright 2025 Camptocamp SA (http://www.camptocamp.com)
# @author Simone Orsi <simahawk@gmail.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

import logging

from odoo import SUPERUSER_ID, api

_logger = logging.getLogger(__name__)


def migrate(cr, version):
if not version:
return

env = api.Environment(cr, SUPERUSER_ID, {})

# Look for templates w/ a type set and set them as allowed on the type
# plus link the type to the template
templates = env["edi.exchange.template.output"].search([("type_id", "!=", False)])
for tmpl in templates:
allowed_type = tmpl.type_id
tmpl.type_id.output_template_id = tmpl
tmpl.allowed_type_ids += allowed_type
tmpl.type_id = None
_logger.info(
"Set output template %s on exchange type %s",
tmpl.name,
allowed_type.name,
)

# Look for types w/o a template
# and find the template by code to set as output template
types = env["edi.exchange.type"].search([("output_template_id", "=", False)])
for t in types:
settings = t.get_settings()
generate_usage = settings.get("components", {}).get("generate", {}).get("usage")
if generate_usage:
templates = env["edi.exchange.template.output"].search(
[
("code", "=", generate_usage),
("backend_type_id", "=", t.backend_type_id.id),
]
)
if len(templates) == 1:
tmpl = templates[0]
tmpl.allowed_type_ids += t
t.output_template_id = tmpl
_logger.info(
"Set output template %s on exchange type %s",
t.output_template_id.name,
t.name,
)
continue

_logger.warning(
"Cannot set a template for exchange type %s. "
"Either no template found or multiple found.",
t.name,
)
1 change: 1 addition & 0 deletions edi_exchange_template_oca/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from . import edi_backend
from . import edi_exchange_template_mixin
from . import edi_exchange_template_output
from . import edi_exchange_type
54 changes: 40 additions & 14 deletions edi_exchange_template_oca/models/edi_backend.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
# Copyright 2020 ACSONE SA
# Copyright 2025 Camptocamp SA
# @author Simone Orsi <simahawk@gmail.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

from odoo import models
import logging

from odoo import fields, models

_logger = logging.getLogger(__name__)


class EDIBackend(models.Model):
Expand All @@ -26,27 +31,48 @@ def output_template_model(self):
return self.env["edi.exchange.template.output"]

def _get_output_template(self, exchange_record, code=None):
"""Retrieve output templates by convention.
"""Retrieve output template.
Template's code must match the same component usage as per normal components.
:param exchange_record: record to generate.
:param code: explicit template code to lookup.
"""
tmpl = exchange_record.type_id.output_template_id
if tmpl:
return tmpl
_logger.warning(
"DEPRECATED: please set the template to use explicitly on the type %s.",
exchange_record.type_id.code,
)
# Deprecated behavior: emplate's code must match
# the same component usage as per normal components.t
# Wherever possible old types relying on code
# have been migrated to use the explicit template.
search = self.output_template_model.search
# TODO: maybe we can add a m2o to output templates
# but then we would need another for input templates if they are introduced.
tmpl = None
# NOTE: this is kind of broken because
# it should use the usage of the generate component one.
# As this is depraecated we can leave it as is.
code = code or exchange_record.type_id.code
if code:
domain = [("code", "=", code)]
return search(domain, limit=1)
for domain in self._get_output_template_domains(exchange_record):
tmpl = search(domain, limit=1)
if tmpl:
break
return tmpl
tmpl = self._get_output_template_fallback(exchange_record)
return tmpl

def _get_output_template_domains(self, exchange_record):
def _get_output_template_fallback(self, exchange_record):
"""Retrieve domains to lookup for templates by priority."""
backend_type_leaf = [("backend_type_id", "=", self.backend_type_id.id)]
exchange_type_leaf = [("type_id", "=", exchange_record.type_id.id)]
full_match_domain = backend_type_leaf + exchange_type_leaf
partial_match_domain = backend_type_leaf
return full_match_domain, partial_match_domain
# Match by backend and allowed types
base_domain = [
("backend_type_id", "=", self.backend_type_id.id),
"|",
("allowed_type_ids", "in", exchange_record.type_id.ids),
("allowed_type_ids", "=", False),
]
candidates = self.output_template_model.search(base_domain)
for rec in candidates:
if rec.type_id == exchange_record.type_id:
return rec
# Take the 1st one having allowed_type_ids set
return fields.first(candidates.sorted(lambda x: 0 if x.allowed_type_ids else 1))
31 changes: 30 additions & 1 deletion edi_exchange_template_oca/models/edi_exchange_template_mixin.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Copyright 2020 ACSONE SA
# Copyright 2025 Camptocamp SA
# @author Simone Orsi <simahawk@gmail.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
import datetime
Expand All @@ -7,7 +8,7 @@

import pytz

from odoo import fields, models
from odoo import _, api, exceptions, fields, models
from odoo.tools import DotDict, safe_eval

_logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -41,12 +42,23 @@ class EDIExchangeTemplateMixin(models.AbstractModel):
ondelete="restrict",
required=True,
)
# TODO: deprecate this field.
# Templates should be explicitly linked by a type
# and use `allowed_type_ids` to define allowed types.
type_id = fields.Many2one(
string="EDI Exchange type",
comodel_name="edi.exchange.type",
ondelete="cascade",
auto_join=True,
)
allowed_type_ids = fields.Many2many(
comodel_name="edi.exchange.type",
relation="edi_exchange_template_type_rel",
column1="template_id",
column2="type_id",
string="Allowed Exchange Types",
help="Types allowed to use this template.",
)
backend_id = fields.Many2one(
comodel_name="edi.backend",
ondelete="cascade",
Expand Down Expand Up @@ -147,3 +159,20 @@ def _get_validator(self, exchange_record):

def validate(self, exchange_record):
pass

@api.constrains("type_id", "allowed_type_ids")
def _check_type_id(self):
for rec in self:
if (
rec.type_id
and rec.allowed_type_ids
and rec.type_id not in rec.allowed_type_ids
):
raise exceptions.ValidationError(
_(
"The selected type must appear among the allowed types. "
"NOTE: the type field is deprecated and will be removed soon. "
"Use 'Allowed types' instead and set the template to use "
"explicitly on the type that will use this template."
)
)
45 changes: 45 additions & 0 deletions edi_exchange_template_oca/models/edi_exchange_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Copyright 2025 Camptocamp SA
# @author: Simone Orsi <simone.orsi@camptocamp.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).


from odoo import _, api, exceptions, fields, models


class EDIExchangeType(models.Model):
_inherit = "edi.exchange.type"

output_template_id = fields.Many2one(
comodel_name="edi.exchange.template.output",
string="Exchange Template",
ondelete="restrict",
required=False,
help="Template used to generate or process this type.",
)
output_template_allowed_ids = fields.Many2many(
comodel_name="edi.exchange.template.output",
# Inverse relation is defined in `edi.exchange.template.mixin`
relation="edi_exchange_template_type_rel",
column1="type_id",
column2="template_id",
string="Allowed Templates",
help="Templates allowed to be used with this type.",
)

@api.constrains("output_template_id")
def _check_output_template_id(self):
for rec in self:
tmpl = rec.output_template_id
if tmpl.type_id:
if tmpl.type_id != rec:
raise exceptions.ValidationError(
_("Template type must match exchange type.")
)
if (
tmpl
and tmpl.allowed_type_ids
and tmpl not in rec.output_template_allowed_ids
):
raise exceptions.ValidationError(
_("Template not allowed for this type.")
)
1 change: 1 addition & 0 deletions edi_exchange_template_oca/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from . import test_edi_backend_output
from . import test_nswrapper
from . import test_backend_and_type
Loading

0 comments on commit 956570f

Please sign in to comment.