From 36dc48bee036a1421e580b863ecbe3568530f59b Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Sat, 21 Mar 2026 19:10:08 +0100 Subject: [PATCH] 21.03.26 --- modules/purchase_trade/purchase.py | 144 ++++++++++++++++++++- modules/purchase_trade/view/assay_form.xml | 4 +- modules/purchase_trade/view/assay_tree.xml | 2 +- 3 files changed, 145 insertions(+), 5 deletions(-) diff --git a/modules/purchase_trade/purchase.py b/modules/purchase_trade/purchase.py index be305ba..2d09ed0 100755 --- a/modules/purchase_trade/purchase.py +++ b/modules/purchase_trade/purchase.py @@ -529,6 +529,138 @@ class PriceComposition(ModelSQL,ModelView): component = fields.Char("Component") price = fields.Numeric("Price") +class AssayImporter: + + def __init__(self): + pool = Pool() + self.AssayLine = pool.get('assay.line') + self.Element = pool.get('assay.element') + self.Uom = pool.get('product.uom') + + # ----------------------------- + # PUBLIC ENTRYPOINT + # ----------------------------- + def import_from_json(self, data: dict, assay): + self._update_assay(data,assay) + lines = self._create_lines(data, assay) + + self.AssayLine.save(lines) + return assay + + # ----------------------------- + # HEADER + # ----------------------------- + def _update_assay(self, data): + Party = Pool().get('party.party') + metadata = data.get('document_metadata', {}) + + assay = self.Assay() + + assay.reference = metadata.get('report_reference') + assay.date = self._parse_date(metadata.get('issue_date')) + assay.type = self._map_type(metadata.get('status')) + assay.status = 'draft' + assay.lab = Party.getPartyByName(metadata.get('lab_name')) + + assay.save() + return assay + + # ----------------------------- + # LINES + # ----------------------------- + def _create_lines(self, data, assay): + lines = [] + + # assays + for item in data.get('assays', []): + lines.append(self._build_line(item, assay, category='assay')) + + # penalties + for item in data.get('penalties', []): + lines.append(self._build_line(item, assay, category='penalty')) + + # moisture + moisture = data.get('weights_and_moisture', {}).get('moisture') + if moisture and moisture.get('value') is not None: + lines.append(self._build_line({ + "element": "H2O", + "value": moisture.get('value'), + "unit": moisture.get('unit') + }, assay, category='moisture')) + + return lines + + # ----------------------------- + # LINE BUILDER + # ----------------------------- + def _build_line(self, item, assay, category): + line = self.AssayLine() + + line.assay = assay + line.element = self._get_or_create_element(item.get('element')) + line.value = self._safe_float(item.get('value')) + line.unit = self._get_uom(item.get('unit')) + line.category = category + + line.method = item.get('method') + line.is_payable = item.get('is_payable', False) + + return line + + # ----------------------------- + # HELPERS + # ----------------------------- + def _get_or_create_element(self, code): + if not code: + return None + + elements = self.Element.search([('name', '=', code)]) + if elements: + return elements[0] + + # auto-create (optionnel mais pratique) + element = self.Element() + element.name = code + element.save() + return element + + def _get_uom(self, unit_name): + if not unit_name: + return None + + uoms = self.Uom.search([('symbol', '=', unit_name)]) + if uoms: + return uoms[0] + + return None # ou lever une erreur selon ton besoin + + def _parse_date(self, date_str): + if not date_str: + return None + try: + return datetime.datetime.strptime(date_str, "%Y-%m-%d").date() + except Exception: + return None + + def _safe_float(self, value): + try: + return float(value) + except Exception: + return None + + def _map_type(self, status): + if not status: + return 'provisional' + + status = status.lower() + + if 'final' in status: + return 'final' + if 'umpire' in status: + return 'umpire' + + return 'provisional' + class Assay(ModelSQL, ModelView): "Assay" __name__ = 'assay.assay' @@ -549,7 +681,7 @@ class Assay(ModelSQL, ModelView): ('validated', 'Validated'), ], "Status") - laboratory = fields.Char("Laboratory") + lab = fields.Many2One('party.party',"Laboratory") lines = fields.One2Many( 'assay.line', 'assay', "Assay Lines" @@ -973,7 +1105,15 @@ class Line(metaclass=PoolMeta): f = Fee(line.fee_) f.purchase = line.purchase Fee.save([f]) - + + if line.assays: + for assay in line.assays: + if not assay.lines and assay.document: + data = json.load(f) + importer = AssayImporter() + importer.import_from_json(data,assay) + logger.info("Updated assay:%s", assay.id) + def check_from_to(self,tr): if tr.pricing_period: date_from,date_to, d, include, dates = tr.getDateWithEstTrigger(1) diff --git a/modules/purchase_trade/view/assay_form.xml b/modules/purchase_trade/view/assay_form.xml index f9f763f..0208528 100644 --- a/modules/purchase_trade/view/assay_form.xml +++ b/modules/purchase_trade/view/assay_form.xml @@ -7,8 +7,8 @@