1 # -*- encoding: utf-8 -*-
2 ##############################################################################
4 # Author: Nicolas Bessi. Copyright Camptocamp SA
5 # Donors: Hasa Sàrl, Open Net Sàrl and Prisme Solutions Informatique SA
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
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
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 Affero General Public License for more details.
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/>.
20 ##############################################################################
23 from datetime import datetime
26 from osv import osv, fields
28 from tools.translate import _
43 string_in= string_in.decode('utf-8')
45 # If exception => then just take the string as is
48 string_in = string_in.replace(k[0],k[1])
50 res= string_in.encode('ascii','replace')
57 def __init__(self, global_context_dict):
58 for i in global_context_dict:
59 global_context_dict[i] = global_context_dict[i] \
60 and tr(global_context_dict[i])
62 self.global_values = global_context_dict
73 self.post={'date_value_hdr': '000000', 'type_paiement': '0'}
74 self.init_local_context()
76 def init_local_context(self):
78 Must instanciate a fields list, field = (name,size)
79 and update a local_values dict.
81 raise _('not implemented')
85 for field in self.fields :
86 if self.pre.has_key(field[0]):
87 value = self.pre[field[0]]
88 elif self.global_values.has_key(field[0]):
89 value = self.global_values[field[0]]
90 elif self.post.has_key(field[0]):
91 value = self.post[field[0]]
95 res = res + c_ljust(value, field[1])
101 class record_gt826(record):
105 def init_local_context(self):
109 ('date_value_hdr', 6),
110 ('partner_bank_clearing', 12),
112 ('creation_date', 6),
113 ('comp_bank_clearing', 7),
117 ('type_paiement', 1),
122 ('comp_bank_iban', 24),
125 ('amount_to_pay', 12),
133 ('comp_country', 20),
137 ('partner_bvr', 12),#numero d'adherent bvr
138 ('partner_name', 20),
139 ('partner_street', 20),
141 ('partner_city', 10),
142 ('partner_country', 20),
143 ('reference', 27),#communication structuree
144 ('padding', 2),#cle de controle
148 'date_value_hdr': self.global_values['date_value'],
150 'partner_bank_clearing': '',
151 'partner_cpt_benef': '',
152 'genre_trans': '826',
154 'option_id_bank': 'D',
155 'partner_bvr': '/C/'+ self.global_values['partner_bvr'],
161 class record_gt827(record):
163 interne suisse (bvpost et bvbank)
165 def init_local_context(self):
169 ('date_value_hdr', 6),
170 ('partner_bank_clearing', 12),
172 ('creation_date', 6),
173 ('comp_bank_clearing', 7),
177 ('type_paiement', 1),
182 ('comp_bank_iban', 24),
185 ('amount_to_pay', 12),
193 ('comp_country', 20),
197 ('partner_bank_number', 30),
198 ('partner_name', 24),
199 ('partner_street', 24),
201 ('partner_city', 12),
202 ('partner_country', 24),
212 'date_value_hdr': self.global_values['date_value'],
214 'partner_cpt_benef': '',
215 'type_paiement': '0',
216 'genre_trans': '827',
218 'option_id_bank': 'D',
225 class record_gt836(record):
229 def init_local_context(self):
233 ('date_value_hdr', 6),
234 ('partner_bank_clearing', 12),
236 ('creation_date', 6),
237 ('comp_bank_clearing', 7),
241 ('type_paiement', 1),
246 ('comp_bank_iban', 24),
249 ('amount_to_pay', 15),
262 ('option_id_bank', 1),
263 ('partner_bank_ident', 70),
264 ('partner_bank_iban', 34),
268 ('partner_name', 35),
269 ('partner_street', 35),
270 ('partner_country', 3),
272 ('partner_city', 22),
282 'partner_bank_clearing': '',
283 'partner_cpt_benef': '',
284 'type_paiement': '0',
285 'genre_trans': '836',
287 'reference': self.global_values['reference'],
292 self.post.update({'option_motif': 'U'})
295 class record_gt890(record):
299 def init_local_context(self):
303 ('date_value_hdr', 6),
304 ('partner_bank_clearing', 12),
306 ('creation_date', 6),
307 ('comp_bank_clearing', 7),
311 ('type_paiement', 1),
314 ('amount_total', 16),
317 self.pre.update({'partner_bank_clearing': '', 'partner_cpt_benef': '',
318 'company_bank_clearing': '', 'genre_trans': '890'})
320 def c_ljust(s, size):
322 check before calling ljust
327 s = s.decode('utf-8').encode('latin1','replace').ljust(size)
330 def _create_dta(obj, cr, uid, data, context=None):
333 v['creation_date'] = time.strftime('%y%m%d')
336 pool = pooler.get_pool(cr.dbname)
337 payment_obj = pool.get('payment.order')
338 attachment_obj = pool.get('ir.attachment')
341 payment = payment_obj.browse(cr, uid, data['id'], context=context)
344 raise osv.except_osv(_('Error'),
345 _('No payment mode'))
346 bank = payment.mode.bank_id
348 raise osv.except_osv(_('Error'), _('No bank account for the company.'))
350 v['comp_bank_name']= bank.bank and bank.bank.name or False
351 v['comp_bank_clearing'] = bank.bank.clearing
353 if not v['comp_bank_clearing']:
354 raise osv.except_osv(_('Error'),
355 _('You must provide a Clearing Number for your bank account.'))
357 user = pool.get('res.users').browse(cr,uid,[uid])[0]
358 company = user.company_id
359 #XXX dirty code use get_addr
360 co_addr = company.partner_id.address[0]
361 v['comp_country'] = co_addr.country_id and co_addr.country_id.name or ''
362 v['comp_street'] = co_addr.street or ''
363 v['comp_zip'] = co_addr.zip
364 v['comp_city'] = co_addr.city
365 v['comp_name'] = co_addr.name
366 v['comp_dta'] = bank.dta_code or '' #XXX not mandatory in pratice
368 v['comp_bank_number'] = bank.acc_number or ''
370 v['comp_bank_iban'] = bank.iban.replace(' ','') or ''
372 v['comp_bank_iban'] = ''
373 if not v['comp_bank_iban']:
374 raise osv.except_osv(_('Error'),
375 _('No IBAN for the company bank account.'))
377 dta_line_obj = pool.get('account.dta.line')
378 res_partner_bank_obj = pool.get('res.partner.bank')
382 amount_currency_tot = 0
384 for pline in payment.line_ids:
385 if not pline.bank_id:
386 raise osv.except_osv(_('Error'), _('No bank account defined\n' \
387 'on line: %s') % pline.name)
388 if not pline.bank_id.bank:
389 raise osv.except_osv(_('Error'), _('No bank defined\n' \
390 'for the bank account: %s\n' \
391 'on the partner: %s\n' \
392 'on line: %s') + (pline.bank_id.state, pline.partner_id.name, pline.name))
394 v['sequence'] = str(seq).rjust(5).replace(' ', '0')
395 v['amount_to_pay']= str(pline.amount_currency).replace('.', ',')
396 v['number'] = pline.name
397 v['currency'] = pline.currency.name
399 v['partner_bank_name'] = pline.bank_id.bank.name or False
400 v['partner_bank_clearing'] = pline.bank_id.bank.clearing or False
401 if not v['partner_bank_name'] :
402 raise osv.except_osv(_('Error'), _('No bank name defined\n' \
403 'for the bank account: %s\n' \
404 'on the partner: %s\n' \
405 'on line: %s') % (pline.bank_id.state, pline.partner_id.name, pline.name))
407 v['partner_bank_iban'] = pline.bank_id.iban or False
408 v['partner_bank_number'] = pline.bank_id.acc_number \
409 and pline.bank_id.acc_number.replace('.','').replace('-','') \
411 v['partner_post_number']= pline.bank_id.post_number \
412 and pline.bank_id.post_number.replace('.', '').replace('-', '') \
414 v['partner_bvr'] = pline.bank_id.post_number or ''
416 v['partner_bvr'] = v['partner_bvr'].replace('-','')
417 if len(v['partner_bvr']) < 9:
418 v['partner_bvr'] = v['partner_bvr'][:2] + '0' * \
419 (9 - len(v['partner_bvr'])) + v['partner_bvr'][2:]
421 if pline.bank_id.bank:
422 v['partner_bank_city'] = pline.bank_id.bank.city or False
423 v['partner_bank_street'] = pline.bank_id.bank.street or ''
424 v['partner_bank_zip'] = pline.bank_id.bank.zip or ''
425 v['partner_bank_country'] = pline.bank_id.bank.country and \
426 pline.bank_id.bank.country.name or ''
428 v['partner_bank_code'] = pline.bank_id.bank.bic
429 v['reference'] = pline.move_line_id.ref
430 # Add support for owner of the account if exists..
431 if pline.bank_id.owner_name:
432 v['partner_name'] = pline.bank_id.owner_name
434 v['partner_name'] = pline.partner_id and pline.partner_id.name or ''
436 if pline.partner_id and pline.partner_id.address \
437 and pline.partner_id.address[0]:
438 v['partner_street'] = pline.partner_id.address[0].street
439 v['partner_city'] = pline.partner_id.address[0].city
440 v['partner_zip'] = pline.partner_id.address[0].zip
441 # If iban => country=country code for space reason
442 elec_pay = pline.bank_id.state #Bank type
443 if elec_pay == 'iban':
444 v['partner_country']= pline.partner_id.address[0].country_id \
445 and pline.partner_id.address[0].country_id.code+'-' \
448 v['partner_country']= pline.partner_id.address[0].country_id \
449 and pline.partner_id.address[0].country_id.name \
452 v['partner_street'] =''
453 v['partner_city']= ''
455 v['partner_country']= ''
456 raise osv.except_osv('Error', 'No address defined \n' \
457 'for the partner: ' + pline.partner_id.name + '\n' \
458 'on line: ' + pline.name)
460 if pline.order_id.date_scheduled:
461 date_value = datetime.strptime(pline.order_id.date_scheduled, '%Y-%m-%d')
463 date_value = datetime.strptime(pline.date, '%Y-%m-%d')
465 date_value = datetime.now()
466 v['date_value'] = date_value.strftime("%y%m%d")
468 # si compte iban -> iban (836)
469 # si payment structure -> bvr (826)
472 if elec_pay == 'dta_iban':
473 # If iban => country=country code for space reason
474 v['comp_country'] = co_addr.country_id and co_addr.country_id.code+'-' or ''
475 record_type = record_gt836
476 if not v['partner_bank_iban']:
477 raise osv.except_osv(_('Error'), _('No IBAN defined \n' \
478 'for the bank account: %s\n' + \
479 'on line: %s') % (res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id], context)[0][1] , pline.name))
481 if v['partner_bank_code'] : # bank code is swift (BIC address)
482 v['option_id_bank']= 'A'
483 v['partner_bank_ident']= v['partner_bank_code']
484 elif v['partner_bank_city']:
486 v['option_id_bank']= 'D'
487 v['partner_bank_ident']= v['partner_bank_name'] \
488 + ' ' + v['partner_bank_street'] \
489 + ' ' + v['partner_bank_zip'] \
490 + ' ' + v['partner_bank_city'] \
491 + ' ' + v['partner_bank_country']
493 raise osv.except_osv(_('Error'), _('You must provide the bank city '
494 'or the bic code for the partner bank: \n %d\n' + \
495 'on line: %s') %(res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id], context)[0][1], pline.name))
497 elif elec_pay == 'bvrbank' or elec_pay == 'bvrpost':
498 from tools import mod10r
500 v['reference'] = v['reference'].replace(' ',
501 '').rjust(27).replace(' ', '0')
502 if not v['reference'] \
503 or (mod10r(v['reference'][:-1]) != v['reference'] and \
504 not len(v['reference']) == 15):
505 raise osv.except_osv(_('Error'), _('You must provide ' \
506 'a valid BVR reference number \n' \
507 'for the line: %s') % pline.name)
508 if not v['partner_bvr']:
509 raise osv.except_osv(_('Error'), _('You must provide a BVR number\n'
510 'for the bank account: %s' \
511 'on line: %s') % (res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id],context)[0][1] ,pline.name))
512 record_type = record_gt826
514 elif elec_pay == 'bvbank':
515 if not v['partner_bank_number'] :
516 if v['partner_bank_iban'] :
517 v['partner_bank_number']= v['partner_bank_iban']
519 raise osv.except_osv(_('Error'), _('You must provide ' \
521 'for the partner bank: %s\n' \
522 'on line: %s') % (res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id], context)[0][1] , pline.name))
523 if not v['partner_bank_clearing']:
524 raise osv.except_osv(_('Error'), _('You must provide ' \
525 'a Clearing Number\n' \
526 'for the partner bank: %s\n' \
527 'on line %s') % (res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id], context)[0][1] , pline.name))
528 v['partner_bank_number'] = '/C/'+v['partner_bank_number']
529 record_type = record_gt827
530 elif elec_pay == 'bvpost':
531 if not v['partner_post_number']:
532 raise osv.except_osv(_('Error'), _('You must provide ' \
534 'for the partner bank: %s\n' \
535 'on line: %s') % (res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id], context)[0][1] ,pline.name))
536 v['partner_bank_clearing']= ''
537 v['partner_bank_number'] = '/C/'+v['partner_post_number']
538 record_type = record_gt827
540 raise osv.except_osv(_('Error'), _('The Bank type %s of the bank account: %s is not supported') \
541 % (elec_pay, res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id], context)[0][1],))
543 dta_line = record_type(v).generate()
546 amount_tot += pline.amount
547 amount_currency_tot += pline.amount_currency
551 v['amount_total'] = str(amount_currency_tot).replace('.',',')
552 v['sequence'] = str(seq).rjust(5).replace(' ','0')
554 dta = dta + record_gt890(v).generate()
556 dta_data = base64.encodestring(dta)
557 payment_obj.set_done(cr, uid, [data['id']], context)
558 attachment_obj.create(cr, uid, {
561 'datas_fname': 'DTA.txt',
562 'res_model': 'payment.order',
563 'res_id': data['id'],
565 return {'dta': dta_data}
567 class create_dta_wizard(osv.osv_memory):
568 _name="create.dta.wizard"
571 'dta_file':fields.binary('DTA File', readonly=True)
573 def create_dta(self, cr, uid, ids, context=None):
577 active_ids = context.get('active_ids', [])
578 active_id = context.get('active_id', [])
580 data['ids'] = active_ids
581 data['id'] = active_id
582 dta_file = _create_dta(self, cr, uid, data, context)
583 context.update({'dta_file':dta_file})
584 return self.save_dta(cr, uid, ids, context)
586 def save_dta(self, cr, uid, ids, context=None):
587 obj_model = self.pool.get('ir.model.data')
590 model_data_ids = obj_model.search(cr,uid,[('model','=','ir.ui.view'), ('name','=','dta_save_view')])
591 resource_id = obj_model.read(cr, uid, model_data_ids, fields=['res_id'])[0]['res_id']
595 'res_model': 'create.dta.wizard',
596 'views': [(resource_id, 'form')],
597 'type': 'ir.actions.act_window',
605 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: