Commit e166c259 authored by Nicolas Wavrant's avatar Nicolas Wavrant

erp5_accounting: closing an Accounting Period generates one Balance...

erp5_accounting: closing an Accounting Period generates one Balance Transaction per accounting ledger
parent e8067494
"""Creates a balance transaction to open the next period. """Creates a balance transaction to open the next period.
""" """
from Products.ZSQLCatalog.SQLCatalog import Query
portal = context.getPortalObject() portal = context.getPortalObject()
Base_translateString = portal.Base_translateString Base_translateString = portal.Base_translateString
...@@ -61,7 +63,9 @@ section_list = [section] ...@@ -61,7 +63,9 @@ section_list = [section]
if group_value is not None: if group_value is not None:
section_list.extend(getDependantSectionList(group_value, section)) section_list.extend(getDependantSectionList(group_value, section))
def createBalanceTransaction(section): ledger_list = portal.portal_categories.ledger.getCategoryChildValueList(is_self_excluded=1) + [None,]
def createBalanceTransaction(section, ledger=None):
balance_date = at_date + 1 balance_date = at_date + 1
# We discard hours, minutes and seconds and at the same time, make sure the date # We discard hours, minutes and seconds and at the same time, make sure the date
# is in its "normal timezone". For example, when at_date is the day of a dailight saving # is in its "normal timezone". For example, when at_date is the day of a dailight saving
...@@ -69,6 +73,7 @@ def createBalanceTransaction(section): ...@@ -69,6 +73,7 @@ def createBalanceTransaction(section):
balance_date = DateTime(balance_date.year(), balance_date.month(), balance_date.day()) balance_date = DateTime(balance_date.year(), balance_date.month(), balance_date.day())
return portal.accounting_module.newContent( return portal.accounting_module.newContent(
portal_type='Balance Transaction', portal_type='Balance Transaction',
ledger=ledger,
start_date=balance_date, start_date=balance_date,
title=context.getTitle() or Base_translateString('Balance Transaction'), title=context.getTitle() or Base_translateString('Balance Transaction'),
destination_section_value=section, destination_section_value=section,
...@@ -76,6 +81,7 @@ def createBalanceTransaction(section): ...@@ -76,6 +81,7 @@ def createBalanceTransaction(section):
causality_value=context) causality_value=context)
with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True): with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True):
for ledger in ledger_list:
for section in section_list: for section in section_list:
section_uid = section.getUid() section_uid = section.getUid()
balance_transaction = None balance_transaction = None
...@@ -104,11 +110,19 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True) ...@@ -104,11 +110,19 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True)
getInventoryList = portal.portal_simulation.getInventoryList getInventoryList = portal.portal_simulation.getInventoryList
if ledger is not None:
ledger_uid = ledger.getUid()
ledger_url = ledger.getCategoryRelativeUrl()
else:
ledger_uid = Query(ledger_uid=None)
ledger_url = ''
inventory_param_dict = dict(section_uid=section_uid, inventory_param_dict = dict(section_uid=section_uid,
simulation_state=('delivered',), simulation_state=('delivered',),
precision=section_currency_precision, precision=section_currency_precision,
portal_type=portal.getPortalAccountingMovementTypeList(), portal_type=portal.getPortalAccountingMovementTypeList(),
at_date=at_date.latestTime(),) at_date=at_date.latestTime(),
ledger_uid=ledger_uid)
# Calculate the sum of profit and loss accounts balances for that period. # Calculate the sum of profit and loss accounts balances for that period.
# This must match the difference between assets, liability and equity accounts. # This must match the difference between assets, liability and equity accounts.
...@@ -144,7 +158,7 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True) ...@@ -144,7 +158,7 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True)
profit_and_loss_quantity += total_price profit_and_loss_quantity += total_price
if balance_transaction is None: if balance_transaction is None:
balance_transaction = createBalanceTransaction(section) balance_transaction = createBalanceTransaction(section, ledger_url)
balance_transaction.newContent( balance_transaction.newContent(
id='%03d' % line_count, id='%03d' % line_count,
portal_type='Balance Transaction Line', portal_type='Balance Transaction Line',
...@@ -162,7 +176,7 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True) ...@@ -162,7 +176,7 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True)
if inventory.node_relative_url != profit_and_loss_account: if inventory.node_relative_url != profit_and_loss_account:
profit_and_loss_quantity += total_price profit_and_loss_quantity += total_price
if balance_transaction is None: if balance_transaction is None:
balance_transaction = createBalanceTransaction(section) balance_transaction = createBalanceTransaction(section, ledger_url)
balance_transaction.newContent( balance_transaction.newContent(
id='%03d' % line_count, id='%03d' % line_count,
portal_type='Balance Transaction Line', portal_type='Balance Transaction Line',
...@@ -188,7 +202,7 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True) ...@@ -188,7 +202,7 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True)
if inventory.resource_uid != section_currency_uid: if inventory.resource_uid != section_currency_uid:
if balance_transaction is None: if balance_transaction is None:
balance_transaction = createBalanceTransaction(section) balance_transaction = createBalanceTransaction(section, ledger_url)
balance_transaction.newContent( balance_transaction.newContent(
id='%03d' % line_count, id='%03d' % line_count,
portal_type='Balance Transaction Line', portal_type='Balance Transaction Line',
...@@ -202,7 +216,7 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True) ...@@ -202,7 +216,7 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True)
raise ValueError('Different price: %s != %s ' % ( raise ValueError('Different price: %s != %s ' % (
total_price, quantity)) total_price, quantity))
if balance_transaction is None: if balance_transaction is None:
balance_transaction = createBalanceTransaction(section) balance_transaction = createBalanceTransaction(section, ledger_url)
balance_transaction.newContent( balance_transaction.newContent(
id='%03d' % line_count, id='%03d' % line_count,
portal_type='Balance Transaction Line', portal_type='Balance Transaction Line',
...@@ -230,7 +244,7 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True) ...@@ -230,7 +244,7 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True)
if inventory.resource_uid != section_currency_uid: if inventory.resource_uid != section_currency_uid:
if balance_transaction is None: if balance_transaction is None:
balance_transaction = createBalanceTransaction(section) balance_transaction = createBalanceTransaction(section, ledger_url)
balance_transaction.newContent( balance_transaction.newContent(
id='%03d' % line_count, id='%03d' % line_count,
portal_type='Balance Transaction Line', portal_type='Balance Transaction Line',
...@@ -244,7 +258,7 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True) ...@@ -244,7 +258,7 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True)
raise ValueError('Different price: %s != %s ' % ( raise ValueError('Different price: %s != %s ' % (
total_price, quantity)) total_price, quantity))
if balance_transaction is None: if balance_transaction is None:
balance_transaction = createBalanceTransaction(section) balance_transaction = createBalanceTransaction(section, ledger_url)
balance_transaction.newContent( balance_transaction.newContent(
id='%03d' % line_count, id='%03d' % line_count,
portal_type='Balance Transaction Line', portal_type='Balance Transaction Line',
...@@ -260,7 +274,7 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True) ...@@ -260,7 +274,7 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True)
# create a balance transaction that notes that the current balance of profit # create a balance transaction that notes that the current balance of profit
# and loss account is 0, so that the delta gets indexed. # and loss account is 0, so that the delta gets indexed.
if profit_and_loss_accounts_balance: if profit_and_loss_accounts_balance:
balance_transaction = createBalanceTransaction(section) balance_transaction = createBalanceTransaction(section, ledger_url)
balance_transaction.newContent( balance_transaction.newContent(
portal_type='Balance Transaction Line', portal_type='Balance Transaction Line',
destination=profit_and_loss_account, destination=profit_and_loss_account,
...@@ -273,6 +287,9 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True) ...@@ -273,6 +287,9 @@ with context.defaultActivateParameterDict({'tag': activity_tag}, placeless=True)
- roundCurrency(selected_profit_and_loss_account_balance, section_currency) - roundCurrency(selected_profit_and_loss_account_balance, section_currency)
- roundCurrency(profit_and_loss_quantity, section_currency), section_currency) - roundCurrency(profit_and_loss_quantity, section_currency), section_currency)
# If profit_and_loss_quantity equals 0 then we are on a
# ledger which no accounting transactions are member of
if profit_and_loss_quantity != 0.:
# add a final line for p&l # add a final line for p&l
balance_transaction.newContent( balance_transaction.newContent(
id='%03d' % (line_count + 1), id='%03d' % (line_count + 1),
......
...@@ -42,6 +42,8 @@ from AccessControl.SecurityManagement import newSecurityManager ...@@ -42,6 +42,8 @@ from AccessControl.SecurityManagement import newSecurityManager
from Products.ERP5Type.tests.Sequence import SequenceList from Products.ERP5Type.tests.Sequence import SequenceList
from Products.ERP5Form.PreferenceTool import Priority from Products.ERP5Form.PreferenceTool import Priority
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
SOURCE = 'source' SOURCE = 'source'
DESTINATION = 'destination' DESTINATION = 'destination'
RUN_ALL_TESTS = 1 RUN_ALL_TESTS = 1
...@@ -1167,6 +1169,196 @@ class TestClosingPeriod(AccountingTestCase): ...@@ -1167,6 +1169,196 @@ class TestClosingPeriod(AccountingTestCase):
self.assertEqual(None, pl_movement.getSourceTotalAssetPrice()) self.assertEqual(None, pl_movement.getSourceTotalAssetPrice())
self.assertEqual(200., pl_movement.getDestinationCredit()) self.assertEqual(200., pl_movement.getDestinationCredit())
@UnrestrictedMethod
def setUpLedger(self):
# Create Ledger Categories
ledger_category = self.portal.portal_categories.ledger
ledger_accounting_category = ledger_category.get('accounting', None)
if ledger_accounting_category is None:
ledger_accounting_category = ledger_category.newContent(portal_type='Category', id='accounting')
if ledger_accounting_category.get('general', None) is None:
ledger_accounting_category.newContent(portal_type='Category', id='general')
if ledger_accounting_category.get('detailed', None) is None:
ledger_accounting_category.newContent(portal_type='Category', id='detailed')
if ledger_accounting_category.get('other', None) is None:
ledger_accounting_category.newContent(portal_type='Category', id='other')
# Allow some ledgers on the 'Sale Invoice Transaction' portal type
self.portal.portal_types['Sale Invoice Transaction'].edit(
ledger=['accounting/general', 'accounting/detailed'])
def unSetUpLedger(self):
self.portal.portal_types['Sale Invoice Transaction'].edit(
ledger=None)
def test_createBalanceOnLedger(self):
self.setUpLedger()
organisation_module = self.organisation_module
period = self.section.newContent(portal_type='Accounting Period')
period.setStartDate(DateTime(2006, 1, 1))
period.setStopDate(DateTime(2006, 12, 31))
pl = self.portal.account_module.newContent(
portal_type='Account',
account_type='equity')
# 2 Transactions for clients 1 and 2 on ledger accounting/general
transaction1 = self._makeOne(
start_date=DateTime(2006, 1, 1),
portal_type='Sale Invoice Transaction',
ledger='accounting/general',
destination_section_value=organisation_module.client_1,
simulation_state='delivered',
lines=(dict(source_value=self.account_module.goods_sales,
source_debit=100),
dict(source_value=self.account_module.receivable,
source_credit=100)))
transaction2 = self._makeOne(
start_date=DateTime(2006, 1, 2),
portal_type='Sale Invoice Transaction',
ledger='accounting/general',
destination_section_value=organisation_module.client_2,
simulation_state='delivered',
lines=(dict(source_value=self.account_module.goods_sales,
source_debit=200),
dict(source_value=self.account_module.receivable,
source_credit=200)))
# 2 Transactions for clients 1 and 2 on ledger accounting/detailed
transaction3 = self._makeOne(
start_date=DateTime(2006, 1, 1),
portal_type='Sale Invoice Transaction',
ledger='accounting/detailed',
destination_section_value=organisation_module.client_1,
simulation_state='delivered',
lines=(dict(source_value=self.account_module.goods_sales,
source_debit=400),
dict(source_value=self.account_module.receivable,
source_credit=400)))
transaction4 = self._makeOne(
start_date=DateTime(2006, 1, 2),
portal_type='Sale Invoice Transaction',
ledger='accounting/detailed',
destination_section_value=organisation_module.client_2,
simulation_state='delivered',
lines=(dict(source_value=self.account_module.goods_sales,
source_debit=800),
dict(source_value=self.account_module.receivable,
source_credit=800)))
# 2 Transactions for clients 1 and 2 with no ledger
transaction5 = self._makeOne(
start_date=DateTime(2006, 1, 1),
portal_type='Sale Invoice Transaction',
ledger='',
destination_section_value=organisation_module.client_1,
simulation_state='delivered',
lines=(dict(source_value=self.account_module.goods_sales,
source_debit=1600),
dict(source_value=self.account_module.receivable,
source_credit=1600)))
transaction6 = self._makeOne(
start_date=DateTime(2006, 1, 2),
portal_type='Sale Invoice Transaction',
ledger='',
destination_section_value=organisation_module.client_2,
simulation_state='delivered',
lines=(dict(source_value=self.account_module.goods_sales,
source_debit=3200),
dict(source_value=self.account_module.receivable,
source_credit=3200)))
period.AccountingPeriod_createBalanceTransaction(
profit_and_loss_account=pl.getRelativeUrl())
accounting_transaction_list = self.accounting_module.contentValues()
self.assertEqual(9, len(accounting_transaction_list))
balance_transaction_list = self.accounting_module.contentValues(
portal_type='Balance Transaction')
self.assertEqual(3, len(balance_transaction_list))
# 1st balance has 3 lines : # 2nd balance has 3 lines :
# on ledger/accounting/general # on ledger/accounting/detailed
# pl = 300 D # pl = 1200 D
# receivable/client1 = 200 C # receivable/client1 = 800 C
# receivable/client2 = 100 C # receivable/client2 = 400 C
# 3rd balance has 3 lines :
# on no ledger
# pl = 4800 D
# receivable/client1 = 3200 C
# receivable/client2 = 1600 C
result_mapping = {}
result_mapping['accounting/general'] = {'client1': 100., 'client2': 200., 'pl': 300.}
result_mapping['accounting/detailed'] = {'client1': 400., 'client2': 800., 'pl': 1200.}
result_mapping[None] = {'client1': 1600., 'client2': 3200., 'pl': 4800.}
for balance_transaction in balance_transaction_list:
self.assertEqual(self.section,
balance_transaction.getDestinationSectionValue())
self.assertEqual(None, balance_transaction.getSourceSection())
self.assertEqual(DateTime(2007, 1, 1),
balance_transaction.getStartDate())
self.assertEqual('currency_module/euro',
balance_transaction.getResource())
self.assertEqual('delivered', balance_transaction.getSimulationState())
movement_list = balance_transaction.getMovementList()
self.assertEqual(3, len(movement_list))
current_ledger = balance_transaction.getLedger()
assert current_ledger in (None, 'accounting/general', 'accounting/detailed')
result = result_mapping[current_ledger]
client1_movement_list = [m for m in movement_list
if m.getSourceSectionValue() == organisation_module.client_1]
self.assertEqual(1, len(client1_movement_list))
client1_movement = client1_movement_list[0]
self.assertEqual([], client1_movement.getValueList('resource'))
self.assertEqual([], client1_movement.getValueList('destination_section'))
self.assertEqual(None, client1_movement.getSource())
self.assertEqual(self.account_module.receivable,
client1_movement.getDestinationValue())
self.assertEqual(organisation_module.client_1,
client1_movement.getSourceSectionValue())
self.assertEqual(None, client1_movement.getDestinationTotalAssetPrice())
self.assertEqual(None, client1_movement.getSourceTotalAssetPrice())
self.assertEqual(result['client1'], client1_movement.getDestinationCredit())
client2_movement_list = [m for m in movement_list
if m.getSourceSectionValue() == organisation_module.client_2]
self.assertEqual(1, len(client2_movement_list))
client2_movement = client2_movement_list[0]
self.assertEqual([], client2_movement.getValueList('resource'))
self.assertEqual([], client2_movement.getValueList('destination_section'))
self.assertEqual(None, client2_movement.getSource())
self.assertEqual(self.account_module.receivable,
client2_movement.getDestinationValue())
self.assertEqual(organisation_module.client_2,
client2_movement.getSourceSectionValue())
self.assertEqual(None, client2_movement.getDestinationTotalAssetPrice())
self.assertEqual(None, client2_movement.getSourceTotalAssetPrice())
self.assertEqual(result['client2'], client2_movement.getDestinationCredit())
pl_movement_list = [m for m in movement_list
if m.getDestinationValue() == pl]
self.assertEqual(1, len(pl_movement_list))
pl_movement = pl_movement_list[0]
self.assertEqual([], pl_movement.getValueList('resource'))
self.assertEqual(None, pl_movement.getSource())
self.assertEqual(pl,
pl_movement.getDestinationValue())
self.assertEqual(None,
pl_movement.getSourceSection())
self.assertEqual(None, pl_movement.getDestinationTotalAssetPrice())
self.assertEqual(None, pl_movement.getSourceTotalAssetPrice())
self.assertEqual(result['pl'], pl_movement.getDestinationDebit())
self.tic()
# Unconfigure ledgers from the instance
self.unSetUpLedger()
def test_createBalanceOnMirrorSectionMultiCurrency(self): def test_createBalanceOnMirrorSectionMultiCurrency(self):
pl = self.portal.account_module.newContent( pl = self.portal.account_module.newContent(
......
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