diff --git a/edi_storage_oca/README.rst b/edi_storage_oca/README.rst index dcd6d47fd..fb78af9ed 100644 --- a/edi_storage_oca/README.rst +++ b/edi_storage_oca/README.rst @@ -7,7 +7,7 @@ EDI Storage backend support !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:f2718fe12ff53362a2da3e253d22e0641ebcd6a01195db14f8d9c8c71878080d + !! source digest: sha256:3806d6eaf0c3ce46d7d24b5c5e002f0c49a42390385f23e4480a33dd94e85451 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -16,14 +16,14 @@ EDI Storage backend support .. |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/15.0/edi_storage_oca - :alt: OCA/edi +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fedi--framework-lightgray.png?logo=github + :target: https://github.com/OCA/edi-framework/tree/16.0/edi_storage_oca + :alt: OCA/edi-framework .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/edi-15-0/edi-15-0-edi_storage_oca + :target: https://translation.odoo-community.org/projects/edi-framework-16-0/edi-framework-16-0-edi_storage_oca :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/edi&target_branch=15.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/edi-framework&target_branch=16.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -62,13 +62,18 @@ Usage Go to "EDI -> EDI backend" then configure your backend to use a storage backend. +Known issues / Roadmap +====================== + +* clean deprecated methods in the storage + Bug Tracker =========== -Bugs are tracked on `GitHub Issues `_. +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 to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -86,6 +91,12 @@ Contributors * Simone Orsi * Foram Shah * Lois Rilo +* Duong (Tran Quoc) + +Other credits +~~~~~~~~~~~~~ + +The migration of this module from 15.0 to 16.0 was financially supported by Camptocamp. Maintainers ~~~~~~~~~~~ @@ -100,6 +111,6 @@ 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. +This module is part of the `OCA/edi-framework `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/edi_storage_oca/__manifest__.py b/edi_storage_oca/__manifest__.py index 2e490068d..7a88dcef9 100644 --- a/edi_storage_oca/__manifest__.py +++ b/edi_storage_oca/__manifest__.py @@ -7,12 +7,12 @@ "summary": """ Base module to allow exchanging files via storage backend (eg: SFTP). """, - "version": "15.0.1.2.0", + "version": "16.0.1.0.0", "development_status": "Beta", "license": "LGPL-3", - "website": "https://github.com/OCA/edi", + "website": "https://github.com/OCA/edi-framework", "author": "ACSONE,Odoo Community Association (OCA)", - "depends": ["edi_oca", "storage_backend", "component"], + "depends": ["edi_oca", "fs_storage", "component"], "data": [ "data/cron.xml", "data/job_channel_data.xml", diff --git a/edi_storage_oca/components/base.py b/edi_storage_oca/components/base.py index db1a2c8a3..3081f77cc 100644 --- a/edi_storage_oca/components/base.py +++ b/edi_storage_oca/components/base.py @@ -14,16 +14,16 @@ class EDIStorageComponentMixin(AbstractComponent): _name = "edi.storage.component.mixin" _inherit = "edi.component.mixin" - # Components having `_storage_backend_type` will have precedence. + # Components having `_storage_type` will have precedence. # If the value is not set, generic components will be used. - _storage_backend_type = None + _storage_type = None @classmethod def _component_match(cls, work, usage=None, model_name=None, **kw): res = super()._component_match(work, usage=usage, model_name=model_name, **kw) - storage_type = kw.get("storage_backend_type") - if storage_type and cls._storage_backend_type: - return cls._storage_backend_type == storage_type + storage_type = kw.get("storage_type") + if storage_type and cls._storage_type: + return cls._storage_type == storage_type return res @property @@ -43,20 +43,6 @@ def _dir_by_state(self, direction, state): (self.backend[direction + "_dir_" + state] or "").strip().rstrip("/") ) - def _remote_file_path(self, direction, state, filename): - """Return remote file path by direction and state for give filename. - - :param direction: string stating direction of the exchange - :param state: string stating state of the exchange - :param filename: string for file name - :return: PurePath object - """ - _logger.warning( - "Call of deprecated function `_remote_file_path`. " - "Please use `_get_remote_file_path` instead.", - ) - return self._dir_by_state(direction, state) / filename.strip("/ ") - def _get_remote_file_path(self, state, filename=None): """Retrieve remote path for current exchange record.""" filename = filename or self.exchange_record.exchange_filename @@ -79,6 +65,7 @@ def _get_remote_file(self, state, filename=None, binary=False): # TODO: support match via pattern (eg: filename-prefix-*) # otherwise is impossible to retrieve input files and acks # (the date will never match) + # TODO: clean this up, .get is deprecated in fs_storage return self.storage.get(path.as_posix(), binary=binary) except FileNotFoundError: _logger.info( diff --git a/edi_storage_oca/components/check.py b/edi_storage_oca/components/check.py index 2cd97fb4a..4643f8c9c 100644 --- a/edi_storage_oca/components/check.py +++ b/edi_storage_oca/components/check.py @@ -69,24 +69,3 @@ def _exchange_output_check(self): self.exchange_record._notify_error("process_ko") return False return True - - # FIXME: this is not used ATM -> should be refactored - # into an incoming exchange. - # The backend will look for records needing an ack - # and generate and ack record. - def _exchange_output_handle_ack(self): - ack_type = self.exchange_record.type_id.ack_type_id - filename = ack_type._make_exchange_filename(self.exchange_record) - ack_file = self._get_remote_file("done", filename=filename) - if ack_file: - self.backend.create_record( - ack_type.code, - { - "parent_id": self.exchange_record.id, - "exchange_file": ack_file, - "edi_exchange_state": "input_received", - }, - ) - self.exchange_record._notify_ack_received() - else: - self.exchange_record._notify_ack_missing() diff --git a/edi_storage_oca/components/listener.py b/edi_storage_oca/components/listener.py index 54ad1ec01..5b3f49300 100644 --- a/edi_storage_oca/components/listener.py +++ b/edi_storage_oca/components/listener.py @@ -2,6 +2,7 @@ # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). import functools +import os from pathlib import PurePath from odoo.addons.component.core import Component @@ -14,19 +15,23 @@ class EdiStorageListener(Component): def _move_file(self, storage, from_dir_str, to_dir_str, filename): from_dir = PurePath(from_dir_str) to_dir = PurePath(to_dir_str) - if filename not in storage.list_files(from_dir.as_posix()): - # The file might have been moved after a previous error. + # - storage.list_files now includes path in fs_storage, breaking change + # - we remove path + # TODO: clean this up, .list_files is deprecated in fs_storage + files = storage.list_files(from_dir.as_posix()) + files = [os.path.basename(f) for f in files] + if filename not in files: return False - self._add_after_commit_hook( - storage._move_files, [(from_dir / filename).as_posix()], to_dir.as_posix() + # TODO: clean this up, .move_files is deprecated in fs_storage + self._add_post_commit_hook( + storage.move_files, [(from_dir / filename).as_posix()], to_dir.as_posix() ) return True - def _add_after_commit_hook(self, move_func, sftp_filepath, sftp_destination_path): + def _add_post_commit_hook(self, move_func, sftp_filepath, sftp_destination_path): """Add hook after commit to move the file when transaction is over.""" - self.env.cr.after( - "commit", - functools.partial(move_func, sftp_filepath, sftp_destination_path), + self.env.cr.postcommit.add( + functools.partial(move_func, sftp_filepath, sftp_destination_path) ) def on_edi_exchange_done(self, record): diff --git a/edi_storage_oca/components/receive.py b/edi_storage_oca/components/receive.py index b0ab8257e..c10a6e629 100644 --- a/edi_storage_oca/components/receive.py +++ b/edi_storage_oca/components/receive.py @@ -15,5 +15,6 @@ class EDIStorageReceiveComponent(Component): def receive(self): path = self._get_remote_file_path("pending") + # TODO: clean this up, .get is deprecated in fs_storage filedata = self.storage.get(path.as_posix()) return filedata diff --git a/edi_storage_oca/components/send.py b/edi_storage_oca/components/send.py index 95c6ecdc6..fe1437ca2 100644 --- a/edi_storage_oca/components/send.py +++ b/edi_storage_oca/components/send.py @@ -25,6 +25,7 @@ def send(self): return True filedata = self.exchange_record.exchange_file path = self._get_remote_file_path("pending") + # TODO: clean this up, .add is deprecated in fs_storage self.storage.add(path.as_posix(), filedata, binary=False) # TODO: delegate this to generic storage backend # except paramiko.ssh_exception.AuthenticationException: diff --git a/edi_storage_oca/demo/edi_backend_demo.xml b/edi_storage_oca/demo/edi_backend_demo.xml index 5b003460f..83e26cc2a 100644 --- a/edi_storage_oca/demo/edi_backend_demo.xml +++ b/edi_storage_oca/demo/edi_backend_demo.xml @@ -3,7 +3,7 @@ Storage Demo EDI backend - + demo_in/pending demo_in/done demo_in/error diff --git a/edi_storage_oca/i18n/edi_storage_oca.pot b/edi_storage_oca/i18n/edi_storage_oca.pot deleted file mode 100644 index 3458c862e..000000000 --- a/edi_storage_oca/i18n/edi_storage_oca.pot +++ /dev/null @@ -1,106 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * edi_storage_oca -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 15.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_storage_oca -#: model:ir.model,name:edi_storage_oca.model_edi_backend -msgid "EDI Backend" -msgstr "" - -#. module: edi_storage_oca -#: model:ir.model,name:edi_storage_oca.model_edi_exchange_type -msgid "EDI Exchange Type" -msgstr "" - -#. module: edi_storage_oca -#: model:ir.actions.server,name:edi_storage_oca.cron_check_storage_pending_input_ir_actions_server -#: model:ir.cron,cron_name:edi_storage_oca.cron_check_storage_pending_input -#: model:ir.cron,name:edi_storage_oca.cron_check_storage_pending_input -msgid "EDI backend storage check pending input" -msgstr "" - -#. module: edi_storage_oca -#: model:ir.model.fields,field_description:edi_storage_oca.field_edi_exchange_type__exchange_filename_pattern -msgid "Exchange Filename Pattern" -msgstr "" - -#. module: edi_storage_oca -#: model:ir.model.fields,help:edi_storage_oca.field_edi_exchange_type__exchange_filename_pattern -msgid "" -"For output exchange types this should be a formatting string with the following variables available (to be used between brackets, `{}`): `exchange_record`, `record_name`, `type` and `dt`. For instance, a valid string would be {record_name}-{type.code}-{dt}\n" -"For input exchange types related to storage backends it should be a regex expression to filter the files to be fetched from the pending directory in the related storage. E.g: `.*my-type-[0-9]*.\\.csv`" -msgstr "" - -#. module: edi_storage_oca -#: model:ir.model.fields,field_description:edi_storage_oca.field_edi_backend__input_dir_done -msgid "Input done directory" -msgstr "" - -#. module: edi_storage_oca -#: model:ir.model.fields,field_description:edi_storage_oca.field_edi_backend__input_dir_error -msgid "Input error directory" -msgstr "" - -#. module: edi_storage_oca -#: model:ir.model.fields,field_description:edi_storage_oca.field_edi_backend__input_dir_pending -msgid "Input pending directory" -msgstr "" - -#. module: edi_storage_oca -#: model:ir.model.fields,field_description:edi_storage_oca.field_edi_backend__output_dir_done -msgid "Output done directory" -msgstr "" - -#. module: edi_storage_oca -#: model:ir.model.fields,field_description:edi_storage_oca.field_edi_backend__output_dir_error -msgid "Output error directory" -msgstr "" - -#. module: edi_storage_oca -#: model:ir.model.fields,field_description:edi_storage_oca.field_edi_backend__output_dir_pending -msgid "Output pending directory" -msgstr "" - -#. module: edi_storage_oca -#: model:ir.model.fields,help:edi_storage_oca.field_edi_backend__input_dir_done -#: model:ir.model.fields,help:edi_storage_oca.field_edi_backend__output_dir_done -msgid "Path to folder for doneful operations" -msgstr "" - -#. module: edi_storage_oca -#: model:ir.model.fields,help:edi_storage_oca.field_edi_backend__input_dir_error -#: model:ir.model.fields,help:edi_storage_oca.field_edi_backend__output_dir_error -msgid "Path to folder for error operations" -msgstr "" - -#. module: edi_storage_oca -#: model:ir.model.fields,help:edi_storage_oca.field_edi_backend__input_dir_pending -#: model:ir.model.fields,help:edi_storage_oca.field_edi_backend__output_dir_pending -msgid "Path to folder for pending operations" -msgstr "" - -#. module: edi_storage_oca -#: model_terms:ir.ui.view,arch_db:edi_storage_oca.edi_backend_view_form -msgid "Storage" -msgstr "" - -#. module: edi_storage_oca -#: model:ir.model.fields,field_description:edi_storage_oca.field_edi_backend__storage_id -msgid "Storage backend" -msgstr "" - -#. module: edi_storage_oca -#: model:ir.model.fields,help:edi_storage_oca.field_edi_backend__storage_id -msgid "Storage for in-out files" -msgstr "" diff --git a/edi_storage_oca/models/edi_backend.py b/edi_storage_oca/models/edi_backend.py index 3669eabf9..6751247a3 100644 --- a/edi_storage_oca/models/edi_backend.py +++ b/edi_storage_oca/models/edi_backend.py @@ -16,8 +16,8 @@ class EDIBackend(models.Model): _inherit = "edi.backend" storage_id = fields.Many2one( - string="Storage backend", - comodel_name="storage.backend", + string="FS Storage", + comodel_name="fs.storage", help="Storage for in-out files", ondelete="restrict", ) @@ -67,21 +67,19 @@ def _get_component_usage_candidates(self, exchange_record, key): return ["storage.{}".format(key)] + candidates def _component_match_attrs(self, exchange_record, key): - # Override to inject storage_backend_type + # Override to inject storage_type res = super()._component_match_attrs(exchange_record, key) if not self.storage_id or key not in self._storage_actions: return res - res["storage_backend_type"] = self.storage_id.backend_type + res["storage_type"] = self.storage_id.protocol return res def _component_sort_key(self, component_class): res = super()._component_sort_key(component_class) - # Override to give precedence by storage_backend_type when needed. + # Override to give precedence by storage_type when needed. if not self.storage_id: return res - return ( - 1 if getattr(component_class, "_storage_backend_type", False) else 0, - ) + res + return (1 if getattr(component_class, "_storage_type", False) else 0,) + res def _storage_cron_check_pending_input(self, **kw): for backend in self: @@ -150,6 +148,7 @@ def _storage_get_input_filenames(self, exchange_type): ).as_posix() if not exchange_type.exchange_filename_pattern: # If there is not pattern, return everything + # TODO: clean this up, .list_files is deprecated in fs_storage filenames = [ x for x in self.storage_id.list_files(full_input_dir_pending) @@ -161,6 +160,7 @@ def _storage_get_input_filenames(self, exchange_type): if exchange_type.exchange_file_ext: bits.append(r"\." + exchange_type.exchange_file_ext) pattern = "".join(bits) + # TODO: clean this up, .find_files is deprecated in fs_storage full_paths = self.storage_id.find_files(pattern, full_input_dir_pending) pending_path_len = len(full_input_dir_pending) return [p[pending_path_len:].strip("/") for p in full_paths] diff --git a/edi_storage_oca/readme/CONTRIBUTORS.rst b/edi_storage_oca/readme/CONTRIBUTORS.rst index 55ca1c7e0..fdb4b1c8a 100644 --- a/edi_storage_oca/readme/CONTRIBUTORS.rst +++ b/edi_storage_oca/readme/CONTRIBUTORS.rst @@ -1,3 +1,4 @@ * Simone Orsi * Foram Shah * Lois Rilo +* Duong (Tran Quoc) diff --git a/edi_storage_oca/readme/CREDITS.rst b/edi_storage_oca/readme/CREDITS.rst new file mode 100644 index 000000000..5511b681b --- /dev/null +++ b/edi_storage_oca/readme/CREDITS.rst @@ -0,0 +1 @@ +The migration of this module from 15.0 to 16.0 was financially supported by Camptocamp. diff --git a/edi_storage_oca/readme/ROADMAP.rst b/edi_storage_oca/readme/ROADMAP.rst new file mode 100644 index 000000000..fd353688e --- /dev/null +++ b/edi_storage_oca/readme/ROADMAP.rst @@ -0,0 +1 @@ +* clean deprecated methods in the storage diff --git a/edi_storage_oca/security/ir_model_access.xml b/edi_storage_oca/security/ir_model_access.xml index b7d7b8498..d50ace4c4 100644 --- a/edi_storage_oca/security/ir_model_access.xml +++ b/edi_storage_oca/security/ir_model_access.xml @@ -1,8 +1,8 @@ - - access_storage_backend EDI manager - + + access_fs_storage EDI manager + diff --git a/edi_storage_oca/static/description/index.html b/edi_storage_oca/static/description/index.html index 3a323e627..3bc24a70c 100644 --- a/edi_storage_oca/static/description/index.html +++ b/edi_storage_oca/static/description/index.html @@ -1,20 +1,20 @@ - + - + EDI Storage backend support