diff --git a/purchase_order_ubl/README.rst b/purchase_order_ubl/README.rst new file mode 100644 index 0000000000..7da3479fae --- /dev/null +++ b/purchase_order_ubl/README.rst @@ -0,0 +1,89 @@ +================== +Purchase Order UBL +================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:2adc2a9795184986db36eb47cd81791eabe7a76238dbe21733ca894d81d7470a + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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-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/16.0/purchase_order_ubl + :alt: OCA/edi +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/edi-16-0/edi-16-0-purchase_order_ubl + :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=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds support for UBL, the `Universal Business Language (UBL) `_ standard, +on purchase orders. The UBL 2.1 standard became the +`ISO/IEC 19845 `_ standard +in December 2015 (cf the `official announce `_). + +With this module, when you generate the purchase order or RFQ report: + +* on a draft/RFQ/Bid Received purchase order, the PDF file will have an embedded XML *Request For Quotation* file compliant with the UBL 2.1 or 2.0 standard. + +* on an approved purchase order, the PDF file will have an embedded XML *Order* file compliant with the UBL 2.1 or 2.0 standard. + +If your supplier has Odoo and has installed the module *sale_order_import_ubl*, he will be able to import the PDF file and it will automatically create the quotation/sale order. + +**Table of contents** + +.. contents:: + :local: + +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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Akretion + +Contributors +~~~~~~~~~~~~ + +* Alexis de Lattre +* Andrea Stirpe +* Robin Conjour + +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/purchase_order_ubl/__init__.py b/purchase_order_ubl/__init__.py new file mode 100644 index 0000000000..31660d6a96 --- /dev/null +++ b/purchase_order_ubl/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import models diff --git a/purchase_order_ubl/__manifest__.py b/purchase_order_ubl/__manifest__.py new file mode 100644 index 0000000000..70984b9ff8 --- /dev/null +++ b/purchase_order_ubl/__manifest__.py @@ -0,0 +1,14 @@ +# © 2016-2017 Akretion (Alexis de Lattre ) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Purchase Order UBL", + "version": "16.0.1.1.0", + "category": "Purchase Management", + "license": "AGPL-3", + "summary": "Embed UBL XML file inside the PDF purchase order", + "author": "Akretion,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/edi", + "depends": ["purchase", "base_ubl"], + "installable": True, +} diff --git a/purchase_order_ubl/i18n/fr.po b/purchase_order_ubl/i18n/fr.po new file mode 100644 index 0000000000..3b8a3a2a57 --- /dev/null +++ b/purchase_order_ubl/i18n/fr.po @@ -0,0 +1,45 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_order_ubl +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-06-17 15:48+0000\n" +"Last-Translator: Yves Le Doeuff \n" +"Language-Team: none\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: purchase_order_ubl +#: model:ir.model.fields,field_description:purchase_order_ubl.field_ir_actions_report__display_name +#: model:ir.model.fields,field_description:purchase_order_ubl.field_purchase_order__display_name +msgid "Display Name" +msgstr "" + +#. module: purchase_order_ubl +#: model:ir.model.fields,field_description:purchase_order_ubl.field_ir_actions_report__id +#: model:ir.model.fields,field_description:purchase_order_ubl.field_purchase_order__id +msgid "ID" +msgstr "ID" + +#. module: purchase_order_ubl +#: model:ir.model.fields,field_description:purchase_order_ubl.field_ir_actions_report____last_update +#: model:ir.model.fields,field_description:purchase_order_ubl.field_purchase_order____last_update +msgid "Last Modified on" +msgstr "Dernière modification le" + +#. module: purchase_order_ubl +#: model:ir.model,name:purchase_order_ubl.model_purchase_order +msgid "Purchase Order" +msgstr "Commande d'achat" + +#. module: purchase_order_ubl +#: model:ir.model,name:purchase_order_ubl.model_ir_actions_report +msgid "Report Action" +msgstr "" diff --git a/purchase_order_ubl/i18n/purchase_order_ubl.pot b/purchase_order_ubl/i18n/purchase_order_ubl.pot new file mode 100644 index 0000000000..5288ebb5d2 --- /dev/null +++ b/purchase_order_ubl/i18n/purchase_order_ubl.pot @@ -0,0 +1,42 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_order_ubl +# +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: purchase_order_ubl +#: model:ir.model.fields,field_description:purchase_order_ubl.field_ir_actions_report__display_name +#: model:ir.model.fields,field_description:purchase_order_ubl.field_purchase_order__display_name +msgid "Display Name" +msgstr "" + +#. module: purchase_order_ubl +#: model:ir.model.fields,field_description:purchase_order_ubl.field_ir_actions_report__id +#: model:ir.model.fields,field_description:purchase_order_ubl.field_purchase_order__id +msgid "ID" +msgstr "" + +#. module: purchase_order_ubl +#: model:ir.model.fields,field_description:purchase_order_ubl.field_ir_actions_report____last_update +#: model:ir.model.fields,field_description:purchase_order_ubl.field_purchase_order____last_update +msgid "Last Modified on" +msgstr "" + +#. module: purchase_order_ubl +#: model:ir.model,name:purchase_order_ubl.model_purchase_order +msgid "Purchase Order" +msgstr "" + +#. module: purchase_order_ubl +#: model:ir.model,name:purchase_order_ubl.model_ir_actions_report +msgid "Report Action" +msgstr "" diff --git a/purchase_order_ubl/models/__init__.py b/purchase_order_ubl/models/__init__.py new file mode 100644 index 0000000000..0dbc3142e1 --- /dev/null +++ b/purchase_order_ubl/models/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import purchase +from . import report diff --git a/purchase_order_ubl/models/purchase.py b/purchase_order_ubl/models/purchase.py new file mode 100644 index 0000000000..c87af9378f --- /dev/null +++ b/purchase_order_ubl/models/purchase.py @@ -0,0 +1,270 @@ +# © 2016-2017 Akretion (Alexis de Lattre ) +# Copyright 2020 Onestein () +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import logging + +from lxml import etree + +from odoo import api, fields, models + +logger = logging.getLogger(__name__) + + +class PurchaseOrder(models.Model): + _name = "purchase.order" + _inherit = ["purchase.order", "base.ubl"] + + @api.model + def get_rfq_states(self): + return ["draft", "sent", "to approve"] + + @api.model + def get_order_states(self): + return ["purchase", "done"] + + def _ubl_add_header(self, doc_type, parent_node, ns, version="2.1"): + if doc_type == "rfq": + now_utc = fields.Datetime.to_string(fields.Datetime.now()) + date = now_utc[:10] + time = now_utc[11:] + currency_node_name = "PricingCurrencyCode" + elif doc_type == "order": + date = self.date_approve or self.date_order + date = fields.Date.to_string(date) + currency_node_name = "DocumentCurrencyCode" + ubl_version = etree.SubElement(parent_node, ns["cbc"] + "UBLVersionID") + ubl_version.text = version + doc_id = etree.SubElement(parent_node, ns["cbc"] + "ID") + doc_id.text = self.name + issue_date = etree.SubElement(parent_node, ns["cbc"] + "IssueDate") + issue_date.text = date + if doc_type == "rfq": # IssueTime is required on RFQ, not on order + issue_time = etree.SubElement(parent_node, ns["cbc"] + "IssueTime") + issue_time.text = time + if self.notes: + note = etree.SubElement(parent_node, ns["cbc"] + "Note") + note.text = self.notes + doc_currency = etree.SubElement(parent_node, ns["cbc"] + currency_node_name) + doc_currency.text = self.currency_id.name + + def _ubl_add_monetary_total(self, parent_node, ns, version="2.1"): + monetary_total = etree.SubElement( + parent_node, ns["cac"] + "AnticipatedMonetaryTotal" + ) + line_total = etree.SubElement( + monetary_total, + ns["cbc"] + "LineExtensionAmount", + currencyID=self.currency_id.name, + ) + line_total.text = str(self.amount_untaxed) + payable_amount = etree.SubElement( + monetary_total, + ns["cbc"] + "PayableAmount", + currencyID=self.currency_id.name, + ) + payable_amount.text = str(self.amount_total) + + def _ubl_add_rfq_line(self, parent_node, oline, line_number, ns, version="2.1"): + line_root = etree.SubElement(parent_node, ns["cac"] + "RequestForQuotationLine") + self._ubl_add_line_item( + line_number, + oline.name, + oline.product_id, + "purchase", + oline.product_qty, + oline.product_uom, + line_root, + ns, + seller=self.partner_id.commercial_partner_id, + version=version, + ) + + def _ubl_add_order_line(self, parent_node, oline, line_number, ns, version="2.1"): + line_root = etree.SubElement(parent_node, ns["cac"] + "OrderLine") + dpo = self.env["decimal.precision"] + qty_precision = dpo.precision_get("Product Unit of Measure") + price_precision = dpo.precision_get("Product Price") + self._ubl_add_line_item( + line_number, + oline.name, + oline.product_id, + "purchase", + oline.product_qty, + oline.product_uom, + line_root, + ns, + seller=self.partner_id.commercial_partner_id, + currency=self.currency_id, + price_subtotal=oline.price_subtotal, + qty_precision=qty_precision, + price_precision=price_precision, + version=version, + ) + + def get_delivery_partner(self): + self.ensure_one() + if self.dest_address_id: + return self.dest_address_id + return self.company_id.partner_id + + def generate_rfq_ubl_xml_etree(self, version="2.1"): + nsmap, ns = self._ubl_get_nsmap_namespace( + "RequestForQuotation-2", version=version + ) + xml_root = etree.Element("RequestForQuotation", nsmap=nsmap) + doc_type = "rfq" + self._ubl_add_header(doc_type, xml_root, ns, version=version) + + # The order of SellerSupplierParty / BuyerCustomerParty is different + # between RFQ and Order ! + self._ubl_add_supplier_party( + self.partner_id, False, "SellerSupplierParty", xml_root, ns, version=version + ) + if version == "2.1": + self._ubl_add_customer_party( + False, + self.company_id, + "BuyerCustomerParty", + xml_root, + ns, + version=version, + ) + delivery_partner = self.get_delivery_partner() + self._ubl_add_delivery(delivery_partner, xml_root, ns, version=version) + if self.incoterm_id: + self._ubl_add_delivery_terms( + self.incoterm_id, xml_root, ns, version=version + ) + + for oline in self.order_line: + # line_number as third arg comes from purchase.order.line id field + # see https://github.com/OCA/edi/issues/300 + self._ubl_add_rfq_line(xml_root, oline, oline.id, ns, version=version) + return xml_root + + def generate_order_ubl_xml_etree(self, version="2.1"): + nsmap, ns = self._ubl_get_nsmap_namespace("Order-2", version=version) + xml_root = etree.Element("Order", nsmap=nsmap) + doc_type = "order" + self._ubl_add_header(doc_type, xml_root, ns, version=version) + + self._ubl_add_customer_party( + False, self.company_id, "BuyerCustomerParty", xml_root, ns, version=version + ) + self._ubl_add_supplier_party( + self.partner_id, False, "SellerSupplierParty", xml_root, ns, version=version + ) + delivery_partner = self.get_delivery_partner() + self._ubl_add_delivery(delivery_partner, xml_root, ns, version=version) + if self.incoterm_id: + self._ubl_add_delivery_terms( + self.incoterm_id, xml_root, ns, version=version + ) + if self.payment_term_id: + self._ubl_add_payment_terms( + self.payment_term_id, xml_root, ns, version=version + ) + self._ubl_add_monetary_total(xml_root, ns, version=version) + + for oline in self.order_line: + # line_number as third arg comes from purchase.order.line id field + # see https://github.com/OCA/edi/issues/300 + self._ubl_add_order_line(xml_root, oline, oline.id, ns, version=version) + return xml_root + + def generate_ubl_xml_string(self, doc_type, version="2.1"): + """Provide UBL Xml string with no check + According to your use check this string integrity with + _ubl_check_xml_schema() method + """ + self.ensure_one() + xml_root = self.get_ubl_xml_etree(doc_type, version=version) + xml_string = etree.tostring( + xml_root, pretty_print=True, encoding="UTF-8", xml_declaration=True + ) + logger.debug( + "%s UBL XML file generated for purchase order ID %d (state %s)", + doc_type, + self.id, + self.state, + ) + logger.debug(xml_string) + return xml_string + + def get_ubl_xml_etree(self, doc_type, version="2.1"): + self.ensure_one() + assert doc_type in ("order", "rfq"), "wrong doc_type" + logger.debug("Starting to generate UBL XML %s file", doc_type) + lang = self.get_ubl_lang() + # The aim of injecting lang in context + # is to have the content of the XML in the partner's lang + # but the problem is that the error messages will also be in + # that lang. But the error messages should almost never + # happen except the first days of use, so it's probably + # not worth the additional code to handle the 2 langs + if doc_type == "order": + xml_root = self.with_context(lang=lang).generate_order_ubl_xml_etree( + version=version + ) + elif doc_type == "rfq": + xml_root = self.with_context(lang=lang).generate_rfq_ubl_xml_etree( + version=version + ) + return xml_root + + def get_document_name(self, doc_type): + document = False + if doc_type == "order": + document = "Order" + elif doc_type == "rfq": + document = "RequestForQuotation" + return document + + def get_ubl_filename(self, doc_type, version="2.1"): + """This method is designed to be inherited""" + if doc_type == "rfq": + return "UBL-RequestForQuotation-%s.xml" % version + elif doc_type == "order": + return "UBL-Order-%s.xml" % version + + def get_ubl_version(self): + return self.env.context.get("ubl_version", "2.1") + + def get_ubl_lang(self): + self.ensure_one() + return self.partner_id.lang or "en_US" + + def add_xml_in_pdf_buffer(self, buffer): + self.ensure_one() + doc_type = self.get_ubl_purchase_order_doc_type() + if doc_type: + version = self.get_ubl_version() + xml_filename = self.get_ubl_filename(doc_type, version=version) + xml_string = self.generate_ubl_xml_string(doc_type, version=version) + buffer = self._ubl_add_xml_in_pdf_buffer(xml_string, xml_filename, buffer) + return buffer + + def embed_ubl_xml_in_pdf(self, pdf_content, pdf_file=None): + self.ensure_one() + doc_type = self.get_ubl_purchase_order_doc_type() + if doc_type: + version = self.get_ubl_version() + xml_filename = self.get_ubl_filename(doc_type, version=version) + xml_string = self.generate_ubl_xml_string(doc_type, version=version) + self._ubl_check_xml_schema( + xml_string, self.get_document_name(doc_type), version=version + ) + pdf_content = self.embed_xml_in_pdf( + xml_string, xml_filename, pdf_content=pdf_content, pdf_file=pdf_file + ) + return pdf_content + + def get_ubl_purchase_order_doc_type(self): + self.ensure_one() + doc_type = False + if self.state in self.get_rfq_states(): + doc_type = "rfq" + elif self.state in self.get_order_states(): + doc_type = "order" + return doc_type diff --git a/purchase_order_ubl/models/report.py b/purchase_order_ubl/models/report.py new file mode 100644 index 0000000000..c22737b095 --- /dev/null +++ b/purchase_order_ubl/models/report.py @@ -0,0 +1,51 @@ +# © 2016-2017 Akretion (Alexis de Lattre ) +# Copyright 2020 Onestein () +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models + + +class IrActionsReport(models.Model): + _inherit = "ir.actions.report" + + def _render_qweb_pdf_prepare_streams(self, report_ref, data, res_ids=None): + collected_streams = super()._render_qweb_pdf_prepare_streams( + report_ref, data, res_ids + ) + if res_ids: + report_sudo = self._get_report(report_ref) + if report_sudo.is_ubl_xml_to_embed_in_purchase_order(): + records = self.env[report_sudo.model].browse(res_ids) + for record in records: + collected_streams[record.id][ + "stream" + ] = record.add_xml_in_pdf_buffer( + collected_streams[record.id]["stream"] + ) + return collected_streams + + def _render_qweb_pdf(self, report_ref, res_ids=None, data=None): + """ + This is only necessary when tests are enabled. + It forces the creation of pdf instead of html.""" + # Even if not expected, we might get an ID. + # Eg https://github.com/odoo/odoo/blob/10378872eddd6037f479fa8cbb3ed65d5e4b52c6 + # /addons/account/models/account_bank_statement.py#L440 + if ( + isinstance(res_ids, int) + or len(res_ids or []) == 1 + and not self.env.context.get("no_embedded_ubl_xml") + ): + if self._get_report(report_ref).is_ubl_xml_to_embed_in_purchase_order(): + self = self.with_context(force_report_rendering=True) + return super()._render_qweb_pdf(report_ref, res_ids, data) + + def is_ubl_xml_to_embed_in_purchase_order(self): + return ( + self.model == "purchase.order" + and not self.env.context.get("no_embedded_ubl_xml") + and self.report_name in self._get_purchase_order_ubl_reports() + ) + + def _get_purchase_order_ubl_reports(self): + return ["purchase.report_purchaseorder", "purchase.report_purchasequotation"] diff --git a/purchase_order_ubl/readme/CONTRIBUTORS.rst b/purchase_order_ubl/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..8517a66d92 --- /dev/null +++ b/purchase_order_ubl/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* Alexis de Lattre +* Andrea Stirpe +* Robin Conjour diff --git a/purchase_order_ubl/readme/DESCRIPTION.rst b/purchase_order_ubl/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..5b03aa7b56 --- /dev/null +++ b/purchase_order_ubl/readme/DESCRIPTION.rst @@ -0,0 +1,12 @@ +This module adds support for UBL, the `Universal Business Language (UBL) `_ standard, +on purchase orders. The UBL 2.1 standard became the +`ISO/IEC 19845 `_ standard +in December 2015 (cf the `official announce `_). + +With this module, when you generate the purchase order or RFQ report: + +* on a draft/RFQ/Bid Received purchase order, the PDF file will have an embedded XML *Request For Quotation* file compliant with the UBL 2.1 or 2.0 standard. + +* on an approved purchase order, the PDF file will have an embedded XML *Order* file compliant with the UBL 2.1 or 2.0 standard. + +If your supplier has Odoo and has installed the module *sale_order_import_ubl*, he will be able to import the PDF file and it will automatically create the quotation/sale order. diff --git a/purchase_order_ubl/static/description/icon.png b/purchase_order_ubl/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/purchase_order_ubl/static/description/icon.png differ diff --git a/purchase_order_ubl/static/description/index.html b/purchase_order_ubl/static/description/index.html new file mode 100644 index 0000000000..cafd89e8da --- /dev/null +++ b/purchase_order_ubl/static/description/index.html @@ -0,0 +1,432 @@ + + + + + + +Purchase Order UBL + + + +
+

