diff --git a/edi_endpoint_oca/README.rst b/edi_endpoint_oca/README.rst new file mode 100644 index 000000000..b19c74827 --- /dev/null +++ b/edi_endpoint_oca/README.rst @@ -0,0 +1,78 @@ +============ +EDI endpoint +============ + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fedi-lightgray.png?logo=github + :target: https://github.com/OCA/edi/tree/14.0/edi_endpoint_oca + :alt: OCA/edi +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/edi-14-0/edi-14-0-edi_endpoint_oca + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/226/14.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Base module allowing configuration of custom endpoints for EDI framework. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +Go to "EDI -> Config -> Endpoints". + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Camptocamp + +Contributors +~~~~~~~~~~~~ + +* Simone Orsi + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/edi `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/edi_endpoint_oca/__init__.py b/edi_endpoint_oca/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/edi_endpoint_oca/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/edi_endpoint_oca/__manifest__.py b/edi_endpoint_oca/__manifest__.py new file mode 100644 index 000000000..8e59fcdce --- /dev/null +++ b/edi_endpoint_oca/__manifest__.py @@ -0,0 +1,24 @@ +# Copyright 2021 Camptocamp SA +# @author: Simone Orsi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +{ + "name": "EDI endpoint", + "summary": """ + Base module allowing configuration of custom endpoints for EDI framework. + """, + "version": "16.0.1.0.0", + "development_status": "Beta", + "license": "LGPL-3", + "website": "https://github.com/OCA/edi-framework", + "author": "Camptocamp,Odoo Community Association (OCA)", + "depends": ["base_edi", "edi_oca", "endpoint"], + "data": [ + "data/server_action.xml", + "security/ir.model.access.csv", + "views/edi_backend_views.xml", + "views/edi_endpoint_views.xml", + "views/edi_exchange_record_views.xml", + ], + "demo": ["demo/edi_backend_demo.xml"], +} diff --git a/edi_endpoint_oca/data/server_action.xml b/edi_endpoint_oca/data/server_action.xml new file mode 100644 index 000000000..897610d76 --- /dev/null +++ b/edi_endpoint_oca/data/server_action.xml @@ -0,0 +1,13 @@ + + + + Sync registry + ir.actions.server + + + code + +records.filtered(lambda x: not x.registry_sync).write({"registry_sync": True}) + + + diff --git a/edi_endpoint_oca/demo/edi_backend_demo.xml b/edi_endpoint_oca/demo/edi_backend_demo.xml new file mode 100644 index 000000000..871d0d307 --- /dev/null +++ b/edi_endpoint_oca/demo/edi_backend_demo.xml @@ -0,0 +1,30 @@ + + + + EDI backend with endpoints DEMO + + + + + EDI exchange demo + demo_endpoint + + input + + + + + + + EDI Demo Endpoint 1 + + /demo/try + GET + code + +record = endpoint.create_exchange_record() +result = {"response": Response("Created record: %s" % record.identifier)} + + + + diff --git a/edi_endpoint_oca/i18n/edi_endpoint_oca.pot b/edi_endpoint_oca/i18n/edi_endpoint_oca.pot new file mode 100644 index 000000000..814c56ebf --- /dev/null +++ b/edi_endpoint_oca/i18n/edi_endpoint_oca.pot @@ -0,0 +1,293 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * edi_endpoint_oca +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: edi_endpoint_oca +#: model_terms:ir.ui.view,arch_db:edi_endpoint_oca.edi_endpoint_form_view +msgid "Exchanges" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model,name:edi_endpoint_oca.model_edi_exchange_consumer_mixin +msgid "Abstract record where exchange records can be assigned" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__active +msgid "Active" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__auth_type +msgid "Auth Type" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__backend_id +#: model_terms:ir.ui.view,arch_db:edi_endpoint_oca.edi_endpoint_search_view +msgid "Backend" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__backend_type_id +msgid "Backend Type" +msgstr "" + +#. module: edi_endpoint_oca +#: code:addons/edi_endpoint_oca/models/edi_endpoint.py:0 +#, python-format +msgid "Backend and exchange type are mandatory" +msgstr "" + +#. module: edi_endpoint_oca +#: model_terms:ir.ui.view,arch_db:edi_endpoint_oca.edi_endpoint_search_view +msgid "Backend type" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__code_snippet +msgid "Code Snippet" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__code_snippet_docs +msgid "Code Snippet Docs" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__create_uid +msgid "Created by" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__create_date +msgid "Created on" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__csrf +msgid "Csrf" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_backend__display_name +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_backend_type__display_name +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__display_name +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_exchange_consumer_mixin__display_name +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_exchange_record__display_name +msgid "Display Name" +msgstr "" + +#. module: edi_endpoint_oca +#: model_terms:ir.ui.view,arch_db:edi_endpoint_oca.edi_endpoint_form_view +msgid "EDI" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model,name:edi_endpoint_oca.model_edi_backend +msgid "EDI Backend" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model,name:edi_endpoint_oca.model_edi_backend_type +msgid "EDI Backend Type" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model,name:edi_endpoint_oca.model_edi_endpoint +msgid "EDI Endpoint" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.actions.act_window,name:edi_endpoint_oca.edi_endpoint_act_window +#: model:ir.ui.menu,name:edi_endpoint_oca.edi_endpoint_menu +msgid "EDI Endpoints" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model,name:edi_endpoint_oca.model_edi_exchange_record +msgid "EDI exchange Record" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_exchange_consumer_mixin__origin_edi_endpoint_id +msgid "EDI origin endpoint" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_exchange_record__edi_endpoint_id +#: model_terms:ir.ui.view,arch_db:edi_endpoint_oca.edi_exchange_record_view_search +#: model_terms:ir.ui.view,arch_db:edi_endpoint_oca.edi_exchange_record_view_tree +msgid "Endpoint" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__endpoint_hash +msgid "Endpoint Hash" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_backend__endpoint_ids +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_backend_type__endpoint_ids +#: model_terms:ir.ui.view,arch_db:edi_endpoint_oca.edi_backend_view_form +msgid "Endpoints" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_backend__endpoints_count +msgid "Endpoints Count" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__exchange_type_id +msgid "Exchange Type" +msgstr "" + +#. module: edi_endpoint_oca +#: model_terms:ir.ui.view,arch_db:edi_endpoint_oca.edi_endpoint_search_view +msgid "Exchange type" +msgstr "" + +#. module: edi_endpoint_oca +#: code:addons/edi_endpoint_oca/models/edi_endpoint.py:0 +#, python-format +msgid "Exchange type not compatible with selected backend type." +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__exec_as_user_id +msgid "Exec As User" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__exec_mode +msgid "Exec Mode" +msgstr "" + +#. module: edi_endpoint_oca +#: model_terms:ir.ui.view,arch_db:edi_endpoint_oca.edi_endpoint_search_view +msgid "Group By" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_backend__id +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_backend_type__id +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__id +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_exchange_consumer_mixin__id +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_exchange_record__id +msgid "ID" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,help:edi_endpoint_oca.field_edi_endpoint__endpoint_hash +msgid "Identify the route with its main params" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_backend____last_update +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_backend_type____last_update +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint____last_update +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_exchange_consumer_mixin____last_update +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_exchange_record____last_update +msgid "Last Modified on" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__write_date +msgid "Last Updated on" +msgstr "" + +#. module: edi_endpoint_oca +#: model_terms:ir.ui.view,arch_db:edi_endpoint_oca.edi_backend_view_form +msgid "Manage endpoints" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__name +msgid "Name" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,help:edi_endpoint_oca.field_edi_endpoint__registry_sync +msgid "" +"ON: the record has been modified and registry was not notified.\n" +"No change will be active until this flag is set to false via proper action.\n" +"\n" +"OFF: record in line with the registry, nothing to do." +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,help:edi_endpoint_oca.field_edi_exchange_consumer_mixin__origin_edi_endpoint_id +#: model:ir.model.fields,help:edi_endpoint_oca.field_edi_exchange_record__edi_endpoint_id +msgid "Record generated via this endpoint" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__registry_sync +msgid "Registry Sync" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__request_content_type +msgid "Request Content Type" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__request_method +msgid "Request Method" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__route +msgid "Route" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__route_group +msgid "Route Group" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__route_type +msgid "Route Type" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.actions.server,name:edi_endpoint_oca.server_action_registry_sync +msgid "Sync registry" +msgstr "" + +#. module: edi_endpoint_oca +#: code:addons/edi_endpoint_oca/models/edi_backend.py:0 +#, python-format +msgid "" +"The following backend(s) have endpoints attached. Please archive them before:\n" +"\n" +"%s" +msgstr "" + +#. module: edi_endpoint_oca +#: model:ir.model.fields,help:edi_endpoint_oca.field_edi_endpoint__route_group +msgid "Use this to classify routes together" +msgstr "" + +#. module: edi_endpoint_oca +#: model_terms:ir.ui.view,arch_db:edi_endpoint_oca.edi_backend_view_form +msgid "endpoints configured" +msgstr "" diff --git a/edi_endpoint_oca/models/__init__.py b/edi_endpoint_oca/models/__init__.py new file mode 100644 index 000000000..8d770d06a --- /dev/null +++ b/edi_endpoint_oca/models/__init__.py @@ -0,0 +1,5 @@ +from . import edi_backend +from . import edi_backend_type +from . import edi_endpoint +from . import edi_exchange_record +from . import edi_exchange_consumer_mixin diff --git a/edi_endpoint_oca/models/edi_backend.py b/edi_endpoint_oca/models/edi_backend.py new file mode 100644 index 000000000..494630c04 --- /dev/null +++ b/edi_endpoint_oca/models/edi_backend.py @@ -0,0 +1,59 @@ +# Copyright 2021 Camptocamp SA +# @author: Simone Orsi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import _, api, exceptions, fields, models + + +class EDIBackend(models.Model): + + _inherit = "edi.backend" + + endpoint_ids = fields.One2many( + string="Endpoints", + comodel_name="edi.endpoint", + inverse_name="backend_id", + ) + endpoints_count = fields.Integer(compute="_compute_endpoints_count") + + @api.depends("endpoint_ids.active") + def _compute_endpoints_count(self): + data = self.env["edi.endpoint"].read_group( + [("backend_id", "in", self.ids), ("active", "=", True)], + ["backend_id"], + ["backend_id"], + ) + by_backend_id = {x["backend_id"][0]: x["backend_id_count"] for x in data} + for record in self: + record.endpoints_count = by_backend_id.get(record.id) + + def action_manage_endpoints(self): + xmlid = "edi_endpoint_oca.edi_endpoint_act_window" + action = self.env["ir.actions.act_window"]._for_xml_id(xmlid) + action["domain"] = [ + ("backend_type_id", "=", self.backend_type_id.id), + "|", + ("backend_id", "=", False), + ("backend_id", "=", self.id), + ] + action["context"] = { + "default_backend_id": self.id, + "default_backend_type_id": self.backend_type_id.id, + } + return action + + @api.constrains("active") + def _check_archive(self): + to_check = [ + x + for x in self + if not x.active and x.endpoint_ids.filtered(lambda x: x.active) + ] + if to_check: + raise exceptions.UserError(self._check_archive_error_msg(to_check)) + + def _check_archive_error_msg(self, backends): + return _( + "The following backend(s) have endpoints attached. " + "Please archive them before:\n\n%s" + ) % "\n- ".join([x.name for x in backends]) diff --git a/edi_endpoint_oca/models/edi_backend_type.py b/edi_endpoint_oca/models/edi_backend_type.py new file mode 100644 index 000000000..cd13a9905 --- /dev/null +++ b/edi_endpoint_oca/models/edi_backend_type.py @@ -0,0 +1,17 @@ +# Copyright 2021 Camptocamp SA +# @author: Simone Orsi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import fields, models + + +# TODO add view +class EDIBackendType(models.Model): + + _inherit = "edi.backend.type" + + endpoint_ids = fields.One2many( + string="Endpoints", + comodel_name="edi.endpoint", + inverse_name="backend_type_id", + ) diff --git a/edi_endpoint_oca/models/edi_endpoint.py b/edi_endpoint_oca/models/edi_endpoint.py new file mode 100644 index 000000000..b2a58e291 --- /dev/null +++ b/edi_endpoint_oca/models/edi_endpoint.py @@ -0,0 +1,88 @@ +# Copyright 2021 Camptocamp SA +# @author: Simone Orsi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). +import werkzeug + +from odoo import _, api, exceptions, fields, models +from odoo.tools import safe_eval + + +class EDIEndpoint(models.Model): + """EDI endpoint. + + Manage endpoints used within EDI framework. + """ + + _name = "edi.endpoint" + _inherit = ["endpoint.mixin"] + _description = "EDI Endpoint" + + _endpoint_route_prefix = "/edi" + + backend_type_id = fields.Many2one( + comodel_name="edi.backend.type", + required=True, + ) + # Leave these as not required to allow pre-configuration of endpoints by backend type + backend_id = fields.Many2one( + comodel_name="edi.backend", domain="[('backend_type_id','=', backend_type_id)]" + ) + exchange_type_id = fields.Many2one( + comodel_name="edi.exchange.type", + domain="[('backend_type_id','=', backend_type_id)]", + ) + + # TODO: add unit tests + + def create_exchange_record(self, file_content=None, **vals): + """Create an EDI exchange record from current endpoint. + + Just a shortcut. + """ + self._check_endpoint_ready() + vals["edi_endpoint_id"] = self.id + rec = self.backend_id.create_record(self.exchange_type_id.code, vals) + if file_content: + rec._set_file_content(file_content) + return rec + + def _check_endpoint_ready(self, request=False): + if not self.backend_id or not self.exchange_type_id: + msg = _("Backend and exchange type are mandatory") + if request: + self._logger.error(msg) + raise werkzeug.exceptions.BadRequest("Endpoint mis-configured") + else: + raise exceptions.UserError(msg) + + @api.constrains("exchange_type_id", "backend_type_id") + def _check_backend_type(self): + for rec in self: + if ( + rec.backend_type_id + and rec.exchange_type_id + and not rec.backend_type_id == rec.exchange_type_id.backend_type_id + ): + raise exceptions.UserError( + _("Exchange type not compatible with selected backend type.") + ) + + def _handle_request(self, request): + self._check_endpoint_ready(request=True) + return super()._handle_request(request) + + def action_view_edi_records(self): + self.ensure_one() + xmlid = "edi_oca.act_open_edi_exchange_record_view" + action = self.env["ir.actions.act_window"]._for_xml_id(xmlid) + action["domain"] = [("edi_endpoint_id", "=", self.id)] + # Purge default search filters from ctx to avoid hiding records + ctx = action.get("context", {}) + if isinstance(ctx, str): + ctx = safe_eval.safe_eval(ctx, self.env.context) + action["context"] = { + k: v for k, v in ctx.items() if not k.startswith("search_default_") + } + # Drop ID otherwise the context will be loaded from the action's record :S + action.pop("id") + return action diff --git a/edi_endpoint_oca/models/edi_exchange_consumer_mixin.py b/edi_endpoint_oca/models/edi_exchange_consumer_mixin.py new file mode 100644 index 000000000..fe6443606 --- /dev/null +++ b/edi_endpoint_oca/models/edi_exchange_consumer_mixin.py @@ -0,0 +1,19 @@ +# Copyright 2023 Camptocamp SA +# @author Simone Orsi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import fields, models + + +class EDIExchangeConsumerMixin(models.AbstractModel): + + _inherit = "edi.exchange.consumer.mixin" + + origin_edi_endpoint_id = fields.Many2one( + string="EDI origin endpoint", + comodel_name="edi.endpoint", + ondelete="set null", + related="origin_exchange_record_id.edi_endpoint_id", + # Store it to ease searching + store=True, + ) diff --git a/edi_endpoint_oca/models/edi_exchange_record.py b/edi_endpoint_oca/models/edi_exchange_record.py new file mode 100644 index 000000000..6b4a2d47a --- /dev/null +++ b/edi_endpoint_oca/models/edi_exchange_record.py @@ -0,0 +1,17 @@ +# Copyright 2023 Camptocamp SA +# @author Simone Orsi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import fields, models + + +class EDIExchangeRecord(models.Model): + + _inherit = "edi.exchange.record" + + edi_endpoint_id = fields.Many2one( + comodel_name="edi.endpoint", + readonly=True, + string="Endpoint", + help="Record generated via this endpoint", + ) diff --git a/edi_endpoint_oca/readme/CONFIGURE.rst b/edi_endpoint_oca/readme/CONFIGURE.rst new file mode 100644 index 000000000..dc2d05dbb --- /dev/null +++ b/edi_endpoint_oca/readme/CONFIGURE.rst @@ -0,0 +1 @@ +Go to "EDI -> Config -> Endpoints". diff --git a/edi_endpoint_oca/readme/CONTRIBUTORS.rst b/edi_endpoint_oca/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..f1c71bce1 --- /dev/null +++ b/edi_endpoint_oca/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Simone Orsi diff --git a/edi_endpoint_oca/readme/DESCRIPTION.rst b/edi_endpoint_oca/readme/DESCRIPTION.rst new file mode 100644 index 000000000..e7951c873 --- /dev/null +++ b/edi_endpoint_oca/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +Base module allowing configuration of custom endpoints for EDI framework. diff --git a/edi_endpoint_oca/security/ir.model.access.csv b/edi_endpoint_oca/security/ir.model.access.csv new file mode 100644 index 000000000..9ba995456 --- /dev/null +++ b/edi_endpoint_oca/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_edi_endpoint_edit,edi_endpoint edit,model_edi_endpoint,base_edi.group_edi_manager,1,1,1,1 diff --git a/edi_endpoint_oca/static/description/icon.png b/edi_endpoint_oca/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/edi_endpoint_oca/static/description/icon.png differ diff --git a/edi_endpoint_oca/static/description/index.html b/edi_endpoint_oca/static/description/index.html new file mode 100644 index 000000000..e7ef8e6bc --- /dev/null +++ b/edi_endpoint_oca/static/description/index.html @@ -0,0 +1,424 @@ + + + + + + +EDI endpoint + + + +
+

EDI endpoint

+ + +

Beta License: LGPL-3 OCA/edi Translate me on Weblate Try me on Runbot

+

Base module allowing configuration of custom endpoints for EDI framework.

+

Table of contents

+ +
+

Configuration

+

Go to “EDI -> Config -> Endpoints”.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp
  • +
+
+ +
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/edi project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/edi_endpoint_oca/tests/__init__.py b/edi_endpoint_oca/tests/__init__.py new file mode 100644 index 000000000..e93f5885e --- /dev/null +++ b/edi_endpoint_oca/tests/__init__.py @@ -0,0 +1,2 @@ +from . import test_edi_endpoint +from . import test_edi_endpoint_controller diff --git a/edi_endpoint_oca/tests/test_edi_endpoint.py b/edi_endpoint_oca/tests/test_edi_endpoint.py new file mode 100644 index 000000000..4407a9425 --- /dev/null +++ b/edi_endpoint_oca/tests/test_edi_endpoint.py @@ -0,0 +1,55 @@ +# Copyright 2021 Camptocamp SA +# @author: Simone Orsi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import exceptions + +from odoo.addons.endpoint.tests.common import CommonEndpoint + + +class TestEndpoint(CommonEndpoint): + @classmethod + def _setup_records(cls): # pylint: disable=missing-return + super()._setup_records() + cls.endpoint = cls.env.ref("edi_endpoint_oca.edi_endpoint_demo_1") + + def test_endpoint_find(self): + self.assertEqual( + self.env["edi.endpoint"]._find_endpoint("/edi/demo/try"), self.endpoint + ) + + def test_exchange_record(self): + rec = self.endpoint.create_exchange_record() + self.assertEqual(rec.edi_endpoint_id, self.endpoint) + + def test_route(self): + rec = self.endpoint.copy( + { + "route": "/noprefix", + } + ) + self.assertEqual(rec.route, "/edi/noprefix") + + def test_endpoint_count(self): + backend = self.endpoint.backend_id + self.assertEqual(backend.endpoints_count, 1) + rec = self.endpoint.copy( + { + "route": "/another", + } + ) + self.assertEqual(backend.endpoints_count, 2) + rec.active = False + self.assertEqual(backend.endpoints_count, 1) + + def test_archive_check(self): + backend = self.endpoint.backend_id + msg = r"The following backend\(s\) have endpoints attached*" + with self.assertRaisesRegex(exceptions.UserError, msg): + backend.active = False + backend.endpoint_ids.active = False + backend.active = False + + def test_sync(self): + # FIXME: just testing if the method here is available on GH + self.endpoint._handle_registry_sync() diff --git a/edi_endpoint_oca/tests/test_edi_endpoint_controller.py b/edi_endpoint_oca/tests/test_edi_endpoint_controller.py new file mode 100644 index 000000000..c71a39d9e --- /dev/null +++ b/edi_endpoint_oca/tests/test_edi_endpoint_controller.py @@ -0,0 +1,27 @@ +# Copyright 2021 Camptocamp SA +# @author: Simone Orsi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +import os +import unittest + +from odoo.tests.common import HttpCase + + +@unittest.skipIf(os.getenv("SKIP_HTTP_CASE"), "EDIEndpointHttpCase skipped") +class EDIEndpointHttpCase(HttpCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + # force sync for demo records + cls.env["edi.endpoint"].search([])._handle_registry_sync() + + def test_call1(self): + endpoint = "/edi/demo/try" + response = self.url_open(endpoint) + self.assertEqual(response.status_code, 401) + # Let's login now + self.authenticate("admin", "admin") + response = self.url_open(endpoint) + self.assertEqual(response.status_code, 200) + self.assertIn("Created record:", response.content.decode()) diff --git a/edi_endpoint_oca/views/edi_backend_views.xml b/edi_endpoint_oca/views/edi_backend_views.xml new file mode 100644 index 000000000..666cc4b08 --- /dev/null +++ b/edi_endpoint_oca/views/edi_backend_views.xml @@ -0,0 +1,21 @@ + + + + edi.backend + + + + +
+ endpoints configured +
+ + + + + +
+
+
+
+
+
+
+
+
+ + + edi.endpoint + + primary + + + + + + + + + + + + + + + + edi.endpoint + + primary + + + + + + + + + + + EDI Endpoints + edi.endpoint + tree,form + [] + {"search_default_all": 1} + + + + EDI Endpoints + + + + + +
diff --git a/edi_endpoint_oca/views/edi_exchange_record_views.xml b/edi_endpoint_oca/views/edi_exchange_record_views.xml new file mode 100644 index 000000000..18535545b --- /dev/null +++ b/edi_endpoint_oca/views/edi_exchange_record_views.xml @@ -0,0 +1,33 @@ + + + + edi.exchange.record + + + + + + + + + + edi.exchange.record + + + + + + + + + + edi.exchange.record + + + + + + + + + diff --git a/edi_oca/tests/common.py b/edi_oca/tests/common.py index 5d65cf843..839ee012d 100644 --- a/edi_oca/tests/common.py +++ b/edi_oca/tests/common.py @@ -74,7 +74,7 @@ def _create_exchange_type(cls, **kw): return model.create(vals) -@tagged("-at_install", "post_install") +@tagged("at_install", "-post_install") class EDIBackendCommonTestCase(TransactionCase, EDIBackendTestMixin): @classmethod def setUpClass(cls): diff --git a/setup/edi_endpoint_oca/odoo/addons/edi_endpoint_oca b/setup/edi_endpoint_oca/odoo/addons/edi_endpoint_oca new file mode 120000 index 000000000..82f69876d --- /dev/null +++ b/setup/edi_endpoint_oca/odoo/addons/edi_endpoint_oca @@ -0,0 +1 @@ +../../../../edi_endpoint_oca \ No newline at end of file diff --git a/setup/edi_endpoint_oca/setup.py b/setup/edi_endpoint_oca/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/edi_endpoint_oca/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)