615 lines
22 KiB
Python
615 lines
22 KiB
Python
# -*- coding: utf-8 -*-
|
|
#
|
|
# dta_wizard.py
|
|
# l10n_ch
|
|
#
|
|
# Created by Nicolas Bessi based on Credric Krier contribution
|
|
#
|
|
# Copyright (c) 2009 CamptoCamp. All rights reserved.
|
|
##############################################################################
|
|
# WARNING: This program as such is intended to be used by professional
|
|
# programmers who take the whole responsability of assessing all potential
|
|
# consequences resulting from its eventual inadequacies and bugs
|
|
# End users who are looking for a ready-to-use solution with commercial
|
|
# garantees and support are strongly adviced to contract a Free Software
|
|
# Service Company
|
|
#
|
|
# This program is Free Software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
#
|
|
##############################################################################
|
|
|
|
import time
|
|
from datetime import datetime
|
|
import base64
|
|
|
|
from osv import osv, fields
|
|
import pooler
|
|
from tools.translate import _
|
|
|
|
TRANS=[
|
|
(u'é','e'),
|
|
(u'è','e'),
|
|
(u'à','a'),
|
|
(u'ê','e'),
|
|
(u'î','i'),
|
|
(u'ï','i'),
|
|
(u'â','a'),
|
|
(u'ä','a'),
|
|
]
|
|
|
|
def tr(string_in):
|
|
try:
|
|
string_in= string_in.decode('utf-8')
|
|
except:
|
|
# If exception => then just take the string as is
|
|
pass
|
|
for k in TRANS:
|
|
string_in = string_in.replace(k[0],k[1])
|
|
try:
|
|
res= string_in.encode('ascii','replace')
|
|
except:
|
|
res = string_in
|
|
return res
|
|
|
|
|
|
class record:
|
|
def __init__(self, global_context_dict):
|
|
for i in global_context_dict:
|
|
global_context_dict[i] = global_context_dict[i] \
|
|
and tr(global_context_dict[i])
|
|
self.fields = []
|
|
self.global_values = global_context_dict
|
|
self.pre = {
|
|
'padding': '',
|
|
'seg_num1': '01',
|
|
'seg_num2': '02',
|
|
'seg_num3': '03',
|
|
'seg_num4': '04',
|
|
'seg_num5': '05',
|
|
'flag': '0',
|
|
'zero5': '00000'
|
|
}
|
|
self.post={'date_value_hdr': '000000', 'type_paiement': '0'}
|
|
self.init_local_context()
|
|
|
|
def init_local_context(self):
|
|
"""
|
|
Must instanciate a fields list, field = (name,size)
|
|
and update a local_values dict.
|
|
"""
|
|
raise _('not implemented')
|
|
|
|
def generate(self):
|
|
res=''
|
|
for field in self.fields :
|
|
if self.pre.has_key(field[0]):
|
|
value = self.pre[field[0]]
|
|
elif self.global_values.has_key(field[0]):
|
|
value = self.global_values[field[0]]
|
|
elif self.post.has_key(field[0]):
|
|
value = self.post[field[0]]
|
|
else :
|
|
pass
|
|
try:
|
|
res = res + c_ljust(value, field[1])
|
|
except :
|
|
pass
|
|
return res
|
|
|
|
|
|
class record_gt826(record):
|
|
"""
|
|
bvr
|
|
"""
|
|
def init_local_context(self):
|
|
self.fields=[
|
|
('seg_num1', 2),
|
|
#header
|
|
('date_value_hdr', 6),
|
|
('partner_bank_clearing', 12),
|
|
('zero5', 5),
|
|
('creation_date', 6),
|
|
('comp_bank_clearing', 7),
|
|
('uid', 5),
|
|
('sequence', 5),
|
|
('genre_trans', 3),
|
|
('type_paiement', 1),
|
|
('flag', 1),
|
|
#seg1
|
|
('comp_dta', 5),
|
|
('number', 11),
|
|
('comp_bank_iban', 24),
|
|
('date_value', 6),
|
|
('currency', 3),
|
|
('amount_to_pay', 12),
|
|
('padding', 14),
|
|
#seg2
|
|
('seg_num2', 2),
|
|
('comp_name', 20),
|
|
('comp_street', 20),
|
|
('comp_zip', 10),
|
|
('comp_city', 10),
|
|
('comp_country', 20),
|
|
('padding', 46),
|
|
#seg3
|
|
('seg_num3', 2),
|
|
('partner_bvr', 12),#numero d'adherent bvr
|
|
('partner_name', 20),
|
|
('partner_street', 20),
|
|
('partner_zip', 10),
|
|
('partner_city', 10),
|
|
('partner_country', 20),
|
|
('reference', 27),#communication structuree
|
|
('padding', 2),#cle de controle
|
|
('padding', 5)
|
|
]
|
|
self.pre.update({
|
|
'date_value_hdr': self.global_values['date_value'],
|
|
'date_value': '',
|
|
'partner_bank_clearing': '',
|
|
'partner_cpt_benef': '',
|
|
'genre_trans': '826',
|
|
'conv_cours': '',
|
|
'option_id_bank': 'D',
|
|
'partner_bvr': '/C/'+ self.global_values['partner_bvr'],
|
|
'ref2': '',
|
|
'ref3': '',
|
|
'format': '0',
|
|
})
|
|
|
|
class record_gt827(record):
|
|
"""
|
|
interne suisse (bvpost et bvbank)
|
|
"""
|
|
def init_local_context(self):
|
|
self.fields = [
|
|
('seg_num1', 2),
|
|
#header
|
|
('date_value_hdr', 6),
|
|
('partner_bank_clearing', 12),
|
|
('zero5', 5),
|
|
('creation_date', 6),
|
|
('comp_bank_clearing', 7),
|
|
('uid', 5),
|
|
('sequence', 5),
|
|
('genre_trans', 3),
|
|
('type_paiement', 1),
|
|
('flag', 1),
|
|
#seg1
|
|
('comp_dta', 5),
|
|
('number', 11),
|
|
('comp_bank_iban', 24),
|
|
('date_value', 6),
|
|
('currency', 3),
|
|
('amount_to_pay', 12),
|
|
('padding', 14),
|
|
#seg2
|
|
('seg_num2', 2),
|
|
('comp_name', 20),
|
|
('comp_street', 20),
|
|
('comp_zip', 10),
|
|
('comp_city', 10),
|
|
('comp_country', 20),
|
|
('padding', 46),
|
|
#seg3
|
|
('seg_num3', 2),
|
|
('partner_bank_number', 30),
|
|
('partner_name', 24),
|
|
('partner_street', 24),
|
|
('partner_zip', 12),
|
|
('partner_city', 12),
|
|
('partner_country', 24),
|
|
#seg4
|
|
('seg_num4', 2),
|
|
('reference', 112),
|
|
('padding', 14),
|
|
#seg5
|
|
#('padding',128)
|
|
]
|
|
|
|
self.pre.update({
|
|
'date_value_hdr': self.global_values['date_value'],
|
|
'date_value': '',
|
|
'partner_cpt_benef': '',
|
|
'type_paiement': '0',
|
|
'genre_trans': '827',
|
|
'conv_cours': '',
|
|
'option_id_bank': 'D',
|
|
'ref2': '',
|
|
'ref3': '',
|
|
'format': '0'
|
|
})
|
|
|
|
|
|
class record_gt836(record):
|
|
"""
|
|
iban
|
|
"""
|
|
def init_local_context(self):
|
|
self.fields = [
|
|
('seg_num1', 2),
|
|
#header
|
|
('date_value_hdr', 6),
|
|
('partner_bank_clearing', 12),
|
|
('zero5', 5),
|
|
('creation_date', 6),
|
|
('comp_bank_clearing', 7),
|
|
('uid', 5),
|
|
('sequence', 5),
|
|
('genre_trans', 3),
|
|
('type_paiement', 1),
|
|
('flag', 1),
|
|
#seg1
|
|
('comp_dta', 5),
|
|
('number', 11),
|
|
('comp_bank_iban', 24),
|
|
('date_value', 6),
|
|
('currency', 3),
|
|
('amount_to_pay', 15),
|
|
('padding', 11),
|
|
#seg2
|
|
('seg_num2', 2),
|
|
('conv_cours', 12),
|
|
('comp_name', 35),
|
|
('comp_street', 35),
|
|
('comp_country', 3),
|
|
('comp_zip', 10),
|
|
('comp_city', 22),
|
|
('padding', 9),
|
|
#seg3
|
|
('seg_num3', 2),
|
|
('option_id_bank', 1),
|
|
('partner_bank_ident', 70),
|
|
('partner_bank_iban', 34),
|
|
('padding', 21),
|
|
#seg4
|
|
('seg_num4', 2),
|
|
('partner_name', 35),
|
|
('partner_street', 35),
|
|
('partner_country', 3),
|
|
('partner_zip', 10),
|
|
('partner_city', 22),
|
|
('padding', 21),
|
|
#seg5
|
|
('seg_num5', 2),
|
|
('option_motif', 1),
|
|
('reference', 105),
|
|
('format', 1),
|
|
('padding', 19)
|
|
]
|
|
self.pre.update( {
|
|
'partner_bank_clearing': '',
|
|
'partner_cpt_benef': '',
|
|
'type_paiement': '0',
|
|
'genre_trans': '836',
|
|
'conv_cours': '',
|
|
'reference': self.global_values['reference'],
|
|
'ref2': '',
|
|
'ref3': '',
|
|
'format': '2'
|
|
})
|
|
self.post.update({'option_motif': 'U'})
|
|
|
|
|
|
class record_gt890(record):
|
|
"""
|
|
Total
|
|
"""
|
|
def init_local_context(self):
|
|
self.fields = [
|
|
('seg_num1', 2),
|
|
#header
|
|
('date_value_hdr', 6),
|
|
('partner_bank_clearing', 12),
|
|
('zero5', 5),
|
|
('creation_date', 6),
|
|
('comp_bank_clearing', 7),
|
|
('uid', 5),
|
|
('sequence', 5),
|
|
('genre_trans', 3),
|
|
('type_paiement', 1),
|
|
('flag', 1),
|
|
#total
|
|
('amount_total', 16),
|
|
('padding', 59)
|
|
]
|
|
self.pre.update({'partner_bank_clearing': '', 'partner_cpt_benef': '',
|
|
'company_bank_clearing': '', 'genre_trans': '890'})
|
|
|
|
def c_ljust(s, size):
|
|
"""
|
|
check before calling ljust
|
|
"""
|
|
s= s or ''
|
|
if len(s) > size:
|
|
s= s[:size]
|
|
s = s.decode('utf-8').encode('latin1','replace').ljust(size)
|
|
return s
|
|
|
|
def _create_dta(obj, cr, uid, data, context=None):
|
|
v = {}
|
|
v['uid'] = str(uid)
|
|
v['creation_date'] = time.strftime('%y%m%d')
|
|
dta = ''
|
|
|
|
pool = pooler.get_pool(cr.dbname)
|
|
payment_obj = pool.get('payment.order')
|
|
attachment_obj = pool.get('ir.attachment')
|
|
if context is None:
|
|
context = {}
|
|
payment = payment_obj.browse(cr, uid, data['id'], context=context)
|
|
|
|
if not payment.mode:
|
|
raise osv.except_osv(_('Error'),
|
|
_('No payment mode'))
|
|
bank = payment.mode.bank_id
|
|
if not bank:
|
|
raise osv.except_osv(_('Error'), _('No bank account for the company.'))
|
|
|
|
v['comp_bank_name']= bank.bank and bank.bank.name or False
|
|
v['comp_bank_clearing'] = bank.bank.clearing
|
|
|
|
if not v['comp_bank_clearing']:
|
|
raise osv.except_osv(_('Error'),
|
|
_('You must provide a Clearing Number for your bank account.'))
|
|
|
|
user = pool.get('res.users').browse(cr,uid,[uid])[0]
|
|
company = user.company_id
|
|
#XXX dirty code use get_addr
|
|
co_addr = company.partner_id.address[0]
|
|
v['comp_country'] = co_addr.country_id and co_addr.country_id.name or ''
|
|
v['comp_street'] = co_addr.street or ''
|
|
v['comp_zip'] = co_addr.zip
|
|
v['comp_city'] = co_addr.city
|
|
v['comp_name'] = co_addr.name
|
|
v['comp_dta'] = bank.dta_code or '' #XXX not mandatory in pratice
|
|
|
|
v['comp_bank_number'] = bank.acc_number or ''
|
|
if bank.iban:
|
|
v['comp_bank_iban'] = bank.iban.replace(' ','') or ''
|
|
else:
|
|
v['comp_bank_iban'] = ''
|
|
if not v['comp_bank_iban']:
|
|
raise osv.except_osv(_('Error'),
|
|
_('No IBAN for the company bank account.'))
|
|
|
|
res_partner_bank_obj = pool.get('res.partner.bank')
|
|
|
|
seq = 1
|
|
amount_tot = 0
|
|
amount_currency_tot = 0
|
|
|
|
for pline in payment.line_ids:
|
|
if not pline.bank_id:
|
|
raise osv.except_osv(_('Error'), _('No bank account defined\n' \
|
|
'on line: %s') % pline.name)
|
|
if not pline.bank_id.bank:
|
|
raise osv.except_osv(_('Error'), _('No bank defined\n' \
|
|
'for the bank account: %s\n' \
|
|
'on the partner: %s\n' \
|
|
'on line: %s') + (pline.bank_id.state, pline.partner_id.name, pline.name))
|
|
|
|
v['sequence'] = str(seq).rjust(5).replace(' ', '0')
|
|
v['amount_to_pay']= str(pline.amount_currency).replace('.', ',')
|
|
v['number'] = pline.name
|
|
v['currency'] = pline.currency.symbol
|
|
|
|
v['partner_bank_name'] = pline.bank_id.bank.name or False
|
|
v['partner_bank_clearing'] = pline.bank_id.bank.clearing or False
|
|
if not v['partner_bank_name'] :
|
|
raise osv.except_osv(_('Error'), _('No bank name defined\n' \
|
|
'for the bank account: %s\n' \
|
|
'on the partner: %s\n' \
|
|
'on line: %s') % (pline.bank_id.state, pline.partner_id.name, pline.name))
|
|
|
|
v['partner_bank_iban'] = pline.bank_id.iban or False
|
|
v['partner_bank_number'] = pline.bank_id.acc_number \
|
|
and pline.bank_id.acc_number.replace('.','').replace('-','') \
|
|
or False
|
|
v['partner_post_number']= pline.bank_id.post_number \
|
|
and pline.bank_id.post_number.replace('.', '').replace('-', '') \
|
|
or False
|
|
v['partner_bvr'] = pline.bank_id.bvr_number or ''
|
|
if v['partner_bvr']:
|
|
v['partner_bvr'] = v['partner_bvr'].replace('-','')
|
|
if len(v['partner_bvr']) < 9:
|
|
v['partner_bvr'] = v['partner_bvr'][:2] + '0' * \
|
|
(9 - len(v['partner_bvr'])) + v['partner_bvr'][2:]
|
|
|
|
if pline.bank_id.bank:
|
|
v['partner_bank_city'] = pline.bank_id.bank.city or False
|
|
v['partner_bank_street'] = pline.bank_id.bank.street or ''
|
|
v['partner_bank_zip'] = pline.bank_id.bank.zip or ''
|
|
v['partner_bank_country'] = pline.bank_id.bank.country and \
|
|
pline.bank_id.bank.country.name or ''
|
|
|
|
v['partner_bank_code'] = pline.bank_id.bank.bic
|
|
v['reference'] = pline.move_line_id.ref
|
|
# Add support for owner of the account if exists..
|
|
if pline.bank_id.owner_name:
|
|
v['partner_name'] = pline.bank_id.owner_name
|
|
else:
|
|
v['partner_name'] = pline.partner_id and pline.partner_id.name or ''
|
|
|
|
if pline.partner_id and pline.partner_id.address \
|
|
and pline.partner_id.address[0]:
|
|
v['partner_street'] = pline.partner_id.address[0].street
|
|
v['partner_city'] = pline.partner_id.address[0].city
|
|
v['partner_zip'] = pline.partner_id.address[0].zip
|
|
# If iban => country=country code for space reason
|
|
elec_pay = pline.bank_id.state #Bank type
|
|
if elec_pay == 'iban':
|
|
v['partner_country']= pline.partner_id.address[0].country_id \
|
|
and pline.partner_id.address[0].country_id.code+'-' \
|
|
or ''
|
|
else:
|
|
v['partner_country']= pline.partner_id.address[0].country_id \
|
|
and pline.partner_id.address[0].country_id.name \
|
|
or ''
|
|
else:
|
|
v['partner_street'] =''
|
|
v['partner_city']= ''
|
|
v['partner_zip']= ''
|
|
v['partner_country']= ''
|
|
raise osv.except_osv('Error', 'No address defined \n' \
|
|
'for the partner: ' + pline.partner_id.name + '\n' \
|
|
'on line: ' + pline.name)
|
|
|
|
if pline.order_id.date_scheduled:
|
|
date_value = datetime.strptime(pline.order_id.date_scheduled, '%Y-%m-%d')
|
|
elif pline.date:
|
|
date_value = datetime.strptime(pline.date, '%Y-%m-%d')
|
|
else:
|
|
date_value = datetime.now()
|
|
v['date_value'] = date_value.strftime("%y%m%d")
|
|
|
|
# si compte iban -> iban (836)
|
|
# si payment structure -> bvr (826)
|
|
# si non -> (827)
|
|
|
|
if elec_pay == 'dta_iban':
|
|
# If iban => country=country code for space reason
|
|
v['comp_country'] = co_addr.country_id and co_addr.country_id.code+'-' or ''
|
|
record_type = record_gt836
|
|
if not v['partner_bank_iban']:
|
|
raise osv.except_osv(_('Error'), _('No IBAN defined \n' \
|
|
'for the bank account: %s\n' + \
|
|
'on line: %s') % (res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id], context)[0][1] , pline.name))
|
|
|
|
if v['partner_bank_code'] : # bank code is swift (BIC address)
|
|
v['option_id_bank']= 'A'
|
|
v['partner_bank_ident']= v['partner_bank_code']
|
|
elif v['partner_bank_city']:
|
|
|
|
v['option_id_bank']= 'D'
|
|
v['partner_bank_ident']= v['partner_bank_name'] \
|
|
+ ' ' + v['partner_bank_street'] \
|
|
+ ' ' + v['partner_bank_zip'] \
|
|
+ ' ' + v['partner_bank_city'] \
|
|
+ ' ' + v['partner_bank_country']
|
|
else:
|
|
raise osv.except_osv(_('Error'), _('You must provide the bank city '
|
|
'or the bic code for the partner bank: \n %d\n' + \
|
|
'on line: %s') %(res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id], context)[0][1], pline.name))
|
|
|
|
elif elec_pay == 'bvrbank' or elec_pay == 'bvrpost':
|
|
from tools import mod10r
|
|
if v['reference']:
|
|
v['reference'] = v['reference'].replace(' ',
|
|
'').rjust(27).replace(' ', '0')
|
|
if not v['reference'] \
|
|
or (mod10r(v['reference'][:-1]) != v['reference'] and \
|
|
not len(v['reference']) == 15):
|
|
raise osv.except_osv(_('Error'), _('You must provide ' \
|
|
'a valid BVR reference number \n' \
|
|
'for the line: %s') % pline.name)
|
|
if not v['partner_bvr']:
|
|
raise osv.except_osv(_('Error'), _('You must provide a BVR number\n'
|
|
'for the bank account: %s' \
|
|
'on line: %s') % (res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id],context)[0][1] ,pline.name))
|
|
record_type = record_gt826
|
|
|
|
elif elec_pay == 'bvbank':
|
|
if not v['partner_bank_number'] :
|
|
if v['partner_bank_iban'] :
|
|
v['partner_bank_number']= v['partner_bank_iban']
|
|
else:
|
|
raise osv.except_osv(_('Error'), _('You must provide ' \
|
|
'a bank number \n' \
|
|
'for the partner bank: %s\n' \
|
|
'on line: %s') % (res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id], context)[0][1] , pline.name))
|
|
if not v['partner_bank_clearing']:
|
|
raise osv.except_osv(_('Error'), _('You must provide ' \
|
|
'a Clearing Number\n' \
|
|
'for the partner bank: %s\n' \
|
|
'on line %s') % (res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id], context)[0][1] , pline.name))
|
|
v['partner_bank_number'] = '/C/'+v['partner_bank_number']
|
|
record_type = record_gt827
|
|
elif elec_pay == 'bvpost':
|
|
if not v['partner_post_number']:
|
|
raise osv.except_osv(_('Error'), _('You must provide ' \
|
|
'a post number \n' \
|
|
'for the partner bank: %s\n' \
|
|
'on line: %s') % (res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id], context)[0][1] ,pline.name))
|
|
v['partner_bank_clearing']= ''
|
|
v['partner_bank_number'] = '/C/'+v['partner_post_number']
|
|
record_type = record_gt827
|
|
else:
|
|
raise osv.except_osv(_('Error'), _('The Bank type %s of the bank account: %s is not supported') \
|
|
% (elec_pay, res_partner_bank_obj.name_get(cr, uid, [pline.bank_id.id], context)[0][1],))
|
|
|
|
dta_line = record_type(v).generate()
|
|
|
|
dta = dta + dta_line
|
|
amount_tot += pline.amount
|
|
amount_currency_tot += pline.amount_currency
|
|
seq += 1
|
|
|
|
# segment total
|
|
v['amount_total'] = str(amount_currency_tot).replace('.',',')
|
|
v['sequence'] = str(seq).rjust(5).replace(' ','0')
|
|
if dta :
|
|
dta = dta + record_gt890(v).generate()
|
|
|
|
dta_data = base64.encodestring(dta)
|
|
payment_obj.set_done(cr, uid, data['id'], context)
|
|
attachment_obj.create(cr, uid, {
|
|
'name': 'DTA',
|
|
'datas': dta_data,
|
|
'datas_fname': 'DTA.txt',
|
|
'res_model': 'payment.order',
|
|
'res_id': data['id'],
|
|
}, context=context)
|
|
return {'dta': dta_data}
|
|
|
|
class create_dta_wizard(osv.osv_memory):
|
|
_name="create.dta.wizard"
|
|
|
|
_columns={
|
|
'dta_file':fields.binary('DTA File', readonly=True)
|
|
}
|
|
def create_dta(self, cr, uid, ids, context=None):
|
|
if not context:
|
|
context = {}
|
|
data = {}
|
|
active_ids = context.get('active_ids', [])
|
|
active_id = context.get('active_id', [])
|
|
data['form'] = {}
|
|
data['ids'] = active_ids
|
|
data['id'] = active_id
|
|
dta_file = _create_dta(self, cr, uid, data, context)
|
|
context.update({'dta_file':dta_file})
|
|
return self.save_dta(cr, uid, ids, context)
|
|
|
|
def save_dta(self, cr, uid, ids, context=None):
|
|
obj_model = self.pool.get('ir.model.data')
|
|
if context is None:
|
|
context = {}
|
|
model_data_ids = obj_model.search(cr,uid,[('model','=','ir.ui.view'), ('name','=','dta_save_view')])
|
|
resource_id = obj_model.read(cr, uid, model_data_ids, fields=['res_id'])[0]['res_id']
|
|
return {
|
|
'view_type': 'form',
|
|
'view_mode': 'form',
|
|
'res_model': 'create.dta.wizard',
|
|
'views': [(resource_id, 'form')],
|
|
'type': 'ir.actions.act_window',
|
|
'target': 'new',
|
|
'context': context,
|
|
}
|
|
|
|
|
|
create_dta_wizard()
|
|
|
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |