Launchpad automatic translations update.
[odoo/odoo.git] / addons / l10n_be_coda / l10n_be_coda.py
1 # -*- encoding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #
6 #    Copyright (c) 2011 Noviat nv/sa (www.noviat.be). All rights reserved.
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
10 #    published by the Free Software Foundation, either version 3 of the
11 #    License, or (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 from osv import osv, fields
24 import decimal_precision as dp
25 from tools.translate import _
26
27 class coda_bank_account(osv.osv):
28     _name= 'coda.bank.account'
29     _description= 'CODA Bank Account Configuration'
30
31     def _check_currency(self, cr, uid, ids, context=None):
32         obj_cba = self.browse(cr, uid, ids[0], context=context)
33         if (obj_cba.state == 'normal') and obj_cba.journal and (obj_cba.currency != obj_cba.journal.currency):
34             return False
35         return True
36
37     _columns = {
38         'name': fields.char('Name', size=64, required=True),
39         'bank_id': fields.many2one('res.partner.bank', 'Bank Account', required=True,
40             help='Bank Account Number.\nThe CODA import function will find its CODA processing parameters on this number.'),
41         'description1': fields.char('Primary Account Description', size=35,
42             help='The Primary or Secondary Account Description should match the corresponding Account Description in the CODA file.'),
43         'description2': fields.char('Secondary Account Description', size=35,
44             help='The Primary or Secondary Account Description should match the corresponding Account Description in the CODA file.'),
45         'state': fields.selection([
46             ('normal', 'Normal'),
47             ('info', 'Info')],
48             'Type', required=True, select=1,
49             help='No Bank Statements will be generated for CODA Bank Statements from Bank Accounts of type \'Info\'.'),
50         'journal': fields.many2one('account.journal', 'Journal',
51             domain=[('type', '=', 'bank')],
52             states={'normal':[('required',True)],'info':[('required',False)]},
53             help='Bank Journal for the Bank Statement'),
54         'currency': fields.many2one('res.currency', 'Currency', required=True,
55             help='The currency of the CODA Bank Statement'),
56         'coda_st_naming': fields.char('Bank Statement Naming Policy', size=64,
57             help="Define the rules to create the name of the Bank Statements generated by the CODA processing." \
58                  "\nE.g. %(code)s%(y)s/%(paper)s"
59                  "\n\nVariables:" \
60                  "\nBank Journal Code: %(code)s" \
61                  "\nCurrent Year with Century: %(year)s" \
62                  "\nCurrent Year without Century: %(y)s" \
63                  "\nCODA sequence number: %(coda)s" \
64                  "\nPaper Statement sequence number: %(paper)s"),
65         'def_payable': fields.many2one('account.account', 'Default Payable Account', domain=[('type', '=', 'payable')], required=True,
66             help= 'Set here the payable account that will be used, by default, if the partner is not found.'),
67         'def_receivable': fields.many2one('account.account', 'Default Receivable Account', domain=[('type', '=', 'receivable')], required=True,
68             help= 'Set here the receivable account that will be used, by default, if the partner is not found.',),
69         'awaiting_account': fields.many2one('account.account', 'Default Account for Unrecognized Movement', domain=[('type', '!=', 'view')], required=True,
70             help= 'Set here the default account that will be used if the partner cannot be unambiguously identified.'),
71         'transfer_account': fields.many2one('account.account', 'Default Internal Transfer Account', domain=[('code', 'like', '58%'), ('type', '!=', 'view')], required=True,
72             help= 'Set here the default account that will be used for internal transfer between own bank accounts (e.g. transfer between current and deposit bank accounts).'),
73         'find_bbacom': fields.boolean('Lookup Invoice', required=True, help='Partner lookup via the \'BBA\' Structured Communication field of the Invoice.'),
74         'find_partner': fields.boolean('Lookup Partner', required=True, help='Partner lookup via Bank Account Number.'),
75         'active': fields.boolean('Active', help='If the active field is set to False, it will allow you to hide the Bank Account without removing it.'),
76         'company_id': fields.many2one('res.company', 'Company', required=True),
77     }
78     _defaults = {
79         'currency': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.currency_id.id,
80         'state': 'normal',
81         'coda_st_naming': '%(code)s/%(y)s/%(coda)s',
82         'active': True,
83         'find_bbacom': True,
84         'find_partner': True,
85         'company_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
86     }
87     _sql_constraints = [
88         ('account_uniq_1', 'unique (bank_id, description1, currency)', 'The combination of Bank Account, Account Description and Currency must be unique !'),
89         ('account_uniq_2', 'unique (bank_id, description2, currency)', 'The combination of Bank Account, Account Description and Currency must be unique !'),
90     ]
91     _constraints = [
92         (_check_currency, '\n\nConfiguration Error! \nThe Bank Account Currency should match the Journal Currency !', ['currency', 'journal']),
93     ]
94     _order = 'name'
95
96     def name_get(self, cr, uid, ids, context=None):
97         res = []
98         if not len(ids):
99             return res
100         for id in self.browse(cr, uid, ids, context=context):
101             res.append((id.id, (id.bank_id.iban or id.bank_id.acc_number) + ' (' + id.currency.name + ')' + \
102                 (id.description1 and (' - ' + id.description1) or '')))
103         return res
104
105     def copy(self, cr, uid, id, default=None, context=None):
106         cba = self.browse(cr, uid, id, context=context)
107         if not default:
108             default = {}
109         default = default.copy()
110         default.update(
111             journal_id=None,
112             description1=cba['description1'] or '',
113             description2=cba['description2'] or '',
114             name=_("%s (copy)") % (cba['name'] or ''),
115             state=cba['state'])
116         return super(coda_bank_account, self).copy(cr, uid, id, default, context)
117
118     def onchange_state(self, cr, uid, ids, state):
119         return state =='info' and {'value': {'journal': None}} or {}
120
121 coda_bank_account()
122
123 class account_coda(osv.osv):
124     _name = 'account.coda'
125     _description = 'Object to store CODA Data Files'
126     _order = 'coda_creation_date desc'
127     _columns = {
128         'name': fields.char('CODA Filename',size=128, readonly=True),
129         'coda_data': fields.binary('CODA File', readonly=True),
130         'statement_ids': fields.one2many('coda.bank.statement','coda_id','Generated CODA Bank Statements', readonly=True),
131         'note': fields.text('Import Log', readonly=True),
132         'coda_creation_date': fields.date('CODA Creation Date', readonly=True, select=True),
133         'date': fields.date('Import Date', readonly=True, select=True),
134         'user_id': fields.many2one('res.users','User', readonly=True, select=True),
135         'company_id': fields.many2one('res.company', 'Company', readonly=True)
136     }
137     _defaults = {
138         'date': fields.date.context_today,
139         'user_id': lambda self,cr,uid,context: uid,
140         'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'account.coda', context=c),
141     }
142     _sql_constraints = [
143         ('coda_uniq', 'unique (name, coda_creation_date)', 'This CODA has already been imported !')
144     ]
145
146     def unlink(self, cr, uid, ids, context=None):
147         if context is None:
148             context = {}
149         context.update({'coda_unlink': True})
150         coda_st_obj = self.pool.get('coda.bank.statement')
151         bank_st_obj = self.pool.get('account.bank.statement')
152         for coda in self.browse(cr, uid, ids, context=context):
153             for coda_statement in coda.statement_ids:
154                 if not context.get('coda_statement_unlink', False):
155                     if coda_st_obj.exists(cr, uid, coda_statement.id, context=context):
156                         coda_st_obj.unlink(cr, uid, [coda_statement.id], context=context)
157                 if not context.get('bank_statement_unlink', False):
158                     if coda_st_obj.exists(cr, uid, coda_statement.id, context=context) and (coda_statement.type == 'normal') and bank_st_obj.exists(cr, uid, coda_statement.statement_id.id, context=context):
159                         bank_st_obj.unlink(cr, uid, [coda_statement.statement_id.id], context=context)
160         context.update({'coda_unlink': False})
161         return super(account_coda, self).unlink(cr, uid, ids, context=context)
162
163 account_coda()
164
165 class account_coda_trans_type(osv.osv):
166     _name = 'account.coda.trans.type'
167     _description = 'CODA transaction type'
168     _rec_name = 'type'
169     _columns = {
170         'type': fields.char('Transaction Type', size=1, required=True),
171         'parent_id': fields.many2one('account.coda.trans.type', 'Parent'),
172         'description': fields.text('Description', translate=True),
173     }
174
175 account_coda_trans_type()
176
177 class account_coda_trans_code(osv.osv):
178     _name = 'account.coda.trans.code'
179     _description = 'CODA transaction code'
180     _rec_name = 'code'
181     _columns = {
182         'code': fields.char('Code', size=2, required=True, select=1),
183         'type': fields.selection([
184                 ('code', 'Transaction Code'),
185                 ('family', 'Transaction Family')],
186                 'Type', required=True, select=1),
187         'parent_id': fields.many2one('account.coda.trans.code', 'Family', select=1),
188         'description': fields.char('Description', size=128, translate=True, select=2),
189         'comment': fields.text('Comment', translate=True),
190     }
191
192 account_coda_trans_code()
193
194 class account_coda_trans_category(osv.osv):
195     _name = 'account.coda.trans.category'
196     _description = 'CODA transaction category'
197     _rec_name = 'category'
198     _columns = {
199         'category': fields.char('Transaction Category', size=3, required=True),
200         'description': fields.char('Description', size=256, translate=True),
201     }
202
203 account_coda_trans_category()
204
205 class account_coda_comm_type(osv.osv):
206     _name = 'account.coda.comm.type'
207     _description = 'CODA structured communication type'
208     _rec_name = 'code'
209     _columns = {
210         'code': fields.char('Structured Communication Type', size=3, required=True, select=1),
211         'description': fields.char('Description', size=128, translate=True),
212     }
213     _sql_constraints = [
214         ('code_uniq', 'unique (code)','The Structured Communication Code must be unique !')
215     ]
216
217 account_coda_comm_type()
218
219 class coda_bank_statement(osv.osv):
220     _name = 'coda.bank.statement'
221     _description = 'CODA Bank Statement'
222
223     def _default_journal_id(self, cr, uid, context=None):
224         if context is None:
225             context = {}
226         if context.get('journal_id', False):
227             return context['journal_id']
228         return False
229
230     def _end_balance(self, cursor, user, ids, name, attr, context=None):
231         res = {}
232         statements = self.browse(cursor, user, ids, context=context)
233         for statement in statements:
234             res[statement.id] = statement.balance_start
235             for line in statement.line_ids:
236                     res[statement.id] += line.amount
237         for r in res:
238             res[r] = round(res[r], 2)
239         return res
240
241     def _get_period(self, cr, uid, context=None):
242         periods = self.pool.get('account.period').find(cr, uid)
243         if periods:
244             return periods[0]
245         else:
246             return False
247
248     _order = 'date desc'
249     _columns = {
250         'name': fields.char('Name', size=64, required=True, readonly=True),
251         'date': fields.date('Date', required=True, readonly=True),
252         'coda_id': fields.many2one('account.coda', 'CODA Data File', ondelete='cascade'),
253         'type': fields.selection([
254             ('normal', 'Normal'),
255             ('info', 'Info')],
256             'Type', required=True, readonly=True,
257             help='No Bank Statements are associated with CODA Bank Statements of type \'Info\'.'),
258         'statement_id': fields.many2one('account.bank.statement', 'Associated Bank Statement'),
259         'journal_id': fields.many2one('account.journal', 'Journal', readonly=True, domain=[('type', '=', 'bank')]),
260         'coda_bank_account_id': fields.many2one('coda.bank.account', 'Bank Account', readonly=True),
261         'period_id': fields.many2one('account.period', 'Period', required=True, readonly=True),
262         'balance_start': fields.float('Starting Balance', digits_compute=dp.get_precision('Account'), readonly=True),
263         'balance_end_real': fields.float('Ending Balance', digits_compute=dp.get_precision('Account'), readonly=True),
264         'balance_end': fields.function(_end_balance, method=True, store=True, string='Balance'),
265         'line_ids': fields.one2many('coda.bank.statement.line',
266             'statement_id', 'CODA Bank Statement lines', readonly=True),
267         'currency': fields.many2one('res.currency', 'Currency', required=True, readonly=True,
268             help='The currency of the CODA Bank Statement'),
269         'company_id': fields.related('journal_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True),
270     }
271     _defaults = {
272         'type': 'normal',
273         'currency': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.currency_id.id,
274         'journal_id': _default_journal_id,
275         'period_id': _get_period,
276     }
277
278     def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
279         if context is None:
280             context = {}
281         res = super(coda_bank_statement, self).search(cr, uid, args=args, offset=offset, limit=limit, order=order,
282                 context=context, count=count)
283         if context.get('bank_statement', False) and not res:
284             raise osv.except_osv('Warning', _('No CODA Bank Statement found for this Bank Statement!'))
285         return res
286
287     def unlink(self, cr, uid, ids, context=None):
288         if context is None:
289             context = {}
290         context.update({'coda_statement_unlink': True})
291         coda_obj = self.pool.get('account.coda')
292         bank_st_obj = self.pool.get('account.bank.statement')
293
294         # find all CODA bank statements that are associated with the selected CODA bank statements via a common CODA file
295         new_ids = []
296         for coda_statement in self.browse(cr, uid, ids, context=context):
297             if coda_obj.exists(cr, uid, coda_statement.coda_id.id, context=context):
298                 new_ids += [x.id for x in coda_obj.browse(cr, uid, coda_statement.coda_id.id, context=context).statement_ids]
299
300         # unlink CODA banks statements as well as associated bank statements and CODA files
301         for coda_statement in self.browse(cr, uid, new_ids, context=context):
302             if coda_statement.statement_id.state == 'confirm':
303                 raise osv.except_osv(_('Invalid Action!'),
304                     _("Cannot delete CODA Bank Statement '%s' of journal '%s'." \
305                       "\nThe associated Bank Statement has already been confirmed." \
306                       "\nPlease undo this action first.") \
307                       % (coda_statement.name, coda_statement.journal_id.name))
308             else:
309                 if not context.get('coda_unlink', False):
310                     if coda_statement.coda_id and coda_obj.exists(cr, uid, coda_statement.coda_id.id, context=context):
311                         coda_obj.unlink(cr, uid, [coda_statement.coda_id.id], context=context)
312                 if not context.get('bank_statement_unlink', False):
313                     if coda_statement.statement_id and bank_st_obj.exists(cr, uid, coda_statement.statement_id.id, context=context):
314                         bank_st_obj.unlink(cr, uid, [coda_statement.statement_id.id], context=context)
315
316         context.update({'coda_statement_unlink': False})
317         return super(coda_bank_statement, self).unlink(cr, uid, new_ids, context=context)
318
319 coda_bank_statement()
320
321 class account_bank_statement(osv.osv):
322     _inherit = 'account.bank.statement'
323     _columns = {
324         'coda_statement_id': fields.many2one('coda.bank.statement', 'Associated CODA Bank Statement'),
325     }
326
327     def unlink(self, cr, uid, ids, context=None):
328         if context is None:
329             context = {}
330         context.update({'bank_statement_unlink': True})
331         coda_obj = self.pool.get('account.coda')
332         coda_st_obj = self.pool.get('coda.bank.statement')
333
334         # find all statements that are associated with the selected bank statements via a common CODA file
335         ids_plus = []
336         for statement in self.browse(cr, uid, ids, context=context):
337             if statement.coda_statement_id:
338                 for x in coda_obj.browse(cr, uid, statement.coda_statement_id.coda_id.id, context=context).statement_ids:
339                     if x.type == 'normal':
340                         ids_plus += [x.statement_id.id]
341
342         # unlink banks statements as well as associated CODA bank statements and CODA files
343         for statement in self.browse(cr, uid, ids_plus, context=context):
344             if not context.get('coda_statement_unlink', False):
345                 if statement.coda_statement_id and coda_st_obj.exists(cr, uid, statement.coda_statement_id.id, context=context):
346                     coda_st_obj.unlink(cr, uid, [statement.coda_statement_id.id], context=context)
347             if not context.get('coda_unlink', False):
348                 if statement.coda_statement_id \
349                     and coda_st_obj.exists(cr, uid, statement.coda_statement_id.id, context=context) \
350                     and statement.coda_statement_id.coda_id \
351                     and coda_obj.exists(cr, uid, statement.coda_statement_id.coda_id.id, context=context):
352                         coda_obj.unlink(cr, uid, [statement.coda_statement_id.coda_id.id], context=context)
353
354         context.update({'bank_statement_unlink': False})
355         new_ids = list(set(ids + ids_plus))
356         return super(account_bank_statement, self).unlink(cr, uid, new_ids, context=context)
357
358 account_bank_statement()
359
360 class coda_bank_statement_line(osv.osv):
361     _name = 'coda.bank.statement.line'
362     _order = 'sequence'
363     _description = 'CODA Bank Statement Line'
364     _columns = {
365         'name': fields.char('Communication', size=268, required=True),
366         'sequence': fields.integer('Sequence'),
367         'date': fields.date('Entry Date', required=True),
368         'val_date': fields.date('Valuta Date'),
369         'account_id': fields.many2one('account.account','Account'),     # remove required=True
370         'type': fields.selection([
371             ('supplier','Supplier'),
372             ('customer','Customer'),
373             ('general','General'),
374             ('globalisation','Globalisation'),
375             ('information','Information'),
376             ('communication','Free Communication'),
377             ], 'Type', required=True),
378         'globalisation_level': fields.integer('Globalisation Level',
379                 help="The value which is mentioned (1 to 9), specifies the hierarchy level"
380                      " of the globalisation of which this record is the first."
381                      "\nThe same code will be repeated at the end of the globalisation."),
382         'globalisation_amount': fields.float('Globalisation Amount', digits_compute=dp.get_precision('Account')),
383         'globalisation_id': fields.many2one('account.bank.statement.line.global', 'Globalisation ID', readonly=True,
384             help="Code to identify transactions belonging to the same globalisation level within a batch payment"),
385         'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')),
386         'partner_id': fields.many2one('res.partner', 'Partner'),
387         'counterparty_name': fields.char('Counterparty Name', size=35),
388         'counterparty_bic': fields.char('Counterparty BIC', size=11),
389         'counterparty_number': fields.char('Counterparty Number', size=34),
390         'counterparty_currency': fields.char('Counterparty Currency', size=3),
391         'statement_id': fields.many2one('coda.bank.statement', 'CODA Bank Statement',
392             select=True, required=True, ondelete='cascade'),
393         'coda_bank_account_id': fields.related('statement_id', 'coda_bank_account_id', type='many2one', relation='coda.bank.account', string='Bank Account', store=True, readonly=True),
394         'ref': fields.char('Reference', size=32),
395         'note': fields.text('Notes'),
396         'company_id': fields.related('statement_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True),
397     }
398
399     def unlink(self, cr, uid, ids, context=None):
400         if context is None:
401             context = {}
402         if context.get('block_statement_line_delete', False):
403             raise osv.except_osv('Warning', _('Delete operation not allowed.'))
404         return super(account_bank_statement_line, self).unlink(cr, uid, ids, context=context)
405
406 coda_bank_statement_line()
407
408 class account_bank_statement_line_global(osv.osv):
409     _inherit = 'account.bank.statement.line.global'
410     _columns = {
411         'coda_statement_line_ids': fields.one2many('coda.bank.statement.line', 'globalisation_id', 'CODA Bank Statement Lines', readonly=True),
412     }
413
414 account_bank_statement_line_global()
415
416 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: