|
|
|
|
@@ -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)
|
|
|
|
|
|