From 7d89418874fad465059d37aa2e8d32e08f6b759f Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Mon, 2 Feb 2026 10:42:08 +0100 Subject: [PATCH] 02.02.26 --- modules/automation/automation.py | 204 ++---------------- modules/automation/cron.py | 3 +- modules/document_incoming/document.py | 2 +- modules/document_incoming_wr/document.py | 3 + modules/purchase_trade/party.py | 7 + modules/purchase_trade/stock.py | 178 +++++++++++++++ .../purchase_trade/view/party_exec_tree.xml | 1 + 7 files changed, 213 insertions(+), 185 deletions(-) diff --git a/modules/automation/automation.py b/modules/automation/automation.py index 8958b7a..9c1618b 100644 --- a/modules/automation/automation.py +++ b/modules/automation/automation.py @@ -220,189 +220,27 @@ class AutomationDocument(ModelSQL, ModelView, Workflow): ShipmentWR.save([swr]) doc.notes = (doc.notes or "") + f"Shipment found: {sh[0].number}\n" logger.info("BL_NUMBER:%s",sh[0].bl_number) - t = Table('freight_booking_lots') - cursor = Transaction().connection.cursor() - query = t.select( - t.BOOKING_NUMBER, - t.LOT_NUMBER, - t.LOT_NBR_BALES, - t.LOT_GROSS_WEIGHT, - t.LOT_NET_WEIGHT, - t.LOT_UOM, - t.LOT_QUALITY, - t.CUSTOMER, - t.SELL_PRICE_CURRENCY, - t.SELL_PRICE_UNIT, - t.SELL_PRICE, - t.SALE_INVOICE, - t.SELL_INV_AMOUNT, - t.SALE_INVOICE_DATE, - t.SELL_PREMIUM, - t.SALE_CONTRACT_NUMBER, - t.SALE_DECLARATION_KEY, - t.SHIPMENT_CHUNK_KEY, - where=(t.BOOKING_NUMBER == int(sh[0].reference)) - ) - cursor.execute(*query) - rows = cursor.fetchall() - logger.info("ROWS:%s",rows) - if rows: - sale_line = None - for row in rows: - logger.info("ROW:%s",row) - #Purchase & Sale creation - LotQt = Pool().get('lot.qt') - Lot = Pool().get('lot.lot') - LotAdd = Pool().get('lot.add.line') - Currency = Pool().get('currency.currency') - Product = Pool().get('product.product') - Party = Pool().get('party.party') - Uom = Pool().get('product.uom') - Sale = Pool().get('sale.sale') - SaleLine = Pool().get('sale.line') - dec_key = str(row[16]).strip() - chunk_key = str(row[17]).strip() - doc.notes = (doc.notes or "") + f"Lots found: {chunk_key}\n" - lot_unit = str(row[5]).strip().lower() - product = str(row[6]).strip().upper() - lot_net_weight = Decimal(row[4]) - logger.info("LOT_NET_WEIGHT:%s",lot_net_weight) - lot_gross_weight = Decimal(row[3]) - lot_bales = Decimal(row[2]) - lot_number = row[1] - customer = str(row[7]).strip().upper() - sell_price_currency = str(row[8]).strip().upper() - sell_price_unit = str(row[9]).strip().lower() - sell_price = Decimal(row[10]) - premium = Decimal(row[14]) - reference = Decimal(row[15]) - logger.info("DECLARATION_KEY:%s",dec_key) - declaration = SaleLine.search(['note','=',dec_key]) - if declaration: - sale_line = declaration[0] - logger.info("WITH_DEC:%s",sale_line) - vlot = sale_line.lots[0] - lqt = LotQt.search([('lot_s','=',vlot.id)]) - if lqt: - for lq in lqt: - if lq.lot_p: - logger.info("VLOT_P:%s",lq.lot_p) - sale_line.quantity_theorical += round(lot_net_weight,2) - SaleLine.save([sale_line]) - lq.lot_p.updateVirtualPart(round(lot_net_weight,2),sh[0],lq.lot_s) - vlot.set_current_quantity(round(lot_net_weight,2),round(lot_gross_weight,2),1) - Lot.save([vlot]) - else: - sale = Sale() - sale_line = SaleLine() - sale.party = Party.getPartyByName(customer,'CLIENT') - logger.info("SALE_PARTY:%s",sale.party) - sale.reference = reference - sale.company = 6 - if sale.party.addresses: - sale.invoice_address = sale.party.addresses[0] - sale.shipment_address = sale.party.addresses[0] - - if sell_price_currency == 'USC': - sale.currency = Currency.get_by_name('USD') - sale_line.enable_linked_currency = True - sale_line.linked_currency = 1 - sale_line.linked_unit = Uom.get_by_name(sell_price_unit) - sale_line.linked_price = round(sell_price,4) - sale_line.unit_price = sale_line.get_price_linked_currency() - else: - sale.currency = Currency.get_by_name(sell_price_currency) - sale_line.unit_price = round(sell_price,4) - sale_line.unit = Uom.get_by_name(sell_price_unit) - sale_line.premium = premium - Sale.save([sale]) - sale_line.sale = sale.id - sale_line.quantity = round(lot_net_weight,2) - sale_line.quantity_theorical = round(lot_net_weight,2) - sale_line.product = Product.get_by_name('BRAZIL COTTON') - logger.info("PRODUCT:%s",sale_line.product) - sale_line.unit = Uom.get_by_name(lot_unit) - sale_line.price_type = 'priced' - sale_line.created_by_code = False - sale_line.note = dec_key - SaleLine.save([sale_line]) - - #need to link the virtual part to the shipment - lqt = LotQt.search([('lot_s','=',sale_line.lots[0])]) - if lqt: - lqt[0].lot_shipment_in = sh[0] - LotQt.save(lqt) - logger.info("SALE_LINKED_TO_SHIPMENT:%s",sh[0]) - - ContractStart = Pool().get('contracts.start') - ContractDetail = Pool().get('contract.detail') - ct = ContractStart() - d = ContractDetail() - ct.type = 'Purchase' - ct.matched = True - ct.shipment_in = sh[0] - ct.lot = sale_line.lots[0] - ct.product = sale_line.product - ct.unit = sale_line.unit - d.party = Party.getPartyByName('FAIRCOT') - if sale_line.enable_linked_currency: - d.currency_unit = str(sale_line.linked_currency.id) + '_' + str(sale_line.linked_unit.id) - else: - d.currency_unit = str(sale.currency.id) + '_' + str(sale_line.unit.id) - d.quantity = sale_line.quantity - d.unit = sale_line.unit - d.price = sale_line.unit_price - d.price_type = 'priced' - d.crop = None - d.tol_min = 0 - d.tol_max = 0 - d.incoterm = None - d.reference = str(sale.id) - d.del_period = None - d.from_del = None - d.to_del = None - ct.contracts = [d] - ContractFactory.create_contracts( - ct.contracts, - type_=ct.type, - ct=ct, - ) - - #Lots creation - vlot = sale_line.lots[0] - lqt = LotQt.search([('lot_s','=',vlot.id),('lot_p','>',0)]) - if lqt and vlot.lot_quantity > 0: - lqt = lqt[0] - l = LotAdd() - l.lot_qt = lot_bales - l.lot_unit = Uom.get_by_name('bale') - l.lot_unit_line = Uom.get_by_name(lot_unit) - l.lot_quantity = round(lot_net_weight,2) - l.lot_gross_quantity = round(lot_gross_weight,2) - l.lot_premium = premium - l.lot_chunk_key = int(chunk_key) - logger.info("ADD_LOT:%s",int(chunk_key)) - LotQt.add_physical_lots(lqt,[l]) - if sale_line: - logger.info("CREATE_FINTRADE_WR_FOR_SL:%s",sale_line) - weight_total = sum([l.lot_quantity for l in sale_line.lots if l.lot_type == 'physic']) - factor = weight_total / wr.net_landed_kg if wr.net_landed_kg else 1 - for lot in sale_line.lots: - if lot.lot_type == 'physic': - wr_payload = { - "chunk_key": lot.lot_chunk_key, - "gross_weight": float(round(lot.lot_gross_quantity / factor,5)), - "net_weight": float(round(lot.lot_quantity / factor,5)), - "tare_total": float(round(wr.tare_kg * (lot.lot_quantity / weight_total),5)) , - "bags": int(wr.bales * (lot.lot_quantity / weight_total)), - "surveyor_code": 231, - "place_key": 0, - "report_date": 20260127 - } - logger.info("PAYLOAD:%s",wr_payload) - data = doc.create_weight_report(wr_payload) - doc.notes = (doc.notes or "") + f"WR created in Fintrade: {data.get('success')}\n" - doc.notes = (doc.notes or "") + f"WR key: {data.get('weight_report_key')}\n" + sale_line = sh[0]._create_lots_from_fintrade() + if sale_line: + logger.info("CREATE_FINTRADE_WR_FOR_SL:%s",sale_line) + weight_total = sum([l.lot_quantity for l in sale_line.lots if l.lot_type == 'physic']) + factor = weight_total / wr.net_landed_kg if wr.net_landed_kg else 1 + for lot in sale_line.lots: + if lot.lot_type == 'physic': + wr_payload = { + "chunk_key": lot.lot_chunk_key, + "gross_weight": float(round(lot.lot_gross_quantity / factor,5)), + "net_weight": float(round(lot.lot_quantity / factor,5)), + "tare_total": float(round(wr.tare_kg * (lot.lot_quantity / weight_total),5)) , + "bags": int(wr.bales * (lot.lot_quantity / weight_total)), + "surveyor_code": 231, + "place_key": 0, + "report_date": 20260127 + } + logger.info("PAYLOAD:%s",wr_payload) + data = doc.create_weight_report(wr_payload) + doc.notes = (doc.notes or "") + f"WR created in Fintrade: {data.get('success')}\n" + doc.notes = (doc.notes or "") + f"WR key: {data.get('weight_report_key')}\n" # if cls.rule_set.ocr_required:[] # cls.run_ocr([doc]) diff --git a/modules/automation/cron.py b/modules/automation/cron.py index 68989e2..83eee17 100644 --- a/modules/automation/cron.py +++ b/modules/automation/cron.py @@ -308,7 +308,8 @@ class AutomationCron(ModelSQL, ModelView): # Sauvegarder ce shipment uniquement ShipmentIn.save([shipment]) - + shipment._create_lots_from_fintrade() + shipment.get_controller() trans_shipment.commit() successful_shipments += 1 logger.info(f"✓ Shipment {si_number} créé avec succès") diff --git a/modules/document_incoming/document.py b/modules/document_incoming/document.py index f2a7dbc..a1a819f 100755 --- a/modules/document_incoming/document.py +++ b/modules/document_incoming/document.py @@ -215,7 +215,7 @@ class Incoming(DeactivableMixin, Workflow, ModelSQL, ModelView): children.append(child) else: child = cls( - name='mail.txt', + name='mail_' + message.get('subject', 'No Subject') + '.txt', company=rule.document_incoming_company, data=body_bytes, type=rule.document_incoming_type, diff --git a/modules/document_incoming_wr/document.py b/modules/document_incoming_wr/document.py index 513bf75..d466eec 100644 --- a/modules/document_incoming_wr/document.py +++ b/modules/document_incoming_wr/document.py @@ -49,6 +49,9 @@ class Incoming(metaclass=PoolMeta): wr.type = 'controller' wr.state = 'draft' WR.save([wr]) + WR.run_ocr([wr]) + WR.run_metadata([wr]) + return wr # @property diff --git a/modules/purchase_trade/party.py b/modules/purchase_trade/party.py index d612244..8a6b6a1 100755 --- a/modules/purchase_trade/party.py +++ b/modules/purchase_trade/party.py @@ -11,6 +11,10 @@ class PartyExecution(ModelSQL,ModelView): party = fields.Many2One('party.party',"Party") area = fields.Many2One('country.region',"Area") percent = fields.Numeric("% targeted") + achieved_percent = fields.Function(fields.Numeric("% achieved"),'get_percent') + + def get_percent(self,name): + return 2 class Party(metaclass=PoolMeta): __name__ = 'party.party' @@ -21,6 +25,9 @@ class Party(metaclass=PoolMeta): association = fields.Many2One('purchase.association',"Association") execution = fields.One2Many('party.execution','party',"") + def IsAvailableForControl(self,sh): + return True + @classmethod def getPartyByName(cls, party, category=None): party = party.upper() diff --git a/modules/purchase_trade/stock.py b/modules/purchase_trade/stock.py index 68d1d59..c6b9f8e 100755 --- a/modules/purchase_trade/stock.py +++ b/modules/purchase_trade/stock.py @@ -16,6 +16,7 @@ from itertools import chain, groupby from operator import itemgetter import datetime from collections import defaultdict +from sql import Table import logging logger = logging.getLogger(__name__) @@ -444,6 +445,183 @@ class ShipmentIn(metaclass=PoolMeta): else: return str(self.id) + def get_controller(self): + ControllerCategory = Pool().get('party.category') + PartyCategory = Pool().get('party.party-party.category') + cc = ControllerCategory.search(['name','=','CONTROLLER']) + if cc: + cc = cc[0] + controllers = PartyCategory.search(['category','=',cc.id]) + for c in controllers: + if c.party.IsAvailableForControl(self): + return c.party + + def _create_lots_from_fintrade(self): + t = Table('freight_booking_lots') + cursor = Transaction().connection.cursor() + query = t.select( + t.BOOKING_NUMBER, + t.LOT_NUMBER, + t.LOT_NBR_BALES, + t.LOT_GROSS_WEIGHT, + t.LOT_NET_WEIGHT, + t.LOT_UOM, + t.LOT_QUALITY, + t.CUSTOMER, + t.SELL_PRICE_CURRENCY, + t.SELL_PRICE_UNIT, + t.SELL_PRICE, + t.SALE_INVOICE, + t.SELL_INV_AMOUNT, + t.SALE_INVOICE_DATE, + t.SELL_PREMIUM, + t.SALE_CONTRACT_NUMBER, + t.SALE_DECLARATION_KEY, + t.SHIPMENT_CHUNK_KEY, + where=(t.BOOKING_NUMBER == int(self.reference)) + ) + cursor.execute(*query) + rows = cursor.fetchall() + logger.info("ROWS:%s",rows) + if rows: + sale_line = None + for row in rows: + logger.info("ROW:%s",row) + #Purchase & Sale creation + LotQt = Pool().get('lot.qt') + Lot = Pool().get('lot.lot') + LotAdd = Pool().get('lot.add.line') + Currency = Pool().get('currency.currency') + Product = Pool().get('product.product') + Party = Pool().get('party.party') + Uom = Pool().get('product.uom') + Sale = Pool().get('sale.sale') + SaleLine = Pool().get('sale.line') + dec_key = str(row[16]).strip() + chunk_key = str(row[17]).strip() + lot_unit = str(row[5]).strip().lower() + product = str(row[6]).strip().upper() + lot_net_weight = Decimal(row[4]) + logger.info("LOT_NET_WEIGHT:%s",lot_net_weight) + lot_gross_weight = Decimal(row[3]) + lot_bales = Decimal(row[2]) + lot_number = row[1] + customer = str(row[7]).strip().upper() + sell_price_currency = str(row[8]).strip().upper() + sell_price_unit = str(row[9]).strip().lower() + sell_price = Decimal(row[10]) + premium = Decimal(row[14]) + reference = Decimal(row[15]) + logger.info("DECLARATION_KEY:%s",dec_key) + declaration = SaleLine.search(['note','=',dec_key]) + if declaration: + sale_line = declaration[0] + logger.info("WITH_DEC:%s",sale_line) + vlot = sale_line.lots[0] + lqt = LotQt.search([('lot_s','=',vlot.id)]) + if lqt: + for lq in lqt: + if lq.lot_p: + logger.info("VLOT_P:%s",lq.lot_p) + sale_line.quantity_theorical += round(lot_net_weight,2) + SaleLine.save([sale_line]) + lq.lot_p.updateVirtualPart(round(lot_net_weight,2),self,lq.lot_s) + vlot.set_current_quantity(round(lot_net_weight,2),round(lot_gross_weight,2),1) + Lot.save([vlot]) + else: + sale = Sale() + sale_line = SaleLine() + sale.party = Party.getPartyByName(customer,'CLIENT') + logger.info("SALE_PARTY:%s",sale.party) + sale.reference = reference + sale.company = 6 + if sale.party.addresses: + sale.invoice_address = sale.party.addresses[0] + sale.shipment_address = sale.party.addresses[0] + + if sell_price_currency == 'USC': + sale.currency = Currency.get_by_name('USD') + sale_line.enable_linked_currency = True + sale_line.linked_currency = 1 + sale_line.linked_unit = Uom.get_by_name(sell_price_unit) + sale_line.linked_price = round(sell_price,4) + sale_line.unit_price = sale_line.get_price_linked_currency() + else: + sale.currency = Currency.get_by_name(sell_price_currency) + sale_line.unit_price = round(sell_price,4) + sale_line.unit = Uom.get_by_name(sell_price_unit) + sale_line.premium = premium + Sale.save([sale]) + sale_line.sale = sale.id + sale_line.quantity = round(lot_net_weight,2) + sale_line.quantity_theorical = round(lot_net_weight,2) + sale_line.product = Product.get_by_name('BRAZIL COTTON') + logger.info("PRODUCT:%s",sale_line.product) + sale_line.unit = Uom.get_by_name(lot_unit) + sale_line.price_type = 'priced' + sale_line.created_by_code = False + sale_line.note = dec_key + SaleLine.save([sale_line]) + + #need to link the virtual part to the shipment + lqt = LotQt.search([('lot_s','=',sale_line.lots[0])]) + if lqt: + lqt[0].lot_shipment_in = self + LotQt.save(lqt) + logger.info("SALE_LINKED_TO_SHIPMENT:%s",self) + + ContractStart = Pool().get('contracts.start') + ContractDetail = Pool().get('contract.detail') + ct = ContractStart() + d = ContractDetail() + ct.type = 'Purchase' + ct.matched = True + ct.shipment_in = self + ct.lot = sale_line.lots[0] + ct.product = sale_line.product + ct.unit = sale_line.unit + d.party = Party.getPartyByName('FAIRCOT') + if sale_line.enable_linked_currency: + d.currency_unit = str(sale_line.linked_currency.id) + '_' + str(sale_line.linked_unit.id) + else: + d.currency_unit = str(sale.currency.id) + '_' + str(sale_line.unit.id) + d.quantity = sale_line.quantity + d.unit = sale_line.unit + d.price = sale_line.unit_price + d.price_type = 'priced' + d.crop = None + d.tol_min = 0 + d.tol_max = 0 + d.incoterm = None + d.reference = str(sale.id) + d.del_period = None + d.from_del = None + d.to_del = None + ct.contracts = [d] + ContractFactory.create_contracts( + ct.contracts, + type_=ct.type, + ct=ct, + ) + + #Lots creation + vlot = sale_line.lots[0] + lqt = LotQt.search([('lot_s','=',vlot.id),('lot_p','>',0)]) + if lqt and vlot.lot_quantity > 0: + lqt = lqt[0] + l = LotAdd() + l.lot_qt = lot_bales + l.lot_unit = Uom.get_by_name('bale') + l.lot_unit_line = Uom.get_by_name(lot_unit) + l.lot_quantity = round(lot_net_weight,2) + l.lot_gross_quantity = round(lot_gross_weight,2) + l.lot_premium = premium + l.lot_chunk_key = int(chunk_key) + logger.info("ADD_LOT:%s",int(chunk_key)) + LotQt.add_physical_lots(lqt,[l]) + + return sale_line + @classmethod @ModelView.button def compute(cls, shipments): diff --git a/modules/purchase_trade/view/party_exec_tree.xml b/modules/purchase_trade/view/party_exec_tree.xml index 96981a3..86531ff 100644 --- a/modules/purchase_trade/view/party_exec_tree.xml +++ b/modules/purchase_trade/view/party_exec_tree.xml @@ -1,4 +1,5 @@ + \ No newline at end of file