Skip to content

Commit

Permalink
[IMP] sale_order_import: Refactor code
Browse files Browse the repository at this point in the history
- Add new selection import_type field for choosing the type to import
- Refactor _parse_file with import_type field
- Drop some not used method
  • Loading branch information
duongtq committed Oct 11, 2023
1 parent 7c521b5 commit 9e50719
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 47 deletions.
4 changes: 2 additions & 2 deletions sale_order_import/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Sale Order Import
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:e3c79f24ecddeae7a12a7de67704f56172423d44b38860a1f98afa12c30874d1
!! source digest: sha256:6158db44a0c9ba1d51e23d0d194d07db117c482df78965721739bdcab5138705
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
Expand All @@ -28,7 +28,7 @@ Sale Order Import

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

This module adds support for the import of electronic RFQ or orders. This module provides the base methods to import electronic orders ; it requires additional modules to support specific order formats:
This module adds support for the import of electronic RFQ or orders. This module provides the base methods to import electronic orders, and you can also plug additional formats by extending the wizard. It requires additional modules to support specific order formats:


* module *sale_order_import_ubl*: adds support for `Universal Business Language (UBL) <http://ubl.xml.org/>`_ RFQs and orders as:
Expand Down
5 changes: 2 additions & 3 deletions sale_order_import/models/sale.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ def name_get(self):
new_res = []
for (sale_id, name) in res:
sale = self.browse(sale_id)
# I didn't find a python method to easily display
# a float + currency symbol (before or after)
# depending on lang of context and currency
# TODO: find a python method to easily display a float + currency
# symbol (before or after) depending on lang of context and currency
name += _(
" Amount w/o tax: %(amount)s %(currency)s",
amount=sale.amount_untaxed,
Expand Down
2 changes: 1 addition & 1 deletion sale_order_import/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
This module adds support for the import of electronic RFQ or orders. This module provides the base methods to import electronic orders ; it requires additional modules to support specific order formats:
This module adds support for the import of electronic RFQ or orders. This module provides the base methods to import electronic orders, and you can also plug additional formats by extending the wizard. It requires additional modules to support specific order formats:


* module *sale_order_import_ubl*: adds support for `Universal Business Language (UBL) <http://ubl.xml.org/>`_ RFQs and orders as:
Expand Down
4 changes: 2 additions & 2 deletions sale_order_import/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -367,10 +367,10 @@ <h1 class="title">Sale Order Import</h1>
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:e3c79f24ecddeae7a12a7de67704f56172423d44b38860a1f98afa12c30874d1
!! source digest: sha256:6158db44a0c9ba1d51e23d0d194d07db117c482df78965721739bdcab5138705
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/edi/tree/16.0/sale_order_import"><img alt="OCA/edi" src="https://img.shields.io/badge/github-OCA%2Fedi-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/edi-16-0/edi-16-0-sale_order_import"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runboat.odoo-community.org/builds?repo=OCA/edi&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module adds support for the import of electronic RFQ or orders. This module provides the base methods to import electronic orders ; it requires additional modules to support specific order formats:</p>
<p>This module adds support for the import of electronic RFQ or orders. This module provides the base methods to import electronic orders, and you can also plug additional formats by extending the wizard. It requires additional modules to support specific order formats:</p>
<ul class="simple">
<li>module <em>sale_order_import_ubl</em>: adds support for <a class="reference external" href="http://ubl.xml.org/">Universal Business Language (UBL)</a> RFQs and orders as:<ul>
<li>XML file,</li>
Expand Down
29 changes: 17 additions & 12 deletions sale_order_import/tests/test_parse_validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,22 @@
class TestParsingValidation(TestCommon):
"""Mostly unit tests on wizard parsing methods."""

def test_onchange_validation_not_supported(self):
# Just test is not broken
self.assertTrue(self.wiz_model._unsupported_file_msg("fname.omg"))
# Test it gets called (cannot do it w/ Form)
mock_file_msg = mock.patch.object(type(self.wiz_model), "_unsupported_file_msg")
with mock_file_msg as mocked:
def test_wrong_import_type(self):
order_file_data = base64.b64encode(
b"<?xml version='1.0' encoding='utf-8'?><root><foo>baz</foo></root>"
)
order_filename = "test_order.xml"
expected_error_message = (
"This file 'test_order.xml' is not recognized as"
" a PDF file. Please check the file and its extension."
)

with self.assertRaisesRegex(exceptions.UserError, expected_error_message):
with Form(
self.wiz_model.with_context(default_order_filename="test.omg")
self.wiz_model.with_context(default_order_filename=order_filename)
) as form:
form.order_file = "00100000"
self.assertFalse(form.doc_type)
mocked.assert_called()
form.import_type = "pdf"
form.order_file = order_file_data

def test_onchange_validation_xml(self):
xml_data = base64.b64encode(
Expand All @@ -44,6 +48,7 @@ def test_onchange_validation_xml(self):
with self.assertRaisesRegex(
exceptions.UserError, "I don't like this file"
):
form.import_type = "xml"
form.order_file = xml_data
mocked.assert_called()

Expand All @@ -54,6 +59,7 @@ def test_onchange_validation_xml(self):
) as form:
with mock_parse_order as mocked:
mocked.return_value = "rfq"
form.import_type = "xml"
form.order_file = xml_data
mocked.assert_called()
self.assertEqual(form.doc_type, "rfq")
Expand All @@ -67,6 +73,7 @@ def test_onchange_validation_pdf(self):
) as form:
with mock_parse_order as mocked:
mocked.return_value = "rfq"
form.import_type = "pdf"
form.order_file = pdf_data
mocked.assert_called()
self.assertEqual(form.doc_type, "rfq")
Expand All @@ -84,12 +91,10 @@ def test_parse_xml_unsupported(self):
xml_root, error_msg = self.wiz_model._parse_xml(xml_data)
self.assertTrue(isinstance(xml_root, etree._Element))
# Due to parse_xml_order NotImplementedError
self.assertEqual(error_msg, "Unsupported XML document")
mock_parse_order = mock.patch.object(type(self.wiz_model), "parse_xml_order")
with mock_parse_order as mocked:
mocked.side_effect = exceptions.UserError("I don't like this file")
self.assertTrue(isinstance(xml_root, etree._Element))
self.assertEqual(error_msg, "Unsupported XML document")

