se crea legal monetary total
FossilOrigin-Name: 8ae3dfadfe9b90b8cc5ad59d2a73f4c8a987c5aac498573e56754a2d32e9e2ae
This commit is contained in:
		| @@ -99,7 +99,7 @@ class Amount: | |||||||
|             return self.fromNumber(val) |             return self.fromNumber(val) | ||||||
|         if isinstance(val, Amount): |         if isinstance(val, Amount): | ||||||
|             return val |             return val | ||||||
|         raise TypeError("cant cast to amount") |         raise TypeError("cant cast %s to amount" % (type(val))) | ||||||
|      |      | ||||||
|     def __add__(self, rother): |     def __add__(self, rother): | ||||||
|         other = self._cast(rother) |         other = self._cast(rother) | ||||||
|   | |||||||
| @@ -1,6 +1,8 @@ | |||||||
| import facho.model as model | import facho.model as model | ||||||
| import facho.model.fields as fields | import facho.model.fields as fields | ||||||
|  | import facho.fe.form as form | ||||||
| from datetime import date, datetime | from datetime import date, datetime | ||||||
|  | from copy import copy | ||||||
|  |  | ||||||
| class Name(model.Model): | class Name(model.Model): | ||||||
|     __name__ = 'Name' |     __name__ = 'Name' | ||||||
| @@ -48,24 +50,44 @@ class AccountingSupplierParty(model.Model): | |||||||
|  |  | ||||||
|     party = fields.Many2One(Party) |     party = fields.Many2One(Party) | ||||||
|  |  | ||||||
| class InvoicedQuantity(model.Model): | class Quantity(model.Model): | ||||||
|     __name__  = 'InvoiceQuantity' |     __name__  = 'Quantity' | ||||||
|  |  | ||||||
|     code = fields.Attribute('unitCode', default='NAR') |     code = fields.Attribute('unitCode', default='NAR') | ||||||
|  |     value = fields.Virtual(default=0, update_internal=True) | ||||||
|  |  | ||||||
|  |     def __default_set__(self, value): | ||||||
|  |         self.value = value | ||||||
|  |         return value | ||||||
|  |  | ||||||
|  |     def __mul__(self, other): | ||||||
|  |         return form.Amount(self.value) * other.value | ||||||
|  |  | ||||||
|  |  | ||||||
| class Amount(model.Model): | class Amount(model.Model): | ||||||
|     __name__ = 'Amount' |     __name__ = 'Amount' | ||||||
|  |  | ||||||
|     currency = fields.Attribute('currencyID', default='COP') |     currency = fields.Attribute('currencyID', default='COP') | ||||||
|  |     value = fields.Virtual(default=form.Amount(0), update_internal=True) | ||||||
|  |  | ||||||
|  |     def __default_set__(self, value): | ||||||
|  |         self.value = value | ||||||
|  |         return 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.Virtual(default=form.Amount(0)) | ||||||
|      |      | ||||||
|     def __default_set__(self, value): |     def __default_set__(self, value): | ||||||
|         self.amount = value |         self.amount = value | ||||||
|  |         self.value = value | ||||||
|  |         return value | ||||||
|  |  | ||||||
|  |     def __mul__(self, other): | ||||||
|  |         return self.value * other.value | ||||||
|  |  | ||||||
|  |  | ||||||
| class Percent(model.Model): | class Percent(model.Model): | ||||||
|     __name__ = 'Percent' |     __name__ = 'Percent' | ||||||
| @@ -103,12 +125,51 @@ class TaxTotal(model.Model): | |||||||
|     tax_amount = fields.Many2One(Amount, name='TaxAmount') |     tax_amount = fields.Many2One(Amount, name='TaxAmount') | ||||||
|     subtotals = fields.One2Many(TaxSubTotal) |     subtotals = fields.One2Many(TaxSubTotal) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class AllowanceCharge(model.Model): | ||||||
|  |     __name__ = 'AllowanceCharge' | ||||||
|  |  | ||||||
|  |     amount = fields.Many2One(Amount) | ||||||
|  |     is_discount = fields.Virtual(default=False) | ||||||
|  |      | ||||||
|  |     def isCharge(self): | ||||||
|  |         return self.is_discount == False | ||||||
|  |  | ||||||
|  |     def isDiscount(self): | ||||||
|  |         return self.is_discount == True | ||||||
|  |  | ||||||
| class InvoiceLine(model.Model): | class InvoiceLine(model.Model): | ||||||
|     __name__ = 'InvoiceLine' |     __name__ = 'InvoiceLine' | ||||||
|  |  | ||||||
|     quantity = fields.Many2One(InvoicedQuantity) |     quantity = fields.Many2One(Quantity, name='InvoicedQuantity') | ||||||
|     taxtotal = fields.Many2One(TaxTotal) |     taxtotal = fields.Many2One(TaxTotal) | ||||||
|     price = fields.Many2One(Price) |     price = fields.Many2One(Price) | ||||||
|  |     amount = fields.Many2One(Amount, name='LineExtensionAmount') | ||||||
|  |     allowance_charge = fields.One2Many(AllowanceCharge) | ||||||
|  |  | ||||||
|  |     @fields.on_change(['price', 'quantity']) | ||||||
|  |     def update_amount(self, name, value): | ||||||
|  |         charge = form.AmountCollection(self.allowance_charge)\ | ||||||
|  |             .filter(lambda charge: charge.isCharge())\ | ||||||
|  |             .map(lambda charge: charge.amount)\ | ||||||
|  |             .sum() | ||||||
|  |  | ||||||
|  |         discount = form.AmountCollection(self.allowance_charge)\ | ||||||
|  |             .filter(lambda charge: charge.isDiscount())\ | ||||||
|  |             .map(lambda charge: charge.amount)\ | ||||||
|  |             .sum() | ||||||
|  |  | ||||||
|  |         total = self.quantity  * self.price | ||||||
|  |         self.amount = total + charge - discount | ||||||
|  |  | ||||||
|  | class LegalMonetaryTotal(model.Model): | ||||||
|  |     __name__ = 'LegalMonetaryTotal' | ||||||
|  |  | ||||||
|  |     line_extension_amount = fields.Many2One(Amount, name='LineExtensionAmount', default=form.Amount(0)) | ||||||
|  |     tax_exclusive_amount = fields.Many2One(Amount, name='TaxExclusiveAmount') | ||||||
|  |     tax_inclusive_amount = fields.Many2One(Amount, name='TaxInclusiveAmount') | ||||||
|  |     charge_total_amount = fields.Many2One(Amount, name='ChargeTotalAmount') | ||||||
|  |     payable_amount = fields.Many2One(Amount, name='PayableAmount') | ||||||
|      |      | ||||||
| class Invoice(model.Model): | class Invoice(model.Model): | ||||||
|     __name__ = 'Invoice' |     __name__ = 'Invoice' | ||||||
| @@ -123,6 +184,12 @@ class Invoice(model.Model): | |||||||
|     supplier = fields.Many2One(AccountingSupplierParty) |     supplier = fields.Many2One(AccountingSupplierParty) | ||||||
|     customer = fields.Many2One(AccountingCustomerParty) |     customer = fields.Many2One(AccountingCustomerParty) | ||||||
|     lines = fields.One2Many(InvoiceLine) |     lines = fields.One2Many(InvoiceLine) | ||||||
|  |     legal_monetary_total = fields.Many2One(LegalMonetaryTotal) | ||||||
|  |  | ||||||
|  |     @fields.on_change(['lines']) | ||||||
|  |     def update_legal_monetary_total(self, name, value): | ||||||
|  |         for line in self.lines: | ||||||
|  |             self.legal_monetary_total.line_extension_amount.value += 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): | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ class ModelBase(object, metaclass=ModelMeta): | |||||||
|         obj = super().__new__(cls, *args, **kwargs) |         obj = super().__new__(cls, *args, **kwargs) | ||||||
|         obj._xml_attributes = {} |         obj._xml_attributes = {} | ||||||
|         obj._fields = {} |         obj._fields = {} | ||||||
|         obj._text = "" |         obj._value = None | ||||||
|         obj._namespace_prefix = None |         obj._namespace_prefix = None | ||||||
|         obj._on_change_fields = defaultdict(list) |         obj._on_change_fields = defaultdict(list) | ||||||
|         obj._order_fields = [] |         obj._order_fields = [] | ||||||
| @@ -72,7 +72,7 @@ class ModelBase(object, metaclass=ModelMeta): | |||||||
|     def _set_content(self, value): |     def _set_content(self, value): | ||||||
|         default = self.__default_set__(value) |         default = self.__default_set__(value) | ||||||
|         if default is not None: |         if default is not None: | ||||||
|             self._text = str(default) |             self._value = default | ||||||
|  |  | ||||||
|     def _hook_before_xml(self): |     def _hook_before_xml(self): | ||||||
|         self.__before_xml__() |         self.__before_xml__() | ||||||
| @@ -116,7 +116,9 @@ class ModelBase(object, metaclass=ModelMeta): | |||||||
|                 content += value.to_xml() |                 content += value.to_xml() | ||||||
|             elif isinstance(value, str): |             elif isinstance(value, str): | ||||||
|                 content += value |                 content += value | ||||||
|         content += self._text |  | ||||||
|  |         if self._value is not None: | ||||||
|  |             content += str(self._value) | ||||||
|  |  | ||||||
|         if content == "": |         if content == "": | ||||||
|             return "<%s%s%s/>" % (ns, tag, attributes) |             return "<%s%s%s/>" % (ns, tag, attributes) | ||||||
|   | |||||||
| @@ -17,9 +17,10 @@ class _RelationProxy(): | |||||||
|     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 generar un fallo por recursion | ||||||
|  |         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 setattr(self._obj, attr, value) |         return response | ||||||
|  |  | ||||||
| class _Relation(): | class _Relation(): | ||||||
|     def __init__(self, creator, inst, attribute): |     def __init__(self, creator, inst, attribute): | ||||||
|   | |||||||
| @@ -20,9 +20,21 @@ def test_simple_invoice(): | |||||||
|     invoice.customer.party.id = '800199436' |     invoice.customer.party.id = '800199436' | ||||||
|  |  | ||||||
|     line = invoice.lines.create() |     line = invoice.lines.create() | ||||||
|     line.quantity = form.Quantity(1, '94') |     line.quantity = 1 | ||||||
|     line.price = form.Amount(5_000) |     line.price = form.Amount(5_000) | ||||||
|     subtotal = line.taxtotal.subtotals.create() |     subtotal = line.taxtotal.subtotals.create() | ||||||
|     subtotal.percent = 19.0 |     subtotal.percent = 19.0 | ||||||
|  |     assert '<Invoice><ID>323200000129</ID><IssueDate>2019-01-16T10:53:10-05:00</IssueDate><IssueTime>10:5310-05:00</IssueTime><AccountingSupplierParty><Party><ID>700085371</ID></Party></AccountingSupplierParty><AccountingCustomerParty><Party><ID>800199436</ID></Party></AccountingCustomerParty><InvoiceLine><InvoicedQuantity unitCode="NAR">1</InvoicedQuantity><TaxTotal><TaxSubTotal><TaxCategory><Percent>19.0</Percent><TaxScheme><ID>01</ID><Name>IVA</Name></TaxScheme></TaxCategory></TaxSubTotal></TaxTotal><Price><PriceAmount currencyID="COP">5000.0</PriceAmount>5000.0</Price><LineExtensionAmount currencyID="COP">5000.0</LineExtensionAmount></InvoiceLine><LegalMonetaryTotal><LineExtensionAmount currencyID="COP">35000.0</LineExtensionAmount></LegalMonetaryTotal></Invoice>' == invoice.to_xml() | ||||||
|  |  | ||||||
|     assert '<Invoice><ID>323200000129</ID><IssueDate>2019-01-16T10:53:10-05:00</IssueDate><IssueTime>10:5310-05:00</IssueTime><AccountingSupplierParty><Party><ID>700085371</ID></Party></AccountingSupplierParty><AccountingCustomerParty><Party><ID>800199436</ID></Party></AccountingCustomerParty><InvoiceLine><InvoiceQuantity unitCode="NAR">1.0</InvoiceQuantity><TaxTotal><TaxSubTotal><TaxCategory><Percent>19.0</Percent><TaxScheme><ID>01</ID><Name>IVA</Name></TaxScheme></TaxCategory></TaxSubTotal></TaxTotal><Price><PriceAmount currencyID="COP">5000.0</PriceAmount></Price></InvoiceLine></Invoice>' == invoice.to_xml() | def _test_simple_invoice_cufe(): | ||||||
|  |     invoice = model.Invoice() | ||||||
|  |     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.quantity = form.Quantity(1, '94') | ||||||
|  |     line.price = form.Amount(1_500_000) | ||||||
|  |     subtotal = line.taxtotal.subtotals.create() | ||||||
|  |     subtotal.percent = 19.0 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user