Purchase Order UBL

+ + +

Beta License: AGPL-3 OCA/edi Translate me on Weblate Try me on Runboat

+

This module adds support for UBL, the Universal Business Language (UBL) standard, +on purchase orders. The UBL 2.1 standard became the +ISO/IEC 19845 standard +in December 2015 (cf the official announce).

+

With this module, when you generate the purchase order or RFQ report:

+
    +
  • on a draft/RFQ/Bid Received purchase order, the PDF file will have an embedded XML Request For Quotation file compliant with the UBL 2.1 or 2.0 standard.
  • +
  • on an approved purchase order, the PDF file will have an embedded XML Order file compliant with the UBL 2.1 or 2.0 standard.
  • +
+

If your supplier has Odoo and has installed the module sale_order_import_ubl, he will be able to import the PDF file and it will automatically create the quotation/sale order.

+

Table of contents

+ +
+

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 to smash it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Akretion
  • +
+
+
+

Contributors

+ +
+
+

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/purchase_order_ubl/tests/__init__.py b/purchase_order_ubl/tests/__init__.py new file mode 100644 index 0000000000..895163754b --- /dev/null +++ b/purchase_order_ubl/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import test_ubl_generate diff --git a/purchase_order_ubl/tests/test_ubl_generate.py b/purchase_order_ubl/tests/test_ubl_generate.py new file mode 100644 index 0000000000..971df19679 --- /dev/null +++ b/purchase_order_ubl/tests/test_ubl_generate.py @@ -0,0 +1,27 @@ +# © 2016-2017 Akretion (Alexis de Lattre ) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.tests.common import HttpCase + + +class TestUblOrder(HttpCase): + def test_ubl_generate(self): + ro = self.env["ir.actions.report"] + poo = self.env["purchase.order"] + buo = self.env["base.ubl"] + order_states = poo.get_order_states() + rfq_states = poo.get_rfq_states() + for i in range(7): + i += 1 + order = self.env.ref("purchase.purchase_order_%d" % i) + for version in ["2.0", "2.1"]: + pdf_file = ro.with_context( + ubl_version=version, force_report_rendering=True + )._render_qweb_pdf("purchase.report_purchase_quotation", order.ids)[0] + res = buo.get_xml_files_from_pdf(pdf_file) + if order.state in order_states: + filename = order.get_ubl_filename("order", version=version) + self.assertTrue(filename in res) + elif order.state in rfq_states: + filename = order.get_ubl_filename("rfq", version=version) + self.assertTrue(filename in res) diff --git a/setup/purchase_order_ubl/odoo/addons/purchase_order_ubl b/setup/purchase_order_ubl/odoo/addons/purchase_order_ubl new file mode 120000 index 0000000000..c5a0ee1778 --- /dev/null +++ b/setup/purchase_order_ubl/odoo/addons/purchase_order_ubl @@ -0,0 +1 @@ +../../../../purchase_order_ubl \ No newline at end of file diff --git a/setup/purchase_order_ubl/setup.py b/setup/purchase_order_ubl/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/purchase_order_ubl/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)