def test_parse_xml_good(self):
xml_data = b"<?xml version='1.0' encoding='utf-8'?><root><foo>baz</foo></root>"
Expand Down
75 changes: 49 additions & 26 deletions sale_order_import/wizard/sale_order_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ class SaleOrderImport(models.TransientModel):
[("import", "Import"), ("update", "Update")], default="import"
)
partner_id = fields.Many2one("res.partner", string="Customer")
import_type = fields.Selection(
[("xml", "XML"), ("pdf", "PDF")],
required=True,
default=None,
help="Select a type which you want to import",
)
order_file = fields.Binary(
string="Request for Quotation or Order",
required=True,
Expand Down Expand Up @@ -62,28 +68,48 @@ def order_file_change(self):
)
if doc_type is None:
return {"warning": self._unsupported_file_msg(self.order_filename)}
# I would expect to set doc_type = csv here
self.doc_type = doc_type

def _get_supported_types(self):
# Define the supported types dictionary
supported_types = {
"xml": ("application/xml", "text/xml"),
"pdf": ("application/pdf"),
}
return supported_types

def _parse_file(self, filename, filecontent, detect_doc_type=False):
assert filename, "Missing filename"
assert filecontent, "Missing file content"
filetype = mimetypes.guess_type(filename)
logger.debug("Order file mimetype: %s", filetype)
mimetype = filetype[0]
supported_types = {
"XML": ("application/xml", "text/xml"),
"PDF": ("application/pdf"),
}
res = None
if filetype and mimetype in supported_types["XML"]:
xml_root, error_msg = self._parse_xml(filecontent)
if (xml_root is None or not len(xml_root)) and error_msg:
raise UserError(error_msg)
res = self.parse_xml_order(xml_root, detect_doc_type=detect_doc_type)
elif filetype and mimetype == supported_types["PDF"]:
res = self.parse_pdf_order(filecontent, detect_doc_type=detect_doc_type)
return res
supported_types = self._get_supported_types()
# Check if the selected import type is supported
if self.import_type not in supported_types:
raise UserError(_("Please select a valid import type before importing!"))

# Check if the detected MIME type is supported for the selected import type
if mimetype not in supported_types[self.import_type]:
raise UserError(
_(
"This file '%(filename)s' is not recognized as a %(type)s file. "
"Please check the file and its extension.",
filename=filename,
type=self.import_type.upper(),
)
)
if hasattr(self, "parse_%s_order" % self.import_type):
return getattr(self, "parse_%s_order" % self.import_type)(
filecontent, detect_doc_type=detect_doc_type
)
else:
raise UserError(
_(
"This Import Type is not supported. Did you install "
"the module to support this type?"
)
)

def _unsupported_file_msg(self, filename):
return {
Expand All @@ -107,27 +133,24 @@ def _parse_xml(self, data):
except etree.XMLSyntaxError:
error_msg = _("This XML file is not XML-compliant")
return xml_root, error_msg
try:
self.parse_xml_order(xml_root, detect_doc_type=True)
except (UserError, NotImplementedError):
error_msg = _("Unsupported XML document")
return xml_root, error_msg

# FIXME: not used at all
@api.model
def get_xml_doc_type(self, xml_root): # pragma: no cover
raise UserError

@api.model
def parse_xml_order(self, xml_root, detect_doc_type=False):
def parse_xml_order(self, data, detect_doc_type=False):
if not self.env.context.get("xml_root", False):
xml_root, error_msg = self._parse_xml(data)
else:
xml_root = data
error_msg = None
if (xml_root is None or not len(xml_root)) and error_msg:
raise UserError(error_msg)
raise NotImplementedError(
_(
"This type of XML RFQ/order is not supported. Did you install "
"the module to support this XML format?"
)
)

# TODO: move it out to a PDF support module
@api.model
def parse_pdf_order(self, order_file, detect_doc_type=False):
"""
Expand All @@ -139,7 +162,7 @@ def parse_pdf_order(self, order_file, detect_doc_type=False):
for xml_filename, xml_root in xml_files_dict.items():
logger.info("Trying to parse XML file %s", xml_filename)
try:
parsed_order = self.parse_xml_order(
parsed_order = self.with_context(xml_root=True).parse_xml_order(
xml_root, detect_doc_type=detect_doc_type
)
return parsed_order
Expand Down
7 changes: 6 additions & 1 deletion sale_order_import/wizard/sale_order_import_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@
</div>
</group>
<group name="import" states="import">
<field name="order_file" filename="order_filename" />
<field name="import_type" />
<field
name="order_file"
filename="order_filename"
attrs="{'readonly': [('import_type', '=', False)]}"
/>
<field name="order_filename" invisible="1" />
</group>
<group name="update" states="update">
Expand Down

0 comments on commit 9e50719

Please sign in to comment.