1
# -*- encoding: utf-8 -*-
2
##############################################################################
4
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
6
# WARNING: This program as such is intended to be used by professional
7
# programmers who take the whole responsability of assessing all potential
8
# consequences resulting from its eventual inadequacies and bugs
9
# End users who are looking for a ready-to-use solution with commercial
10
# garantees and support are strongly adviced to contract a Free Software
13
# This program is Free Software; you can redistribute it and/or
14
# modify it under the terms of the GNU General Public License
15
# as published by the Free Software Foundation; either version 2
16
# of the License, or (at your option) any later version.
18
# This program is distributed in the hope that it will be useful,
19
# but WITHOUT ANY WARRANTY; without even the implied warranty of
20
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
# GNU General Public License for more details.
23
# You should have received a copy of the GNU General Public License
24
# along with this program; if not, write to the Free Software
25
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27
##############################################################################
35
from mx.DateTime import RelativeDateTime, DateTime
37
def _bank_get(self, cr, uid, context={}):
38
pool = pooler.get_pool(cr.dbname)
39
partner_id = pool.get('res.users').browse(cr,uid,[uid])[0].company_id.partner_id
41
obj = pool.get('res.partner.bank')
42
ids = obj.search(cr, uid, [('partner_id','=',partner_id.id)])
43
res = obj.read(cr, uid, ids, ['active', 'name'], context)
44
res = [(r['id'], r['name']) for r in res]
48
check_form = """<?xml version="1.0"?>
49
<form string="DTA file creation">
50
<separator colspan="4" string="DTA Details :" />
52
<field name="journal"/>
53
<field name="dta_line_ids" nolabel="1" colspan="4" />
61
'relation':'account.dta.line',
64
'string':'Bank Account',
66
'selection':_bank_get,
73
'relation':'account.journal',
74
'domain':"[('type','=','cash')]",
76
'help':'The journal used for the bank statement',
81
res_form = """<?xml version="1.0"?>
82
<form string="DTA file creation - Results">
83
<separator colspan="4" string="Clic on 'Save as' to save the DTA file :" />
85
<separator string="Logs" colspan="4"/>
86
<field name="note" colspan="4" nolabel="1"/>
97
'note' : {'string':'Log','type':'text'}
101
def _get_bank(self,cr,uid,data,context):
102
pool = pooler.get_pool(cr.dbname)
103
user = pool.get('res.users').browse(cr,uid,[uid])[0]
104
company= user.company_id
106
if company.partner_id.bank_ids:
107
bank = company.partner_id.bank_ids[0]
108
return {'bank':bank.bank_name,'bank_code':bank.bank_code or ''} # 'city':'',
113
def _get_dta_lines(self,cr,uid,data,context):
114
pool = pooler.get_pool(cr.dbname)
118
user = pool.get('res.users').browse(cr,uid,[uid])[0]
119
company= user.company_id
121
if company.partner_id.bank_ids:
122
bank = company.partner_id.bank_ids[0]
123
res.update({'bank':bank.bank_name,'bank_code':bank.bank_code or ''}) # 'city':'',
126
dta_line_obj = pool.get('account.dta.line')
129
id_dta= pool.get('account.dta').create(cr,uid,{
130
'date':time.strftime('%Y-%m-%d'),
135
for i in pool.get('account.invoice').browse(cr,uid,data['ids']):
136
if i.dta_state in ['none','paid'] or i.state in ['draft','cancel','paid']:
142
disc_list= pool.get('account.payment.term').get_discounts(cr,uid,i.payment_term.id, i.date_invoice)
144
for (cash_disc_date,discount) in disc_list:
145
if cash_disc_date >= time.strftime('%Y-%m-%d'):
149
lines.append(dta_line_obj.create(cr,uid,{
151
'partner_id': i.partner_id.id,
152
'due_date': i.date_due,
153
'invoice_date': i.date_invoice,
154
'cashdisc_date': cash_disc_date and cash_disc_date or None,
155
'amount_to_pay': discount and i.amount_total*(1-discount) or i.amount_total,
156
'amount_invoice': i.amount_total,
157
'amount_cashdisc': discount and i.amount_total*(1-discount),
161
res.update({'dta_line_ids': lines,'dta_id': id_dta})
178
s = s.replace(k[0],k[1])
181
res= s.encode('ascii','replace')
187
def __init__(self,global_context_dict):
189
for i in global_context_dict:
190
global_context_dict[i]= global_context_dict[i] and tr(global_context_dict[i])
192
self.global_values = global_context_dict
193
self.pre={'padding':'','seg_num1':'01','seg_num2':'02',
194
'seg_num3':'03','seg_num4':'04','seg_num5':'05',
195
'flag':'0', 'zero5':'00000'
197
self.post={'date_value_hdr':'000000','type_paiement':'0'}
198
self.init_local_context()
200
def init_local_context(self):
202
Must instanciate a fields list, field = (name,size)
203
and update a local_values dict.
205
raise Exception, "not implemented"
209
for field in self.fields :
210
if self.pre.has_key(field[0]):
211
value = self.pre[field[0]]
212
elif self.global_values.has_key(field[0]):
213
value = self.global_values[field[0]]
214
elif self.post.has_key(field[0]):
215
value = self.post[field[0]]
218
#raise Exception(field[0]+' not found !')
221
res = res + c_ljust(value, field[1])
227
class record_gt826(record):
229
def init_local_context(self):
233
('date_value_hdr',6),('partner_bank_clearing',12),('zero5',5),('creation_date',6),
234
('comp_bank_clearing',7), ('uid',5),
237
('type_paiement',1),('flag',1),
239
('comp_dta',5),('invoice_number',11),('comp_bank_iban',24),('date_value',6),
240
('invoice_currency',3),('amount_to_pay',12),('padding',14),
242
('seg_num2',2),('comp_name',20),('comp_street',20),('comp_zip',10),
243
('comp_city',10),('comp_country',20),('padding',46),
245
('seg_num3',2),('partner_bvr',12),#numero d'adherent bvr
246
('partner_name',20),('partner_street',20),('partner_zip',10),
247
('partner_city',10),('partner_country',20),
248
('invoice_bvr_num',27),#communication structuree
249
('padding',2),#cle de controle
253
self.pre.update({'date_value_hdr': self.global_values['date_value'],
255
'partner_bank_clearing':'','partner_cpt_benef':'',
257
'conv_cours':'', 'option_id_bank':'D',
258
'partner_bvr' : '/C/'+ self.global_values['partner_bvr'],
262
class record_gt827(record):
264
def init_local_context(self):
268
('date_value_hdr',6),('partner_bank_clearing',12),('zero5',5),('creation_date',6),
269
('comp_bank_clearing',7), ('uid',5),
272
('type_paiement',1),('flag',1),
274
('comp_dta',5),('invoice_number',11),('comp_bank_iban',24),('date_value',6),
275
('invoice_currency',3),('amount_to_pay',12),('padding',14),
277
('seg_num2',2),('comp_name',20),('comp_street',20),('comp_zip',10),
278
('comp_city',10),('comp_country',20),('padding',46),
280
('seg_num3',2),('partner_bank_number',30),
281
('partner_name',24),('partner_street',24),('partner_zip',12),
282
('partner_city',12),('partner_country',24),
284
('seg_num4',2),('partner_comment',112),('padding',14),
289
self.pre.update({'date_value_hdr': self.global_values['date_value'],
291
'partner_cpt_benef':'',
292
'type_paiement':'0', 'genre_trans':'827',
293
'conv_cours':'', 'option_id_bank':'D',
300
class record_gt836(record):
302
def init_local_context(self):
306
('date_value_hdr',6),('partner_bank_clearing',12),('zero5',5),('creation_date',6),
307
('comp_bank_clearing',7), ('uid',5),
310
('type_paiement',1),('flag',1),
312
('comp_dta',5),('invoice_number',11),('comp_bank_iban',24),('date_value',6),
313
('invoice_currency',3),('amount_to_pay',15),('padding',11),
315
('seg_num2',2),('conv_cours',12),('comp_name',35),('comp_street',35),('comp_country',3),('comp_zip',10),
316
('comp_city',22),('padding',9),
318
('seg_num3',2),('option_id_bank',1),('partner_bank_ident',70),
319
('partner_bank_iban',34),('padding',21),
321
('seg_num4',2),('partner_name',35),('partner_street',35),('partner_country',3),('partner_zip',10),('partner_city',22),
324
('seg_num5',2),('option_motif',1),('invoice_reference',105),('format',1),('padding',19)
328
'partner_bank_clearing':'','partner_cpt_benef':'',
329
'type_paiement':'0','genre_trans':'836',
331
'invoice_reference': self.global_values['invoice_reference'] or self.global_values['partner_comment'],
335
self.post.update({'comp_dta':'','option_motif':'U'})
338
class record_gt890(record):
340
def init_local_context(self):
344
('date_value_hdr',6),('partner_bank_clearing',12),('zero5',5),('creation_date',6),
345
('comp_bank_clearing',7), ('uid',5),
348
('type_paiement',1),('flag',1),
350
('amount_total',16),('padding',59)]
352
self.pre.update({'partner_bank_clearing':'','partner_cpt_benef':'',
353
'company_bank_clearing':'','genre_trans':'890'})
355
def c_ljust(s, size):
357
check before calling ljust
362
s = s.decode('utf-8').encode('latin1','replace').ljust(size)
367
def _create_dta(self,cr,uid,data,context):
372
v['creation_date']= time.strftime('%y%m%d')
376
pool = pooler.get_pool(cr.dbname)
377
bank= pool.get('res.partner.bank').browse(cr,uid,[data['form']['bank']])[0]
380
return {'note':'No bank account for the company.'}
383
v['comp_bank_name']= bank.name or False
384
v['comp_bank_clearing'] = bank.bank_clearing or False # clearing
385
v['comp_bank_code'] = bank.bank_code or False # swift or BIC
387
if not v['comp_bank_clearing']:
388
return {'note':'You must provide a Clearing Number for your bank account.'}
390
user = pool.get('res.users').browse(cr,uid,[uid])[0]
391
company= user.company_id
392
co_addr= company.partner_id.address[0]
393
v['comp_country'] = co_addr.country_id and co_addr.country_id.name or ''
394
v['comp_street'] = co_addr.street or ''
395
v['comp_zip'] = co_addr.zip
396
v['comp_city'] = co_addr.city
397
v['comp_name'] = co_addr.name
399
v['comp_dta'] = ''#FIXME
402
v['comp_bank_number'] = bank.number or ''
404
v['comp_bank_iban'] = bank.iban or ''
405
if not v['comp_bank_iban'] :
406
return {'note':'No iban number for the company bank account.'}
409
inv_obj = pool.get('account.invoice')
410
dta_line_obj = pool.get('account.dta.line')
415
dta_id=data['form']['dta_id']
418
return {'note':'No dta line'}
420
# write the bank account for the dta object
421
pool.get('account.dta').write(cr,uid,[dta_id],{'bank':data['form']['bank']})
425
for line in data['form']['dta_line_ids']:
426
if line[1]!=0 and line[2] and line[2]['partner_id']:
427
dta_line_ids.append(line[1])
428
th_amount_tot += line[2]['amount_to_pay']
429
dta_line_obj.write(cr, uid, [line[1]] , line[2] )
432
# creation of a bank statement : TODO ajouter le partner
433
bk_st_id = pool.get('account.bank.statement').create(cr,uid,{
434
'journal_id':data['form']['journal'],
436
'balance_end_real':0,
440
for dtal in dta_line_obj.browse(cr,uid,dta_line_ids):
442
i = dtal.name #dta_line.name is the invoice id
443
invoice_number = i.number or '??'
444
if not i.partner_bank_id:
445
log= log +'\nNo partner bank defined. (invoice '+ invoice_number +')'
449
v['sequence'] = str(seq).rjust(5).replace(' ','0')
450
v['amount_to_pay']= str(dtal.amount_to_pay).replace('.',',')
451
v['invoice_number'] = invoice_number or ''
452
v['invoice_currency'] = i.currency_id.code or ''
453
if not v['invoice_currency'] :
454
log= log +'\nInvoice currency code undefined. (invoice '+ invoice_number +')'
458
v['partner_bank_name'] = i.partner_bank_id.bank_name or False
459
v['partner_bank_clearing'] = i.partner_bank_id.bank_clearing or False
460
if not v['partner_bank_name'] :
461
log= log +'\nPartner bank account not well defined. (invoice '+ invoice_number +')'
464
v['partner_bank_iban']= i.partner_bank_id.iban or False
465
v['partner_bank_number']= i.partner_bank_id.number and i.partner_bank_id.number.replace('.','').replace('-','') or False
467
v['partner_bvr']= i.partner_bank_id.bvr_number or ''
470
v['partner_bvr']= v['partner_bvr'].replace('-','')
471
if len(v['partner_bvr']) < 9:
472
v['partner_bvr']= v['partner_bvr'][:2]+ '0'*(9-len(v['partner_bvr'])) +v['partner_bvr'][2:]
476
v['partner_bank_city']= i.partner_bank_id.city or False
477
v['partner_bank_street']= i.partner_bank_id.street or ''
478
v['partner_bank_zip']= i.partner_bank_id.zip or ''
479
v['partner_bank_country']= i.partner_bank_id.country_id and i.partner_bank_id.country_id.name or ''
480
v['partner_bank_code']= i.partner_bank_id.bank_code or False
481
v['invoice_reference']= i.reference
482
v['invoice_bvr_num']= i.bvr_ref_num
483
if v['invoice_bvr_num']:
484
v['invoice_bvr_num'] = v['invoice_bvr_num'].replace(' ', '').rjust(27).replace(' ','0')
486
v['partner_comment']= i.partner_comment
488
v['partner_name'] = i.partner_id and i.partner_id.name or ''
489
if i.partner_id and i.partner_id.address and i.partner_id.address[0]:
490
v['partner_street'] = i.partner_id.address[0].street
491
v['partner_city']= i.partner_id.address[0].city
492
v['partner_zip']= i.partner_id.address[0].zip
493
# If iban => country=country code for space reason
494
elec_pay = i.partner_bank_id.type_id.elec_pay
495
if elec_pay == 'iban':
496
v['partner_country']= i.partner_id.address[0].country_id and i.partner_id.address[0].country_id.code+'-' or ''
498
v['partner_country']= i.partner_id.address[0].country_id and i.partner_id.address[0].country_id.name or ''
500
v['partner_street'] =''
501
v['partner_city']= ''
503
v['partner_country']= ''
504
log= log +'\nNo address for the invoice partner. (invoice '+ invoice_number+')'
507
date_value = dtal.cashdisc_date or dtal.due_date
509
date_value = mx.DateTime.strptime( date_value,'%Y-%m-%d') or mx.DateTime.now()
510
v['date_value'] = date_value.strftime("%y%m%d")
512
v['date_value'] = "000000"
514
# si compte iban -> iban (836)
515
# si payment structure -> bvr (826)
518
elec_pay = i.partner_bank_id.type_id.elec_pay
520
log= log +'\nBank type does not support DTA. (invoice '+ invoice_number +')'
523
if elec_pay == 'iban':
524
# If iban => country=country code for space reason
525
v['comp_country'] = co_addr.country_id and co_addr.country_id.code+'-' or ''
526
record_type = record_gt836
527
if not v['partner_bank_iban']:
528
log= log +'\nNo iban number for the partner bank. (invoice '+ invoice_number +')'
531
if v['partner_bank_code'] :
532
v['option_id_bank']= 'A'
533
v['partner_bank_ident']= v['partner_bank_code']
534
elif v['partner_bank_city']:
538
log= log +'\nCode IBAN or Swift code doesn t exist. (invoice '+ invoice_number +')'
541
v['option_id_bank']= 'D'
542
v['partner_bank_ident']= v['partner_bank_name'] +' '+v['partner_bank_street']\
543
+' '+v['partner_bank_zip']+' '+v['partner_bank_city']\
544
+' '+v['partner_bank_country']
546
log= log +'\nYou must provide the bank city or the bank code. (invoice '+ invoice_number +')'
550
elif elec_pay == 'bvrbank' or elec_pay == 'bvrpost':
551
if not v['invoice_bvr_num']:
552
log= log +'\nYou must provide an Bvr reference number. (invoice '+ invoice_number +')'
554
if not v['partner_bvr']:
555
log= log +'\nYou must provide a BVR reference number in the partner bank. (invoice '+ invoice_number +')'
557
record_type = record_gt826
561
elif elec_pay == 'bvbank':
562
if not v['partner_bank_number'] :
563
if v['partner_bank_iban'] :
564
v['partner_bank_number']= v['partner_bank_iban']
566
log= log +'\nYou must provide a bank number in the partner bank. (invoice '+ invoice_number +')'
569
if not v['partner_bank_clearing']:
570
log= log +'\nPartner bank must have a Clearing Number for a BV Bank operation. (invoice '+ invoice_number +')'
572
v['partner_bank_number'] = '/C/'+v['partner_bank_number']
573
record_type = record_gt827
576
elif elec_pay == 'bvpost':
577
if not v['partner_bank_number']:
578
log= log +'\nYou must provide a post number in the partner bank. (invoice '+ invoice_number +')'
580
v['partner_bank_clearing']= ''
581
v['partner_bank_number'] = '/C/'+v['partner_bank_number']
582
record_type = record_gt827
585
log= log +'\nBank type not supported. (invoice '+ invoice_number +')'
590
dta_line = record_type(v).generate()
592
log= log +'\nERROR:'+ str(e)+'(invoice '+ invoice_number+')'
593
dta_line_obj.write(cr,uid,[dtal.id],{'state':'cancel'})
598
log = log + "Invoice : %s, Amount paid : %d %s, Value date : %s, State : Paid."%\
599
(invoice_number,dtal.amount_to_pay,v['invoice_currency'],date_value and date_value.strftime("%Y-%m-%d") or 'Empty date')
601
reconcile_id = pool.get('account.bank.statement.reconcile').create(cr, uid, {
602
'name': time.strftime('%Y-%m-%d'),
603
'line_ids': [(6, 0, i.move_line_id_payment_get(cr, uid, [i.id]))],
606
pool.get('account.bank.statement.line').create(cr,uid,{
608
'date': time.strftime('%Y-%m-%d'),
609
'amount': -dtal.amount_to_pay,
610
'type':{'out_invoice':'customer','in_invoice':'supplier','out_refund':'customer','in_refund':'supplier'}[i.type],
611
'partner_id':i.partner_id.id,
612
'account_id':i.account_id.id,
613
'statement_id': bk_st_id,
614
'reconcile_id': reconcile_id,
618
amount_tot += dtal.amount_to_pay
619
inv_obj.write(cr,uid,[i.id],{'dta_state':'paid'})
620
dta_line_obj.write(cr,uid,[dtal.id],{'state':'done'})
623
# bank statement updated with the total amount :
624
pool.get('account.bank.statement').write(cr,uid,[bk_st_id],{'balance_end_real': -amount_tot})
627
v['amount_total'] = str(amount_tot).replace('.',',')
628
v['sequence'] = str(seq).rjust(5).replace(' ','0')
631
dta = dta + record_gt890(v).generate()
633
log= log +'\n'+ str(e) + 'CORRUPTED FILE !\n'
637
log = log + "\n--\nSummary :\nTotal amount paid : %.2f\nTotal amount expected : %.2f"%(amount_tot,th_amount_tot)
638
pool.get('account.dta').write(cr,uid,[dta_id],{'note':log,'name':base64.encodestring(dta or "")})
640
return {'note':log, 'dta': base64.encodestring(dta)}
644
class wizard_dta_create(wizard.interface):
648
'actions' : [_get_dta_lines],
649
'result' : {'type' : 'form',
651
'fields' : check_fields,
652
'state' : [('end', 'Cancel'),('creation', 'Yes') ]}
656
'actions' : [_create_dta],
657
'result' : {'type' : 'form',
659
'fields' : res_fields,
660
'state' : [('end', 'Quit') ]}
665
wizard_dta_create('account.dta_create')