Skip to content

Commit

Permalink
[ADD] edi_upflow: EDI mechanism to comunicate with upflow.io
Browse files Browse the repository at this point in the history
---------

Co-authored-by: Matthias BARKAT <matthias.barkat@foodles.co>
Co-authored-by: Alexandre Galdeano <alexandre.galdeano@foodles.co>
  • Loading branch information
3 people committed Sep 4, 2024
1 parent e32c5a9 commit cd97643
Show file tree
Hide file tree
Showing 64 changed files with 6,064 additions and 0 deletions.
131 changes: 131 additions & 0 deletions edi_upflow/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
==========
EDI UPFLOW
==========

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:00bc337e6cc52b983cc045c3ce3d00bac45a579a40f1c927696738ed7433fa59
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
:target: https://odoo-community.org/page/development-status
:alt: Alpha
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fcredit--control-lightgray.png?logo=github
:target: https://github.com/OCA/credit-control/tree/14.0/edi_upflow
:alt: OCA/credit-control
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/credit-control-14-0/credit-control-14-0-edi_upflow
: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/credit-control&target_branch=14.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|


Based on OCA EDI Frameworks this modules aims to integrate
Odoo and Upflow.io.

# Trigger

Here is the list of event that generate exchange that push data to upflow:

* When account entry of the following type are posted
out invoice / out refund / invoice payment or refund payment, then
the customer will be synchronised if no ufpflow id present in the database.

* When full reconcile line is created it will create missing account entry if any
(backend statement reconcile can works without account payment in odoo) and send reconcile
info to upflow.

* any change on synchronized information to a customer or a contact will update all customers
informations to upflow.


# Multi-company

A customer and sales accounting entries are linked to only one backend.

Backend are linked to a company, but once a customer has been synchronised
for a given backend (first sale accounting entry), next accounting entries
will be linked to the same backend (upflow organisation) what ever the current
backend set on the current company.

# Asynchrone tasks

Data are send asynchronously, according your configuration tasks can take few minutes
to be handle and send to upflow.

On each relevent form views you will see an EDI smart button
that let you check the state of the reletated exchange synchronizations.

This module is based on EDI Frameworks maintain by OCA which depends on the `queue_job`
module you should also monitor queue job tasks.

.. IMPORTANT::
This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
`More details on development status <https://odoo-community.org/page/development-status>`_

**Table of contents**

.. contents::
:local:

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/credit-control/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 <https://github.com/OCA/credit-control/issues/new?body=module:%20edi_upflow%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

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

Credits
=======

Authors
~~~~~~~

* Pierre Verkest

Contributors
~~~~~~~~~~~~

* `Foodles <https://https://www.foodles.com>`_

* Pierre Verkest <pierreverkest84@gmail.com>
* Alexandre Galdeano <alexandre.galdeano@foodles.co>
* Matthias BARKAT <matthias.barkat@foodles.co>

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.

.. |maintainer-petrus-v| image:: https://github.com/petrus-v.png?size=40px
:target: https://github.com/petrus-v
:alt: petrus-v

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-petrus-v|

This module is part of the `OCA/credit-control <https://github.com/OCA/credit-control/tree/14.0/edi_upflow>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
3 changes: 3 additions & 0 deletions edi_upflow/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from . import components, models
36 changes: 36 additions & 0 deletions edi_upflow/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright 2023 Foodles (https://www.foodles.com/)
# @author Pierre Verkest <pierreverkest84@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
"name": "EDI UPFLOW",
"summary": "Odoo Upflow.io connector",
"version": "14.0.2.0.1",
"development_status": "Alpha",
"category": "EDI",
"website": "https://github.com/OCA/credit-control",
"author": "Pierre Verkest, Odoo Community Association (OCA)",
"maintainers": ["petrus-v"],
"license": "AGPL-3",
"application": True,
"depends": [
"account",
"base_upflow",
"edi_oca",
"webservice",
"edi_webservice_oca",
"edi_account_oca",
],
"data": [
"data/cron.xml",
"data/edi.xml",
"views/account_full_reconcile.xml",
"views/account_partial_reconcile.xml",
"views/edi_exchange_record.xml",
"views/res_config_settings.xml",
"views/res_partner.xml",
"views/webservice_backend.xml",
],
"external_dependencies": {"python": ["responses"]},
"demo": [],
"installable": True,
}
29 changes: 29 additions & 0 deletions edi_upflow/components/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from . import base_upflow_edi_output_generate
from . import base_upflow_edi_output_check
from . import event_listener_base
from . import (
edi_output_check_upflow_post_credit_notes,
edi_output_check_upflow_post_credit_notes_pdf,
edi_output_check_upflow_post_customers,
edi_output_check_upflow_post_invoice,
edi_output_check_upflow_post_invoice_pdf,
edi_output_check_upflow_post_payments,
edi_output_check_upflow_post_reconcile,
edi_output_check_upflow_post_refunds,
edi_output_check_upflow_put_contacts,
edi_output_generate_upflow_post_credit_notes,
edi_output_generate_upflow_post_credit_notes_pdf,
edi_output_generate_upflow_post_customers,
edi_output_generate_upflow_post_invoice,
edi_output_generate_upflow_post_invoice_pdf,
edi_output_generate_upflow_post_payments,
edi_output_generate_upflow_post_reconcile,
edi_output_generate_upflow_post_refunds,
edi_output_generate_upflow_put_contacts,
edi_webservice_send,
event_listener_account_move,
event_listener_account_partial_reconcile,
event_listener_exchange_record,
event_listener_res_partner,
request_adapter,
)
87 changes: 87 additions & 0 deletions edi_upflow/components/base_upflow_edi_output_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Copyright 2023 Foodles (https://www.foodles.com/)
# @author Pierre Verkest <pierreverkest84@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import json

from odoo import _
from odoo.exceptions import ValidationError

from odoo.addons.component.core import Component
from odoo.addons.edi_oca.models.edi_backend import _get_exception_msg


class BaseUpflowEDIOutputCheck(Component):
_name = "base.upflow.edi.output.check"
_inherit = "edi.component.check.mixin"
_usage = "output.check"
_backend_type = "upflow"

_action = "check"

def check(self):
try:
self._check_and_process()
except Exception as ex:
state = "output_sent_and_error"
self.exchange_record.exchange_error = (
f"{ex.__class__.__name__}: {_get_exception_msg()}"
)
else:
state = "output_sent_and_processed"
finally:
self.exchange_record.edi_exchange_state = state

def _check_ws_response_status_code(self):
if (
self.exchange_record.ws_response_status_code < 200
or self.exchange_record.ws_response_status_code >= 300
):
raise ValidationError(
_(
"Not a valid HTTP error (expected 2xx, received %s) "
"in order to processed the payload (%s)"
)
% (
self.exchange_record.ws_response_status_code,
self._get_upflow_response(),
)
)

def _get_upflow_response(self):
return self.exchange_record._get_file_content(field_name="ws_response_content")

def _parse_upflow_response(self):
try:
data = json.loads(self._get_upflow_response())
except Exception:
data = {}
return data

def _get_response_upflow_uuid(self):
return self._parse_upflow_response()["id"]

def _get_response_upflow_direct_url(self):
return self._parse_upflow_response().get("directUrl", False)

def _set_record_upflow_uuid(self):
self.exchange_record.record.upflow_uuid = self._get_response_upflow_uuid()

def _set_record_upflow_direct_url(self):
self.exchange_record.record.upflow_direct_url = (
self._get_response_upflow_direct_url()
)

def _upflow_check_and_process(self):
self._check_ws_response_status_code()
self._set_record_upflow_uuid()
self._set_record_upflow_direct_url()

def _check_and_process(self):
raise NotImplementedError(
_(
"You should implement _check_and_process method "
"to process upflow.io REST response "
"on this exchange type (code: %s)"
)
% (self.exchange_record.type_id.code)
)
44 changes: 44 additions & 0 deletions edi_upflow/components/base_upflow_edi_output_generate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright 2023 Foodles (https://www.foodles.com/)
# @author Pierre Verkest <pierreverkest84@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import _

from odoo.addons.component.core import Component
from odoo.addons.queue_job.exception import RetryableJobError


class BaseUpflowEDIOutputGenerate(Component):
_name = "base.upflow.edi.output.generate"
_inherit = "edi.component.output.mixin"
_usage = "output.generate"
_backend_type = "upflow"

_action = "generate"

def generate(self):
raise NotImplementedError(
_(
"You should implement generate method "
"to create the payload or fix the exchange type. "
"(Received exchange type code: %s)"
)
% self.exchange_record.type_id.code
)

def _wait_related_exchange_to_be_sent_and_processed(self):
# while moving this to edi_oca
# https://github.com/OCA/edi/issues/782
# consider to gives a way to make list of states configurable
# I belives in some case we wan't to generate the event event
# depends one is in error but manually fix it (an other way)
# in the mean time is to remove the dependence to force the event
if not all(
self.exchange_record.dependent_exchange_ids.mapped(
lambda rel_exch: rel_exch.edi_exchange_state
== "output_sent_and_processed"
)
):
raise RetryableJobError(
"Waiting related exchanges to be done before generate...",
)
14 changes: 14 additions & 0 deletions edi_upflow/components/edi_output_check_upflow_post_credit_notes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright 2023 Foodles (https://www.foodles.com/)
# @author Pierre Verkest <pierreverkest84@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo.addons.component.core import Component


class EdiOutputCheckUpflowPostCreditNotes(Component):
_name = "edi.output.check.upflow_post_credit_notes"
_inherit = "base.upflow.edi.output.check"
_exchange_type = "upflow_post_credit_notes"

def _check_and_process(self):
self._upflow_check_and_process()
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright 2023 Foodles (https://www.foodles.com/)
# @author Pierre Verkest <pierreverkest84@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo.addons.component.core import Component


class EdiOutputCheckUpflowPostCreditNotesPDF(Component):
_name = "edi.output.check.upflow_post_credit_notes_pdf"
_inherit = "base.upflow.edi.output.check"
_exchange_type = "upflow_post_credit_notes_pdf"

def _check_and_process(self):
self._check_ws_response_status_code()
24 changes: 24 additions & 0 deletions edi_upflow/components/edi_output_check_upflow_post_customers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2023 Foodles (https://www.foodles.com/)
# @author Pierre Verkest <pierreverkest84@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import logging

from odoo.addons.component.core import Component

_logger = logging.getLogger(__name__)


class EdiOutputCheckUpflowPostCustomers(Component):
_name = "edi.output.check.upflow_post_customers"
_inherit = "base.upflow.edi.output.check"
_exchange_type = "upflow_post_customers"

def _check_and_process(self):
self._upflow_check_and_process()
for contact in self._parse_upflow_response().get("contacts", []):
if not contact.get("externalId"):
_logger.warning("No externalId found for contact %s", contact.get("id"))
continue
self.exchange_record.record.child_ids.filtered_domain(
[("id", "=", int(contact.get("externalId")))]
).upflow_uuid = contact.get("id")
Loading

0 comments on commit cd97643

Please sign in to comment.