From e5e76e2dcb334fb2836930237b8ad5226986d5d5 Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Tue, 20 Jan 2026 16:13:52 +0100 Subject: [PATCH] 20.01.26 --- modules/automation/cron.py | 300 +++++++++++++++++++++++-------------- 1 file changed, 188 insertions(+), 112 deletions(-) diff --git a/modules/automation/cron.py b/modules/automation/cron.py index 2a6627f..7975506 100644 --- a/modules/automation/cron.py +++ b/modules/automation/cron.py @@ -68,126 +68,202 @@ class AutomationCron(ModelSQL, ModelView): t.FintradeBookingKey, )) - # Préparer les listes pour la sauvegarde et les données du shipment - parties_to_save = [] - vessels_to_save = [] - locations_to_save = [] - shipments_data = [] # <-- nouvelle liste + # ---- PREMIÈRE TRANSACTION : Création des objets de référence ---- + with Transaction().new_transaction() as trans1: + try: + parties_to_save = [] + vessels_to_save = [] + locations_to_save = [] + + parties_cache = {} + vessels_cache = {} + locations_cache = {} + + # Collecter les données des objets de référence + rows = cursor.fetchall() + for row in rows: + ( + si_number, si_date, si_quantity, si_unit, + container_number, container_type, + loading_name, destination_name, + agent_name, carrier_name, + vessel_name, bl_number, + etd_date, bl_date, controller, + comments, fintrade_booking_key + ) = row - parties_cache = {} - vessels_cache = {} - locations_cache = {} + # Fonction pour obtenir ou créer un Party + def get_or_create_party(name): + if not name: + return None + name_upper = name.upper() + if name_upper in parties_cache: + return parties_cache[name_upper] + + # Chercher d'abord dans la base + existing = Party.search([('name', '=', name_upper)], limit=1) + if existing: + parties_cache[name_upper] = existing[0] + return existing[0] + + # Créer un nouveau + new_p = Party() + new_p.name = name_upper + parties_cache[name_upper] = new_p + parties_to_save.append(new_p) + return new_p - rows = cursor.fetchall() - for row in rows: - ( - si_number, si_date, si_quantity, si_unit, - container_number, container_type, - loading_name, destination_name, - agent_name, carrier_name, - vessel_name, bl_number, - etd_date, bl_date, controller, - comments, fintrade_booking_key - ) = row + # Fonction pour obtenir ou créer un Vessel + def get_or_create_vessel(name): + if not name: + return None + name_upper = name.upper() + if name_upper in vessels_cache: + return vessels_cache[name_upper] + + existing = Vessel.search([('vessel_name', '=', name_upper)], limit=1) + if existing: + vessels_cache[name_upper] = existing[0] + return existing[0] + + new_v = Vessel() + new_v.vessel_name = name_upper + vessels_cache[name_upper] = new_v + vessels_to_save.append(new_v) + return new_v - logger.info("ROW_FROM_CRON: %s", row) + # Fonction pour obtenir ou créer une Location + def get_or_create_location(name, type_): + if not name: + return None + key = f"{name.upper()}_{type_}" + if key in locations_cache: + return locations_cache[key] + + existing = Location.search([ + ('name', '=', name.upper()), + ('type', '=', type_) + ], limit=1) + + if existing: + locations_cache[key] = existing[0] + return existing[0] + + new_loc = Location() + new_loc.name = name.upper() + new_loc.type = type_ + locations_cache[key] = new_loc + locations_to_save.append(new_loc) + return new_loc - # ----- Fonctions pour créer ou récupérer les objets ----- - def get_or_create_party(name): - name_upper = name.upper() - if name_upper in parties_cache: - return parties_cache[name_upper] - existing = Party.search([('name', '=', name_upper)], limit=1) - if existing: - parties_cache[name_upper] = existing[0] - return existing[0] - if name: - new_p = Party() - new_p.name = name_upper - parties_cache[name_upper] = new_p - parties_to_save.append(new_p) - return new_p + # Collecter les objets à créer + _ = get_or_create_party(carrier_name) + _ = get_or_create_party(agent_name) + _ = get_or_create_vessel(vessel_name) + _ = get_or_create_location(loading_name, 'supplier') + _ = get_or_create_location(destination_name, 'customer') - def get_or_create_vessel(name, imo=None): - name_upper = name.upper() - if name_upper in vessels_cache: - return vessels_cache[name_upper] - existing = Vessel.search([('vessel_name', '=', name_upper)], limit=1) - if existing: - vessels_cache[name_upper] = existing[0] - return existing[0] - if name: - new_v = Vessel() - new_v.vessel_name = name_upper - new_v.vessel_imo = imo - vessels_cache[name_upper] = new_v - vessels_to_save.append(new_v) - return new_v + # Sauvegarder tous les objets de référence + if parties_to_save: + Party.save(parties_to_save) + if vessels_to_save: + Vessel.save(vessels_to_save) + if locations_to_save: + Location.save(locations_to_save) + + trans1.commit() + logger.info("Première transaction commitée : objets de référence créés") + + except Exception as e: + trans1.rollback() + logger.error(f"Erreur dans la première transaction : {e}") + raise - def get_or_create_location(name, type_): - key = f"{name.upper()}_{type_}" - if key in locations_cache: - return locations_cache[key] - existing = Location.search([('name', '=', name.upper()), ('type', '=', type_)], limit=1) - if existing: - locations_cache[key] = existing[0] - return existing[0] - if name: - new_loc = Location() - new_loc.name = name.upper() - new_loc.type = type_ - locations_cache[key] = new_loc - locations_to_save.append(new_loc) - return new_loc + # ---- DEUXIÈME TRANSACTION : Création des shipments ---- + with Transaction().new_transaction() as trans2: + try: + # Recréer les curseurs après la nouvelle transaction + cursor2 = Transaction().connection.cursor() + cursor2.execute(*t.select( + t.ShippingInstructionNumber, + t.ShippingInstructionDate, + t.ShippingInstructionQuantity, + t.ShippingInstructionQuantityUnit, + t.NumberOfContainers, + t.ContainerType, + t.Loading, + t.Destination, + t.BookingAgent, + t.Carrier, + t.Vessel, + t.BL_Number, + t.ETD_Date, + t.BL_Date, + t.ExpectedController, + t.Comments, + t.FintradeBookingKey, + )) - # ----- Récupération ou création des objets ----- - carrier = get_or_create_party(carrier_name) - agent = get_or_create_party(agent_name) - vessel = get_or_create_vessel(vessel_name) - loc_from = get_or_create_location(loading_name, 'supplier') - loc_to = get_or_create_location(destination_name, 'customer') + rows2 = cursor2.fetchall() + shipments_to_save = [] + + for row in rows2: + ( + si_number, si_date, si_quantity, si_unit, + container_number, container_type, + loading_name, destination_name, + agent_name, carrier_name, + vessel_name, bl_number, + etd_date, bl_date, controller, + comments, fintrade_booking_key + ) = row - # Stocker les données pour la deuxième étape - shipments_data.append({ - 'si_number': si_number, - 'bl_number': bl_number, - 'bl_date': bl_date, - 'etd_date': etd_date, - 'carrier': carrier, - 'agent': agent, - 'vessel': vessel, - 'from_location': loc_from, - 'to_location': loc_to, - }) + # Vérifier si le shipment existe déjà + existing_shipment = ShipmentIn.search([ + ('reference', '=', si_number) + ], limit=1) + + if existing_shipment: + logger.info(f"Shipment existe déjà : {si_number}") + continue - # ----- Étape 1 : sauvegarde des objets de référence ----- - if parties_to_save: - Party.save(parties_to_save) - if vessels_to_save: - Vessel.save(vessels_to_save) - if locations_to_save: - Location.save(locations_to_save) + # Récupérer les objets (maintenant ils existent dans la base) + carrier = Party.search([('name', '=', carrier_name.upper())], limit=1) if carrier_name else None + agent = Party.search([('name', '=', agent_name.upper())], limit=1) if agent_name else None + vessel = Vessel.search([('vessel_name', '=', vessel_name.upper())], limit=1) if vessel_name else None + loc_from = Location.search([ + ('name', '=', loading_name.upper()), + ('type', '=', 'supplier') + ], limit=1) if loading_name else None + loc_to = Location.search([ + ('name', '=', destination_name.upper()), + ('type', '=', 'customer') + ], limit=1) if destination_name else None - # Commit pour garantir que tous les IDs sont corrects - Transaction().commit() + # Créer le shipment + shipment = ShipmentIn() + shipment.reference = si_number + shipment.from_location = loc_from[0] if loc_from else None + shipment.to_location = loc_to[0] if loc_to else None + shipment.carrier = carrier[0] if carrier else None + shipment.supplier = agent[0] if agent else None + shipment.vessel = vessel[0] if vessel else None + shipment.cargo_mode = 'bulk' + shipment.bl_number = bl_number + shipment.bl_date = bl_date + shipment.etd = etd_date + + shipments_to_save.append(shipment) + logger.info(f"Shipment préparé : {si_number}") - # ----- Étape 2 : création des shipments ----- - for data in shipments_data: - si_number = data['si_number'] - shipment = ShipmentIn.search([('reference', '=', si_number)], limit=1) - if shipment: - sh = shipment[0] - else: - sh = ShipmentIn() - sh.reference = si_number - sh.from_location = data['from_location'] - sh.to_location = data['to_location'] - sh.carrier = data['carrier'] - sh.supplier = data['agent'] - sh.vessel = data['vessel'] - sh.cargo_mode = 'bulk' - sh.bl_number = data['bl_number'] - sh.bl_date = data['bl_date'] - sh.etd = data['etd_date'] - ShipmentIn.save([sh]) - logger.info("SHIPMENT_CREATED: %s", sh) + # Sauvegarder tous les shipments + if shipments_to_save: + ShipmentIn.save(shipments_to_save) + logger.info(f"{len(shipments_to_save)} shipments créés") + + trans2.commit() + + except Exception as e: + trans2.rollback() + logger.error(f"Erreur dans la deuxième transaction : {e}") + raise \ No newline at end of file