el uso de __default_set__ y __default_get__ facilitan la creacion de un objeto como tipo

FossilOrigin-Name: e7fa7e3a3b312ad6b88a85b508b496308e5bb54b1d51ab5d50f4d4207830f175
This commit is contained in:
bit4bit 2021-07-31 18:31:38 +00:00
parent 69a74c0714
commit ddee0e45c1
5 changed files with 85 additions and 88 deletions

View File

@ -45,6 +45,9 @@ class InvoicePeriod(model.Model):
class ID(model.Model):
__name__ = 'ID'
def __default_get__(self, name, value):
return self._value
def __str__(self):
return str(self._value)
@ -67,17 +70,16 @@ class Quantity(model.Model):
__name__ = 'Quantity'
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):
self.value = value
return value
def __mul__(self, other):
return form.Amount(self.value) * other.value
def __add__(self, other):
return form.Amount(self.value) + other.value
def __default_get__(self, name, value):
return self.value
class Amount(model.Model):
__name__ = 'Amount'
@ -89,32 +91,23 @@ class Amount(model.Model):
self.value = value
return value
def __default__get__(self, value):
return value
def __default_get__(self, name, value):
return self.value
def __str__(self):
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):
__name__ = 'Price'
amount = fields.Many2One(Amount, name='PriceAmount')
value = fields.Amount(0.0)
def __default_set__(self, value):
self.amount = value
self.value = value
return value
def __mul__(self, other):
return self.value * other.value
def __default_get__(self, name, value):
return self.amount
class Percent(model.Model):
__name__ = 'Percent'
@ -177,16 +170,18 @@ class AllowanceCharge(model.Model):
def isDiscount(self):
return self.is_discount == True
class TaxScheme:
pass
class Taxes:
class Scheme:
def __init__(self, scheme):
self.scheme = scheme
class TaxIva(TaxScheme):
def __init__(self, percent):
self.scheme = '01'
self.percent = percent
class Iva(Scheme):
def __init__(self, percent):
super().__init__('01')
self.percent = percent
def calculate(self, amount):
return form.Amount(amount) * form.Amount(self.percent / 100)
def calculate(self, amount):
return form.Amount(amount) * form.Amount(self.percent / 100)
class InvoiceLine(model.Model):
__name__ = 'InvoiceLine'
@ -200,23 +195,28 @@ class InvoiceLine(model.Model):
def __setup__(self):
self._taxs = defaultdict(list)
self._subtotals = {
'01': self.taxtotal.subtotals.create()
}
self._subtotals['01'].scheme = '01'
self._subtotals = {}
def add_tax(self, tax):
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):
total = form.Amount(0)
for (scheme, subtotal) in self._subtotals.items():
total += subtotal.tax_amount.value
total += subtotal.tax_amount
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'])
def update_amount(self, name, value):
charge = form.AmountCollection(self.allowance_charge)\
@ -229,14 +229,15 @@ class InvoiceLine(model.Model):
.map(lambda charge: charge.amount)\
.sum()
total = self.quantity * self.price
total = form.Amount(self.quantity) * form.Amount(self.price)
self.amount = total + charge - discount
for (scheme, subtotal) in self._subtotals.items():
subtotal.tax_amount.value = 0
subtotal.tax_amount = 0
for (scheme, taxes) in self._taxs.items():
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):
__name__ = 'LegalMonetaryTotal'
@ -250,19 +251,11 @@ class LegalMonetaryTotal(model.Model):
@fields.on_change(['tax_inclusive_amount', 'charge_total'])
def update_payable_amount(self, name, value):
self.payable_amount = self.tax_inclusive_amount.value + self.charge_total_amount.value
class Technical(model.Model):
__name__ = 'Technical'
token = fields.Virtual(default='')
environment = fields.Virtual(default=fe.AMBIENTE_PRODUCCION)
self.payable_amount = self.tax_inclusive_amount + self.charge_total_amount
class Invoice(model.Model):
__name__ = 'Invoice'
technical = fields.Many2One(Technical, virtual=True)
id = fields.Many2One(ID)
issue = fields.Virtual(setter='set_issue')
issue_date = fields.Many2One(Date, name='IssueDate')
@ -279,12 +272,6 @@ class Invoice(model.Model):
taxtotal_04 = 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):
# Se requieren minimo estos impuestos para
# validar el cufe
@ -298,10 +285,10 @@ class Invoice(model.Model):
self._subtotal_03 = self.taxtotal_03.subtotals.create()
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_total_pagar = self.legal_monetary_total.payable_amount.value
valor_bruto = self.legal_monetary_total.line_extension_amount
valor_total_pagar = self.legal_monetary_total.payable_amount
valor_impuesto_01 = 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 subtotal in line.taxtotal.subtotals:
scheme_id = subtotal.scheme
if str(subtotal.scheme.id) == '01':
valor_impuesto_01 += subtotal.tax_amount.value
if subtotal.scheme.id == '01':
valor_impuesto_01 += subtotal.tax_amount
elif subtotal.scheme.id == '04':
valor_impuesto_04 += subtotal.tax_amount.value
valor_impuesto_04 += subtotal.tax_amount
elif subtotal.scheme.id == '03':
valor_impuesto_03 += subtotal.tax_amount.value
valor_impuesto_03 += subtotal.tax_amount
pattern = [
'%s' % str(self.id),
@ -330,8 +314,8 @@ class Invoice(model.Model):
valor_total_pagar.truncate_as_string(2),
str(self.supplier.party.id),
str(self.customer.party.id),
str(self.technical.token),
str(self.technical.environment)
str(token),
str(environment)
]
cufe = "".join(pattern)
@ -341,13 +325,12 @@ class Invoice(model.Model):
@fields.on_change(['lines'])
def update_legal_monetary_total(self, name, value):
self.legal_monetary_total.line_extension_amount.value = 0
self.legal_monetary_total.tax_inclusive_amount.value = 0
self.legal_monetary_total.line_extension_amount = 0
self.legal_monetary_total.tax_inclusive_amount = 0
for line in self.lines:
self.legal_monetary_total.line_extension_amount.value += line.amount.value
self.legal_monetary_total.tax_inclusive_amount += line.amount.value + line.tax_amount
print("update legal monetary %s" % (str(line.amount.value)))
self.legal_monetary_total.line_extension_amount += line.amount
self.legal_monetary_total.tax_inclusive_amount += line.amount + line.tax_amount
def set_issue(self, name, value):
if not isinstance(value, datetime):

View File

@ -52,6 +52,7 @@ class ModelBase(object, metaclass=ModelMeta):
obj._on_change_fields[field].append(fun)
# post inicializacion del objeto
obj.__setup__()
return obj
@ -76,17 +77,17 @@ class ModelBase(object, metaclass=ModelMeta):
if default is not None:
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):
"""
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__
ns = ''
@ -149,6 +150,7 @@ class Model(ModelBase):
def __default_get__(self, name, value):
"""
Al obtener el valor atraves de una relacion (age = person.age)
Retorno de valor por defecto
"""
return value

View File

@ -25,8 +25,10 @@ class Many2One(Field):
# se puede obtener directamente un valor indicado por el modelo
if hasattr(value, '__default_get__'):
return value.__default_get__(self.name, value)
else:
elif hasattr(inst, '__default_get__'):
return inst.__default_get__(self.name, value)
else:
return value
def __set__(self, inst, value):
assert self.name is not None

View File

@ -13,12 +13,21 @@ class _RelationProxy():
if (name in self.__dict__):
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):
# 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
response = setattr(self._obj, attr, value)
# algo burdo, se usa __dict__ para saltarnos el __getattr__ y evitar un fallo por recursion
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']]:
fun(self.__dict__['_inst'], self.__dict__['_attribute'], value)
return response

View File

@ -29,16 +29,17 @@ def _test_simple_invoice():
def test_simple_invoice_cufe():
token = '693ff6f2a553c3646a063436fd4dd9ded0311471'
environment = fe.AMBIENTE_PRODUCCION
invoice = model.Invoice()
invoice.technical.token = '693ff6f2a553c3646a063436fd4dd9ded0311471'
invoice.technical.environment = fe.AMBIENTE_PRODUCCION
invoice.id = '323200000129'
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.customer.party.id = '800199436'
line = invoice.lines.create()
line.add_tax(model.TaxIva(19.0))
line.add_tax(model.Taxes.Iva(19.0))
# TODO(bit4bit) acoplamiento temporal
# se debe crear primero el subotatl
@ -46,4 +47,4 @@ def test_simple_invoice_cufe():
line.quantity = 1
line.price = 1_500_000
assert invoice.cufe == '8bb918b19ba22a694f1da11c643b5e9de39adf60311cf179179e9b33381030bcd4c3c3f156c506ed5908f9276f5bd9b4'
assert invoice.cufe(token, environment) == '8bb918b19ba22a694f1da11c643b5e9de39adf60311cf179179e9b33381030bcd4c3c3f156c506ed5908f9276f5bd9b4'