From 088fa9e6e03727bbbcbe0b5d1d53f701b162aa61 Mon Sep 17 00:00:00 2001 From: bit4bit Date: Sun, 8 Aug 2021 21:20:54 +0000 Subject: [PATCH] se adiciona namespaces a invoice FossilOrigin-Name: caf85d4a30e7945ca2a6fc3a9430855fa8623442b1a30ae824f742e2a93e2956 --- facho/fe/model/__init__.py | 86 +++++++++++++++++++++------------- facho/model/fields/field.py | 16 +++++-- facho/model/fields/one2many.py | 2 +- tests/test_model.py | 52 ++++++++++++++++++++ 4 files changed, 119 insertions(+), 37 deletions(-) diff --git a/facho/fe/model/__init__.py b/facho/fe/model/__init__.py index 5de325e..504c644 100644 --- a/facho/fe/model/__init__.py +++ b/facho/fe/model/__init__.py @@ -38,9 +38,9 @@ class Time(model.Model): class InvoicePeriod(model.Model): __name__ = 'InvoicePeriod' - start_date = fields.Many2One(Date, name='StartDate') + start_date = fields.Many2One(Date, name='StartDate', namespace='cbc') - end_date = fields.Many2One(Date, name='EndDate') + end_date = fields.Many2One(Date, name='EndDate', namespace='cbc') class ID(model.Model): __name__ = 'ID' @@ -51,15 +51,27 @@ class ID(model.Model): def __str__(self): return str(self._value) +class PartyTaxScheme(model.Model): + __name__ = 'PartyTaxScheme' + + company_id = fields.Many2One(ID, name='CompanyID', namespace='cbc') + tax_level_code = fields.Many2One(ID, name='TaxLevelCode', namespace='cbc', default='ZZ') + class Party(model.Model): __name__ = 'Party' - id = fields.Many2One(ID) + id = fields.Virtual(setter='set_id') + + tax_scheme = fields.Many2One(PartyTaxScheme, namespace='cac') + + def set_id(self, name, value): + self.tax_scheme.company_id = value + return value class AccountingCustomerParty(model.Model): __name__ = 'AccountingCustomerParty' - party = fields.Many2One(Party) + party = fields.Many2One(Party, namespace='cac') class AccountingSupplierParty(model.Model): __name__ = 'AccountingSupplierParty' @@ -100,7 +112,7 @@ class Amount(model.Model): class Price(model.Model): __name__ = 'Price' - amount = fields.Many2One(Amount, name='PriceAmount') + amount = fields.Many2One(Amount, name='PriceAmount', namespace='cbc') def __default_set__(self, value): self.amount = value @@ -115,14 +127,14 @@ class Percent(model.Model): class TaxScheme(model.Model): __name__ = 'TaxScheme' - id = fields.Many2One(ID) - name= fields.Many2One(Name) + id = fields.Many2One(ID, namespace='cbc') + name= fields.Many2One(Name, namespace='cbc') class TaxCategory(model.Model): __name__ = 'TaxCategory' - percent = fields.Many2One(Percent) - tax_scheme = fields.Many2One(TaxScheme) + percent = fields.Many2One(Percent, namespace='cbc') + tax_scheme = fields.Many2One(TaxScheme, namespace='cac') class TaxSubTotal(model.Model): __name__ = 'TaxSubTotal' @@ -154,14 +166,14 @@ class TaxSubTotal(model.Model): class TaxTotal(model.Model): __name__ = 'TaxTotal' - tax_amount = fields.Many2One(Amount, name='TaxAmount', default=0.00) - subtotals = fields.One2Many(TaxSubTotal) + tax_amount = fields.Many2One(Amount, name='TaxAmount', namespace='cbc', default=0.00) + subtotals = fields.One2Many(TaxSubTotal, namespace='cac') class AllowanceCharge(model.Model): __name__ = 'AllowanceCharge' - amount = fields.Many2One(Amount) + amount = fields.Many2One(Amount, namespace='cbc') is_discount = fields.Virtual(default=False) def isCharge(self): @@ -186,11 +198,12 @@ class Taxes: class InvoiceLine(model.Model): __name__ = 'InvoiceLine' - quantity = fields.Many2One(Quantity, name='InvoicedQuantity') - taxtotal = fields.Many2One(TaxTotal) - price = fields.Many2One(Price) - amount = fields.Many2One(Amount, name='LineExtensionAmount') - allowance_charge = fields.One2Many(AllowanceCharge) + id = fields.Many2One(ID, namespace='cbc') + quantity = fields.Many2One(Quantity, name='InvoicedQuantity', namespace='cbc') + taxtotal = fields.Many2One(TaxTotal, namespace='cac') + price = fields.Many2One(Price, namespace='cac') + amount = fields.Many2One(Amount, name='LineExtensionAmount', namespace='cbc') + allowance_charge = fields.One2Many(AllowanceCharge, 'cac') tax_amount = fields.Virtual(getter='get_tax_amount') def __setup__(self): @@ -242,12 +255,12 @@ class InvoiceLine(model.Model): class LegalMonetaryTotal(model.Model): __name__ = 'LegalMonetaryTotal' - line_extension_amount = fields.Many2One(Amount, name='LineExtensionAmount', default=0) + line_extension_amount = fields.Many2One(Amount, name='LineExtensionAmount', namespace='cbc', default=0) - tax_exclusive_amount = fields.Many2One(Amount, name='TaxExclusiveAmount', default=form.Amount(0)) - tax_inclusive_amount = fields.Many2One(Amount, name='TaxInclusiveAmount', default=form.Amount(0)) - charge_total_amount = fields.Many2One(Amount, name='ChargeTotalAmount', default=form.Amount(0)) - payable_amount = fields.Many2One(Amount, name='PayableAmount', default=form.Amount(0)) + tax_exclusive_amount = fields.Many2One(Amount, name='TaxExclusiveAmount', namespace='cbc', default=form.Amount(0)) + tax_inclusive_amount = fields.Many2One(Amount, name='TaxInclusiveAmount', namespace='cbc', default=form.Amount(0)) + charge_total_amount = fields.Many2One(Amount, name='ChargeTotalAmount', namespace='cbc', default=form.Amount(0)) + payable_amount = fields.Many2One(Amount, name='PayableAmount', namespace='cbc', default=form.Amount(0)) @fields.on_change(['tax_inclusive_amount', 'charge_total']) def update_payable_amount(self, name, value): @@ -255,18 +268,27 @@ class LegalMonetaryTotal(model.Model): class Invoice(model.Model): __name__ = 'Invoice' - - id = fields.Many2One(ID) - issue = fields.Virtual(setter='set_issue') - issue_date = fields.Many2One(Date, name='IssueDate') - issue_time = fields.Many2One(Time, name='IssueTime') + __namespace__ = { + 'cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2', + 'cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2', + 'cdt': 'urn:DocumentInformation:names:specification:ubl:colombia:schema:xsd:DocumentInformationAggregateComponents-1', + 'ext': 'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2', + 'sts': 'http://www.dian.gov.co/contratos/facturaelectronica/v1/Structures', + 'xades': 'http://uri.etsi.org/01903/v1.3.2#', + 'ds': 'http://www.w3.org/2000/09/xmldsig#' + } - period = fields.Many2One(InvoicePeriod) + id = fields.Many2One(ID, namespace='cbc') + issue = fields.Virtual(setter='set_issue') + issue_date = fields.Many2One(Date, name='IssueDate', namespace='cbc') + issue_time = fields.Many2One(Time, name='IssueTime', namespace='cbc') + + period = fields.Many2One(InvoicePeriod, namespace='cac') - supplier = fields.Many2One(AccountingSupplierParty) - customer = fields.Many2One(AccountingCustomerParty) - lines = fields.One2Many(InvoiceLine) - legal_monetary_total = fields.Many2One(LegalMonetaryTotal) + supplier = fields.Many2One(AccountingSupplierParty, namespace='cac') + customer = fields.Many2One(AccountingCustomerParty, namespace='cac') + lines = fields.One2Many(InvoiceLine, namespace='cac') + legal_monetary_total = fields.Many2One(LegalMonetaryTotal, namespace='cac') taxtotal_01 = fields.Many2One(TaxTotal) taxtotal_04 = fields.Many2One(TaxTotal) diff --git a/facho/model/fields/field.py b/facho/model/fields/field.py index d8a6fe4..7deec60 100644 --- a/facho/model/fields/field.py +++ b/facho/model/fields/field.py @@ -1,3 +1,5 @@ +import warnings + class Field: def __set_name__(self, owner, name, virtual=False): self.name = name @@ -17,8 +19,10 @@ class Field: if name is None: return - if name not in namespaces: - raise KeyError("namespace %s not found" % (name)) + #TODO(bit4bit) aunque las pruebas confirmar + #que si se escribe el namespace que es + #no ahi confirmacion de declaracion previa del namespace + inst._namespace_prefix = name def _call(self, inst, method, *args): @@ -27,7 +31,7 @@ class Field: if callable(call): return call(*args) - def _create_model(self, inst, name=None, model=None, attribute=None): + def _create_model(self, inst, name=None, model=None, attribute=None, namespace=None): try: return inst._fields[self.name] except KeyError: @@ -37,7 +41,11 @@ class Field: obj = self.model() if name is not None: obj.__name__ = name - self._set_namespace(obj, self.namespace, inst.__namespace__) + + if namespace: + self._set_namespace(obj, namespace, inst.__namespace__) + else: + self._set_namespace(obj, self.namespace, inst.__namespace__) if attribute: inst._fields[attribute] = obj diff --git a/facho/model/fields/one2many.py b/facho/model/fields/one2many.py index 2c2dca7..da7960c 100644 --- a/facho/model/fields/one2many.py +++ b/facho/model/fields/one2many.py @@ -67,7 +67,7 @@ class One2Many(Field): assert self.name is not None def creator(attribute): - return self._create_model(inst, name=self.field_name, model=self.model, attribute=attribute) + return self._create_model(inst, name=self.field_name, model=self.model, attribute=attribute, namespace=self.namespace) if inst in self.relation: return self.relation[inst] diff --git a/tests/test_model.py b/tests/test_model.py index 10cc99e..0ceebec 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -195,6 +195,58 @@ def test_model_with_xml_namespace_nested(): person.id = 33 assert '33' == person.to_xml() +def test_model_with_xml_namespace_nested_nested(): + class ID(facho.model.Model): + __name__ = 'ID' + + class Party(facho.model.Model): + __name__ = 'Party' + + id = fields.Many2One(ID, namespace='party') + + def __default_set__(self, value): + self.id = value + + class Person(facho.model.Model): + __name__ = 'Person' + __namespace__ = { + 'person': 'http://lib.facho.cyou', + 'party': 'http://lib.facho.cyou' + } + + id = fields.Many2One(Party, namespace='person') + + person = Person() + person.id = 33 + assert '33' == person.to_xml() + +def test_model_with_xml_namespace_nested_one_many(): + class Name(facho.model.Model): + __name__ = 'Name' + + class Contact(facho.model.Model): + __name__ = 'Contact' + + name = fields.Many2One(Name, namespace='contact') + + class Person(facho.model.Model): + __name__ = 'Person' + __namespace__ = { + 'facho': 'http://lib.facho.cyou', + 'contact': 'http://lib.facho.cyou' + } + + contacts = fields.One2Many(Contact, namespace='facho') + + person = Person() + contact = person.contacts.create() + contact.name = 'contact1' + + contact = person.contacts.create() + contact.name = 'contact2' + + assert 'contact1contact2' == person.to_xml() + def test_field_model_with_namespace(): class ID(facho.model.Model): __name__ = 'ID'