trytond-edocument-ubl 8.0.3__tar.gz → 8.0.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/PKG-INFO +2 -2
  2. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/edocument.py +50 -29
  3. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/scenario_ubl_2_credit_note_parse.rst +1 -1
  4. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/scenario_ubl_2_invoice_parse.rst +1 -1
  5. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tryton.cfg +1 -1
  6. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/.hgignore +0 -0
  7. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/COPYRIGHT +0 -0
  8. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/LICENSE +0 -0
  9. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/__init__.py +0 -0
  10. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/account.py +0 -0
  11. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/account.xml +0 -0
  12. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/document.py +0 -0
  13. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/exceptions.py +0 -0
  14. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/icons/LICENSE +0 -0
  15. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/bg.po +0 -0
  16. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/ca.po +0 -0
  17. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/cs.po +0 -0
  18. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/de.po +0 -0
  19. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/es.po +0 -0
  20. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/es_419.po +0 -0
  21. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/et.po +0 -0
  22. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/fa.po +0 -0
  23. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/fi.po +0 -0
  24. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/fr.po +0 -0
  25. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/hu.po +0 -0
  26. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/id.po +0 -0
  27. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/it.po +0 -0
  28. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/lo.po +0 -0
  29. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/lt.po +0 -0
  30. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/nl.po +0 -0
  31. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/pl.po +0 -0
  32. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/pt.po +0 -0
  33. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/ro.po +0 -0
  34. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/ru.po +0 -0
  35. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/sl.po +0 -0
  36. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/tr.po +0 -0
  37. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/uk.po +0 -0
  38. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/locale/zh_CN.po +0 -0
  39. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/message.xml +0 -0
  40. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/party.py +0 -0
  41. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/pyproject.toml +0 -0
  42. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/template/2/CreditNote.xml +0 -0
  43. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/template/2/Invoice.xml +0 -0
  44. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/template/2/base.xml +0 -0
  45. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/common/BDNDR-CCTS_CCT_SchemaModule-1.1.xsd +0 -0
  46. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/common/BDNDR-UnqualifiedDataTypes-1.1.xsd +0 -0
  47. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/common/UBL-CommonAggregateComponents-2.4.xsd +0 -0
  48. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/common/UBL-CommonBasicComponents-2.4.xsd +0 -0
  49. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/common/UBL-CommonExtensionComponents-2.4.xsd +0 -0
  50. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/common/UBL-CommonSignatureComponents-2.4.xsd +0 -0
  51. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/common/UBL-ExtensionContentDataType-2.4.xsd +0 -0
  52. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/common/UBL-QualifiedDataTypes-2.4.xsd +0 -0
  53. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/common/UBL-SignatureAggregateComponents-2.4.xsd +0 -0
  54. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/common/UBL-SignatureBasicComponents-2.4.xsd +0 -0
  55. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/common/UBL-XAdES01903v132-201601-2.4.xsd +0 -0
  56. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/common/UBL-XAdES01903v141-201601-2.4.xsd +0 -0
  57. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/common/UBL-xmldsig-core-schema-2.4.xsd +0 -0
  58. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/common/UBL-xmldsig1-schema-2.4.xsd +0 -0
  59. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/common/UBL-xmldsig11-schema-2.4.xsd +0 -0
  60. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/maindoc/UBL-CreditNote-2.4.xsd +0 -0
  61. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/2.4/maindoc/UBL-Invoice-2.4.xsd +0 -0
  62. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/UBL-CreditNote-2.1-Example.xml +0 -0
  63. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/UBL-Invoice-2.1-Example-Trivial.xml +0 -0
  64. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/UBL-Invoice-2.1-Example.xml +0 -0
  65. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/__init__.py +0 -0
  66. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/scenario_ubl_2_credit_note_parse.json +0 -0
  67. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/scenario_ubl_2_invoice_parse.json +0 -0
  68. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/scenario_ubl_2_invoice_parse_trivial.rst +0 -0
  69. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/test_module.py +0 -0
  70. {trytond_edocument_ubl-8.0.3 → trytond_edocument_ubl-8.0.5}/tests/test_scenario.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: trytond_edocument_ubl
3
- Version: 8.0.3
3
+ Version: 8.0.5
4
4
  Summary: UBL electronic document for Tryton
5
5
  Project-URL: homepage, https://www.tryton.org/
6
6
  Project-URL: documentation, https://docs.tryton.org/modules-edocument-ubl/
@@ -321,11 +321,24 @@ class Invoice(Model):
321
321
  type_code=type_code))
322
322
 
323
323
  invoice = Invoice(type='in')
324
+
325
+ if (customer_party := root.find('./{*}AccountingCustomerParty')
326
+ ) is not None:
327
+ invoice.company = cls._parse_2_company(customer_party)
328
+ else:
329
+ invoice.company = Invoice.default_company()
330
+ if not invoice.company:
331
+ raise InvoiceError(gettext(
332
+ 'edocument_ubl.msg_company_not_found',
333
+ company=etree.tostring(
334
+ customer_party, pretty_print=True).decode()
335
+ if customer_party else ''))
336
+
324
337
  invoice.reference = root.findtext('./{*}ID')
325
338
  invoice.invoice_date = dt.date.fromisoformat(
326
339
  root.findtext('./{*}IssueDate'))
327
340
  invoice.party = cls._parse_2_supplier(
328
- root.find('./{*}AccountingSupplierParty'), create=True)
341
+ root.find('./{*}AccountingSupplierParty'), create=True).id
329
342
  payees = [invoice.party]
330
343
  invoice.set_journal()
331
344
  invoice.on_change_party()
@@ -341,17 +354,6 @@ class Invoice(Model):
341
354
  supplier = cls._parse_2_supplier(seller)
342
355
  else:
343
356
  supplier = invoice.party
344
- if (customer_party := root.find('./{*}AccountingCustomerParty')
345
- ) is not None:
346
- invoice.company = cls._parse_2_company(customer_party)
347
- else:
348
- invoice.company = Invoice.default_company()
349
- if not invoice.company:
350
- raise InvoiceError(gettext(
351
- 'edocument_ubl.msg_company_not_found',
352
- company=etree.tostring(
353
- customer_party, pretty_print=True).decode()
354
- if customer_party else ''))
355
357
 
356
358
  if (payee_party := root.find('./{*}PayeeParty')) is not None:
357
359
  party = cls._parse_2_party(payee_party)
@@ -382,6 +384,9 @@ class Invoice(Model):
382
384
  root.findall('./{*}PaymentMeans'), payees=payees)
383
385
  invoice.payment_term_date = cls._parse_2_payment_term_date(
384
386
  root.findall('./{*}PaymentTerms'))
387
+ if not invoice.payment_term_date:
388
+ if due_date := root.findtext('./{*}DueDate'):
389
+ invoice.payment_term_date = dt.date.fromisoformat(due_date)
385
390
  lines = [
386
391
  cls._parse_invoice_2_line(
387
392
  line,
@@ -460,7 +465,9 @@ class Invoice(Model):
460
465
  if (invoiced_quantity := invoice_line.find('./{*}InvoicedQuantity')
461
466
  ) is not None:
462
467
  line.quantity = float(invoiced_quantity.text)
463
- digits = -Decimal(invoiced_quantity.text).as_tuple().exponent
468
+ digits = (
469
+ -Decimal(invoiced_quantity.text)
470
+ .normalize().as_tuple().exponent)
464
471
  if (unit_code := invoiced_quantity.get('unitCode')) not in {
465
472
  None, 'ZZ', 'XZZ'}:
466
473
  try:
@@ -654,11 +661,24 @@ class Invoice(Model):
654
661
  type_code=type_code))
655
662
 
656
663
  invoice = Invoice(type='in')
664
+
665
+ if (customer_party := root.find('./{*}AccountingCustomerParty')
666
+ ) is not None:
667
+ invoice.company = cls._parse_2_company(customer_party)
668
+ else:
669
+ invoice.company = Invoice.default_company()
670
+ if not invoice.company:
671
+ raise InvoiceError(gettext(
672
+ 'edocument_ubl.msg_company_not_found',
673
+ company=etree.tostring(
674
+ customer_party, pretty_print=True).decode()
675
+ if customer_party else ''))
676
+
657
677
  invoice.reference = root.findtext('./{*}ID')
658
678
  invoice.invoice_date = dt.date.fromisoformat(
659
679
  root.findtext('./{*}IssueDate'))
660
680
  invoice.party = cls._parse_2_supplier(
661
- root.find('./{*}AccountingSupplierParty'), create=True)
681
+ root.find('./{*}AccountingSupplierParty'), create=True).id
662
682
  payees = [invoice.party]
663
683
  invoice.set_journal()
664
684
  invoice.on_change_party()
@@ -666,11 +686,7 @@ class Invoice(Model):
666
686
  supplier = cls._parse_2_supplier(seller)
667
687
  else:
668
688
  supplier = invoice.party
669
- if (customer_party := root.find('./{*}AccountingCustomerParty')
670
- ) is not None:
671
- invoice.company = cls._parse_2_company(customer_party)
672
- else:
673
- invoice.company = Invoice.default_company()
689
+
674
690
  if (payee_party := root.find('./{*}PayeeParty')) is not None:
675
691
  party = cls._parse_2_party(payee_party)
676
692
  if not party:
@@ -695,6 +711,9 @@ class Invoice(Model):
695
711
  root.findall('./{*}PaymentMeans'), payees=payees)
696
712
  invoice.payment_term_date = cls._parse_2_payment_term_date(
697
713
  root.findall('./{*}PaymentTerms'))
714
+ if not invoice.payment_term_date:
715
+ if due_date := root.findtext('./{*}DueDate'):
716
+ invoice.payment_term_date = dt.date.fromisoformat(due_date)
698
717
  lines = [
699
718
  cls._parse_credit_note_2_line(
700
719
  line, company=invoice.company, currency=invoice.currency,
@@ -771,7 +790,9 @@ class Invoice(Model):
771
790
  if (credited_quantity := credit_note_line.find('./{*}CreditedQuantity')
772
791
  ) is not None:
773
792
  line.quantity = -float(credited_quantity.text)
774
- digits = -Decimal(credited_quantity.text).as_tuple().exponent
793
+ digits = (
794
+ -Decimal(credited_quantity.text)
795
+ .normalize().as_tuple().exponent)
775
796
  if (unit_code := credited_quantity.get('unitCode')) not in {
776
797
  None, 'ZZ', 'XZZ'}:
777
798
  try:
@@ -1070,9 +1091,8 @@ class Invoice(Model):
1070
1091
  address.building_number = address_el.findtext('./{*}BuildingNumber')
1071
1092
  address.city = address_el.findtext('./{*}CityName')
1072
1093
  address.postal_code = address_el.findtext('./{*}PostalZone')
1073
- if (country_code := address_el.findtext(
1074
- './{*}Country/{*}IdentificationCode[@listId="ISO3166-1"]')
1075
- ) is not None:
1094
+ if country_code := address_el.findtext(
1095
+ './{*}Country/{*}IdentificationCode[@listId="ISO3166-1"]'):
1076
1096
  try:
1077
1097
  country, = Country.search([
1078
1098
  ('code', '=', country_code),
@@ -1188,8 +1208,7 @@ class Invoice(Model):
1188
1208
  def _parse_2_payment_term_date(cls, payment_terms):
1189
1209
  dates = []
1190
1210
  for payment_term in payment_terms:
1191
- if (date := payment_term.findtext('./{*}PaymentDueDate')
1192
- ) is not None:
1211
+ if date := payment_term.findtext('./{*}PaymentDueDate'):
1193
1212
  dates.append(dt.date.fromisoformat(date))
1194
1213
  return min(dates, default=None)
1195
1214
 
@@ -1212,8 +1231,7 @@ class Invoice(Model):
1212
1231
  pass
1213
1232
  else:
1214
1233
  return product
1215
- if (code := item.findtext('./{*}BuyersItemIdentification/{*}ID')
1216
- ) is not None:
1234
+ if code := item.findtext('./{*}BuyersItemIdentification/{*}ID'):
1217
1235
  try:
1218
1236
  product, = Product.search([
1219
1237
  ('code', '=', code),
@@ -1314,13 +1332,16 @@ class Invoice(Model):
1314
1332
  ) is not None:
1315
1333
  mime_code = (
1316
1334
  data.get('mimeCode') or 'application/octet-stream')
1317
- name += mimetypes.guess_extension(mime_code) or ''
1335
+ if extension := mimetypes.guess_extension(mime_code):
1336
+ if not name.lower().endswith(extension):
1337
+ name += extension
1318
1338
  attachment.type = 'data'
1319
1339
  data = b64decode(data.text)
1320
1340
  attachment.data = data
1321
1341
  elif data := document.findtext(
1322
1342
  './{*}Attachment/{*}EmbeddedDocument'):
1323
- name += '.txt'
1343
+ if not name.lower().endswith('.txt'):
1344
+ name += '.txt'
1324
1345
  attachment.type = 'data'
1325
1346
  attachment.data = data
1326
1347
  elif url := document.findtext(
@@ -62,7 +62,7 @@ Parse the UBL invoice::
62
62
  >>> with file_open(
63
63
  ... 'edocument_ubl/tests/UBL-CreditNote-2.1-Example.xml',
64
64
  ... mode='rb') as fp:
65
- ... invoice_id = EInvoice.parse(fp.read(), config.context)
65
+ ... invoice_id = EInvoice.parse(fp.read(), {**config.context, 'company': None})
66
66
 
67
67
  >>> invoice = Invoice(invoice_id)
68
68
 
@@ -62,7 +62,7 @@ Parse the UBL invoice::
62
62
  >>> with file_open(
63
63
  ... 'edocument_ubl/tests/UBL-Invoice-2.1-Example.xml',
64
64
  ... mode='rb') as fp:
65
- ... invoice_id = EInvoice.parse(fp.read(), config.context)
65
+ ... invoice_id = EInvoice.parse(fp.read(), {**config.context, 'company': None})
66
66
 
67
67
  >>> invoice = Invoice(invoice_id)
68
68
 
@@ -1,5 +1,5 @@
1
1
  [tryton]
2
- version=8.0.3
2
+ version=8.0.5
3
3
  depends:
4
4
  edocument_unece
5
5
  ir