openerp-community-reviewer team mailing list archive
-
openerp-community-reviewer team
-
Mailing list archive
-
Message #06012
[Merge] lp:~camptocamp/account-consolidation/fix-domain-nbi into lp:account-consolidation
Nicolas Bessi - Camptocamp has proposed merging lp:~camptocamp/account-consolidation/fix-domain-nbi into lp:account-consolidation.
Requested reviews:
Account Core Editors (account-core-editors)
For more details, see:
https://code.launchpad.net/~camptocamp/account-consolidation/fix-domain-nbi/+merge/216330
[FIX] missing domain on function fields that can have a really bad performace issue
--
https://code.launchpad.net/~camptocamp/account-consolidation/fix-domain-nbi/+merge/216330
Your team Account Core Editors is requested to review the proposed merge of lp:~camptocamp/account-consolidation/fix-domain-nbi into lp:account-consolidation.
=== modified file 'account_consolidation/__init__.py'
--- account_consolidation/__init__.py 2011-08-12 15:39:07 +0000
+++ account_consolidation/__init__.py 2014-04-17 13:57:59 +0000
@@ -1,3 +1,4 @@
-import company
-import account
-import wizard
+from . import company
+from . import account
+from . import account_move_line
+from . import wizard
=== modified file 'account_consolidation/__openerp__.py'
--- account_consolidation/__openerp__.py 2012-04-11 07:52:09 +0000
+++ account_consolidation/__openerp__.py 2014-04-17 13:57:59 +0000
@@ -1,72 +1,72 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
-# All Right Reserved
-#
-# Author : Guewen Baconnier (Camptocamp)
-#
-# WARNING: This program as such is intended to be used by professional
-# programmers who take the whole responsability of assessing all potential
-# consequences resulting from its eventual inadequacies and bugs
-# End users who are looking for a ready-to-use solution with commercial
-# garantees and support are strongly adviced to contract a Free Software
-# Service Company
-#
-# This program is Free Software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Author: Guewen Baconnier
+# Copyright 2011-2013 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
-
-
-{
- "name" : "Account Consolidation",
- "version" : "0.0",
- "author" : "Camptocamp",
- "category" : "Generic Modules/Accounting",
- "description":
-"""
-Account consolidation module. Coding in progress...
-
-Some explanations to do...
-
- - Difference between debit/credit is balanced on the debit/credit default account of the journal?
-""",
- "website": "http://www.camptocamp.com",
- "depends" : [
- 'base',
- 'account',
- 'account_reversal',
- ],
- "init_xml" : [],
- "demo_xml" : [
- 'demo/consolidation_demo.xml',
- 'demo/chart_a_demo.xml',
- 'demo/chart_b_demo.xml',
- ],
- "update_xml" : [
- 'company_view.xml',
- 'account_view.xml',
- 'wizard/consolidation_check_view.xml',
- 'wizard/consolidation_consolidate_view.xml',
- 'consolidation_menu.xml',
- ],
- 'test': [
- 'test/test_data.yml',
- 'test/consolidation_checks.yml',
- 'test/consolidation_consolidate.yml',
- ],
- "active": False,
- "installable": True
-}
+{"name": "Account Consolidation",
+ "version": "1.0",
+ "author": "Camptocamp",
+ "license": "AGPL-3",
+ "category": "Generic Modules/Accounting",
+ "description": """
+Account consolidation
+=====================
+
+Introduction
+------------
+
+Consolidate chart of accounts on subsidiaries
+in a virtual chart of accounts of the holding.
+
+Installation
+------------
+The `account_reversal` module is required,
+it can be found on the account-financial-tools_
+project
+
+.. _account-financial-tools: https://launchpad.net/account-financial-tools""",
+
+ "website": "http://www.camptocamp.com",
+ "depends": ['base',
+ 'account',
+ 'account_reversal', # TODO check account_constraints compat.
+ ],
+
+ "demo_xml": ['demo/consolidation_demo.xml',
+ 'demo/chart_a_demo.xml',
+ 'demo/chart_b_demo.xml',
+ ],
+
+ "data": ['data.xml',
+ 'account_move_line_view.xml',
+ 'company_view.xml',
+ 'account_view.xml',
+ 'wizard/consolidation_check_view.xml',
+ 'wizard/consolidation_consolidate_view.xml',
+ 'consolidation_menu.xml',
+ 'analysis_view.xml'
+ ],
+
+ "test": ['test/test_data.yml',
+ 'test/consolidation_checks.yml',
+ 'test/consolidation_consolidate.yml',
+ ],
+
+ "active": False,
+ "installable": True,
+ }
=== modified file 'account_consolidation/account.py'
--- account_consolidation/account.py 2011-08-29 14:04:57 +0000
+++ account_consolidation/account.py 2014-04-17 13:57:59 +0000
@@ -1,77 +1,74 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
-#
-# Author : Guewen Baconnier (Camptocamp)
-#
-# WARNING: This program as such is intended to be used by professional
-# programmers who take the whole responsability of assessing all potential
-# consequences resulting from its eventual inadequacies and bugs
-# End users who are looking for a ready-to-use solution with commercial
-# garantees and support are strongly adviced to contract a Free Software
-# Service Company
-#
-# This program is Free Software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Author: Guewen Baconnier
+# Copyright 2011-2013 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
-from osv import osv, fields
-
-
-class account_account(osv.osv):
+from openerp.osv import orm, fields
+
+
+class account_account(orm.Model):
_inherit = 'account.account'
_columns = {
- 'consolidation_rate_type_id': fields.many2one('res.currency.rate.type',
- 'Consolidation Currency Rate Type',
- help="Currency rate type used on this account for the consolidation, Leave empty to use the rate type of the account type."),
- 'consolidation_mode': fields.selection([('', ''),
- ('ytd', 'YTD'),
- ('period', 'Period Movements'),
- ],
- 'Consolidation Mode'),
+ 'consolidation_rate_type_id': fields.many2one(
+ 'res.currency.rate.type',
+ 'Consolidation Currency Rate Type',
+ help="Currency rate type used on this account "
+ "for the consolidation. "
+ "Leave empty to use the rate type of the account type."),
+
+ 'consolidation_mode': fields.selection(
+ [('ytd', 'YTD'),
+ ('period', 'Period Movements')],
+ 'Consolidation Mode',
+ help="This must be set on the holding company accounts only"),
}
-account_account()
-
-
-class account_account_type(osv.osv):
+
+class account_account_type(orm.Model):
_inherit = 'account.account.type'
_columns = {
- 'consolidation_rate_type_id': fields.many2one('res.currency.rate.type',
- 'Consolidation Currency Rate Type',
- help="Currency rate type used on this account type for the consolidation, Leave empty to use the 'spot' rate type."),
- 'consolidation_mode': fields.selection([('ytd', 'YTD'),
- ('period', 'Period Movements'),],
- 'Consolidation Mode'),
- }
-
- _defaults = {
- 'consolidation_mode': 'ytd',
- }
-
-account_account_type()
-
-
-class account_move(osv.osv):
+ 'consolidation_rate_type_id': fields.many2one(
+ 'res.currency.rate.type',
+ 'Consolidation Currency Rate Type',
+ help="Currency rate type used on this account type "
+ "for the consolidation. "
+ "Leave empty to use the 'spot' rate type."),
+
+ 'consolidation_mode': fields.selection(
+ [('ytd', 'YTD'),
+ ('period', 'Period Movements')],
+ 'Consolidation Mode',
+ help="This must be set on the holding company accounts only"),
+
+ }
+
+ _defaults = {'consolidation_mode': 'ytd'}
+
+
+class account_move(orm.Model):
_inherit = 'account.move'
_columns = {
- 'consol_company_id': fields.many2one('res.company', 'Consolidated from Company', readonly=True),
+ 'consol_company_id': fields.many2one(
+ 'res.company',
+ 'Consolidated from Company',
+ readonly=True),
}
-
-account_move()
=== added file 'account_consolidation/account_move_line.py'
--- account_consolidation/account_move_line.py 1970-01-01 00:00:00 +0000
+++ account_consolidation/account_move_line.py 2014-04-17 13:57:59 +0000
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Author: Nicolas Bessi Guewen Baconnier
+# Copyright 2011-2013 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import orm, fields
+
+
+class AccountMoveLine(orm.Model):
+ _inherit = 'account.move.line'
+
+ def _current_company(self, cursor, uid, ids, name, args, context=None):
+ company_id = self.pool['res.company']._company_default_get(cursor, uid)
+ curr_ids = self.search(cursor, uid, [('company_id', '=', company_id),
+ ('id', 'in', ids)])
+ res = dict([(tid, tid in curr_ids) for tid in ids])
+ return res
+
+
+ def search_is_current_company(self, cursor, uid, obj, name, args, context=None):
+ company_id = self.pool['res.company']._company_default_get(cursor, uid)
+ res = self.search(cursor, uid, [('company_id', '=', company_id)])
+ return [('id', 'in', res)]
+
+ _columns = {'consol_company_id': fields.related('move_id', 'consol_company_id',
+ relation='res.company',
+ type="many2one",
+ string='Subsidaries',
+ store=True, # for the group_by
+ readonly=True),
+
+ 'is_current_company': fields.function(_current_company,
+ string="Current company",
+ type="boolean",
+ fnct_search=search_is_current_company)
+ }
=== added file 'account_consolidation/account_move_line_view.xml'
--- account_consolidation/account_move_line_view.xml 1970-01-01 00:00:00 +0000
+++ account_consolidation/account_move_line_view.xml 2014-04-17 13:57:59 +0000
@@ -0,0 +1,30 @@
+<openerp>
+ <data>
+ <record id="view_move_line_tree" model="ir.ui.view">
+ <field name="name">account.move.line.tree.conso</field>
+ <field name="model">account.move.line</field>
+ <field name="inherit_id" ref="account.view_move_line_tree"/>
+ <field name="arch" type="xml">
+ <field name="date" position="before">
+ <field name="consol_company_id"
+ groups="account_consolidation.consolidation_manager,account_consolidation.consolidation_user"/>
+ <field name="is_current_company" invisible="1"/>
+ </field>
+ </field>
+ </record>
+
+ <record id="view_account_move_line_filter" model="ir.ui.view">
+ <field name="name">Journal Items conso</field>
+ <field name="model">account.move.line</field>
+ <field name="inherit_id" ref="account.view_account_move_line_filter"/>
+ <field name="arch" type="xml">
+ <filter string="Period" position="after">
+ <filter string="Subsidaries"
+ icon="terp-folder-green"
+ context="{'group_by':'consol_company_id'}"
+ groups="account_consolidation.consolidation_manager,account_consolidation.consolidation_user"/>
+ </filter>
+ </field>
+ </record>
+ </data>
+</openerp>
=== modified file 'account_consolidation/account_view.xml'
--- account_consolidation/account_view.xml 2011-08-29 14:04:57 +0000
+++ account_consolidation/account_view.xml 2014-04-17 13:57:59 +0000
@@ -9,8 +9,8 @@
<field name="type">form</field>
<field name="arch" type="xml">
<data>
- <xpath expr="/form/notebook/page[@string='General Information']/group[2]" position="after">
- <group col="2" colspan="2">
+ <xpath expr="//field[@name='note']" position="after">
+ <group groups="account_consolidation.consolidation_manager">
<separator string="Consolidation" colspan="2"/>
<field name="consolidation_rate_type_id" widget="selection"/>
<field name="consolidation_mode"/>
@@ -20,7 +20,7 @@
</data>
</field>
</record>
-
+
<record id="view_account_type_consolidation_form" model="ir.ui.view">
<field name="name">account.account.type.consolidation.form</field>
<field name="model">account.account.type</field>
@@ -28,7 +28,7 @@
<field name="type">form</field>
<field name="arch" type="xml">
<separator string="Description" position="before">
- <group col="2" colspan="2">
+ <group col="2" colspan="2" groups="account_consolidation.consolidation_manager">
<separator string="Consolidation" colspan="4"/>
<field name="consolidation_rate_type_id" widget="selection"/>
<field name="consolidation_mode"/>
@@ -44,11 +44,12 @@
<field name="type">form</field>
<field name="arch" type="xml">
<field name="company_id" position="after">
- <field name="consol_company_id" attrs="{'invisible': [('consol_company_id', '=', False)]}"/>
+ <field name="consol_company_id"
+ attrs="{'invisible': [('consol_company_id', '=', False)]}"
+ groups="account_consolidation.consolidation_manager,account_consolidation.consolidation_user"/>
</field>
</field>
</record>
</data>
</openerp>
-
=== added file 'account_consolidation/analysis_view.xml'
--- account_consolidation/analysis_view.xml 1970-01-01 00:00:00 +0000
+++ account_consolidation/analysis_view.xml 2014-04-17 13:57:59 +0000
@@ -0,0 +1,39 @@
+<openerp>
+ <data>
+
+ <menuitem id="menu_conso_entries"
+ name="Consolidation Entries"
+ parent="account.menu_finance"
+ sequence="5"
+ groups="account_consolidation.consolidation_manager,account_consolidation.consolidation_user"/>
+
+ <record id="action_account_moves_all_a" model="ir.actions.act_window">
+ <field name="context">{'journal_type':'general'}</field>
+ <field name="name">Journal Items</field>
+ <field name="domain">[('is_current_company', '=', True)]</field>
+ <field name="res_model">account.move.line</field>
+ <field name="view_id" ref="account.view_move_line_tree"/>
+ <field name="view_mode">tree_account_move_line_quickadd,form</field>
+ <field name="help" type="html">
+ <p class="oe_view_nocontent_create">
+ Select the period and the journal you want to fill.
+ </p><p>
+ This view can be used by accountants in order to quickly record
+ entries in OpenERP. If you want to record a supplier invoice,
+ start by recording the line of the expense account. OpenERP
+ will propose to you automatically the Tax related to this
+ account and the counterpart "Account Payable".
+ </p>
+ </field>
+ </record>
+
+ <menuitem
+ action="action_account_moves_all_a"
+ icon="STOCK_JUSTIFY_FILL"
+ id="menu_action_account_moves_all"
+ parent="menu_conso_entries"
+ sequence="1"
+ groups="account_consolidation.consolidation_manager,account_consolidation.consolidation_user"/>
+
+ </data>
+</openerp>
=== modified file 'account_consolidation/company.py'
--- account_consolidation/company.py 2011-08-19 07:16:03 +0000
+++ account_consolidation/company.py 2014-04-17 13:57:59 +0000
@@ -1,44 +1,41 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
-# All Right Reserved
-#
-# Author : Guewen Baconnier (Camptocamp)
-#
-# WARNING: This program as such is intended to be used by professional
-# programmers who take the whole responsability of assessing all potential
-# consequences resulting from its eventual inadequacies and bugs
-# End users who are looking for a ready-to-use solution with commercial
-# garantees and support are strongly adviced to contract a Free Software
-# Service Company
-#
-# This program is Free Software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-##############################################################################
-
-from osv import osv, fields
-
-
-class res_company(osv.osv):
+# -* coding: utf-8 -*-
+##############################################################################
+#
+# Author: Guewen Baconnier
+# Copyright 2011-2013 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import orm, fields
+
+
+class res_company(orm.Model):
_inherit = 'res.company'
- _columns = {
- 'consolidation_chart_account_id': fields.many2one('account.account',
- 'Chart of Accounts for Consolidation',
- domain=[('parent_id', '=', False)]),
- }
+ _columns = {'consolidation_chart_account_id': fields.many2one(
+ 'account.account',
+ 'Chart of Accounts for Consolidation',
+ domain=[('parent_id', '=', False)],
+ help=("Current company root account"
+ " to be used when consolidating")),
-res_company()
+ 'consolidation_diff_account_id': fields.many2one(
+ 'account.account',
+ 'Consolidation difference account',
+ domain=[('type', '=', 'other')],
+ help=("Conso. differences will be affected"
+ " to this account"))
+ }
=== modified file 'account_consolidation/company_view.xml'
--- account_consolidation/company_view.xml 2011-08-19 07:16:03 +0000
+++ account_consolidation/company_view.xml 2014-04-17 13:57:59 +0000
@@ -9,9 +9,10 @@
<field name="type">form</field>
<field name="arch" type="xml">
<page string="Configuration" position="inside">
- <group col="2" colspan="2">
+ <group col="2" colspan="2" groups="account_consolidation.consolidation_manager">
<separator string="Accounts Consolidation" colspan="2"/>
<field name="consolidation_chart_account_id" colspan="2"/>
+ <field name="consolidation_diff_account_id" colspan="2"/>
</group>
</page>
</field>
=== modified file 'account_consolidation/consolidation_menu.xml'
--- account_consolidation/consolidation_menu.xml 2011-08-12 15:39:07 +0000
+++ account_consolidation/consolidation_menu.xml 2014-04-17 13:57:59 +0000
@@ -5,18 +5,21 @@
<menuitem
name="Consolidation"
parent="account.menu_finance_periodical_processing"
+ groups="account_consolidation.consolidation_manager,account_consolidation.consolidation_user"
id="menu_consolidation"/>
<menuitem
name="Consolidation: Checks"
parent="menu_consolidation"
action="action_consolidation_checks"
+ groups="account_consolidation.consolidation_manager,account_consolidation.consolidation_user"
id="menu_consolidation_checks"/>
<menuitem
name="Consolidation: Consolidate"
parent="menu_consolidation"
action="action_consolidation_consolidate"
+ groups="account_consolidation.consolidation_manager,account_consolidation.consolidation_user"
id="menu_consolidation_consolidate"/>
</data>
=== added file 'account_consolidation/data.xml'
--- account_consolidation/data.xml 1970-01-01 00:00:00 +0000
+++ account_consolidation/data.xml 2014-04-17 13:57:59 +0000
@@ -0,0 +1,13 @@
+<openerp>
+ <data>
+ <record id="consolidation_manager" model="res.groups">
+ <field name="name">Consolidation manager</field>
+ <field name="category_id" ref="base.module_category_accounting_and_finance"/>
+ </record>
+
+ <record id="consolidation_user" model="res.groups">
+ <field name="name">Consolidation user</field>
+ <field name="category_id" ref="base.module_category_accounting_and_finance"/>
+ </record>
+ </data>
+</openerp>
=== modified file 'account_consolidation/demo/consolidation_demo.xml'
--- account_consolidation/demo/consolidation_demo.xml 2012-04-18 14:35:42 +0000
+++ account_consolidation/demo/consolidation_demo.xml 2014-04-17 13:57:59 +0000
@@ -183,7 +183,7 @@
<field name="company_id" ref="subsidiary_a"/>
</record>
- <record id="period_b_1" model="account.period">
+ <record id="period_b_1" model="account.period">
<field eval="'01/'+time.strftime('%Y')" name="code"/>
<field eval="'01/'+time.strftime('%Y')" name="name"/>
<field eval="True" name="special"/>
@@ -292,25 +292,23 @@
<field name="company_id" ref="subsidiary_b"/>
</record>
- <record id="account_journal_sale0" model="account.journal">
- <field name="code">SALE</field>
- <field name="name">SALE</field>
- <field name="view_id" ref="account.account_sp_journal_view"/>
- <field name="company_id" ref="account_consolidation.subsidiary_a"/>
- <field name="sequence_id" ref="account.sequence_sale_journal"/>
- <field eval="1" name="allow_date"/>
- <field name="type">sale</field>
- </record>
+ <record id="account_journal_sale0" model="account.journal">
+ <field name="code">SALE</field>
+ <field name="name">SALE</field>
+ <field name="company_id" ref="account_consolidation.subsidiary_a"/>
+ <field name="sequence_id" ref="account.sequence_sale_journal"/>
+ <field eval="1" name="allow_date"/>
+ <field name="type">sale</field>
+ </record>
- <record id="account_journal_sale1" model="account.journal">
- <field name="code">SALE</field>
- <field name="name">SALE</field>
- <field name="view_id" ref="account.account_sp_journal_view"/>
- <field name="company_id" ref="account_consolidation.subsidiary_b"/>
- <field name="sequence_id" ref="account.sequence_sale_journal"/>
- <field eval="1" name="allow_date"/>
- <field name="type">sale</field>
- </record>
+ <record id="account_journal_sale1" model="account.journal">
+ <field name="code">SALE</field>
+ <field name="name">SALE</field>
+ <field name="company_id" ref="account_consolidation.subsidiary_b"/>
+ <field name="sequence_id" ref="account.sequence_sale_journal"/>
+ <field eval="1" name="allow_date"/>
+ <field name="type">sale</field>
+ </record>
</data>
</openerp>
=== added file 'account_consolidation/i18n/account_consolidation.pot'
--- account_consolidation/i18n/account_consolidation.pot 1970-01-01 00:00:00 +0000
+++ account_consolidation/i18n/account_consolidation.pot 2014-04-17 13:57:59 +0000
@@ -0,0 +1,453 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * account_consolidation
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 7.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-10-21 09:06+0000\n"
+"PO-Revision-Date: 2013-10-21 09:06+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: account_consolidation
+#: help:account.account,consolidation_rate_type_id:0
+msgid "Currency rate type used on this account for the consolidation. Leave empty to use the rate type of the account type."
+msgstr ""
+
+#. module: account_consolidation
+#: help:account.consolidation.consolidate,from_period_id:0
+msgid "Select the same period in 'from' and 'to' if you want to proceed with a single period. Start Period is ignored for Year To Date accounts."
+msgstr ""
+
+#. module: account_consolidation
+#: model:ir.model,name:account_consolidation.model_account_consolidation_base
+#: model:ir.model,name:account_consolidation.model_account_consolidation_consolidate
+msgid "Common consolidation wizard. Intended to be inherited"
+msgstr ""
+
+#. module: account_consolidation
+#: field:account.account,consolidation_mode:0
+#: field:account.account.type,consolidation_mode:0
+msgid "Consolidation Mode"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_base.py:323
+#, python-format
+msgid "Invalid periods, please launch the \"Consolidation: Checks\" wizard"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_check.py:67
+#, python-format
+msgid "Invalid charts"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_consolidate.py:434
+#, python-format
+msgid "Consolidation %s"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_check.py:53
+#, python-format
+msgid "Chart of Accounts are OK."
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_consolidate.py:261
+#, python-format
+msgid "Consolidation line in %s mode"
+msgstr ""
+
+#. module: account_consolidation
+#: field:account.move,consol_company_id:0
+msgid "Consolidated from Company"
+msgstr ""
+
+#. module: account_consolidation
+#: view:account.move.line:0
+msgid "Period"
+msgstr ""
+
+#. module: account_consolidation
+#: help:account.consolidation.base,fiscalyear_id:0
+#: help:account.consolidation.check,fiscalyear_id:0
+#: help:account.consolidation.consolidate,fiscalyear_id:0
+msgid "The checks will be done on the periods of the selected fiscal year."
+msgstr ""
+
+#. module: account_consolidation
+#: model:ir.model,name:account_consolidation.model_account_account_type
+msgid "Account Type"
+msgstr ""
+
+#. module: account_consolidation
+#: field:account.consolidation.base,holding_chart_account_id:0
+#: field:account.consolidation.check,holding_chart_account_id:0
+#: field:account.consolidation.consolidate,holding_chart_account_id:0
+msgid "Chart of Accounts"
+msgstr ""
+
+#. module: account_consolidation
+#: help:account.consolidation.consolidate,to_period_id:0
+msgid "The consolidation will be done at the very last date of the selected period."
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_consolidate.py:185
+#, python-format
+msgid "Settings ERROR"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_check.py:59
+#: code:addons/account_consolidation/wizard/consolidation_check.py:85
+#, python-format
+msgid "%s :"
+msgstr ""
+
+#. module: account_consolidation
+#: field:account.consolidation.base,subsidiary_ids:0
+#: field:account.consolidation.check,subsidiary_ids:0
+#: field:account.consolidation.consolidate,subsidiary_ids:0
+msgid "Subsidiaries"
+msgstr ""
+
+#. module: account_consolidation
+#: view:account.account.type:0
+msgid "Description"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_base.py:328
+#, python-format
+msgid "Invalid charts, please launch the \"Consolidation: Checks\" wizard"
+msgstr ""
+
+#. module: account_consolidation
+#: view:account.consolidation.check:0
+msgid "Check Periods"
+msgstr ""
+
+#. module: account_consolidation
+#: selection:account.account,consolidation_mode:0
+#: selection:account.account.type,consolidation_mode:0
+msgid "Period Movements"
+msgstr ""
+
+#. module: account_consolidation
+#: field:account.consolidation.base,company_id:0
+#: field:account.consolidation.check,company_id:0
+#: field:account.consolidation.consolidate,company_id:0
+msgid "Company"
+msgstr ""
+
+#. module: account_consolidation
+#: view:account.consolidation.check:0
+#: model:ir.actions.act_window,name:account_consolidation.action_consolidation_checks
+#: model:ir.ui.menu,name:account_consolidation.menu_consolidation_checks
+msgid "Consolidation: Checks"
+msgstr ""
+
+#. module: account_consolidation
+#: view:account.account:0
+#: view:account.account.type:0
+#: model:ir.ui.menu,name:account_consolidation.menu_consolidation
+msgid "Consolidation"
+msgstr ""
+
+#. module: account_consolidation
+#: view:account.consolidation.check:0
+msgid "Check Charts"
+msgstr ""
+
+#. module: account_consolidation
+#: view:account.move.line:0
+#: field:account.move.line,consol_company_id:0
+msgid "Subsidaries"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_consolidate.py:186
+#, python-format
+msgid "Please set the \"Consolidation difference account\" in company %s"
+msgstr ""
+
+#. module: account_consolidation
+#: field:res.company,consolidation_chart_account_id:0
+msgid "Chart of Accounts for Consolidation"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_check.py:90
+#, python-format
+msgid "Invalid periods"
+msgstr ""
+
+#. module: account_consolidation
+#: field:res.company,consolidation_diff_account_id:0
+msgid "Consolidation difference account"
+msgstr ""
+
+#. module: account_consolidation
+#: view:res.company:0
+msgid "Accounts Consolidation"
+msgstr ""
+
+#. module: account_consolidation
+#: view:res.company:0
+msgid "Configuration"
+msgstr ""
+
+#. module: account_consolidation
+#: field:account.consolidation.consolidate,target_move:0
+msgid "Target Moves"
+msgstr ""
+
+#. module: account_consolidation
+#: field:account.consolidation.consolidate,from_period_id:0
+msgid "Start Period"
+msgstr ""
+
+#. module: account_consolidation
+#: model:res.groups,name:account_consolidation.consolidation_manager
+msgid "Consolidation manager"
+msgstr ""
+
+#. module: account_consolidation
+#: help:res.company,consolidation_chart_account_id:0
+msgid "Current company root account to be used when consolidating"
+msgstr ""
+
+#. module: account_consolidation
+#: model:ir.model,name:account_consolidation.model_account_account
+msgid "Account"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_base.py:297
+#, python-format
+msgid "No chart of accounts for company %s"
+msgstr ""
+
+#. module: account_consolidation
+#: view:account.consolidation.check:0
+msgid "Prepare your consolidation and make sure that your consolidation will be correct by proceeding with the checks. The 'Check Periods' verify if fiscal year exists for each subsidiary, and if the periods have the same beginning and ending dates. The 'Check Charts' verify if subsidiary accounts are missing in the Holding's Chart of Accounts."
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_base.py:176
+#, python-format
+msgid "Period from %s to %s not found in holding company %s"
+msgstr ""
+
+#. module: account_consolidation
+#: selection:account.consolidation.consolidate,target_move:0
+msgid "All Posted Entries"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_base.py:162
+#, python-format
+msgid "Holding company has less periods than the subsidiary company %s!"
+msgstr ""
+
+#. module: account_consolidation
+#: model:ir.model,name:account_consolidation.model_res_company
+msgid "Companies"
+msgstr ""
+
+#. module: account_consolidation
+#: field:account.consolidation.consolidate,to_period_id:0
+msgid "End Period"
+msgstr ""
+
+#. module: account_consolidation
+#: model:ir.actions.act_window,help:account_consolidation.action_account_moves_all_a
+msgid "<p class=\"oe_view_nocontent_create\">\n"
+" Select the period and the journal you want to fill.\n"
+" </p><p>\n"
+" This view can be used by accountants in order to quickly record\n"
+" entries in OpenERP. If you want to record a supplier invoice,\n"
+" start by recording the line of the expense account. OpenERP\n"
+" will propose to you automatically the Tax related to this\n"
+" account and the counterpart \"Account Payable\".\n"
+" </p>\n"
+" "
+msgstr ""
+
+#. module: account_consolidation
+#: field:account.consolidation.base,fiscalyear_id:0
+#: field:account.consolidation.check,fiscalyear_id:0
+#: field:account.consolidation.consolidate,fiscalyear_id:0
+msgid "Fiscal Year"
+msgstr ""
+
+#. module: account_consolidation
+#: help:account.account,consolidation_mode:0
+#: help:account.account.type,consolidation_mode:0
+msgid "This must be set on the holding company accounts only"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_check.py:62
+#, python-format
+msgid "Account with code %s does not exist on the Holding company."
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_base.py:296
+#: code:addons/account_consolidation/wizard/consolidation_base.py:322
+#: code:addons/account_consolidation/wizard/consolidation_base.py:327
+#, python-format
+msgid "Error"
+msgstr ""
+
+#. module: account_consolidation
+#: view:account.consolidation.check:0
+#: view:account.consolidation.consolidate:0
+msgid "Subsidiaries to Consolidate"
+msgstr ""
+
+#. module: account_consolidation
+#: selection:account.account,consolidation_mode:0
+#: selection:account.account.type,consolidation_mode:0
+msgid "YTD"
+msgstr ""
+
+#. module: account_consolidation
+#: view:account.consolidation.consolidate:0
+msgid "Run the consolidation for the selected periods and subsidiaries."
+msgstr ""
+
+#. module: account_consolidation
+#: field:account.move.line,is_current_company:0
+msgid "Current company"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_consolidate.py:207
+#, python-format
+msgid "Consolidation difference in mode %s"
+msgstr ""
+
+#. module: account_consolidation
+#: view:account.consolidation.consolidate:0
+msgid "Consolidate"
+msgstr ""
+
+#. module: account_consolidation
+#: constraint:account.consolidation.consolidate:0
+msgid "Start Period and End Period must be of the same Fiscal Year !"
+msgstr ""
+
+#. module: account_consolidation
+#: view:account.consolidation.consolidate:0
+#: model:ir.actions.act_window,name:account_consolidation.action_consolidation_consolidate
+#: model:ir.ui.menu,name:account_consolidation.menu_consolidation_consolidate
+msgid "Consolidation: Consolidate"
+msgstr ""
+
+#. module: account_consolidation
+#: model:ir.model,name:account_consolidation.model_account_move
+msgid "Account Entry"
+msgstr ""
+
+#. module: account_consolidation
+#: model:ir.ui.menu,name:account_consolidation.menu_conso_entries
+msgid "Consolidation Entries"
+msgstr ""
+
+#. module: account_consolidation
+#: help:res.company,consolidation_diff_account_id:0
+msgid "Conso. differences will be affected to this account"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_base.py:141
+#, python-format
+msgid "The fiscal year of the subsidiary company %s does not exists from %s to %s"
+msgstr ""
+
+#. module: account_consolidation
+#: model:ir.model,name:account_consolidation.model_account_consolidation_check
+msgid "Consolidation Checks. Model used for views"
+msgstr ""
+
+#. module: account_consolidation
+#: view:account.consolidation.check:0
+#: view:account.consolidation.consolidate:0
+msgid "or"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_consolidate.py:504
+#, python-format
+msgid "Consolidated Entries"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_check.py:52
+#: code:addons/account_consolidation/wizard/consolidation_check.py:78
+#, python-format
+msgid "Validation"
+msgstr ""
+
+#. module: account_consolidation
+#: code:addons/account_consolidation/wizard/consolidation_check.py:78
+#, python-format
+msgid "Periods are OK."
+msgstr ""
+
+#. module: account_consolidation
+#: model:res.groups,name:account_consolidation.consolidation_user
+msgid "Consolidation user"
+msgstr ""
+
+#. module: account_consolidation
+#: help:account.account.type,consolidation_rate_type_id:0
+msgid "Currency rate type used on this account type for the consolidation. Leave empty to use the 'spot' rate type."
+msgstr ""
+
+#. module: account_consolidation
+#: view:account.consolidation.consolidate:0
+msgid "Holding Chart of Accounts"
+msgstr ""
+
+#. module: account_consolidation
+#: view:account.consolidation.check:0
+#: view:account.consolidation.consolidate:0
+msgid "Cancel"
+msgstr ""
+
+#. module: account_consolidation
+#: field:account.account,consolidation_rate_type_id:0
+#: field:account.account.type,consolidation_rate_type_id:0
+msgid "Consolidation Currency Rate Type"
+msgstr ""
+
+#. module: account_consolidation
+#: field:account.consolidation.consolidate,journal_id:0
+msgid "Journal"
+msgstr ""
+
+#. module: account_consolidation
+#: selection:account.consolidation.consolidate,target_move:0
+msgid "All Entries"
+msgstr ""
+
+#. module: account_consolidation
+#: model:ir.actions.act_window,name:account_consolidation.action_account_moves_all_a
+#: model:ir.model,name:account_consolidation.model_account_move_line
+#: model:ir.ui.menu,name:account_consolidation.menu_action_account_moves_all
+msgid "Journal Items"
+msgstr ""
+
=== modified file 'account_consolidation/test/consolidation_checks.yml'
--- account_consolidation/test/consolidation_checks.yml 2011-08-19 13:08:01 +0000
+++ account_consolidation/test/consolidation_checks.yml 2014-04-17 13:57:59 +0000
@@ -42,7 +42,8 @@
raise
-
- In order to test the consolidation checks on misconfigured periods, I use the wizard on FY2012
+ In order to test the consolidation checks on misconfigured periods, I use the wizard on the next year
+ which is misconfigured
-
!record {model: account.consolidation.check, id: conso_check_period_1}:
fiscalyear_id: account_fiscalyear_fy0
@@ -79,8 +80,8 @@
name: Virtual Account Spare
parent_id: account_consolidation.virtual_chart_subsidiary_a
type: consolidation
- user_type: account.account_type_expense
-
+ user_type: account.data_account_type_expense
+
-
In order to test the consolidation checks on misconfigured charts, I use the wizard
-
=== modified file 'account_consolidation/test/test_data.yml'
--- account_consolidation/test/test_data.yml 2011-08-19 13:08:01 +0000
+++ account_consolidation/test/test_data.yml 2014-04-17 13:57:59 +0000
@@ -3,14 +3,14 @@
-
!record {model: account.move, id: account_move_0}:
company_id: subsidiary_b
- date: '2011-01-02'
+ date: !eval "'%s-01-02' % datetime.now().year"
journal_id: account_journal_sale1
line_id:
- company_id: subsidiary_b
account_id: a_sale_b
amount_currency: 0.0
credit: 0.0
- date: '2011-01-01'
+ date: !eval "'%s-01-02' % datetime.now().year"
debit: 1240.0
journal_id: account_journal_sale1
name: Entry 0
@@ -22,7 +22,7 @@
account_id: cog_b
amount_currency: 0.0
credit: 1240.0
- date: '2011-01-01'
+ date: !eval "'%s-01-02' % datetime.now().year"
debit: 0.0
journal_id: account_journal_sale1
name: Entry 0
@@ -40,14 +40,14 @@
-
!record {model: account.move, id: account_move_1}:
company_id: account_consolidation.subsidiary_a
- date: '2011-01-20'
+ date: !eval "'%s-01-20' % datetime.now().year"
journal_id: account_journal_sale0
line_id:
- account_id: account_consolidation.a_sale_a
amount_currency: 0.0
company_id: account_consolidation.subsidiary_a
credit: 0.0
- date: '2011-01-20'
+ date: !eval "'%s-01-20' % datetime.now().year"
debit: 40.0
journal_id: account_journal_sale0
name: Entry 1
@@ -59,7 +59,7 @@
amount_currency: 0.0
company_id: account_consolidation.subsidiary_a
credit: 40.0
- date: '2011-01-20'
+ date: !eval "'%s-01-20' % datetime.now().year"
debit: 0.0
journal_id: account_journal_sale0
name: Entry 1
@@ -77,14 +77,14 @@
-
!record {model: account.move, id: account_move_2}:
company_id: account_consolidation.subsidiary_a
- date: '2011-02-23'
+ date: !eval "'%s-02-23' % datetime.now().year"
journal_id: account_journal_sale0
line_id:
- account_id: account_consolidation.a_sale_a
amount_currency: 0.0
company_id: account_consolidation.subsidiary_a
credit: 0.0
- date: '2011-02-01'
+ date: !eval "'%s-02-23' % datetime.now().year"
debit: 200.0
journal_id: account_journal_sale0
name: Entry 2
@@ -96,7 +96,7 @@
amount_currency: 0.0
company_id: account_consolidation.subsidiary_a
credit: 200.0
- date: '2011-02-01'
+ date: !eval "'%s-02-23' % datetime.now().year"
debit: 0.0
journal_id: account_journal_sale0
name: Entry 2
@@ -114,14 +114,14 @@
-
!record {model: account.move, id: account_move_3}:
company_id: account_consolidation.subsidiary_a
- date: '2011-01-15'
+ date: !eval "'%s-01-15' % datetime.now().year"
journal_id: account_journal_sale0
line_id:
- account_id: account_consolidation.cog_a
amount_currency: 0.0
company_id: account_consolidation.subsidiary_a
credit: 300.0
- date: '2011-01-01'
+ date: !eval "'%s-01-15' % datetime.now().year"
debit: 0.0
journal_id: account_journal_sale0
name: Entry 3
@@ -133,7 +133,7 @@
amount_currency: 0.0
company_id: account_consolidation.subsidiary_a
credit: 0.0
- date: '2011-01-01'
+ date: !eval "'%s-01-15' % datetime.now().year"
debit: 300.0
journal_id: account_journal_sale0
name: Entry 3
@@ -150,94 +150,94 @@
Creating a account.fiscalyear record with a missing period for january
-
!record {model: account.fiscalyear, id: account_fiscalyear_fy0}:
- code: FY2012
+ code: !eval "'FY%s' % (datetime.now().year + 1)"
company_id: base.main_company
- date_start: '2012-01-01'
- date_stop: '2012-12-31'
- name: FY2012
+ date_start: !eval "'%s-01-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-12-31' % (datetime.now().year + 1)"
+ name: !eval "'FY%s' % (datetime.now().year + 1)"
period_ids:
- - code: 00/2012
+ - code: !eval "'00/%s' % (datetime.now().year + 1)"
company_id: base.main_company
- date_start: '2012-01-01'
- date_stop: '2012-01-01'
+ date_start: !eval "'%s-01-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-01-01' % (datetime.now().year + 1)"
name: Opening Period
special: true
- - code: 01/2012
- company_id: base.main_company
- date_start: '2012-01-01'
- date_stop: '2012-01-31'
- name: 01/2012
- - code: 02/2012
- company_id: base.main_company
- date_start: '2012-02-01'
- date_stop: '2012-02-29'
- name: 02/2012
- - code: 03/2012
- company_id: base.main_company
- date_start: '2012-03-01'
- date_stop: '2012-03-31'
- name: 03/2012
- - code: 04/2012
- company_id: base.main_company
- date_start: '2012-04-01'
- date_stop: '2012-04-30'
- name: 04/2012
- - code: 05/2012
- company_id: base.main_company
- date_start: '2012-05-01'
- date_stop: '2012-05-31'
- name: 05/2012
- - code: 06/2012
- company_id: base.main_company
- date_start: '2012-06-01'
- date_stop: '2012-06-30'
- name: 06/2012
- - code: 07/2012
- company_id: base.main_company
- date_start: '2012-07-01'
- date_stop: '2012-07-31'
- name: 07/2012
- - code: 08/2012
- company_id: base.main_company
- date_start: '2012-08-01'
- date_stop: '2012-08-31'
- name: 08/2012
- - code: 09/2012
- company_id: base.main_company
- date_start: '2012-09-01'
- date_stop: '2012-09-30'
- name: 09/2012
- - code: 10/2012
- company_id: base.main_company
- date_start: '2012-10-01'
- date_stop: '2012-10-31'
- name: 10/2012
- - code: 11/2012
- company_id: base.main_company
- date_start: '2012-11-01'
- date_stop: '2012-11-30'
- name: 11/2012
- - code: 12/2012
- company_id: base.main_company
- date_start: '2012-12-01'
- date_stop: '2012-12-31'
- name: 12/2012
+ - code: !eval "'01/%s' % (datetime.now().year + 1)"
+ company_id: base.main_company
+ date_start: !eval "'%s-01-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-01-31' % (datetime.now().year + 1)"
+ name: !eval "'01/%s' % (datetime.now().year + 1)"
+ - code: !eval "'02/%s' % (datetime.now().year + 1)"
+ company_id: base.main_company
+ date_start: !eval "'%s-02-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-02-%s' % ((datetime.now().year + 1), (datetime((datetime.now().year + 1), 3, 1) - timedelta(days=1)).day)"
+ name: !eval "'02/%s' % (datetime.now().year + 1)"
+ - code: !eval "'03/%s' % (datetime.now().year + 1)"
+ company_id: base.main_company
+ date_start: !eval "'%s-03-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-03-31' % (datetime.now().year + 1)"
+ name: !eval "'03/%s' % (datetime.now().year + 1)"
+ - code: !eval "'04/%s' % (datetime.now().year + 1)"
+ company_id: base.main_company
+ date_start: !eval "'%s-04-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-04-30' % (datetime.now().year + 1)"
+ name: !eval "'04/%s' % (datetime.now().year + 1)"
+ - code: !eval "'05/%s' % (datetime.now().year + 1)"
+ company_id: base.main_company
+ date_start: !eval "'%s-05-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-05-31' % (datetime.now().year + 1)"
+ name: !eval "'05/%s' % (datetime.now().year + 1)"
+ - code: !eval "'06/%s' % (datetime.now().year + 1)"
+ company_id: base.main_company
+ date_start: !eval "'%s-06-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-06-30' % (datetime.now().year + 1)"
+ name: !eval "'06/%s' % (datetime.now().year + 1)"
+ - code: !eval "'07/%s' % (datetime.now().year + 1)"
+ company_id: base.main_company
+ date_start: !eval "'%s-07-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-07-31' % (datetime.now().year + 1)"
+ name: !eval "'07/%s' % (datetime.now().year + 1)"
+ - code: !eval "'08/%s' % (datetime.now().year + 1)"
+ company_id: base.main_company
+ date_start: !eval "'%s-08-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-08-31' % (datetime.now().year + 1)"
+ name: !eval "'08/%s' % (datetime.now().year + 1)"
+ - code: !eval "'09/%s' % (datetime.now().year + 1)"
+ company_id: base.main_company
+ date_start: !eval "'%s-09-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-09-30' % (datetime.now().year + 1)"
+ name: !eval "'09/%s' % (datetime.now().year + 1)"
+ - code: !eval "'10/%s' % (datetime.now().year + 1)"
+ company_id: base.main_company
+ date_start: !eval "'%s-10-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-10-31' % (datetime.now().year + 1)"
+ name: !eval "'10/%s' % (datetime.now().year + 1)"
+ - code: !eval "'11/%s' % (datetime.now().year + 1)"
+ company_id: base.main_company
+ date_start: !eval "'%s-11-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-11-30' % (datetime.now().year + 1)"
+ name: !eval "'11/%s' % (datetime.now().year + 1)"
+ - code: !eval "'12/%s' % (datetime.now().year + 1)"
+ company_id: base.main_company
+ date_start: !eval "'%s-12-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-12-31' % (datetime.now().year + 1)"
+ name: !eval "'12/%s' % (datetime.now().year + 1)"
-
Creating a account.fiscalyear record with a period in december but with different dates than the holding
-
!record {model: account.fiscalyear, id: account_fiscalyear_fy1}:
- code: FY2012
+ code: !eval "'FY%s' % (datetime.now().year + 1)"
company_id: account_consolidation.subsidiary_b
- date_start: '2012-01-01'
- date_stop: '2012-12-31'
- name: FY2012
+ date_start: !eval "'%s-01-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-12-31' % (datetime.now().year + 1)"
+ name: !eval "'FY%s' % (datetime.now().year + 1)"
period_ids:
- code: diff_dates
company_id: account_consolidation.subsidiary_b
- date_start: '2012-12-15'
- date_stop: '2012-12-31'
+ date_start: !eval "'%s-12-15' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-12-31' % (datetime.now().year + 1)"
name: diff_dates
@@ -245,70 +245,70 @@
Creating a account.fiscalyear record on subsidiary with a period for january (missing on holding)
-
!record {model: account.fiscalyear, id: account_fiscalyear_fy2}:
- code: FY2012
+ code: !eval "'FY%s' % (datetime.now().year + 1)"
company_id: account_consolidation.subsidiary_a
- date_start: '2012-01-01'
- date_stop: '2012-12-31'
- name: FY2012
+ date_start: !eval "'%s-01-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-12-31' % (datetime.now().year + 1)"
+ name: !eval "'FY%s' % (datetime.now().year + 1)"
period_ids:
- - code: 00/2012
+ - code: !eval "'00/%s' % (datetime.now().year + 1)"
company_id: account_consolidation.subsidiary_a
- date_start: '2012-01-01'
- date_stop: '2012-01-01'
+ date_start: !eval "'%s-01-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-01-01' % (datetime.now().year + 1)"
name: Opening Period
special: true
- - code: 01/2012
- company_id: account_consolidation.subsidiary_a
- date_start: '2012-01-01'
- date_stop: '2012-01-31'
- name: 01/2012
- - code: 02/2012
- company_id: account_consolidation.subsidiary_a
- date_start: '2012-02-01'
- date_stop: '2012-02-29'
- name: 02/2012
- - code: 03/2012
- company_id: account_consolidation.subsidiary_a
- date_start: '2012-03-01'
- date_stop: '2012-03-31'
- name: 03/2012
- - code: 04/2012
- company_id: account_consolidation.subsidiary_a
- date_start: '2012-04-01'
- date_stop: '2012-04-30'
- name: 04/2012
- - code: 05/2012
- company_id: account_consolidation.subsidiary_a
- date_start: '2012-05-01'
- date_stop: '2012-05-31'
- name: 05/2012
- - code: 06/2012
- company_id: account_consolidation.subsidiary_a
- date_start: '2012-06-01'
- date_stop: '2012-06-30'
- name: 06/2012
- - code: 08/2012
- company_id: account_consolidation.subsidiary_a
- date_start: '2012-08-01'
- date_stop: '2012-08-31'
- name: 08/2012
- - code: 09/2012
- company_id: account_consolidation.subsidiary_a
- date_start: '2012-09-01'
- date_stop: '2012-09-30'
- name: 09/2012
- - code: 10/2012
- company_id: account_consolidation.subsidiary_a
- date_start: '2012-10-01'
- date_stop: '2012-10-31'
- name: 10/2012
- - code: 11/2012
- company_id: account_consolidation.subsidiary_a
- date_start: '2012-11-01'
- date_stop: '2012-11-30'
- name: 11/2012
- - code: 12/2012
- company_id: account_consolidation.subsidiary_a
- date_start: '2012-12-01'
- date_stop: '2012-12-31'
- name: 12/2012
+ - code: !eval "'01/%s' % (datetime.now().year + 1)"
+ company_id: account_consolidation.subsidiary_a
+ date_start: !eval "'%s-01-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-01-31' % (datetime.now().year + 1)"
+ name: !eval "'01/%s' % (datetime.now().year + 1)"
+ - code: !eval "'02/%s' % (datetime.now().year + 1)"
+ company_id: account_consolidation.subsidiary_a
+ date_start: !eval "'%s-02-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-02-%s' % ((datetime.now().year + 1), (datetime((datetime.now().year + 1), 3, 1) - timedelta(days=1)).day)"
+ name: !eval "'02/%s' % (datetime.now().year + 1)"
+ - code: !eval "'03/%s' % (datetime.now().year + 1)"
+ company_id: account_consolidation.subsidiary_a
+ date_start: !eval "'%s-03-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-03-31' % (datetime.now().year + 1)"
+ name: !eval "'03/%s' % (datetime.now().year + 1)"
+ - code: !eval "'04/%s' % (datetime.now().year + 1)"
+ company_id: account_consolidation.subsidiary_a
+ date_start: !eval "'%s-04-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-04-30' % (datetime.now().year + 1)"
+ name: !eval "'04/%s' % (datetime.now().year + 1)"
+ - code: !eval "'05/%s' % (datetime.now().year + 1)"
+ company_id: account_consolidation.subsidiary_a
+ date_start: !eval "'%s-05-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-05-31' % (datetime.now().year + 1)"
+ name: !eval "'05/%s' % (datetime.now().year + 1)"
+ - code: !eval "'06/%s' % (datetime.now().year + 1)"
+ company_id: account_consolidation.subsidiary_a
+ date_start: !eval "'%s-06-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-06-30' % (datetime.now().year + 1)"
+ name: !eval "'06/%s' % (datetime.now().year + 1)"
+ - code: !eval "'08/%s' % (datetime.now().year + 1)"
+ company_id: account_consolidation.subsidiary_a
+ date_start: !eval "'%s-08-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-08-31' % (datetime.now().year + 1)"
+ name: !eval "'08/%s' % (datetime.now().year + 1)"
+ - code: !eval "'09/%s' % (datetime.now().year + 1)"
+ company_id: account_consolidation.subsidiary_a
+ date_start: !eval "'%s-09-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-09-30' % (datetime.now().year + 1)"
+ name: !eval "'09/%s' % (datetime.now().year + 1)"
+ - code: !eval "'10/%s' % (datetime.now().year + 1)"
+ company_id: account_consolidation.subsidiary_a
+ date_start: !eval "'%s-10-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-10-31' % (datetime.now().year + 1)"
+ name: !eval "'10/%s' % (datetime.now().year + 1)"
+ - code: !eval "'11/%s' % (datetime.now().year + 1)"
+ company_id: account_consolidation.subsidiary_a
+ date_start: !eval "'%s-11-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-11-30' % (datetime.now().year + 1)"
+ name: !eval "'11/%s' % (datetime.now().year + 1)"
+ - code: !eval "'12/%s' % (datetime.now().year + 1)"
+ company_id: account_consolidation.subsidiary_a
+ date_start: !eval "'%s-12-01' % (datetime.now().year + 1)"
+ date_stop: !eval "'%s-12-31' % (datetime.now().year + 1)"
+ name: !eval "'12/%s' % (datetime.now().year + 1)"
=== modified file 'account_consolidation/wizard/consolidation_base.py'
--- account_consolidation/wizard/consolidation_base.py 2012-04-18 14:35:42 +0000
+++ account_consolidation/wizard/consolidation_base.py 2014-04-17 13:57:59 +0000
@@ -1,75 +1,76 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
-#
-# Author : Guewen Baconnier (Camptocamp)
-#
-# WARNING: This program as such is intended to be used by professional
-# programmers who take the whole responsability of assessing all potential
-# consequences resulting from its eventual inadequacies and bugs
-# End users who are looking for a ready-to-use solution with commercial
-# garantees and support are strongly adviced to contract a Free Software
-# Service Company
-#
-# This program is Free Software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Author: Guewen Baconnier
+# Copyright 2011-2013 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
-from osv import osv, fields
-from tools.translate import _
-
-
-class account_consolidation_base(osv.osv_memory):
+from openerp.osv import osv, orm, fields
+from openerp.tools.translate import _
+
+
+class account_consolidation_base(orm.AbstractModel):
_name = 'account.consolidation.base'
_description = 'Common consolidation wizard. Intended to be inherited'
def _default_company(self, cr, uid, context=None):
- user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
- if user.company_id:
- return user.company_id.id
- return self.pool.get('res.company').search(cr, uid, [('parent_id', '=', False)])[0]
+ comp_obj = self.pool['res.company']
+ return comp_obj._company_default_get(cr, uid)
+
+ def _default_chart(self, cr, uid, context=None):
+ comp_obj = self.pool['res.company']
+ comp_id = comp_obj._company_default_get(cr, uid)
+ company = comp_obj.browse(cr, uid, comp_id)
+ return company.consolidation_chart_account_id.id
_columns = {
- 'fiscalyear_id': fields.many2one('account.fiscalyear', 'Fiscal Year', required=True,
- help="The checks will be done on the periods of the selected fiscal year."),
- 'company_id': fields.many2one('res.company', 'Company', required=True),
- 'holding_chart_account_id': fields.many2one('account.account',
- 'Chart of Accounts',
- required=True,
- domain=[('parent_id', '=', False)]),
- 'subsidiary_ids': fields.many2many('res.company', 'account_conso_comp_rel', 'conso_id', 'company_id',
- 'Subsidiaries', required=True)
+ 'fiscalyear_id': fields.many2one(
+ 'account.fiscalyear',
+ 'Fiscal Year',
+ required=True,
+ help="The checks will be done on the periods of "
+ "the selected fiscal year."),
+ 'company_id': fields.many2one(
+ 'res.company', 'Company', required=True),
+ 'holding_chart_account_id': fields.many2one(
+ 'account.account',
+ 'Chart of Accounts',
+ required=True,
+ domain=[('parent_id', '=', False)]),
+ 'subsidiary_ids': fields.many2many(
+ 'res.company',
+ 'account_conso_comp_rel',
+ 'conso_id',
+ 'company_id',
+ 'Subsidiaries',
+ required=True)
}
- _defaults = {
- 'company_id': _default_company,
- }
+ _defaults = {'company_id': _default_company,
+ 'holding_chart_account_id': _default_chart,
+ }
def on_change_company_id(self, cr, uid, ids, company_id, context=None):
"""
On change of the company, set the chart of account and the subsidiaries
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param company_id: ID of the selected company
- @param context: A standard dictionary for contextual values
+ :param company_id: ID of the selected company
- @return: dict of values to change
+ :return: dict of values to change
"""
company_obj = self.pool.get('res.company')
@@ -82,21 +83,27 @@
return {'value': result}
- def check_subsidiary_periods(self, cr, uid, ids, holding_company_id, subs_company_id, fyear_id, context=None):
- """
- Check Subsidiary company periods vs Holding company periods and returns a list of errors
- All the periods defined within the group must be the same (same beginning and ending dates)
-
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param holding_company_id: ID of the holding company
- @param subs_company_id: ID of the subsidiary company to check
- @param fyear_id: ID of the fiscal years to compare
- @param context: A standard dictionary for contextual values
-
- @return: dict of list with errors for each company {company_id: ['error 1', 'error2']}
+ def check_subsidiary_periods(self, cr, uid, ids, holding_company_id,
+ subs_company_id, fyear_id, context=None):
+ """ Check Subsidiary company periods vs Holding company periods and
+ returns a list of errors
+
+ The periods checked are the periods within the fiscal year of the
+ holding, and the periods of the subsidiary company in the same range of
+ time.
+
+ The fiscal year of the subsidiary is deduced from the start/stop date
+ of the holding's fiscal year.
+
+ All the periods defined within the group must have the same beginning
+ and ending dates to be valid.
+
+ :param holding_company_id: ID of the holding company
+ :param subs_company_id: ID of the subsidiary company to check
+ :param fyear_id: ID of the fiscal year of the holding.
+
+ :return: dict of list with errors for each company
+ {company_id: ['error 1', 'error2']}
"""
company_obj = self.pool.get('res.company')
period_obj = self.pool.get('account.period')
@@ -108,48 +115,69 @@
errors = []
# get holding fiscal year and periods
- holding = company_obj.browse(cr, uid, holding_company_id, context=context)
- subsidiary = company_obj.browse(cr, uid, subs_company_id, context=context)
+ holding = company_obj.browse(
+ cr, uid, holding_company_id, context=context)
+ subsidiary = company_obj.browse(
+ cr, uid, subs_company_id, context=context)
- holding_periods_ids = period_obj.search(cr, uid,
+ holding_periods_ids = period_obj.search(
+ cr, uid,
[('company_id', '=', holding.id),
('fiscalyear_id', '=', holding_fiscal_year.id)],
context=context)
- holding_periods = period_obj.browse(cr, uid, holding_periods_ids, context=context)
+ holding_periods = period_obj.browse(
+ cr, uid, holding_periods_ids, context=context)
# get subsidiary fiscal year and periods
- subsidiary_fiscal_year = fy_obj.search(cr, uid,
+ subsidiary_fiscal_year = fy_obj.search(
+ cr, uid,
[('company_id', '=', subsidiary.id),
('date_start', '=', holding_fiscal_year.date_start),
('date_stop', '=', holding_fiscal_year.date_stop),
- ])
+ ],
+ context=context)
if not subsidiary_fiscal_year:
- errors.append(_('The fiscal year of the subsidiary company %s does not exists from %s to %s')
- % (subsidiary.name, holding_fiscal_year.date_start, holding_fiscal_year.date_stop))
+ errors.append(
+ _('The fiscal year of the subsidiary company %s '
+ 'does not exists from %s to %s') %
+ (subsidiary.name,
+ holding_fiscal_year.date_start,
+ holding_fiscal_year.date_stop))
else:
- subsidiary_period_ids = period_obj.search(cr, uid,
+ subsidiary_period_ids = period_obj.search(
+ cr, uid,
[('company_id', '=', subsidiary.id),
- ('fiscalyear_id', '=', subsidiary_fiscal_year[0])], # 0 because there can be only 1 fiscal year on the same dates as the holding
+ # 0 because there can be only 1 fiscal year
+ # on the same dates than the holding
+ ('fiscalyear_id', '=', subsidiary_fiscal_year[0])],
context=context)
- subsidiary_periods = period_obj.browse(cr, uid, subsidiary_period_ids, context=context)
+ subsidiary_periods = period_obj.browse(
+ cr, uid, subsidiary_period_ids, context=context)
- # a holding fiscal year may have more periods than a subsidiary (a subsidiary created at the middle of the year for example)
+ # a holding fiscal year may have more periods than a subsidiary
+ # (a subsidiary created at the middle of the year for example)
# but the reverse situation is not allowed
if len(holding_periods) < len(subsidiary_periods):
- errors.append(_('Holding company has less periods than the subsidiary company %s!') % (subsidiary.name,))
+ errors.append(
+ _('Holding company has less periods than the '
+ 'subsidiary company %s!') % subsidiary.name)
- # check subsidiary periods dates vs holding periods for each period of the subsidiary
+ # check subsidiary periods dates vs holding periods
+ # for each period of the subsidiary
for subsidiary_period in subsidiary_periods:
period_exists = False
for holding_period in holding_periods:
- if subsidiary_period.date_start == holding_period.date_start \
- and subsidiary_period.date_stop == holding_period.date_stop:
- period_exists = True
- break
+ if (subsidiary_period.date_start == holding_period.date_start and
+ subsidiary_period.date_stop == holding_period.date_stop):
+ period_exists = True
+ break
if not period_exists:
- errors.append(_('Period from %s to %s not found in holding company %s')
- % (subsidiary_period.date_start, subsidiary_period.date_stop, holding.name))
-
+ errors.append(
+ _('Period from %s to %s not found '
+ 'in holding company %s') %
+ (subsidiary_period.date_start,
+ subsidiary_period.date_stop,
+ holding.name))
return errors
def check_all_periods(self, cr, uid, ids, context=None):
@@ -157,24 +185,24 @@
Call the period check on each period of all subsidiaries
Returns the errors by subsidiary
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param context: A standard dictionary for contextual values
-
- @return: dict of list with errors for each company {company_id: ['error 1', 'error2']}
+ :return: dict of list with errors for each company
+ {company_id: ['error 1', 'error2']}
"""
+ if isinstance(ids, (int, long)):
+ ids = [ids]
+ assert len(ids) == 1, "only 1 id expected"
+
form = self.browse(cr, uid, ids[0], context=context)
errors_by_company = {}
for subsidiary in form.subsidiary_ids:
- errors = \
- self.check_subsidiary_periods(cr, uid, ids,
- form.company_id.id,
- subsidiary.id,
- form.fiscalyear_id.id,
- context=context)
+ errors = self.check_subsidiary_periods(
+ cr, uid,
+ ids,
+ form.company_id.id,
+ subsidiary.id,
+ form.fiscalyear_id.id,
+ context=context)
if errors:
errors_by_company[subsidiary.id] = errors
@@ -182,24 +210,23 @@
def _chart_accounts_data(self, cr, uid, ids, chart_account_id, context=None):
"""
- Returns the list of accounts to use for the consolidation for the holding
- or the subsidiaries. Keys of the returned dict are the account codes and
- if the context is holding_coa, dict values are the browse instances of the accounts
-
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @chart_account_id: ID of the "Chart" Account for which we want the account codes
- @param context: A standard dictionary for contextual values
-
- @return: dict with {account codes: browse instances}
+ Returns the list of accounts to use for the consolidation
+ for the holding or the subsidiaries.
+ Keys of the returned dict are the account codes and
+ if the context is holding_coa,
+ dict values are the browse instances of the accounts
+
+ :chart_account_id: ID of the Chart of Account for which
+ we want the account codes
+
+ :return: dict with {account codes: browse instances}
"""
- context = context or {}
+ if context is None:
+ context = {}
account_obj = self.pool.get('account.account')
res = {}
- account_ids = account_obj.\
- _get_children_and_consol(cr, uid, chart_account_id, context=context)
+ account_ids = account_obj._get_children_and_consol(
+ cr, uid, chart_account_id, context=context)
# do not consolidate chart root
account_ids.remove(chart_account_id)
@@ -216,33 +243,37 @@
continue
res[account.code] = {}
- # we'll need the browse object during the "consolidate wizard" for the holding
- res[account.code] = holding and account or True
+ # we'll need the browse object during the
+ # "consolidate wizard" for the holding
+ res[account.code] = account if holding else True
return res
- def check_subsidiary_chart(self, cr, uid, ids, holding_chart_account_id, subsidiary_chart_account_id, context=None):
+ def check_subsidiary_chart(self, cr, uid, ids, holding_chart_account_id,
+ subsidiary_chart_account_id, context=None):
"""
- Check a Holding Chart of Accounts vs a Subsidiary Virtual Chart of Accounts
+ Check a Holding Chart of Accounts vs a Subsidiary Virtual
+ Chart of Accounts
All the accounts of the Virtual CoA must exist in the Holding CoA.
- The Holding's CoA may hold accounts which do not exist in the Subsidiary's Virtual CoA.
-
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param holding_chart_account_id: ID of the "Chart" Account of the holding company
- @param subsidiary_chart_account_id: ID of the "Chart" Account of the subsidiary company to check
- @param context: A standard dictionary for contextual values
-
- @return: List of accounts existing on subsidiary but no on holding COA
+ The Holding's CoA may hold accounts which do not exist
+ in the Subsidiary's Virtual CoA.
+
+ :param holding_chart_account_id: ID of the Chart of Account
+ of the holding company
+ :param subsidiary_chart_account_id: ID of the Chart of Account
+ of the subsidiary company to check
+
+ :return: List of accounts existing on subsidiary but no on holding COA
"""
- context = context or {}
- holding_ctx = context.copy()
- holding_ctx.update({'holding_coa': True})
- holding_accounts = self._chart_accounts_data(cr, uid, ids, holding_chart_account_id, context=holding_ctx)
- subsidiary_accounts = self._chart_accounts_data(cr, uid, ids, subsidiary_chart_account_id, context=context)
- # accounts which are configured on the subsidiary VCoA but not on the holding CoA
+ if context is None:
+ context = {}
+ holding_ctx = dict(context, holding_coa=True)
+ holding_accounts = self._chart_accounts_data(
+ cr, uid, ids, holding_chart_account_id, context=holding_ctx)
+ subsidiary_accounts = self._chart_accounts_data(
+ cr, uid, ids, subsidiary_chart_account_id, context=context)
+ # accounts which are configured on the subsidiary
+ # Virtual CoA but not on the holding CoA
spare_accounts = [code for code
in subsidiary_accounts
if code not in holding_accounts]
@@ -250,26 +281,27 @@
def check_account_charts(self, cr, uid, ids, context=None):
"""
- Check the chart of accounts of the holding vs each virtual chart of accounts of the subsidiaries
-
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param context: A standard dictionary for contextual values
+ Check the chart of accounts of the holding vs
+ each virtual chart of accounts of the subsidiaries
"""
+ if isinstance(ids, (int, long)):
+ ids = [ids]
+ assert len(ids) == 1, "only 1 id expected"
form = self.browse(cr, uid, ids[0], context=context)
invalid_items_per_company = {}
for subsidiary in form.subsidiary_ids:
if not subsidiary.consolidation_chart_account_id:
- raise osv.except_osv(_('Error'), _('No chart of accounts for company %s') % (subsidiary,))
+ raise osv.except_osv(
+ _('Error'),
+ _('No chart of accounts for company %s') % subsidiary)
- invalid_items = \
- self.check_subsidiary_chart(cr, uid, ids,
- form.holding_chart_account_id.id,
- subsidiary.consolidation_chart_account_id.id,
- context=context)
+ invalid_items = self.check_subsidiary_chart(
+ cr, uid,
+ ids,
+ form.holding_chart_account_id.id,
+ subsidiary.consolidation_chart_account_id.id,
+ context=context)
if any(invalid_items):
invalid_items_per_company[subsidiary.id] = invalid_items
@@ -278,25 +310,24 @@
def run_consolidation(self, cr, uid, ids, context=None):
"""
Proceed with all checks before launch any consolidation step
- This is a base method intended to be inherited with the next consolidation steps
-
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param context: A standard dictionary for contextual values
+ This is a base method intended to be inherited with the next
+ consolidation steps
"""
+ if isinstance(ids, (int, long)):
+ ids = [ids]
+ assert len(ids) == 1, "only 1 id expected"
if self.check_all_periods(cr, uid, ids, context=context):
- raise osv.except_osv(_('Error'),
- _('Invalid periods, please launch the "Consolidation: Checks" wizard'))
+ raise osv.except_osv(
+ _('Error'),
+ _('Invalid periods, please launch the '
+ '"Consolidation: Checks" wizard'))
if self.check_account_charts(cr, uid, ids, context=context):
- raise osv.except_osv(_('Error'),
- _('Invalid charts, please launch the "Consolidation: Checks" wizard'))
+ raise osv.except_osv(
+ _('Error'),
+ _('Invalid charts, please launch the '
+ '"Consolidation: Checks" wizard'))
# inherit to add the next steps of the reconciliation
return {'type': 'ir.actions.act_window_close'}
-
-
-account_consolidation_base()
=== modified file 'account_consolidation/wizard/consolidation_check.py'
--- account_consolidation/wizard/consolidation_check.py 2012-04-18 14:35:42 +0000
+++ account_consolidation/wizard/consolidation_check.py 2014-04-17 13:57:59 +0000
@@ -1,109 +1,91 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
-#
-# Author : Guewen Baconnier (Camptocamp)
-#
-# WARNING: This program as such is intended to be used by professional
-# programmers who take the whole responsability of assessing all potential
-# consequences resulting from its eventual inadequacies and bugs
-# End users who are looking for a ready-to-use solution with commercial
-# garantees and support are strongly adviced to contract a Free Software
-# Service Company
-#
-# This program is Free Software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Author: Guewen Baconnier
+# Copyright 2011-2013 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
-from osv import osv, fields
-
-from tools.translate import _
-
-
-class account_consolidation_check(osv.osv_memory):
+from openerp.osv import osv, orm, fields
+from openerp.tools.translate import _
+
+
+class account_consolidation_check(orm.TransientModel):
_name = 'account.consolidation.check'
_inherit = 'account.consolidation.base'
_description = 'Consolidation Checks. Model used for views'
_columns = {
- 'subsidiary_ids': fields.many2many('res.company', 'account_conso_check_comp_rel', 'conso_id', 'company_id',
- 'Subsidiaries', required=True),
+ 'subsidiary_ids': fields.many2many(
+ 'res.company',
+ 'account_conso_check_comp_rel',
+ 'conso_id',
+ 'company_id',
+ 'Subsidiaries',
+ required=True),
}
def check_account_charts(self, cr, uid, ids, context=None):
"""
Action launched with the button on the view.
Check the account charts and display a report of the errors
-
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param context: A standard dictionary for contextual values
"""
- invalid_items_per_company = \
- super(account_consolidation_check, self).check_account_charts(cr, uid, ids, context=context)
- if invalid_items_per_company:
- err_lines = []
- for company_id, account_codes in invalid_items_per_company.iteritems():
- company_obj = self.pool.get('res.company')
- company = company_obj.browse(cr, uid, company_id, context=context)
- err_lines.append(_("%s :") % (company.name,))
- [err_lines.append(_("Account with code %s does not exist on the Holding company.") % (account_code,))
- for account_code
- in account_codes]
- err_lines.append('')
-
- raise osv.except_osv(_('Invalid charts'),
- '\n'.join(err_lines))
-
- else:
- raise osv.except_osv(_('Validation'), _('Chart of Accounts are OK.'))
- # open a confirmation view ?
- return True
+ company_obj = self.pool.get('res.company')
+ invalid_items_per_company = super(account_consolidation_check, self).\
+ check_account_charts(cr, uid, ids, context=context)
+
+ if not invalid_items_per_company:
+ raise osv.except_osv(
+ _('Validation'),
+ _('Chart of Accounts are OK.'))
+
+ err_lines = []
+ for company_id, account_codes in invalid_items_per_company.iteritems():
+ company = company_obj.browse(
+ cr, uid, company_id, context=context)
+ err_lines.append(_("%s :") % company.name)
+ for account_code in account_codes:
+ err_lines.append(
+ _("Account with code %s does not exist on the "
+ "Holding company.") % account_code)
+ err_lines.append('')
+
+ raise osv.except_osv(
+ _('Invalid charts'), '\n'.join(err_lines))
def check_all_periods(self, cr, uid, ids, context=None):
"""
Action launched with the button on the view.
Check the periods and display a report of the errors
-
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param context: A standard dictionary for contextual values
"""
- errors_by_company = \
- super(account_consolidation_check, self).check_all_periods(cr, uid, ids, context=context)
-
- if errors_by_company:
- company_obj = self.pool.get('res.company')
-
- err_lines = []
- for company_id, errors in errors_by_company.iteritems():
- company = company_obj.browse(cr, uid, company_id, context=context)
- err_lines.append(_("%s :") % (company.name,))
- [err_lines.append(error) for error in errors]
- err_lines.append('')
-
- raise osv.except_osv(_('Invalid periods'),
- '\n'.join(err_lines))
- else:
+ errors_by_company = super(account_consolidation_check, self).\
+ check_all_periods(cr, uid, ids, context=context)
+
+ if not errors_by_company:
raise osv.except_osv(_('Validation'), _('Periods are OK.'))
- # open a confirmation view ?
- return True
-
-account_consolidation_check()
+
+ company_obj = self.pool.get('res.company')
+
+ err_lines = []
+ for company_id, errors in errors_by_company.iteritems():
+ company = company_obj.browse(cr, uid, company_id, context=context)
+ err_lines.append(_("%s :") % company.name)
+ for error in errors:
+ err_lines.append(error)
+ err_lines.append('')
+
+ raise osv.except_osv(_('Invalid periods'),
+ '\n'.join(err_lines))
=== modified file 'account_consolidation/wizard/consolidation_check_view.xml'
--- account_consolidation/wizard/consolidation_check_view.xml 2011-08-19 13:08:01 +0000
+++ account_consolidation/wizard/consolidation_check_view.xml 2014-04-17 13:57:59 +0000
@@ -2,32 +2,44 @@
<openerp>
<data>
- <record id="view_consolidation_check_form" model="ir.ui.view">
+ <record id="view_consolidation_check_form" model="ir.ui.view">
<field name="name">account.consolidation.check.form</field>
<field name="model">account.consolidation.check</field>
<field name="type">form</field>
<field name="arch" type="xml">
- <form string="Consolidation: Checks">
- <group col="4" colspan="6">
- <field name="company_id" on_change="on_change_company_id(company_id)" invisible="True"/>
- <field name="fiscalyear_id" domain="[('company_id', '=', company_id)]"/>
- <newline/>
- <field name="holding_chart_account_id" domain="[('company_id', '=', company_id), ('parent_id', '=', False)]"/>
- <separator string="Subsidiaries to Consolidate" colspan="4"/>
- <field name="subsidiary_ids" colspan="4" nolabel="1" required="True" domain="[('parent_id', '=', company_id)]">
- <tree>
- <field name="name"/>
- <field name="consolidation_chart_account_id"/>
- </tree>
- </field>
- </group>
- <separator colspan="4"/>
- <group col="3" colspan="4">
- <button special="cancel" string="Cancel" icon='gtk-cancel'/>
- <button name="check_all_periods" string="Check Periods" colspan="1" type="object" icon="gtk-execute"/>
- <button name="check_account_charts" string="Check Charts" colspan="1" type="object" icon="gtk-execute"/>
- </group>
- </form>
+ <form string="Consolidation: Checks" version="7.0">
+ <label string="Prepare your consolidation and make sure that your consolidation will be correct by proceeding with the checks. The 'Check Periods' verify if fiscal year exists for each subsidiary, and if the periods have the same beginning and ending dates. The 'Check Charts' verify if subsidiary accounts are missing in the Holding's Chart of Accounts."/>
+ <group>
+ <field name="company_id"
+ on_change="on_change_company_id(company_id)"
+ invisible="True"/>
+ <field name="fiscalyear_id"
+ domain="[('company_id', '=', company_id)]"/>
+ <newline/>
+ <field name="holding_chart_account_id"
+ domain="[('company_id', '=', company_id), ('parent_id', '=', False)]"/>
+ <separator string="Subsidiaries to Consolidate" colspan="4"/>
+ <field name="subsidiary_ids" colspan="4" nolabel="1"
+ required="True"
+ domain="[('parent_id', '=', company_id)]">
+ <tree>
+ <field name="name"/>
+ <field name="consolidation_chart_account_id"/>
+ </tree>
+ </field>
+ </group>
+ <footer>
+ <button name="check_all_periods"
+ string="Check Periods" type="object"
+ class="oe_highlight"/>
+ or
+ <button name="check_account_charts"
+ string="Check Charts" type="object"
+ class="oe_highlight"/>
+ or
+ <button string="Cancel" class="oe_link" special="cancel"/>
+ </footer>
+ </form>
</field>
</record>
@@ -37,9 +49,8 @@
<field name="res_model">account.consolidation.check</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
- <field name="help">Prepare your consolidation and make sure that your consolidation will be correct by proceeding with the checks. The "Check Periods" verify if fiscal year exists for each subsidiary, and if the periods have the same beginning and ending dates. The "Check Charts" verify if subsidiary accounts are missing in the Holding's Chart of Accounts.</field>
<field name="target">new</field>
</record>
- </data>
+ </data>
</openerp>
=== modified file 'account_consolidation/wizard/consolidation_consolidate.py'
--- account_consolidation/wizard/consolidation_consolidate.py 2012-04-11 07:57:56 +0000
+++ account_consolidation/wizard/consolidation_consolidate.py 2014-04-17 13:57:59 +0000
@@ -1,94 +1,113 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
-#
-# Author : Guewen Baconnier (Camptocamp)
-#
-# WARNING: This program as such is intended to be used by professional
-# programmers who take the whole responsability of assessing all potential
-# consequences resulting from its eventual inadequacies and bugs
-# End users who are looking for a ready-to-use solution with commercial
-# garantees and support are strongly adviced to contract a Free Software
-# Service Company
-#
-# This program is Free Software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Author: Guewen Baconnier
+# Copyright 2011-2013 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
-from osv import osv, fields
-from tools.translate import _
-from tools import safe_eval as eval
+from openerp.osv import orm, fields
+from openerp.osv.osv import except_osv
+from openerp.tools.translate import _
-class account_consolidation_consolidate(osv.osv_memory):
+class account_consolidation_consolidate(orm.TransientModel):
_name = 'account.consolidation.consolidate'
_inherit = 'account.consolidation.base'
+ def _default_journal(self, cr, uid, context=None):
+ comp_obj = self.pool['res.company']
+ journ_obj = self.pool['account.journal']
+ comp_id = comp_obj._company_default_get(cr, uid)
+ journal_id = journ_obj.search(cr, uid, [('company_id', '=', comp_id)], limit=1)
+ if journal_id:
+ return journal_id[0]
+ return False
+
_columns = {
- 'from_period_id': fields.many2one('account.period', 'Start Period', required=True,
- help="Select the same period in 'from' and 'to' if you want to proceed with a single period. Start Period is ignored for Year To Date accounts."),
- 'to_period_id': fields.many2one('account.period', 'End Period', required=True,
- help="The consolidation will be done at the very last date of the selected period."),
- 'journal_id': fields.many2one('account.journal', 'Journal', required=True),
- # not sure that we'll use them, actually using centralised counterpart journal
-# 'gain_account_id': fields.many2one('account.account', 'Gain Account', required=True,),
-# 'loss_account_id': fields.many2one('account.account', 'Loss Account', required=True,),
- 'target_move': fields.selection([('posted', 'All Posted Entries'),
- ('all', 'All Entries'),
- ], 'Target Moves', required=True),
- 'subsidiary_ids': fields.many2many('res.company', 'account_conso_conso_comp_rel', 'conso_id', 'company_id',
- 'Subsidiaries', required=True),
- }
-
- _defaults = {
- 'target_move': 'posted'
- }
+ 'from_period_id': fields.many2one(
+ 'account.period',
+ 'Start Period',
+ required=True,
+ help="Select the same period in 'from' and 'to' "
+ "if you want to proceed with a single period. "
+ "Start Period is ignored for Year To Date accounts."),
+
+ 'to_period_id': fields.many2one(
+ 'account.period',
+ 'End Period',
+ required=True,
+ help="The consolidation will be done at the very "
+ "last date of the selected period."),
+
+ 'journal_id': fields.many2one(
+ 'account.journal', 'Journal', required=True),
+
+ 'target_move': fields.selection(
+ [('posted', 'All Posted Entries'),
+ ('all', 'All Entries')],
+ 'Target Moves',
+ required=True),
+
+ 'subsidiary_ids': fields.many2many(
+ 'res.company',
+ 'account_conso_conso_comp_rel',
+ 'conso_id',
+ 'company_id',
+ string='Subsidiaries',
+ required=True),
+ }
+
+ _defaults = {'target_move': 'posted',
+ 'journal_id': _default_journal,
+ }
def _check_periods_fy(self, cr, uid, ids, context=None):
- if context is None:
- context = {}
+ if isinstance(ids, (int, long)):
+ ids = [ids]
+ assert len(ids) == 1, "only 1 id expected"
+
form = self.browse(cr, uid, ids[0], context=context)
- if form.from_period_id.fiscalyear_id.id != form.to_period_id.fiscalyear_id.id:
- return False
- return True
+ return (form.from_period_id.fiscalyear_id.id ==
+ form.to_period_id.fiscalyear_id.id)
_constraints = [
- (_check_periods_fy, 'Start Period and End Period must be of the same Fiscal Year !', ['from_period_id', 'to_period_id']),
+ (_check_periods_fy,
+ 'Start Period and End Period must be of the same Fiscal Year !',
+ ['from_period_id', 'to_period_id']),
]
- def on_change_from_period_id(self, cr, uid, ids, from_period_id, to_period_id, context=None):
- """
- On change of the From period, set the To period to the same period if it is empty
-
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param from_period_id: ID of the selected from period id
- @param to_period_id: ID of the current from period id
- @param context: A standard dictionary for contextual values
-
- @return: dict of values to change
+ def on_change_from_period_id(self, cr, uid, ids, from_period_id,
+ to_period_id, context=None):
+ """ On change of the From period, set the To period
+ to the same period if it is empty
+
+ :param from_period_id: ID of the selected from period id
+ :param to_period_id: ID of the current from period id
+
+ :return: dict of values to change
"""
result = {}
period_obj = self.pool.get('account.period')
- from_period = period_obj.browse(cr, uid, from_period_id, context=context)
+ from_period = period_obj.browse(cr, uid, from_period_id,
+ context=context)
if not to_period_id:
result['to_period_id'] = from_period_id
else:
- to_period = period_obj.browse(cr, uid, to_period_id, context=context)
+ to_period = period_obj.browse(cr, uid, to_period_id,
+ context=context)
if to_period.date_start < from_period.date_start:
result['to_period_id'] = from_period_id
@@ -99,97 +118,120 @@
"""
Returns the currency rate type to use
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param account: browse instance of account.account
- @param context: A standard dictionary for contextual values
+ :param account: browse_record instance of account.account
- @return: 'spot' or 'average'
+ :return: id of the currency rate type to use
"""
- return account.consolidation_rate_type_id and account.consolidation_rate_type_id \
- or account.user_type.consolidation_rate_type_id and account.user_type.consolidation_rate_type_id.id \
- or False
+ if account.consolidation_rate_type_id:
+ return account.consolidation_rate_type_id.id
+
+ elif account.user_type.consolidation_rate_type_id:
+ return account.user_type.consolidation_rate_type_id.id
+
+ else:
+ return False
def _consolidation_mode(self, cr, uid, ids, account, context=None):
"""
Returns the consolidation mode to use
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param account: browse instance of account.account
- @param context: A standard dictionary for contextual values
-
- @return: 'ytd' or 'period'
- """
- return account.consolidation_mode or account.user_type.consolidation_mode
-
- def _periods_holding_to_subsidiary(self, cr, uid, ids, period_ids, subsidiary_id, context=None):
- """
- Returns the periods of a subsidiary company which correspond to the holding periods
- (same beginning and ending dates)
-
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param period_ids: list of periods of the holding
- @param subsidiary_id: ID of the subsidiary for which we want the period IDs
- @param context: A standard dictionary for contextual values
-
- @return: list of periods of the subsidiaries
+ :param account: browse instance of account.account
+
+ :return: 'ytd' or 'period'
+ """
+ return (account.consolidation_mode or
+ account.user_type.consolidation_mode)
+
+ def _periods_holding_to_subsidiary(self, cr, uid, ids, period_ids,
+ subsidiary_id, context=None):
+ """
+ Returns the periods of a subsidiary company which
+ correspond to the holding periods (same beginning and ending dates)
+
+ :param period_ids: list of periods of the holding
+ :param subsidiary_id: ID of the subsidiary for which
+ we want the period IDs
+
+ :return: list of periods of the subsidiaries
"""
period_obj = self.pool.get('account.period')
if isinstance(period_ids, (int, long)):
period_ids = [period_ids]
+
subs_period_ids = []
for period in period_obj.browse(cr, uid, period_ids, context=context):
- subs_period_ids.extend(period_obj.search(cr, uid,
+ subs_period_ids += period_obj.search(
+ cr, uid,
[('date_start', '=', period.date_start),
('date_stop', '=', period.date_stop),
- ('company_id', '=', subsidiary_id)])
- )
+ ('company_id', '=', subsidiary_id)],
+ context=context)
return subs_period_ids
- def create_rate_difference_line(self, cr, uid, ids, move_id, context):
- """
- Create a move line for the gain/loss currency difference
-
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param move_id: ID of the move
- @param context: A standard dictionary for contextual values
-
- @return:
- """
-
- pass
-
- def consolidate_account(self, cr, uid, ids, consolidation_mode, subsidiary_period_ids, state, move_id,
+ def create_rate_difference_line(self, cr, uid, ids, move_id, consolidation_mode, context):
+ """
+ We can have consolidation difference when a account is in YTD but in normal counterpart
+ has a different setting.
+ """
+ move_obj = self.pool['account.move']
+ move_line_obj = self.pool['account.move.line']
+ currency_obj = self.pool['res.currency']
+ move = move_obj.browse(cr, uid, move_id, context=context)
+
+ if not move.line_id:
+ return False
+ diff_account = move.company_id.consolidation_diff_account_id
+ if not diff_account:
+ raise except_osv(_('Settings ERROR'),
+ _('Please set the "Consolidation difference account"'
+ ' in company %s') % move.company_id.name)
+ debit = credit = 0.0
+ for line in move.line_id:
+ debit += line.debit
+ credit += line.credit
+ balance = debit - credit
+ # We do not want to create counter parts for amount smaller than
+ # "holding" company currency rounding policy.
+ # As generated lines are in draft state, accountant will be able to manage
+ # special cases
+ move_is_balanced = currency_obj.is_zero(cr, uid, move.company_id.currency_id, balance)
+ if not move_is_balanced:
+ diff_vals = {'account_id': diff_account.id,
+ 'move_id': move.id,
+ 'journal_id': move.journal_id.id,
+ 'period_id': move.period_id.id,
+ 'company_id': move.company_id.id,
+ 'date': move.date,
+ 'debit': abs(balance) if balance < 0.0 else 0.0,
+ 'credit': balance if balance > 0.0 else 0.0,
+ 'name': _('Consolidation difference in mode %s') % consolidation_mode
+ }
+ return move_line_obj.create(cr, uid, diff_vals, context=context)
+ return False
+
+ def consolidate_account(self, cr, uid, ids, consolidation_mode,
+ subsidiary_period_ids, state, move_id,
holding_account_id, subsidiary_id, context=None):
"""
Consolidates the subsidiary account on the holding account
Creates move lines on the move with id "move_id"
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param consolidation_mode: consolidate by Periods or Year To Date ('period' or 'ytd')
- @param subsidiary_period_ids: IDs of periods for which we want to sum the debit/credit
- @param state: state of the moves to consolidate ('all' or 'posted')
- @param move_id: ID of the move on which all the created move lines will be linked
- @param holding_account_id: ID of the account to consolidate (on the holding), the method will find the subsidiary's corresponding account
- @param subsidiary_id: ID of the subsidiary to consolidate
- @param context: A standard dictionary for contextual values
+ :param consolidation_mode: consolidate by Periods or
+ Year To Date ('period' or 'ytd')
+ :param subsidiary_period_ids: IDs of periods for which we
+ want to sum the debit/credit
+ :param state: state of the moves to consolidate ('all' or 'posted')
+ :param move_id: ID of the move on which all the
+ created move lines will be linked
+ :param holding_account_id: ID of the account to consolidate
+ (on the holding), the method will
+ find the subsidiary's corresponding account
+ :param subsidiary_id: ID of the subsidiary to consolidate
- @return: list of IDs of the created move lines
+ :return: list of IDs of the created move lines
"""
+ if context is None:
+ context = {}
account_obj = self.pool.get('account.account')
move_obj = self.pool.get('account.move')
@@ -197,7 +239,8 @@
currency_obj = self.pool.get('res.currency')
move = move_obj.browse(cr, uid, move_id, context=context)
- holding_account = account_obj.browse(cr, uid, holding_account_id, context=context)
+ holding_account = account_obj.browse(cr, uid, holding_account_id,
+ context=context)
subsidiary_account_id = account_obj.search(cr, uid,
[('code', '=', holding_account.code),
@@ -205,18 +248,17 @@
context=context)
if not subsidiary_account_id:
- return [] # an account may exist on the holding and not in the subsidiaries, nothing to do
+ # an account may exist on the holding and not in the subsidiaries,
+ # nothing to do
+ return []
- browse_ctx = context.copy()
- browse_ctx.update({
- 'state': state,
- 'periods': subsidiary_period_ids,
- })
- # subsidiary_account_id[0] because only one account per company for one code is permitted
- subs_account = account_obj.browse(cr, uid, subsidiary_account_id[0], context=browse_ctx)
+ browse_ctx = dict(context, state=state, periods=subsidiary_period_ids)
+ # 1st item because the account's code is unique per company
+ subs_account = account_obj.browse(cr, uid, subsidiary_account_id[0],
+ context=browse_ctx)
vals = {
- 'name': _("Consolidation line in %s mode") % (consolidation_mode,),
+ 'name': _("Consolidation line in %s mode") % consolidation_mode,
'account_id': holding_account.id,
'move_id': move.id,
'journal_id': move.journal_id.id,
@@ -225,47 +267,47 @@
'date': move.date
}
- if holding_account.company_currency_id.id != subs_account.company_currency_id.id:
- currency_rate_type = self._currency_rate_type(cr, uid, ids, holding_account, context=context)
+ balance = subs_account.balance
+ if not balance:
+ return False
+ if (holding_account.company_currency_id.id ==
+ subs_account.company_currency_id.id):
+ vals.update({
+ 'debit': balance if balance > 0.0 else 0.0,
+ 'credit': abs(balance) if balance < 0.0 else 0.0,
+ })
+ else:
+ currency_rate_type = self._currency_rate_type(cr, uid, ids,
+ holding_account, context=context)
currency_value = currency_obj.compute(cr, uid,
holding_account.company_currency_id.id,
subs_account.company_currency_id.id,
- subs_account.balance,
+ balance,
currency_rate_type_from=False, # means spot
currency_rate_type_to=currency_rate_type,
context=context)
vals.update({
'currency_id': subs_account.company_currency_id.id,
'amount_currency': subs_account.balance,
- 'debit': currency_value > 0 and currency_value or 0.0,
- 'credit': currency_value < 0 and -currency_value or 0.0
- })
-
- else:
- vals.update({
- 'debit': subs_account.debit,
- 'credit': subs_account.credit,
- })
-
- move_line_id = move_line_obj.create(cr, uid, vals, context=context)
-
- return move_line_id
-
- def reverse_moves(self, cr, uid, ids, subsidiary_id, journal_id, reversal_date, context):
+ 'debit': currency_value if currency_value > 0.0 else 0.0,
+ 'credit': abs(currency_value) if currency_value < 0.0 else 0.0,
+ })
+
+ return move_line_obj.create(cr, uid, vals, context=context)
+
+ def reverse_moves(self, cr, uid, ids, subsidiary_id, journal_id,
+ reversal_date, context=None):
"""
- Reverse all account moves of a journal which have the "To be reversed" flag
-
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param subsidiary_id: ID of the subsidiary moves to reverse
- @param journal_id: ID of the journal with moves to reverse
- @param reversal_date: date when to create the reversal
- @param context: A standard dictionary for contextual values
-
- @return: tuple with : list of IDs of the reversed moves, list of IDs of the reversal moves
+ Reverse all account moves of a journal which have
+ the "To be reversed" flag
+
+ :param subsidiary_id: ID of the subsidiary moves to reverse
+ :param journal_id: ID of the journal with moves to reverse
+ :param reversal_date: date when to create the reversal
+
+ :return: tuple with : list of IDs of the reversed moves,
+ list of IDs of the reversal moves
"""
move_obj = self.pool.get('account.move')
reversed_ids = move_obj.search(cr, uid,
@@ -273,41 +315,49 @@
('to_be_reversed', '=', True),
('consol_company_id', '=', subsidiary_id)],
context=context)
- reversal_ids = move_obj.create_reversals(cr, uid, reversed_ids, reversal_date, context=context)
+ reversal_ids = move_obj.create_reversals(
+ cr, uid, reversed_ids, reversal_date, context=context)
return reversed_ids, reversal_ids
- def consolidate_subsidiary(self, cr, uid, ids, subsidiary_id, context=None):
+ def consolidate_subsidiary(self, cr, uid, ids,
+ subsidiary_id, context=None):
"""
Consolidate one subsidiary on the Holding.
Create a move per subsidiary and consolidation type (YTD/Period)
and an move line per account of the subsidiary
- Plus a move line for the currency gain / loss # FIXME to check!
-
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param subsidiary_id: ID of the subsidiary to consolidate on the holding
- @param context: A standard dictionary for contextual values
-
- @return: Tuple of (list of IDs of the YTD moves, list of IDs of the Period Moves)
+
+ :param subsidiary_id: ID of the subsidiary to consolidate
+ on the holding
+
+ :return: Tuple of form:
+ (list of IDs of the YTD moves,
+ list of IDs of the Period Moves)
"""
-
- context = context or {}
+ if context is None:
+ context = {}
+
+ if isinstance(ids, (int, long)):
+ ids = [ids]
+ assert len(ids) == 1, "only 1 id expected"
+
company_obj = self.pool.get('res.company')
move_obj = self.pool.get('account.move')
period_obj = self.pool.get('account.period')
+
form = self.browse(cr, uid, ids[0], context=context)
subsidiary = company_obj.browse(cr, uid, subsidiary_id, context=None)
- data_ctx = context.copy()
- data_ctx.update({'holding_coa': True})
- holding_accounts_data = self._chart_accounts_data(cr, uid, ids,
- form.holding_chart_account_id.id,
- context=data_ctx)
- subs_accounts_codes = self._chart_accounts_data(cr, uid, ids,
- subsidiary.consolidation_chart_account_id.id,
- context=context)
+ data_ctx = dict(context, holding_coa=True)
+ holding_accounts_data = self._chart_accounts_data(
+ cr, uid,
+ ids,
+ form.holding_chart_account_id.id,
+ context=data_ctx)
+ subs_accounts_codes = self._chart_accounts_data(
+ cr, uid,
+ ids,
+ subsidiary.consolidation_chart_account_id.id,
+ context=context)
holding_accounts = [values for key, values
in holding_accounts_data.iteritems()
if key in subs_accounts_codes]
@@ -316,12 +366,14 @@
# a move per type will be created
consolidation_modes = {'ytd': [], 'period': []}
for account in holding_accounts:
- cm = self._consolidation_mode(cr, uid, ids, account, context=context)
+ cm = self._consolidation_mode(
+ cr, uid, ids, account, context=context)
consolidation_modes[cm].append(account)
- period_ids = period_obj.build_ctx_periods(cr, uid,
- form.from_period_id.id,
- form.to_period_id.id)
+ period_ids = period_obj.build_ctx_periods(
+ cr, uid,
+ form.from_period_id.id,
+ form.to_period_id.id)
generic_move_vals = {
'journal_id': form.journal_id.id,
@@ -337,15 +389,18 @@
# get list of periods for which we have to create a move
# in period mode : a move per period
- # in ytd mode : a move at the last period (which will contains lines from 1st january to last period)
- move_period_ids = consolidation_mode == 'period' \
- and period_ids \
- or [form.to_period_id.id]
+ # in ytd mode : a move at the last period
+ # (which will contains lines from 1st january to last period)
+ move_period_ids = (period_ids
+ if consolidation_mode == 'period'
+ else [form.to_period_id.id])
for move_period_id in move_period_ids:
- period = period_obj.browse(cr, uid, move_period_id, context=context)
+ period = period_obj.browse(
+ cr, uid, move_period_id, context=context)
- # in ytd we compute the amount from the first day of the fiscal year
+ # in ytd we compute the amount from the first
+ # day of the fiscal year
# in period, only for the period
if consolidation_mode == 'ytd':
date_from = period.fiscalyear_id.date_start
@@ -353,52 +408,61 @@
date_from = period.date_start
date_to = period.date_stop
- period_ctx = context.copy()
- period_ctx.update({
- 'company_id': subsidiary.id,
- })
- compute_from_period_id = period_obj.find(cr, uid, date_from, context=period_ctx)[0]
- compute_to_period_id = period_obj.find(cr, uid, date_to, context=period_ctx)[0]
- compute_period_ids = period_obj.build_ctx_periods(cr, uid,
- compute_from_period_id,
- compute_to_period_id)
+ period_ctx = dict(context, company_id=subsidiary.id)
+ compute_from_period_id = period_obj.find(
+ cr, uid, date_from, context=period_ctx)[0]
+ compute_to_period_id = period_obj.find(
+ cr, uid, date_to, context=period_ctx)[0]
+ compute_period_ids = period_obj.build_ctx_periods(
+ cr, uid,
+ compute_from_period_id,
+ compute_to_period_id)
# reverse previous entries with flag 'to_be_reversed' (YTD)
- self.reverse_moves(cr, uid, ids, subsidiary.id, form.journal_id.id, date_to, context=context)
-
- # TODO if moves found for the same period : skip ?
+ self.reverse_moves(
+ cr, uid,
+ ids,
+ subsidiary.id,
+ form.journal_id.id,
+ date_to,
+ context=context)
# create the account move
# at the very last date of the end period
- move_vals = generic_move_vals.copy()
- move_vals.update({
- 'ref': _("Consolidation %s") % (consolidation_mode,),
- 'period_id': period.id,
- 'date': period.date_stop,
- })
+ move_vals = dict(
+ generic_move_vals,
+ ref=_("Consolidation %s") % consolidation_mode,
+ period_id=period.id,
+ date=period.date_stop)
move_id = move_obj.create(cr, uid, move_vals, context=context)
- move_line_ids = []
# create a move line per account
+ has_move_line = False
for account in accounts:
- move_line_ids.append(
- self.consolidate_account(cr, uid, ids,
- consolidation_mode,
- compute_period_ids,
- form.target_move,
- move_id,
- account.id,
- subsidiary.id,
- context=context)
- )
-
- # TODO calculate currency rate difference (all move lines debit - all move lines credit) and post a move line
- # on the gain / loss account
- # will works IF : counterparts are always configured with the same mode (YTD/Periods)
- self.create_rate_difference_line(cr, uid, ids,
- move_id, context=context)
-
- locals()[consolidation_mode + '_move_ids'].append(move_id)
+ m_id = self.consolidate_account(
+ cr, uid, ids,
+ consolidation_mode,
+ compute_period_ids,
+ form.target_move,
+ move_id,
+ account.id,
+ subsidiary.id,
+ context=context)
+ if m_id:
+ has_move_line = True
+
+ if has_move_line:
+ self.create_rate_difference_line(cr, uid, ids,
+ move_id, consolidation_mode, context=context)
+ locals()[consolidation_mode + '_move_ids'].append(move_id)
+
+ else:
+ # We delete created move if it has no line.
+ # As move are generated in draft mode they will be no gap in
+ # number if consolidation journal has correct settings.
+ # I agree it can be more efficient but size of refactoring
+ # is not in ressource scope
+ move_obj.unlink(cr, uid, [move_id])
return ytd_move_ids, period_move_ids
@@ -407,15 +471,10 @@
Consolidate all selected subsidiaries Virtual Chart of Accounts
on the Holding Chart of Account
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of the wizard IDs (commonly the first element is the current ID)
- @param context: A standard dictionary for contextual values
-
- @return: dict to open an Entries view filtered on the created moves
+ :return: dict to open an Entries view filtered on the created moves
"""
- super(account_consolidation_consolidate, self).run_consolidation(cr, uid, ids, context=context)
+ super(account_consolidation_consolidate, self).run_consolidation(
+ cr, uid, ids, context=context)
mod_obj = self.pool.get('ir.model.data')
act_obj = self.pool.get('ir.actions.act_window')
@@ -425,20 +484,23 @@
move_ids = []
ytd_move_ids = []
for subsidiary in form.subsidiary_ids:
- new_move_ids = self.consolidate_subsidiary(cr, uid, ids, subsidiary.id, context=context)
- ytd_move_ids.extend(new_move_ids[0])
- move_ids.extend(sum(new_move_ids, []))
+ new_move_ids = self.consolidate_subsidiary(
+ cr, uid, ids, subsidiary.id, context=context)
+ ytd_move_ids += new_move_ids[0]
+ move_ids += sum(new_move_ids, [])
# YTD moves have to be reversed on the next consolidation
- move_obj.write(cr, uid, ytd_move_ids, {'to_be_reversed': True}, context=context)
+ move_obj.write(
+ cr, uid,
+ ytd_move_ids,
+ {'to_be_reversed': True},
+ context=context)
context.update({'move_ids': move_ids})
- action_ref = mod_obj.get_object_reference(cr, uid, 'account', 'action_move_journal_line')
- action_id = action_ref and action_ref[1] or False
+ __, action_id = mod_obj.get_object_reference(
+ cr, uid, 'account', 'action_move_journal_line')
action = act_obj.read(cr, uid, [action_id], context=context)[0]
action['domain'] = unicode([('id', 'in', move_ids)])
action['name'] = _('Consolidated Entries')
action['context'] = unicode({'search_default_to_be_reversed': 0})
return action
-
-account_consolidation_consolidate()
=== modified file 'account_consolidation/wizard/consolidation_consolidate_view.xml'
--- account_consolidation/wizard/consolidation_consolidate_view.xml 2011-08-29 05:45:40 +0000
+++ account_consolidation/wizard/consolidation_consolidate_view.xml 2014-04-17 13:57:59 +0000
@@ -2,39 +2,49 @@
<openerp>
<data>
- <record id="view_consolidation_consolidate_form" model="ir.ui.view">
+ <record id="view_consolidation_consolidate_form" model="ir.ui.view">
<field name="name">account.consolidation.consolidate.form</field>
<field name="model">account.consolidation.consolidate</field>
<field name="type">form</field>
<field name="arch" type="xml">
- <form string="Consolidation: Consolidate">
- <group col="4" colspan="6">
- <field name="company_id" on_change="on_change_company_id(company_id)" invisible="True"/>
- <field name="fiscalyear_id" invisible="True"/>
- <field name="from_period_id" on_change="on_change_from_period_id(from_period_id, to_period_id)" domain="[('company_id', '=', company_id)]"/>
- <field name="to_period_id" domain="[('company_id', '=', company_id)]"/>
- <field name="journal_id" domain="[('company_id', '=', company_id)]"/>
- <field name="target_move"/>
- <separator string="Holding Chart of Accounts" colspan="4"/>
- <field name="holding_chart_account_id" domain="[('company_id', '=', company_id), ('parent_id', '=', False)]"/>
+ <form string="Consolidation: Consolidate" version="7.0">
+ <label string="Run the consolidation for the selected periods and subsidiaries."/>
+ <group>
+ <field name="company_id"
+ on_change="on_change_company_id(company_id)"
+ invisible="True"/>
+ <field name="fiscalyear_id" invisible="True"/>
+ <field name="from_period_id"
+ on_change="on_change_from_period_id(from_period_id, to_period_id)"
+ domain="[('company_id', '=', company_id)]"/>
+ <field name="to_period_id"
+ domain="[('company_id', '=', company_id)]"/>
+ <field name="journal_id"
+ domain="[('company_id', '=', company_id)]"/>
+ <field name="target_move"/>
+ <separator string="Holding Chart of Accounts" colspan="4"/>
+ <field name="holding_chart_account_id"
+ domain="[('company_id', '=', company_id), ('parent_id', '=', False)]"/>
- <!--<separator string="Consolidation Difference Accounts" colspan="4"/>-->
- <!--<field name="gain_account_id" domain="[('type','<>','view'), ('id', 'child_of', [holding_chart_account_id])]"/>-->
- <!--<field name="loss_account_id" domain="[('type','<>','view'), ('id', 'child_of', [holding_chart_account_id])]"/>-->
- <separator string="Subsidiaries to Consolidate" colspan="4"/>
- <field name="subsidiary_ids" colspan="4" nolabel="1" required="True">
- <tree>
- <field name="name"/>
- <field name="consolidation_chart_account_id"/>
- </tree>
- </field>
- </group>
- <separator colspan="4"/>
- <group col="2" colspan="4">
- <button special="cancel" string="Cancel" icon='gtk-cancel'/>
- <button name="run_consolidation" string="Consolidate" colspan="1" type="object" icon="gtk-execute"/>
- </group>
- </form>
+ <separator string="Subsidiaries to Consolidate" colspan="4"/>
+ <field name="subsidiary_ids" colspan="4"
+ nolabel="1" required="True">
+ <tree>
+ <field name="name"/>
+ <field name="consolidation_chart_account_id"/>
+ </tree>
+ </field>
+ </group>
+ <separator colspan="4"/>
+ <footer>
+ <button name="run_consolidation"
+ string="Consolidate"
+ type="object"
+ class="oe_highlight"/>
+ or
+ <button string="Cancel" class="oe_link" special="cancel"/>
+ </footer>
+ </form>
</field>
</record>
@@ -44,9 +54,8 @@
<field name="res_model">account.consolidation.consolidate</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
- <field name="help">Run the consolidation for the selected periods and subsidiaries.</field>
<field name="target">new</field>
</record>
- </data>
+ </data>
</openerp>
=== added directory 'account_parallel_currency'
=== added file 'account_parallel_currency/AUTHORS.txt'
--- account_parallel_currency/AUTHORS.txt 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/AUTHORS.txt 2014-04-17 13:57:59 +0000
@@ -0,0 +1,1 @@
+Lorenzo Battistini <lorenzo.battistini@xxxxxxxxxxx>
=== added file 'account_parallel_currency/__init__.py'
--- account_parallel_currency/__init__.py 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/__init__.py 2014-04-17 13:57:59 +0000
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2012 Agile Business Group sagl (<http://www.agilebg.com>)
+# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+import account
+import res_company
+import wizard
=== added file 'account_parallel_currency/__openerp__.py'
--- account_parallel_currency/__openerp__.py 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/__openerp__.py 2014-04-17 13:57:59 +0000
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2012-2013 Agile Business Group sagl
+# (<http://www.agilebg.com>)
+# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+{
+ 'name': "Account Parallel Currency",
+ 'version': '0.2',
+ 'category': 'Generic Modules/Accounting',
+ 'description': """
+This module handles parallel accounting entries based on different currencies.
+It is useful for companies who have to manage accounting with more than one currency at the same time. For instance, companies who have to produce balances on different currencies.
+
+In order to use the module, you have to define one company for each parallel chart of accounts. Then you have to map parallel accounts and parallel journals through the related forms.
+
+A 'Parallel Account Mapping' wizard is provided. It is intended to be run when the same chart of account is used for the parallel companies. It allows to automatically map the 'master' account to 'parallel' accounts, based on account code.
+
+When posting new journal entries, the system checks the configured parallel accounts and automatically generates the parallel entries.
+This is achieved keeping the companies separate, so that users of the master company don't see secondary company data (e.g. currencies and journals) but the system uses the super user in order to perform the parallel registrations.
+""",
+ 'author': 'Agile Business Group',
+ 'website': 'http://www.agilebg.com',
+ 'license': 'AGPL-3',
+ "depends" : ['account'],
+ "data" : [
+ 'account_view.xml',
+ 'company_view.xml',
+ 'wizard/do_mapping.xml',
+ 'security/security.xml',
+ ],
+ "demo" : [
+ 'account_demo.xml',
+ ],
+ 'test': [
+ 'test/mapping_parallel_accounts.yml',
+ 'test/customer_invoice.yml',
+ ],
+ "active": False,
+ "installable": True
+}
=== added file 'account_parallel_currency/account.py'
--- account_parallel_currency/account.py 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/account.py 2014-04-17 13:57:59 +0000
@@ -0,0 +1,505 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2012-2013 Agile Business Group sagl
+# (<http://www.agilebg.com>)
+# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import fields, orm
+from tools.translate import _
+import logging
+from openerp import SUPERUSER_ID
+
+_logger = logging.getLogger(__name__)
+
+
+class account_account(orm.Model):
+ _inherit = "account.account"
+
+ def _get_parallel_accounts_summary(self, cr, uid, ids, field_name, arg, context=None):
+ res = {}
+ for account in self.browse(cr, SUPERUSER_ID, ids, context):
+ text = 'Configured parallel accounts:\n'
+ text2 = ''
+ for parallel_account in account.parallel_account_ids:
+ text2 += _('Account code: %s. Company: %s\n') % (
+ parallel_account.code, parallel_account.company_id.name)
+ if text2:
+ res[account.id] = text + text2
+ else:
+ res[account.id] = _("No parallel accounts found")
+ return res
+
+ _columns = {
+ 'parallel_account_ids': fields.many2many('account.account',
+ 'parallel_account_rel', 'parent_id',
+ 'child_id', 'Parallel Currency Accounts',
+ Help="""Set here the accounts you want to automatically move when
+ registering entries in this account"""),
+ 'master_parallel_account_ids': fields.many2many('account.account',
+ 'parallel_account_rel', 'child_id',
+ 'parent_id', 'Master Parallel Currency Accounts',
+ Help="You can see here the accounts that automatically move this account",
+ readonly=True),
+ 'parallel_accounts_summary': fields.function(
+ _get_parallel_accounts_summary, type='text',
+ string='Parallel accounts summary'),
+ }
+
+ def _search_parallel_account(self, cr, uid, account_code, parallel_company,
+ context=None):
+ parallel_acc_ids = self.search(cr, uid, [
+ ('company_id', '=', parallel_company.id),
+ ('code', '=', account_code),
+ ], context=context)
+ if len(parallel_acc_ids) > 1:
+ raise orm.except_orm(_('Error'), _('Too many accounts %s for company %s')
+ % (account_code, parallel_company.name))
+ return parallel_acc_ids and parallel_acc_ids[0] or False
+
+ def _build_account_vals(self, cr, uid, account_vals, parallel_company, context=None):
+ # build only fields I need
+ vals = {}
+ if 'name' in account_vals:
+ vals['name'] = account_vals['name']
+ if 'code' in account_vals:
+ vals['code'] = account_vals['code']
+ if 'type' in account_vals:
+ vals['type'] = account_vals['type']
+ if 'user_type' in account_vals:
+ vals['user_type'] = account_vals['user_type']
+ if 'active' in account_vals:
+ vals['active'] = account_vals['active']
+ if 'centralized' in account_vals:
+ vals['centralized'] = account_vals['centralized']
+ if 'parent_id' in account_vals:
+ parent_account = self.browse(cr, uid, account_vals['parent_id'], context)
+ parent_parallel_acc_id = self._search_parallel_account(
+ cr, uid, parent_account.code, parallel_company, context=context)
+ if not parent_parallel_acc_id:
+ raise orm.except_orm(_('Error'),
+ _('No parent account %s found in company %s') %
+ (parent_account.code, parallel_company.name))
+ vals['parent_id'] = parent_parallel_acc_id
+ return vals
+
+ def create_parallel_accounts(self, cr, uid, ids, context=None):
+ for account in self.browse(cr, SUPERUSER_ID, ids, context):
+ for parallel_company in account.company_id.parallel_company_ids:
+ parent_parallel_acc_id = self._search_parallel_account(
+ cr, SUPERUSER_ID, account.parent_id.code, parallel_company,
+ context=context)
+ new_id = self.create(cr, SUPERUSER_ID, {
+ 'company_id': parallel_company.id,
+ 'parent_id': parent_parallel_acc_id,
+ 'name': account.name,
+ 'code': account.code,
+ 'type': account.type,
+ 'user_type': account.user_type and account.user_type.id or False,
+ 'active': account.active,
+ 'centralized': account.centralized,
+ })
+ cr.execute("insert into parallel_account_rel(parent_id,child_id) values (%d,%d)"
+ % (account.id, new_id))
+ return True
+
+ '''
+ def sync_parallel_accounts(self, cr, uid, ids, vals={}, context=None):
+ for account in self.browse(cr, uid, ids, context):
+ new_parallel_acc_ids = []
+ company_id = vals.get('company_id') or account.company_id.id
+ code = vals.get('code') or account.code
+ company = self.pool.get('res.company').browse(cr, uid, company_id, context)
+ for parallel_company in company.parallel_company_ids:
+ parallel_acc_id = self._search_parallel_account(
+ cr, uid, code, parallel_company, context=context)
+ if not parallel_acc_id:
+ # Then I create it, linked to parent account
+ #parallel_acc_id = self.create(cr, uid,
+ #self._build_account_vals(cr, uid,
+ #vals, parallel_company, context=context), context=context)
+ pass
+ else:
+ super(account_account,self).write(cr, uid, [parallel_acc_id],
+ self._build_account_vals(cr, uid,
+ vals, parallel_company, context=context), context)
+ _logger.info(
+ _("Parallel account %s (company %s) written") %
+ (code, parallel_company.name))
+ new_parallel_acc_ids.append(parallel_acc_id)
+ return new_parallel_acc_ids
+ '''
+
+ def write(self, cr, uid, ids, vals, context=None):
+ if 'parallel_account_ids' not in vals:
+ # write/create parallel accounts only if 'parallel_account_ids' not explicity written
+ for acc_id in ids:
+ account = self.browse(cr, SUPERUSER_ID, acc_id, context)
+ for parallel_account in account.parallel_account_ids:
+ parallel_vals = self._build_account_vals(
+ cr, SUPERUSER_ID, vals, parallel_account.company_id,
+ context=context)
+ parallel_account.write(parallel_vals)
+ res=super(account_account,self).write(cr, uid, ids, vals, context=context)
+ return res
+
+ def create(self, cr, uid, vals, context=None):
+ res=super(account_account,self).create(cr, uid, vals, context)
+ self.create_parallel_accounts(cr, uid, [res], context=None)
+ return res
+
+ def unlink(self, cr, uid, ids, context=None):
+ for account in self.browse(cr, SUPERUSER_ID, ids, context):
+ for parallel_account in account.parallel_account_ids:
+ parallel_account.unlink()
+ res=super(account_account,self).unlink(cr, uid, ids, context=context)
+ return res
+
+class account_move(orm.Model):
+ _inherit = "account.move"
+
+ _columns = {
+ 'parallel_move_ids': fields.one2many('account.move', 'master_parallel_move_id', 'Parallel Entries',
+ readonly=True),
+ 'master_parallel_move_id': fields.many2one('account.move', 'Master Parallel Entry'),
+ }
+
+ def button_cancel(self, cr, uid, ids, context=None):
+ res = super(account_move, self).button_cancel(cr, uid, ids, context=context)
+ for move in self.browse(cr, SUPERUSER_ID, ids, context=context):
+ for parallel_move in move.parallel_move_ids:
+ parallel_move.button_cancel(context=context)
+ parallel_move.unlink(context=context)
+ return res
+
+ def lines_balance(self, move_lines):
+ """
+ returns 0 if lines are balanced, difference if unbalanced
+ """
+ balance = 0.0
+ for line_tuple in move_lines:
+ balance += line_tuple[2]['debit'] or (- line_tuple[2]['credit']) or 0.0
+ return balance
+
+ def balance_lines(self, cr, uid, move_lines, currency_id, context=None):
+ """
+ Balance move lines that were unbalanced due to roundings.
+ """
+ balance = self.lines_balance(move_lines)
+ acc_pool = self.pool.get('account.account')
+ curr_pool = self.pool.get('res.currency')
+ if curr_pool.is_zero(cr, uid, curr_pool.browse(cr, uid, currency_id), balance):
+ return move_lines
+ else:
+ found = False
+ for line_tuple in move_lines:
+ account = acc_pool.browse(cr, uid, line_tuple[2]['account_id'], context)
+ # search for liquidity, receivable or payable accounts
+ # beacause usually they are the result of operations (invoice total).
+ # So, if we made the invoice in parallel currency, we'd get that different invoice total
+ if account.type == 'liquidity' or account.type == 'receivable' or account.type == 'payable':
+ if line_tuple[2]['debit']:
+ line_tuple[2]['debit'] -= balance
+ found = True
+ break
+ elif line_tuple[2]['credit']:
+ line_tuple[2]['credit'] += balance
+ found = True
+ break
+ if not found:
+ # if no liquidity, receivable or payable accounts are present, we use the first line (randomly).
+ # TODO check if this makes sense
+ if move_lines[0][2]['debit']:
+ move_lines[0][2]['debit'] -= balance
+ elif move_lines[0][2]['credit']:
+ move_lines[0][2]['credit'] += balance
+ return move_lines
+
+ def post(self, cr, uid, ids, context=None):
+ res = super(account_move, self).post(cr, uid, ids, context=context)
+ if context is None:
+ context = {}
+ curr_pool = self.pool.get('res.currency')
+ company_pool = self.pool.get('res.company')
+ uid = SUPERUSER_ID
+ for move in self.browse(cr, uid, ids, context=context):
+ if move.state == 'posted' and not move.parallel_move_ids:
+ # avoid double post in case of 'Skip Draft State for Manual Entries'
+ new_move_lines = []
+ parallel_data = {}
+ for line in move.line_id:
+ for parallel_account in line.account_id.parallel_account_ids:
+ parallel_data[parallel_account.company_id.id] = {}
+ parallel_data[parallel_account.company_id.id]['move_name'] = line.move_id.name
+ parallel_data[parallel_account.company_id.id]['ref'] = line.move_id.ref
+ parallel_data[parallel_account.company_id.id]['date'] = line.date
+ parallel_data[parallel_account.company_id.id]['move_id'] = line.move_id.id
+
+ # search period by code and parallel company
+ period_ids = self.pool.get('account.period').search(cr, uid, [
+ ('code','=',line.period_id.code),
+ ('company_id', '=', parallel_account.company_id.id),
+ ])
+
+ if len(period_ids) == 0:
+ raise orm.except_orm(_('Error !'), _('Period %s does not exist in company %s !')
+ % (line.period_id.code, parallel_account.company_id.name))
+ if len(period_ids) > 1:
+ raise orm.except_orm(_('Error !'), _('Too many periods %s for company %s !')
+ % (line.period_id.code, parallel_account.company_id.name))
+
+ parallel_data[parallel_account.company_id.id]['period_id'] = period_ids[0]
+
+ # search parallel journals for the parallel company
+ parallel_journal_ids = []
+ for journal in line.journal_id.parallel_journal_ids:
+ if journal.company_id.id == parallel_account.company_id.id:
+ parallel_journal_ids.append(journal.id)
+
+ if len(parallel_journal_ids) == 0:
+ raise orm.except_orm(_('Error !'), _('Journal %s does not exist in company %s !')
+ % (line.journal_id.name, parallel_account.company_id.name))
+ if len(parallel_journal_ids) > 1:
+ raise orm.except_orm(_('Error !'), _('Too many journals %s for company %s !')
+ % (line.journal_id.name, parallel_account.company_id.name))
+
+ parallel_data[parallel_account.company_id.id]['journal_id'] = parallel_journal_ids[0]
+
+ new_line_values = {
+ 'name': line.name,
+ 'date_maturity': line.date_maturity or False,
+ 'account_id': parallel_account.id,
+ 'period_id': period_ids[0],
+ 'journal_id': parallel_journal_ids[0],
+ 'company_id': parallel_account.company_id.id,
+ 'partner_id': line.partner_id and line.partner_id.id or False,
+ }
+
+ if line.currency_id and line.amount_currency:
+ parallel_sec_curr_iso_code = line.currency_id.name
+ amount = line.amount_currency
+ else:
+ parallel_sec_curr_iso_code = line.company_id.currency_id.name
+ amount = line.debit or ( - line.credit)
+
+ parallel_base_amount = amount
+ if parallel_sec_curr_iso_code != parallel_account.company_id.currency_id.name:
+ # only if parallel company currency is != master move currency
+ # search parallel currency by ISO code and parallel company
+ parallel_secondary_curr_ids = curr_pool.search(cr, uid, [
+ ('name', '=', parallel_sec_curr_iso_code),
+ ('company_id', '=', parallel_account.company_id.id),
+ ], context=context)
+
+ if len(parallel_secondary_curr_ids) == 0:
+ raise orm.except_orm(_('Error !'), _('Currency %s does not exist in company %s !')
+ % (parallel_sec_curr_iso_code, parallel_account.company_id.name))
+ if len(parallel_secondary_curr_ids) > 1:
+ raise orm.except_orm(_('Error !'), _('Too many currencies %s for company %s !')
+ % (parallel_sec_curr_iso_code, parallel_account.company_id.name))
+
+ # compute parallel base amount from document currency, using move date
+ context.update({'date': line.date})
+ parallel_base_amount = curr_pool.compute(cr, uid, parallel_secondary_curr_ids[0],
+ parallel_account.company_id.currency_id.id, amount,
+ context=context)
+
+ new_line_values['amount_currency'] = amount
+ new_line_values['currency_id'] = parallel_secondary_curr_ids[0]
+
+ new_line_values['debit'] = 0.0
+ new_line_values['credit'] = 0.0
+ if parallel_base_amount > 0:
+ new_line_values['debit'] = abs(parallel_base_amount)
+ elif parallel_base_amount < 0:
+ new_line_values['credit'] = abs(parallel_base_amount)
+
+ if line.tax_code_id and line.tax_amount:
+ # search parallel tax codes for the parallel company
+ parallel_tax_code_ids = []
+ for tax_code in line.tax_code_id.parallel_tax_code_ids:
+ if tax_code.company_id.id == parallel_account.company_id.id:
+ parallel_tax_code_ids.append(tax_code.id)
+
+ if len(parallel_tax_code_ids) == 0:
+ raise orm.except_orm(_('Error !'), _('Tax code %s does not exist in company %s !')
+ % (line.tax_code_id.name, parallel_account.company_id.name))
+ if len(parallel_tax_code_ids) > 1:
+ raise orm.except_orm(_('Error !'), _('Too many tax_codes %s for company %s !')
+ % (line.tax_code_id.name, parallel_account.company_id.name))
+
+ new_line_values['tax_code_id'] = parallel_tax_code_ids[0]
+ total_tax = new_line_values['debit'] - new_line_values['credit']
+ new_line_values['tax_amount'] = line.tax_amount < 0 \
+ and - abs(total_tax) \
+ or line.tax_amount > 0 \
+ and abs(total_tax) \
+ or 0.0
+
+ new_move_lines.append((parallel_account.company_id.id, (0,0,new_line_values)))
+ #parallel_data[parallel_account.company_id.id]['move_lines'].append((0,0,new_line_values))
+
+ for company_id in parallel_data:
+ move_lines = []
+ for new_move_line in new_move_lines:
+ if new_move_line[0] == company_id:
+ move_lines.append(new_move_line[1])
+ move_lines=self.balance_lines(cr, uid, move_lines, company_pool.browse(cr, uid, company_id).currency_id.id, context=context)
+ move_values = {
+ 'name': parallel_data[company_id]['move_name'],
+ 'period_id': parallel_data[company_id]['period_id'],
+ 'journal_id': parallel_data[company_id]['journal_id'],
+ 'date': parallel_data[company_id]['date'],
+ 'company_id': company_id,
+ 'line_id': move_lines,
+ 'master_parallel_move_id': parallel_data[company_id]['move_id'],
+ 'ref': parallel_data[company_id]['ref'],
+ }
+ self.create(cr, uid, move_values, context=context)
+ # self.post(cr, uid, [move_id], context=context)
+
+ return res
+
+
+class account_journal(orm.Model):
+ _inherit = "account.journal"
+
+ _columns = {
+ 'parallel_journal_ids': fields.many2many('account.journal',
+ 'parallel_journal_rel', 'parent_id',
+ 'child_id', 'Parallel Currency Journals',
+ Help="Set here the journals you want to automatically move when registering entries in this journal"),
+ 'master_parallel_journal_ids': fields.many2many('account.journal',
+ 'parallel_journal_rel', 'child_id',
+ 'parent_id', 'Master Parallel Currency Journals',
+ Help="You can see here the journals that automatically move this journal", readonly=True),
+ }
+
+class account_tax_code(orm.Model):
+ _inherit = "account.tax.code"
+
+ def _get_parallel_tax_codes_summary(self, cr, uid, ids, field_name, arg, context=None):
+ res={}
+ for tax_code in self.browse(cr, SUPERUSER_ID, ids, context):
+ text='Configured parallel tax codes:\n'
+ text2=''
+ for parallel_tax_code in tax_code.parallel_tax_code_ids:
+ text2+= _('Tax code: %s. Company: %s\n') % (
+ parallel_tax_code.code, parallel_tax_code.company_id.name)
+ if text2:
+ res[tax_code.id] = text + text2
+ else:
+ res[tax_code.id] = _("No parallel tax codes found")
+ return res
+
+ _columns = {
+ 'parallel_tax_code_ids': fields.many2many('account.tax.code',
+ 'parallel_tax_code_rel', 'parent_id',
+ 'child_id', 'Parallel Currency Tax Codes',
+ Help="Set here the tax codes you want to automatically move when registering entries in this tax code"),
+ 'master_parallel_tax_code_ids': fields.many2many('account.tax.code',
+ 'parallel_tax_code_rel', 'child_id',
+ 'parent_id', 'Master Parallel Currency Tax Codes',
+ Help="You can see here the tax codes that automatically move this journal", readonly=True),
+ 'parallel_tax_codes_summary': fields.function(_get_parallel_tax_codes_summary, type='text', string='Parallel tax codes summary'),
+ }
+
+ def _search_parallel_tax_code(self, cr, uid, tax_code, parallel_company,
+ context=None):
+ parallel_tax_code_ids = self.search(cr, uid, [
+ ('company_id','=', parallel_company.id),
+ ('code','=', tax_code),
+ ], context=context)
+ if len(parallel_tax_code_ids) > 1:
+ raise orm.except_orm(_('Error'), _('Too many tax codes %s for company %s')
+ % (tax_code,parallel_company.name))
+ return parallel_tax_code_ids and parallel_tax_code_ids[0] or False
+
+ def _build_tax_code_vals(self, cr, uid, tax_code_vals, parallel_company, context=None):
+ # build only fields I need
+ vals={}
+ if tax_code_vals.has_key('name'):
+ vals['name'] = tax_code_vals['name']
+ if tax_code_vals.has_key('code'):
+ vals['code'] = tax_code_vals['code']
+ if tax_code_vals.has_key('type'):
+ vals['type'] = tax_code_vals['type']
+ if tax_code_vals.has_key('user_type'):
+ vals['user_type'] = tax_code_vals['user_type']
+ if tax_code_vals.has_key('active'):
+ vals['active'] = tax_code_vals['active']
+ if tax_code_vals.has_key('centralized'):
+ vals['centralized'] = tax_code_vals['centralized']
+ if tax_code_vals.has_key('parent_id'):
+ parent_tax_code = self.browse(cr, uid, tax_code_vals['parent_id'], context)
+ parent_parallel_acc_id = self._search_parallel_tax_code(
+ cr, uid, parent_tax_code.code, parallel_company, context=context)
+ if not parent_parallel_acc_id:
+ raise orm.except_orm(_('Error'),
+ _('No parent tax code %s found in company %s') %
+ (parent_tax_code.code, parallel_company.name))
+ vals['parent_id'] = parent_parallel_acc_id
+ return vals
+
+ def create_parallel_tax_codes(self, cr, uid, ids, context=None):
+ for tax_code in self.browse(cr, SUPERUSER_ID, ids, context):
+ for parallel_company in tax_code.company_id.parallel_company_ids:
+ if not tax_code.parent_id:
+ raise orm.except_orm(_('Error'),_('Tax code %s does not have parent')
+ % tax_code.code)
+ existing_ids = self.search(cr, SUPERUSER_ID, [
+ ('code', '=', tax_code.code),
+ ('company_id', '=', parallel_company.id),
+ ])
+ if existing_ids:
+ raise orm.except_orm(_('Error'),
+ _('Tax code %s already exists for company %s')
+ % (tax_code.code, parallel_company.name))
+ parent_parallel_tax_code_id = self._search_parallel_tax_code(
+ cr, SUPERUSER_ID, tax_code.parent_id.code, parallel_company,
+ context=context)
+ new_id = self.create(cr, SUPERUSER_ID,{
+ 'company_id': parallel_company.id,
+ 'parent_id': parent_parallel_tax_code_id,
+ 'name': tax_code.name,
+ 'code': tax_code.code,
+ 'notprintable': tax_code.notprintable,
+ 'sign': tax_code.sign,
+ 'info': tax_code.info,
+ })
+ cr.execute(
+ "insert into parallel_tax_code_rel(parent_id,child_id) values (%d,%d)"
+ % (tax_code.id,new_id))
+ return True
+
+ def write(self, cr, uid, ids, vals, context=None):
+ if not vals.has_key('parallel_tax_code_ids'):
+ # write/create parallel tax codes only if 'parallel_tax_code_ids' not explicity written
+ for tax_code_id in ids:
+ tax_code = self.browse(cr, SUPERUSER_ID, tax_code_id, context)
+ for parallel_tax_code in tax_code.parallel_tax_code_ids:
+ parallel_vals = self._build_tax_code_vals(
+ cr, SUPERUSER_ID, vals, parallel_tax_code.company_id, context=context)
+ parallel_tax_code.write(parallel_vals)
+ res=super(account_tax_code,self).write(cr, uid, ids, vals, context=context)
+ return res
+
+ def create(self, cr, uid, vals, context=None):
+ res=super(account_tax_code,self).create(cr, uid, vals, context)
+ self.create_parallel_tax_codes(cr, uid, [res], context=None)
+ return res
=== added file 'account_parallel_currency/account_demo.xml'
--- account_parallel_currency/account_demo.xml 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/account_demo.xml 2014-04-17 13:57:59 +0000
@@ -0,0 +1,504 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+
+ <!--
+ Parallel company
+ -->
+
+ <record id="parallel_company" model="res.company">
+ <field name="name" >Parallel company</field>
+ <field name="currency_id" ref="base.CHF"></field>
+ </record>
+
+ <record id="base.main_company" model="res.company">
+ <field name="parallel_company_ids" eval="[(6,0,[ref('parallel_company')])]"></field>
+ </record>
+
+ <!--
+ currencies
+ -->
+
+ <record id="USD" model="res.currency">
+ <field name="name">USD</field>
+ <field name="symbol">$</field>
+ <field name="rounding">0.01</field>
+ <field name="accuracy">4</field>
+ <field name="position">before</field>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+ <record id="rateUSD" model="res.currency.rate">
+ <field name="rate">1.2834</field>
+ <field name="currency_id" ref="USD"/>
+ <field eval="time.strftime('%Y-01-01')" name="name"/>
+ </record>
+ <record id="CHF" model="res.currency">
+ <field name="name">CHF</field>
+ <field name="symbol">CHF</field>
+ <field name="rounding">0.01</field>
+ <field name="accuracy">4</field>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+ <record id="rateCHF" model="res.currency.rate">
+ <field name="rate">1.3086</field>
+ <field name="currency_id" ref="CHF"/>
+ <field eval="time.strftime('%Y-01-01')" name="name"/>
+ </record>
+ <record id="EUR" model="res.currency">
+ <field name="name">EUR</field>
+ <field name="symbol">€</field>
+ <field name="rounding">0.01</field>
+ <field name="accuracy">4</field>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+ <record id="rateEUR" model="res.currency.rate">
+ <field name="currency_id" ref="EUR" />
+ <field eval="time.strftime('%Y-01-01')" name="name"/>
+ <field name="rate">1.0</field>
+ </record>
+
+ <!--
+ Journal
+ -->
+
+ <record id="parallel_sales_journal" model="account.journal">
+ <field name="name">Parallel Sales Journal - (test)</field>
+ <field name="code">PSAJ</field>
+ <field name="type">sale</field>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+ <record id="account.sales_journal" model="account.journal">
+ <field name="parallel_journal_ids" eval="[(6,0,[ref('parallel_sales_journal')])]"></field>
+ </record>
+
+ <!--
+ Fiscal year
+ -->
+
+ <record id="data_fiscalyear" model="account.fiscalyear">
+ <field eval="'Fiscal Year X '+time.strftime('%Y')" name="name"/>
+ <field eval="'FY'+time.strftime('%Y')" name="code"/>
+ <field eval="time.strftime('%Y')+'-01-01'" name="date_start"/>
+ <field eval="time.strftime('%Y')+'-12-31'" name="date_stop"/>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+
+ <!--
+ Fiscal Periods
+ -->
+
+ <record id="period_1" model="account.period">
+ <field eval="'01/'+time.strftime('%Y')" name="code"/>
+ <field eval="'X 01/'+time.strftime('%Y')" name="name"/>
+ <field eval="True" name="special"/>
+ <field name="fiscalyear_id" ref="data_fiscalyear"/>
+ <field eval="time.strftime('%Y')+'-01-01'" name="date_start"/>
+ <field eval="time.strftime('%Y')+'-01-31'" name="date_stop"/>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+ <record id="period_2" model="account.period">
+ <field eval="'02/'+time.strftime('%Y')" name="code"/>
+ <field eval="'X 02/'+time.strftime('%Y')" name="name"/>
+ <field eval="True" name="special"/>
+ <field name="fiscalyear_id" ref="data_fiscalyear"/>
+ <field eval="time.strftime('%Y')+'-02-01'" name="date_start"/>
+ <!-- for the last day of February, we have to compute the day before March 1st -->
+ <field eval="(DateTime.today().replace(month=3, day=1) - timedelta(days=1)).strftime('%Y-%m-%d')" name="date_stop"/>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+ <record id="period_3" model="account.period">
+ <field eval="'03/'+time.strftime('%Y')" name="code"/>
+ <field eval="'X 03/'+time.strftime('%Y')" name="name"/>
+ <field eval="True" name="special"/>
+ <field name="fiscalyear_id" ref="data_fiscalyear"/>
+ <field eval="time.strftime('%Y')+'-03-01'" name="date_start"/>
+ <field eval="time.strftime('%Y')+'-03-31'" name="date_stop"/>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+ <record id="period_4" model="account.period">
+ <field eval="'04/'+time.strftime('%Y')" name="code"/>
+ <field eval="'X 04/'+time.strftime('%Y')" name="name"/>
+ <field eval="True" name="special"/>
+ <field name="fiscalyear_id" ref="data_fiscalyear"/>
+ <field eval="time.strftime('%Y')+'-04-01'" name="date_start"/>
+ <field eval="time.strftime('%Y')+'-04-30'" name="date_stop"/>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+ <record id="period_5" model="account.period">
+ <field eval="'05/'+time.strftime('%Y')" name="code"/>
+ <field eval="'X 05/'+time.strftime('%Y')" name="name"/>
+ <field eval="True" name="special"/>
+ <field name="fiscalyear_id" ref="data_fiscalyear"/>
+ <field eval="time.strftime('%Y')+'-05-01'" name="date_start"/>
+ <field eval="time.strftime('%Y')+'-05-31'" name="date_stop"/>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+ <record id="period_6" model="account.period">
+ <field eval="'06/'+time.strftime('%Y')" name="code"/>
+ <field eval="'X 06/'+time.strftime('%Y')" name="name"/>
+ <field name="fiscalyear_id" ref="data_fiscalyear"/>
+ <field eval="True" name="special"/>
+ <field eval="time.strftime('%Y')+'-06-01'" name="date_start"/>
+ <field eval="time.strftime('%Y')+'-06-30'" name="date_stop"/>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+ <record id="period_7" model="account.period">
+ <field eval="'07/'+time.strftime('%Y')" name="code"/>
+ <field eval="'X 07/'+time.strftime('%Y')" name="name"/>
+ <field eval="True" name="special"/>
+ <field name="fiscalyear_id" ref="data_fiscalyear"/>
+ <field eval="time.strftime('%Y')+'-07-01'" name="date_start"/>
+ <field eval="time.strftime('%Y')+'-07-31'" name="date_stop"/>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+ <record id="period_8" model="account.period">
+ <field eval="'08/'+time.strftime('%Y')" name="code"/>
+ <field eval="'X 08/'+time.strftime('%Y')" name="name"/>
+ <field eval="True" name="special"/>
+ <field name="fiscalyear_id" ref="data_fiscalyear"/>
+ <field eval="time.strftime('%Y')+'-08-01'" name="date_start"/>
+ <field eval="time.strftime('%Y')+'-08-31'" name="date_stop"/>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+ <record id="period_9" model="account.period">
+ <field eval="'09/'+time.strftime('%Y')" name="code"/>
+ <field eval="'X 09/'+time.strftime('%Y')" name="name"/>
+ <field eval="True" name="special"/>
+ <field name="fiscalyear_id" ref="data_fiscalyear"/>
+ <field eval="time.strftime('%Y')+'-09-01'" name="date_start"/>
+ <field eval="time.strftime('%Y')+'-09-30'" name="date_stop"/>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+ <record id="period_10" model="account.period">
+ <field eval="'10/'+time.strftime('%Y')" name="code"/>
+ <field eval="'X 10/'+time.strftime('%Y')" name="name"/>
+ <field eval="True" name="special"/>
+ <field name="fiscalyear_id" ref="data_fiscalyear"/>
+ <field eval="time.strftime('%Y')+'-10-01'" name="date_start"/>
+ <field eval="time.strftime('%Y')+'-10-31'" name="date_stop"/>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+ <record id="period_11" model="account.period">
+ <field eval="'11/'+time.strftime('%Y')" name="code"/>
+ <field eval="'X 11/'+time.strftime('%Y')" name="name"/>
+ <field eval="True" name="special"/>
+ <field name="fiscalyear_id" ref="data_fiscalyear"/>
+ <field eval="time.strftime('%Y')+'-11-01'" name="date_start"/>
+ <field eval="time.strftime('%Y')+'-11-30'" name="date_stop"/>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+ <record id="period_12" model="account.period">
+ <field eval="'12/'+time.strftime('%Y')" name="code"/>
+ <field eval="'X 12/'+time.strftime('%Y')" name="name"/>
+ <field eval="True" name="special"/>
+ <field name="fiscalyear_id" ref="data_fiscalyear"/>
+ <field eval="time.strftime('%Y')+'-12-01'" name="date_start"/>
+ <field eval="time.strftime('%Y')+'-12-31'" name="date_stop"/>
+ <field name="company_id" ref="parallel_company"/>
+ </record>
+
+ <!--
+ Chart of Accounts
+ -->
+
+ <record id="chart0" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X0</field>
+ <field name="name">Chart For Automated Tests</field>
+ <field name="type">view</field>
+ <field name="user_type" ref="account.data_account_type_view"/>
+ </record>
+
+ <!-- Balance Sheet -->
+
+ <record id="bal" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X1</field>
+ <field name="name">Balance Sheet - (test)</field>
+ <field ref="chart0" name="parent_id"/>
+ <field name="type">view</field>
+ <field name="user_type" ref="account.data_account_type_view"/>
+ </record>
+
+ <record model="account.account" id="assets_view">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="name">Assets - (test)</field>
+ <field name="code">X10</field>
+ <field name="type">view</field>
+ <field name="user_type" ref="account.data_account_type_asset"/>
+ <field name="reconcile" eval="False"/>
+ <field name="parent_id" ref="bal"/>
+ </record>
+
+ <record id="fas" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X100</field>
+ <field name="name">Fixed Assets - (test)</field>
+ <field ref="assets_view" name="parent_id"/>
+ <field name="type">view</field>
+ <field name="user_type" ref="account.data_account_type_asset"/>
+ </record>
+
+ <record id="xfa" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X1000</field>
+ <field name="name">Fixed Asset Account - (test)</field>
+ <field ref="fas" name="parent_id"/>
+ <field name="type">other</field>
+ <field name="user_type" ref="account.data_account_type_asset"/>
+ </record>
+
+ <record id="nca" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X101</field>
+ <field name="name">Net Current Assets - (test)</field>
+ <field ref="assets_view" name="parent_id"/>
+ <field name="type">view</field>
+ <field name="user_type" ref="account.data_account_type_asset"/>
+ </record>
+
+ <record id="cas" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X1100</field>
+ <field name="name">Current Assets - (test)</field>
+ <field ref="nca" name="parent_id"/>
+ <field name="type">view</field>
+ <field name="user_type" ref="account.data_account_type_asset"/>
+ </record>
+
+ <record id="stk" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X11001</field>
+ <field name="name">Purchased Stocks - (test)</field>
+ <field ref="cas" name="parent_id"/>
+ <field name="type">other</field>
+ <field name="user_type" ref="account.data_account_type_asset"/>
+ </record>
+
+ <record id="a_recv" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X11002</field>
+ <field name="name">Debtors - (test)</field>
+ <field ref="cas" name="parent_id"/>
+ <field name="type">receivable</field>
+ <field eval="True" name="reconcile"/>
+ <field name="user_type" ref="account.data_account_type_receivable"/>
+ </record>
+
+ <record id="ova" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X11003</field>
+ <field name="name">Output VAT - (test)</field>
+ <field ref="cas" name="parent_id"/>
+ <field name="type">other</field>
+ <field name="user_type" ref="account.data_account_type_asset"/>
+ </record>
+
+ <record id="bnk" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X11004</field>
+ <field name="name">Bank Current Account - (test)</field>
+ <field ref="cas" name="parent_id"/>
+ <field name="type">liquidity</field>
+ <field name="user_type" ref="account.data_account_type_asset"/>
+ </record>
+
+ <record id="cash" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X11005</field>
+ <field name="name">Cash - (test)</field>
+ <field ref="cas" name="parent_id"/>
+ <field name="type">liquidity</field>
+ <field name="user_type" ref="account.data_account_type_asset"/>
+ </record>
+
+ <record id="o_income" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X11006</field>
+ <field name="name">Opening Income - (test)</field>
+ <field ref="cas" name="parent_id"/>
+ <field name="type">other</field>
+ <field name="user_type" ref="account.data_account_type_income"/>
+ </record>
+ <record id="usd_bnk" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X11007</field>
+ <field name="name">USD Bank Account - (test)</field>
+ <field ref="cas" name="parent_id"/>
+ <field name="type">liquidity</field>
+ <field name="user_type" ref="account.data_account_type_asset"/>
+ <field name="currency_id" ref="base.USD"/>
+ </record>
+
+ <record model="account.account" id="liabilities_view">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="name">Liabilities - (test)</field>
+ <field name="code">X11</field>
+ <field name="type">view</field>
+ <field name="user_type" ref="account.data_account_type_liability"/>
+ <field name="reconcile" eval="False"/>
+ <field name="parent_id" ref="bal"/>
+ </record>
+
+ <record id="cli" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X110</field>
+ <field name="name">Current Liabilities - (test)</field>
+ <field ref="liabilities_view" name="parent_id"/>
+ <field name="type">view</field>
+ <field name="user_type" ref="account.data_account_type_liability"/>
+ </record>
+
+ <record id="a_pay" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X1111</field>
+ <field name="name">Creditors - (test)</field>
+ <field ref="cli" name="parent_id"/>
+ <field name="type">payable</field>
+ <field eval="True" name="reconcile"/>
+ <field name="user_type" ref="account.data_account_type_payable"/>
+ </record>
+
+ <record id="iva" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X1112</field>
+ <field name="name">Input VAT - (test)</field>
+ <field ref="cli" name="parent_id"/>
+ <field name="type">other</field>
+ <field name="user_type" ref="account.data_account_type_liability"/>
+ </record>
+
+ <record id="rsa" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X1113</field>
+ <field name="name">Reserve and Profit/Loss - (test)</field>
+ <field ref="cli" name="parent_id"/>
+ <field name="type">other</field>
+ <field name="user_type" ref="account.data_account_type_liability"/>
+ </record>
+
+ <record id="o_expense" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X1114</field>
+ <field name="name">Opening Expense - (test)</field>
+ <field ref="cli" name="parent_id"/>
+ <field name="type">other</field>
+ <field name="user_type" ref="account.data_account_type_expense"/>
+ </record>
+
+ <!-- Profit and Loss -->
+
+ <record id="gpf" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X2</field>
+ <field name="name">Profit and Loss - (test)</field>
+ <field ref="chart0" name="parent_id"/>
+ <field name="type">view</field>
+ <field name="user_type" ref="account.data_account_type_view"/>
+ </record>
+
+ <record model="account.account" id="income_view">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="name">Income - (test)</field>
+ <field name="code">X20</field>
+ <field name="type">view</field>
+ <field name="user_type" ref="account.data_account_type_income"/>
+ <field name="reconcile" eval="False"/>
+ <field name="parent_id" ref="gpf"/>
+ </record>
+
+ <record model="account.account" id="income_fx_income">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="name">Foreign Exchange Gain - (test)</field>
+ <field name="code">X201</field>
+ <field name="type">other</field>
+ <field name="user_type" ref="account.data_account_type_income"/>
+ <field name="reconcile" eval="False"/>
+ <field name="parent_id" ref="income_view"/>
+ </record>
+
+ <record id="rev" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X200</field>
+ <field name="name">Revenue - (test)</field>
+ <field ref="income_view" name="parent_id"/>
+ <field name="type">view</field>
+ <field name="user_type" ref="account.data_account_type_income"/>
+ </record>
+
+ <record id="a_sale" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X2001</field>
+ <field name="name">Product Sales - (test)</field>
+ <field ref="rev" name="parent_id"/>
+ <field name="type">other</field>
+ <field name="user_type" ref="account.data_account_type_income"/>
+ </record>
+
+ <record model="account.account" id="expense_view">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="name">Expense - (test)</field>
+ <field name="code">X21</field>
+ <field name="type">view</field>
+ <field name="user_type" ref="account.data_account_type_expense"/>
+ <field name="reconcile" eval="False"/>
+ <field name="parent_id" ref="gpf"/>
+ </record>
+
+
+ <record id="cos" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X210</field>
+ <field name="name">Cost of Sales - (test)</field>
+ <field ref="expense_view" name="parent_id"/>
+ <field name="type">view</field>
+ <field name="user_type" ref="account.data_account_type_expense"/>
+ </record>
+
+ <record id="cog" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X2100</field>
+ <field name="name">Cost of Goods Sold - (test)</field>
+ <field ref="cos" name="parent_id"/>
+ <field name="type">other</field>
+ <field name="user_type" ref="account.data_account_type_expense"/>
+ </record>
+
+ <record id="ovr" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X211</field>
+ <field name="name">Overheads - (test)</field>
+ <field ref="expense_view" name="parent_id"/>
+ <field name="type">view</field>
+ <field name="user_type" ref="account.data_account_type_expense"/>
+ </record>
+
+ <record id="a_expense" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X2110</field>
+ <field name="name">Expenses - (test)</field>
+ <field ref="ovr" name="parent_id"/>
+ <field name="type">other</field>
+ <field name="user_type" ref="account.data_account_type_expense"/>
+ </record>
+
+ <record model="account.account" id="income_fx_expense">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="name">Foreign Exchange Loss - (test)</field>
+ <field name="code">X2111</field>
+ <field name="type">other</field>
+ <field name="user_type" ref="account.data_account_type_expense"/>
+ <field name="reconcile" eval="False"/>
+ <field name="parent_id" ref="ovr"/>
+ </record>
+
+ <record id="a_salary_expense" model="account.account">
+ <field name="company_id" ref="parallel_company"/>
+ <field name="code">X2112</field>
+ <field name="name">Salary Expenses - (test)</field>
+ <field ref="ovr" name="parent_id"/>
+ <field name="type">other</field>
+ <field name="user_type" ref="account.data_account_type_expense"/>
+ </record>
+ </data>
+</openerp>
=== added file 'account_parallel_currency/account_view.xml'
--- account_parallel_currency/account_view.xml 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/account_view.xml 2014-04-17 13:57:59 +0000
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+ <record id="view_account_form" model="ir.ui.view">
+ <field name="name">account.account.form</field>
+ <field name="model">account.account</field>
+ <field name="inherit_id" ref="account.view_account_form"></field>
+ <field name="arch" type="xml">
+ <field name="note" position="after">
+ <group colspan="4" string="Parallel Currency" groups="account.group_account_manager">
+ <field name="parallel_accounts_summary" />
+ <button name="create_parallel_accounts" type="object" string="Create parallel accounts"></button>
+ <separator string="Parallel Currency Accounts" colspan="4"/>
+ <field colspan="4" name="parallel_account_ids" nolabel="1" domain="[('company_id', '!=', company_id)]"/>
+ <separator string="Master Parallel Currency Accounts" colspan="4"/>
+ <field colspan="4" name="master_parallel_account_ids" nolabel="1"/>
+ </group>
+ </field>
+ </field>
+ </record>
+ <record id="view_account_journal_form" model="ir.ui.view">
+ <field name="name">view_account_journal_form</field>
+ <field name="model">account.journal</field>
+ <field name="inherit_id" ref="account.view_account_journal_form"></field>
+ <field name="arch" type="xml">
+ <page string="Entry Controls" position="after">
+ <page string="Parallel Currency" groups="account.group_account_manager">
+ <separator string="Parallel Currency Journals" colspan="4"/>
+ <field colspan="4" name="parallel_journal_ids" nolabel="1" domain="[('company_id', '!=', company_id)]"/>
+ <separator string="Master Parallel Currency Journals" colspan="4"/>
+ <field colspan="4" name="master_parallel_journal_ids" nolabel="1"/>
+ </page>
+ </page>
+ </field>
+ </record>
+ <record id="view_tax_code_form" model="ir.ui.view">
+ <field name="name">view_tax_code_form</field>
+ <field name="model">account.tax.code</field>
+ <field name="inherit_id" ref="account.view_tax_code_form"></field>
+ <field name="arch" type="xml">
+ <field name="info" position="after">
+ <group colspan="4" col="1" groups="account.group_account_manager">
+ <field name="parallel_tax_codes_summary" />
+ <button name="create_parallel_tax_codes" type="object" string="Create parallel tax codes"></button>
+ <field name="parallel_tax_code_ids" domain="[('company_id', '!=', company_id)]"/>
+ <field name="master_parallel_tax_code_ids"/>
+ </group>
+ </field>
+ </field>
+ </record>
+ <record id="view_move_form" model="ir.ui.view">
+ <field name="name">view_move_form</field>
+ <field name="model">account.move</field>
+ <field name="inherit_id" ref="account.view_move_form"></field>
+ <field name="arch" type="xml">
+ <page string="Journal Items" position="after">
+ <page string="Parallel Entries" groups="account.group_account_manager">
+ <field colspan="4" name="parallel_move_ids" nolabel="1" />
+ </page>
+ </page>
+ </field>
+ </record>
+ </data>
+</openerp>
=== added file 'account_parallel_currency/company_view.xml'
--- account_parallel_currency/company_view.xml 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/company_view.xml 2014-04-17 13:57:59 +0000
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+ <data>
+ <record id="view_company_form" model="ir.ui.view">
+ <field name="inherit_id" ref="base.view_company_form"/>
+ <field name="name">view.company.form</field>
+ <field name="model">res.company</field>
+ <field name="arch" type="xml">
+ <page string="Configuration" position="inside">
+ <separator string="Parallel Companies" colspan="4"/>
+ <field name="parallel_company_ids" nolabel="1" colspan="4"/>
+ </page>
+ </field>
+ </record>
+ </data>
+</openerp>
=== added directory 'account_parallel_currency/i18n'
=== added file 'account_parallel_currency/i18n/account_parallel_currency.pot'
--- account_parallel_currency/i18n/account_parallel_currency.pot 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/i18n/account_parallel_currency.pot 2014-04-17 13:57:59 +0000
@@ -0,0 +1,343 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * account_parallel_currency
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 7.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-10-21 09:05+0000\n"
+"PO-Revision-Date: 2013-10-21 09:05+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/wizard/do_mapping.py:83
+#, python-format
+msgid "Duplicated tax code %s for company %s"
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:account.journal:0
+#: field:account.journal,master_parallel_journal_ids:0
+msgid "Master Parallel Currency Journals"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:429
+#, python-format
+msgid "Too many tax codes %s for company %s"
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:account.move:0
+#: field:account.move,parallel_move_ids:0
+msgid "Parallel Entries"
+msgstr ""
+
+#. module: account_parallel_currency
+#: model:ir.model,name:account_parallel_currency.model_res_company
+msgid "Companies"
+msgstr ""
+
+#. module: account_parallel_currency
+#: model:ir.model,name:account_parallel_currency.model_account_tax_code
+msgid "Tax Code"
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:account.account:0
+#: view:account.journal:0
+msgid "Parallel Currency"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:343
+#, python-format
+msgid "Too many tax_codes %s for company %s !"
+msgstr ""
+
+#. module: account_parallel_currency
+#: field:account.parallel.mapping,remove_old_mapping:0
+msgid "Remove Previous Mapping"
+msgstr ""
+
+#. module: account_parallel_currency
+#: field:account.tax.code,master_parallel_tax_code_ids:0
+msgid "Master Parallel Currency Tax Codes"
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:account.account:0
+#: field:account.account,parallel_account_ids:0
+msgid "Parallel Currency Accounts"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:278
+#, python-format
+msgid "Too many journals %s for company %s !"
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:account.journal:0
+#: field:account.journal,parallel_journal_ids:0
+msgid "Parallel Currency Journals"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:260
+#: code:addons/account_parallel_currency/account.py:263
+#: code:addons/account_parallel_currency/account.py:275
+#: code:addons/account_parallel_currency/account.py:278
+#: code:addons/account_parallel_currency/account.py:310
+#: code:addons/account_parallel_currency/account.py:313
+#: code:addons/account_parallel_currency/account.py:340
+#: code:addons/account_parallel_currency/account.py:343
+#, python-format
+msgid "Error !"
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:account.parallel.mapping:0
+msgid "This wizard will create the parallel account mapping. Please make sure you configured the 'Parallel Companies' field on your company. The wizard will search for matching account and tax codes and write the result in the 'Parallel Currency Accounts' and 'Parallel Currency Tax Codes' fields"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:45
+#, python-format
+msgid "No parallel accounts found"
+msgstr ""
+
+#. module: account_parallel_currency
+#: model:ir.model,name:account_parallel_currency.model_account_journal
+msgid "Journal"
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:account.account:0
+msgid "Create parallel accounts"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:340
+#, python-format
+msgid "Tax code %s does not exist in company %s !"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:40
+#, python-format
+msgid "Account code: %s. Company: %s\n"
+""
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:313
+#, python-format
+msgid "Too many currencies %s for company %s !"
+msgstr ""
+
+#. module: account_parallel_currency
+#: model:ir.model,name:account_parallel_currency.model_account_parallel_mapping
+msgid "account.parallel.mapping"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:454
+#, python-format
+msgid "No parent tax code %s found in company %s"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:71
+#, python-format
+msgid "Too many accounts %s for company %s"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:463
+#, python-format
+msgid "Tax code %s does not have parent"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:402
+#, python-format
+msgid "Tax code: %s. Company: %s\n"
+""
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:account.move:0
+msgid "Journal Items"
+msgstr ""
+
+#. module: account_parallel_currency
+#: field:account.tax.code,parallel_tax_codes_summary:0
+msgid "Parallel tax codes summary"
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:res.company:0
+msgid "Configuration"
+msgstr ""
+
+#. module: account_parallel_currency
+#: model:ir.actions.act_window,name:account_parallel_currency.action_account_parallel_mapping
+#: model:ir.ui.menu,name:account_parallel_currency.menu_action_account_parallel_mapping
+msgid "Parallel Accounting Mapping"
+msgstr ""
+
+#. module: account_parallel_currency
+#: model:ir.model,name:account_parallel_currency.model_account_account
+msgid "Account"
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:account.journal:0
+msgid "Entry Controls"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:275
+#, python-format
+msgid "Journal %s does not exist in company %s !"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:407
+#, python-format
+msgid "No parallel tax codes found"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:471
+#, python-format
+msgid "Tax code %s already exists for company %s"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/wizard/do_mapping.py:66
+#, python-format
+msgid "Duplicated account %s for company %s"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:71
+#: code:addons/account_parallel_currency/account.py:95
+#: code:addons/account_parallel_currency/account.py:429
+#: code:addons/account_parallel_currency/account.py:453
+#: code:addons/account_parallel_currency/account.py:463
+#: code:addons/account_parallel_currency/account.py:470
+#: code:addons/account_parallel_currency/wizard/do_mapping.py:66
+#: code:addons/account_parallel_currency/wizard/do_mapping.py:69
+#: code:addons/account_parallel_currency/wizard/do_mapping.py:83
+#: code:addons/account_parallel_currency/wizard/do_mapping.py:86
+#, python-format
+msgid "Error"
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:account.account:0
+#: field:account.account,master_parallel_account_ids:0
+msgid "Master Parallel Currency Accounts"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:310
+#, python-format
+msgid "Currency %s does not exist in company %s !"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:96
+#, python-format
+msgid "No parent account %s found in company %s"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:263
+#, python-format
+msgid "Too many periods %s for company %s !"
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:res.company:0
+#: field:res.company,parallel_company_ids:0
+msgid "Parallel Companies"
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:account.parallel.mapping:0
+msgid "Run"
+msgstr ""
+
+#. module: account_parallel_currency
+#: model:ir.model,name:account_parallel_currency.model_account_move
+msgid "Account Entry"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/account.py:260
+#, python-format
+msgid "Period %s does not exist in company %s !"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/wizard/do_mapping.py:86
+#, python-format
+msgid "No tax code %s for company %s"
+msgstr ""
+
+#. module: account_parallel_currency
+#: field:account.account,parallel_accounts_summary:0
+msgid "Parallel accounts summary"
+msgstr ""
+
+#. module: account_parallel_currency
+#: field:account.move,master_parallel_move_id:0
+msgid "Master Parallel Entry"
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:account.parallel.mapping:0
+msgid "Parallel Mapping"
+msgstr ""
+
+#. module: account_parallel_currency
+#: field:account.tax.code,parallel_tax_code_ids:0
+msgid "Parallel Currency Tax Codes"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/wizard/do_mapping.py:91
+#, python-format
+msgid "Done"
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:account.tax.code:0
+msgid "Create parallel tax codes"
+msgstr ""
+
+#. module: account_parallel_currency
+#: view:account.parallel.mapping:0
+msgid "Close"
+msgstr ""
+
+#. module: account_parallel_currency
+#: field:account.parallel.mapping,message:0
+msgid "Message"
+msgstr ""
+
+#. module: account_parallel_currency
+#: code:addons/account_parallel_currency/wizard/do_mapping.py:69
+#, python-format
+msgid "No account %s for company %s"
+msgstr ""
+
=== added file 'account_parallel_currency/res_company.py'
--- account_parallel_currency/res_company.py 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/res_company.py 2014-04-17 13:57:59 +0000
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2012-2013 Agile Business Group sagl
+# (<http://www.agilebg.com>)
+# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import fields, orm
+from osv import fields
+
+class res_company(orm.Model):
+ _inherit = "res.company"
+
+ _columns = {
+ 'parallel_company_ids': fields.many2many('res.company', 'parallel_companies_rel', 'master_id',
+ 'parallel_id', 'Parallel Companies'),
+ }
+
=== added directory 'account_parallel_currency/security'
=== added file 'account_parallel_currency/security/security.xml'
--- account_parallel_currency/security/security.xml 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/security/security.xml 2014-04-17 13:57:59 +0000
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+<data noupdate="0">
+ <record model="ir.rule" id="res_currency_comp_rule">
+ <field name="name">Currency multi-company</field>
+ <field name="model_id" ref="base.model_res_currency"/>
+ <field name="global" eval="True"/>
+ <field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
+ </record>
+</data>
+</openerp>
=== added directory 'account_parallel_currency/test'
=== added file 'account_parallel_currency/test/customer_invoice.yml'
--- account_parallel_currency/test/customer_invoice.yml 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/test/customer_invoice.yml 2014-04-17 13:57:59 +0000
@@ -0,0 +1,143 @@
+-
+ In order to test account invoice I create a new customer invoice
+-
+ I will create bank detail
+-
+ !record {model: res.partner.bank, id: res_partner_bank_0}:
+ state: bank
+ company_id: base.main_company
+ partner_id: base.main_partner
+ acc_number: 123456789
+ footer: True
+ bank: base.res_bank_1
+ bank_name: Reserve
+-
+ I create a customer invoice
+-
+ !record {model: account.invoice, id: account_invoice_customer0, view: account.invoice_form}:
+ payment_term: account.account_payment_term_advance
+ partner_bank_id: res_partner_bank_0
+ journal_id: account.sales_journal
+ partner_id: base.res_partner_3
+ reference_type: none
+ name: 'Test Customer Invoice'
+ invoice_line:
+ - product_id: product.product_product_5
+ quantity: 10.0
+-
+ I manually assign tax on invoice
+-
+ !python {model: account.invoice.tax}: |
+ amt = self.amount_change(cr, uid, [], 50.0, ref('base.EUR'), ref('base.main_company'), False)
+ base_amt = self.base_change(cr, uid, [], 9000.0, ref('base.EUR'), ref('base.main_company'), False)
+ invoice_tax_line = {
+ 'name': 'Test Tax for Customer Invoice',
+ 'manual': 1,
+ 'base': base_amt['value']['base_amount'],
+ 'amount': amt['value']['tax_amount'],
+ 'account_id': ref('account.ova'),
+ 'invoice_id': ref("account_invoice_customer0"),
+ 'tax_code_id': ref('tax_code'),
+ 'tax_amount': amt['value']['tax_amount'],
+ }
+ tax = self.create(cr, uid, invoice_tax_line)
+ assert tax, "Tax has not been assigned correctly"
+
+-
+ I check that Initially customer invoice is in the "Draft" state
+-
+ !assert {model: account.invoice, id: account_invoice_customer0}:
+ - state == 'draft'
+-
+ I confirm invoice by clicking on validate button
+-
+ !workflow {model: account.invoice, action: invoice_open, ref: account_invoice_customer0}
+-
+ I check that the invoice state is "Open"
+-
+ !assert {model: account.invoice, id: account_invoice_customer0}:
+ - state == 'open'
+
+-
+ I check moves attached to the invoice
+-
+ !python {model: account.invoice}: |
+ acc_id=self.browse(cr, uid, ref("account_invoice_customer0"))
+ assert acc_id.move_id, "Move not created for open invoice"
+ assert acc_id.move_id.parallel_move_ids, "Parallel move not created for open invoice"
+ for parallel_move in acc_id.move_id.parallel_move_ids:
+ for line in parallel_move.line_id:
+ if line.account_id.id == ref("a_sale"):
+ assert line.credit == 11777.40, "CHF Product Sales must be 11777.40"
+ assert line.amount_currency == -9000.0, "EUR Product Sales must be -9000.0"
+ assert line.currency_id.id == ref("EUR"), "Secondary currency must be EUR"
+ if line.account_id.id == ref("ova"):
+ assert line.tax_amount == 65.43, "CHF Tax amount must be 65.43"
+ assert line.credit == 65.43, "CHF Tax amount must be 65.43"
+
+-
+ I create a customer CHF invoice
+-
+ !record {model: account.invoice, id: account_invoice_customer1, view: account.invoice_form}:
+ partner_bank_id: res_partner_bank_0
+ journal_id: account.sales_journal
+ partner_id: base.res_partner_3
+ reference_type: none
+ name: 'Test Customer CHF Invoice'
+ currency_id: base.CHF
+ invoice_line:
+ - product_id: product.product_product_5
+ quantity: 1.0
+ price_unit: 100.0
+
+-
+ I confirm invoice by clicking on validate button
+-
+ !workflow {model: account.invoice, action: invoice_open, ref: account_invoice_customer1}
+
+-
+ I check moves attached to the invoice
+-
+ !python {model: account.invoice}: |
+ acc_id=self.browse(cr, uid, ref("account_invoice_customer1"))
+ assert acc_id.move_id, "Move not created for open invoice"
+ assert acc_id.move_id.parallel_move_ids, "Parallel move not created for open invoice"
+ for parallel_move in acc_id.move_id.parallel_move_ids:
+ for line in parallel_move.line_id:
+ if line.account_id.id == ref("a_sale"):
+ assert line.credit == 100.0, "CHF Product Sales must be 100.0"
+ assert not line.amount_currency, "amount_currency must be empty"
+ assert not line.currency_id, "currency_id must be empty"
+
+-
+ I create a customer USD invoice
+-
+ !record {model: account.invoice, id: account_invoice_customer2, view: account.invoice_form}:
+ journal_id: account.sales_journal
+ partner_id: base.res_partner_3
+ reference_type: none
+ name: 'Test Customer USD Invoice'
+ currency_id: base.USD
+ invoice_line:
+ - product_id: product.product_product_5
+ quantity: 1.0
+ price_unit: 100.0
+
+-
+ I confirm invoice by clicking on validate button
+-
+ !workflow {model: account.invoice, action: invoice_open, ref: account_invoice_customer2}
+
+-
+ I check moves attached to the invoice
+-
+ !python {model: account.invoice}: |
+ acc_id=self.browse(cr, uid, ref("account_invoice_customer2"))
+ assert acc_id.move_id, "Move not created for open invoice"
+ assert acc_id.move_id.parallel_move_ids, "Parallel move not created for open invoice"
+ for parallel_move in acc_id.move_id.parallel_move_ids:
+ for line in parallel_move.line_id:
+ if line.account_id.id == ref("a_sale"):
+ assert line.credit == 101.96, "USD Product Sales must be 101.96"
+ assert line.amount_currency == -100.0, "USD Product Sales must be -100.0"
+ assert line.currency_id.id == ref("USD"), "Secondary currency must be USD"
=== added file 'account_parallel_currency/test/mapping_parallel_accounts.yml'
--- account_parallel_currency/test/mapping_parallel_accounts.yml 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/test/mapping_parallel_accounts.yml 2014-04-17 13:57:59 +0000
@@ -0,0 +1,25 @@
+-
+ I create Tax Codes
+-
+ !record {model: account.tax.code, id: tax_code}:
+ name: tax_code
+ code: 1
+ company_id: base.main_company
+ sign: 1
+-
+ !record {model: account.tax.code, id: parallel_tax_code}:
+ name: parallel_tax_code
+ code: 1
+ company_id: parallel_company
+ sign: 1
+-
+ I create the mapping wizard
+-
+ !record {model: account.parallel.mapping, id: account_parallel_mapping_0}:
+ remove_old_mapping: True
+
+-
+ I click on do mapping
+-
+ !python {model: account.parallel.mapping}: |
+ self.do_mapping(cr, uid, [ref("account_parallel_mapping_0")])
=== added directory 'account_parallel_currency/wizard'
=== added file 'account_parallel_currency/wizard/__init__.py'
--- account_parallel_currency/wizard/__init__.py 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/wizard/__init__.py 2014-04-17 13:57:59 +0000
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2012-2013 Agile Business Group sagl
+# (<http://www.agilebg.com>)
+# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+import do_mapping
=== added file 'account_parallel_currency/wizard/do_mapping.py'
--- account_parallel_currency/wizard/do_mapping.py 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/wizard/do_mapping.py 2014-04-17 13:57:59 +0000
@@ -0,0 +1,92 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2012-2013 Agile Business Group sagl
+# (<http://www.agilebg.com>)
+# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import fields, orm
+from tools.translate import _
+import logging
+from openerp import SUPERUSER_ID
+
+_logger = logging.getLogger(__name__)
+
+class account_parallel_mapping(orm.TransientModel):
+
+ _name = "account.parallel.mapping"
+
+ _columns = {
+ 'message': fields.text('Message'),
+ 'remove_old_mapping': fields.boolean('Remove Previous Mapping'),
+ }
+
+ _defaults = {
+ 'remove_old_mapping': True,
+ }
+
+ def do_mapping(self, cr, uid, ids, context=None):
+ company_pool = self.pool.get('res.company')
+ account_pool = self.pool.get('account.account')
+ tax_code_pool = self.pool.get('account.tax.code')
+ company_ids = company_pool.search(cr, SUPERUSER_ID, [])
+ wizard =self.browse(cr, uid, ids[0])
+ if wizard.remove_old_mapping:
+ account_ids = account_pool.search(cr, SUPERUSER_ID, [])
+ account_pool.write(cr, SUPERUSER_ID, account_ids, {'parallel_account_ids': [(6,0,[])]})
+ for company_id in company_ids:
+ company = company_pool.browse(cr, SUPERUSER_ID, company_id)
+ if company.parallel_company_ids:
+ master_account_ids = account_pool.search(cr, SUPERUSER_ID, [('company_id', '=', company.id)])
+ master_tax_code_ids = tax_code_pool.search(cr, SUPERUSER_ID, [('company_id', '=', company.id)])
+ # account mapping
+ for master_account_id in master_account_ids:
+ master_account = account_pool.browse(cr, SUPERUSER_ID, master_account_id)
+ for parallel_company in company.parallel_company_ids:
+ parallel_account_ids = account_pool.search(cr, SUPERUSER_ID, [
+ ('code', '=', master_account.code),
+ ('company_id', '=', parallel_company.id),
+ ])
+ if len(parallel_account_ids) > 1:
+ raise orm.except_orm(_('Error'), _('Duplicated account %s for company %s')
+ % (master_account.code,parallel_company.name))
+ elif not parallel_account_ids:
+ raise orm.except_orm(_('Error'), _('No account %s for company %s')
+ % (master_account.code,parallel_company.name))
+ elif len(parallel_account_ids) == 1:
+ master_account.write({'parallel_account_ids':
+ [(4,parallel_account_ids[0])]})
+ # tax code mapping
+ for master_tax_code_id in master_tax_code_ids:
+ master_tax_code = tax_code_pool.browse(cr, SUPERUSER_ID, master_tax_code_id)
+ for parallel_company in company.parallel_company_ids:
+ parallel_tax_code_ids = tax_code_pool.search(cr, SUPERUSER_ID, [
+ ('code', '=', master_tax_code.code),
+ ('company_id', '=', parallel_company.id),
+ ])
+ if len(parallel_tax_code_ids) > 1:
+ raise orm.except_orm(_('Error'), _('Duplicated tax code %s for company %s')
+ % (master_tax_code.code,parallel_company.name))
+ elif not parallel_tax_code_ids:
+ raise orm.except_orm(_('Error'), _('No tax code %s for company %s')
+ % (master_tax_code.code,parallel_company.name))
+ elif len(parallel_tax_code_ids) == 1:
+ master_tax_code.write({'parallel_tax_code_ids':
+ [(4,parallel_tax_code_ids[0])]})
+ self.write(cr, uid, ids, {'message': _('Done')})
+ return True
=== added file 'account_parallel_currency/wizard/do_mapping.xml'
--- account_parallel_currency/wizard/do_mapping.xml 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/wizard/do_mapping.xml 2014-04-17 13:57:59 +0000
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+
+ <record id="account_parallel_mapping" model="ir.ui.view">
+ <field name="name">account.parallel.mapping</field>
+ <field name="model">account.parallel.mapping</field>
+ <field name="arch" type="xml">
+ <form string="Parallel Mapping" >
+ <group col="2">
+ <label string="This wizard will create the parallel account mapping. Please make sure you configured the 'Parallel Companies' field on your company. The wizard will search for matching account and tax codes and write the result in the 'Parallel Currency Accounts' and 'Parallel Currency Tax Codes' fields" colspan="2"/>
+ <field name="remove_old_mapping" colspan="2"/>
+ <button icon="gtk-cancel" special="cancel" string="Close" />
+ <button icon="gtk-ok" name="do_mapping" string="Run" type="object" />
+ <field name="message" colspan="2" nolabel="1" readonly="1"/>
+ </group>
+ </form>
+ </field>
+ </record>
+
+ <record id="action_account_parallel_mapping" model="ir.actions.act_window">
+ <field name="name">Parallel Accounting Mapping</field>
+ <field name="res_model">account.parallel.mapping</field>
+ <field name="view_type">form</field>
+ <field name="view_mode">form</field>
+ <field name="view_id" ref="account_parallel_mapping"/>
+ <field name="target">new</field>
+ </record>
+
+ <menuitem name="Parallel Accounting Mapping" action="action_account_parallel_mapping" id="menu_action_account_parallel_mapping" parent="account.menu_finance_accounting"/>
+ </data>
+</openerp>