From ec90d19cc7cb26965a5a8d063ca56fb3a9b8aa09 Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Sat, 13 Jun 2026 11:04:13 +0200 Subject: [PATCH] Delivery period changed into Shipment period --- modules/purchase_trade/company_defaults.py | 50 ++++++++++++ modules/purchase_trade/ctrm_reporting.py | 6 +- modules/purchase_trade/fee.py | 32 +++++++- modules/purchase_trade/lot.py | 46 ++++++++--- modules/purchase_trade/pricing.py | 81 ++++++++++++++----- modules/purchase_trade/purchase.py | 62 ++++++++++++-- modules/purchase_trade/sale.py | 54 ++++++++++++- modules/purchase_trade/stock.py | 2 +- .../purchase_trade/view/lot_report_list.xml | 4 +- modules/purchase_trade/view/purchase_tree.xml | 2 +- 10 files changed, 288 insertions(+), 51 deletions(-) create mode 100644 modules/purchase_trade/company_defaults.py diff --git a/modules/purchase_trade/company_defaults.py b/modules/purchase_trade/company_defaults.py new file mode 100644 index 0000000..f32fcfd --- /dev/null +++ b/modules/purchase_trade/company_defaults.py @@ -0,0 +1,50 @@ +from trytond.pool import Pool +from trytond.transaction import Transaction + + +ITSA_COMPANY_NAME = 'ITSA' + + +def record_id(record): + return getattr(record, 'id', record) + + +def is_itsa_company(company=None): + if company is None: + company_id = Transaction().context.get('company') + if not company_id: + return False + Company = Pool().get('company.company') + company = Company(company_id) + party = getattr(company, 'party', None) + return bool(party and party.name == ITSA_COMPANY_NAME) + + +def _search_first(model_name, domains): + Model = Pool().get(model_name) + for domain in domains: + try: + records = Model.search(domain, limit=1) + except Exception: + continue + if records: + return records[0] + + +def default_itsa_currency(): + currency = _search_first('currency.currency', [ + [('code', '=', 'USD')], + [('name', '=', 'USD')], + [('symbol', '=', 'USD')], + ]) + return record_id(currency) if currency else None + + +def default_itsa_unit(): + unit = _search_first('product.uom', [ + [('symbol', '=', 'Mt')], + [('name', '=', 'Mt')], + [('symbol', '=', 'MT')], + [('name', '=', 'MT')], + ]) + return record_id(unit) if unit else None diff --git a/modules/purchase_trade/ctrm_reporting.py b/modules/purchase_trade/ctrm_reporting.py index 3e2f060..95e8518 100644 --- a/modules/purchase_trade/ctrm_reporting.py +++ b/modules/purchase_trade/ctrm_reporting.py @@ -1186,7 +1186,7 @@ class CTRMContractPerformanceContext(ModelView): ], "Side") product = fields.Many2One('product.product', "Product") counterparty = fields.Many2One('party.party', "Counterparty") - delivery_period = fields.Many2One('product.month', "Delivery Period") + delivery_period = fields.Many2One('product.month', "Shipment Period") status = fields.Selection([ (None, ''), ('under', 'Under delivery'), @@ -1210,7 +1210,7 @@ class CTRMContractPerformance(ModelSQL, ModelView): sale_line = fields.Many2One('sale.line', "Sale Line") counterparty = fields.Many2One('party.party', "Counterparty") product = fields.Many2One('product.product', "Product") - delivery_period = fields.Many2One('product.month', "Delivery Period") + delivery_period = fields.Many2One('product.month', "Shipment Period") from_date = fields.Date("From") to_date = fields.Date("To") contract_quantity = fields.Numeric("Contract Quantity", digits=(16, 5)) @@ -1453,7 +1453,7 @@ class CTRMScheduling(ModelSQL, ModelView): warehouse = fields.Many2One('stock.location', "Warehouse") from_location = fields.Many2One('stock.location', "From") to_location = fields.Many2One('stock.location', "To") - delivery_period = fields.Many2One('product.month', "Delivery Period") + delivery_period = fields.Many2One('product.month', "Shipment Period") contract_from = fields.Date("Contract From") contract_to = fields.Date("Contract To") scheduled_date = fields.Date("Scheduled Date") diff --git a/modules/purchase_trade/fee.py b/modules/purchase_trade/fee.py index 3342ac3..56bffc5 100755 --- a/modules/purchase_trade/fee.py +++ b/modules/purchase_trade/fee.py @@ -19,6 +19,8 @@ import logging from collections import defaultdict from trytond.exceptions import UserWarning, UserError from trytond.modules.account.exceptions import PeriodNotFoundError +from trytond.modules.purchase_trade.company_defaults import ( + default_itsa_currency, default_itsa_unit, is_itsa_company) logger = logging.getLogger(__name__) @@ -101,11 +103,25 @@ class Fee(ModelSQL,ModelView): fee_date = fields.Date("Date") - @classmethod + @classmethod def default_fee_date(cls): Date = Pool().get('ir.date') return Date.today() + @classmethod + def default_currency(cls): + if is_itsa_company(): + currency = default_itsa_currency() + if currency: + return currency + + @classmethod + def default_unit(cls): + if is_itsa_company(): + unit = default_itsa_unit() + if unit: + return unit + @classmethod def default_generated_by_rule(cls): return False @@ -1056,6 +1072,20 @@ class FeeRule(ModelSQL, ModelView): def default_weight_type(cls): return 'brut' + @classmethod + def default_currency(cls): + if is_itsa_company(): + currency = default_itsa_currency() + if currency: + return currency + + @classmethod + def default_unit(cls): + if is_itsa_company(): + unit = default_itsa_unit() + if unit: + return unit + @staticmethod def _same_record(left, right): return bool( diff --git a/modules/purchase_trade/lot.py b/modules/purchase_trade/lot.py index d807b8b..c6c898c 100755 --- a/modules/purchase_trade/lot.py +++ b/modules/purchase_trade/lot.py @@ -20,8 +20,10 @@ from operator import itemgetter import datetime import json import logging -from trytond.exceptions import UserWarning, UserError -from trytond.modules.purchase_trade.service import ContractFactory +from trytond.exceptions import UserWarning, UserError +from trytond.modules.purchase_trade.service import ContractFactory +from trytond.modules.purchase_trade.company_defaults import ( + default_itsa_unit, is_itsa_company) logger = logging.getLogger(__name__) @@ -289,8 +291,24 @@ class Lot(metaclass=PoolMeta): or self.planned_from_date or self.planned_to_date or self.planned_note) - - def get_pivot(self,name=None): + + @classmethod + def default_lot_unit(cls): + if is_itsa_company(): + return default_itsa_unit() + default = getattr(super(), 'default_lot_unit', None) + if default: + return default() + + @classmethod + def default_lot_unit_line(cls): + if is_itsa_company(): + return default_itsa_unit() + default = getattr(super(), 'default_lot_unit_line', None) + if default: + return default() + + def get_pivot(self,name=None): AccountMoveLine = Pool().get('account.move.line') Account = Pool().get('account.account') Stock = Pool().get('stock.move') @@ -2708,9 +2726,9 @@ class LotReport( r_lot_price = fields.Function(fields.Numeric("Price", digits='r_lot_unit_line'),'get_lot_price') r_lot_price_sale = fields.Function(fields.Numeric("Price", digits='r_lot_unit_line'),'get_lot_sale_price') r_del_period = fields.Many2One( - 'product.month', "Purchase Delivery Period") + 'product.month', "Purchase Shipment Period") r_sale_del_period = fields.Many2One( - 'product.month', "Sale Delivery Period") + 'product.month', "Sale Shipment Period") r_sale_line = fields.Many2One('sale.line',"S. line") r_sale = fields.Many2One('sale.sale',"Sale") r_tot = fields.Numeric("Qt tot", digits='r_lot_unit_line') @@ -4161,8 +4179,18 @@ class LotAddLine(ModelView): lot_quantity = fields.Numeric("Net weight") lot_gross_quantity = fields.Numeric("Gross weight") lot_unit_line = fields.Many2One('product.uom', "Unit",required=True) - lot_premium = fields.Numeric("Premium") - lot_chunk_key = fields.Integer("Chunk key") + lot_premium = fields.Numeric("Premium") + lot_chunk_key = fields.Integer("Chunk key") + + @classmethod + def default_lot_unit(cls): + if is_itsa_company(): + return default_itsa_unit() + + @classmethod + def default_lot_unit_line(cls): + if is_itsa_company(): + return default_itsa_unit() # @fields.depends('lot_qt') # def on_change_with_lot_quantity(self): @@ -5049,7 +5077,7 @@ class ContractDetail(ModelView): crop = fields.Many2One( 'purchase.crop', "Crop", states={'invisible': Eval('company_visible')}) - del_period = fields.Many2One('product.month',"Delivery Period") + del_period = fields.Many2One('product.month',"Shipment Period") from_del = fields.Date("From") to_del = fields.Date("To") price = fields.Numeric("Price", required=True,digits=(1,4),states={'invisible': Eval('price_type') != 'priced'}) diff --git a/modules/purchase_trade/pricing.py b/modules/purchase_trade/pricing.py index 94004ba..ec8c2c8 100755 --- a/modules/purchase_trade/pricing.py +++ b/modules/purchase_trade/pricing.py @@ -22,8 +22,10 @@ import logging import re import zipfile from io import BytesIO -from xml.etree import ElementTree -from trytond.modules.purchase_trade.purchase import (TRIGGERS) +from xml.etree import ElementTree +from trytond.modules.purchase_trade.purchase import (TRIGGERS) +from trytond.modules.purchase_trade.company_defaults import ( + default_itsa_currency, default_itsa_unit, is_itsa_company) logger = logging.getLogger(__name__) @@ -586,9 +588,16 @@ class MtmStrategy(ModelSQL, ModelView): 'pricing.component', 'strategy', "Components" ) - @classmethod - def default_active(cls): - return True + @classmethod + def default_active(cls): + return True + + @classmethod + def default_currency(cls): + if is_itsa_company(): + currency = default_itsa_currency() + if currency: + return currency def get_mtm(self,line,qty): pool = Pool() @@ -709,11 +718,18 @@ class Mtm(ModelSQL, ModelView): return self.price_matrix.currency return None - @fields.depends('price_index','price_matrix') - def on_change_with_currency(self): - return self.get_cur() - -class PriceMatrix(ModelSQL, ModelView): + @fields.depends('price_index','price_matrix') + def on_change_with_currency(self): + return self.get_cur() + + @classmethod + def default_currency(cls): + if is_itsa_company(): + currency = default_itsa_currency() + if currency: + return currency + +class PriceMatrix(ModelSQL, ModelView): "Price Matrix" __name__ = 'price.matrix' @@ -737,11 +753,25 @@ class PriceMatrix(ModelSQL, ModelView): valid_from = fields.Date("Valid From") valid_to = fields.Date("Valid To") - lines = fields.One2Many( - 'price.matrix.line', 'matrix', "Lines" - ) - -class PriceMatrixLine(ModelSQL, ModelView): + lines = fields.One2Many( + 'price.matrix.line', 'matrix', "Lines" + ) + + @classmethod + def default_currency(cls): + if is_itsa_company(): + currency = default_itsa_currency() + if currency: + return currency + + @classmethod + def default_unit(cls): + if is_itsa_company(): + unit = default_itsa_unit() + if unit: + return unit + +class PriceMatrixLine(ModelSQL, ModelView): "Price Matrix Line" __name__ = 'price.matrix.line' @@ -851,13 +881,20 @@ class Component(ModelSQL, ModelView): @fields.depends( 'price_source_type', 'price_index', 'price_matrix', 'fixed_currency') - def on_change_with_currency(self): - if self.price_source_type == 'curve' and self.price_index: - return self.get_cur() - if self.price_source_type == 'matrix' and self.price_matrix: - return self.get_cur() - if self.price_source_type == 'fixed': - return self.fixed_currency + def on_change_with_currency(self): + if self.price_source_type == 'curve' and self.price_index: + return self.get_cur() + if self.price_source_type == 'matrix' and self.price_matrix: + return self.get_cur() + if self.price_source_type == 'fixed': + return self.fixed_currency + + @classmethod + def default_fixed_currency(cls): + if is_itsa_company(): + currency = default_itsa_currency() + if currency: + return currency @classmethod def set_cur(cls, components, name, value): diff --git a/modules/purchase_trade/purchase.py b/modules/purchase_trade/purchase.py index c10790e..95dbf70 100755 --- a/modules/purchase_trade/purchase.py +++ b/modules/purchase_trade/purchase.py @@ -24,7 +24,9 @@ import re import jwt from collections import defaultdict from trytond.exceptions import UserWarning, UserError -from trytond.modules.purchase_trade.numbers_to_words import quantity_to_words, amount_to_currency_words, format_date_en +from trytond.modules.purchase_trade.numbers_to_words import quantity_to_words, amount_to_currency_words, format_date_en +from trytond.modules.purchase_trade.company_defaults import ( + default_itsa_currency, default_itsa_unit, is_itsa_company, record_id) import requests import io @@ -323,7 +325,7 @@ class Purchase(metaclass=PoolMeta): ('efp', 'EFP'), ], "Price Type"), 'get_first_line_price_type') first_line_del_period = fields.Function( - fields.Many2One('product.month', "Delivery Period"), + fields.Many2One('product.month', "Shipment Period"), 'get_first_line_del_period') first_line_from_del = fields.Function( fields.Date("Delivery From"), 'get_first_line_from_del') @@ -434,9 +436,29 @@ class Purchase(metaclass=PoolMeta): @fields.depends('company', 'currency', 'our_bank_account', '_parent_company.party') def on_change_company(self): + previous_currency = self.currency super().on_change_company() + if (is_itsa_company(self.company) + and (not previous_currency + or record_id(self.currency) + == record_id(getattr(self.company, 'currency', None)) + or record_id(previous_currency) + == record_id(getattr(self.company, 'currency', None)))): + currency = default_itsa_currency() + if currency: + self.currency = currency self.our_bank_account = self._get_default_our_bank_account() + @classmethod + def default_currency(cls): + if is_itsa_company(): + currency = default_itsa_currency() + if currency: + return currency + default = getattr(super(), 'default_currency', None) + if default: + return default() + @classmethod def default_wb(cls): WB = Pool().get('purchase.weight.basis') @@ -1831,7 +1853,7 @@ class Line(metaclass=PoolMeta): to_del = values.get('to_del', getattr(line, 'to_del', None)) if from_del and to_del and from_del > to_del: raise UserError( - "Delivery period From date must be before To date.") + "Shipment period From date must be before To date.") @classmethod def create(cls, vlist): @@ -1852,7 +1874,7 @@ class Line(metaclass=PoolMeta): def _check_delivery_period(self): if self._has_invalid_delivery_period(self): raise UserError( - "Delivery period From date must be before To date.") + "Shipment period From date must be before To date.") @fields.depends('from_del', 'to_del') def on_change_from_del(self): @@ -1873,7 +1895,7 @@ class Line(metaclass=PoolMeta): states={ 'invisible': Eval('price_type') != 'basis', }),'get_progress') - del_period = fields.Many2One('product.month',"Delivery Period") + del_period = fields.Many2One('product.month',"Shipment Period") from_del = fields.Date("From") to_del = fields.Date("To") period_at = fields.Selection([ @@ -1947,8 +1969,32 @@ class Line(metaclass=PoolMeta): 'get_premium', setter='set_premium') fee_ = fields.Many2One('fee.fee',"Fee") pricing_rule = fields.Text("Pricing description") - - attributes = fields.Dict( + + @classmethod + def default_unit(cls): + if is_itsa_company(): + unit = default_itsa_unit() + if unit: + return unit + default = getattr(super(), 'default_unit', None) + if default: + return default() + + @fields.depends('product', 'unit', 'purchase', + '_parent_purchase.company', '_parent_purchase.company.party') + def on_change_product(self): + previous_unit = self.unit + parent_on_change = getattr(super(), 'on_change_product', None) + if parent_on_change: + parent_on_change() + if (self.purchase and is_itsa_company(self.purchase.company) + and (not previous_unit + or record_id(previous_unit) == default_itsa_unit())): + unit = default_itsa_unit() + if unit: + self.unit = unit + + attributes = fields.Dict( 'product.attribute', 'Attributes', domain=[ ('sets', '=', Eval('attribute_set')), @@ -2580,7 +2626,7 @@ class Line(metaclass=PoolMeta): for line in lines: if cls._has_invalid_delivery_period(line): raise UserError( - "Delivery period From date must be before To date.") + "Shipment period From date must be before To date.") if line.price_components: for pc in line.price_components: if pc.triggers: diff --git a/modules/purchase_trade/sale.py b/modules/purchase_trade/sale.py index 34b2f9c..2e4189f 100755 --- a/modules/purchase_trade/sale.py +++ b/modules/purchase_trade/sale.py @@ -18,6 +18,8 @@ import json from collections import defaultdict from trytond.exceptions import UserWarning, UserError from trytond.modules.purchase_trade.numbers_to_words import quantity_to_words, amount_to_currency_words, format_date_en +from trytond.modules.purchase_trade.company_defaults import ( + default_itsa_currency, default_itsa_unit, is_itsa_company, record_id) logger = logging.getLogger(__name__) @@ -378,8 +380,28 @@ class Sale(metaclass=PoolMeta): @fields.depends('company', 'currency', 'our_bank_account', '_parent_company.party') def on_change_company(self): + previous_currency = self.currency super().on_change_company() + if (is_itsa_company(self.company) + and (not previous_currency + or record_id(self.currency) + == record_id(getattr(self.company, 'currency', None)) + or record_id(previous_currency) + == record_id(getattr(self.company, 'currency', None)))): + currency = default_itsa_currency() + if currency: + self.currency = currency self.our_bank_account = self._get_default_our_bank_account() + + @classmethod + def default_currency(cls): + if is_itsa_company(): + currency = default_itsa_currency() + if currency: + return currency + default = getattr(super(), 'default_currency', None) + if default: + return default() @classmethod def default_wb(cls): @@ -1564,6 +1586,30 @@ class SaleLine(metaclass=PoolMeta): super().__setup__() cls.quantity.readonly = True + @classmethod + def default_unit(cls): + if is_itsa_company(): + unit = default_itsa_unit() + if unit: + return unit + default = getattr(super(), 'default_unit', None) + if default: + return default() + + @fields.depends('product', 'unit', 'sale', + '_parent_sale.company', '_parent_sale.company.party') + def on_change_product(self): + previous_unit = self.unit + parent_on_change = getattr(super(), 'on_change_product', None) + if parent_on_change: + parent_on_change() + if (self.sale and is_itsa_company(self.sale.company) + and (not previous_unit + or record_id(previous_unit) == default_itsa_unit())): + unit = default_itsa_unit() + if unit: + self.unit = unit + @staticmethod def _is_empty_quantity(quantity): if quantity in (None, ''): @@ -1692,7 +1738,7 @@ class SaleLine(metaclass=PoolMeta): to_del = values.get('to_del', getattr(line, 'to_del', None)) if from_del and to_del and from_del > to_del: raise UserError( - "Delivery period From date must be before To date.") + "Shipment period From date must be before To date.") @classmethod def create(cls, vlist): @@ -1713,7 +1759,7 @@ class SaleLine(metaclass=PoolMeta): def _check_delivery_period(self): if self._has_invalid_delivery_period(self): raise UserError( - "Delivery period From date must be before To date.") + "Shipment period From date must be before To date.") @fields.depends('from_del', 'to_del') def on_change_from_del(self): @@ -1723,7 +1769,7 @@ class SaleLine(metaclass=PoolMeta): def on_change_to_del(self): self._check_delivery_period() - del_period = fields.Many2One('product.month',"Delivery Period") + del_period = fields.Many2One('product.month',"Shipment Period") lots = fields.One2Many('lot.lot','sale_line',"Lots",readonly=True) fees = fields.One2Many('fee.fee', 'sale_line', 'Fees') quantity_theorical = fields.Numeric("Th. quantity", digits='unit', readonly=False) @@ -2580,7 +2626,7 @@ class SaleLine(metaclass=PoolMeta): for line in salelines: if cls._has_invalid_delivery_period(line): raise UserError( - "Delivery period From date must be before To date.") + "Shipment period From date must be before To date.") if line.price_components: for pc in line.price_components: if pc.triggers: diff --git a/modules/purchase_trade/stock.py b/modules/purchase_trade/stock.py index 41c65fd..7e144af 100755 --- a/modules/purchase_trade/stock.py +++ b/modules/purchase_trade/stock.py @@ -722,7 +722,7 @@ class ShipmentIn(metaclass=PoolMeta): fields.One2Many('charter.condition', '', "Customer Conditions"), 'get_sale_charter_conditions') sof = fields.One2Many('sof.statement', 'shipment',"Demurrage calculations") - del_from = fields.Date("Delivery period from") + del_from = fields.Date("Shipment period from") del_to = fields.Date("to") estimated_date = fields.One2Many('pricing.estimated','shipment_in',"Estimated date") carrier_ = fields.Many2One('party.party',"Carrier") diff --git a/modules/purchase_trade/view/lot_report_list.xml b/modules/purchase_trade/view/lot_report_list.xml index f18f01a..f192b92 100755 --- a/modules/purchase_trade/view/lot_report_list.xml +++ b/modules/purchase_trade/view/lot_report_list.xml @@ -1,8 +1,8 @@ - - + + diff --git a/modules/purchase_trade/view/purchase_tree.xml b/modules/purchase_trade/view/purchase_tree.xml index 691d700..1711fd6 100755 --- a/modules/purchase_trade/view/purchase_tree.xml +++ b/modules/purchase_trade/view/purchase_tree.xml @@ -13,7 +13,7 @@ this repository contains the full copyright notices and license terms. --> badge_colors="priced:#16a34a,basis:#2563eb,efp:#8b5cf6,cash:#f59e0b" optional="0" width="100"/> - +