Merge lp:~elbati/account-consolidation/adding_account_parallel_currency_7 into lp:~account-core-editors/account-consolidation/7.0

Proposed by Lorenzo Battistini
Status: Merged
Merged at revision: 18
Proposed branch: lp:~elbati/account-consolidation/adding_account_parallel_currency_7
Merge into: lp:~account-core-editors/account-consolidation/7.0
Diff against target: 1601 lines (+1527/-0)
14 files modified
account_parallel_currency/AUTHORS.txt (+1/-0)
account_parallel_currency/__init__.py (+23/-0)
account_parallel_currency/__openerp__.py (+56/-0)
account_parallel_currency/account.py (+505/-0)
account_parallel_currency/account_demo.xml (+504/-0)
account_parallel_currency/account_view.xml (+64/-0)
account_parallel_currency/company_view.xml (+16/-0)
account_parallel_currency/res_company.py (+33/-0)
account_parallel_currency/security/security.xml (+11/-0)
account_parallel_currency/test/customer_invoice.yml (+143/-0)
account_parallel_currency/test/mapping_parallel_accounts.yml (+25/-0)
account_parallel_currency/wizard/__init__.py (+22/-0)
account_parallel_currency/wizard/do_mapping.py (+92/-0)
account_parallel_currency/wizard/do_mapping.xml (+32/-0)
To merge this branch: bzr merge lp:~elbati/account-consolidation/adding_account_parallel_currency_7
Reviewer Review Type Date Requested Status
Maxime Chambreuil (http://www.savoirfairelinux.com) code review Approve
Stefan Rijnhart (Opener) Approve
Review via email: mp+151723@code.launchpad.net

Description of the change

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.
For each user, it is possible to configure a 'parallel user' (that should be associated to a dummy parent company), used to carry out the parallel registrations. This allows to keep 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 his parallel user in order to perform the parallel registrations

To post a comment you must log in.
Revision history for this message
Frederic Clementi - Camptocamp (frederic-clementi) wrote :

Hi Lorenzzo,

Sorry for the question : this looks very interesting but I cannot find any cases/example in real situation where this could be a must have...
I mean, why would you duplicate the entire accounting books of the company instead of simply do a report or a view which convert account balances ?
Any legal reason ? unless a segregation of duties issue maybe ?

Thanks

Frederic

Revision history for this message
Nhomar - Vauxoo (nhomar) wrote :

Hi Lorenzo,

We have same question, we frequently use Consolidated accounts to build consolidation reports, some specific or generical reason or accounting Good practice to support the development?

For sure i had some times this idea in my mind because when you have some customers you think in several options to solve the problem, but i never developed because Consolidated acounts works for me.

Regards, and Kudos for you contribution

Revision history for this message
Lorenzo Battistini (elbati) wrote :

On 03/18/2013 01:15 PM, Frederic Clementi - Camptocamp.com wrote:
> Hi Lorenzzo,
>
> Sorry for the question : this looks very interesting but I cannot find any cases/example in real situation where this could be a must have...
> I mean, why would you duplicate the entire accounting books of the company instead of simply do a report or a view which convert account balances ?
> Any legal reason ? unless a segregation of duties issue maybe ?

Hi Frederic and Nhomar,

simply converting balances can be insufficient if you have to consider
historical rates.

Just found a recent publication
<http://www.altenburger.ch/uploads/tx_altenburger/mc_2013_Revisione_del_diritto_contabile_svizzero.pdf>
(Italian) about Swiss accounting law.

The interesting part:

"To facilitate the international companies, moreover, the accounts can
be held in one of the national languages ​​(German, French, Italian)
and, in addition to the CHF, other currencies are accepted - crucial for
the company activities - such as Euro or USD, with an indication,
however, of the values ​​in CHF too"

22. By Lorenzo Battistini

[FIX] using _logger.warning

23. By Lorenzo Battistini

[fix] string formatting

24. By Lorenzo Battistini

[add] sync_parallel_accounts method: automatically write/create parallel accounts when writing account

25. By Lorenzo Battistini

[ADD] tests

26. By Lorenzo Battistini

[MERGE] tax codes handling

27. By Lorenzo Battistini

[add] Parallel accounts summary

28. By Lorenzo Battistini

[ref] create_parallel_accounts

29. By Lorenzo Battistini

[fix] useless code

30. By Lorenzo Battistini

[fix] allow mapping for normal users

31. By Lorenzo Battistini

[add] runtime tax codes sync

32. By Lorenzo Battistini

[add] comment

33. By Lorenzo Battistini

[add] parallel accounts at creation

34. By Lorenzo Battistini

[imp]messages

35. By Lorenzo Battistini

[imp] error message

36. By Lorenzo Battistini

[imp] error message

37. By Lorenzo Battistini

[fix] impossible to change parent account

38. By Lorenzo Battistini

[FIX] searching parallel period by code

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

This has been the oldest proposal on the community projects for some time now, maybe because of the relatively rare business case, and the large amount of code impacting the core of the accounting system. So I'll have ago. I think I can understand the particular business case of this module, and the code does look good. Tests are provided too, so I think this should be fine.

It would be nice to know whether this module has already been used in production by now?

One nit:

l.174..185 + l.535..536 is a bit tiresome. Can you make this a list comprehension or at least iterate over a list of fields?

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Forgot to assign review status, make that 'needs information'

review: Needs Information
Revision history for this message
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) wrote :

Thanks Lorenzo.

Can you please run autopep8 on your module ?

review: Needs Fixing (code review)
Revision history for this message
Lorenzo Battistini (elbati) wrote :

On 09/08/2013 08:17 AM, Stefan Rijnhart (Therp) wrote:
> It would be nice to know whether this module has already been used in production by now?

Hello Stefan.

The module has been used in production from this winter.

Unfortunately, we could not verify deeply the data accuracy yet. We will
probably do it at the end the year.

39. By Lorenzo Battistini

[IMP] some PEP8

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Thanks for the info, and for updating the code style a little bit.

review: Approve
Revision history for this message
Lorenzo Battistini (elbati) wrote :

On 09/29/2013 08:30 PM, Stefan Rijnhart (Therp) wrote:
> and for updating the code style a little bit

I had no time to complete it for now..

Revision history for this message
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) :
review: Approve (code review)
Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

> I had no time to complete it for now..

That's quite alright by me for now. I think this proposal has been waiting long enough.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== 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 2013-09-27 07:51:38 +0000
@@ -0,0 +1,1 @@
1Lorenzo Battistini <lorenzo.battistini@agilebg.com>
02
=== added file 'account_parallel_currency/__init__.py'
--- account_parallel_currency/__init__.py 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/__init__.py 2013-09-27 07:51:38 +0000
@@ -0,0 +1,23 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (C) 2012 Agile Business Group sagl (<http://www.agilebg.com>)
5# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as published
9# by the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21import account
22import res_company
23import wizard
024
=== added file 'account_parallel_currency/__openerp__.py'
--- account_parallel_currency/__openerp__.py 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/__openerp__.py 2013-09-27 07:51:38 +0000
@@ -0,0 +1,56 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (C) 2012-2013 Agile Business Group sagl
5# (<http://www.agilebg.com>)
6# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as published
10# by the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22{
23 'name': "Account Parallel Currency",
24 'version': '0.2',
25 'category': 'Generic Modules/Accounting',
26 'description': """
27This module handles parallel accounting entries based on different currencies.
28It 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.
29
30In 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.
31
32A '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.
33
34When posting new journal entries, the system checks the configured parallel accounts and automatically generates the parallel entries.
35This 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.
36""",
37 'author': 'Agile Business Group',
38 'website': 'http://www.agilebg.com',
39 'license': 'AGPL-3',
40 "depends" : ['account'],
41 "data" : [
42 'account_view.xml',
43 'company_view.xml',
44 'wizard/do_mapping.xml',
45 'security/security.xml',
46 ],
47 "demo" : [
48 'account_demo.xml',
49 ],
50 'test': [
51 'test/mapping_parallel_accounts.yml',
52 'test/customer_invoice.yml',
53 ],
54 "active": False,
55 "installable": True
56}
057
=== added file 'account_parallel_currency/account.py'
--- account_parallel_currency/account.py 1970-01-01 00:00:00 +0000
+++ account_parallel_currency/account.py 2013-09-27 07:51:38 +0000
@@ -0,0 +1,505 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (C) 2012-2013 Agile Business Group sagl
5# (<http://www.agilebg.com>)
6# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as published
10# by the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23from openerp.osv import fields, orm
24from tools.translate import _
25import logging
26from openerp import SUPERUSER_ID
27
28_logger = logging.getLogger(__name__)
29
30
31class account_account(orm.Model):
32 _inherit = "account.account"
33
34 def _get_parallel_accounts_summary(self, cr, uid, ids, field_name, arg, context=None):
35 res = {}
36 for account in self.browse(cr, SUPERUSER_ID, ids, context):
37 text = 'Configured parallel accounts:\n'
38 text2 = ''
39 for parallel_account in account.parallel_account_ids:
40 text2 += _('Account code: %s. Company: %s\n') % (
41 parallel_account.code, parallel_account.company_id.name)
42 if text2:
43 res[account.id] = text + text2
44 else:
45 res[account.id] = _("No parallel accounts found")
46 return res
47
48 _columns = {
49 'parallel_account_ids': fields.many2many('account.account',
50 'parallel_account_rel', 'parent_id',
51 'child_id', 'Parallel Currency Accounts',
52 Help="""Set here the accounts you want to automatically move when
53 registering entries in this account"""),
54 'master_parallel_account_ids': fields.many2many('account.account',
55 'parallel_account_rel', 'child_id',
56 'parent_id', 'Master Parallel Currency Accounts',
57 Help="You can see here the accounts that automatically move this account",
58 readonly=True),
59 'parallel_accounts_summary': fields.function(
60 _get_parallel_accounts_summary, type='text',
61 string='Parallel accounts summary'),
62 }
63
64 def _search_parallel_account(self, cr, uid, account_code, parallel_company,
65 context=None):
66 parallel_acc_ids = self.search(cr, uid, [
67 ('company_id', '=', parallel_company.id),
68 ('code', '=', account_code),
69 ], context=context)
70 if len(parallel_acc_ids) > 1:
71 raise orm.except_orm(_('Error'), _('Too many accounts %s for company %s')
72 % (account_code, parallel_company.name))
73 return parallel_acc_ids and parallel_acc_ids[0] or False
74
75 def _build_account_vals(self, cr, uid, account_vals, parallel_company, context=None):
76 # build only fields I need
77 vals = {}
78 if 'name' in account_vals:
79 vals['name'] = account_vals['name']
80 if 'code' in account_vals:
81 vals['code'] = account_vals['code']
82 if 'type' in account_vals:
83 vals['type'] = account_vals['type']
84 if 'user_type' in account_vals:
85 vals['user_type'] = account_vals['user_type']
86 if 'active' in account_vals:
87 vals['active'] = account_vals['active']
88 if 'centralized' in account_vals:
89 vals['centralized'] = account_vals['centralized']
90 if 'parent_id' in account_vals:
91 parent_account = self.browse(cr, uid, account_vals['parent_id'], context)
92 parent_parallel_acc_id = self._search_parallel_account(
93 cr, uid, parent_account.code, parallel_company, context=context)
94 if not parent_parallel_acc_id:
95 raise orm.except_orm(_('Error'),
96 _('No parent account %s found in company %s') %
97 (parent_account.code, parallel_company.name))
98 vals['parent_id'] = parent_parallel_acc_id
99 return vals
100
101 def create_parallel_accounts(self, cr, uid, ids, context=None):
102 for account in self.browse(cr, SUPERUSER_ID, ids, context):
103 for parallel_company in account.company_id.parallel_company_ids:
104 parent_parallel_acc_id = self._search_parallel_account(
105 cr, SUPERUSER_ID, account.parent_id.code, parallel_company,
106 context=context)
107 new_id = self.create(cr, SUPERUSER_ID, {
108 'company_id': parallel_company.id,
109 'parent_id': parent_parallel_acc_id,
110 'name': account.name,
111 'code': account.code,
112 'type': account.type,
113 'user_type': account.user_type and account.user_type.id or False,
114 'active': account.active,
115 'centralized': account.centralized,
116 })
117 cr.execute("insert into parallel_account_rel(parent_id,child_id) values (%d,%d)"
118 % (account.id, new_id))
119 return True
120
121 '''
122 def sync_parallel_accounts(self, cr, uid, ids, vals={}, context=None):
123 for account in self.browse(cr, uid, ids, context):
124 new_parallel_acc_ids = []
125 company_id = vals.get('company_id') or account.company_id.id
126 code = vals.get('code') or account.code
127 company = self.pool.get('res.company').browse(cr, uid, company_id, context)
128 for parallel_company in company.parallel_company_ids:
129 parallel_acc_id = self._search_parallel_account(
130 cr, uid, code, parallel_company, context=context)
131 if not parallel_acc_id:
132 # Then I create it, linked to parent account
133 #parallel_acc_id = self.create(cr, uid,
134 #self._build_account_vals(cr, uid,
135 #vals, parallel_company, context=context), context=context)
136 pass
137 else:
138 super(account_account,self).write(cr, uid, [parallel_acc_id],
139 self._build_account_vals(cr, uid,
140 vals, parallel_company, context=context), context)
141 _logger.info(
142 _("Parallel account %s (company %s) written") %
143 (code, parallel_company.name))
144 new_parallel_acc_ids.append(parallel_acc_id)
145 return new_parallel_acc_ids
146 '''
147
148 def write(self, cr, uid, ids, vals, context=None):
149 if 'parallel_account_ids' not in vals:
150 # write/create parallel accounts only if 'parallel_account_ids' not explicity written
151 for acc_id in ids:
152 account = self.browse(cr, SUPERUSER_ID, acc_id, context)
153 for parallel_account in account.parallel_account_ids:
154 parallel_vals = self._build_account_vals(
155 cr, SUPERUSER_ID, vals, parallel_account.company_id,
156 context=context)
157 parallel_account.write(parallel_vals)
158 res=super(account_account,self).write(cr, uid, ids, vals, context=context)
159 return res
160
161 def create(self, cr, uid, vals, context=None):
162 res=super(account_account,self).create(cr, uid, vals, context)
163 self.create_parallel_accounts(cr, uid, [res], context=None)
164 return res
165
166 def unlink(self, cr, uid, ids, context=None):
167 for account in self.browse(cr, SUPERUSER_ID, ids, context):
168 for parallel_account in account.parallel_account_ids:
169 parallel_account.unlink()
170 res=super(account_account,self).unlink(cr, uid, ids, context=context)
171 return res
172
173class account_move(orm.Model):
174 _inherit = "account.move"
175
176 _columns = {
177 'parallel_move_ids': fields.one2many('account.move', 'master_parallel_move_id', 'Parallel Entries',
178 readonly=True),
179 'master_parallel_move_id': fields.many2one('account.move', 'Master Parallel Entry'),
180 }
181
182 def button_cancel(self, cr, uid, ids, context=None):
183 res = super(account_move, self).button_cancel(cr, uid, ids, context=context)
184 for move in self.browse(cr, SUPERUSER_ID, ids, context=context):
185 for parallel_move in move.parallel_move_ids:
186 parallel_move.button_cancel(context=context)
187 parallel_move.unlink(context=context)
188 return res
189
190 def lines_balance(self, move_lines):
191 """
192 returns 0 if lines are balanced, difference if unbalanced
193 """
194 balance = 0.0
195 for line_tuple in move_lines:
196 balance += line_tuple[2]['debit'] or (- line_tuple[2]['credit']) or 0.0
197 return balance
198
199 def balance_lines(self, cr, uid, move_lines, currency_id, context=None):
200 """
201 Balance move lines that were unbalanced due to roundings.
202 """
203 balance = self.lines_balance(move_lines)
204 acc_pool = self.pool.get('account.account')
205 curr_pool = self.pool.get('res.currency')
206 if curr_pool.is_zero(cr, uid, curr_pool.browse(cr, uid, currency_id), balance):
207 return move_lines
208 else:
209 found = False
210 for line_tuple in move_lines:
211 account = acc_pool.browse(cr, uid, line_tuple[2]['account_id'], context)
212 # search for liquidity, receivable or payable accounts
213 # beacause usually they are the result of operations (invoice total).
214 # So, if we made the invoice in parallel currency, we'd get that different invoice total
215 if account.type == 'liquidity' or account.type == 'receivable' or account.type == 'payable':
216 if line_tuple[2]['debit']:
217 line_tuple[2]['debit'] -= balance
218 found = True
219 break
220 elif line_tuple[2]['credit']:
221 line_tuple[2]['credit'] += balance
222 found = True
223 break
224 if not found:
225 # if no liquidity, receivable or payable accounts are present, we use the first line (randomly).
226 # TODO check if this makes sense
227 if move_lines[0][2]['debit']:
228 move_lines[0][2]['debit'] -= balance
229 elif move_lines[0][2]['credit']:
230 move_lines[0][2]['credit'] += balance
231 return move_lines
232
233 def post(self, cr, uid, ids, context=None):
234 res = super(account_move, self).post(cr, uid, ids, context=context)
235 if context is None:
236 context = {}
237 curr_pool = self.pool.get('res.currency')
238 company_pool = self.pool.get('res.company')
239 uid = SUPERUSER_ID
240 for move in self.browse(cr, uid, ids, context=context):
241 if move.state == 'posted' and not move.parallel_move_ids:
242 # avoid double post in case of 'Skip Draft State for Manual Entries'
243 new_move_lines = []
244 parallel_data = {}
245 for line in move.line_id:
246 for parallel_account in line.account_id.parallel_account_ids:
247 parallel_data[parallel_account.company_id.id] = {}
248 parallel_data[parallel_account.company_id.id]['move_name'] = line.move_id.name
249 parallel_data[parallel_account.company_id.id]['ref'] = line.move_id.ref
250 parallel_data[parallel_account.company_id.id]['date'] = line.date
251 parallel_data[parallel_account.company_id.id]['move_id'] = line.move_id.id
252
253 # search period by code and parallel company
254 period_ids = self.pool.get('account.period').search(cr, uid, [
255 ('code','=',line.period_id.code),
256 ('company_id', '=', parallel_account.company_id.id),
257 ])
258
259 if len(period_ids) == 0:
260 raise orm.except_orm(_('Error !'), _('Period %s does not exist in company %s !')
261 % (line.period_id.code, parallel_account.company_id.name))
262 if len(period_ids) > 1:
263 raise orm.except_orm(_('Error !'), _('Too many periods %s for company %s !')
264 % (line.period_id.code, parallel_account.company_id.name))
265
266 parallel_data[parallel_account.company_id.id]['period_id'] = period_ids[0]
267
268 # search parallel journals for the parallel company
269 parallel_journal_ids = []
270 for journal in line.journal_id.parallel_journal_ids:
271 if journal.company_id.id == parallel_account.company_id.id:
272 parallel_journal_ids.append(journal.id)
273
274 if len(parallel_journal_ids) == 0:
275 raise orm.except_orm(_('Error !'), _('Journal %s does not exist in company %s !')
276 % (line.journal_id.name, parallel_account.company_id.name))
277 if len(parallel_journal_ids) > 1:
278 raise orm.except_orm(_('Error !'), _('Too many journals %s for company %s !')
279 % (line.journal_id.name, parallel_account.company_id.name))
280
281 parallel_data[parallel_account.company_id.id]['journal_id'] = parallel_journal_ids[0]
282
283 new_line_values = {
284 'name': line.name,
285 'date_maturity': line.date_maturity or False,
286 'account_id': parallel_account.id,
287 'period_id': period_ids[0],
288 'journal_id': parallel_journal_ids[0],
289 'company_id': parallel_account.company_id.id,
290 'partner_id': line.partner_id and line.partner_id.id or False,
291 }
292
293 if line.currency_id and line.amount_currency:
294 parallel_sec_curr_iso_code = line.currency_id.name
295 amount = line.amount_currency
296 else:
297 parallel_sec_curr_iso_code = line.company_id.currency_id.name
298 amount = line.debit or ( - line.credit)
299
300 parallel_base_amount = amount
301 if parallel_sec_curr_iso_code != parallel_account.company_id.currency_id.name:
302 # only if parallel company currency is != master move currency
303 # search parallel currency by ISO code and parallel company
304 parallel_secondary_curr_ids = curr_pool.search(cr, uid, [
305 ('name', '=', parallel_sec_curr_iso_code),
306 ('company_id', '=', parallel_account.company_id.id),
307 ], context=context)
308
309 if len(parallel_secondary_curr_ids) == 0:
310 raise orm.except_orm(_('Error !'), _('Currency %s does not exist in company %s !')
311 % (parallel_sec_curr_iso_code, parallel_account.company_id.name))
312 if len(parallel_secondary_curr_ids) > 1:
313 raise orm.except_orm(_('Error !'), _('Too many currencies %s for company %s !')
314 % (parallel_sec_curr_iso_code, parallel_account.company_id.name))
315
316 # compute parallel base amount from document currency, using move date
317 context.update({'date': line.date})
318 parallel_base_amount = curr_pool.compute(cr, uid, parallel_secondary_curr_ids[0],
319 parallel_account.company_id.currency_id.id, amount,
320 context=context)
321
322 new_line_values['amount_currency'] = amount
323 new_line_values['currency_id'] = parallel_secondary_curr_ids[0]
324
325 new_line_values['debit'] = 0.0
326 new_line_values['credit'] = 0.0
327 if parallel_base_amount > 0:
328 new_line_values['debit'] = abs(parallel_base_amount)
329 elif parallel_base_amount < 0:
330 new_line_values['credit'] = abs(parallel_base_amount)
331
332 if line.tax_code_id and line.tax_amount:
333 # search parallel tax codes for the parallel company
334 parallel_tax_code_ids = []
335 for tax_code in line.tax_code_id.parallel_tax_code_ids:
336 if tax_code.company_id.id == parallel_account.company_id.id:
337 parallel_tax_code_ids.append(tax_code.id)
338
339 if len(parallel_tax_code_ids) == 0:
340 raise orm.except_orm(_('Error !'), _('Tax code %s does not exist in company %s !')
341 % (line.tax_code_id.name, parallel_account.company_id.name))
342 if len(parallel_tax_code_ids) > 1:
343 raise orm.except_orm(_('Error !'), _('Too many tax_codes %s for company %s !')
344 % (line.tax_code_id.name, parallel_account.company_id.name))
345
346 new_line_values['tax_code_id'] = parallel_tax_code_ids[0]
347 total_tax = new_line_values['debit'] - new_line_values['credit']
348 new_line_values['tax_amount'] = line.tax_amount < 0 \
349 and - abs(total_tax) \
350 or line.tax_amount > 0 \
351 and abs(total_tax) \
352 or 0.0
353
354 new_move_lines.append((parallel_account.company_id.id, (0,0,new_line_values)))
355 #parallel_data[parallel_account.company_id.id]['move_lines'].append((0,0,new_line_values))
356
357 for company_id in parallel_data:
358 move_lines = []
359 for new_move_line in new_move_lines:
360 if new_move_line[0] == company_id:
361 move_lines.append(new_move_line[1])
362 move_lines=self.balance_lines(cr, uid, move_lines, company_pool.browse(cr, uid, company_id).currency_id.id, context=context)
363 move_values = {
364 'name': parallel_data[company_id]['move_name'],
365 'period_id': parallel_data[company_id]['period_id'],
366 'journal_id': parallel_data[company_id]['journal_id'],
367 'date': parallel_data[company_id]['date'],
368 'company_id': company_id,
369 'line_id': move_lines,
370 'master_parallel_move_id': parallel_data[company_id]['move_id'],
371 'ref': parallel_data[company_id]['ref'],
372 }
373 self.create(cr, uid, move_values, context=context)
374 # self.post(cr, uid, [move_id], context=context)
375
376 return res
377
378
379class account_journal(orm.Model):
380 _inherit = "account.journal"
381
382 _columns = {
383 'parallel_journal_ids': fields.many2many('account.journal',
384 'parallel_journal_rel', 'parent_id',
385 'child_id', 'Parallel Currency Journals',
386 Help="Set here the journals you want to automatically move when registering entries in this journal"),
387 'master_parallel_journal_ids': fields.many2many('account.journal',
388 'parallel_journal_rel', 'child_id',
389 'parent_id', 'Master Parallel Currency Journals',
390 Help="You can see here the journals that automatically move this journal", readonly=True),
391 }
392
393class account_tax_code(orm.Model):
394 _inherit = "account.tax.code"
395
396 def _get_parallel_tax_codes_summary(self, cr, uid, ids, field_name, arg, context=None):
397 res={}
398 for tax_code in self.browse(cr, SUPERUSER_ID, ids, context):
399 text='Configured parallel tax codes:\n'
400 text2=''
401 for parallel_tax_code in tax_code.parallel_tax_code_ids:
402 text2+= _('Tax code: %s. Company: %s\n') % (
403 parallel_tax_code.code, parallel_tax_code.company_id.name)
404 if text2:
405 res[tax_code.id] = text + text2
406 else:
407 res[tax_code.id] = _("No parallel tax codes found")
408 return res
409
410 _columns = {
411 'parallel_tax_code_ids': fields.many2many('account.tax.code',
412 'parallel_tax_code_rel', 'parent_id',
413 'child_id', 'Parallel Currency Tax Codes',
414 Help="Set here the tax codes you want to automatically move when registering entries in this tax code"),
415 'master_parallel_tax_code_ids': fields.many2many('account.tax.code',
416 'parallel_tax_code_rel', 'child_id',
417 'parent_id', 'Master Parallel Currency Tax Codes',
418 Help="You can see here the tax codes that automatically move this journal", readonly=True),
419 'parallel_tax_codes_summary': fields.function(_get_parallel_tax_codes_summary, type='text', string='Parallel tax codes summary'),
420 }
421
422 def _search_parallel_tax_code(self, cr, uid, tax_code, parallel_company,
423 context=None):
424 parallel_tax_code_ids = self.search(cr, uid, [
425 ('company_id','=', parallel_company.id),
426 ('code','=', tax_code),
427 ], context=context)
428 if len(parallel_tax_code_ids) > 1:
429 raise orm.except_orm(_('Error'), _('Too many tax codes %s for company %s')
430 % (tax_code,parallel_company.name))
431 return parallel_tax_code_ids and parallel_tax_code_ids[0] or False
432
433 def _build_tax_code_vals(self, cr, uid, tax_code_vals, parallel_company, context=None):
434 # build only fields I need
435 vals={}
436 if tax_code_vals.has_key('name'):
437 vals['name'] = tax_code_vals['name']
438 if tax_code_vals.has_key('code'):
439 vals['code'] = tax_code_vals['code']
440 if tax_code_vals.has_key('type'):
441 vals['type'] = tax_code_vals['type']
442 if tax_code_vals.has_key('user_type'):
443 vals['user_type'] = tax_code_vals['user_type']
444 if tax_code_vals.has_key('active'):
445 vals['active'] = tax_code_vals['active']
446 if tax_code_vals.has_key('centralized'):
447 vals['centralized'] = tax_code_vals['centralized']
448 if tax_code_vals.has_key('parent_id'):
449 parent_tax_code = self.browse(cr, uid, tax_code_vals['parent_id'], context)
450 parent_parallel_acc_id = self._search_parallel_tax_code(
451 cr, uid, parent_tax_code.code, parallel_company, context=context)
452 if not parent_parallel_acc_id:
453 raise orm.except_orm(_('Error'),
454 _('No parent tax code %s found in company %s') %
455 (parent_tax_code.code, parallel_company.name))
456 vals['parent_id'] = parent_parallel_acc_id
457 return vals
458
459 def create_parallel_tax_codes(self, cr, uid, ids, context=None):
460 for tax_code in self.browse(cr, SUPERUSER_ID, ids, context):
461 for parallel_company in tax_code.company_id.parallel_company_ids:
462 if not tax_code.parent_id:
463 raise orm.except_orm(_('Error'),_('Tax code %s does not have parent')
464 % tax_code.code)
465 existing_ids = self.search(cr, SUPERUSER_ID, [
466 ('code', '=', tax_code.code),
467 ('company_id', '=', parallel_company.id),
468 ])
469 if existing_ids:
470 raise orm.except_orm(_('Error'),
471 _('Tax code %s already exists for company %s')
472 % (tax_code.code, parallel_company.name))
473 parent_parallel_tax_code_id = self._search_parallel_tax_code(
474 cr, SUPERUSER_ID, tax_code.parent_id.code, parallel_company,
475 context=context)
476 new_id = self.create(cr, SUPERUSER_ID,{
477 'company_id': parallel_company.id,
478 'parent_id': parent_parallel_tax_code_id,
479 'name': tax_code.name,
480 'code': tax_code.code,
481 'notprintable': tax_code.notprintable,
482 'sign': tax_code.sign,
483 'info': tax_code.info,
484 })
485 cr.execute(
486 "insert into parallel_tax_code_rel(parent_id,child_id) values (%d,%d)"
487 % (tax_code.id,new_id))
488 return True
489
490 def write(self, cr, uid, ids, vals, context=None):
491 if not vals.has_key('parallel_tax_code_ids'):
492 # write/create parallel tax codes only if 'parallel_tax_code_ids' not explicity written
493 for tax_code_id in ids:
494 tax_code = self.browse(cr, SUPERUSER_ID, tax_code_id, context)
495 for parallel_tax_code in tax_code.parallel_tax_code_ids:
496 parallel_vals = self._build_tax_code_vals(
497 cr, SUPERUSER_ID, vals, parallel_tax_code.company_id, context=context)
498 parallel_tax_code.write(parallel_vals)
499 res=super(account_tax_code,self).write(cr, uid, ids, vals, context=context)
500 return res
501
502 def create(self, cr, uid, vals, context=None):
503 res=super(account_tax_code,self).create(cr, uid, vals, context)
504 self.create_parallel_tax_codes(cr, uid, [res], context=None)
505 return res
0506
=== 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 2013-09-27 07:51:38 +0000
@@ -0,0 +1,504 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4
5 <!--
6 Parallel company
7 -->
8
9 <record id="parallel_company" model="res.company">
10 <field name="name" >Parallel company</field>
11 <field name="currency_id" ref="base.CHF"></field>
12 </record>
13
14 <record id="base.main_company" model="res.company">
15 <field name="parallel_company_ids" eval="[(6,0,[ref('parallel_company')])]"></field>
16 </record>
17
18 <!--
19 currencies
20 -->
21
22 <record id="USD" model="res.currency">
23 <field name="name">USD</field>
24 <field name="symbol">$</field>
25 <field name="rounding">0.01</field>
26 <field name="accuracy">4</field>
27 <field name="position">before</field>
28 <field name="company_id" ref="parallel_company"/>
29 </record>
30 <record id="rateUSD" model="res.currency.rate">
31 <field name="rate">1.2834</field>
32 <field name="currency_id" ref="USD"/>
33 <field eval="time.strftime('%Y-01-01')" name="name"/>
34 </record>
35 <record id="CHF" model="res.currency">
36 <field name="name">CHF</field>
37 <field name="symbol">CHF</field>
38 <field name="rounding">0.01</field>
39 <field name="accuracy">4</field>
40 <field name="company_id" ref="parallel_company"/>
41 </record>
42 <record id="rateCHF" model="res.currency.rate">
43 <field name="rate">1.3086</field>
44 <field name="currency_id" ref="CHF"/>
45 <field eval="time.strftime('%Y-01-01')" name="name"/>
46 </record>
47 <record id="EUR" model="res.currency">
48 <field name="name">EUR</field>
49 <field name="symbol">€</field>
50 <field name="rounding">0.01</field>
51 <field name="accuracy">4</field>
52 <field name="company_id" ref="parallel_company"/>
53 </record>
54 <record id="rateEUR" model="res.currency.rate">
55 <field name="currency_id" ref="EUR" />
56 <field eval="time.strftime('%Y-01-01')" name="name"/>
57 <field name="rate">1.0</field>
58 </record>
59
60 <!--
61 Journal
62 -->
63
64 <record id="parallel_sales_journal" model="account.journal">
65 <field name="name">Parallel Sales Journal - (test)</field>
66 <field name="code">PSAJ</field>
67 <field name="type">sale</field>
68 <field name="company_id" ref="parallel_company"/>
69 </record>
70 <record id="account.sales_journal" model="account.journal">
71 <field name="parallel_journal_ids" eval="[(6,0,[ref('parallel_sales_journal')])]"></field>
72 </record>
73
74 <!--
75 Fiscal year
76 -->
77
78 <record id="data_fiscalyear" model="account.fiscalyear">
79 <field eval="'Fiscal Year X '+time.strftime('%Y')" name="name"/>
80 <field eval="'FY'+time.strftime('%Y')" name="code"/>
81 <field eval="time.strftime('%Y')+'-01-01'" name="date_start"/>
82 <field eval="time.strftime('%Y')+'-12-31'" name="date_stop"/>
83 <field name="company_id" ref="parallel_company"/>
84 </record>
85
86 <!--
87 Fiscal Periods
88 -->
89
90 <record id="period_1" model="account.period">
91 <field eval="'01/'+time.strftime('%Y')" name="code"/>
92 <field eval="'X 01/'+time.strftime('%Y')" name="name"/>
93 <field eval="True" name="special"/>
94 <field name="fiscalyear_id" ref="data_fiscalyear"/>
95 <field eval="time.strftime('%Y')+'-01-01'" name="date_start"/>
96 <field eval="time.strftime('%Y')+'-01-31'" name="date_stop"/>
97 <field name="company_id" ref="parallel_company"/>
98 </record>
99 <record id="period_2" model="account.period">
100 <field eval="'02/'+time.strftime('%Y')" name="code"/>
101 <field eval="'X 02/'+time.strftime('%Y')" name="name"/>
102 <field eval="True" name="special"/>
103 <field name="fiscalyear_id" ref="data_fiscalyear"/>
104 <field eval="time.strftime('%Y')+'-02-01'" name="date_start"/>
105 <!-- for the last day of February, we have to compute the day before March 1st -->
106 <field eval="(DateTime.today().replace(month=3, day=1) - timedelta(days=1)).strftime('%Y-%m-%d')" name="date_stop"/>
107 <field name="company_id" ref="parallel_company"/>
108 </record>
109 <record id="period_3" model="account.period">
110 <field eval="'03/'+time.strftime('%Y')" name="code"/>
111 <field eval="'X 03/'+time.strftime('%Y')" name="name"/>
112 <field eval="True" name="special"/>
113 <field name="fiscalyear_id" ref="data_fiscalyear"/>
114 <field eval="time.strftime('%Y')+'-03-01'" name="date_start"/>
115 <field eval="time.strftime('%Y')+'-03-31'" name="date_stop"/>
116 <field name="company_id" ref="parallel_company"/>
117 </record>
118 <record id="period_4" model="account.period">
119 <field eval="'04/'+time.strftime('%Y')" name="code"/>
120 <field eval="'X 04/'+time.strftime('%Y')" name="name"/>
121 <field eval="True" name="special"/>
122 <field name="fiscalyear_id" ref="data_fiscalyear"/>
123 <field eval="time.strftime('%Y')+'-04-01'" name="date_start"/>
124 <field eval="time.strftime('%Y')+'-04-30'" name="date_stop"/>
125 <field name="company_id" ref="parallel_company"/>
126 </record>
127 <record id="period_5" model="account.period">
128 <field eval="'05/'+time.strftime('%Y')" name="code"/>
129 <field eval="'X 05/'+time.strftime('%Y')" name="name"/>
130 <field eval="True" name="special"/>
131 <field name="fiscalyear_id" ref="data_fiscalyear"/>
132 <field eval="time.strftime('%Y')+'-05-01'" name="date_start"/>
133 <field eval="time.strftime('%Y')+'-05-31'" name="date_stop"/>
134 <field name="company_id" ref="parallel_company"/>
135 </record>
136 <record id="period_6" model="account.period">
137 <field eval="'06/'+time.strftime('%Y')" name="code"/>
138 <field eval="'X 06/'+time.strftime('%Y')" name="name"/>
139 <field name="fiscalyear_id" ref="data_fiscalyear"/>
140 <field eval="True" name="special"/>
141 <field eval="time.strftime('%Y')+'-06-01'" name="date_start"/>
142 <field eval="time.strftime('%Y')+'-06-30'" name="date_stop"/>
143 <field name="company_id" ref="parallel_company"/>
144 </record>
145 <record id="period_7" model="account.period">
146 <field eval="'07/'+time.strftime('%Y')" name="code"/>
147 <field eval="'X 07/'+time.strftime('%Y')" name="name"/>
148 <field eval="True" name="special"/>
149 <field name="fiscalyear_id" ref="data_fiscalyear"/>
150 <field eval="time.strftime('%Y')+'-07-01'" name="date_start"/>
151 <field eval="time.strftime('%Y')+'-07-31'" name="date_stop"/>
152 <field name="company_id" ref="parallel_company"/>
153 </record>
154 <record id="period_8" model="account.period">
155 <field eval="'08/'+time.strftime('%Y')" name="code"/>
156 <field eval="'X 08/'+time.strftime('%Y')" name="name"/>
157 <field eval="True" name="special"/>
158 <field name="fiscalyear_id" ref="data_fiscalyear"/>
159 <field eval="time.strftime('%Y')+'-08-01'" name="date_start"/>
160 <field eval="time.strftime('%Y')+'-08-31'" name="date_stop"/>
161 <field name="company_id" ref="parallel_company"/>
162 </record>
163 <record id="period_9" model="account.period">
164 <field eval="'09/'+time.strftime('%Y')" name="code"/>
165 <field eval="'X 09/'+time.strftime('%Y')" name="name"/>
166 <field eval="True" name="special"/>
167 <field name="fiscalyear_id" ref="data_fiscalyear"/>
168 <field eval="time.strftime('%Y')+'-09-01'" name="date_start"/>
169 <field eval="time.strftime('%Y')+'-09-30'" name="date_stop"/>
170 <field name="company_id" ref="parallel_company"/>
171 </record>
172 <record id="period_10" model="account.period">
173 <field eval="'10/'+time.strftime('%Y')" name="code"/>
174 <field eval="'X 10/'+time.strftime('%Y')" name="name"/>
175 <field eval="True" name="special"/>
176 <field name="fiscalyear_id" ref="data_fiscalyear"/>
177 <field eval="time.strftime('%Y')+'-10-01'" name="date_start"/>
178 <field eval="time.strftime('%Y')+'-10-31'" name="date_stop"/>
179 <field name="company_id" ref="parallel_company"/>
180 </record>
181 <record id="period_11" model="account.period">
182 <field eval="'11/'+time.strftime('%Y')" name="code"/>
183 <field eval="'X 11/'+time.strftime('%Y')" name="name"/>
184 <field eval="True" name="special"/>
185 <field name="fiscalyear_id" ref="data_fiscalyear"/>
186 <field eval="time.strftime('%Y')+'-11-01'" name="date_start"/>
187 <field eval="time.strftime('%Y')+'-11-30'" name="date_stop"/>
188 <field name="company_id" ref="parallel_company"/>
189 </record>
190 <record id="period_12" model="account.period">
191 <field eval="'12/'+time.strftime('%Y')" name="code"/>
192 <field eval="'X 12/'+time.strftime('%Y')" name="name"/>
193 <field eval="True" name="special"/>
194 <field name="fiscalyear_id" ref="data_fiscalyear"/>
195 <field eval="time.strftime('%Y')+'-12-01'" name="date_start"/>
196 <field eval="time.strftime('%Y')+'-12-31'" name="date_stop"/>
197 <field name="company_id" ref="parallel_company"/>
198 </record>
199
200 <!--
201 Chart of Accounts
202 -->
203
204 <record id="chart0" model="account.account">
205 <field name="company_id" ref="parallel_company"/>
206 <field name="code">X0</field>
207 <field name="name">Chart For Automated Tests</field>
208 <field name="type">view</field>
209 <field name="user_type" ref="account.data_account_type_view"/>
210 </record>
211
212 <!-- Balance Sheet -->
213
214 <record id="bal" model="account.account">
215 <field name="company_id" ref="parallel_company"/>
216 <field name="code">X1</field>
217 <field name="name">Balance Sheet - (test)</field>
218 <field ref="chart0" name="parent_id"/>
219 <field name="type">view</field>
220 <field name="user_type" ref="account.data_account_type_view"/>
221 </record>
222
223 <record model="account.account" id="assets_view">
224 <field name="company_id" ref="parallel_company"/>
225 <field name="name">Assets - (test)</field>
226 <field name="code">X10</field>
227 <field name="type">view</field>
228 <field name="user_type" ref="account.data_account_type_asset"/>
229 <field name="reconcile" eval="False"/>
230 <field name="parent_id" ref="bal"/>
231 </record>
232
233 <record id="fas" model="account.account">
234 <field name="company_id" ref="parallel_company"/>
235 <field name="code">X100</field>
236 <field name="name">Fixed Assets - (test)</field>
237 <field ref="assets_view" name="parent_id"/>
238 <field name="type">view</field>
239 <field name="user_type" ref="account.data_account_type_asset"/>
240 </record>
241
242 <record id="xfa" model="account.account">
243 <field name="company_id" ref="parallel_company"/>
244 <field name="code">X1000</field>
245 <field name="name">Fixed Asset Account - (test)</field>
246 <field ref="fas" name="parent_id"/>
247 <field name="type">other</field>
248 <field name="user_type" ref="account.data_account_type_asset"/>
249 </record>
250
251 <record id="nca" model="account.account">
252 <field name="company_id" ref="parallel_company"/>
253 <field name="code">X101</field>
254 <field name="name">Net Current Assets - (test)</field>
255 <field ref="assets_view" name="parent_id"/>
256 <field name="type">view</field>
257 <field name="user_type" ref="account.data_account_type_asset"/>
258 </record>
259
260 <record id="cas" model="account.account">
261 <field name="company_id" ref="parallel_company"/>
262 <field name="code">X1100</field>
263 <field name="name">Current Assets - (test)</field>
264 <field ref="nca" name="parent_id"/>
265 <field name="type">view</field>
266 <field name="user_type" ref="account.data_account_type_asset"/>
267 </record>
268
269 <record id="stk" model="account.account">
270 <field name="company_id" ref="parallel_company"/>
271 <field name="code">X11001</field>
272 <field name="name">Purchased Stocks - (test)</field>
273 <field ref="cas" name="parent_id"/>
274 <field name="type">other</field>
275 <field name="user_type" ref="account.data_account_type_asset"/>
276 </record>
277
278 <record id="a_recv" model="account.account">
279 <field name="company_id" ref="parallel_company"/>
280 <field name="code">X11002</field>
281 <field name="name">Debtors - (test)</field>
282 <field ref="cas" name="parent_id"/>
283 <field name="type">receivable</field>
284 <field eval="True" name="reconcile"/>
285 <field name="user_type" ref="account.data_account_type_receivable"/>
286 </record>
287
288 <record id="ova" model="account.account">
289 <field name="company_id" ref="parallel_company"/>
290 <field name="code">X11003</field>
291 <field name="name">Output VAT - (test)</field>
292 <field ref="cas" name="parent_id"/>
293 <field name="type">other</field>
294 <field name="user_type" ref="account.data_account_type_asset"/>
295 </record>
296
297 <record id="bnk" model="account.account">
298 <field name="company_id" ref="parallel_company"/>
299 <field name="code">X11004</field>
300 <field name="name">Bank Current Account - (test)</field>
301 <field ref="cas" name="parent_id"/>
302 <field name="type">liquidity</field>
303 <field name="user_type" ref="account.data_account_type_asset"/>
304 </record>
305
306 <record id="cash" model="account.account">
307 <field name="company_id" ref="parallel_company"/>
308 <field name="code">X11005</field>
309 <field name="name">Cash - (test)</field>
310 <field ref="cas" name="parent_id"/>
311 <field name="type">liquidity</field>
312 <field name="user_type" ref="account.data_account_type_asset"/>
313 </record>
314
315 <record id="o_income" model="account.account">
316 <field name="company_id" ref="parallel_company"/>
317 <field name="code">X11006</field>
318 <field name="name">Opening Income - (test)</field>
319 <field ref="cas" name="parent_id"/>
320 <field name="type">other</field>
321 <field name="user_type" ref="account.data_account_type_income"/>
322 </record>
323 <record id="usd_bnk" model="account.account">
324 <field name="company_id" ref="parallel_company"/>
325 <field name="code">X11007</field>
326 <field name="name">USD Bank Account - (test)</field>
327 <field ref="cas" name="parent_id"/>
328 <field name="type">liquidity</field>
329 <field name="user_type" ref="account.data_account_type_asset"/>
330 <field name="currency_id" ref="base.USD"/>
331 </record>
332
333 <record model="account.account" id="liabilities_view">
334 <field name="company_id" ref="parallel_company"/>
335 <field name="name">Liabilities - (test)</field>
336 <field name="code">X11</field>
337 <field name="type">view</field>
338 <field name="user_type" ref="account.data_account_type_liability"/>
339 <field name="reconcile" eval="False"/>
340 <field name="parent_id" ref="bal"/>
341 </record>
342
343 <record id="cli" model="account.account">
344 <field name="company_id" ref="parallel_company"/>
345 <field name="code">X110</field>
346 <field name="name">Current Liabilities - (test)</field>
347 <field ref="liabilities_view" name="parent_id"/>
348 <field name="type">view</field>
349 <field name="user_type" ref="account.data_account_type_liability"/>
350 </record>
351
352 <record id="a_pay" model="account.account">
353 <field name="company_id" ref="parallel_company"/>
354 <field name="code">X1111</field>
355 <field name="name">Creditors - (test)</field>
356 <field ref="cli" name="parent_id"/>
357 <field name="type">payable</field>
358 <field eval="True" name="reconcile"/>
359 <field name="user_type" ref="account.data_account_type_payable"/>
360 </record>
361
362 <record id="iva" model="account.account">
363 <field name="company_id" ref="parallel_company"/>
364 <field name="code">X1112</field>
365 <field name="name">Input VAT - (test)</field>
366 <field ref="cli" name="parent_id"/>
367 <field name="type">other</field>
368 <field name="user_type" ref="account.data_account_type_liability"/>
369 </record>
370
371 <record id="rsa" model="account.account">
372 <field name="company_id" ref="parallel_company"/>
373 <field name="code">X1113</field>
374 <field name="name">Reserve and Profit/Loss - (test)</field>
375 <field ref="cli" name="parent_id"/>
376 <field name="type">other</field>
377 <field name="user_type" ref="account.data_account_type_liability"/>
378 </record>
379
380 <record id="o_expense" model="account.account">
381 <field name="company_id" ref="parallel_company"/>
382 <field name="code">X1114</field>
383 <field name="name">Opening Expense - (test)</field>
384 <field ref="cli" name="parent_id"/>
385 <field name="type">other</field>
386 <field name="user_type" ref="account.data_account_type_expense"/>
387 </record>
388
389 <!-- Profit and Loss -->
390
391 <record id="gpf" model="account.account">
392 <field name="company_id" ref="parallel_company"/>
393 <field name="code">X2</field>
394 <field name="name">Profit and Loss - (test)</field>
395 <field ref="chart0" name="parent_id"/>
396 <field name="type">view</field>
397 <field name="user_type" ref="account.data_account_type_view"/>
398 </record>
399
400 <record model="account.account" id="income_view">
401 <field name="company_id" ref="parallel_company"/>
402 <field name="name">Income - (test)</field>
403 <field name="code">X20</field>
404 <field name="type">view</field>
405 <field name="user_type" ref="account.data_account_type_income"/>
406 <field name="reconcile" eval="False"/>
407 <field name="parent_id" ref="gpf"/>
408 </record>
409
410 <record model="account.account" id="income_fx_income">
411 <field name="company_id" ref="parallel_company"/>
412 <field name="name">Foreign Exchange Gain - (test)</field>
413 <field name="code">X201</field>
414 <field name="type">other</field>
415 <field name="user_type" ref="account.data_account_type_income"/>
416 <field name="reconcile" eval="False"/>
417 <field name="parent_id" ref="income_view"/>
418 </record>
419
420 <record id="rev" model="account.account">
421 <field name="company_id" ref="parallel_company"/>
422 <field name="code">X200</field>
423 <field name="name">Revenue - (test)</field>
424 <field ref="income_view" name="parent_id"/>
425 <field name="type">view</field>
426 <field name="user_type" ref="account.data_account_type_income"/>
427 </record>
428
429 <record id="a_sale" model="account.account">
430 <field name="company_id" ref="parallel_company"/>
431 <field name="code">X2001</field>
432 <field name="name">Product Sales - (test)</field>
433 <field ref="rev" name="parent_id"/>
434 <field name="type">other</field>
435 <field name="user_type" ref="account.data_account_type_income"/>
436 </record>
437
438 <record model="account.account" id="expense_view">
439 <field name="company_id" ref="parallel_company"/>
440 <field name="name">Expense - (test)</field>
441 <field name="code">X21</field>
442 <field name="type">view</field>
443 <field name="user_type" ref="account.data_account_type_expense"/>
444 <field name="reconcile" eval="False"/>
445 <field name="parent_id" ref="gpf"/>
446 </record>
447
448
449 <record id="cos" model="account.account">
450 <field name="company_id" ref="parallel_company"/>
451 <field name="code">X210</field>
452 <field name="name">Cost of Sales - (test)</field>
453 <field ref="expense_view" name="parent_id"/>
454 <field name="type">view</field>
455 <field name="user_type" ref="account.data_account_type_expense"/>
456 </record>
457
458 <record id="cog" model="account.account">
459 <field name="company_id" ref="parallel_company"/>
460 <field name="code">X2100</field>
461 <field name="name">Cost of Goods Sold - (test)</field>
462 <field ref="cos" name="parent_id"/>
463 <field name="type">other</field>
464 <field name="user_type" ref="account.data_account_type_expense"/>
465 </record>
466
467 <record id="ovr" model="account.account">
468 <field name="company_id" ref="parallel_company"/>
469 <field name="code">X211</field>
470 <field name="name">Overheads - (test)</field>
471 <field ref="expense_view" name="parent_id"/>
472 <field name="type">view</field>
473 <field name="user_type" ref="account.data_account_type_expense"/>
474 </record>
475
476 <record id="a_expense" model="account.account">
477 <field name="company_id" ref="parallel_company"/>
478 <field name="code">X2110</field>
479 <field name="name">Expenses - (test)</field>
480 <field ref="ovr" name="parent_id"/>
481 <field name="type">other</field>
482 <field name="user_type" ref="account.data_account_type_expense"/>
483 </record>
484
485 <record model="account.account" id="income_fx_expense">
486 <field name="company_id" ref="parallel_company"/>
487 <field name="name">Foreign Exchange Loss - (test)</field>
488 <field name="code">X2111</field>
489 <field name="type">other</field>
490 <field name="user_type" ref="account.data_account_type_expense"/>
491 <field name="reconcile" eval="False"/>
492 <field name="parent_id" ref="ovr"/>
493 </record>
494
495 <record id="a_salary_expense" model="account.account">
496 <field name="company_id" ref="parallel_company"/>
497 <field name="code">X2112</field>
498 <field name="name">Salary Expenses - (test)</field>
499 <field ref="ovr" name="parent_id"/>
500 <field name="type">other</field>
501 <field name="user_type" ref="account.data_account_type_expense"/>
502 </record>
503 </data>
504</openerp>
0505
=== 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 2013-09-27 07:51:38 +0000
@@ -0,0 +1,64 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4 <record id="view_account_form" model="ir.ui.view">
5 <field name="name">account.account.form</field>
6 <field name="model">account.account</field>
7 <field name="inherit_id" ref="account.view_account_form"></field>
8 <field name="arch" type="xml">
9 <field name="note" position="after">
10 <group colspan="4" string="Parallel Currency" groups="account.group_account_manager">
11 <field name="parallel_accounts_summary" />
12 <button name="create_parallel_accounts" type="object" string="Create parallel accounts"></button>
13 <separator string="Parallel Currency Accounts" colspan="4"/>
14 <field colspan="4" name="parallel_account_ids" nolabel="1" domain="[('company_id', '!=', company_id)]"/>
15 <separator string="Master Parallel Currency Accounts" colspan="4"/>
16 <field colspan="4" name="master_parallel_account_ids" nolabel="1"/>
17 </group>
18 </field>
19 </field>
20 </record>
21 <record id="view_account_journal_form" model="ir.ui.view">
22 <field name="name">view_account_journal_form</field>
23 <field name="model">account.journal</field>
24 <field name="inherit_id" ref="account.view_account_journal_form"></field>
25 <field name="arch" type="xml">
26 <page string="Entry Controls" position="after">
27 <page string="Parallel Currency" groups="account.group_account_manager">
28 <separator string="Parallel Currency Journals" colspan="4"/>
29 <field colspan="4" name="parallel_journal_ids" nolabel="1" domain="[('company_id', '!=', company_id)]"/>
30 <separator string="Master Parallel Currency Journals" colspan="4"/>
31 <field colspan="4" name="master_parallel_journal_ids" nolabel="1"/>
32 </page>
33 </page>
34 </field>
35 </record>
36 <record id="view_tax_code_form" model="ir.ui.view">
37 <field name="name">view_tax_code_form</field>
38 <field name="model">account.tax.code</field>
39 <field name="inherit_id" ref="account.view_tax_code_form"></field>
40 <field name="arch" type="xml">
41 <field name="info" position="after">
42 <group colspan="4" col="1" groups="account.group_account_manager">
43 <field name="parallel_tax_codes_summary" />
44 <button name="create_parallel_tax_codes" type="object" string="Create parallel tax codes"></button>
45 <field name="parallel_tax_code_ids" domain="[('company_id', '!=', company_id)]"/>
46 <field name="master_parallel_tax_code_ids"/>
47 </group>
48 </field>
49 </field>
50 </record>
51 <record id="view_move_form" model="ir.ui.view">
52 <field name="name">view_move_form</field>
53 <field name="model">account.move</field>
54 <field name="inherit_id" ref="account.view_move_form"></field>
55 <field name="arch" type="xml">
56 <page string="Journal Items" position="after">
57 <page string="Parallel Entries" groups="account.group_account_manager">
58 <field colspan="4" name="parallel_move_ids" nolabel="1" />
59 </page>
60 </page>
61 </field>
62 </record>
63 </data>
64</openerp>
065
=== 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 2013-09-27 07:51:38 +0000
@@ -0,0 +1,16 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<openerp>
3 <data>
4 <record id="view_company_form" model="ir.ui.view">
5 <field name="inherit_id" ref="base.view_company_form"/>
6 <field name="name">view.company.form</field>
7 <field name="model">res.company</field>
8 <field name="arch" type="xml">
9 <page string="Configuration" position="inside">
10 <separator string="Parallel Companies" colspan="4"/>
11 <field name="parallel_company_ids" nolabel="1" colspan="4"/>
12 </page>
13 </field>
14 </record>
15 </data>
16</openerp>
017
=== added directory 'account_parallel_currency/i18n'
=== 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 2013-09-27 07:51:38 +0000
@@ -0,0 +1,33 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (C) 2012-2013 Agile Business Group sagl
5# (<http://www.agilebg.com>)
6# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as published
10# by the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23from openerp.osv import fields, orm
24from osv import fields
25
26class res_company(orm.Model):
27 _inherit = "res.company"
28
29 _columns = {
30 'parallel_company_ids': fields.many2many('res.company', 'parallel_companies_rel', 'master_id',
31 'parallel_id', 'Parallel Companies'),
32 }
33
034
=== 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 2013-09-27 07:51:38 +0000
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3<data noupdate="0">
4 <record model="ir.rule" id="res_currency_comp_rule">
5 <field name="name">Currency multi-company</field>
6 <field name="model_id" ref="base.model_res_currency"/>
7 <field name="global" eval="True"/>
8 <field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
9 </record>
10</data>
11</openerp>
012
=== 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 2013-09-27 07:51:38 +0000
@@ -0,0 +1,143 @@
1-
2 In order to test account invoice I create a new customer invoice
3-
4 I will create bank detail
5-
6 !record {model: res.partner.bank, id: res_partner_bank_0}:
7 state: bank
8 company_id: base.main_company
9 partner_id: base.main_partner
10 acc_number: 123456789
11 footer: True
12 bank: base.res_bank_1
13 bank_name: Reserve
14-
15 I create a customer invoice
16-
17 !record {model: account.invoice, id: account_invoice_customer0, view: account.invoice_form}:
18 payment_term: account.account_payment_term_advance
19 partner_bank_id: res_partner_bank_0
20 journal_id: account.sales_journal
21 partner_id: base.res_partner_3
22 reference_type: none
23 name: 'Test Customer Invoice'
24 invoice_line:
25 - product_id: product.product_product_5
26 quantity: 10.0
27-
28 I manually assign tax on invoice
29-
30 !python {model: account.invoice.tax}: |
31 amt = self.amount_change(cr, uid, [], 50.0, ref('base.EUR'), ref('base.main_company'), False)
32 base_amt = self.base_change(cr, uid, [], 9000.0, ref('base.EUR'), ref('base.main_company'), False)
33 invoice_tax_line = {
34 'name': 'Test Tax for Customer Invoice',
35 'manual': 1,
36 'base': base_amt['value']['base_amount'],
37 'amount': amt['value']['tax_amount'],
38 'account_id': ref('account.ova'),
39 'invoice_id': ref("account_invoice_customer0"),
40 'tax_code_id': ref('tax_code'),
41 'tax_amount': amt['value']['tax_amount'],
42 }
43 tax = self.create(cr, uid, invoice_tax_line)
44 assert tax, "Tax has not been assigned correctly"
45
46-
47 I check that Initially customer invoice is in the "Draft" state
48-
49 !assert {model: account.invoice, id: account_invoice_customer0}:
50 - state == 'draft'
51-
52 I confirm invoice by clicking on validate button
53-
54 !workflow {model: account.invoice, action: invoice_open, ref: account_invoice_customer0}
55-
56 I check that the invoice state is "Open"
57-
58 !assert {model: account.invoice, id: account_invoice_customer0}:
59 - state == 'open'
60
61-
62 I check moves attached to the invoice
63-
64 !python {model: account.invoice}: |
65 acc_id=self.browse(cr, uid, ref("account_invoice_customer0"))
66 assert acc_id.move_id, "Move not created for open invoice"
67 assert acc_id.move_id.parallel_move_ids, "Parallel move not created for open invoice"
68 for parallel_move in acc_id.move_id.parallel_move_ids:
69 for line in parallel_move.line_id:
70 if line.account_id.id == ref("a_sale"):
71 assert line.credit == 11777.40, "CHF Product Sales must be 11777.40"
72 assert line.amount_currency == -9000.0, "EUR Product Sales must be -9000.0"
73 assert line.currency_id.id == ref("EUR"), "Secondary currency must be EUR"
74 if line.account_id.id == ref("ova"):
75 assert line.tax_amount == 65.43, "CHF Tax amount must be 65.43"
76 assert line.credit == 65.43, "CHF Tax amount must be 65.43"
77
78-
79 I create a customer CHF invoice
80-
81 !record {model: account.invoice, id: account_invoice_customer1, view: account.invoice_form}:
82 partner_bank_id: res_partner_bank_0
83 journal_id: account.sales_journal
84 partner_id: base.res_partner_3
85 reference_type: none
86 name: 'Test Customer CHF Invoice'
87 currency_id: base.CHF
88 invoice_line:
89 - product_id: product.product_product_5
90 quantity: 1.0
91 price_unit: 100.0
92
93-
94 I confirm invoice by clicking on validate button
95-
96 !workflow {model: account.invoice, action: invoice_open, ref: account_invoice_customer1}
97
98-
99 I check moves attached to the invoice
100-
101 !python {model: account.invoice}: |
102 acc_id=self.browse(cr, uid, ref("account_invoice_customer1"))
103 assert acc_id.move_id, "Move not created for open invoice"
104 assert acc_id.move_id.parallel_move_ids, "Parallel move not created for open invoice"
105 for parallel_move in acc_id.move_id.parallel_move_ids:
106 for line in parallel_move.line_id:
107 if line.account_id.id == ref("a_sale"):
108 assert line.credit == 100.0, "CHF Product Sales must be 100.0"
109 assert not line.amount_currency, "amount_currency must be empty"
110 assert not line.currency_id, "currency_id must be empty"
111
112-
113 I create a customer USD invoice
114-
115 !record {model: account.invoice, id: account_invoice_customer2, view: account.invoice_form}:
116 journal_id: account.sales_journal
117 partner_id: base.res_partner_3
118 reference_type: none
119 name: 'Test Customer USD Invoice'
120 currency_id: base.USD
121 invoice_line:
122 - product_id: product.product_product_5
123 quantity: 1.0
124 price_unit: 100.0
125
126-
127 I confirm invoice by clicking on validate button
128-
129 !workflow {model: account.invoice, action: invoice_open, ref: account_invoice_customer2}
130
131-
132 I check moves attached to the invoice
133-
134 !python {model: account.invoice}: |
135 acc_id=self.browse(cr, uid, ref("account_invoice_customer2"))
136 assert acc_id.move_id, "Move not created for open invoice"
137 assert acc_id.move_id.parallel_move_ids, "Parallel move not created for open invoice"
138 for parallel_move in acc_id.move_id.parallel_move_ids:
139 for line in parallel_move.line_id:
140 if line.account_id.id == ref("a_sale"):
141 assert line.credit == 101.96, "USD Product Sales must be 101.96"
142 assert line.amount_currency == -100.0, "USD Product Sales must be -100.0"
143 assert line.currency_id.id == ref("USD"), "Secondary currency must be USD"
0144
=== 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 2013-09-27 07:51:38 +0000
@@ -0,0 +1,25 @@
1-
2 I create Tax Codes
3-
4 !record {model: account.tax.code, id: tax_code}:
5 name: tax_code
6 code: 1
7 company_id: base.main_company
8 sign: 1
9-
10 !record {model: account.tax.code, id: parallel_tax_code}:
11 name: parallel_tax_code
12 code: 1
13 company_id: parallel_company
14 sign: 1
15-
16 I create the mapping wizard
17-
18 !record {model: account.parallel.mapping, id: account_parallel_mapping_0}:
19 remove_old_mapping: True
20
21-
22 I click on do mapping
23-
24 !python {model: account.parallel.mapping}: |
25 self.do_mapping(cr, uid, [ref("account_parallel_mapping_0")])
026
=== 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 2013-09-27 07:51:38 +0000
@@ -0,0 +1,22 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (C) 2012-2013 Agile Business Group sagl
5# (<http://www.agilebg.com>)
6# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as published
10# by the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22import do_mapping
023
=== 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 2013-09-27 07:51:38 +0000
@@ -0,0 +1,92 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (C) 2012-2013 Agile Business Group sagl
5# (<http://www.agilebg.com>)
6# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as published
10# by the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23from openerp.osv import fields, orm
24from tools.translate import _
25import logging
26from openerp import SUPERUSER_ID
27
28_logger = logging.getLogger(__name__)
29
30class account_parallel_mapping(orm.TransientModel):
31
32 _name = "account.parallel.mapping"
33
34 _columns = {
35 'message': fields.text('Message'),
36 'remove_old_mapping': fields.boolean('Remove Previous Mapping'),
37 }
38
39 _defaults = {
40 'remove_old_mapping': True,
41 }
42
43 def do_mapping(self, cr, uid, ids, context=None):
44 company_pool = self.pool.get('res.company')
45 account_pool = self.pool.get('account.account')
46 tax_code_pool = self.pool.get('account.tax.code')
47 company_ids = company_pool.search(cr, SUPERUSER_ID, [])
48 wizard =self.browse(cr, uid, ids[0])
49 if wizard.remove_old_mapping:
50 account_ids = account_pool.search(cr, SUPERUSER_ID, [])
51 account_pool.write(cr, SUPERUSER_ID, account_ids, {'parallel_account_ids': [(6,0,[])]})
52 for company_id in company_ids:
53 company = company_pool.browse(cr, SUPERUSER_ID, company_id)
54 if company.parallel_company_ids:
55 master_account_ids = account_pool.search(cr, SUPERUSER_ID, [('company_id', '=', company.id)])
56 master_tax_code_ids = tax_code_pool.search(cr, SUPERUSER_ID, [('company_id', '=', company.id)])
57 # account mapping
58 for master_account_id in master_account_ids:
59 master_account = account_pool.browse(cr, SUPERUSER_ID, master_account_id)
60 for parallel_company in company.parallel_company_ids:
61 parallel_account_ids = account_pool.search(cr, SUPERUSER_ID, [
62 ('code', '=', master_account.code),
63 ('company_id', '=', parallel_company.id),
64 ])
65 if len(parallel_account_ids) > 1:
66 raise orm.except_orm(_('Error'), _('Duplicated account %s for company %s')
67 % (master_account.code,parallel_company.name))
68 elif not parallel_account_ids:
69 raise orm.except_orm(_('Error'), _('No account %s for company %s')
70 % (master_account.code,parallel_company.name))
71 elif len(parallel_account_ids) == 1:
72 master_account.write({'parallel_account_ids':
73 [(4,parallel_account_ids[0])]})
74 # tax code mapping
75 for master_tax_code_id in master_tax_code_ids:
76 master_tax_code = tax_code_pool.browse(cr, SUPERUSER_ID, master_tax_code_id)
77 for parallel_company in company.parallel_company_ids:
78 parallel_tax_code_ids = tax_code_pool.search(cr, SUPERUSER_ID, [
79 ('code', '=', master_tax_code.code),
80 ('company_id', '=', parallel_company.id),
81 ])
82 if len(parallel_tax_code_ids) > 1:
83 raise orm.except_orm(_('Error'), _('Duplicated tax code %s for company %s')
84 % (master_tax_code.code,parallel_company.name))
85 elif not parallel_tax_code_ids:
86 raise orm.except_orm(_('Error'), _('No tax code %s for company %s')
87 % (master_tax_code.code,parallel_company.name))
88 elif len(parallel_tax_code_ids) == 1:
89 master_tax_code.write({'parallel_tax_code_ids':
90 [(4,parallel_tax_code_ids[0])]})
91 self.write(cr, uid, ids, {'message': _('Done')})
92 return True
093
=== 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 2013-09-27 07:51:38 +0000
@@ -0,0 +1,32 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4
5 <record id="account_parallel_mapping" model="ir.ui.view">
6 <field name="name">account.parallel.mapping</field>
7 <field name="model">account.parallel.mapping</field>
8 <field name="arch" type="xml">
9 <form string="Parallel Mapping" >
10 <group col="2">
11 <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"/>
12 <field name="remove_old_mapping" colspan="2"/>
13 <button icon="gtk-cancel" special="cancel" string="Close" />
14 <button icon="gtk-ok" name="do_mapping" string="Run" type="object" />
15 <field name="message" colspan="2" nolabel="1" readonly="1"/>
16 </group>
17 </form>
18 </field>
19 </record>
20
21 <record id="action_account_parallel_mapping" model="ir.actions.act_window">
22 <field name="name">Parallel Accounting Mapping</field>
23 <field name="res_model">account.parallel.mapping</field>
24 <field name="view_type">form</field>
25 <field name="view_mode">form</field>
26 <field name="view_id" ref="account_parallel_mapping"/>
27 <field name="target">new</field>
28 </record>
29
30 <menuitem name="Parallel Accounting Mapping" action="action_account_parallel_mapping" id="menu_action_account_parallel_mapping" parent="account.menu_finance_accounting"/>
31 </data>
32</openerp>

Subscribers

People subscribed via source and target branches