Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[14.0][ADD] sale_order_import_edifact & base_edifact #779

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions base_edifact/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
============
Base EDIFACT
============

.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |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%2Fedi-lightgray.png?logo=github
:target: https://github.com/OCA/edi/tree/14.0/base_edifact
: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-base_edifact
: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|


This module contains methods to generate and parse EDIFACT/D96A files

.. 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:

Installation
============


This module requires 'pydifact' python library.

Configuration
=============

Requires partner_identification_gln module to store GLN identifiers.

Partner identification code assigned by the European Article Numbering Association.

Use two identification categories:

- "GLN Identificatin Number". Partner identification like invoice or delivery address.
- "GCP Identification Number". Global Company Prefix.

If GCP codes are needed in UNB interchange header.

If you need group partners, consider oca/partner-contact/partner_company_group module.

Usage
=====


This module doesn't do anything useful by itself, but it is used by several other modules:

* *sale_order_import_edifact* that imports EDIFACT/D96A sale orders.

Changelog
=========


14.0.1.0.0 (2023-04-13)
~~~~~~~~~~~~~~~~~~~~~~~
Strong migration from 12.0.1.0.1 because it's not working for Amazon vendor orders.

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

Bugs are tracked on `GitHub Issues <https://github.com/OCA/edi/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 <https://github.com/OCA/edi/issues/new?body=module:%20base_edifact%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
~~~~~~~

* ALBA Software
* PlanetaTIC

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

* Rafa Morant <[email protected]> (www.albasoft.com)
* Marc Poch <[email protected]>

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-rmorant| image:: https://github.com/rmorant.png?size=40px
:target: https://github.com/rmorant
:alt: rmorant

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

|maintainer-rmorant|

This module is part of the `OCA/edi <https://github.com/OCA/edi/tree/14.0/base_edifact>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions base_edifact/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
29 changes: 29 additions & 0 deletions base_edifact/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright 2023 ALBA Software S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl-3.0)

{
"name": "Base EDIFACT",
"summary": "UN/EDIFACT/D96A utilities using pydifact parser",
"version": "14.0.1.0.0",
"development_status": "Alpha",
"category": "Tools",
"website": "https://github.com/OCA/edi",
"author": "ALBA Software, PlanetaTIC, Odoo Community Association (OCA)",
"maintainers": ["rmorant"],
"license": "AGPL-3",
"application": False,
"installable": True,
# "preloadable": True,
"external_dependencies": {
"python": ["pydifact"],
"bin": [],
},
"depends": [
# "edi_party_data_oca"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# "edi_party_data_oca"

# for configuration
"account",
"partner_identification",
"partner_identification_gln",
],
"data": [],
}
1 change: 1 addition & 0 deletions base_edifact/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import edifact
211 changes: 211 additions & 0 deletions base_edifact/models/edifact.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
import datetime
import logging

from pydifact.segmentcollection import Interchange, Message
from pydifact.segments import Segment

from odoo import _, api, exceptions, models

from odoo.addons.edi_party_data_oca.utils import get_party_data_component

logger = logging.getLogger(__name__)


# https://github.com/nerdocs/pydifact
class BasePydifact(models.AbstractModel):
_name = "base.edifact"
_description = "Generate and parse Edifact documents"

MAP_AGENCY_CODE_2_RES_PARTNER_NAMEREF = {"9": "gln"}
CURRENCY_SYMBOLS = {
"EUR": "€",
"USD": "$",
}
PRODUCT_CODE_TYPES = {"EN": "EAN", "UP": "UPC", "SRV": "GTIN"}

@api.model
def pydifact_import(self, names):
classes = {
"Segment": Segment,
"Message": Message,
"Interchange": Interchange,
}
return [classes.get(name, None) for name in names]

@api.model
def pydifact_obj(self, docu):
obj = []
interchange = self._loads_edifact(docu)
header_seg = interchange.get_header_segment()
header_dict = dict()
header_dict[header_seg.tag] = header_seg.elements
obj.append(header_dict)
for message in interchange.get_messages():
segms = []
msg = {
"reference_number": message.reference_number,
"type": message.type,
"version": message.version,
"identifier": message.identifier,
"HEADER_TAG": message.HEADER_TAG,
"FOOTER_TAG": message.FOOTER_TAG,
"characters": str(message.characters),
"extra_header_elements": message.extra_header_elements,
"has_una_segment": message.has_una_segment,
}
logger.info(message)
for segment in message.segments:
logger.info(
"Segment tag: {}, content: {}".format(segment.tag, segment.elements)
)
# segms.append((segment.tag, segment.elements))
seg = dict()
seg[segment.tag] = segment.elements
segms.append(seg)
msg["segments"] = segms
obj.append(msg)
return obj

@api.model
def get_party_data(self, exchange_record, partner, raise_if_not_found=True):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this must be dropped

provider = get_party_data_component(exchange_record, partner)
if not provider and raise_if_not_found:
raise exceptions.UserError(_("No info provider found for party data"))
return provider.get_party() if provider else None

@api.model
def _loads_edifact(self, order_file):
interchange = Interchange.from_str(order_file.decode())
return interchange

@api.model
def _get_msg_type(self, interchange):
seg = interchange.get_segment("UNH")
# MSG_TYPE, EDIFACT_MSG_TYPE_RELEASE
return (seg[1][0], "{}{}".format(seg[1][1], seg[1][2]))

@api.model
def map2odoo_date(self, dt):
# '102'
dtt = datetime.datetime.strptime(dt[1], "%Y%m%d")
return dtt.date()

@api.model
def map2odoo_partner(self, seg):
"""
BY. Party to which merchandise is sold.
NAD+BY+5550534000017::9'
NAD segment: ['BY', ['5550534001649', '', '9']]

SU. Party which manufactures or otherwise has possession of
goods,and consigns or makes them available in trade.
NAD+SU+<Supplier GLN>::9'
"""

partner_dict = {}
codes = ["BY", "SU"]
reference_code = seg[0]
if reference_code not in codes:
raise NotImplementedError(f"Code '{reference_code}' not implemented")
#
party_identification = seg[1]
party_id = party_identification[0]
agency_code = party_identification[2]
nameref = self.MAP_AGENCY_CODE_2_RES_PARTNER_NAMEREF.get(agency_code, "gln")
partner_dict[nameref] = party_id
return partner_dict

@api.model
def map2odoo_address(self, seg):
"""
DP. Party to which goods should be delivered, if not identical with
consignee.
NAD+DP+5550534000086::9+++++++DE'
NAD segment: ['DP', ['5550534022101', '', '9'], '', '', '', '', '', '', 'ES']
IV. Party to whom an invoice is issued.
NAD+IV+5450534005838::9++AMAZON EU SARL:NIEDERLASSUNG
DEUTSCHLAND+MARCEL-BREUER-STR. 12+MUENCHEN++80807+DE

:returns: {
'type':
'partner': {'gln':''}
'address': {...}
}
"""
if seg[0] not in ("DP", "IV"):
return False
order_type = "delivery" if seg[0] == "DP" else "invoice"
address = dict(type=order_type, partner={}, address={})
# PARTY IDENTIFICATION DETAILS
iden = seg[1]
party_id = iden[0]
agency_code = iden[2]
nameref = self.MAP_AGENCY_CODE_2_RES_PARTNER_NAMEREF.get(agency_code, "gln")
address["partner"][nameref] = party_id
d = address["address"]
# PARTY NAME
if bool(seg[2]):
d["name"] = seg[2]
if bool(seg[3]):
d["name"] = "{}{}".format(f"{d['name']}. " if d.get("name") else "", seg[3])
if bool(seg[4]):
# Street address and/or PO Box number in a structured address: one to three lines.
d["street"] = seg[4]
if bool(seg[5]):
d["city"] = seg[5]
if bool(seg[6]):
# Country sub-entity identification
d["state_code"] = seg[6]
if bool(seg[7]):
d["zip"] = seg[7]
if bool(seg[8]):
# Country, coded ISO 3166
d["country_code"] = seg[8]

return address

@api.model
def map2odoo_currency(self, seg):
"""
['2', 'EUR', '9']
"""
# Identification of the name or symbol of the monetary unit involved in the transaction.
currency_coded = seg[1]
return {
"iso": currency_coded,
"symbol": self.CURRENCY_SYMBOLS.get(currency_coded, False),
}

@api.model
def map2odoo_product(self, seg):
"""
:seg: LIN segment
['1', '', ['8885583503464', 'EN']]
EN. International Article Numbering Association (EAN)
UP. UPC (Universal product code)
SRV. GTIN
"""
product = seg[2]
pct = product[1]
return dict(code=product[0]) if pct == "SRV" else dict(barcode=product[0])

@api.model
def map2odoo_qty(self, seg):
"""
'QTY' EDI segment: [['21', '2']]
'21'. Ordered quantity
"""
return float(seg[0][1])

@api.model
def map2odoo_unit_price(self, seg):
"""
'PRI' EDI segment: [['AAA', '19.75']]
Price qualifier:
* 'AAA'. Calculation net
* 'AAB'. Calculation gross
"""
pri = seg[0]
if pri[0] == "AAA":
return float(pri[1])
return 0.0
12 changes: 12 additions & 0 deletions base_edifact/readme/CONFIGURE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Requires partner_identification_gln module to store GLN identifiers.

Partner identification code assigned by the European Article Numbering Association.

Use two identification categories:

- "GLN Identificatin Number". Partner identification like invoice or delivery address.
- "GCP Identification Number". Global Company Prefix.

If GCP codes are needed in UNB interchange header.

If you need group partners, consider oca/partner-contact/partner_company_group module.
2 changes: 2 additions & 0 deletions base_edifact/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* Rafa Morant <[email protected]> (www.albasoft.com)
* Marc Poch <[email protected]>
2 changes: 2 additions & 0 deletions base_edifact/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

This module contains methods to generate and parse EDIFACT/D96A files
4 changes: 4 additions & 0 deletions base_edifact/readme/HISTORY.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

14.0.1.0.0 (2023-04-13)
~~~~~~~~~~~~~~~~~~~~~~~
Strong migration from 12.0.1.0.1 because it's not working for Amazon vendor orders.
Loading