el uso de __default_set__ y __default_get__ facilitan la creacion de un objeto como tipo
FossilOrigin-Name: e7fa7e3a3b312ad6b88a85b508b496308e5bb54b1d51ab5d50f4d4207830f175
This commit is contained in:
parent
69a74c0714
commit
ddee0e45c1
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
Loading…
Reference in New Issue
Block a user