From bfb9bb3188b3a54330168e1c644fdeca974537c4 Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Mon, 6 Apr 2026 11:02:13 +0200 Subject: [PATCH] Add WR draft management --- modules/automation/automation.py | 29 +---- modules/purchase_trade/docs/business-rules.md | 25 ++++ modules/purchase_trade/tests/test_module.py | 42 +++++++ .../view/weight_report_form.xml | 9 +- .../view/weight_report_list.xml | 3 +- modules/purchase_trade/weight_report.py | 119 +++++++++++++++++- modules/purchase_trade/weight_report.xml | 14 +-- 7 files changed, 200 insertions(+), 41 deletions(-) diff --git a/modules/automation/automation.py b/modules/automation/automation.py index 4e98aee..f3ea1a3 100644 --- a/modules/automation/automation.py +++ b/modules/automation/automation.py @@ -248,29 +248,10 @@ 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) - if sh[0].incoming_moves: - factor_net = wr.net_landed_kg / wr.bales if wr.bales else 1 - factor_gross = wr.gross_landed_kg / wr.bales if wr.bales else 1 - for move in sh[0].incoming_moves: - lot = move.lot - if lot.lot_type == 'physic': - wr_payload = { - "chunk_key": lot.lot_chunk_key, - "gross_weight": float(round(Decimal(lot.lot_qt) * factor_gross,5)), - "net_weight": float(round(Decimal(lot.lot_qt) * factor_net,5)), - "tare_total": float(round(wr.tare_kg * (Decimal(lot.lot_qt) / wr.bales),5)) , - "bags": int(lot.lot_qt), - "surveyor_code": sh[0].controller.get_alf(), - "place_key": sh[0].to_location.get_places(), - "report_date": int(wr.report_date.strftime("%Y%m%d")),#wr.report_date.isoformat() if wr.report_date else None, - "weight_date": int(wr.weight_date.strftime("%Y%m%d")),#wr.weight_date.isoformat() if wr.weight_date else None, - "agent": sh[0].agent.get_alf(), - "forwarder_ref": sh[0].returned_id - } - 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" + doc.notes = ( + (doc.notes or "") + + "Global WR linked to shipment. " + + "Create remote lot WRs from the weight report form.\n") # if cls.rule_set.ocr_required:[] # cls.run_ocr([doc]) @@ -293,4 +274,4 @@ class AutomationDocument(ModelSQL, ModelView, Workflow): # except Exception as e: # doc.state = "error" # doc.notes = (doc.notes or "") + f"Pipeline error: {e}\n" - doc.save() \ No newline at end of file + doc.save() diff --git a/modules/purchase_trade/docs/business-rules.md b/modules/purchase_trade/docs/business-rules.md index eb1c3fb..0c706e8 100644 --- a/modules/purchase_trade/docs/business-rules.md +++ b/modules/purchase_trade/docs/business-rules.md @@ -306,10 +306,35 @@ Owner technique: `a completer` - Resultat attendu: - pour une ligne `party.execution`, `achieved_percent` = `shipments de la zone avec ce controller / shipments controles de la zone` + - le denominateur ne compte que les `stock.shipment.in` qui ont deja un + `controller`; les shipments encore non affectes ne biaisent donc pas la + statistique affichee - lors d'un choix automatique de controller, la priorite va a la regle dont l'ecart `targeted - achieved` est le plus eleve - un controller a `80%` cible et `40%` reel doit donc passer avant un controller a `50%` cible et `45%` reel sur la meme zone + - l'appartenance a la zone se lit depuis `shipment.to_location.country`, et + une region parente couvre aussi ses sous-regions +- Priorite: + - `importante` + +### BR-PT-015 - Les weight reports distants par lot partent du weight report global attache au shipment + +- Intent: separer la creation du `weight.report` global et l'export detaille + par lot vers le systeme distant. +- Description: + - l'automation cree le `weight.report` global et l'attache au + `stock.shipment.in` + - l'export FastAPI par lot ne part plus directement de l'automation + - l'utilisateur ouvre le `weight.report` voulu depuis le shipment et lance + l'action d'export depuis ce rapport +- Resultat attendu: + - le rapport choisi sert de base unique pour calculer les payloads par lot + - seuls les lots physiques des `incoming_moves` du shipment sont exportes + - l'action exige au minimum un `controller` et un `returned_id` sur le + shipment + - les cles renvoyees par le systeme distant et la date d'envoi sont + conservees sur le `weight.report` local - Priorite: - `importante` - Resultat attendu: diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py index ae8e15c..a7ea2fe 100644 --- a/modules/purchase_trade/tests/test_module.py +++ b/modules/purchase_trade/tests/test_module.py @@ -259,6 +259,48 @@ class PurchaseTradeTestCase(ModuleTestCase): self.assertIs(shipment.get_controller(), party_a) + def test_weight_report_get_source_shipment_rejects_multiple_shipments(self): + 'weight report export must not guess when the same WR is linked twice' + WeightReport = Pool().get('weight.report') + report = WeightReport() + report.id = 7 + + shipment_wr_model = Mock() + shipment_wr_model.search.return_value = [ + Mock(shipment_in=Mock(id=1)), + Mock(shipment_in=Mock(id=2)), + ] + + with patch( + 'trytond.modules.purchase_trade.weight_report.Pool' + ) as PoolMock: + PoolMock.return_value.get.return_value = shipment_wr_model + with self.assertRaises(UserError): + report.get_source_shipment() + + def test_weight_report_remote_context_requires_controller_and_returned_id(self): + 'weight report export checks the shipment prerequisites before calling FastAPI' + WeightReport = Pool().get('weight.report') + report = WeightReport() + report.bales = 100 + report.report_date = Mock(strftime=Mock(return_value='20260406')) + report.weight_date = Mock(strftime=Mock(return_value='20260406')) + + shipment = Mock( + controller=None, + returned_id='RET-001', + agent=Mock(), + to_location=Mock(), + ) + + with self.assertRaises(UserError): + report.validate_remote_weight_report_context(shipment) + + shipment.controller = Mock() + shipment.returned_id = None + with self.assertRaises(UserError): + report.validate_remote_weight_report_context(shipment) + def test_sale_report_multi_line_helpers_aggregate_all_lines(self): 'sale report helpers aggregate quantity, price lines and shipment periods' Sale = Pool().get('sale.sale') diff --git a/modules/purchase_trade/view/weight_report_form.xml b/modules/purchase_trade/view/weight_report_form.xml index 84773fb..3206dcf 100644 --- a/modules/purchase_trade/view/weight_report_form.xml +++ b/modules/purchase_trade/view/weight_report_form.xml @@ -79,9 +79,16 @@