Commit 439ff1b3 authored by Jérome Perrin's avatar Jérome Perrin

accounting: reset grouping reference in a "context free" script

Introduce a new ERP5Site_resetAccountingTransactionLineGroupingReference
script to reset grouping reference on accounting transaction lines.

This solve a problem with the way we activated on
AccountingTransactionLine_resetGroupingReference the context of the
line, if line was removed from OFS before activity was executed, the
activity was discarded and grouping references on related lines was not
reset.

Also drop the unused `keep_if_valid_group` parameter, it was not making
sense.

/reviewed-on nexedi/erp5!849
parent a3dada56
"""Resets grouping reference on this line and all related lines. """Resets grouping reference on this line and all related lines.
If the parameter keep_if_valid_group is true, then the grouping reference This runs by default asynchronously, but can be call with `async=False` to
will be kept as is if the group is still valid, ie. the total quantity run synchronously and returns the list of ungrouped lines. With `async=True`,
of all accounting lines in the group is 0. the returned list is always empty.
Returns the list of ungroupped lines.
""" """
if not context.getGroupingReference(): if not context.getGroupingReference():
# The line grouping reference can alredy have been removed, for example when two # The line grouping reference can already have been removed, for example when two
# lines of the same transaction have the same grouping reference. # lines of the same transaction have the same grouping reference.
return [] return []
portal = context.getPortalObject() portal = context.getPortalObject()
precision = context.getResourceValue(portal_type='Currency').getQuantityPrecision()
if context.AccountingTransaction_isSourceView(): resetGroupingReference = portal.ERP5Site_resetAccountingTransactionLineGroupingReference
node_uid = context.getSourceUid() if async:
section_category = None resetGroupingReference = portal.portal_simulation.activate(
section = context.getSourceSectionValue() after_tag='accounting_grouping_reference'
if section is not None: ).ERP5Site_resetAccountingTransactionLineGroupingReference
section = section.Organisation_getMappingRelatedOrganisation()
section_category = section.getGroup(base=1) ungrouped_line_list = []
mirror_section_uid = context.getDestinationSectionUid() for (section_value, node_uid, mirror_section_uid) in (
else: (context.getSourceSectionValue(), context.getSourceUid(), context.getDestinationSectionUid(),),
node_uid = context.getDestinationUid() (context.getDestinationSectionValue(), context.getDestinationUid(), context.getSourceSectionUid(),),
section = context.getDestinationSectionValue() ):
if section is not None: if section_value is not None:
section = section.Organisation_getMappingRelatedOrganisation() section_value = section_value.Organisation_getMappingRelatedOrganisation()
section_category = section.getGroup(base=1) section_category = section_value.getGroup(base=True)
mirror_section_uid = context.getSourceSectionUid() if section_category:
ungrouped_line_list.extend(resetGroupingReference(
line_list = portal.portal_simulation.getMovementHistoryList( section_category=section_category,
portal_type=portal.getPortalAccountingMovementTypeList(), node_uid=node_uid,
grouping_reference=context.getGroupingReference(), mirror_section_uid=mirror_section_uid,
node_uid=node_uid, grouping_reference=context.getGroupingReference()
section_category=section_category, ) or [])
mirror_section_uid=mirror_section_uid)
return ungrouped_line_list
# If the group is still valid, we may want to keep it as is.
if keep_if_valid_group and round(sum([(l.total_price or 0) for l in line_list]), precision) == 0:
return
for line in line_list:
line.setGroupingReference(None)
line.setGroupingDate(None)
return line_list
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>keep_if_valid_group=0</string> </value> <value> <string>async=True</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -114,7 +114,9 @@ else: ...@@ -114,7 +114,9 @@ else:
ungrouped_line_list = [] ungrouped_line_list = []
for line in line_list: for line in line_list:
if line.getGroupingReference(): if line.getGroupingReference():
ungrouped_line_list.extend(line.AccountingTransactionLine_resetGroupingReference()) # Call AccountingTransactionLine_resetGroupingReference synchronously
# to know the number of ungrouped lines.
ungrouped_line_list.extend(line.AccountingTransactionLine_resetGroupingReference(async=False))
psm = Base_translateString('${ungrouped_line_count} lines ungrouped.', psm = Base_translateString('${ungrouped_line_count} lines ungrouped.',
mapping=dict(ungrouped_line_count=len(ungrouped_line_list))) mapping=dict(ungrouped_line_count=len(ungrouped_line_list)))
......
portal = context.getPortalObject()
line_list = []
for brain in portal.portal_simulation.getMovementHistoryList(
portal_type=portal.getPortalAccountingMovementTypeList(),
grouping_reference=grouping_reference,
node_uid=node_uid,
section_category=section_category,
mirror_section_uid=mirror_section_uid):
line = brain.getObject()
line.setGroupingReference(None)
line.setGroupingDate(None)
line_list.append(line)
return line_list
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>section_category, node_uid, mirror_section_uid, grouping_reference</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ERP5Site_resetAccountingTransactionLineGroupingReference</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
"""When transaction is restarted, we'll break existing grouping references on lines. """When transaction is restarted, we'll unset existing grouping references on lines.
""" """
transaction = sci['object'] transaction = sci['object']
for line in transaction.getMovementList( for line in transaction.getMovementList(
portal_type=sci.getPortal().getPortalAccountingMovementTypeList()): portal_type=sci.getPortal().getPortalAccountingMovementTypeList()):
if line.getGroupingReference(): line.AccountingTransactionLine_resetGroupingReference()
line.activate(
after_tag='accounting_grouping_reference'
).AccountingTransactionLine_resetGroupingReference()
...@@ -3675,7 +3675,7 @@ class TestTransactions(AccountingTestCase): ...@@ -3675,7 +3675,7 @@ class TestTransactions(AccountingTestCase):
# reset from the payment line, the invoice line from the same group will be # reset from the payment line, the invoice line from the same group will be
# ungrouped # ungrouped
payment_line.AccountingTransactionLine_resetGroupingReference() payment_line.AccountingTransactionLine_resetGroupingReference(async=False)
self.assertFalse(payment_line.getGroupingReference()) self.assertFalse(payment_line.getGroupingReference())
self.assertFalse(payment_line.getGroupingDate()) self.assertFalse(payment_line.getGroupingDate())
self.assertFalse(invoice_line.getGroupingReference()) self.assertFalse(invoice_line.getGroupingReference())
...@@ -3688,6 +3688,41 @@ class TestTransactions(AccountingTestCase): ...@@ -3688,6 +3688,41 @@ class TestTransactions(AccountingTestCase):
self.assertTrue(other_section_line.getGroupingDate()) self.assertTrue(other_section_line.getGroupingDate())
self.assertTrue(other_letter_line.getGroupingDate()) self.assertTrue(other_letter_line.getGroupingDate())
def test_GroupingReferenceResetedOnCancelWithDeleteRaceCondition(self):
"""Reproduction for a bug when transaction is cancelled and grouped line
is deleted before the reset-grouping-reference activity is executed, the
related grouped lines where not reset.
"""
invoice = self._makeOne(
title='First Invoice',
destination_section_value=self.organisation_module.client_1,
lines=(dict(source_value=self.account_module.goods_purchase,
source_debit=100),
dict(source_value=self.account_module.receivable,
source_credit=100,
id='line_with_grouping_reference',
grouping_date=DateTime(),
grouping_reference='A'),))
payment = self._makeOne(
title='First Invoice Payment',
portal_type='Payment Transaction',
source_payment_value=self.section.newContent(
portal_type='Bank Account'),
destination_section_value=self.organisation_module.client_1,
lines=(dict(source_value=self.account_module.receivable,
id='line_with_grouping_reference',
grouping_reference='A',
grouping_date=DateTime(),
source_debit=100),
dict(source_value=self.account_module.bank,
source_credit=100,)))
payment_line = payment.line_with_grouping_reference
self.tic()
invoice.cancel()
invoice.manage_delObjects([line.getId() for line in invoice.contentValues()])
self.tic()
self.assertFalse(payment.line_with_grouping_reference.getGroupingReference())
def test_automatically_setting_grouping_reference(self): def test_automatically_setting_grouping_reference(self):
invoice = self._makeOne( invoice = self._makeOne(
title='First Invoice', title='First Invoice',
......
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