This commit is contained in:
2026-01-20 15:25:15 +01:00
parent c5fbd3e528
commit c5053638df

View File

@@ -2,11 +2,12 @@ import requests
from decimal import getcontext, Decimal, ROUND_HALF_UP from decimal import getcontext, Decimal, ROUND_HALF_UP
from datetime import datetime from datetime import datetime
from trytond.model import fields from trytond.model import fields
from trytond.model import (ModelSQL, ModelView) from trytond.model import ModelSQL, ModelView
from trytond.pool import Pool, PoolMeta from trytond.pool import Pool, PoolMeta
from trytond.transaction import Transaction from trytond.transaction import Transaction
import logging import logging
from sql import Table from sql import Table
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class Cron(metaclass=PoolMeta): class Cron(metaclass=PoolMeta):
@@ -16,7 +17,8 @@ class Cron(metaclass=PoolMeta):
def __setup__(cls): def __setup__(cls):
super().__setup__() super().__setup__()
cls.method.selection.append( cls.method.selection.append(
('automation.cron|update_shipment', "Update Shipment from freight booking info")) ('automation.cron|update_shipment', "Update Shipment from freight booking info")
)
class AutomationCron(ModelSQL, ModelView): class AutomationCron(ModelSQL, ModelView):
"Automation Cron" "Automation Cron"
@@ -37,7 +39,6 @@ class AutomationCron(ModelSQL, ModelView):
@classmethod @classmethod
def update_shipment(cls): def update_shipment(cls):
# Objets Tryton
PoolObj = Pool() PoolObj = Pool()
ShipmentIn = PoolObj.get('stock.shipment.in') ShipmentIn = PoolObj.get('stock.shipment.in')
Party = PoolObj.get('party.party') Party = PoolObj.get('party.party')
@@ -47,7 +48,6 @@ class AutomationCron(ModelSQL, ModelView):
# Table externe # Table externe
t = Table('freight_booking_info') t = Table('freight_booking_info')
cursor = Transaction().connection.cursor() cursor = Transaction().connection.cursor()
cursor.execute(*t.select( cursor.execute(*t.select(
t.ShippingInstructionNumber, t.ShippingInstructionNumber,
t.ShippingInstructionDate, t.ShippingInstructionDate,
@@ -68,77 +68,125 @@ class AutomationCron(ModelSQL, ModelView):
t.FintradeBookingKey, t.FintradeBookingKey,
)) ))
for row in cursor.fetchall(): # On prépare deux listes pour la sauvegarde en batch
parties_to_save = []
vessels_to_save = []
locations_to_save = []
# Dictionnaires pour éviter de recréer plusieurs fois le même objet
parties_cache = {}
vessels_cache = {}
locations_cache = {}
rows = cursor.fetchall()
for row in rows:
( (
si_number, si_number, si_date, si_quantity, si_unit,
si_date, container_number, container_type,
si_quantity, loading_name, destination_name,
si_unit, agent_name, carrier_name,
container_number, vessel_name, bl_number,
container_type, etd_date, bl_date, controller,
loading_name, comments, fintrade_booking_key
destination_name,
agent_name,
carrier_name,
vessel_name,
bl_number,
etd_date,
bl_date,
controller,
comments,
fintrade_booking_key,
) = row ) = row
logger.info("ROW_FROM_CRON: %s", row) logger.info("ROW_FROM_CRON: %s", row)
# ----- Récupération / création des recordsets ----- # ----- Fonctions pour créer ou récupérer les objets en mémoire -----
def get_or_create_party(name): def get_or_create_party(name):
name = name.upper() name_upper = name.upper()
p = Party.search([('name', '=', name)], limit=1) if name_upper in parties_cache:
if p: return parties_cache[name_upper]
return p[0] existing = Party.search([('name', '=', name_upper)], limit=1)
if existing:
parties_cache[name_upper] = existing[0]
return existing[0]
new_p = Party() new_p = Party()
new_p.name = name new_p.name = name_upper
Party.save([new_p]) parties_cache[name_upper] = new_p
parties_to_save.append(new_p)
return new_p return new_p
def get_or_create_vessel(name, imo=None): def get_or_create_vessel(name, imo=None):
name = name.upper() name_upper = name.upper()
v = Vessel.search([('vessel_name', '=', name)], limit=1) if name_upper in vessels_cache:
if v: return vessels_cache[name_upper]
return v[0] 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()
new_v.vessel_name = name new_v.vessel_name = name_upper
new_v.vessel_imo = imo new_v.vessel_imo = imo
Vessel.save([new_v]) vessels_cache[name_upper] = new_v
vessels_to_save.append(new_v)
return new_v return new_v
def get_or_create_location(name, type_): def get_or_create_location(name, type_):
name = name.upper() key = f"{name.upper()}_{type_}"
loc = Location.search([('name', '=', name), ('type', '=', type_)], limit=1) if key in locations_cache:
if loc: return locations_cache[key]
return loc[0] 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 = Location()
new_loc.name = name new_loc.name = name.upper()
new_loc.type = type_ new_loc.type = type_
Location.save([new_loc]) locations_cache[key] = new_loc
locations_to_save.append(new_loc)
return new_loc return new_loc
# ----- Vérification si le Shipment existe ----- # ----- Récupération ou création des objets -----
shipment = ShipmentIn.search([('reference','=',si_number)], limit=1) 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')
# Stocke toutes les infos du shipment pour la deuxième étape
row_dict = {
'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
}
row._shipment_data = row_dict # on attache les infos au row temporairement
# ----- É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)
# Commit pour garantir que tous les IDs sont corrects
Transaction().commit()
# ----- Étape 2 : création des shipments -----
for row in rows:
data = row._shipment_data
si_number = data['si_number']
shipment = ShipmentIn.search([('reference', '=', si_number)], limit=1)
if shipment: if shipment:
sh = shipment[0] sh = shipment[0]
else: else:
sh = ShipmentIn() sh = ShipmentIn()
sh.reference = si_number sh.reference = si_number
sh.from_location = get_or_create_location(loading_name, 'supplier') sh.from_location = data['from_location']
sh.to_location = get_or_create_location(destination_name, 'customer') sh.to_location = data['to_location']
sh.carrier = get_or_create_party(carrier_name) sh.carrier = data['carrier']
sh.supplier = get_or_create_party(agent_name) sh.supplier = data['agent']
sh.vessel = get_or_create_vessel(vessel_name) sh.vessel = data['vessel']
sh.cargo_mode = 'bulk' sh.cargo_mode = 'bulk'
sh.bl_number = bl_number sh.bl_number = data['bl_number']
sh.bl_date = bl_date sh.bl_date = data['bl_date']
sh.etd = etd_date sh.etd = data['etd_date']
ShipmentIn.save([sh]) ShipmentIn.save([sh])
logger.info("SHIPMENT_CREATED: %s", sh) logger.info("SHIPMENT_CREATED: %s", sh)