def _parse_file_name(self, cr, uid, file_name): ''' Check if file is syntactically correct with this format: TypeYear Customer N.doc.Company direction_in = True >> file= BF 2012 501.000001 0701.MMI direction_in = False >> file= BC 2012 501.000001 0701.MMI Return 3 extra information: year, partner_id, doc_number ''' import parse_function direction_in = file_name[:2].upper()=='BF' parsed = file_name[3:-4].split(" ") if len(parsed) == 3: parsed[1] = parse_function.get_partner_supplier(self, cr, uid, parsed[1], direction_in) return parsed return False,False,False # error
def import_or_test_loaded_files(self, cr, uid, ids, test, context=None): ''' This function has 2 mode: 1) If test=True, the function try to read the files in wizard line verify some errors (no line, no lot, no hygro for coal, no partner and so on, if OK no error are returned 2) If test=False, the function do the importation in the database return error and log informations Return value: (log_error, log_activity, record created (if 2) The return is befor natural end of function if is a locked error ''' separator = ";" log_activity = "%s Start operation" % (datetime.now()) # TODO setup for errors log_error = "" pick_ids = [] # for final redirect date_now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') try: if_error = _('Error loading object') # create all used proxy reference: wizard_proxy = self.browse(cr, uid, ids)[0] wizard_line_pool = self.pool.get('picking.import.wizard.file') # in test, for update line importer_order_pool = self.pool.get('importation.purchase.order') partner_proxy = self.pool.get('res.partner') location_proxy = self.pool.get('importation.default.location') lot_proxy = self.pool.get('stock.production.lot') product_proxy = self.pool.get('product.product') move_proxy = self.pool.get('stock.move') picking_proxy = self.pool.get('stock.picking') picking_proxy_out = self.pool.get('stock.picking.out') picking_proxy_in = self.pool.get('stock.picking.in') # 3 default value for stock location (IN, OUT, INTERNAL) stock_in, stock_out, stock_internal = self.import_default_stock_location( cr, uid, context=context) if not (stock_in and stock_out and stock_internal): # locked error return ( "Need to setup default location for In, Internal, Production, Out before import! (Coal / Configuration / Stock location default)", log_activity, pick_ids, ) # TODO IMPORTANTE VALUTARE I LOTTI IN INGRESSO PER CONTROLLARE SE IL PRODOTTO SIA COERENTE!!!!! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # TODO Ricordarsi anche la storicizzazione del numero lotto in base a OF direction_in = wizard_proxy.direction_in # IN o OUT if test: # Operations in test mode (verify if yet present): if direction_in: # if BF test double insert # Test if there's some document present (partner-number-year) for item_line in wizard_proxy.line_ids: # read all lines of wizard full_name = item_line.full_name.split(" ") year = full_name[-3] partner_ref = full_name[-2] ref = full_name[-1].split(".")[0] partner_id = parse_function.get_partner_supplier( self, cr, uid, partner_ref, direction_in) if not partner_id: continue # no partner, no document present domain = [ ('partner_id', '=', partner_id), ('date', '>=', '%s-01-01 00:00:00' % (year)), ('date', '<=', '%s-12-31 23:59:59' % (year)), ('type', '=', 'in'), ('origin', 'ilike', '%s [%s' % (ref, '%')), ] BF_ids = picking_proxy.search(cr, uid, domain, context=context) if BF_ids: wizard_line_pool.write(cr, uid, item_line.id, { 'to_import': False, 'exist': True, 'log_error': 'Documento già presente in OpenERP!', }, context=context) else: # if BC test double insert history_line_ids = {} for item_line in wizard_proxy.line_ids: # read all lines of wizard # Test for duplicated exportation (ID and date are test) not_import_lines = [] BC_id = item_line.import_document.split("/")[0] if BC_id in history_line_ids: # yet present? if item_line.date > history_line_ids[BC_id]['date']: # save this parameter and not import previous wizard_line_pool.write(cr,uid,history_line_ids[BC_id]['id'], { 'to_import': False, 'log_error': 'Documento duplicata (controllare la data per vedere quale tenere)!'}, context=context) history_line_ids[BC_id]['id'] = item_line.id history_line_ids[BC_id]['date'] = item_line.date else: # not import this wizard_line_pool.write(cr,uid,item_line.id, { 'to_import': False, 'log_error': 'Documento duplicata (controllare la data per vedere quale tenere)!'}, context=context) else: # Create element history_line_ids[BC_id] = {} history_line_ids[BC_id]['id'] = item_line.id history_line_ids[BC_id]['date'] = item_line.date for file_item in wizard_proxy.line_ids: # all wizard line if not file_item.to_import: if file_item.exist: # delete file yet imported: os.remove(file_item.full_name) log_activity += "\n- Documento rimosso %s!" % ( file_item.name ) else: log_activity += "\n- Documento saltato %s!" % ( file_item.name, ) continue # next file # Import document: if_error = _('Nessun %s CSV file, prego esportare il documenti prima e salvarlo in: %s' % ( file_item.name, file_item.path, )) lines = open(file_item.full_name, 'rb', ) first = True if not lines: update_line = wizard_line_pool.write(cr, uid, [file_item.id], { 'log_error': "Nessuna linea presente nel file:\n%s" % ( file_item.import_document), 'to_import': False,}, context=context) continue # next line if_error = _('Errore leggendo / interpretando il file:\n%s' % ( file_item.import_document)) # Import file creatin stock.picking and stock.move (wit stock lot) line_ids_to_assigned = [] for line_all in lines: # lines of file opened line = line_all.replace('\x00', '').split(separator) # CSV imported element (HEADER element): ref = parse_function.prepare(line[0]) # Pick ref. date = parse_function.prepare_date(line[1]) # Date partner_ref = parse_function.prepare(line[2]) # Partner code partner = parse_function.prepare(line[3]) # Partner name purchase_order = parse_function.prepare(line[8]) # Purchase order # CSV imported element (LINE element): product_ref = parse_function.prepare(line[4]) # Product code um = parse_function.prepare(line[5]) # UOM #product_um = parse_function.prepare(line[5]) # Product UM product_q = parse_function.prepare_float(line[6]) # Quantity product_price = parse_function.prepare_float(line[7]) # Price product_lot = parse_function.prepare(line[9]) # Lot (sometimes non present but get from openerp history) hygro = parse_function.prepare_float(line[10]) # Hygro for coal # calculed fields: export_date=file_item.date[:10] partner_id = parse_function.get_partner_supplier(self, cr, uid, partner_ref, direction_in) if not partner_id: # update log for the line update_line=wizard_line_pool.write(cr, uid, [file_item.id], { 'log_error': "Partner non trovato: %s - %s!" % (partner_ref, partner), 'to_import': False, }, context = context) continue # next line uom_id = parse_function.get_product_um(self, cr, uid, um) if not uom_id: # update log for the line update_line = wizard_line_pool.write(cr, uid, [file_item.id], { 'log_error': "U.M. non trovata: %s!" % (um), 'to_import': False, }, context = context) continue # next line product_id = parse_function.get_product(self, cr, uid, product_ref) # Product ID from product_ref if not product_id: update_line = wizard_line_pool.write(cr, uid, [file_item.id], { 'log_error': "File: %s Errore non riesco ad abbinare prodotto al codice: %s!" % ( file_item.import_document, product_ref), 'to_import': False, }, context = context) continue # next line # test mandatory values (usually for coal product): is_coal = is_product_coal(self, cr, uid, product_id, context=None) if is_coal: if not hygro and direction_in: # hygro mandatory for coal (only in pickin in document) update_line = wizard_line_pool.write(cr, uid, [file_item.id], { 'log_error': "Umidita' non presente ma obbligatoria per carboni: %s!" % (product_ref), 'to_import': False, }, context = context) continue # next line if not direction_in and not product_lot: # on BC, mandatory lot update_line = wizard_line_pool.write(cr, uid, [file_item.id], { 'log_error': "Obbligo del lotto per carbone in BC! Prodotto: %s!" % (product_ref), 'to_import': False, }, context = context) continue # next line try: # manage error during single file operation: # stock.production.lot ******************************** if not direction_in: # BC ***************************** lot_id = False # TODO change for the future! if product_lot: lot_id = lot_proxy.search(cr, uid, [ ('name', '=', product_lot)]) # TODO verify also the product if lot_id: # not present: create? lot_control_proxy = lot_proxy.browse(cr, uid, lot_id[0]) # TODO verify also the product if lot_control_proxy.product_id and lot_control_proxy.product_id.id == product_id: lot_id = lot_id[0] # use the first! else: update_line = wizard_line_pool.write(cr, uid, [file_item.id], { 'log_error': "Lotto %s e' per il prodotto %s, attualmente nel doc. e': %s" % ( product_lot, lot_control_proxy.product_id.name, product_ref), 'to_import': False,}, context=context) continue # next line if not lot_id and is_coal: update_line = wizard_line_pool.write(cr, uid, [file_item.id], { 'log_error': "Il lotto dovrebbe già essere presente ma non è stato trovato (BC con carbone), Lotto: '%s'! Prodotto: %s!" % ( product_lot, product_ref), 'to_import': False, }, context=context) continue # next line else: # lot not present: pass # For now not mandatory lot for BC (only for coal) else: # BF ******************************************** import pdb; pdb.set_trace() # ----------------- # Test product lot: # ----------------- if product_lot: # lot number from import lot_id = lot_proxy.search(cr, uid, [ ('name', '=', product_lot) ], context=context) if lot_id: # Lot not found in system: create lot_id = lot_id[0] # take the first else: # No creation, test for product # Create lot in OpenERP lot_id = lot_proxy.create(cr, uid, { 'product_id': product_id, 'name': product_lot, 'stock_available': product_q, 'date': date_now, #'2012-06-05 15:13:14', }) # Create update lot importation history importer_order_pool.new_lot( cr, uid, product_id, partner_id, purchase_order, lot_id, context = context) else: # Lot number not from import (test in OpenERP history) lot_id = importer_order_pool.check_lot( cr, uid, product_id, partner_id, purchase_order, context=context) if not lot_id: update_line = wizard_line_pool.write(cr, uid, [file_item.id], { 'log_error': "Lotto vuoto e nessun precedente OF per questo prodotto: %s!" % ( product_ref), 'to_import': False, }, context=context) continue # next line # Check if log get match with product_id on OpenERP (note: obviuosly correct for creation): lot_control_proxy = lot_proxy.browse( cr, uid, lot_id, context=context) if not (lot_control_proxy.product_id and lot_control_proxy.product_id.id == product_id): # lot for another product update_line = wizard_line_pool.write( cr, uid, [file_item.id], { 'log_error': "Lotto %s e' per il prodotto %s, attualmente nel doc. e': %s" % ( product_lot, lot_control_proxy.product_id.name if lot_control_proxy.product_id else "", product_ref), 'to_import': False, }, context=context) continue # next line except: update_line = wizard_line_pool.write(cr, uid, [file_item.id], { 'log_error': "Errore generico cercando analizzare il documento", 'to_import': False,}, context=context) continue # next line (doesn't create picking) if first: # Aggiorno il wizard principale: **** PICKING HEADER ***** if_error = _('Error creating picking document:\n%s' % (file_item.import_document)) first=False # Calculated fields (this only for header) #address_id = partner_proxy.address_get(cr, uid, partner_id).values()[0] # TODO verificare se sono più di uno if not partner_id: # update log for the line update_line=wizard_line_pool.write(cr, uid, [file_item.id], { 'log_error': "Indirizzo partner non trovato: %s - %s!" % (partner_ref, partner), 'to_import': False,}, context=context) continue # next line # stock.picking ***************************************** if not test: # create pick_id picking_data = { 'origin': "%s [%s:%s]" % ( ref, "OF" if direction_in else "OC", purchase_order), #'name': sequence_pool.get(cr, uid, "stock.picking.in" if direction_in else "stock.picking.out") # or use picking_proxy different for out and in #'name': 'IN/00001','stock_journal_id':,'invoice_state': , 'date': date, #'address_id': address_id, 'partner_id': partner_id, # aggiunto dalla 7 'move_type': 'direct', 'type': 'in' if direction_in else 'out', 'note': 'Loaded from external program', 'state': 'done', # TODO test 'min_date': date, 'max_date': date, 'import_document': file_item.import_document, #'import_date': export_date, # for registration 'wizard_id': wizard_proxy.id, # TODO togliere non serve, trovare il modo per il redirect finale } if not direction_in and is_coal: # assign XAB number picking_data['xab_number'] = self.pool.get('ir.sequence').get(cr, uid, 'stock.picking.out.xab') _logger.info("XAB for BC created %s" % picking_data['xab_number']) pick_id = picking_proxy.create(cr, uid, picking_data) # NOTE: Below the part that generate "No XAB Number" in commercial report #if direction_in: # pick_id = picking_proxy_in.create(cr, uid, picking_data) #else: # pick_id = picking_proxy_out.create(cr, uid, picking_data) # Create XAB if not pick_id: wizard_line_pool.write(cr, uid, [file_item.id], { 'log_error':"Errore creando documento di prelievo: %s (%s)!"%(ref, purchase_order), 'to_import': False,}, context=context) continue # next line pick_ids.append(pick_id) else: # test mode: pick_id = 0 else: # not the first pass if_error = _('Errore creando i movimenti per il documento di carico / scarico: %s'%(file_item.name)) if not test: # create move, analysis, rename file # stock.move *********************************************** product_browse=product_proxy.browse(cr, uid, product_id) data_move={ 'product_uos_qty': product_q, #'create_date': '2012-06-04 18:58:05', #'price_unit': 0.0, 'product_qty': product_q, #300.0, 'product_uos': product_browse.uos_id.id if product_browse.uos_id else False, 'product_uom': uom_id, #product_browse.uom_id.id if product_browse.uom_id else False, #[2, 'kg'], <<< TODO devo caricarla come fa l'on_change!! #'partner_id': [429, 'Luxalloys S.A.'], 'priority': '1', #'sale_line_id': False, 'auto_validate': False, 'price_currency_id': False, 'location_id': stock_in if direction_in else stock_internal, # depends on direction BF > comes from IN, BC > comes from INTERNAL 'location_dest_id': stock_internal if direction_in else stock_out, # depends on direction BF > goes to INTERNAL, BC > goes to OUT #'company_id': [1, 'Minerals & Metals spa'], 'note': False, 'state': 'done', 'product_packaging': False, 'purchase_line_id': False, 'move_history_ids': [], 'date_expected': export_date, #'backorder_id': False, #'move_dest_id': False, 'date': export_date, #'production_id': False, 'is_coal': , 'scrapped': False, 'tracking_id': False, 'move_history_ids2': [], 'product_id': product_id, 'name': '[%s] %s'%(product_browse.code, product_browse.name), 'picking_id': pick_id, 'state': 'done', 'prodlot_id': lot_id, 'via_hygro': hygro, # TODO verify for VIA also in production (not override!!) } if direction_in and is_coal: # assign VIA number data_move['via_number'] = self.pool.get('ir.sequence').get(cr, uid, 'product.coal') # forse era stato tolto nella 6: if not direction_in and is_coal: # assign XAB number pass #data_move['xab_number']=self.pool.get('ir.sequence').get(cr, uid, 'stock.picking.out.xab') # TODO debug try: pick_line_id=move_proxy.create(cr, uid, data_move, context=context) except: return ("Errore creando movimento: %s" % (data_move), log_activity, pick_ids) if direction_in: # Create analysis for all new lot (starting from stock.picking: picking_proxy.create_all_analysis(cr, uid, [pick_id], context=context) # TODO: better to put at the end of creation stock.picking (not for performance) # TODO need to be logged better if did not create analysis!! # move parsed files in history folder os.rename(file_item.full_name, "%s%s.%s"%(file_item.path_history, pick_id, file_item.name[-3:])) # TODO delete wizar line! except: # TODO if error in stock move, pick created without movements!!!!!!!! # TODO non viene comunicato: raise osv.except_osv(_('Error!'), _("Generic error during importation")) # TODO test if works! return (if_error, log_activity, pick_ids) #wizard_raise_error(self, cr, uid, ids, if_error, log_activity, context=context) return (False, False, pick_ids) #Normal exit return no error stock.picking created