ICT template

This commit is contained in:
2026-06-15 18:14:42 +02:00
parent 9b7ccf1feb
commit 3a0edea8cd
10 changed files with 21377 additions and 13 deletions

View File

@@ -405,6 +405,18 @@ this repository contains the full copyright notices and license terms. -->
<field name="action" ref="report_purchase"/>
</record>
<record model="ir.action.report" id="report_purchase_commission_ict">
<field name="name">Commission invoice</field>
<field name="model">purchase.purchase</field>
<field name="report_name">purchase.purchase</field>
<field name="report">purchase/purchase_commission_ict.fodt</field>
</record>
<record model="ir.action.keyword" id="report_purchase_commission_ict_keyword">
<field name="keyword">form_print</field>
<field name="model">purchase.purchase,-1</field>
<field name="action" ref="report_purchase_commission_ict"/>
</record>
<record model="ir.ui.view" id="purchase_line_view_form">
<field name="model">purchase.line</field>
<field name="type">form</field>

File diff suppressed because it is too large Load Diff

View File

@@ -58,6 +58,8 @@ class Configuration(ModelSingleton, ModelSQL, ModelView):
_REPORT_LABELS = (
('sale_report_label', 'sale', 'report_sale', 'Proforma'),
('sale_commission_report_label', 'sale',
'report_sale_commission_ict', 'Commission invoice'),
('sale_bill_report_label', 'sale', 'report_bill', 'Draft'),
('invoice_report_label', 'account_invoice', 'report_invoice',
'Invoice'),
@@ -72,6 +74,8 @@ class Configuration(ModelSingleton, ModelSQL, ModelView):
('invoice_payment_order_report_label', 'purchase_trade',
'report_payment_order', 'Payment Order'),
('purchase_report_label', 'purchase', 'report_purchase', 'Purchase'),
('purchase_commission_report_label', 'purchase',
'report_purchase_commission_ict', 'Commission invoice'),
('shipment_shipping_report_label', 'stock',
'report_shipment_in_shipping', 'Shipping instructions'),
('shipment_insurance_report_label', 'purchase_trade',
@@ -85,6 +89,10 @@ class Configuration(ModelSingleton, ModelSQL, ModelView):
pricing_rule = fields.Text("Pricing Rule")
sale_report_template = fields.Char("Sale Template")
sale_report_label = fields.Char("Sale Menu Label")
sale_commission_report_template = fields.Char(
"Sale Commission Template")
sale_commission_report_label = fields.Char(
"Sale Commission Menu Label")
sale_bill_report_template = fields.Char("Sale Bill Template")
sale_bill_report_label = fields.Char("Sale Bill Menu Label")
sale_final_report_template = fields.Char("Sale Final Template")
@@ -105,6 +113,10 @@ class Configuration(ModelSingleton, ModelSQL, ModelView):
"Payment Order Menu Label")
purchase_report_template = fields.Char("Purchase Template")
purchase_report_label = fields.Char("Purchase Menu Label")
purchase_commission_report_template = fields.Char(
"Purchase Commission Template")
purchase_commission_report_label = fields.Char(
"Purchase Commission Menu Label")
shipment_shipping_report_template = fields.Char("Shipping Template")
shipment_shipping_report_label = fields.Char("Shipping Menu Label")
shipment_insurance_report_template = fields.Char("Insurance Template")

View File

@@ -1967,7 +1967,10 @@ class SaleReport(ReportTemplateMixin, BaseSaleReport):
def _resolve_configured_report_path(cls, action):
report_path = cls._get_action_report_path(action)
action_name = cls._get_action_name(action)
if report_path.endswith('/bill.fodt') or action_name == 'Bill':
if (report_path.endswith('/sale_commission_ict.fodt')
or action_name == 'Commission invoice'):
field_name = 'sale_commission_report_template'
elif report_path.endswith('/bill.fodt') or action_name == 'Bill':
field_name = 'sale_bill_report_template'
elif report_path.endswith('/sale_final.fodt') or action_name == 'Sale (final)':
field_name = 'sale_final_report_template'
@@ -1981,5 +1984,11 @@ class PurchaseReport(ReportTemplateMixin, BasePurchaseReport):
@classmethod
def _resolve_configured_report_path(cls, action):
report_path = cls._get_action_report_path(action)
action_name = cls._get_action_name(action)
if (report_path.endswith('/purchase_commission_ict.fodt')
or action_name == 'Commission invoice'):
return cls._resolve_template_path(
action, 'purchase_commission_report_template', 'purchase')
return cls._resolve_template_path(
action, 'purchase_report_template', 'purchase')

View File

@@ -631,17 +631,196 @@ class Purchase(metaclass=PoolMeta):
else:
return ''
@property
def report_price(self):
if self.lines:
if self.lines[0].price_type == 'priced':
return amount_to_currency_words(self.lines[0].unit_price)
elif self.lines[0].price_type == 'basis':
return amount_to_currency_words(self.lines[0].unit_price)
else:
return ''
@property
@property
def report_price(self):
if self.lines:
if self.lines[0].price_type == 'priced':
return amount_to_currency_words(self.lines[0].unit_price)
elif self.lines[0].price_type == 'basis':
return amount_to_currency_words(self.lines[0].unit_price)
else:
return ''
@staticmethod
def _format_report_number(value, digits='0.0000',
strip_trailing_zeros=True):
value = Decimal(str(value or 0)).quantize(Decimal(digits))
text = format(value, 'f')
if strip_trailing_zeros:
text = text.rstrip('0').rstrip('.')
return text or '0'
def _get_report_lines(self):
return [
line for line in self.lines or []
if getattr(line, 'type', None) == 'line']
def _get_report_first_line(self):
lines = self._get_report_lines()
return lines[0] if lines else None
@property
def report_commission_invoice_number(self):
return self.reference or self.full_number or self.number or ''
@property
def report_commission_contract_number(self):
return self.full_number or self.number or ''
def _get_report_commission_fee(self):
fallback = None
for line in self._get_report_lines():
for fee in getattr(line, 'fees', []) or []:
if fallback is None:
fallback = fee
product = getattr(fee, 'product', None)
product_name = (
getattr(product, 'rec_name', None)
or getattr(product, 'name', None) or '')
if 'commission' in product_name.lower():
return fee
return fallback
def _get_report_commission_shipment(self):
for line in self._get_report_lines():
for lot in getattr(line, 'lots', []) or []:
shipment = (
getattr(lot, 'lot_shipment_in', None)
or getattr(lot, 'lot_shipment_out', None)
or getattr(lot, 'lot_shipment_internal', None))
if shipment:
return shipment
@property
def report_commission_bl_number(self):
shipment = self._get_report_commission_shipment()
return getattr(shipment, 'bl_number', None) or ''
@property
def report_commission_bl_date(self):
shipment = self._get_report_commission_shipment()
return getattr(shipment, 'bl_date', None)
@property
def report_commission_vessel(self):
shipment = self._get_report_commission_shipment()
vessel = getattr(shipment, 'vessel', None) if shipment else None
return (
getattr(vessel, 'vessel_name', None)
or getattr(shipment, 'vessel_name', None)
or '')
@property
def report_commission_quantity(self):
return sum(
Decimal(str(getattr(line, 'quantity', 0) or 0))
for line in self._get_report_lines())
@property
def report_commission_quantity_display(self):
return self._format_report_number(
self.report_commission_quantity, digits='0.01',
strip_trailing_zeros=False)
@property
def report_commission_quantity_unit_upper(self):
line = self._get_report_first_line()
unit = getattr(line, 'unit', None) if line else None
return (getattr(unit, 'rec_name', None) or '').upper()
@staticmethod
def _find_report_unit(name):
Uom = Pool().get('product.uom')
units = Uom.search([
'OR',
('name', '=', name),
('symbol', '=', name),
], limit=1)
return units[0] if units else None
@property
def report_commission_lbs_display(self):
line = self._get_report_first_line()
unit = getattr(line, 'unit', None) if line else None
lbs_unit = self._find_report_unit('LBS') or self._find_report_unit('LB')
if not unit or not lbs_unit:
return ''
Uom = Pool().get('product.uom')
converted = Uom.compute_qty(
unit, float(self.report_commission_quantity), lbs_unit) or 0
return self._format_report_number(
Decimal(str(converted)), digits='0.01')
@property
def report_commission_base_amount_display(self):
return self._format_report_number(
self.untaxed_amount or self.total_amount or 0,
digits='0.01', strip_trailing_zeros=False)
@property
def report_commission_currency_name(self):
return getattr(self.currency, 'name', None) or getattr(
self.currency, 'code', None) or ''
@property
def report_commission_invoice_line(self):
return ' '.join(part for part in [
'Our invoice N.',
self.report_commission_invoice_number,
self.report_commission_currency_name,
self.report_commission_base_amount_display,
] if part)
@property
def report_commission_rate_line(self):
fee = self._get_report_commission_fee()
base = self.report_commission_base_amount_display
currency = self.report_commission_currency_name
if fee:
price = self._format_report_number(
getattr(fee, 'price', 0) or 0, digits='0.0000')
if getattr(fee, 'mode', None) in {'pprice', 'rate', 'pcost'}:
return ' '.join(part for part in [
price, '% on', base, currency,
] if part)
fee_currency = getattr(fee, 'currency', None)
fee_unit = getattr(fee, 'unit', None)
return ' '.join(part for part in [
price,
getattr(fee_currency, 'name', None) or getattr(
fee_currency, 'code', None) or '',
'/',
(getattr(fee_unit, 'rec_name', None) or '').upper(),
] if part)
return ' '.join(part for part in ['0 % on', base, currency] if part)
@property
def report_commission_secondary_rate_line(self):
fee = self._get_report_commission_fee()
if not fee or not getattr(fee, 'enable_linked_currency', False):
return ''
currency = getattr(fee, 'linked_currency', None)
unit = getattr(fee, 'linked_unit', None)
return ' '.join(part for part in [
self._format_report_number(
getattr(fee, 'linked_price', 0) or 0, digits='0.0000'),
getattr(currency, 'name', None) or getattr(currency, 'code', None) or '',
'/',
(getattr(unit, 'rec_name', None) or '').upper(),
] if part)
@property
def report_commission_total_display(self):
fee = self._get_report_commission_fee()
if fee and hasattr(fee, 'get_amount'):
amount = fee.get_amount()
else:
amount = self.total_amount or 0
return self._format_report_number(
abs(Decimal(str(amount or 0))), digits='0.01',
strip_trailing_zeros=False)
@property
def report_delivery(self):
del_date = 'PROMPT'
if self.lines:

View File

@@ -1068,6 +1068,159 @@ class Sale(metaclass=PoolMeta):
return '\n'.join(self._format_report_price_line(line) for line in lines)
return ''
@property
def report_commission_invoice_number(self):
return self.reference or self.full_number or self.number or ''
@property
def report_commission_contract_number(self):
return self.full_number or self.number or ''
def _get_report_commission_fee(self):
fallback = None
for line in self._get_report_lines():
for fee in getattr(line, 'fees', []) or []:
if fallback is None:
fallback = fee
product = getattr(fee, 'product', None)
product_name = (
getattr(product, 'rec_name', None)
or getattr(product, 'name', None) or '')
if 'commission' in product_name.lower():
return fee
return fallback
def _get_report_commission_shipment(self):
for line in self._get_report_lines():
for lot in getattr(line, 'lots', []) or []:
shipment = (
getattr(lot, 'lot_shipment_out', None)
or getattr(lot, 'lot_shipment_in', None)
or getattr(lot, 'lot_shipment_internal', None))
if shipment:
return shipment
@property
def report_commission_bl_number(self):
shipment = self._get_report_commission_shipment()
return getattr(shipment, 'bl_number', None) or ''
@property
def report_commission_bl_date(self):
shipment = self._get_report_commission_shipment()
return getattr(shipment, 'bl_date', None)
@property
def report_commission_vessel(self):
shipment = self._get_report_commission_shipment()
vessel = getattr(shipment, 'vessel', None) if shipment else None
return (
getattr(vessel, 'vessel_name', None)
or getattr(shipment, 'vessel_name', None)
or '')
@property
def report_commission_quantity_display(self):
return self.report_total_quantity
@property
def report_commission_quantity_unit_upper(self):
return self.report_quantity_unit_upper or ''
@property
def report_commission_lbs_display(self):
total = self._get_report_total_weight(0)
if total is None:
return ''
unit = self._get_report_total_unit()
lbs_unit = self._find_report_unit('LBS')
if not lbs_unit:
lbs_unit = self._find_report_unit('LB')
if not lbs_unit:
return ''
return self._format_report_number(
self._convert_report_quantity(total, unit, lbs_unit),
digits='0.01')
@staticmethod
def _find_report_unit(name):
Uom = Pool().get('product.uom')
units = Uom.search([
'OR',
('name', '=', name),
('symbol', '=', name),
], limit=1)
return units[0] if units else None
@property
def report_commission_base_amount_display(self):
return self._format_report_number(
self.untaxed_amount or self.total_amount or 0,
digits='0.01', strip_trailing_zeros=False)
@property
def report_commission_currency_name(self):
return getattr(self.currency, 'name', None) or getattr(
self.currency, 'code', None) or ''
@property
def report_commission_invoice_line(self):
return ' '.join(part for part in [
'Our invoice N.',
self.report_commission_invoice_number,
self.report_commission_currency_name,
self.report_commission_base_amount_display,
] if part)
@property
def report_commission_rate_line(self):
fee = self._get_report_commission_fee()
base = self.report_commission_base_amount_display
currency = self.report_commission_currency_name
if fee:
price = self._format_report_number(
getattr(fee, 'price', 0) or 0, digits='0.0000')
if getattr(fee, 'mode', None) in {'pprice', 'rate', 'pcost'}:
return ' '.join(part for part in [
price, '% on', base, currency,
] if part)
fee_currency = getattr(fee, 'currency', None)
fee_unit = getattr(fee, 'unit', None)
return ' '.join(part for part in [
price,
getattr(fee_currency, 'name', None) or getattr(
fee_currency, 'code', None) or '',
'/',
(getattr(fee_unit, 'rec_name', None) or '').upper(),
] if part)
return ' '.join(part for part in ['0 % on', base, currency] if part)
@property
def report_commission_secondary_rate_line(self):
fee = self._get_report_commission_fee()
if not fee or not getattr(fee, 'enable_linked_currency', False):
return ''
currency = getattr(fee, 'linked_currency', None)
unit = getattr(fee, 'linked_unit', None)
return ' '.join(part for part in [
self._format_report_number(
getattr(fee, 'linked_price', 0) or 0, digits='0.0000'),
getattr(currency, 'name', None) or getattr(currency, 'code', None) or '',
'/',
(getattr(unit, 'rec_name', None) or '').upper(),
] if part)
@property
def report_commission_total_display(self):
fee = self._get_report_commission_fee()
if fee and hasattr(fee, 'get_amount'):
amount = fee.get_amount()
else:
amount = self.total_amount or 0
return self._format_report_number(
abs(Decimal(str(amount or 0))), digits='0.01',
strip_trailing_zeros=False)
@property
def report_price_composition_lines(self):
return '\n'.join(

View File

@@ -4551,6 +4551,7 @@ class PurchaseTradeTestCase(ModuleTestCase):
config_model.search.return_value = [
Mock(
sale_report_template='sale_melya.fodt',
sale_commission_report_template='sale_commission_ict.fodt',
sale_bill_report_template='bill_melya.fodt',
sale_final_report_template='sale_final_melya.fodt',
invoice_report_template='invoice_melya.fodt',
@@ -4561,6 +4562,8 @@ class PurchaseTradeTestCase(ModuleTestCase):
invoice_packing_list_report_template='packing_list.fodt',
invoice_payment_order_report_template='payment_order.fodt',
purchase_report_template='purchase_melya.fodt',
purchase_commission_report_template=(
'purchase_commission_ict.fodt'),
)
]
@@ -4648,6 +4651,7 @@ class PurchaseTradeTestCase(ModuleTestCase):
config_model.search.return_value = [
Mock(
sale_report_template='sale_melya.fodt',
sale_commission_report_template='sale_commission_ict.fodt',
sale_bill_report_template='bill_melya.fodt',
sale_final_report_template='sale_final_melya.fodt',
)
@@ -4664,6 +4668,12 @@ class PurchaseTradeTestCase(ModuleTestCase):
'report': 'sale/sale.fodt',
}),
'sale/sale_melya.fodt')
self.assertEqual(
report_class._resolve_configured_report_path({
'name': 'Commission invoice',
'report': 'sale/sale_commission_ict.fodt',
}),
'sale/sale_commission_ict.fodt')
self.assertEqual(
report_class._resolve_configured_report_path({
'name': 'Bill',
@@ -4682,7 +4692,11 @@ class PurchaseTradeTestCase(ModuleTestCase):
report_class = Pool().get('purchase.purchase', type='report')
config_model = Mock()
config_model.search.return_value = [
Mock(purchase_report_template='purchase_melya.fodt')
Mock(
purchase_report_template='purchase_melya.fodt',
purchase_commission_report_template=(
'purchase_commission_ict.fodt'),
)
]
with patch(
@@ -4696,6 +4710,12 @@ class PurchaseTradeTestCase(ModuleTestCase):
'report': 'purchase/purchase.fodt',
}),
'purchase/purchase_melya.fodt')
self.assertEqual(
report_class._resolve_configured_report_path({
'name': 'Commission invoice',
'report': 'purchase/purchase_commission_ict.fodt',
}),
'purchase/purchase_commission_ict.fodt')
def test_shipment_reports_use_templates_from_configuration(self):
'shipment report paths are resolved from purchase_trade configuration'

View File

@@ -5,6 +5,10 @@
<field name="sale_report_template" colspan="3"/>
<label name="sale_report_label"/>
<field name="sale_report_label" colspan="3"/>
<label name="sale_commission_report_template"/>
<field name="sale_commission_report_template" colspan="3"/>
<label name="sale_commission_report_label"/>
<field name="sale_commission_report_label" colspan="3"/>
<label name="sale_bill_report_template"/>
<field name="sale_bill_report_template" colspan="3"/>
<label name="sale_bill_report_label"/>
@@ -45,6 +49,10 @@
<field name="purchase_report_template" colspan="3"/>
<label name="purchase_report_label"/>
<field name="purchase_report_label" colspan="3"/>
<label name="purchase_commission_report_template"/>
<field name="purchase_commission_report_template" colspan="3"/>
<label name="purchase_commission_report_label"/>
<field name="purchase_commission_report_label" colspan="3"/>
<separator id="shipment_templates" string="Shipment" colspan="4"/>
<label name="shipment_shipping_report_template"/>

View File

@@ -410,6 +410,18 @@ this repository contains the full copyright notices and license terms. -->
<field name="action" ref="report_sale"/>
</record>
<record model="ir.action.report" id="report_sale_commission_ict">
<field name="name">Commission invoice</field>
<field name="model">sale.sale</field>
<field name="report_name">sale.sale</field>
<field name="report">sale/sale_commission_ict.fodt</field>
</record>
<record model="ir.action.keyword" id="report_sale_commission_ict_keyword">
<field name="keyword">form_print</field>
<field name="model">sale.sale,-1</field>
<field name="action" ref="report_sale_commission_ict"/>
</record>
<record model="ir.action.report" id="report_bill">
<field name="name">Draft</field>
<field name="model">sale.sale</field>

File diff suppressed because it is too large Load Diff