Commit 68c37523 authored by Jérome Perrin's avatar Jérome Perrin

accounting: prevent user from creating balance transaction while previous one...

accounting: prevent user from creating balance transaction while previous one is still beeing reindexed
parent 35f4f631
...@@ -67,8 +67,8 @@ def roundCurrency(value, resource_relative_url):\n ...@@ -67,8 +67,8 @@ def roundCurrency(value, resource_relative_url):\n
qty_precision = precision_cache[resource_relative_url]\n qty_precision = precision_cache[resource_relative_url]\n
return round(value, qty_precision)\n return round(value, qty_precision)\n
\n \n
# This tag is checked in accounting period workflow\n
activity_tag = \'BalanceTransactionCreation\'\n activity_tag = \'BalanceTransactionCreation\'\n
activate_kw=dict(tag=activity_tag)\n
\n \n
at_date = context.getStopDate()\n at_date = context.getStopDate()\n
assert at_date\n assert at_date\n
...@@ -109,7 +109,7 @@ def getDependantSectionList(group, main_section):\n ...@@ -109,7 +109,7 @@ def getDependantSectionList(group, main_section):\n
section_list.extend(getDependantSectionList(subgroup, main_section))\n section_list.extend(getDependantSectionList(subgroup, main_section))\n
\n \n
return section_list\n return section_list\n
\n \n
group_value = section.getGroupValue()\n group_value = section.getGroupValue()\n
section_list = [section]\n section_list = [section]\n
if group_value is not None:\n if group_value is not None:\n
...@@ -117,7 +117,6 @@ if group_value is not None:\n ...@@ -117,7 +117,6 @@ if group_value is not None:\n
\n \n
def createBalanceTransaction(section):\n def createBalanceTransaction(section):\n
return portal.accounting_module.newContent(\n return portal.accounting_module.newContent(\n
activate_kw=activate_kw,\n
portal_type=\'Balance Transaction\',\n portal_type=\'Balance Transaction\',\n
start_date=(at_date + 1).earliestTime(),\n start_date=(at_date + 1).earliestTime(),\n
title=context.getTitle() or Base_translateString(\'Balance Transaction\'),\n title=context.getTitle() or Base_translateString(\'Balance Transaction\'),\n
...@@ -125,221 +124,214 @@ def createBalanceTransaction(section):\n ...@@ -125,221 +124,214 @@ def createBalanceTransaction(section):\n
resource=section_currency,\n resource=section_currency,\n
causality_value=context)\n causality_value=context)\n
\n \n
for section in section_list:\n with context.defaultActivateParameterDict({\'tag\': activity_tag}, placeless=True):\n
section_uid = section.getUid()\n for section in section_list:\n
balance_transaction = None\n section_uid = section.getUid()\n
\n balance_transaction = None\n
group_by_node_node_category_list = []\n \n
group_by_mirror_section_node_category_list = []\n group_by_node_node_category_list = []\n
group_by_payment_node_category_list = []\n group_by_mirror_section_node_category_list = []\n
profit_and_loss_node_category_list = []\n group_by_payment_node_category_list = []\n
\n profit_and_loss_node_category_list = []\n
node_category_list = portal.portal_categories\\\n \n
.account_type.getCategoryChildValueList()\n node_category_list = portal.portal_categories\\\n
for node_category in node_category_list:\n .account_type.getCategoryChildValueList()\n
node_category_url = node_category.getRelativeUrl()\n for node_category in node_category_list:\n
if node_category_url in (\n node_category_url = node_category.getRelativeUrl()\n
\'account_type/asset/cash/bank\',):\n if node_category_url in (\n
group_by_payment_node_category_list.append(node_category_url)\n \'account_type/asset/cash/bank\',):\n
elif node_category_url in (\n group_by_payment_node_category_list.append(node_category_url)\n
\'account_type/asset/receivable\',\n elif node_category_url in (\n
\'account_type/liability/payable\'):\n \'account_type/asset/receivable\',\n
group_by_mirror_section_node_category_list.append(node_category_url)\n \'account_type/liability/payable\'):\n
elif node_category.isMemberOf(\'account_type/income\') or \\\n group_by_mirror_section_node_category_list.append(node_category_url)\n
node_category.isMemberOf(\'account_type/expense\'):\n elif node_category.isMemberOf(\'account_type/income\') or \\\n
profit_and_loss_node_category_list.append(node_category_url)\n node_category.isMemberOf(\'account_type/expense\'):\n
else:\n profit_and_loss_node_category_list.append(node_category_url)\n
group_by_node_node_category_list.append(node_category_url)\n else:\n
\n group_by_node_node_category_list.append(node_category_url)\n
getInventoryList = portal.portal_simulation.getInventoryList\n \n
\n getInventoryList = portal.portal_simulation.getInventoryList\n
inventory_param_dict = dict(section_uid=section_uid,\n \n
simulation_state=(\'delivered\',),\n inventory_param_dict = dict(section_uid=section_uid,\n
precision=section_currency_precision,\n simulation_state=(\'delivered\',),\n
portal_type=portal.getPortalAccountingMovementTypeList(),\n precision=section_currency_precision,\n
at_date=at_date.latestTime(),)\n portal_type=portal.getPortalAccountingMovementTypeList(),\n
\n at_date=at_date.latestTime(),)\n
# Calculate the sum of profit and loss accounts balances for that period.\n
# This must match the difference between assets, liability and equity accounts.\n
profit_and_loss_accounts_balance = portal.portal_simulation.getInventoryAssetPrice(\n
from_date=context.getStartDate(),\n
node_category_strict_membership=profit_and_loss_node_category_list,\n
**inventory_param_dict)\n
selected_profit_and_loss_account_balance = portal.portal_simulation.getInventoryAssetPrice(\n
node=profit_and_loss_account,\n
resource=section_currency,\n
**inventory_param_dict)\n
\n \n
section_currency_uid = context.getParentValue().getPriceCurrencyUid()\n # Calculate the sum of profit and loss accounts balances for that period.\n
\n # This must match the difference between assets, liability and equity accounts.\n
profit_and_loss_quantity = 0\n profit_and_loss_accounts_balance = portal.portal_simulation.getInventoryAssetPrice(\n
line_count = 0\n from_date=context.getStartDate(),\n
\n node_category_strict_membership=profit_and_loss_node_category_list,\n
for inventory in getInventoryList(\n **inventory_param_dict)\n
node_category_strict_membership=group_by_node_node_category_list,\n selected_profit_and_loss_account_balance = portal.portal_simulation.getInventoryAssetPrice(\n
group_by_node=1,\n node=profit_and_loss_account,\n
group_by_resource=1,\n resource=section_currency,\n
**inventory_param_dict):\n **inventory_param_dict)\n
\n \n
total_price = roundCurrency(inventory.total_price or 0, section_currency)\n section_currency_uid = context.getParentValue().getPriceCurrencyUid()\n
quantity = roundCurrency(inventory.total_quantity or 0,\n \n
inventory.resource_relative_url)\n profit_and_loss_quantity = 0\n
\n line_count = 0\n
if not total_price and not quantity:\n \n
continue\n for inventory in getInventoryList(\n
\n node_category_strict_membership=group_by_node_node_category_list,\n
line_count += 1\n group_by_node=1,\n
if inventory.resource_uid != section_currency_uid:\n group_by_resource=1,\n
**inventory_param_dict):\n
\n
total_price = roundCurrency(inventory.total_price or 0, section_currency)\n
quantity = roundCurrency(inventory.total_quantity or 0,\n
inventory.resource_relative_url)\n
\n
if not total_price and not quantity:\n
continue\n
\n
line_count += 1\n
if inventory.resource_uid != section_currency_uid:\n
profit_and_loss_quantity += total_price\n
\n
if balance_transaction is None:\n
balance_transaction = createBalanceTransaction(section)\n
balance_transaction.newContent(\n
id=\'%03d\' % line_count,\n
portal_type=\'Balance Transaction Line\',\n
destination=inventory.node_relative_url,\n
resource=inventory.resource_relative_url,\n
quantity=quantity,\n
destination_total_asset_price=total_price)\n
else:\n
if total_price != quantity:\n
# If this fail for you, your accounting doesn\'t use currencies with\n
# consistency\n
raise ValueError(\'Different price: %s != %s \' % (\n
total_price, quantity))\n
\n
if inventory.node_relative_url != profit_and_loss_account:\n
profit_and_loss_quantity += total_price\n
if balance_transaction is None:\n
balance_transaction = createBalanceTransaction(section)\n
balance_transaction.newContent(\n
id=\'%03d\' % line_count,\n
portal_type=\'Balance Transaction Line\',\n
destination=inventory.node_relative_url,\n
quantity=total_price)\n
\n
\n
for inventory in getInventoryList(\n
node_category_strict_membership=group_by_mirror_section_node_category_list,\n
group_by_node=1,\n
group_by_mirror_section=1,\n
group_by_resource=1,\n
**inventory_param_dict):\n
\n
total_price = roundCurrency(inventory.total_price or 0, section_currency)\n
quantity = roundCurrency(inventory.total_quantity or 0,\n
inventory.resource_relative_url)\n
\n
if not total_price and not quantity:\n
continue\n
profit_and_loss_quantity += total_price\n profit_and_loss_quantity += total_price\n
\n line_count += 1\n
if balance_transaction is None:\n \n
balance_transaction = createBalanceTransaction(section)\n if inventory.resource_uid != section_currency_uid:\n
balance_transaction.newContent(\n if balance_transaction is None:\n
balance_transaction = createBalanceTransaction(section)\n
balance_transaction.newContent(\n
id=\'%03d\' % line_count,\n id=\'%03d\' % line_count,\n
portal_type=\'Balance Transaction Line\',\n portal_type=\'Balance Transaction Line\',\n
activate_kw=activate_kw,\n
destination=inventory.node_relative_url,\n destination=inventory.node_relative_url,\n
source_section_uid=inventory.mirror_section_uid,\n
resource=inventory.resource_relative_url,\n resource=inventory.resource_relative_url,\n
quantity=quantity,\n quantity=quantity,\n
destination_total_asset_price=total_price)\n destination_total_asset_price=total_price)\n
else:\n else:\n
if total_price != quantity:\n if total_price != quantity:\n
# If this fail for you, your accounting doesn\'t use currencies with\n raise ValueError(\'Different price: %s != %s \' % (\n
# consistency\n total_price, quantity))\n
raise ValueError(\'Different price: %s != %s \' % (\n
total_price, quantity))\n
\n
if inventory.node_relative_url != profit_and_loss_account:\n
profit_and_loss_quantity += total_price\n
if balance_transaction is None:\n if balance_transaction is None:\n
balance_transaction = createBalanceTransaction(section)\n balance_transaction = createBalanceTransaction(section)\n
balance_transaction.newContent(\n balance_transaction.newContent(\n
id=\'%03d\' % line_count,\n id=\'%03d\' % line_count,\n
portal_type=\'Balance Transaction Line\',\n portal_type=\'Balance Transaction Line\',\n
activate_kw=activate_kw,\n
destination=inventory.node_relative_url,\n destination=inventory.node_relative_url,\n
source_section_uid=inventory.mirror_section_uid,\n
quantity=total_price)\n quantity=total_price)\n
\n \n
\n
for inventory in getInventoryList(\n
node_category_strict_membership=group_by_mirror_section_node_category_list,\n
group_by_node=1,\n
group_by_mirror_section=1,\n
group_by_resource=1,\n
**inventory_param_dict):\n
\n
total_price = roundCurrency(inventory.total_price or 0, section_currency)\n
quantity = roundCurrency(inventory.total_quantity or 0,\n
inventory.resource_relative_url)\n
\n
if not total_price and not quantity:\n
continue\n
profit_and_loss_quantity += total_price\n
line_count += 1\n
\n \n
if inventory.resource_uid != section_currency_uid:\n for inventory in getInventoryList(\n
if balance_transaction is None:\n node_category_strict_membership=group_by_payment_node_category_list,\n
balance_transaction = createBalanceTransaction(section)\n group_by_node=1,\n
balance_transaction.newContent(\n group_by_payment=1,\n
id=\'%03d\' % line_count,\n group_by_resource=1,\n
portal_type=\'Balance Transaction Line\',\n **inventory_param_dict):\n
activate_kw=activate_kw,\n \n
destination=inventory.node_relative_url,\n total_price = roundCurrency(inventory.total_price or 0, section_currency)\n
source_section_uid=inventory.mirror_section_uid,\n quantity = roundCurrency(inventory.total_quantity or 0,\n
resource=inventory.resource_relative_url,\n inventory.resource_relative_url)\n
quantity=quantity,\n \n
destination_total_asset_price=total_price)\n if not total_price and not quantity:\n
else:\n continue\n
if total_price != quantity:\n profit_and_loss_quantity += total_price\n
raise ValueError(\'Different price: %s != %s \' % (\n \n
total_price, quantity))\n line_count += 1\n
if balance_transaction is None:\n \n
if inventory.resource_uid != section_currency_uid:\n
if balance_transaction is None:\n
balance_transaction = createBalanceTransaction(section)\n
balance_transaction.newContent(\n
id=\'%03d\' % line_count,\n
portal_type=\'Balance Transaction Line\',\n
destination=inventory.node_relative_url,\n
resource=inventory.resource_relative_url,\n
quantity=quantity,\n
destination_payment_uid=inventory.payment_uid,\n
destination_total_asset_price=total_price)\n
else:\n
if total_price != quantity:\n
raise ValueError(\'Different price: %s != %s \' % (\n
total_price, quantity))\n
if balance_transaction is None:\n
balance_transaction = createBalanceTransaction(section)\n
balance_transaction.newContent(\n
id=\'%03d\' % line_count,\n
portal_type=\'Balance Transaction Line\',\n
destination=inventory.node_relative_url,\n
destination_payment_uid=inventory.payment_uid,\n
quantity=total_price)\n
\n
if balance_transaction is None:\n
# we did not have any transaction for this section\n
\n
# One possible corner case is that we have only transactions that brings\n
# the balance of all balance sheets accounts to 0. In this case we want to\n
# create a balance transaction that notes that the current balance of profit\n
# and loss account is 0, so that the delta gets indexed. \n
if profit_and_loss_accounts_balance:\n
balance_transaction = createBalanceTransaction(section)\n balance_transaction = createBalanceTransaction(section)\n
balance_transaction.newContent(\n balance_transaction.newContent(\n
id=\'%03d\' % line_count,\n portal_type=\'Balance Transaction Line\',\n
portal_type=\'Balance Transaction Line\',\n destination=profit_and_loss_account,\n
activate_kw=activate_kw,\n quantity=0)\n
destination=inventory.node_relative_url,\n balance_transaction.stop()\n
source_section_uid=inventory.mirror_section_uid,\n balance_transaction.deliver()\n
quantity=total_price)\n
\n
\n
for inventory in getInventoryList(\n
node_category_strict_membership=group_by_payment_node_category_list,\n
group_by_node=1,\n
group_by_payment=1,\n
group_by_resource=1,\n
**inventory_param_dict):\n
\n
total_price = roundCurrency(inventory.total_price or 0, section_currency)\n
quantity = roundCurrency(inventory.total_quantity or 0,\n
inventory.resource_relative_url)\n
\n
if not total_price and not quantity:\n
continue\n continue\n
profit_and_loss_quantity += total_price\n
\n
line_count += 1\n
\n \n
if inventory.resource_uid != section_currency_uid:\n assert roundCurrency(profit_and_loss_accounts_balance, section_currency) == roundCurrency(\n
if balance_transaction is None:\n - roundCurrency(selected_profit_and_loss_account_balance, section_currency)\n
balance_transaction = createBalanceTransaction(section)\n - roundCurrency(profit_and_loss_quantity, section_currency), section_currency)\n
balance_transaction.newContent(\n \n
id=\'%03d\' % line_count,\n # add a final line for p&l\n
portal_type=\'Balance Transaction Line\',\n balance_transaction.newContent(\n
activate_kw=activate_kw,\n id=\'%03d\' % (line_count + 1),\n
destination=inventory.node_relative_url,\n portal_type=\'Balance Transaction Line\',\n
resource=inventory.resource_relative_url,\n destination=profit_and_loss_account,\n
quantity=quantity,\n quantity=-profit_and_loss_quantity)\n
destination_payment_uid=inventory.payment_uid,\n
destination_total_asset_price=total_price)\n
else:\n
if total_price != quantity:\n
raise ValueError(\'Different price: %s != %s \' % (\n
total_price, quantity))\n
if balance_transaction is None:\n
balance_transaction = createBalanceTransaction(section)\n
balance_transaction.newContent(\n
id=\'%03d\' % line_count,\n
portal_type=\'Balance Transaction Line\',\n
activate_kw=activate_kw,\n
destination=inventory.node_relative_url,\n
destination_payment_uid=inventory.payment_uid,\n
quantity=total_price)\n
\n
if balance_transaction is None:\n
# we did not have any transaction for this section\n
\n
# One possible corner case is that we have only transactions that brings\n
# the balance of all balance sheets accounts to 0. In this case we want to\n
# create a balance transaction that notes that the current balance of profit\n
# and loss account is 0, so that the delta gets indexed. \n
if profit_and_loss_accounts_balance:\n
balance_transaction = createBalanceTransaction(section)\n
balance_transaction.newContent(\n
activate_kw=activate_kw,\n
portal_type=\'Balance Transaction Line\',\n
destination=profit_and_loss_account,\n
quantity=0)\n
balance_transaction.stop()\n
balance_transaction.deliver()\n
continue\n
\n
assert roundCurrency(profit_and_loss_accounts_balance, section_currency) == roundCurrency(\n
- roundCurrency(selected_profit_and_loss_account_balance, section_currency)\n
- roundCurrency(profit_and_loss_quantity, section_currency), section_currency)\n
\n
# add a final line for p&l\n
balance_transaction.newContent(\n
id=\'%03d\' % (line_count + 1),\n
activate_kw=activate_kw,\n
portal_type=\'Balance Transaction Line\',\n
destination=profit_and_loss_account,\n
quantity=-profit_and_loss_quantity)\n
\n \n
# and go to delivered state directly (the user is not supposed to edit this document)\n # and go to delivered state directly (the user is not supposed to edit this document)\n
balance_transaction.stop()\n balance_transaction.stop()\n
balance_transaction.deliver()\n balance_transaction.deliver()\n
\n \n
# make sure this Accounting Period has an activity pending during the indexing\n # make sure this Accounting Period has an activity pending during the indexing\n
# of the balance transaction.\n # of the balance transaction.\n
......
...@@ -60,6 +60,10 @@ portal = period.getPortalObject()\n ...@@ -60,6 +60,10 @@ portal = period.getPortalObject()\n
\n \n
period.Base_checkConsistency()\n period.Base_checkConsistency()\n
\n \n
# This tag is used in AccountingPeriod_createBalanceTransaction\n
if portal.portal_activities.countMessageWithTag(\'BalanceTransactionCreation\'):\n
raise ValidationFailed(translateString("Balance transaction creation already in progress. Please try again later."))\n
\n
valid_simulation_state_list = [\'cancelled\', \'delivered\', \'deleted\', \'rejected\']\n valid_simulation_state_list = [\'cancelled\', \'delivered\', \'deleted\', \'rejected\']\n
all_state_list = [x[1] for x in\n all_state_list = [x[1] for x in\n
portal.Base_getTranslatedWorkflowStateItemList(wf_id=\'accounting_workflow\')]\n portal.Base_getTranslatedWorkflowStateItemList(wf_id=\'accounting_workflow\')]\n
......
...@@ -2499,6 +2499,40 @@ class TestClosingPeriod(AccountingTestCase): ...@@ -2499,6 +2499,40 @@ class TestClosingPeriod(AccountingTestCase):
section_uid=self.section.getUid(), section_uid=self.section.getUid(),
node_uid=self.account_module.receivable.getUid())) node_uid=self.account_module.receivable.getUid()))
def test_ParrallelClosingRefused(self):
organisation_module = self.organisation_module
stool = self.portal.portal_simulation
period = self.section.newContent(portal_type='Accounting Period')
period.setStartDate(DateTime(2006, 1, 1))
period.setStopDate(DateTime(2006, 12, 31))
period.start()
period2 = self.section.newContent(portal_type='Accounting Period')
period2.setStartDate(DateTime(2007, 1, 1))
period2.setStopDate(DateTime(2007, 12, 31))
period2.start()
pl = self.portal.account_module.newContent(
portal_type='Account',
account_type='equity')
transaction1 = self._makeOne(
start_date=DateTime(2006, 1, 1),
destination_section_value=organisation_module.client_1,
portal_type='Sale Invoice Transaction',
simulation_state='delivered',
lines=(dict(source_value=self.account_module.goods_sales,
source_credit=100),
dict(source_value=self.account_module.receivable,
source_debit=100)))
self.portal.portal_workflow.doActionFor(
period, 'stop_action',
profit_and_loss_account=pl.getRelativeUrl())
self.assertRaises(ValidationFailed,
self.getPortal().portal_workflow.doActionFor,
period2, 'stop_action' )
class TestAccountingExport(AccountingTestCase): class TestAccountingExport(AccountingTestCase):
......
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