Commit f3bebea3 authored by Jérome Perrin's avatar Jérome Perrin

Extend grouping_reference with grouping_date

The grouping date is a property representing the date when this grouping is
effective.
In erp5_accounting, when setting a grouping reference, the grouping date will
be set to the latest date of grouped line. When running reports with
"omit_grouping_reference", lines that are grouped after the end date of the
report will still be displayed.

SQLCatalog structure changed, and can be updated with:
alter table catalog add column grouping_date datetime after grouping_reference;

You might also want to set a grouping date on movements with a grouping
reference in the migration.
parent c9febbef
...@@ -54,13 +54,12 @@ ...@@ -54,13 +54,12 @@
"""Get the report sections for general ledger\n """Get the report sections for general ledger\n
"""\n """\n
from Products.ZSQLCatalog.SQLCatalog import Query\n from Products.ZSQLCatalog.SQLCatalog import Query, ComplexQuery\n
from Products.ERP5Form.Report import ReportSection\n from Products.ERP5Form.Report import ReportSection\n
portal = context.portal_url.getPortalObject()\n portal = context.portal_url.getPortalObject()\n
request = portal.REQUEST\n request = portal.REQUEST\n
cat_tool = portal.portal_categories\n cat_tool = portal.portal_categories\n
sim_tool = portal.portal_simulation\n Base_translateString = portal.Base_translateString\n
Base_translateString = context.Base_translateString\n
\n \n
at_date = request[\'at_date\']\n at_date = request[\'at_date\']\n
section_category = request[\'section_category\']\n section_category = request[\'section_category\']\n
...@@ -133,6 +132,17 @@ if mirror_section:\n ...@@ -133,6 +132,17 @@ if mirror_section:\n
\n \n
default_selection_params = params.copy()\n default_selection_params = params.copy()\n
\n \n
# if user request report without grouping reference, don\'t show accounts that only have grouped lines in the period.\n
if request.get(\'omit_grouping_reference\', False):\n
if at_date:\n
params[\'grouping_query\'] = ComplexQuery(\n
Query(grouping_reference=None),\n
Query(grouping_date=at_date, range="min"),\n
operator="OR")\n
else:\n
params[\'grouping_reference\'] = None\n
\n
\n
analytic_column_list = ()\n analytic_column_list = ()\n
if hide_analytic:\n if hide_analytic:\n
default_selection_params[\'group_by\'] = ( \'explanation_uid\',\n default_selection_params[\'group_by\'] = ( \'explanation_uid\',\n
...@@ -197,7 +207,7 @@ def getFullAccountName(account_info):\n ...@@ -197,7 +207,7 @@ def getFullAccountName(account_info):\n
\n \n
\n \n
# look at inventories to decide which sections will be shown\n # look at inventories to decide which sections will be shown\n
balance_sheet_account_type_list = [c[0] for c in \n balance_sheet_account_type_list = [c[0] for c in\n
cat_tool.account_type.asset.getCategoryChildItemList(base=1, is_self_excluded=False, display_none_category=False ) + \\\n cat_tool.account_type.asset.getCategoryChildItemList(base=1, is_self_excluded=False, display_none_category=False ) + \\\n
cat_tool.account_type.equity.getCategoryChildItemList(base=1, is_self_excluded=False, display_none_category=False) + \\\n cat_tool.account_type.equity.getCategoryChildItemList(base=1, is_self_excluded=False, display_none_category=False) + \\\n
cat_tool.account_type.liability.getCategoryChildItemList(base=1, is_self_excluded=False, display_none_category=False) ]\n cat_tool.account_type.liability.getCategoryChildItemList(base=1, is_self_excluded=False, display_none_category=False) ]\n
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
"""Reset the grouping reference after a copy & paste.\n """Reset the grouping reference after a copy & paste.\n
"""\n """\n
context.setGroupingReference(None)\n context.setGroupingReference(None)\n
context.setGroupingDate(None)\n
]]></string> </value> ]]></string> </value>
......
<?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>_body</string> </key>
<value> <string>"""This script is a placeholder for projects to implement extra constraint to prevent grouping of accounting transaction lines.\n
Note that the sequence of letters will still remain unique for section, mirror_section and node, regardless of extra grouping parameters.\n
\n
For instance, we can refuse to group together lines for different order by returning the reference of the order in that script.\n
\n
The returned value must be hashable.\n
"""\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>source=True</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>AccountingTransactionLine_getGroupingExtraParameterList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -90,11 +90,12 @@ line_list = portal.portal_simulation.getMovementHistoryList(\n ...@@ -90,11 +90,12 @@ line_list = portal.portal_simulation.getMovementHistoryList(\n
mirror_section_uid=mirror_section_uid)\n mirror_section_uid=mirror_section_uid)\n
\n \n
# If the group is still valid, we may want to keep it as is.\n # If the group is still valid, we may want to keep it as is.\n
if round(sum([(l.total_price or 0) for l in line_list]), precision) == 0 and keep_if_valid_group:\n if keep_if_valid_group and round(sum([(l.total_price or 0) for l in line_list]), precision) == 0:\n
return\n return\n
\n \n
for line in line_list:\n for line in line_list:\n
line.setGroupingReference(None)\n line.setGroupingReference(None)\n
line.setGroupingDate(None)\n
\n \n
return line_list\n return line_list\n
</string> </value> </string> </value>
......
...@@ -97,6 +97,7 @@ ...@@ -97,6 +97,7 @@
<string>my_source_credit</string> <string>my_source_credit</string>
<string>my_resource</string> <string>my_resource</string>
<string>my_grouping_reference</string> <string>my_grouping_reference</string>
<string>my_grouping_date</string>
</list> </list>
</value> </value>
</item> </item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>description</string>
<string>editable</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_grouping_date</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_date_time_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Grouping Date</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -97,6 +97,7 @@ ...@@ -97,6 +97,7 @@
<string>my_destination_credit</string> <string>my_destination_credit</string>
<string>my_resource</string> <string>my_resource</string>
<string>my_grouping_reference</string> <string>my_grouping_reference</string>
<string>my_grouping_date</string>
</list> </list>
</value> </value>
</item> </item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>description</string>
<string>editable</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_grouping_date</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_date_time_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Grouping Date</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -50,17 +50,18 @@ ...@@ -50,17 +50,18 @@
</item> </item>
<item> <item>
<key> <string>_body</string> </key> <key> <string>_body</string> </key>
<value> <string encoding="cdata"><![CDATA[ <value> <string>"""Guess a grouping references for lines whose uids are passed as\n
"""Guess a grouping references for lines whose uids are passed as\n
accounting_transaction_line_uid_list.\n accounting_transaction_line_uid_list.\n
If accounting_transaction_line_uid_list is not passed, this script assumes that\n If accounting_transaction_line_uid_list is not passed, this script assumes that\n
it\'s called on the context of an accounting transaction and it guess the group\n it\'s called on the context of an accounting transaction and it guess the grouping\n
of accounting transaction using causality relations.\n of related accounting transactions using causality.\n
"""\n """\n
\n \n
# this dict associates (node, section, mirror_section) to a list of\n from Products.ERP5Type.Utils import int2letter\n
# accounting lines info (ie total_price and path).\n \n
# this dict associates (node, section, mirror_section,\n
# extra_grouping_parameter) to a list of\n
# accounting lines info (total_price, date and path).\n
lines_per_node = {}\n lines_per_node = {}\n
\n \n
portal = context.getPortalObject()\n portal = context.getPortalObject()\n
...@@ -69,15 +70,6 @@ ctool = portal.portal_catalog\n ...@@ -69,15 +70,6 @@ ctool = portal.portal_catalog\n
allow_grouping_with_different_quantity = portal.portal_preferences.getPreference(\n allow_grouping_with_different_quantity = portal.portal_preferences.getPreference(\n
\'preferred_grouping_with_different_quantities\', 0)\n \'preferred_grouping_with_different_quantities\', 0)\n
\n \n
def int2letter(i):\n
"""Convert an integer to letters, to use as a grouping reference code.\n
A, B, C ..., Z, AA, AB, ..., AZ, BA, ..., ZZ, AAA ...\n
"""\n
if i < 26:\n
return (chr(i + ord(\'A\')))\n
d, m = divmod(i, 26)\n
return int2letter(d - 1) + int2letter(m)\n
\n
\n \n
accounting_transaction_line_value_list = []\n accounting_transaction_line_value_list = []\n
if accounting_transaction_line_uid_list is None:\n if accounting_transaction_line_uid_list is None:\n
...@@ -107,8 +99,11 @@ for line in accounting_transaction_line_value_list:\n ...@@ -107,8 +99,11 @@ for line in accounting_transaction_line_value_list:\n
lines_per_node.setdefault(\n lines_per_node.setdefault(\n
(line.getSource(portal_type=\'Account\'),\n (line.getSource(portal_type=\'Account\'),\n
section_relative_url,\n section_relative_url,\n
line.getDestinationSection(), ), []).append(\n line.getDestinationSection(),\n
line.AccountingTransactionLine_getGroupingExtraParameterList(source=True),\n
), []).append(\n
dict(total_price=line.getSourceInventoriatedTotalAssetPrice() or 0,\n dict(total_price=line.getSourceInventoriatedTotalAssetPrice() or 0,\n
date=line.getStartDate(),\n
path=line.getRelativeUrl()))\n path=line.getRelativeUrl()))\n
else:\n else:\n
section_relative_url = None\n section_relative_url = None\n
...@@ -121,12 +116,15 @@ for line in accounting_transaction_line_value_list:\n ...@@ -121,12 +116,15 @@ for line in accounting_transaction_line_value_list:\n
lines_per_node.setdefault(\n lines_per_node.setdefault(\n
(line.getDestination(portal_type=\'Account\'),\n (line.getDestination(portal_type=\'Account\'),\n
section_relative_url,\n section_relative_url,\n
line.getSourceSection(), ), []).append(\n line.getSourceSection(),\n
line.AccountingTransactionLine_getGroupingExtraParameterList(source=False),\n
), []).append(\n
dict(total_price=line.getDestinationInventoriatedTotalAssetPrice() or 0,\n dict(total_price=line.getDestinationInventoriatedTotalAssetPrice() or 0,\n
date=line.getStopDate(),\n
path=line.getRelativeUrl()))\n path=line.getRelativeUrl()))\n
\n \n
changed_lines = []\n changed_line_list = []\n
for (node, section, mirror_section), line_info_list in lines_per_node.items():\n for (node, section, mirror_section, extra_parameter), line_info_list in lines_per_node.items():\n
if node is None:\n if node is None:\n
continue\n continue\n
total_price = sum([l[\'total_price\'] for l in line_info_list])\n total_price = sum([l[\'total_price\'] for l in line_info_list])\n
...@@ -143,20 +141,22 @@ for (node, section, mirror_section), line_info_list in lines_per_node.items():\n ...@@ -143,20 +141,22 @@ for (node, section, mirror_section), line_info_list in lines_per_node.items():\n
grouping_reference = portal.portal_ids.generateNewId(id_generator=\'uid\',\n grouping_reference = portal.portal_ids.generateNewId(id_generator=\'uid\',\n
id_group=id_group,\n id_group=id_group,\n
default=previous_default + 1)\n default=previous_default + 1)\n
\n \n
# convert from int to letters\n # convert from int to letters\n
string_reference = int2letter(grouping_reference)\n string_reference = int2letter(grouping_reference)\n
\n
# get the grouping date\n
date = max([line[\'date\'] for line in line_info_list])\n
\n \n
for line in line_info_list:\n for line in line_info_list:\n
line_obj = portal.restrictedTraverse(line[\'path\'])\n line_obj = portal.restrictedTraverse(line[\'path\'])\n
line_obj.setGroupingReference(string_reference)\n line_obj.setGroupingReference(string_reference)\n
line_obj.setGroupingDate(date)\n
line_obj.reindexObject(activate_kw=dict(tag=\'accounting_grouping_reference\'))\n line_obj.reindexObject(activate_kw=dict(tag=\'accounting_grouping_reference\'))\n
changed_lines.append(line[\'path\'])\n changed_line_list.append(line[\'path\'])\n
\n \n
return changed_lines\n return changed_line_list\n
</string> </value>
]]></string> </value>
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
......
...@@ -75,6 +75,9 @@ Here, a group of movement means:\n ...@@ -75,6 +75,9 @@ Here, a group of movement means:\n
mirror_section_uid is the same\n mirror_section_uid is the same\n
node_uid is the same\n node_uid is the same\n
grouping_reference is the same\n grouping_reference is the same\n
\n
XXX now that grouping_date exists, this script will become useless.\n
\n
</dtml-comment>\n </dtml-comment>\n
\n \n
( SELECT catalog.path as path,\n ( SELECT catalog.path as path,\n
......
...@@ -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[
from Products.ZSQLCatalog.SQLCatalog import Query\n from Products.ZSQLCatalog.SQLCatalog import Query, ComplexQuery\n
from Products.ERP5Type.Message import translateString\n from Products.ERP5Type.Message import translateString\n
from Products.ERP5Type.Log import log\n from Products.ERP5Type.Log import log\n
portal = context.getPortalObject()\n portal = context.getPortalObject()\n
...@@ -141,6 +141,15 @@ period_start_date = params.pop(\'period_start_date\', None)\n ...@@ -141,6 +141,15 @@ period_start_date = params.pop(\'period_start_date\', None)\n
if is_pl_account and not from_date:\n if is_pl_account and not from_date:\n
from_date = period_start_date\n from_date = period_start_date\n
\n \n
if portal.portal_selections.getSelectionParamsFor(selection_name).get(\'hide_grouping\'):\n
if params.get(\'at_date\'):\n
params[\'grouping_query\'] = ComplexQuery(\n
Query(grouping_reference=None),\n
Query(grouping_date=params[\'at_date\'], range="min"),\n
operator="OR")\n
else:\n
params[\'grouping_reference\'] = None\n
\n
if from_date or is_pl_account:\n if from_date or is_pl_account:\n
# Create a new parameter list to get the previous balance\n # Create a new parameter list to get the previous balance\n
get_inventory_kw = params.copy()\n get_inventory_kw = params.copy()\n
...@@ -228,8 +237,6 @@ if from_date or is_pl_account:\n ...@@ -228,8 +237,6 @@ if from_date or is_pl_account:\n
previous_balance.edit(Movement_getExplanationTitle=\'\')\n previous_balance.edit(Movement_getExplanationTitle=\'\')\n
\n \n
new_result = [previous_balance]\n new_result = [previous_balance]\n
if context.portal_selections.getSelectionParamsFor(selection_name).get(\'hide_grouping\'):\n
params[\'where_expression\'] = \'catalog.grouping_reference is NULL\'\n
new_result.extend(\n new_result.extend(\n
portal.portal_simulation.getMovementHistoryList(\n portal.portal_simulation.getMovementHistoryList(\n
from_date=from_date,\n from_date=from_date,\n
...@@ -242,9 +249,6 @@ if from_date or is_pl_account:\n ...@@ -242,9 +249,6 @@ if from_date or is_pl_account:\n
**params))\n **params))\n
return new_result\n return new_result\n
\n \n
if context.portal_selections.getSelectionParamsFor(selection_name).get(\'hide_grouping\'):\n
params[\'where_expression\'] = \'catalog.grouping_reference is NULL\'\n
\n
# We try not to convert to a list, hence the copy & paste\n # We try not to convert to a list, hence the copy & paste\n
return portal.portal_simulation.getMovementHistoryList(\n return portal.portal_simulation.getMovementHistoryList(\n
from_date=from_date,\n from_date=from_date,\n
......
1504 1505
\ No newline at end of file \ No newline at end of file
...@@ -131,3 +131,12 @@ class AccountingTransactionLine(DeliveryLine): ...@@ -131,3 +131,12 @@ class AccountingTransactionLine(DeliveryLine):
# directly from the URL, that's why this method is without docstring. # directly from the URL, that's why this method is without docstring.
self._baseSetGroupingReference(value) self._baseSetGroupingReference(value)
self.reindexObject() self.reindexObject()
security.declareProtected(Permissions.AccessContentsInformation,
'setGroupingDate')
def setGroupingDate(self, value):
# Sets the grouping date.
# See also setGroupingReference.
self._baseSetGroupingDate(value)
self.reindexObject()
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
<key>alarm.alarm_date</key> <key>alarm.alarm_date</key>
<key>alarm_date</key> <key>alarm_date</key>
<key>catalog.creation_date</key> <key>catalog.creation_date</key>
<key>catalog.grouping_date</key>
<key>catalog.modification_date</key> <key>catalog.modification_date</key>
<key>creation_date</key> <key>creation_date</key>
<key>date</key> <key>date</key>
...@@ -13,6 +14,7 @@ ...@@ -13,6 +14,7 @@
<key>delivery.stop_date_range_min</key> <key>delivery.stop_date_range_min</key>
<key>effective_date</key> <key>effective_date</key>
<key>expiration_date</key> <key>expiration_date</key>
<key>grouping_date</key>
<key>inventory.date</key> <key>inventory.date</key>
<key>inventory_stock.date</key> <key>inventory_stock.date</key>
<key>inventory_stock.mirror_date</key> <key>inventory_stock.mirror_date</key>
......
...@@ -38,6 +38,7 @@ getEventState\r\n ...@@ -38,6 +38,7 @@ getEventState\r\n
getImmobilisationState\r\n getImmobilisationState\r\n
getReference\r\n getReference\r\n
getGroupingReference\r\n getGroupingReference\r\n
getGroupingDate\r\n
getSourceReference\r\n getSourceReference\r\n
getDestinationReference\r\n getDestinationReference\r\n
getStringIndex\r\n getStringIndex\r\n
...@@ -89,7 +90,7 @@ REPLACE INTO\n ...@@ -89,7 +90,7 @@ REPLACE INTO\n
catalog\n catalog\n
(`uid`, `security_uid`, `owner`, `viewable_owner`, `path`, `relative_url`, `parent_uid`, `id`, `description`, `title`, `meta_type`,\n (`uid`, `security_uid`, `owner`, `viewable_owner`, `path`, `relative_url`, `parent_uid`, `id`, `description`, `title`, `meta_type`,\n
`portal_type`, `opportunity_state`, `corporate_registration_code`, `ean13_code`, `validation_state`, `simulation_state`,\n `portal_type`, `opportunity_state`, `corporate_registration_code`, `ean13_code`, `validation_state`, `simulation_state`,\n
`causality_state`, `invoice_state`, `payment_state`, `event_state`, `immobilisation_state`, `reference`, `grouping_reference`,\n `causality_state`, `invoice_state`, `payment_state`, `event_state`, `immobilisation_state`, `reference`, `grouping_reference`, `grouping_date`,\n
`source_reference`, `destination_reference`, `string_index`, `int_index`, `float_index`, `has_cell_content`, `creation_date`,\n `source_reference`, `destination_reference`, `string_index`, `int_index`, `float_index`, `has_cell_content`, `creation_date`,\n
`modification_date`)\n `modification_date`)\n
VALUES\n VALUES\n
...@@ -119,6 +120,7 @@ VALUES\n ...@@ -119,6 +120,7 @@ VALUES\n
<dtml-sqlvar expr="getImmobilisationState[loop_item]" type="string" optional>,\n <dtml-sqlvar expr="getImmobilisationState[loop_item]" type="string" optional>,\n
<dtml-sqlvar expr="getReference[loop_item]" type="string" optional>,\n <dtml-sqlvar expr="getReference[loop_item]" type="string" optional>,\n
<dtml-sqlvar expr="getGroupingReference[loop_item]" type="string" optional>,\n <dtml-sqlvar expr="getGroupingReference[loop_item]" type="string" optional>,\n
<dtml-sqlvar expr="getGroupingDate[loop_item]" type="datetime" optional>,\n
<dtml-sqlvar expr="getSourceReference[loop_item]" type="string" optional>,\n <dtml-sqlvar expr="getSourceReference[loop_item]" type="string" optional>,\n
<dtml-sqlvar expr="getDestinationReference[loop_item]" type="string" optional>,\n <dtml-sqlvar expr="getDestinationReference[loop_item]" type="string" optional>,\n
<dtml-sqlvar expr="getStringIndex[loop_item]" type="string" optional>,\n <dtml-sqlvar expr="getStringIndex[loop_item]" type="string" optional>,\n
......
...@@ -87,6 +87,7 @@ CREATE TABLE `catalog` (\n ...@@ -87,6 +87,7 @@ CREATE TABLE `catalog` (\n
`immobilisation_state` varchar(255) default \'\',\n `immobilisation_state` varchar(255) default \'\',\n
`reference` varchar(255) binary default \'\',\n `reference` varchar(255) binary default \'\',\n
`grouping_reference` varchar(255) default \'\',\n `grouping_reference` varchar(255) default \'\',\n
`grouping_date` datetime,\n
`source_reference` varchar(255) default \'\',\n `source_reference` varchar(255) default \'\',\n
`destination_reference` varchar(255) default \'\',\n `destination_reference` varchar(255) default \'\',\n
`string_index` varchar(255),\n `string_index` varchar(255),\n
......
233 234
\ No newline at end of file \ No newline at end of file
...@@ -3,6 +3,8 @@ alarm_date ...@@ -3,6 +3,8 @@ alarm_date
catalog.creation_date catalog.creation_date
catalog.modification_date catalog.modification_date
creation_date creation_date
grouping_date
catalog.grouping_date
date date
delivery.start_date delivery.start_date
delivery.start_date_range_max delivery.start_date_range_max
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>mode</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/date</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>The date when the grouping reference is effective.</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>grouping_date_property</string> </value>
</item>
<item>
<key> <string>mode</string> </key>
<value> <string>w</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
54 55
\ No newline at end of file \ No newline at end of file
...@@ -2813,12 +2813,15 @@ class TestTransactions(AccountingTestCase): ...@@ -2813,12 +2813,15 @@ class TestTransactions(AccountingTestCase):
line = accounting_transaction.newContent( line = accounting_transaction.newContent(
id = 'line_with_grouping_reference', id = 'line_with_grouping_reference',
grouping_reference='A', grouping_reference='A',
grouping_date=DateTime(),
portal_type=transaction_to_line_mapping[portal_type]) portal_type=transaction_to_line_mapping[portal_type])
cp = accounting_module.manage_copyObjects(ids=[accounting_transaction.getId()]) cp = accounting_module.manage_copyObjects(ids=[accounting_transaction.getId()])
copy_id = accounting_module.manage_pasteObjects(cp)[0]['new_id'] copy_id = accounting_module.manage_pasteObjects(cp)[0]['new_id']
self.failIf(accounting_module[copy_id]\ self.failIf(accounting_module[copy_id]\
.line_with_grouping_reference.getGroupingReference()) .line_with_grouping_reference.getGroupingReference())
self.failIf(accounting_module[copy_id]\
.line_with_grouping_reference.getGroupingDate())
def test_AccountingTransaction_lineResetGroupingReference(self): def test_AccountingTransaction_lineResetGroupingReference(self):
invoice = self._makeOne( invoice = self._makeOne(
...@@ -2829,6 +2832,7 @@ class TestTransactions(AccountingTestCase): ...@@ -2829,6 +2832,7 @@ class TestTransactions(AccountingTestCase):
dict(source_value=self.account_module.receivable, dict(source_value=self.account_module.receivable,
source_credit=100, source_credit=100,
id='line_with_grouping_reference', id='line_with_grouping_reference',
grouping_date=DateTime(),
grouping_reference='A'),)) grouping_reference='A'),))
invoice_line = invoice.line_with_grouping_reference invoice_line = invoice.line_with_grouping_reference
...@@ -2840,6 +2844,7 @@ class TestTransactions(AccountingTestCase): ...@@ -2840,6 +2844,7 @@ class TestTransactions(AccountingTestCase):
dict(source_value=self.account_module.goods_sales, dict(source_value=self.account_module.goods_sales,
source_credit=100, source_credit=100,
id='line_with_grouping_reference', id='line_with_grouping_reference',
grouping_date=DateTime(),
grouping_reference='A'),)) grouping_reference='A'),))
other_account_line = other_account_invoice.line_with_grouping_reference other_account_line = other_account_invoice.line_with_grouping_reference
...@@ -2851,6 +2856,7 @@ class TestTransactions(AccountingTestCase): ...@@ -2851,6 +2856,7 @@ class TestTransactions(AccountingTestCase):
dict(source_value=self.account_module.receivable, dict(source_value=self.account_module.receivable,
source_credit=100, source_credit=100,
id='line_with_grouping_reference', id='line_with_grouping_reference',
grouping_date=DateTime(),
grouping_reference='A'),)) grouping_reference='A'),))
other_section_line = other_section_invoice.line_with_grouping_reference other_section_line = other_section_invoice.line_with_grouping_reference
...@@ -2862,6 +2868,7 @@ class TestTransactions(AccountingTestCase): ...@@ -2862,6 +2868,7 @@ class TestTransactions(AccountingTestCase):
dict(source_value=self.account_module.receivable, dict(source_value=self.account_module.receivable,
source_credit=100, source_credit=100,
id='line_with_grouping_reference', id='line_with_grouping_reference',
grouping_date=DateTime(),
grouping_reference='B'),)) grouping_reference='B'),))
other_letter_line = other_letter_invoice.line_with_grouping_reference other_letter_line = other_letter_invoice.line_with_grouping_reference
...@@ -2874,6 +2881,7 @@ class TestTransactions(AccountingTestCase): ...@@ -2874,6 +2881,7 @@ class TestTransactions(AccountingTestCase):
lines=(dict(source_value=self.account_module.receivable, lines=(dict(source_value=self.account_module.receivable,
id='line_with_grouping_reference', id='line_with_grouping_reference',
grouping_reference='A', grouping_reference='A',
grouping_date=DateTime(),
source_debit=100), source_debit=100),
dict(source_value=self.account_module.bank, dict(source_value=self.account_module.bank,
source_credit=100,))) source_credit=100,)))
...@@ -2883,16 +2891,21 @@ class TestTransactions(AccountingTestCase): ...@@ -2883,16 +2891,21 @@ class TestTransactions(AccountingTestCase):
# ungrouped # ungrouped
payment_line.AccountingTransactionLine_resetGroupingReference() payment_line.AccountingTransactionLine_resetGroupingReference()
self.failIf(payment_line.getGroupingReference()) self.failIf(payment_line.getGroupingReference())
self.failIf(payment_line.getGroupingDate())
self.failIf(invoice_line.getGroupingReference()) self.failIf(invoice_line.getGroupingReference())
self.failIf(invoice_line.getGroupingDate())
# other lines are not touched: # other lines are not touched:
self.failUnless(other_account_line.getGroupingReference()) self.failUnless(other_account_line.getGroupingReference())
self.failUnless(other_account_line.getGroupingDate())
self.failUnless(other_section_line.getGroupingReference()) self.failUnless(other_section_line.getGroupingReference())
self.failUnless(other_letter_line.getGroupingReference()) self.failUnless(other_section_line.getGroupingDate())
self.failUnless(other_letter_line.getGroupingDate())
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',
start_date=DateTime(2012, 1, 2),
destination_section_value=self.organisation_module.client_1, destination_section_value=self.organisation_module.client_1,
lines=(dict(source_value=self.account_module.goods_purchase, lines=(dict(source_value=self.account_module.goods_purchase,
source_debit=100), source_debit=100),
...@@ -2905,6 +2918,7 @@ class TestTransactions(AccountingTestCase): ...@@ -2905,6 +2918,7 @@ class TestTransactions(AccountingTestCase):
title='First Invoice Payment', title='First Invoice Payment',
portal_type='Payment Transaction', portal_type='Payment Transaction',
simulation_state='delivered', simulation_state='delivered',
start_date=DateTime(2012, 1, 3),
causality_value=invoice, causality_value=invoice,
source_payment_value=self.section.newContent( source_payment_value=self.section.newContent(
portal_type='Bank Account'), portal_type='Bank Account'),
...@@ -2915,23 +2929,34 @@ class TestTransactions(AccountingTestCase): ...@@ -2915,23 +2929,34 @@ class TestTransactions(AccountingTestCase):
dict(source_value=self.account_module.bank, dict(source_value=self.account_module.bank,
source_credit=100,))) source_credit=100,)))
payment_line = payment.line_for_grouping_reference payment_line = payment.line_for_grouping_reference
self.failIf(invoice_line.getGroupingReference()) self.failIf(invoice_line.getGroupingReference())
self.failIf(invoice_line.getGroupingDate())
self.failIf(payment_line.getGroupingReference()) self.failIf(payment_line.getGroupingReference())
self.failIf(payment_line.getGroupingDate())
# lines match, they are automatically grouped # lines match, they are automatically grouped
invoice.stop() invoice.stop()
self.failUnless(invoice_line.getGroupingReference()) self.failUnless(invoice_line.getGroupingReference())
self.failUnless(payment_line.getGroupingReference()) self.failUnless(payment_line.getGroupingReference())
# the grouping date is set to the latest date of all grouped lines
self.assertEquals(DateTime(2012, 1, 3), invoice_line.getGroupingDate())
self.assertEquals(DateTime(2012, 1, 3), payment_line.getGroupingDate())
# when restarting, grouping is removed # when restarting, grouping is removed
invoice.restart() invoice.restart()
self.tic() self.tic()
self.failIf(invoice_line.getGroupingReference()) self.failIf(invoice_line.getGroupingReference())
self.failIf(invoice_line.getGroupingDate())
self.failIf(payment_line.getGroupingReference()) self.failIf(payment_line.getGroupingReference())
self.failIf(payment_line.getGroupingDate())
# when stopping again, grouping is set again
invoice.stop() invoice.stop()
self.failUnless(invoice_line.getGroupingReference()) self.failUnless(invoice_line.getGroupingReference())
self.failUnless(payment_line.getGroupingReference()) self.failUnless(payment_line.getGroupingReference())
self.assertEquals(DateTime(2012, 1, 3), invoice_line.getGroupingDate())
self.assertEquals(DateTime(2012, 1, 3), payment_line.getGroupingDate())
def test_automatically_setting_grouping_reference_same_group(self): def test_automatically_setting_grouping_reference_same_group(self):
# invoice is for section, payment is for main_section # invoice is for section, payment is for main_section
......
...@@ -1013,6 +1013,170 @@ class TestAccountingReports(AccountingTestCase, ERP5ReportTestCase): ...@@ -1013,6 +1013,170 @@ class TestAccountingReports(AccountingTestCase, ERP5ReportTestCase):
data_line_list[0].getColumnProperty('Movement_getSpecificReference')) data_line_list[0].getColumnProperty('Movement_getSpecificReference'))
def createHideGroupingDataSet(self):
account_module = self.account_module
# before the date
self._makeOne(
portal_type='Accounting Transaction',
simulation_state='delivered',
start_date=DateTime(2006, 1, 1),
lines=(dict(source_value=account_module.equity,
source_debit=100),
dict(source_value=account_module.stocks,
source_credit=100)))
first = self._makeOne(
portal_type='Sale Invoice Transaction',
title='Grouped during period',
simulation_state='delivered',
reference='1',
destination_section_value=self.organisation_module.client_1,
start_date=DateTime(2006, 2, 2),
lines=(dict(source_value=account_module.receivable,
grouping_reference='A',
grouping_date=DateTime(2006, 2, 2),
source_debit=119.60),
dict(source_value=account_module.collected_vat,
source_credit=19.60),
dict(source_value=account_module.goods_sales,
source_credit=100.00)))
second = self._makeOne(
portal_type='Sale Invoice Transaction',
title='Grouped after period',
simulation_state='delivered',
reference='ref2',
source_reference='2',
destination_section_value=self.organisation_module.client_2,
start_date=DateTime(2006, 2, 3),
lines=(dict(source_value=account_module.receivable,
grouping_reference='B',
grouping_date=DateTime(2006, 3, 2),
source_debit=239.20),
dict(source_value=account_module.collected_vat,
source_credit=39.20),
dict(source_value=account_module.goods_sales,
source_credit=200.00)))
def testAccountStatementHideGrouping(self):
"""Simple test for hide grouping on account statement.
"""
self.createHideGroupingDataSet()
request_form = self.portal.REQUEST.form
request_form['node'] = \
self.portal.account_module.receivable.getRelativeUrl()
request_form['at_date'] = DateTime(2006, 3, 1)
request_form['section_category'] = 'group/demo_group/sub1'
request_form['section_category_strict'] = False
request_form['simulation_state'] = ['delivered']
request_form['hide_analytic'] = False
request_form['omit_grouping_reference'] = True
report_section_list = self.getReportSectionList(
self.portal.accounting_module,
'AccountModule_viewAccountStatementReport')
self.assertEquals(1, len(report_section_list))
line_list = self.getListBoxLineList(report_section_list[0])
data_line_list = [l for l in line_list if l.isDataLine()]
# we have 1 transactions, because 1st is grouped during the period.
self.assertEquals(1, len(data_line_list))
# test columns values
line = data_line_list[0]
self.assertEquals(line.column_id_list,
['Movement_getSpecificReference', 'date',
'Movement_getExplanationTitle', 'Movement_getMirrorSectionTitle',
'Movement_getExplanationReference',
'debit_price', 'credit_price', 'running_total_price'])
self.checkLineProperties(data_line_list[0],
Movement_getSpecificReference='2',
Movement_getExplanationReference='ref2',
date=DateTime(2006, 2, 3),
Movement_getExplanationTitle='Grouped after period',
Movement_getMirrorSectionTitle='Client 2',
debit_price=239.20,
credit_price=0,
running_total_price=239.20)
self.failUnless(line_list[-1].isStatLine())
self.checkLineProperties(line_list[-1],
Movement_getSpecificReference=None,
date=None,
Movement_getExplanationTitle=None,
Movement_getMirrorSectionTitle=None,
# The bottom line remain the same as when showing
# grouped lines
debit_price=358.80,
credit_price=0,
running_total_price=None)
def testGeneralLedgerHideGrouping(self):
# similar to testAccountStatementHideGrouping, but in general ledger.
self.createHideGroupingDataSet()
request_form = self.portal.REQUEST.form
request_form['from_date'] = DateTime(2006, 1, 1)
request_form['at_date'] = DateTime(2006, 3, 1)
request_form['section_category'] = 'group/demo_group'
request_form['section_category_strict'] = False
request_form['simulation_state'] = ['delivered']
request_form['hide_analytic'] = False
request_form['gap_list'] = ['my_country/my_accounting_standards/4/41']
request_form['omit_grouping_reference'] = True
report_section_list = self.getReportSectionList(
self.portal.accounting_module,
'AccountModule_viewGeneralLedgerReport')
# Except the stat, we only have one report section, because Client 1 is
# grouped in the period.
self.assertEquals(2, len(report_section_list))
self.assertEquals('41 - Receivable (Client 2)',
report_section_list[0].getTitle())
line_list = self.getListBoxLineList(report_section_list[0])
data_line_list = [l for l in line_list if l.isDataLine()]
# report layout
self.assertEquals(['Movement_getSpecificReference',
'Movement_getExplanationTitle', 'date',
'Movement_getExplanationTranslatedPortalType',
'Movement_getExplanationReference', 'Movement_getMirrorSectionTitle',
'debit_price', 'credit_price', 'running_total_price'],
data_line_list[0].column_id_list)
self.assertEquals(1, len(data_line_list))
self.checkLineProperties(data_line_list[0],
Movement_getSpecificReference='2',
Movement_getExplanationTitle='Grouped after period',
date=DateTime(2006, 2, 3),
Movement_getExplanationTranslatedPortalType='Sale Invoice Transaction',
Movement_getExplanationReference='ref2',
Movement_getMirrorSectionTitle='Client 2',
debit_price=239.20, credit_price=0, running_total_price=239.20, )
self.failUnless(line_list[-1].isStatLine())
self.checkLineProperties(line_list[-1],
Movement_getSpecificReference=None,
Movement_getExplanationTitle=None,
date=None,
Movement_getExplanationTranslatedPortalType=None,
Movement_getExplanationReference=None,
Movement_getMirrorSectionTitle=None,
debit_price=239.20, credit_price=0, )
self.assertEquals('Total', report_section_list[1].getTitle())
line_list = self.getListBoxLineList(report_section_list[1])
data_line_list = [l for l in line_list if l.isDataLine()]
# report layout
self.assertEquals(['debit_price', 'credit_price'], data_line_list[0].column_id_list)
self.assertEquals(1, len(data_line_list))
# The bottom line remain the same as when showing grouped lines
self.checkLineProperties(data_line_list[0], debit_price=358.80, credit_price=0)
def testAccountStatementFromDateDetailedSummary(self): def testAccountStatementFromDateDetailedSummary(self):
# Detailed from date summary shows all lines corresponding to the balance # Detailed from date summary shows all lines corresponding to the balance
# at the beginning of the period. # at the beginning of the period.
......
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