Commit d2111b51 authored by Gabriel Monnerat's avatar Gabriel Monnerat Committed by Jérome Perrin

erp5_accounting: Improve AccountingTransaction_roundDebitCredit to fix the rounding issue

parent 79656b59
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
<key> <string>_body</string> </key> <key> <string>_body</string> </key>
<value> <string encoding="cdata"><![CDATA[ <value> <string encoding="cdata"><![CDATA[
""" Rounds debit and credit lines on generated transactions, according to \n """ Rounds debit and credit lines on generated transactions, according to\n
precision of this transaction\'s resource.\n precision of this transaction\'s resource.\n
"""\n """\n
precision = context.getQuantityPrecisionFromResource(context.getResource())\n precision = context.getQuantityPrecisionFromResource(context.getResource())\n
...@@ -77,9 +77,60 @@ for line in line_list:\n ...@@ -77,9 +77,60 @@ for line in line_list:\n
if abs(round(total_quantity, precision)) > 2 * resource.getBaseUnitQuantity():\n if abs(round(total_quantity, precision)) > 2 * resource.getBaseUnitQuantity():\n
return\n return\n
\n \n
# if the difference is <= the base quantity unit, we round the last line.\n total_price = round(context.getTotalPrice(), precision)\n
if line is not None:\n asset_list = (\'asset/receivable\', \'asset/payable\')\n
line.setQuantity(round(line.getQuantity() - total_quantity, precision))\n try:\n
asset_line = [x for x in line_list \\\n
if x.getSourceValue().getAccountType() in asset_list][0]\n
except IndexError:\n
assert total_price == 0.0 and total_quantity == 0.0, \\\n
\'receivable or payable line not found.\'\n
return\n
\n
account_type_dict = dict()\n
for line in line_list:\n
for account in (line.getSourceValue(portal_type=\'Account\'),\n
line.getDestinationValue(portal_type=\'Account\'),):\n
account_type_dict.setdefault(line, set()).add(\n
account is not None and account.getAccountTypeValue() or None)\n
\n
abs_total_quantity = abs(round(total_quantity, precision))\n
line_to_adjust = None\n
\n
# If we have a difference between total credit and total debit, one line is \n
# chosen to add or remove this difference. The payable or receivable is chosen \n
# only if this line is not matching with invoice total price, because total price\n
# comes from all invoice lines (quantity * price) and it is what should be payed.\n
# And payable or receivable line is the record in the accounting of what has \n
# to be payed. Then, we must not touch it when it already matches.\n
# If is not a payable or receivable, vat or other line (ie. income) is used.\n
if abs_total_quantity != 0:\n
account_type = context.getPortalObject().portal_categories.account_type\n
if round(abs(asset_line.getQuantity()), precision) != round(abs(context.getTotalPrice()), precision):\n
# adjust payable or receivable\n
for line in line_list:\n
if account_type.asset.receivable in account_type_dict[line] or \\\n
account_type.liability.payable in account_type_dict[line]:\n
line_to_adjust = line\n
break\n
if line_to_adjust is None:\n
# VAT\n
for line in line_list:\n
if account_type.asset.receivable.refundable_vat in account_type_dict[line] or \\\n
account_type.liability.payable.collected_vat in account_type_dict[line]:\n
line_to_adjust = line\n
break\n
if line_to_adjust is None:\n
# adjust anything except payable or receivable\n
for line in line_list:\n
if account_type.asset.receivable not in account_type_dict[line] and \\\n
account_type.liability.payable not in account_type_dict[line]:\n
line_to_adjust = line\n
break\n
\n
if line_to_adjust is not None:\n
line_to_adjust.setQuantity(\n
round(line_to_adjust.getQuantity() - total_quantity, precision))\n
]]></string> </value> ]]></string> </value>
......
...@@ -2613,7 +2613,7 @@ class TestSaleInvoice(TestSaleInvoiceMixin, TestInvoice, ERP5TypeTestCase): ...@@ -2613,7 +2613,7 @@ class TestSaleInvoice(TestSaleInvoiceMixin, TestInvoice, ERP5TypeTestCase):
base_unit_quantity=0.01) base_unit_quantity=0.01)
sequence.edit(currency=currency) sequence.edit(currency=currency)
def stepCreateInvoiceWithBadPrecision(self, sequence): def stepCheckInvoiceWithBadPrecision(self, sequence):
portal = self.portal portal = self.portal
vendor = sequence.get('vendor') vendor = sequence.get('vendor')
invoice = portal.accounting_module.newContent( invoice = portal.accounting_module.newContent(
...@@ -2646,6 +2646,11 @@ class TestSaleInvoice(TestSaleInvoiceMixin, TestInvoice, ERP5TypeTestCase): ...@@ -2646,6 +2646,11 @@ class TestSaleInvoice(TestSaleInvoiceMixin, TestInvoice, ERP5TypeTestCase):
if m.getSourceValue().getAccountType() == \ if m.getSourceValue().getAccountType() == \
"asset/receivable"][0] "asset/receivable"][0]
self.assertEquals(0.03, receivable_line.getSourceDebit()) self.assertEquals(0.03, receivable_line.getSourceDebit())
data = invoice.Invoice_getODTDataDict()
precision = invoice.getQuantityPrecisionFromResource(
invoice.getResource())
self.assertEquals(round(data['total_price'], precision),
receivable_line.getSourceDebit())
vat_line = [m for m in movement_list \ vat_line = [m for m in movement_list \
if m.getSourceValue().getAccountType() == \ if m.getSourceValue().getAccountType() == \
"liability/payable/collected_vat"][0] "liability/payable/collected_vat"][0]
...@@ -2655,12 +2660,16 @@ class TestSaleInvoice(TestSaleInvoiceMixin, TestInvoice, ERP5TypeTestCase): ...@@ -2655,12 +2660,16 @@ class TestSaleInvoice(TestSaleInvoiceMixin, TestInvoice, ERP5TypeTestCase):
"income"][0] "income"][0]
self.assertEquals(0.03, income_line.getSourceCredit()) self.assertEquals(0.03, income_line.getSourceCredit())
def test_rounding_issue(self): def test_AccountingTransaction_roundDebitCredit(self):
"""
Check that with two invoice lines with total price equal 0.14,
the receivable line will be 0.03 and vat line 0
"""
sequence_list = SequenceList() sequence_list = SequenceList()
sequence_list.addSequenceString(""" sequence_list.addSequenceString("""
stepCreateCurrency stepCreateCurrency
stepCreateEntities stepCreateEntities
stepCreateInvoiceWithBadPrecision stepCheckInvoiceWithBadPrecision
""") """)
sequence_list.play(self) sequence_list.play(self)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment