Commit cbe50b0f authored by Nicolas Wavrant's avatar Nicolas Wavrant

erp5_accounting_l10n_fr: the French Fiscal Report (FEC) can be generated for different ledgers

Adds the support of filtering with Ledgers for the generation of the French Fiscal Report (aka FEC).

/reviewed-on nexedi/erp5!195
parent 5815d3cb
...@@ -21,6 +21,7 @@ context.activate().AccountingTransactionModule_viewFrenchAccountingTransactionFi ...@@ -21,6 +21,7 @@ context.activate().AccountingTransactionModule_viewFrenchAccountingTransactionFi
section_category_strict, section_category_strict,
at_date, at_date,
simulation_state, simulation_state,
ledger,
user_name=person_value.getReference(), user_name=person_value.getReference(),
tag=tag, tag=tag,
aggregate_tag=aggregate_tag) aggregate_tag=aggregate_tag)
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>section_category, section_category_strict, at_date, simulation_state, form_id=None, **kw</string> </value> <value> <string>section_category, section_category_strict, at_date, simulation_state, ledger=None, form_id=None, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -22,6 +22,7 @@ for portal_type in portal.getPortalAccountingTransactionTypeList(): ...@@ -22,6 +22,7 @@ for portal_type in portal.getPortalAccountingTransactionTypeList():
from_date, from_date,
at_date, at_date,
simulation_state, simulation_state,
ledger,
active_process.getRelativeUrl(), active_process.getRelativeUrl(),
this_portal_type_active_process.getRelativeUrl(), this_portal_type_active_process.getRelativeUrl(),
tag, tag,
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>section_category, section_category_strict, at_date, simulation_state, user_name, tag, aggregate_tag, **kw</string> </value> <value> <string>section_category, section_category_strict, at_date, simulation_state, ledger, user_name, tag, aggregate_tag, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>_proxy_roles</string> </key> <key> <string>_proxy_roles</string> </key>
......
...@@ -96,6 +96,7 @@ ...@@ -96,6 +96,7 @@
<string>your_section_category</string> <string>your_section_category</string>
<string>your_section_category_strict</string> <string>your_section_category_strict</string>
<string>your_at_date</string> <string>your_at_date</string>
<string>your_ledger</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/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_ledger</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>
</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>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>your_ledger</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>AccountModule_viewDialogFieldLibrary</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
portal = context.getPortalObject() portal = context.getPortalObject()
portal_categories = portal.portal_categories
search_kw = { search_kw = {
'simulation_state': simulation_state, 'simulation_state': simulation_state,
...@@ -7,6 +8,13 @@ search_kw = { ...@@ -7,6 +8,13 @@ search_kw = {
'portal_type': portal_type, '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 = { method_kw = {
'active_process': this_portal_type_active_process, 'active_process': this_portal_type_active_process,
'section_uid_list': section_uid_list, 'section_uid_list': section_uid_list,
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>portal_type, section_uid_list, from_date, at_date, simulation_state, active_process, this_portal_type_active_process, tag, aggregate_tag, priority</string> </value> <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>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -37,6 +37,16 @@ ...@@ -37,6 +37,16 @@
<key> <string>action</string> </key> <key> <string>action</string> </key>
<value> <string>FiscalReport_doReport</string> </value> <value> <string>FiscalReport_doReport</string> </value>
</item> </item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>edit_order</string> </key>
<value>
<list/>
</value>
</item>
<item> <item>
<key> <string>encoding</string> </key> <key> <string>encoding</string> </key>
<value> <string>UTF-8</string> </value> <value> <string>UTF-8</string> </value>
...@@ -62,6 +72,7 @@ ...@@ -62,6 +72,7 @@
<key> <string>Default</string> </key> <key> <string>Default</string> </key>
<value> <value>
<list> <list>
<string>my_organisation</string>
<string>my_from_date</string> <string>my_from_date</string>
<string>my_from_date_n_1</string> <string>my_from_date_n_1</string>
<string>my_report</string> <string>my_report</string>
...@@ -74,7 +85,6 @@ ...@@ -74,7 +85,6 @@
<list> <list>
<string>my_at_date</string> <string>my_at_date</string>
<string>my_at_date_n_1</string> <string>my_at_date_n_1</string>
<string>my_organisation</string>
</list> </list>
</value> </value>
</item> </item>
...@@ -117,6 +127,10 @@ ...@@ -117,6 +127,10 @@
<key> <string>update_action</string> </key> <key> <string>update_action</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>update_action_title</string> </key>
<value> <string></string> </value>
</item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
gap_base gap_base
simulation_state simulation_state
section_category section_category
ledger
those are ignored from the request and should explicitely passed as keywords args to this script: those are ignored from the request and should explicitely passed as keywords args to this script:
from_date from_date
...@@ -22,12 +23,23 @@ getURL = lambda gap_id: context.GAPCategory_getURLFromId(gap_id, gap_base) ...@@ -22,12 +23,23 @@ getURL = lambda gap_id: context.GAPCategory_getURLFromId(gap_id, gap_base)
section = context.restrictedTraverse(request.get("organisation")) section = context.restrictedTraverse(request.get("organisation"))
section_region = section.getRegion() section_region = section.getRegion()
ledger = request.get("ledger", None)
if ledger is not None:
portal_categories = context.getPortalObject().portal_categories
if isinstance(ledger, list) or isinstance(ledger, tuple):
ledger_uid = [portal_categories.ledger.restrictedTraverse(item).getUid() for item in ledger]
else:
ledger_uid = portal_categories.ledger.restrictedTraverse(item).getUid()
else:
ledger_uid = None
# 'getInventory' common parameters # 'getInventory' common parameters
params = { 'omit_simulation' : True params = { 'omit_simulation' : True
, 'simulation_state': request.get("simulation_state", ['stopped', 'delivered']) , 'simulation_state': request.get("simulation_state", ['stopped', 'delivered'])
, 'section_uid' : section.getUid() , 'section_uid' : section.getUid()
, 'precision' : 2 , 'precision' : 2
, 'at_date' : request['at_date'] , 'at_date' : request['at_date']
, 'ledger_uid' : ledger_uid
} }
params.update(kw) params.update(kw)
......
...@@ -20,6 +20,14 @@ kw["section_category"] = kwd.get("section_category", ...@@ -20,6 +20,14 @@ kw["section_category"] = kwd.get("section_category",
kw['to_date'] = kwd.get('at_date', request['at_date']) +1 kw['to_date'] = kwd.get('at_date', request['at_date']) +1
kw['where_expression'] = " section.portal_type = 'Organisation' " kw['where_expression'] = " section.portal_type = 'Organisation' "
ledger = kw.get('ledger', request.get("ledger", None))
if ledger is not None:
portal_categories = context.getPortalObject().portal_categories
if isinstance(ledger, list) or isinstance(ledger, tuple):
kw['ledger_uid'] = [portal_categories.ledger.restrictedTraverse(item).getUid() for item in ledger]
else:
kw['ledger_uid'] = portal_categories.ledger.restrictedTraverse(item).getUid()
sum = 0.0 sum = 0.0
for accountNumber in accounts: for accountNumber in accounts:
# we get all acounts strict member of this GAP category # we get all acounts strict member of this GAP category
......
...@@ -19,6 +19,13 @@ kw["section_category"] = kwd.get("section_category", ...@@ -19,6 +19,13 @@ kw["section_category"] = kwd.get("section_category",
kw['at_date'] = kwd.get('at_date', request['at_date']) kw['at_date'] = kwd.get('at_date', request['at_date'])
kw['where_expression'] = " section.portal_type = 'Organisation' " kw['where_expression'] = " section.portal_type = 'Organisation' "
ledger = kwd.get('ledger', request.get("ledger", None))
if ledger is not None:
portal_categories = context.getPortalObject().portal_categories
if isinstance(ledger, list) or isinstance(ledger, tuple):
kw['ledger_uid'] = [portal_categories.ledger.restrictedTraverse(item).getUid() for item in ledger]
else:
kw['ledger_uid'] = portal_categories.ledger.restrictedTraverse(item).getUid()
sum = 0.0 sum = 0.0
for account in accounts: for account in accounts:
......
...@@ -24,6 +24,14 @@ kw['simulation_state'] = kwd.get('simulation_state', request.get('simulation_sta ...@@ -24,6 +24,14 @@ kw['simulation_state'] = kwd.get('simulation_state', request.get('simulation_sta
kw['section_category'] = kwd.get("section_category", "group/%s" % context.restrictedTraverse(request.get("organisation")).getGroup()) kw['section_category'] = kwd.get("section_category", "group/%s" % context.restrictedTraverse(request.get("organisation")).getGroup())
kw['where_expression'] = " section.portal_type = 'Organisation' " kw['where_expression'] = " section.portal_type = 'Organisation' "
ledger = kwd.get('ledger', request.get("ledger", None))
if ledger is not None:
portal_categories = context.getPortalObject().portal_categories
if isinstance(ledger, list) or isinstance(ledger, tuple):
kw['ledger_uid'] = [portal_categories.ledger.restrictedTraverse(item).getUid() for item in ledger]
else:
kw['ledger_uid'] = portal_categories.ledger.restrictedTraverse(item).getUid()
# Find accounts that can be expanded according category membership # Find accounts that can be expanded according category membership
acc_type = context.portal_categories.account_type acc_type = context.portal_categories.account_type
......
...@@ -159,6 +159,113 @@ class TestAccounting_l10n_fr(AccountingTestCase): ...@@ -159,6 +159,113 @@ class TestAccounting_l10n_fr(AccountingTestCase):
self.assertEqual(6, len(credit_list)) self.assertEqual(6, len(credit_list))
self.assertEqual(372, sum([float(x.text) for x in credit_list])) self.assertEqual(372, sum([float(x.text) for x in credit_list]))
def _FECWithLedger(self, ledger_list=None):
self.setUpLedger()
account_module = self.portal.account_module
first = self._makeOne(
portal_type='Purchase Invoice Transaction',
title='Première Écriture',
simulation_state='delivered',
ledger='accounting/general',
reference='1',
source_section_value=self.organisation_module.supplier,
stop_date=DateTime(2014, 2, 2),
lines=(dict(destination_value=account_module.payable,
destination_debit=132.00),
dict(destination_value=account_module.refundable_vat,
destination_credit=22.00),
dict(destination_value=account_module.goods_purchase,
destination_credit=110.00)))
second = self._makeOne(
portal_type='Sale Invoice Transaction',
title='Seconde Écriture',
simulation_state='delivered',
ledger='accounting/general',
reference='2',
destination_section_value=self.organisation_module.client_2,
start_date=DateTime(2014, 3, 1),
lines=(dict(source_value=account_module.receivable,
source_debit=240.00),
dict(source_value=account_module.collected_vat,
source_credit=40.00),
dict(source_value=account_module.goods_sales,
source_credit=200.00)))
third = self._makeOne(
portal_type='Sale Invoice Transaction',
title='Troisième Écriture',
simulation_state='delivered',
ledger='accounting/detailed',
reference='3',
destination_section_value=self.organisation_module.client_2,
start_date=DateTime(2014, 2, 16),
lines=(dict(source_value=account_module.receivable,
source_debit=185.00),
dict(source_value=account_module.collected_vat,
source_credit=37.00),
dict(source_value=account_module.goods_sales,
source_credit=148.00)))
self.tic()
self.portal.accounting_module.AccountingTransactionModule_viewFrenchAccountingTransactionFile(
section_category='group/demo_group',
section_category_strict=False,
at_date=DateTime(2014, 12, 31),
simulation_state=['delivered'],
ledger=ledger_list)
self.tic()
fec_xml = ''
last_message = self.portal.MailHost._last_message
self.assertNotEquals((), last_message)
mfrom, mto, message_text = last_message
self.assertEqual('"%s" <%s>' % (self.first_name, self.recipient_email_address), mto[0])
mail_message = email.message_from_string(message_text)
for part in mail_message.walk():
content_type = part.get_content_type()
file_name = part.get_filename()
if file_name == 'FEC-2014.zip':
self.assertEqual('application/zip', content_type)
data = part.get_payload(decode=True)
zf = zipfile.ZipFile(StringIO(data))
fec_xml = zf.open("FEC.xml").read()
break
else:
self.fail("Attachment not found")
# validate against official schema
schema = etree.XMLSchema(etree.XML(open(os.path.join(
os.path.dirname(__file__), 'test_data',
'formatA47A-I-VII-1.xsd')).read()))
# this raise if invalid
tree = etree.fromstring(fec_xml, etree.XMLParser(schema=schema))
return tree
def test_FECWithOneLedger(self):
tree = self._FECWithLedger(['accounting/general'])
debit_list = tree.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")
self.assertEqual(6, len(credit_list))
self.assertEqual(372, sum([float(x.text) for x in credit_list]))
def test_FECWithMultipleLedger(self):
tree = self._FECWithLedger(['accounting/general', 'accounting/detailed'])
debit_list = tree.xpath("//Debit")
self.assertEqual(9, len(debit_list))
self.assertEqual(557, 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]))
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
......
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