2
# -*- encoding: utf-8 -*-
4
# ETL. import csv file with preformatted data comes from Mexal orders
5
# use: import.csv mexal_file_csv.csv
8
import xmlrpclib, csv, sys, ConfigParser
10
import sys, time, os # for get date of file
12
# Start main code *************************************************************
16
* Use the command with this syntax: python ./import.py ocdetoerp.FIA
23
# For problems: input win output ubuntu; trim extra spaces
24
#valore=valore.decode('ISO-8859-1')
25
valore=valore.decode('cp1252')
26
valore=valore.encode('utf-8')
29
def prepare_date(valore):
32
if valore: # TODO test correct date format
33
return valore[:4] + "/" + valore[4:6] + "/" + valore[6:8]
34
return '' #time.strftime("%d/%m/%Y") (per gli altri casi)
36
def prepare_float(valore):
38
if valore: # TODO test correct date format
39
return float(valore.replace(",","."))
41
return 0.0 # for empty values
43
def get_partner_id(sock, uid, pwd, mexal_id):
44
''' Ricavo l'ID del partner dall'id di mexal
46
item_id = sock.execute(dbname, uid, pwd, 'res.partner', 'search', [('ref', '=', mexal_id)])
53
sigla_azienda=FileInput[-3:].lower()
55
print "[ERR] File input non presente!"
57
if sigla_azienda in ('gpb','fia'):
58
cfg_file=sigla_azienda + ".openerp.cfg"
60
print "[ERR] Sigla azienda non trovata!"
63
# Ricavo la data del file per comunicarla
64
create_date=time.ctime(os.path.getctime(FileInput))
66
# Set up parameters (for connection to Open ERP Database) ********************************************
67
config = ConfigParser.ConfigParser()
68
config.read([cfg_file]) # if file is in home dir add also: , os.path.expanduser('~/.openerp.cfg')])
69
dbname = config.get('dbaccess','dbname')
70
user = config.get('dbaccess','user')
71
pwd = config.get('dbaccess','pwd')
72
server = config.get('dbaccess','server')
73
port = config.get('dbaccess','port') # verify if it's necessary: getint
74
separator = config.get('dbaccess','separator') # test
75
verbose = eval(config.get('import_mode','verbose')) #;verbose=True
77
verbose= False # TODO togliere
79
smtp_sender = config.get('smtp', 'sender')
80
smtp_receiver = config.get('smtp', 'receiver')
81
smtp_subject = config.get('smtp', 'subject') + " (Importazione Ordini e verifica date files)"
82
smtp_text = config.get('smtp', 'text')
83
smtp_log = config.get('smtp', 'log_file') + ".ordini.csv"
84
smtp_server = config.get('smtp', 'server')
87
debug_mode=True # TODO reset false when OK
89
# Open file log error (if verbose mail the file are sent to admin email)
91
out_file = open(smtp_log,"w")
93
print "[WARNING]","Error creating log files:", smtp_log
94
# No raise as it'a a warning
96
header_lines = 0 # mai da mexal
97
# XMLRPC connection for autentication (UID) and proxy
98
sock = xmlrpclib.ServerProxy('http://' + server + ':' + port + '/xmlrpc/common', allow_none=True)
99
uid = sock.login(dbname ,user ,pwd)
100
sock = xmlrpclib.ServerProxy('http://' + server + ':' + port + '/xmlrpc/object', allow_none=True)
102
# Open CSV passed file (see arguments) mode: read / binary, delimiation char
103
lines = csv.reader(open(FileInput,'rU'),delimiter=separator) # prima era: rb
104
counter={'tot':-header_lines,'new':0,'upd':0,'order':0} # tot negative (jump N lines)
106
# Elimino tutti gli elementi della tabella prima di procedere all'importazione:
107
header_ids = sock.execute(dbname, uid, pwd, 'statistic.header', 'search', [])
108
response = sock.execute(dbname, uid, pwd, 'statistic.header', 'unlink', header_ids)
110
order_ids = sock.execute(dbname, uid, pwd, 'statistic.order', 'search', [])
111
response = sock.execute(dbname, uid, pwd, 'statistic.order', 'unlink', order_ids)
113
# Carico gli elementi da file CSV:
116
old_order_number = ''
120
if tot_col==0: # memorizzo il numero colonne la prima volta
122
print "[INFO] Colonne rilevate", tot_col
123
raise_error("[INFO] Procedura: %s \n\tFile importato: %s [creazione: %s]"%(sys.argv, FileInput, create_date), out_file)
124
if counter['tot']<0: # salto le N righe di intestazione
127
if len(line) and (tot_col==len(line)): # salto le righe vuote e le righe con colonne diverse
130
csv_id=0 # Codice cliente di mexal forma (NNN.NNNNN)
131
mexal_id = prepare(line[csv_id])
132
csv_id+=1 # Cliente descrizione
133
cliente = prepare(line[csv_id])
134
csv_id+=1 # Order number
135
number = prepare(line[csv_id])
136
csv_id+=1 # Data OC formato: YYYYMMDD
137
order_date = prepare_date(line[csv_id]) or False
138
csv_id+=1 # Scadenza OC formato: YYYYMMDD
139
order_deadline = prepare_date(line[csv_id]) or False
141
articolo_id = prepare(line[csv_id])
142
csv_id+=1 # Articolo descrizione (oppure campo campo note nelle righe (D)escrittive )
143
articolo = prepare(line[csv_id])
145
quantity = prepare_float(line[csv_id]) or 0.0
146
csv_id+=1 # Tipo di riga (b si intende prodotto)
147
type_of_line = prepare(line[csv_id])
149
note = prepare(line[csv_id])
151
csv_id+=1 # Descrizione italiano
152
product_description = prepare(line[csv_id])
153
csv_id+=1 # Descrizione inglese
154
product_description_eng = prepare(line[csv_id])
155
csv_id+=1 # Numero colli
156
colli = prepare(line[csv_id])
157
csv_id+=1 # Tipo di riga (A o D)
158
line_type = prepare(line[csv_id]).lower() # a=articolo, d=descrizione
160
csv_id+=1 # Codice porto
161
port_code = prepare(line[csv_id]).lower()
162
csv_id+=1 # Descrizione italiano
163
port_description = prepare(line[csv_id])
164
csv_id+=1 # Destinazione descrizione
165
destination_description = prepare(line[csv_id])
166
csv_id+=1 # Destinazione indirizzo
167
destination_address = prepare(line[csv_id])
168
csv_id+=1 # Destinazione CAP
169
destination_cap = prepare(line[csv_id])
170
csv_id+=1 # Destinazione localita'
171
destination_loc = prepare(line[csv_id])
172
csv_id+=1 # Destinazione provincia
173
destination_prov = prepare(line[csv_id])
176
csv_id+=1 # Data di registrazione
177
registration_date = prepare_date(line[csv_id]) or False
178
csv_id+=1 # Note aggiuntive (nella stampa)
179
extra_note = prepare(line[csv_id])
180
csv_id+=1 # Note aggiuntive (nella stampa)
181
agent_description = prepare(line[csv_id])
184
# Dati dimensionali letti dal prodotto:
185
product_ids = sock.execute(dbname, uid, pwd, 'product.product', 'search', [('mexal_id','=', articolo_id )])
187
if product_ids and line_type == 'a':
188
product_item = sock.execute(dbname, uid, pwd, 'product.product', 'read', product_ids)[0]
189
total_linear_meter = (quantity or 0.0) * product_item['linear_length']
190
total_volume = (quantity or 0.0) * (product_item['volume'] or 0.0)
191
total_weight = (quantity or 0.0) * (product_item['weight'] or 0.0)
192
else: # description line
193
total_linear_meter = False
198
raise_error("[ERR] Riga:%s - Prodotto non trovato: %s"%(counter['tot'], articolo_id), out_file)
201
partner_id = get_partner_id(sock, uid, pwd, mexal_id)
205
colli = quantity # se non ci sono i colli metto uguale a quantity (per avere il 20 x 1)
206
if port_code not in ('', 'f', 'a', 'd'):
207
raise_error("[ERR] Riga:%s - Codice Porto non trovato: %s"%(counter['tot'], port_code), out_file)
209
if line_type not in ('a', 'd'):
210
raise_error("[ERR] Riga:%s - Tipo di linea non trovato: %s"%(counter['tot'], line_type), out_file)
213
raise_error("[ERR] Riga:%s - Partner non trovato: %s"%(counter['tot'], mexal_id), out_file)
215
if type_of_line.lower() == 'b':
216
quantity_ok = quantity or 0.0
221
raise_error("[ERR] Riga:%s - Numero d'ordine non trovato: %s"%(counter['tot'], number), out_file)
223
# Inserimento ordine testata statistic.header
224
if old_order_number != number: # se cambia faccio le verifiche o lo creo altrimenti rimane l'ID prec.
225
old_order_number = number # memorizzo il vecchio numero
228
header = {'name': number, #"Ordine n.:%s"%(number,),
229
'partner_id': partner_id,
231
'deadline': order_deadline,
232
#'total': fields.float('Total', digits=(16, 2)),
234
'port_code': port_code,
235
'port_description':port_description,
236
'destination':destination_description,
237
'destination_address': destination_address,
238
'destination_cap': destination_cap,
239
'destination_country': destination_loc,
240
'destination_prov': destination_prov,
241
'agent_description': agent_description,
244
'registration_date': registration_date,
245
'extra_note': extra_note,
247
# TODO ottimizzabile cercando la rottura di codice:
248
search_header_id = sock.execute(dbname, uid, pwd, 'statistic.header', 'search', [('name','=',number)])
250
header_id=search_header_id[0] # Memorizzo per associarlo poi all'ordine
253
header_id = sock.execute(dbname, uid, pwd, 'statistic.header', 'create', header)
255
raise_error("[ERR] Riga:%s - Errore creando header: %s"%(counter['tot'], number), out_file)
257
raise_error("[INFO] Riga:%s - Header inserito: %s"%(counter['tot'], number), out_file)
258
else: # stesso ordine
261
# Inserimento dettaglio ordine (associando la riga con l'header_id)
262
# Importazione dato: statistic.order
263
data={'name': number,
264
'partner_id': partner_id,
266
'deadline': order_deadline,
268
'code': articolo_id, # codice di mexal
269
'article': "%s %s"%(articolo,product_description), # descrizione articolo + descrizione italiana aggiuntiva
270
'quantity': quantity,
271
'quantity_ok': quantity_ok,
272
'total_linear_meter': total_linear_meter,
273
'total_volume': total_volume,
274
'total_weight': total_weight,
276
'header_id': header_id,
277
'line_type': line_type,
279
'sequence': sequence,
282
if not order_deadline and line_type=="a": # Comunico solo nel caso non sia riga descrittiva
283
raise_error("[ERR] Riga:%s - Scadenza non trovata: %s"%(counter['tot'], number), out_file)
285
mod_response = sock.execute(dbname, uid, pwd, 'statistic.header', 'write', header_id, {'deadline': order_deadline,}) # TODO optimize! <<<<<<<<<<<
289
data['type']= type_of_line.lower()
292
order_id = sock.execute(dbname, uid, pwd, 'statistic.order', 'create', data)
294
raise_error("[ERR] Riga:%s - Errore creando ordine: %s"%(counter['tot'], number), out_file)
297
raise_error("[INFO] Riga:%s - Ordine inserito: %s"%(counter['tot'], number), out_file)
300
raise_error("[ERR] Riga:%s - Errore di importazione: %s"%(counter['tot'], sys.exc_info()[0]), out_file)
302
raise_error("[ERR] Riga:%s - Riga vuota o con colonne diverse: file %s, riga %s"%(counter['tot'], tot_col, len(line)), out_file)
304
raise_error("[ERR] Errore importando gli ordini!", out_file)
306
raise_error("[INFO] Totale ordini: %s - Totale righe: %s"%(counter['order'],counter['tot'],), out_file)
308
if debug_mode: # Parte comune a tutte le procedure:
309
file_log=os.path.abspath(os.path.dirname(FileInput))+"/log.FIA"
310
raise_error("\n\n[DEBUG] Date files importati:", out_file)
312
for line in open(file_log,'r'):
314
if i>7: # jump first line (description and . / ..)
315
if line and line[0:1]!=" ":
316
raise_error("\tData: %s - File: %s"%(line[0:17], line[35:].strip(),), out_file)
319
send_mail(smtp_sender,[smtp_receiver,],smtp_subject,smtp_text,[smtp_log,],smtp_server)