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'