el uso de __default_set__ y __default_get__ facilitan la creacion de un objeto como tipo
FossilOrigin-Name: e7fa7e3a3b312ad6b88a85b508b496308e5bb54b1d51ab5d50f4d4207830f175
This commit is contained in:
		| @@ -45,6 +45,9 @@ class InvoicePeriod(model.Model): | |||||||
| class ID(model.Model): | class ID(model.Model): | ||||||
|     __name__ = 'ID' |     __name__ = 'ID' | ||||||
|  |  | ||||||
|  |     def __default_get__(self, name, value): | ||||||
|  |         return self._value | ||||||
|  |  | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return str(self._value) |         return str(self._value) | ||||||
|  |  | ||||||
| @@ -67,17 +70,16 @@ class Quantity(model.Model): | |||||||
|     __name__  = 'Quantity' |     __name__  = 'Quantity' | ||||||
|  |  | ||||||
|     code = fields.Attribute('unitCode', default='NAR') |     code = fields.Attribute('unitCode', default='NAR') | ||||||
|     value = fields.Virtual(default=0, update_internal=True) |  | ||||||
|  |     def __setup__(self): | ||||||
|  |         self.value = 0 | ||||||
|  |  | ||||||
|     def __default_set__(self, value): |     def __default_set__(self, value): | ||||||
|         self.value = value |         self.value = value | ||||||
|         return value |         return value | ||||||
|  |  | ||||||
|     def __mul__(self, other): |     def __default_get__(self, name, value): | ||||||
|         return form.Amount(self.value) * other.value |         return self.value | ||||||
|  |  | ||||||
|     def __add__(self, other): |  | ||||||
|         return form.Amount(self.value) + other.value |  | ||||||
|  |  | ||||||
| class Amount(model.Model): | class Amount(model.Model): | ||||||
|     __name__ = 'Amount' |     __name__ = 'Amount' | ||||||
| @@ -89,32 +91,23 @@ class Amount(model.Model): | |||||||
|         self.value = value |         self.value = value | ||||||
|         return value |         return value | ||||||
|  |  | ||||||
|     def __default__get__(self, value): |     def __default_get__(self, name, value): | ||||||
|         return value |         return self.value | ||||||
|  |  | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return str(self.value) |         return str(self.value) | ||||||
|  |  | ||||||
|     def __add__(self, other): |  | ||||||
|         if isinstance(other, form.Amount): |  | ||||||
|             return self.value + other |  | ||||||
|  |  | ||||||
|         return self.value + other.value |  | ||||||
|  |  | ||||||
| class Price(model.Model): | class Price(model.Model): | ||||||
|     __name__ = 'Price' |     __name__ = 'Price' | ||||||
|  |  | ||||||
|     amount = fields.Many2One(Amount, name='PriceAmount') |     amount = fields.Many2One(Amount, name='PriceAmount') | ||||||
|     value = fields.Amount(0.0) |  | ||||||
|      |      | ||||||
|     def __default_set__(self, value): |     def __default_set__(self, value): | ||||||
|         self.amount = value |         self.amount = value | ||||||
|         self.value = value |  | ||||||
|         return value |         return value | ||||||
|  |  | ||||||
|     def __mul__(self, other): |     def __default_get__(self, name, value): | ||||||
|         return self.value * other.value |         return self.amount | ||||||
|  |  | ||||||
|  |  | ||||||
| class Percent(model.Model): | class Percent(model.Model): | ||||||
|     __name__ = 'Percent' |     __name__ = 'Percent' | ||||||
| @@ -177,16 +170,18 @@ class AllowanceCharge(model.Model): | |||||||
|     def isDiscount(self): |     def isDiscount(self): | ||||||
|         return self.is_discount == True |         return self.is_discount == True | ||||||
|  |  | ||||||
| class TaxScheme: | class Taxes: | ||||||
|     pass |     class Scheme: | ||||||
|  |         def __init__(self, scheme): | ||||||
|  |             self.scheme = scheme | ||||||
|  |  | ||||||
| class TaxIva(TaxScheme): |     class Iva(Scheme): | ||||||
|     def __init__(self, percent): |         def __init__(self, percent): | ||||||
|         self.scheme = '01' |             super().__init__('01') | ||||||
|         self.percent = percent |             self.percent = percent | ||||||
|  |  | ||||||
|     def calculate(self, amount): |         def calculate(self, amount): | ||||||
|         return form.Amount(amount) * form.Amount(self.percent / 100) |             return form.Amount(amount) * form.Amount(self.percent / 100) | ||||||
|      |      | ||||||
| class InvoiceLine(model.Model): | class InvoiceLine(model.Model): | ||||||
|     __name__ = 'InvoiceLine' |     __name__ = 'InvoiceLine' | ||||||
| @@ -200,23 +195,28 @@ class InvoiceLine(model.Model): | |||||||
|      |      | ||||||
|     def __setup__(self): |     def __setup__(self): | ||||||
|         self._taxs = defaultdict(list) |         self._taxs = defaultdict(list) | ||||||
|         self._subtotals = { |         self._subtotals = {} | ||||||
|             '01': self.taxtotal.subtotals.create() |  | ||||||
|         } |     def add_tax(self, tax): | ||||||
|         self._subtotals['01'].scheme = '01' |         if not isinstance(tax, Taxes.Scheme): | ||||||
|  |             raise ValueError('tax expected TaxIva') | ||||||
|  |  | ||||||
|  |         # inicialiamos subtotal para impuesto | ||||||
|  |         if not tax.scheme in self._subtotals: | ||||||
|  |             subtotal = self.taxtotal.subtotals.create() | ||||||
|  |             subtotal.scheme = tax.scheme | ||||||
|  |              | ||||||
|  |             self._subtotals[tax.scheme] = subtotal | ||||||
|  |          | ||||||
|  |         self._taxs[tax.scheme].append(tax) | ||||||
|  |  | ||||||
|     def get_tax_amount(self, name, value): |     def get_tax_amount(self, name, value): | ||||||
|         total = form.Amount(0) |         total = form.Amount(0) | ||||||
|         for (scheme, subtotal) in self._subtotals.items(): |         for (scheme, subtotal) in self._subtotals.items(): | ||||||
|             total += subtotal.tax_amount.value |             total += subtotal.tax_amount | ||||||
|  |  | ||||||
|         return total |         return total | ||||||
|  |  | ||||||
|     def add_tax(self, tax): |  | ||||||
|         if not isinstance(tax, TaxScheme): |  | ||||||
|             raise ValueError('tax expected TaxScheme') |  | ||||||
|  |  | ||||||
|         self._taxs[tax.scheme].append(tax) |  | ||||||
|  |  | ||||||
|     @fields.on_change(['price', 'quantity']) |     @fields.on_change(['price', 'quantity']) | ||||||
|     def update_amount(self, name, value): |     def update_amount(self, name, value): | ||||||
|         charge = form.AmountCollection(self.allowance_charge)\ |         charge = form.AmountCollection(self.allowance_charge)\ | ||||||
| @@ -229,14 +229,15 @@ class InvoiceLine(model.Model): | |||||||
|             .map(lambda charge: charge.amount)\ |             .map(lambda charge: charge.amount)\ | ||||||
|             .sum() |             .sum() | ||||||
|  |  | ||||||
|         total = self.quantity  * self.price |         total = form.Amount(self.quantity)  * form.Amount(self.price) | ||||||
|         self.amount = total + charge - discount |         self.amount = total + charge - discount | ||||||
|  |          | ||||||
|         for (scheme, subtotal) in self._subtotals.items(): |         for (scheme, subtotal) in self._subtotals.items(): | ||||||
|             subtotal.tax_amount.value = 0 |             subtotal.tax_amount = 0 | ||||||
|  |  | ||||||
|         for (scheme, taxes) in self._taxs.items(): |         for (scheme, taxes) in self._taxs.items(): | ||||||
|             for tax in taxes: |             for tax in taxes: | ||||||
|                 self._subtotals[scheme].tax_amount += tax.calculate(self.amount.value) |                 self._subtotals[scheme].tax_amount += tax.calculate(self.amount) | ||||||
|  |  | ||||||
| class LegalMonetaryTotal(model.Model): | class LegalMonetaryTotal(model.Model): | ||||||
|     __name__ = 'LegalMonetaryTotal' |     __name__ = 'LegalMonetaryTotal' | ||||||
| @@ -250,19 +251,11 @@ class LegalMonetaryTotal(model.Model): | |||||||
|  |  | ||||||
|     @fields.on_change(['tax_inclusive_amount', 'charge_total']) |     @fields.on_change(['tax_inclusive_amount', 'charge_total']) | ||||||
|     def update_payable_amount(self, name, value): |     def update_payable_amount(self, name, value): | ||||||
|         self.payable_amount = self.tax_inclusive_amount.value + self.charge_total_amount.value |         self.payable_amount = self.tax_inclusive_amount + self.charge_total_amount | ||||||
|      |  | ||||||
| class Technical(model.Model): |  | ||||||
|     __name__ = 'Technical' |  | ||||||
|  |  | ||||||
|     token = fields.Virtual(default='') |  | ||||||
|     environment = fields.Virtual(default=fe.AMBIENTE_PRODUCCION) |  | ||||||
|  |  | ||||||
| class Invoice(model.Model): | class Invoice(model.Model): | ||||||
|     __name__ = 'Invoice' |     __name__ = 'Invoice' | ||||||
|  |  | ||||||
|     technical = fields.Many2One(Technical, virtual=True) |  | ||||||
|      |  | ||||||
|     id = fields.Many2One(ID) |     id = fields.Many2One(ID) | ||||||
|     issue = fields.Virtual(setter='set_issue') |     issue = fields.Virtual(setter='set_issue') | ||||||
|     issue_date = fields.Many2One(Date, name='IssueDate') |     issue_date = fields.Many2One(Date, name='IssueDate') | ||||||
| @@ -279,12 +272,6 @@ class Invoice(model.Model): | |||||||
|     taxtotal_04 = fields.Many2One(TaxTotal) |     taxtotal_04 = fields.Many2One(TaxTotal) | ||||||
|     taxtotal_03 = fields.Many2One(TaxTotal) |     taxtotal_03 = fields.Many2One(TaxTotal) | ||||||
|  |  | ||||||
|     cufe = fields.Virtual(getter='calculate_cufe') |  | ||||||
|  |  | ||||||
|     _subtotal_01 = fields.Virtual() |  | ||||||
|     _subtotal_04 = fields.Virtual() |  | ||||||
|     _subtotal_03 = fields.Virtual() |  | ||||||
|  |  | ||||||
|     def __setup__(self): |     def __setup__(self): | ||||||
|         # Se requieren minimo estos impuestos para |         # Se requieren minimo estos impuestos para | ||||||
|         # validar el cufe |         # validar el cufe | ||||||
| @@ -298,10 +285,10 @@ class Invoice(model.Model): | |||||||
|         self._subtotal_03 = self.taxtotal_03.subtotals.create() |         self._subtotal_03 = self.taxtotal_03.subtotals.create() | ||||||
|         self._subtotal_03.scheme = '03' |         self._subtotal_03.scheme = '03' | ||||||
|  |  | ||||||
|     def calculate_cufe(self, name, value): |     def cufe(self, token, environment): | ||||||
|  |  | ||||||
|         valor_bruto = self.legal_monetary_total.line_extension_amount.value |         valor_bruto = self.legal_monetary_total.line_extension_amount | ||||||
|         valor_total_pagar = self.legal_monetary_total.payable_amount.value |         valor_total_pagar = self.legal_monetary_total.payable_amount | ||||||
|  |  | ||||||
|         valor_impuesto_01 = form.Amount(0.0) |         valor_impuesto_01 = form.Amount(0.0) | ||||||
|         valor_impuesto_04 = form.Amount(0.0) |         valor_impuesto_04 = form.Amount(0.0) | ||||||
| @@ -309,15 +296,12 @@ class Invoice(model.Model): | |||||||
|  |  | ||||||
|         for line in self.lines: |         for line in self.lines: | ||||||
|             for subtotal in line.taxtotal.subtotals: |             for subtotal in line.taxtotal.subtotals: | ||||||
|                 scheme_id = subtotal.scheme |                 if subtotal.scheme.id == '01': | ||||||
|                 if str(subtotal.scheme.id) == '01': |                     valor_impuesto_01 += subtotal.tax_amount | ||||||
|                     valor_impuesto_01 += subtotal.tax_amount.value |  | ||||||
|                 elif subtotal.scheme.id == '04': |                 elif subtotal.scheme.id == '04': | ||||||
|                     valor_impuesto_04 += subtotal.tax_amount.value |                     valor_impuesto_04 += subtotal.tax_amount | ||||||
|                 elif subtotal.scheme.id == '03': |                 elif subtotal.scheme.id == '03': | ||||||
|                     valor_impuesto_03 += subtotal.tax_amount.value |                     valor_impuesto_03 += subtotal.tax_amount | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         pattern = [ |         pattern = [ | ||||||
|             '%s' % str(self.id), |             '%s' % str(self.id), | ||||||
| @@ -330,8 +314,8 @@ class Invoice(model.Model): | |||||||
|             valor_total_pagar.truncate_as_string(2), |             valor_total_pagar.truncate_as_string(2), | ||||||
|             str(self.supplier.party.id), |             str(self.supplier.party.id), | ||||||
|             str(self.customer.party.id), |             str(self.customer.party.id), | ||||||
|             str(self.technical.token), |             str(token), | ||||||
|             str(self.technical.environment) |             str(environment) | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|         cufe = "".join(pattern) |         cufe = "".join(pattern) | ||||||
| @@ -341,13 +325,12 @@ class Invoice(model.Model): | |||||||
|  |  | ||||||
|     @fields.on_change(['lines']) |     @fields.on_change(['lines']) | ||||||
|     def update_legal_monetary_total(self, name, value): |     def update_legal_monetary_total(self, name, value): | ||||||
|         self.legal_monetary_total.line_extension_amount.value = 0 |         self.legal_monetary_total.line_extension_amount = 0 | ||||||
|         self.legal_monetary_total.tax_inclusive_amount.value = 0 |         self.legal_monetary_total.tax_inclusive_amount = 0 | ||||||
|  |  | ||||||
|         for line in self.lines: |         for line in self.lines: | ||||||
|             self.legal_monetary_total.line_extension_amount.value += line.amount.value |             self.legal_monetary_total.line_extension_amount += line.amount | ||||||
|             self.legal_monetary_total.tax_inclusive_amount += line.amount.value + line.tax_amount |             self.legal_monetary_total.tax_inclusive_amount += line.amount + line.tax_amount | ||||||
|             print("update legal monetary %s" % (str(line.amount.value))) |  | ||||||
|  |  | ||||||
|     def set_issue(self, name, value): |     def set_issue(self, name, value): | ||||||
|         if not isinstance(value, datetime): |         if not isinstance(value, datetime): | ||||||
|   | |||||||
| @@ -52,6 +52,7 @@ class ModelBase(object, metaclass=ModelMeta): | |||||||
|                     obj._on_change_fields[field].append(fun) |                     obj._on_change_fields[field].append(fun) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         # post inicializacion del objeto | ||||||
|         obj.__setup__() |         obj.__setup__() | ||||||
|         return obj |         return obj | ||||||
|  |  | ||||||
| @@ -76,17 +77,17 @@ class ModelBase(object, metaclass=ModelMeta): | |||||||
|         if default is not None: |         if default is not None: | ||||||
|             self._value = default |             self._value = default | ||||||
|  |  | ||||||
|     def _hook_before_xml(self): |  | ||||||
|         self.__before_xml__() |  | ||||||
|         for field in self._fields.values(): |  | ||||||
|             if hasattr(field, '__before_xml__'): |  | ||||||
|                 field.__before_xml__() |  | ||||||
|  |  | ||||||
|     def to_xml(self): |     def to_xml(self): | ||||||
|         """ |         """ | ||||||
|         Genera xml del modelo y sus relaciones |         Genera xml del modelo y sus relaciones | ||||||
|         """ |         """ | ||||||
|         self._hook_before_xml() |         def _hook_before_xml(): | ||||||
|  |             self.__before_xml__() | ||||||
|  |             for field in self._fields.values(): | ||||||
|  |                 if hasattr(field, '__before_xml__'): | ||||||
|  |                     field.__before_xml__() | ||||||
|  |                      | ||||||
|  |         _hook_before_xml() | ||||||
|  |  | ||||||
|         tag = self.__name__ |         tag = self.__name__ | ||||||
|         ns = '' |         ns = '' | ||||||
| @@ -149,6 +150,7 @@ class Model(ModelBase): | |||||||
|  |  | ||||||
|     def __default_get__(self, name, value): |     def __default_get__(self, name, value): | ||||||
|         """ |         """ | ||||||
|  |         Al obtener el valor atraves de una relacion (age = person.age) | ||||||
|         Retorno de valor por defecto |         Retorno de valor por defecto | ||||||
|         """ |         """ | ||||||
|         return value |         return value | ||||||
|   | |||||||
| @@ -25,8 +25,10 @@ class Many2One(Field): | |||||||
|         # se puede obtener directamente un valor indicado por el modelo |         # se puede obtener directamente un valor indicado por el modelo | ||||||
|         if hasattr(value, '__default_get__'): |         if hasattr(value, '__default_get__'): | ||||||
|             return value.__default_get__(self.name, value) |             return value.__default_get__(self.name, value) | ||||||
|         else: |         elif hasattr(inst, '__default_get__'): | ||||||
|             return inst.__default_get__(self.name, value) |             return inst.__default_get__(self.name, value) | ||||||
|  |         else: | ||||||
|  |             return value | ||||||
|          |          | ||||||
|     def __set__(self, inst, value): |     def __set__(self, inst, value): | ||||||
|         assert self.name is not None |         assert self.name is not None | ||||||
|   | |||||||
| @@ -13,12 +13,21 @@ class _RelationProxy(): | |||||||
|         if (name in self.__dict__): |         if (name in self.__dict__): | ||||||
|             return self.__dict__[name] |             return self.__dict__[name] | ||||||
|  |  | ||||||
|         return getattr(self.__dict__['_obj'], name) |         rel = getattr(self.__dict__['_obj'], name) | ||||||
|  |         if hasattr(rel, '__default_get__'): | ||||||
|  |             return rel.__default_get__(name, rel) | ||||||
|  |  | ||||||
|  |         return rel | ||||||
|  |  | ||||||
|     def __setattr__(self, attr, value): |     def __setattr__(self, attr, value): | ||||||
|         # TODO(bit4bit) hacemos proxy al sistema de notificacion de cambios |         # TODO(bit4bit) hacemos proxy al sistema de notificacion de cambios | ||||||
|         # algo burdo, se usa __dict__ para saltarnos el __getattr__ y generar un fallo por recursion |         # algo burdo, se usa __dict__ para saltarnos el __getattr__ y evitar un fallo por recursion | ||||||
|         response = setattr(self._obj, attr, value) |         rel = getattr(self.__dict__['_obj'], attr) | ||||||
|  |         if hasattr(rel, '__default_set__'): | ||||||
|  |             response = setattr(self._obj, attr, rel.__default_set__(value)) | ||||||
|  |         else: | ||||||
|  |             response = setattr(self._obj, attr, value) | ||||||
|  |  | ||||||
|         for fun in self.__dict__['_inst']._on_change_fields[self.__dict__['_attribute']]: |         for fun in self.__dict__['_inst']._on_change_fields[self.__dict__['_attribute']]: | ||||||
|             fun(self.__dict__['_inst'], self.__dict__['_attribute'], value) |             fun(self.__dict__['_inst'], self.__dict__['_attribute'], value) | ||||||
|         return response |         return response | ||||||
|   | |||||||
| @@ -29,16 +29,17 @@ def _test_simple_invoice(): | |||||||
|  |  | ||||||
|  |  | ||||||
| def test_simple_invoice_cufe(): | def test_simple_invoice_cufe(): | ||||||
|  |     token = '693ff6f2a553c3646a063436fd4dd9ded0311471' | ||||||
|  |     environment = fe.AMBIENTE_PRODUCCION | ||||||
|  |  | ||||||
|     invoice = model.Invoice() |     invoice = model.Invoice() | ||||||
|     invoice.technical.token = '693ff6f2a553c3646a063436fd4dd9ded0311471' |  | ||||||
|     invoice.technical.environment = fe.AMBIENTE_PRODUCCION |  | ||||||
|     invoice.id = '323200000129' |     invoice.id = '323200000129' | ||||||
|     invoice.issue = datetime.strptime('2019-01-16 10:53:10-05:00', '%Y-%m-%d %H:%M:%S%z') |     invoice.issue = datetime.strptime('2019-01-16 10:53:10-05:00', '%Y-%m-%d %H:%M:%S%z') | ||||||
|     invoice.supplier.party.id = '700085371' |     invoice.supplier.party.id = '700085371' | ||||||
|     invoice.customer.party.id = '800199436' |     invoice.customer.party.id = '800199436' | ||||||
|  |  | ||||||
|     line = invoice.lines.create() |     line = invoice.lines.create() | ||||||
|     line.add_tax(model.TaxIva(19.0)) |     line.add_tax(model.Taxes.Iva(19.0)) | ||||||
|  |  | ||||||
|     # TODO(bit4bit) acoplamiento temporal |     # TODO(bit4bit) acoplamiento temporal | ||||||
|     # se debe crear primero el subotatl |     # se debe crear primero el subotatl | ||||||
| @@ -46,4 +47,4 @@ def test_simple_invoice_cufe(): | |||||||
|     line.quantity = 1 |     line.quantity = 1 | ||||||
|     line.price = 1_500_000 |     line.price = 1_500_000 | ||||||
|  |  | ||||||
|     assert invoice.cufe == '8bb918b19ba22a694f1da11c643b5e9de39adf60311cf179179e9b33381030bcd4c3c3f156c506ed5908f9276f5bd9b4' |     assert invoice.cufe(token, environment) == '8bb918b19ba22a694f1da11c643b5e9de39adf60311cf179179e9b33381030bcd4c3c3f156c506ed5908f9276f5bd9b4' | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user