import pooler
import time
import wizard
-import ir
import netsvc
-from time import sleep
from base64 import b64decode
+from osv import osv
+ask_form = """<?xml version="1.0"?>
+<form string="V11 parsing">
+<separator colspan="4" string="Extract V11 data :" />
+ <field name="journal_id" colspan="1"/>
+ <newline/>
+ <field name="v11"/>
+</form>
+"""
+
+ask_fields = {
+ 'journal_id' : {
+ 'string':'Destination Journal',
+ 'type':'many2one',
+ 'relation':'account.journal',
+ 'required':True,
+ },
+ 'v11' : {
+ 'string':'V11 file',
+ 'type':'binary',
+ 'required':True,
+ },
+
+}
-test_form = """<?xml version="1.0"?>
+res_form = """<?xml version="1.0"?>
<form string="V11 parsing">
- <separator colspan="4" string="Extract V11 data ?" />
+<separator colspan="4" string="Results :" />
<field name="journal_id"/>
+ <newline/>
+ <field name="v11"/>
+ <separator string="Logs" colspan="4"/>
+ <field name="note" colspan="4" nolabel="1"/>
</form>
"""
-test_fields = {
+res_fields = {
'journal_id' : {
'string':'Destination Journal',
'type':'many2one',
'relation':'account.journal',
'required':True,
-# 'domain':[('type','=','sale')]
},
+ 'v11' : {
+ 'string':'V11 file',
+ 'type':'binary',
+ 'required':True,
+ },
+
+ 'note' : {'string':'Log','type':'text'}
}
+
def _v11_parsing(self, cr, uid, data, context):
pool = pooler.get_pool(cr.dbname)
- v11_obj = pool.get('account.v11')
+ v11 = data['form']['v11']
- for v11 in v11_obj.browse(cr, uid, data['ids']):
-
- line=""
- record={}
- total={}
- total_compute= 0
- rec_list=[]
- log=''
+ line=""
+ record={}
+ total={}
+ total_compute= 0
+ rec_list=[]
+ log=''
+ nb_err=0
- # v11 parsing :
- for char in b64decode(v11.file):
+ # v11 parsing :
+ for char in b64decode(v11):
- if not char == '\n':
- line += char
+ if not char == '\n':
+ line += char
- else :
+ else :
- record['genre'] = line[0:3]
+ record['genre'] = line[0:3]
- if record['genre'] == '999':
+ if record['genre'] == '999':
- total={'n_postal': line[3:12],
- 'cle': line[12:39],
- 'tot_montant': line[39:51],
- 'nb_rec': line[51:63],
- 'date_etabl': line[63:69],
- 'tot_frais_encaissement': line[69:78],
- }
+ total={'n_postal': line[3:12],
+ 'cle': line[12:39],
+ 'tot_montant': line[39:51],
+ 'nb_rec': line[51:63],
+ 'date_etabl': line[63:69],
+ 'tot_frais_encaissement': line[69:78],
+ }
- else :
+ else :
- record={'n_postal': line[3:12],
- 'n_ref': line[12:39],
- 'montant': line[39:49],
- 'reserve': line[49:59],
- 'date_remise': line[59:65],
- 'date_comptable': line[65:71],
- 'date_valeur': line[71:77],
- 'internal_ref': line[77:87],
- 'reserve2': line[87:96],
- 'frais_encaissement': line[96:100],
- 'line':line,
- }
+ record={'n_postal': line[3:12],
+ 'n_ref': line[12:39],
+ 'montant': line[39:49],
+ 'reserve': line[49:59],
+ 'date_remise': line[59:65],
+ 'date_comptable': line[65:71],
+ 'date_valeur': line[71:77],
+ 'invoice_ref': line[77:87],
+ 'reserve2': line[87:96],
+ 'frais_encaissement': line[96:100],
+ 'line':line,
+ }
- total_compute+= int(record['montant'])
- rec_list.append( record )
+ total_compute+= int(record['montant'])
+ rec_list.append( record )
- line=""
+ line=""
- # check the amounts :
- if not total_compute == int(total['tot_montant']):
- raise wizard.except_wizard('warning', 'Incoherent v11 file !')
- continue
-
+ # check the amounts :
+ if not total_compute == int(total['tot_montant']):
+ return {'note': 'Incoherent V11 file ! IMPORT ABORTED.' }
- period_id = pool.get('account.period').find(cr,uid, context=context)
- if not period_id:
- raise wizard.except_wizard('No period found !', 'Unable to find a valid period !')
- period_id = period_id[0]
- invoice_obj= pool.get('account.invoice')
- for rec in rec_list:
+ period_id = pool.get('account.period').find(cr,uid, context=context)
+ if not period_id:
+ return {'note': 'No period found ! IMPORT ABORTED.' }
+ period_id = period_id[0]
+ invoice_obj= pool.get('account.invoice')
- # recherche sur l'id (pr garder un num absolu):
- # implique de mettre l'id sur le bvr..
- invoice_id= invoice_obj.search(cr,uid,[ ('id','=',int(rec['internal_ref'])) ])[0]
- print invoice_id
- invoice = invoice_obj.browse(cr, uid, invoice_id)
- invoice_obj.write(cr,uid,[invoice_id],{'state':'paid'})
+ acc2 = pool.get('account.journal').browse(cr,uid,data['form']['journal_id'],context).default_debit_account_id.id
+ if not acc2:
+ return {'note': 'No debit account specified for this journal ! IMPORT ABORTED.' }
- # TODO feedbacker en log les erreurs
- acc2 = pool.get('account.journal').browse(cr,uid,data['form']['journal_id'],context).default_debit_account_id.id
- if not acc2:
- raise wizard.except_wizard('Warning !', 'No debit account specified for this journal !')
- continue
-
- # TODO idem
- try:
- acc1 = invoice.partner_id.property_account_receivable[0]
- except:
- raise wizard.except_wizard('Warning !','invoice with number '+str(int(rec['internal_ref'])) +' has no partner !')
- continue
+ for rec in rec_list:
+ # get the invoice via his number
+ try:
+ invoice_id= invoice_obj.search(cr,uid,[ ('number','=',int(rec['invoice_ref'])) ])[0]
+ except:
+ log = log + '\n * No invoice with invoice number '+ rec['invoice_ref'].lstrip('0') + '.\n line : '+rec['line']
+ nb_err+=1
+ continue
+ invoice = invoice_obj.browse(cr, uid, invoice_id)
+ try:
+ acc1 = invoice.partner_id.property_account_receivable[0]
+ except:
+ log = log + '\n * invoice with number '+ rec['invoice_ref'].lstrip('0') +' has no partner !'+ '\n line : '+rec['line']
+ nb_err+=1
+ continue
+ try:
move_id = pool.get('account.move').create(cr, uid, {
'name': 'Imported from v11',
'period_id': period_id,
'journal_id': data['form']['journal_id']
- })
-
-
-
- pool.get('account.move.line').create(cr,uid,{
- 'name': 'v11',
+ })
+ line_id = pool.get('account.move.line').create(cr,uid,{
+ 'name': 'v11', # maybe a better name ..
'debit': 0,
'credit': rec['montant'],
'account_id': acc1,
'journal_id': data['form']['journal_id']
})
-
-
-
- log= log + 'Number of parsed lines : '+ str(len(rec_list)) +'\nTotal amount for this bvr : '+ str(int(total['tot_montant']))+' '+invoice.currency_id.name
-
-
- v11.write(cr,uid,[v11.id],{'note': log })
-
- # peut-etre retourner un nouvel onglet avec la liste des ecritures generee :
- return {}
-
-
-
+ account_move_lines = invoice.move_line_id_payment_get(cr,uid,[invoice.id])
+
+ if not account_move_lines:
+ raise Exception("No moves associated to invoice number "+ rec['invoice_ref'].lstrip('0'))
+ account_move_lines.append(line_id )
+ pool.get('account.move.line').reconcile(cr,uid,account_move_lines,
+ writeoff_acc_id=0,#FIXME
+ writeoff_journal_id=0,#FIXME
+ writeoff_period_id= 0,
+ )
+ cr.commit()
+
+ except osv.except_osv, e:
+ cr.rollback()
+ nb_err+=1
+ if e.value.startswith('You have to provide an account for the write off entry !'):
+ log= log +'\n * Error amount mismatch for invoice '+ rec['invoice_ref'].lstrip('0')+ ':\n line : '+rec['line']
+ else:
+ log= log +'\n * '+str(e.value)+ ' :\n line : '+rec['line']
+ #raise # REMOVEME
+
+ except Exception, e:
+ cr.rollback()
+ nb_err+=1
+ log= log +'\n * '+str(e)+ ' :\n line : '+rec['line']
+ #raise # REMOVEME
+ except :
+ cr.rollback()
+ nb_err+=1
+ log= log +'\n * Reconciliation Error\n line : '+rec['line']
+ #raise
+
+ log= log + '-'*5 +'\nNumber of parsed lines : '+ str(len(rec_list)) +'\nNumber of error : '+ str(nb_err)
+
+ return {'note':log,'journal_id': data['form']['journal_id'], 'v11': data['form']['v11']}
+
+
+# def _init(self, cr, uid, data, context):
+# if not data['form']:
+# return {}
+# return {'journal_id': data['form']['journal_id'], 'v11': data['form']['v11']}
class v11_import(wizard.interface):
states = {
'init' : {
'actions' : [],
'result' : {'type' : 'form',
- 'arch' : test_form,
- 'fields' : test_fields,
+ 'arch' : ask_form,
+ 'fields' : ask_fields,
'state' : [('end', 'Cancel'),('extraction', 'Yes') ]}
},
'extraction' : {
'actions' : [_v11_parsing],
- 'result' : {'type' : 'state', 'state' : 'end'}
+ 'result' : {'type' : 'form',
+ 'arch' : res_form,
+ 'fields' : res_fields,
+ 'state' : [('extraction', 'Retry') ,('end', 'Quit') ]}
},
-# 'result' : {
-# 'actions' : [],
-# 'result' : {'type' : 'form',
-# 'state' : 'end'}
-# },
-
-
-
}
v11_import("account.v11_import")
-<!-- defini le formulaire -->
- <record model="ir.ui.view" id="view_v11_form">
- <field name="name">account.v11.form</field>
- <field name="model">account.v11</field>
- <field name="type">form</field>
- <field name="arch" type="xml">
- <form string="V11">
- <field name="name" />
- <field name="file" />
- <separator colspan="3" />
- <field name="note" colspan="4" select="1"/>
- </form>
- </field>
- </record>
-
-<!-- defini une action -->
- <record model="ir.actions.act_window" id="open_view_test_form">
- <field name="name">account.v11</field>
- <field name="type">ir.actions.act_window</field>
- <field name="res_model">account.v11</field>
- <field name="view_type">form</field>
- <field name="view_mode">form,tree</field>
- </record>
+<!-- <\!-- defini le formulaire -\-> -->
+<!-- <record model="ir.ui.view" id="view_v11_form"> -->
+<!-- <field name="name">account.v11.form</field> -->
+<!-- <field name="model">account.v11</field> -->
+<!-- <field name="type">form</field> -->
+<!-- <field name="arch" type="xml"> -->
+<!-- <form string="V11"> -->
+<!-- <field name="name" /> -->
+<!-- <field name="file" /> -->
+<!-- <field name="state" colors="red:state=='error'"/> -->
+<!-- <separator colspan="3" /> -->
+<!-- <field name="note" colspan="4" select="1"/> -->
+<!-- </form> -->
+<!-- </field> -->
+<!-- </record> -->
+
+<!-- <\!-- defini une action -\-> -->
+<!-- <record model="ir.actions.act_window" id="open_view_test_form"> -->
+<!-- <field name="name">account.v11</field> -->
+<!-- <field name="type">ir.actions.act_window</field> -->
+<!-- <field name="res_model">account.v11</field> -->
+<!-- <field name="view_type">form</field> -->
+<!-- <field name="view_mode">form,tree</field> -->
+<!-- </record> -->
<!-- defini l'entree -->
- <menuitem name="Financial Management/V11" id="menu_account_v11" action="open_view_test_form"/>
+<!-- <menuitem name="Financial Management/V11" id="menu_account_v11" action=""/> -->
</data>