From 43421951f36a84d39f9c1a5de0c39d7b1b450fc5 Mon Sep 17 00:00:00 2001
From: Arnaud Fontaine <arnaud.fontaine@nexedi.com>
Date: Wed, 25 Apr 2018 11:50:21 +0900
Subject: [PATCH] erp5_accounting_l10n_fr: FEC Report: Allow to group by ledger
 or ledger+portal_type in addition as per portal_type (the default).

This required refactoring the source files as the implementation was
portal_type-centric. This adds a dedicated Python Script with ProxyRole=Manager
to create Active Processes and thus avoid executing code as Manager as much as
possible.
---
 ...AccountingTransactionFileForOneJournal.py} |  12 +-
 ...ccountingTransactionFileForOneJournal.xml} |   4 +-
 ...ocessForFrenchAccountingTransactionFile.py |   1 +
 ...essForFrenchAccountingTransactionFile.xml} |  12 +-
 ...ule_viewFrenchAccountingTransactionFile.py |   6 +-
 ...le_viewFrenchAccountingTransactionFile.xml |   2 +-
 ...ewFrenchAccountingTransactionFileActive.py | 102 +++++--
 ...wFrenchAccountingTransactionFileActive.xml |  10 +-
 ...wFrenchAccountingTransactionFileDialog.xml |   1 +
 .../your_group_by.xml                         | 275 ++++++++++++++++++
 ...hAccountingTransactionFileForPortalType.py |  37 ---
 ...gTransactionModule_viewJournalAsFECXML.zpt |   4 +-
 product/ERP5/tests/testAccounting_l10n_fr.py  | 157 +++++++++-
 13 files changed, 535 insertions(+), 88 deletions(-)
 rename bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/{AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForPortalType.py => AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForOneJournal.py} (56%)
 rename bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/{AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForPortalType.xml => AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForOneJournal.xml} (93%)
 create mode 100644 bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_createActiveProcessForFrenchAccountingTransactionFile.py
 rename bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/{AccountingTransactionModule_viewFrenchAccountingTransactionFileForPortalType.xml => AccountingTransactionModule_createActiveProcessForFrenchAccountingTransactionFile.xml} (84%)
 create mode 100644 bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileDialog/your_group_by.xml
 delete mode 100644 bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileForPortalType.py

diff --git a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForPortalType.py b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForOneJournal.py
similarity index 56%
rename from bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForPortalType.py
rename to bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForOneJournal.py
index 60814962fd..04598736d6 100644
--- a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForPortalType.py
+++ b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForOneJournal.py
@@ -1,18 +1,18 @@
 from Products.CMFActivity.ActiveResult import ActiveResult
 portal = context.getPortalObject()
-portal_type = portal.portal_types[portal_type]
 active_process = portal.restrictedTraverse(active_process)
-this_portal_type_active_process = portal.restrictedTraverse(this_portal_type_active_process)
+this_journal_active_process = portal.restrictedTraverse(this_journal_active_process)
 
 # XXX we need proxy role for this
-result_list = this_portal_type_active_process.getResultList()
+result_list = this_journal_active_process.getResultList()
 
 if result_list:
   journal_fragment = context.AccountingTransactionModule_viewJournalAsFECXML(
-      portal_type=portal_type,
+      journal_code=journal_code,
+      journal_lib=journal_lib,
       result_list=result_list)
-  
+
   active_process.postResult(ActiveResult(detail=journal_fragment.encode('utf8').encode('zlib')))
 
 # delete no longer needed active process
-this_portal_type_active_process.getParentValue().manage_delObjects(ids=[this_portal_type_active_process.getId()])
+this_journal_active_process.getParentValue().manage_delObjects(ids=[this_journal_active_process.getId()])
diff --git a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForPortalType.xml b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForOneJournal.xml
similarity index 93%
rename from bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForPortalType.xml
rename to bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForOneJournal.xml
index eaa4478882..967c684f04 100644
--- a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForPortalType.xml
+++ b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForOneJournal.xml
@@ -50,7 +50,7 @@
         </item>
         <item>
             <key> <string>_params</string> </key>
-            <value> <string>portal_type, active_process, this_portal_type_active_process</string> </value>
+            <value> <string>journal_code, journal_lib, active_process, this_journal_active_process</string> </value>
         </item>
         <item>
             <key> <string>_proxy_roles</string> </key>
@@ -62,7 +62,7 @@
         </item>
         <item>
             <key> <string>id</string> </key>
-            <value> <string>AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForPortalType</string> </value>
+            <value> <string>AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForOneJournal</string> </value>
         </item>
       </dictionary>
     </pickle>
diff --git a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_createActiveProcessForFrenchAccountingTransactionFile.py b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_createActiveProcessForFrenchAccountingTransactionFile.py
new file mode 100644
index 0000000000..0e89a1ba0f
--- /dev/null
+++ b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_createActiveProcessForFrenchAccountingTransactionFile.py
@@ -0,0 +1 @@
+return context.getPortalObject().portal_activities.newActiveProcess()
diff --git a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileForPortalType.xml b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_createActiveProcessForFrenchAccountingTransactionFile.xml
similarity index 84%
rename from bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileForPortalType.xml
rename to bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_createActiveProcessForFrenchAccountingTransactionFile.xml
index b8bea077d2..79cfcfdce8 100644
--- a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileForPortalType.xml
+++ b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_createActiveProcessForFrenchAccountingTransactionFile.xml
@@ -50,11 +50,19 @@
         </item>
         <item>
             <key> <string>_params</string> </key>
-            <value> <string>portal_type, section_uid_list, from_date, at_date, simulation_state, ledger, active_process, this_portal_type_active_process, tag, aggregate_tag, priority,</string> </value>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>_proxy_roles</string> </key>
+            <value>
+              <tuple>
+                <string>Manager</string>
+              </tuple>
+            </value>
         </item>
         <item>
             <key> <string>id</string> </key>
-            <value> <string>AccountingTransactionModule_viewFrenchAccountingTransactionFileForPortalType</string> </value>
+            <value> <string>AccountingTransactionModule_createActiveProcessForFrenchAccountingTransactionFile</string> </value>
         </item>
       </dictionary>
     </pickle>
diff --git a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFile.py b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFile.py
index 0f0b8764c4..4a603942f4 100644
--- a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFile.py
+++ b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFile.py
@@ -1,6 +1,10 @@
 from Products.ERP5Type.Message import translateString
 portal = context.getPortalObject()
 
+if group_by in ('ledger', 'portal_type_ledger') and ledger is None:
+  return context.Base_redirect('view', keep_items=dict(
+              portal_status_message=translateString("At least one Ledger must be selected")))
+
 person_value = portal.portal_membership.getAuthenticatedMember().getUserValue()
 if person_value is None:
   portal.changeSkin(None)
@@ -15,11 +19,11 @@ if portal.portal_activities.countMessageWithTag(tag) or \
   return context.Base_redirect(form_id, keep_items=dict(
               portal_status_message=translateString("Report already in progress.")))
 
-  
 context.activate().AccountingTransactionModule_viewFrenchAccountingTransactionFileActive(
   section_category,
   section_category_strict,
   at_date,
+  group_by,
   simulation_state,
   ledger,
   user_name=person_value.Person_getUserId(),
diff --git a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFile.xml b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFile.xml
index 53fd1caf71..3b1c15af28 100644
--- a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFile.xml
+++ b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFile.xml
@@ -50,7 +50,7 @@
         </item>
         <item>
             <key> <string>_params</string> </key>
-            <value> <string>section_category, section_category_strict, at_date, simulation_state, ledger=None, form_id=None, **kw</string> </value>
+            <value> <string>section_category, section_category_strict, at_date, simulation_state, group_by=\'portal_type\', ledger=None, form_id=None, **kw</string> </value>
         </item>
         <item>
             <key> <string>id</string> </key>
diff --git a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileActive.py b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileActive.py
index 84444c00fb..d307b4b506 100644
--- a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileActive.py
+++ b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileActive.py
@@ -7,26 +7,94 @@ section_uid_list = portal.Base_getSectionUidListForSectionCategory(
 from_date = portal.Base_getAccountingPeriodStartDateForSectionCategory(
   section_category, at_date)
 
-# XXX we need proxy role for that
-active_process = portal.portal_activities.newActiveProcess()
+ledger_obj_list = []
+if ledger is not None:
+  if not (isinstance(ledger, list) or isinstance(ledger, tuple)):
+    ledger = (ledger,)
+  category_tool = portal.portal_categories
+  for item in ledger:
+    ledger_obj_list.append(category_tool.ledger.restrictedTraverse(item))
+elif group_by in ('ledger', 'portal_type_ledger'):
+  raise ValueError("At least one Ledger is needed for group_by=%r" % group_by)
+
+def _groupedJournalTupleDict():
+  portal_type_list = portal.getPortalAccountingTransactionTypeList()
+  default_search_kw = {
+    'simulation_state': simulation_state,
+    'accounting_transaction.section_uid': section_uid_list,
+    'operation_date': {'query': (from_date, at_date), 'range': 'minngt' },
+  }
+
+  journal_tuple_list = []
+  if group_by == 'ledger':
+    default_search_kw['portal_type'] = portal_type_list
+    for ledger_obj in ledger_obj_list:
+      journal_code = journal_lib = ledger_obj.getReference(ledger_obj.getId())
+
+      ledger_search_kw = default_search_kw.copy()
+      ledger_search_kw['default_ledger_uid'] = ledger_obj.getUid()
+
+      journal_tuple_list.append((journal_code, journal_lib, ledger_search_kw))
+
+  elif group_by == 'portal_type_ledger':
+    for ledger_obj in ledger_obj_list:
+      for portal_type in portal_type_list:
+        portal_type_obj = portal.portal_types[portal_type]
+        ledger_reference = ledger_obj.getReference(ledger_obj.getId())
+        journal_code = "%s: %s" % (portal_type_obj.getCompactTranslatedTitle(), ledger_reference)
+        journal_lib = "%s: %s" % (portal_type_obj.getTranslatedTitle(), ledger_reference)
+
+        portal_type_ledger_search_kw = default_search_kw.copy()
+        portal_type_ledger_search_kw['default_ledger_uid'] = ledger_obj.getUid()
+        portal_type_ledger_search_kw['portal_type'] = portal_type
+
+        journal_tuple_list.append((journal_code, journal_lib, portal_type_ledger_search_kw))
+
+  # group_by == 'portal_type' (Default)
+  else:
+    if ledger_obj_list:
+      default_search_kw['default_ledger_uid'] = [ ledger_obj.getUid() for ledger_obj in ledger_obj_list ]
+
+    for portal_type in portal_type_list:
+      portal_type_obj = portal.portal_types[portal_type]
+      journal_code = portal_type_obj.getCompactTranslatedTitle()
+      journal_lib = portal_type_obj.getTranslatedTitle()
+
+      portal_type_search_kw = default_search_kw.copy()
+      portal_type_search_kw['portal_type'] = portal_type
+
+      journal_tuple_list.append((journal_code, journal_lib, portal_type_search_kw))
+
+  return journal_tuple_list
 
 priority = 4
+# Proxy Role needed to create an 'Active Process'
+active_process = context.AccountingTransactionModule_createActiveProcessForFrenchAccountingTransactionFile()
+
+if tag is None:
+  tag = script.getId()
+if aggregate_tag is None:
+  aggregate_tag = '%s:aggregate' % tag
+
+for journal_code, journal_lib, search_kw in _groupedJournalTupleDict():
+  # This script is executed with Proxy Role, required to create 'Active Process'
+  this_journal_active_process = context.AccountingTransactionModule_createActiveProcessForFrenchAccountingTransactionFile()
+
+  portal.portal_catalog.searchAndActivate(
+    method_id='AccountingTransaction_postFECResult',
+    method_kw=dict(section_uid_list=section_uid_list, active_process=this_journal_active_process.getRelativeUrl()),
+    activate_kw=dict(tag=tag, priority=priority),
+    **search_kw)
 
-for portal_type in portal.getPortalAccountingTransactionTypeList():
-  # XXX we need proxy role for that
-  this_portal_type_active_process = portal.portal_activities.newActiveProcess()
-  context.AccountingTransactionModule_viewFrenchAccountingTransactionFileForPortalType(
-    portal_type,
-    section_uid_list,
-    from_date,
-    at_date,
-    simulation_state,
-    ledger,
-    active_process.getRelativeUrl(),
-    this_portal_type_active_process.getRelativeUrl(),
-    tag,
-    aggregate_tag,
-    priority)
+  context.activate(
+    tag=aggregate_tag,
+    after_tag=tag,
+    activity='SQLQueue').AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForOneJournal(
+      journal_code,
+      journal_lib,
+      active_process=active_process.getRelativeUrl(),
+      # Proxy Role needed to create an 'Active Process'
+      this_journal_active_process=this_journal_active_process.getRelativeUrl())
 
 context.activate(after_tag=(tag, aggregate_tag)).AccountingTransactionModule_aggregateFrenchAccountingTransactionFile(
   at_date,
diff --git a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileActive.xml b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileActive.xml
index ad3a5e63f4..a7b522e8c1 100644
--- a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileActive.xml
+++ b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileActive.xml
@@ -50,15 +50,7 @@
         </item>
         <item>
             <key> <string>_params</string> </key>
-            <value> <string>section_category, section_category_strict, at_date, simulation_state, ledger, user_name, tag, aggregate_tag, **kw</string> </value>
-        </item>
-        <item>
-            <key> <string>_proxy_roles</string> </key>
-            <value>
-              <tuple>
-                <string>Manager</string>
-              </tuple>
-            </value>
+            <value> <string>section_category, section_category_strict, at_date, group_by, simulation_state, ledger, user_name=None, tag=None, aggregate_tag=None, **kw</string> </value>
         </item>
         <item>
             <key> <string>id</string> </key>
diff --git a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileDialog.xml b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileDialog.xml
index 3f6053a9de..53f21b1532 100644
--- a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileDialog.xml
+++ b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileDialog.xml
@@ -97,6 +97,7 @@
                         <string>your_section_category_strict</string>
                         <string>your_at_date</string>
                         <string>your_ledger</string>
+                        <string>your_group_by</string>
                       </list>
                     </value>
                 </item>
diff --git a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileDialog/your_group_by.xml b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileDialog/your_group_by.xml
new file mode 100644
index 0000000000..061c365e35
--- /dev/null
+++ b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileDialog/your_group_by.xml
@@ -0,0 +1,275 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="ListField" module="Products.Formulator.StandardFields"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>your_group_by</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>
+                <item>
+                    <key> <string>required_not_found</string> </key>
+                    <value> <string>Input is required but no input given.</string> </value>
+                </item>
+                <item>
+                    <key> <string>unknown_selection</string> </key>
+                    <value> <string>You selected an item that was not in the list.</string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>overrides</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>alternate_name</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>css_class</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>default</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>description</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>enabled</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>external_validator</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>extra</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>extra_item</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>first_item</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>hidden</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>items</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>required</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>size</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>title</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>unicode</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>whitespace_preserve</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>tales</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>alternate_name</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>css_class</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>default</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>description</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>enabled</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>external_validator</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>extra</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>extra_item</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>first_item</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>hidden</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>items</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>required</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>size</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>title</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>unicode</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>whitespace_preserve</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>alternate_name</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>css_class</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>default</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>description</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value> <int>1</int> </value>
+                </item>
+                <item>
+                    <key> <string>enabled</string> </key>
+                    <value> <int>1</int> </value>
+                </item>
+                <item>
+                    <key> <string>external_validator</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>extra</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>extra_item</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>first_item</string> </key>
+                    <value> <int>1</int> </value>
+                </item>
+                <item>
+                    <key> <string>hidden</string> </key>
+                    <value> <int>0</int> </value>
+                </item>
+                <item>
+                    <key> <string>items</string> </key>
+                    <value>
+                      <list>
+                        <tuple>
+                          <string>Transaction Type</string>
+                          <string>portal_type</string>
+                        </tuple>
+                        <tuple>
+                          <string>Ledger</string>
+                          <string>ledger</string>
+                        </tuple>
+                        <tuple>
+                          <string>Both</string>
+                          <string>portal_type_ledger</string>
+                        </tuple>
+                      </list>
+                    </value>
+                </item>
+                <item>
+                    <key> <string>required</string> </key>
+                    <value> <int>0</int> </value>
+                </item>
+                <item>
+                    <key> <string>size</string> </key>
+                    <value> <int>1</int> </value>
+                </item>
+                <item>
+                    <key> <string>title</string> </key>
+                    <value> <string>Kind of Report</string> </value>
+                </item>
+                <item>
+                    <key> <string>unicode</string> </key>
+                    <value> <int>0</int> </value>
+                </item>
+                <item>
+                    <key> <string>whitespace_preserve</string> </key>
+                    <value> <int>0</int> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileForPortalType.py b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileForPortalType.py
deleted file mode 100644
index feaebf357a..0000000000
--- a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewFrenchAccountingTransactionFileForPortalType.py
+++ /dev/null
@@ -1,37 +0,0 @@
-portal = context.getPortalObject()
-portal_categories = portal.portal_categories
-
-search_kw = {
-  'simulation_state': simulation_state,
-  'accounting_transaction.section_uid': section_uid_list,
-  'operation_date': {'query': (from_date, at_date), 'range': 'minngt' },
-  'portal_type': portal_type,
-}
-
-if ledger is not None:
-  if isinstance(ledger, list) or isinstance(ledger, tuple):
-    ledger_uid_list = [portal_categories.ledger.restrictedTraverse(item).getUid() for item in ledger]
-  else:
-    ledger_uid_list = [portal_categories.ledger.restrictedTraverse(ledger).getUid(), ]
-  search_kw['default_ledger_uid'] = ledger_uid_list
-
-method_kw = {
-  'active_process': this_portal_type_active_process,
-  'section_uid_list': section_uid_list,
-}
-
-activate_kw = {
-  'tag': tag,
-  'priority': priority,
-}
-
-portal.portal_catalog.searchAndActivate(
-  method_id='AccountingTransaction_postFECResult', 
-  method_kw=method_kw,
-  activate_kw=activate_kw,
-  **search_kw)
-
-context.activate(tag=aggregate_tag, after_tag=tag, activity='SQLQueue').AccountingTransactionModule_aggregateFrenchAccountingTransactionFileForPortalType(
-  portal_type=portal_type,
-  active_process=active_process,
-  this_portal_type_active_process=this_portal_type_active_process)
diff --git a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewJournalAsFECXML.zpt b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewJournalAsFECXML.zpt
index 11253753f5..40511aeacb 100644
--- a/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewJournalAsFECXML.zpt
+++ b/bt5/erp5_accounting_l10n_fr/SkinTemplateItem/portal_skins/erp5_accounting_l10n_fr/AccountingTransactionModule_viewJournalAsFECXML.zpt
@@ -1,5 +1,5 @@
 <journal xmlns:tal="http://xml.zope.org/namespaces/tal">
-  <JournalCode tal:content="options/portal_type/getCompactTranslatedTitle"></JournalCode>
-  <JournalLib tal:content="options/portal_type/getTranslatedTitle"></JournalLib>
+  <JournalCode tal:content="options/journal_code"></JournalCode>
+  <JournalLib tal:content="options/journal_lib"></JournalLib>
   <tal:block tal:repeat="result options/result_list"><tal:block tal:replace="structure python: result.detail.decode('zlib')"/></tal:block>
 </journal>
\ No newline at end of file
diff --git a/product/ERP5/tests/testAccounting_l10n_fr.py b/product/ERP5/tests/testAccounting_l10n_fr.py
index 5b3589c23d..c2a814c3b7 100644
--- a/product/ERP5/tests/testAccounting_l10n_fr.py
+++ b/product/ERP5/tests/testAccounting_l10n_fr.py
@@ -161,7 +161,7 @@ class TestAccounting_l10n_fr(AccountingTestCase):
     self.assertEqual(6, len(credit_list))
     self.assertEqual(372, sum([float(x.text) for x in credit_list]))
 
-  def _FECWithLedger(self, ledger_list=None):
+  def _FECWithLedger(self, ledger_list=None, group_by=None):
     self.setUpLedger()
     account_module = self.portal.account_module
     first = self._makeOne(
@@ -215,6 +215,7 @@ class TestAccounting_l10n_fr(AccountingTestCase):
         section_category_strict=False,
         at_date=DateTime(2014, 12, 31),
         simulation_state=['delivered'],
+        group_by=group_by,
         ledger=ledger_list)
     self.tic()
 
@@ -249,25 +250,159 @@ class TestAccounting_l10n_fr(AccountingTestCase):
   def test_FECWithOneLedger(self):
     tree = self._FECWithLedger(['accounting/general'])
 
-    debit_list = tree.xpath("//Debit")
+    # 'Purchase Invoice Transaction' portal_type
+    journal_list = tree.xpath("//JournalCode[text()='Purchase Invoice Transaction']/..")
+    self.assertEqual(1, len(journal_list))
+    journal = journal_list[0]
+
+    ecriture_list = sorted([x.text.encode('utf-8') for x in journal.xpath(".//EcritureLib")])
+    self.assertEqual(['Première Écriture'], ecriture_list)
+
+    debit_list = journal.xpath(".//Debit")
+    self.assertEqual(3, len(debit_list))
+    self.assertEqual(132, sum([float(x.text) for x in debit_list]))
+
+    credit_list = journal.xpath(".//Credit")
+    self.assertEqual(3, len(credit_list))
+    self.assertEqual(132, sum([float(x.text) for x in credit_list]))
+
+    # 'Sale Invoice Transaction' portal_type
+    journal_list = tree.xpath("//JournalCode[text()='Sale Invoice Transaction']/..")
+    self.assertEqual(1, len(journal_list))
+    journal = journal_list[0]
+
+    ecriture_list = sorted([x.text.encode('utf-8') for x in journal.xpath(".//EcritureLib")])
+    self.assertEqual(['Seconde Écriture'], ecriture_list)
+
+    debit_list = journal.xpath(".//Debit")
+    self.assertEqual(3, len(debit_list))
+    self.assertEqual(240, sum([float(x.text) for x in debit_list]))
+
+    credit_list = journal.xpath(".//Credit")
+    self.assertEqual(3, len(credit_list))
+    self.assertEqual(240, sum([float(x.text) for x in credit_list]))
+
+  def test_FECWithMultipleLedger(self):
+    # group_by=portal_type by default
+    tree = self._FECWithLedger(['accounting/general', 'accounting/detailed'])
+
+    # 'Purchase Invoice Transaction' portal_type
+    journal_list = tree.xpath("//JournalCode[text()='Purchase Invoice Transaction']/..")
+    self.assertEqual(1, len(journal_list))
+    journal = journal_list[0]
+
+    ecriture_list = sorted([x.text.encode('utf-8') for x in journal.xpath(".//EcritureLib")])
+    self.assertEqual(['Première Écriture'], ecriture_list)
+
+    debit_list = journal.xpath(".//Debit")
+    self.assertEqual(3, len(debit_list))
+    self.assertEqual(132, sum([float(x.text) for x in debit_list]))
+
+    credit_list = journal.xpath(".//Credit")
+    self.assertEqual(3, len(credit_list))
+    self.assertEqual(132, sum([float(x.text) for x in credit_list]))
+
+    # 'Sale Invoice Transaction' portal_type
+    journal_list = tree.xpath("//JournalCode[text()='Sale Invoice Transaction']/..")
+    self.assertEqual(1, len(journal_list))
+    journal = journal_list[0]
+
+    ecriture_list = sorted([x.text.encode('utf-8') for x in journal.xpath(".//EcritureLib")])
+    self.assertEqual(['Seconde Écriture', 'Troisième Écriture'], ecriture_list)
+
+    debit_list = journal.xpath(".//Debit")
+    self.assertEqual(6, len(debit_list))
+    self.assertEqual(425, sum([float(x.text) for x in debit_list]))
+
+    credit_list = journal.xpath(".//Credit")
+    self.assertEqual(6, len(credit_list))
+    self.assertEqual(425, sum([float(x.text) for x in credit_list]))
+
+  def test_FECWithMultipleLedgerGroupByLedger(self):
+    tree = self._FECWithLedger(['accounting/general', 'accounting/detailed'], group_by='ledger')
+
+    # 'accounting/general' ledger
+    journal_list = tree.xpath("//JournalCode[text()='general']/..")
+    self.assertEqual(1, len(journal_list))
+    journal = journal_list[0]
+
+    ecriture_list = sorted([x.text.encode('utf-8') for x in journal.xpath(".//EcritureLib")])
+    self.assertEqual(['Première Écriture', 'Seconde Écriture'], ecriture_list)
+
+    debit_list = journal.xpath(".//Debit")
     self.assertEqual(6, len(debit_list))
     self.assertEqual(372, sum([float(x.text) for x in debit_list]))
 
-    credit_list = tree.xpath("//Credit")
+    credit_list = journal.xpath(".//Credit")
     self.assertEqual(6, len(credit_list))
     self.assertEqual(372, sum([float(x.text) for x in credit_list]))
 
+    # 'accounting/detailed' ledger
+    journal_list = tree.xpath("//JournalCode[text()='detailed']/..")
+    self.assertEqual(1, len(journal_list))
+    journal = journal_list[0]
 
-  def test_FECWithMultipleLedger(self):
-    tree = self._FECWithLedger(['accounting/general', 'accounting/detailed'])
+    ecriture_list = sorted([x.text.encode('utf-8') for x in journal.xpath(".//EcritureLib")])
+    self.assertEqual(['Troisième Écriture'], ecriture_list)
 
-    debit_list = tree.xpath("//Debit")
-    self.assertEqual(9, len(debit_list))
-    self.assertEqual(557, sum([float(x.text) for x in debit_list]))
+    debit_list = journal.xpath(".//Debit")
+    self.assertEqual(3, len(debit_list))
+    self.assertEqual(185, sum([float(x.text) for x in debit_list]))
 
-    credit_list = tree.xpath("//Credit")
-    self.assertEqual(9, len(credit_list))
-    self.assertEqual(557, sum([float(x.text) for x in credit_list]))
+    credit_list = journal.xpath(".//Credit")
+    self.assertEqual(3, len(credit_list))
+    self.assertEqual(185, sum([float(x.text) for x in credit_list]))
+
+  def test_FECWithMultipleLedgerGroupByLedgerAndPortalType(self):
+    tree = self._FECWithLedger(['accounting/general', 'accounting/detailed'], group_by='portal_type_ledger')
+
+    # 'Purchase Invoice Transaction' portal_type and 'accounting/general' ledger
+    journal_list = tree.xpath("//JournalCode[text()='Purchase Invoice Transaction: general']/..")
+    self.assertEqual(1, len(journal_list))
+    journal = journal_list[0]
+
+    ecriture_list = sorted([x.text.encode('utf-8') for x in journal.xpath(".//EcritureLib")])
+    self.assertEqual(['Première Écriture'], ecriture_list)
+
+    debit_list = journal.xpath(".//Debit")
+    self.assertEqual(3, len(debit_list))
+    self.assertEqual(132, sum([float(x.text) for x in debit_list]))
+
+    credit_list = journal.xpath(".//Credit")
+    self.assertEqual(3, len(credit_list))
+    self.assertEqual(132, sum([float(x.text) for x in credit_list]))
+
+    # 'Sale Invoice Transaction' portal_type and 'accounting/general' ledger
+    journal_list = tree.xpath("//JournalCode[text()='Sale Invoice Transaction: general']/..")
+    self.assertEqual(1, len(journal_list))
+    journal = journal_list[0]
+
+    ecriture_list = sorted([x.text.encode('utf-8') for x in journal.xpath(".//EcritureLib")])
+    self.assertEqual(['Seconde Écriture'], ecriture_list)
+
+    debit_list = journal.xpath(".//Debit")
+    self.assertEqual(3, len(debit_list))
+    self.assertEqual(240, sum([float(x.text) for x in debit_list]))
+
+    credit_list = journal.xpath(".//Credit")
+    self.assertEqual(3, len(credit_list))
+    self.assertEqual(240, sum([float(x.text) for x in credit_list]))
+
+    # 'Sale Invoice Transaction' portal_type and 'accounting/detailed' ledger
+    journal_list = tree.xpath("//JournalCode[text()='Sale Invoice Transaction: detailed']/..")
+    self.assertEqual(1, len(journal_list))
+    journal = journal_list[0]
+
+    ecriture_list = sorted([x.text.encode('utf-8') for x in journal.xpath(".//EcritureLib")])
+    self.assertEqual(['Troisième Écriture'], ecriture_list)
+
+    debit_list = journal.xpath(".//Debit")
+    self.assertEqual(3, len(debit_list))
+    self.assertEqual(185, sum([float(x.text) for x in debit_list]))
+
+    credit_list = journal.xpath(".//Credit")
+    self.assertEqual(3, len(credit_list))
+    self.assertEqual(185, sum([float(x.text) for x in credit_list]))
 
 def test_suite():
   suite = unittest.TestSuite()
-- 
2.30.9