from trytond.model import ModelSQL, ModelView, fields from trytond.pool import Pool from decimal import Decimal, ROUND_HALF_UP from datetime import datetime as dt import logging logger = logging.getLogger(__name__) class WeightReport(ModelSQL, ModelView): 'Weight Report' __name__ = 'weight.report' _rec_name = 'reference' # Identification lab = fields.Char('Laboratory', required=True) # Report Information reference = fields.Char('Reference') file_no = fields.Char('File Number') report_date = fields.Date('Report Date') # Contract Information contract_no = fields.Char('Contract Number') invoice_no = fields.Char('Invoice Number') lc_no = fields.Char('LC Number') origin = fields.Char('Origin') commodity = fields.Char('Commodity') # Parties Information seller = fields.Many2One('party.party','Seller', required=True) buyer = fields.Many2One('party.party','Buyer', required=True) carrier = fields.Many2One('party.party','Carrier') # Shipment Information vessel = fields.Many2One('trade.vessel','Vessel') bl_no = fields.Char('B/L Number') bl_date = fields.Date('B/L Date') port_loading = fields.Many2One('stock.location','Port of Loading') port_destination = fields.Many2One('stock.location','Port of Destination') arrival_date = fields.Date('Arrival Date') weighing_place = fields.Char('Weighing Place') weighing_method = fields.Char('Weighing Method') weight_date = fields.Date('Weight Date') bales = fields.Integer('Number of Bales') # Weights Information gross_landed_kg = fields.Numeric('Gross Landed (kg)', digits=(16, 2)) tare_kg = fields.Numeric('Tare Weight (kg)', digits=(16, 2)) net_landed_kg = fields.Numeric('Net Landed (kg)', digits=(16, 2)) invoice_net_kg = fields.Numeric('Invoice Net (kg)', digits=(16, 2)) gain_loss_kg = fields.Numeric('Gain/Loss (kg)', digits=(16, 2)) gain_loss_percent = fields.Numeric('Gain/Loss (%)', digits=(16, 2)) @classmethod def __setup__(cls): super().__setup__() cls._order = [('report_date', 'DESC')] # cls._buttons.update({ # 'import_json': {}, # 'export_json': {}, # }) def get_rec_name(self, name): items = [self.lab] if self.reference: items.append('[%s]' % self.reference) return ' '.join(items) # @classmethod # @ModelView.button_action('weight_report.act_import_json') # def import_json(cls, reports): # pass # @classmethod # @ModelView.button_action('weight_report.act_export_json') # def export_json(cls, reports): # pass @classmethod def create_from_json(cls, json_data): """Crée un rapport à partir de données JSON""" pool = Pool() Party = pool.get('party.party') Vessel = pool.get('trade.vessel') Location = pool.get('stock.location') # Préparer les données report = {} # 1. Identification (champs simples) report['lab'] = json_data.get('lab', '') # 2. Report Information report_data = json_data.get('report', {}) report['reference'] = report_data.get('reference', '') report['file_no'] = report_data.get('file_no', '') # Conversion de la date (format: "28 October 2025") def parse_date(date_str): logger.info("TRY_TO_PARSE:%s",date_str) for fmt in ('%d %B %Y', '%d %b %Y'): try: return dt.strptime(date_str, fmt).date() except ValueError: pass return None report['report_date'] = parse_date(report_data.get('date', '')) # 3. Contract Information contract_data = json_data.get('contract', {}) report['contract_no'] = contract_data.get('contract_no', '') report['invoice_no'] = contract_data.get('invoice_no', '') report['lc_no'] = contract_data.get('lc_no', '') report['origin'] = contract_data.get('origin', '') report['commodity'] = contract_data.get('commodity', '') # 4. Parties Information (Many2One) parties_data = json_data.get('parties', {}) # Recherche ou création des parties seller_name = parties_data.get('seller', '') if seller_name: seller = Party.getPartyByName(seller_name) report['seller'] = seller.id if seller else None buyer_name = parties_data.get('buyer', '') if buyer_name: buyer = Party.getPartyByName(buyer_name) report['buyer'] = buyer.id if buyer else None carrier_name = parties_data.get('carrier', '') if carrier_name: carrier = Party.getPartyByName(carrier_name) report['carrier'] = carrier.id if carrier else None # 5. Shipment Information shipment_data = json_data.get('shipment', {}) # Recherche du navire par nom vessel_name = shipment_data.get('vessel', '') if vessel_name: vessel = Vessel.search([('vessel_name', '=', vessel_name)], limit=1) report['vessel'] = vessel[0].id if vessel else None report['bl_no'] = shipment_data.get('bl_no', '') # Conversion de la date B/L (format: "16-Aug-2025") bl_date_str = shipment_data.get('bl_date', '') if bl_date_str: try: report['bl_date'] = dt.strptime(bl_date_str, '%d-%b-%Y').date() except: report['bl_date'] = None # Ports (Many2One - nécessite recherche par nom) port_loading_name = shipment_data.get('port_loading', '') if port_loading_name: port_loading = Location.search([ ('name', '=', port_loading_name), ('type', '=', 'supplier') ], limit=1) report['port_loading'] = port_loading[0].id if port_loading else None port_destination_name = shipment_data.get('port_destination', '') if port_destination_name: port_destination = Location.search([ ('name', '=', port_destination_name), ('type', '=', 'customer') ], limit=1) report['port_destination'] = port_destination[0].id if port_destination else None # Conversion de la date d'arrivée (format: "20-Oct-2025") arrival_date_str = shipment_data.get('arrival_date', '') if arrival_date_str: try: report['arrival_date'] = dt.strptime(arrival_date_str, '%d-%b-%Y').date() except: report['arrival_date'] = None report['weighing_place'] = shipment_data.get('weighing_place', '') report['weighing_method'] = shipment_data.get('weighing_method', '') report['bales'] = int(shipment_data.get('bales', 0) or 0) # 6. Weights Information weights_data = json_data.get('weights', {}) gross = Decimal(str(weights_data.get('gross_landed_kg', 0) or 0)) tare = Decimal(str(weights_data.get('tare_kg', 0) or 0)) net = Decimal(str(weights_data.get('net_landed_kg', 0) or 0)) invoice = Decimal(str(weights_data.get('invoice_net_kg', 0) or 0)) gain_loss = Decimal(str(weights_data.get('gain_loss_kg', 0) or 0)) gain_loss_percent = Decimal(str(weights_data.get('gain_loss_percent', 0) or 0)) # Arrondir à 2 décimales report['weight_date'] = parse_date(weights_data.get('weight_date', '')) report['gross_landed_kg'] = gross.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP) report['tare_kg'] = tare.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP) report['net_landed_kg'] = net.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP) report['invoice_net_kg'] = invoice.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP) report['gain_loss_kg'] = gain_loss.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP) report['gain_loss_percent'] = gain_loss_percent.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP) # 7. Création du rapport return cls.create([report])[0]