Add insurance template

This commit is contained in:
2026-04-06 17:30:50 +02:00
parent 845b9cf749
commit ec359f6b8a
12 changed files with 1472 additions and 26 deletions

View File

@@ -1528,12 +1528,9 @@
<text:p text:style-name="P3"/> <text:p text:style-name="P3"/>
<text:h text:style-name="P27" text:outline-level="1"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T3">COMMERCIAL INVOICE</text:span></text:span></text:h> <text:h text:style-name="P27" text:outline-level="1"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T3">COMMERCIAL INVOICE</text:span></text:span></text:h>
<text:p text:style-name="P2"/> <text:p text:style-name="P2"/>
<text:p text:style-name="P8"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T4">Invoice Nr: <text:tab/><text:tab/><text:tab/>Date:</text:span></text:span></text:p> <text:p text:style-name="P8"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T4">Invoice: <text:placeholder text:placeholder-type="text">&lt;invoice.number or &apos;&apos;&gt;</text:placeholder><text:tab/><text:tab/>Date: <text:placeholder text:placeholder-type="text">&lt;format_date(invoice.invoice_date, invoice.party.lang) if invoice.invoice_date else &apos;&apos;&gt;</text:placeholder></text:span></text:span></text:p>
<text:p text:style-name="P20"/>
<text:p text:style-name="P8"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T4"><text:placeholder text:placeholder-type="text">&lt;invoice.number or &apos;&apos;&gt;</text:placeholder></text:span></text:span><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T5"><text:s text:c="48"/></text:span></text:span><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T4"><text:placeholder text:placeholder-type="text">&lt;format_date(invoice.invoice_date, invoice.party.lang) if invoice.invoice_date else &apos;&apos;&gt;</text:placeholder></text:span></text:span></text:p>
<text:p text:style-name="P3"/> <text:p text:style-name="P3"/>
<text:p text:style-name="P8"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T4">Order reference:</text:span></text:span></text:p> <text:p text:style-name="P8"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T4">Reference: <text:placeholder text:placeholder-type="text">&lt;invoice.report_contract_number or &apos;&apos;&gt;</text:placeholder></text:span></text:span></text:p>
<text:p text:style-name="P14"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T4"><text:placeholder text:placeholder-type="text">&lt;invoice.report_contract_number or &apos;&apos;&gt;</text:placeholder></text:span></text:span></text:p>
</table:table-cell> </table:table-cell>
</table:table-row> </table:table-row>
<table:table-row> <table:table-row>
@@ -1626,6 +1623,7 @@
<text:p text:style-name="P17"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T9"><text:s/></text:span></text:span><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T12"><text:s/></text:span></text:span><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T12"><text:placeholder text:placeholder-type="text">&lt;format_number_symbol(invoice.report_net, invoice.party.lang, invoice.lines[0].unit, digits=2) if invoice.lines else &apos;&apos;&gt;</text:placeholder></text:span></text:span></text:p> <text:p text:style-name="P17"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T9"><text:s/></text:span></text:span><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T12"><text:s/></text:span></text:span><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T12"><text:placeholder text:placeholder-type="text">&lt;format_number_symbol(invoice.report_net, invoice.party.lang, invoice.lines[0].unit, digits=2) if invoice.lines else &apos;&apos;&gt;</text:placeholder></text:span></text:span></text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau2.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau2.A1" office:value-type="string">
<text:p text:style-name="P15"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T9"><text:placeholder text:placeholder-type="text">&lt;invoice.report_product_name or &apos;&apos;&gt;</text:placeholder></text:span></text:span></text:p>
<text:p text:style-name="P15"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T9"><text:placeholder text:placeholder-type="text">&lt;invoice.report_product_description or &apos;&apos;&gt;</text:placeholder></text:span></text:span></text:p> <text:p text:style-name="P15"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T9"><text:placeholder text:placeholder-type="text">&lt;invoice.report_product_description or &apos;&apos;&gt;</text:placeholder></text:span></text:span></text:p>
<text:p text:style-name="P6"/> <text:p text:style-name="P6"/>
</table:table-cell> </table:table-cell>
@@ -1707,4 +1705,4 @@
<text:p text:style-name="Standard"><text:placeholder text:placeholder-type="text">&lt;/for&gt;</text:placeholder></text:p> <text:p text:style-name="Standard"><text:placeholder text:placeholder-type="text">&lt;/for&gt;</text:placeholder></text:p>
</office:text> </office:text>
</office:body> </office:body>
</office:document> </office:document>

View File

@@ -278,5 +278,7 @@ def register():
invoice.InvoiceReport, invoice.InvoiceReport,
invoice.SaleReport, invoice.SaleReport,
invoice.PurchaseReport, invoice.PurchaseReport,
stock.ShipmentShippingReport,
stock.ShipmentInsuranceReport,
module='purchase_trade', type_='report') module='purchase_trade', type_='report')

View File

@@ -13,3 +13,5 @@ class Configuration(ModelSingleton, ModelSQL, ModelView):
invoice_cndn_report_template = fields.Char("CN/DN Template") invoice_cndn_report_template = fields.Char("CN/DN Template")
invoice_prepayment_report_template = fields.Char("Prepayment Template") invoice_prepayment_report_template = fields.Char("Prepayment Template")
purchase_report_template = fields.Char("Purchase Template") purchase_report_template = fields.Char("Purchase Template")
shipment_shipping_report_template = fields.Char("Shipping Template")
shipment_insurance_report_template = fields.Char("Insurance Template")

View File

@@ -29,6 +29,8 @@ Derniere mise a jour: `2026-03-27`
- reutiliser si possible les proprietes `report_*` deja presentes sur `sale.sale` - reutiliser si possible les proprietes `report_*` deja presentes sur `sale.sale`
- Pour un achat: - Pour un achat:
- reutiliser si possible les proprietes `report_*` deja presentes sur `purchase.purchase` - reutiliser si possible les proprietes `report_*` deja presentes sur `purchase.purchase`
- Pour un shipment entrant:
- reutiliser si possible les proprietes `report_*` exposees sur `stock.shipment.in`
## 4) Propriete disponibles sur `account.invoice` ## 4) Propriete disponibles sur `account.invoice`
@@ -288,8 +290,30 @@ Usage typique:
- `modules/account_invoice/invoice_ict.fodt` - `modules/account_invoice/invoice_ict.fodt`
- `modules/account_invoice/invoice_ict_final.fodt` - `modules/account_invoice/invoice_ict_final.fodt`
- `modules/sale/sale_ict.fodt` - `modules/sale/sale_ict.fodt`
- `modules/stock/insurance.fodt`
## 9) Recommandations ## 9) Proprietes utiles deja presentes sur `stock.shipment.in`
Source code: `modules/purchase_trade/stock.py`
- `report_product_name`
- `report_product_description`
- `report_insurance_footer_ref`
- `report_insurance_certificate_number`
- `report_insurance_account_of`
- `report_insurance_goods_description`
- `report_insurance_loading_port`
- `report_insurance_discharge_port`
- `report_insurance_transport`
- `report_insurance_amount`
- `report_insurance_surveyor`
- `report_insurance_issue_place_and_date`
Usage typique:
- templates shipment relies a l'assurance
- templates qui lisent le fee `Insurance` d'un `stock.shipment.in`
## 10) Recommandations
- Avant d'ajouter une nouvelle expression dans un `.fodt`, verifier si une - Avant d'ajouter une nouvelle expression dans un `.fodt`, verifier si une
propriete `report_*` existe deja ici. propriete `report_*` existe deja ici.

View File

@@ -198,6 +198,13 @@ class Invoice(metaclass=PoolMeta):
return line.product.description or '' return line.product.description or ''
return '' return ''
@property
def report_product_name(self):
line = self._get_report_trade_line()
if line and line.product:
return line.product.name or ''
return ''
@property @property
def report_description_upper(self): def report_description_upper(self):
if self.lines: if self.lines:
@@ -598,6 +605,15 @@ class InvoiceLine(metaclass=PoolMeta):
return origin.product.description or '' return origin.product.description or ''
return '' return ''
@property
def report_product_name(self):
if self.product:
return self.product.name or ''
origin = getattr(self, 'origin', None)
if origin and getattr(origin, 'product', None):
return origin.product.name or ''
return ''
@property @property
def report_description_upper(self): def report_description_upper(self):
return Invoice._clean_report_description(self.description) return Invoice._clean_report_description(self.description)

View File

@@ -492,6 +492,20 @@ class Sale(metaclass=PoolMeta):
return 'NB BALES: ' + str(int(nb_bale)) return 'NB BALES: ' + str(int(nb_bale))
return '' return ''
@property
def report_product_name(self):
line = self._get_report_first_line()
if line and line.product:
return line.product.name or ''
return ''
@property
def report_product_description(self):
line = self._get_report_first_line()
if line and line.product:
return line.product.description or ''
return ''
@property @property
def report_crop_name(self): def report_crop_name(self):
if self.crop: if self.crop:

View File

@@ -6,7 +6,7 @@ from trytond.pyson import Bool, Eval, Id
from trytond.model import (ModelSQL, ModelView) from trytond.model import (ModelSQL, ModelView)
from trytond.tools import is_full_text, lstrip_wildcard from trytond.tools import is_full_text, lstrip_wildcard
from trytond.transaction import Transaction, inactive_records from trytond.transaction import Transaction, inactive_records
from decimal import getcontext, Decimal, ROUND_HALF_UP from decimal import getcontext, Decimal, ROUND_HALF_UP
from sql.aggregate import Count, Max, Min, Sum, Avg, BoolOr from sql.aggregate import Count, Max, Min, Sum, Avg, BoolOr
from sql.conditionals import Case from sql.conditionals import Case
from sql import Column, Literal from sql import Column, Literal
@@ -23,8 +23,10 @@ import io
import base64 import base64
import logging import logging
import json import json
import re import re
import html import html
from trytond.exceptions import UserError
from trytond.modules.stock.shipment import SupplierShipping as BaseSupplierShipping
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -387,8 +389,8 @@ class ShipmentWR(ModelSQL,ModelView):
shipment_in = fields.Many2One('stock.shipment.in',"Shipment In") shipment_in = fields.Many2One('stock.shipment.in',"Shipment In")
wr = fields.Many2One('weight.report',"WR") wr = fields.Many2One('weight.report',"WR")
class ShipmentIn(metaclass=PoolMeta): class ShipmentIn(metaclass=PoolMeta):
__name__ = 'stock.shipment.in' __name__ = 'stock.shipment.in'
from_location = fields.Many2One('stock.location', 'From location') from_location = fields.Many2One('stock.location', 'From location')
to_location = fields.Many2One('stock.location', 'To location') to_location = fields.Many2One('stock.location', 'To location')
@@ -459,9 +461,134 @@ class ShipmentIn(metaclass=PoolMeta):
'send': {}, 'send': {},
}) })
def get_vessel_type(self,name=None): def get_vessel_type(self,name=None):
if self.vessel: if self.vessel:
return self.vessel.vessel_type return self.vessel.vessel_type
def _get_report_primary_move(self):
moves = list(self.incoming_moves or self.moves or [])
return moves[0] if moves else None
def _get_report_primary_lot(self):
move = self._get_report_primary_move()
return getattr(move, 'lot', None) if move else None
def _get_report_trade_line(self):
lot = self._get_report_primary_lot()
if not lot:
return None
return getattr(lot, 'sale_line', None) or getattr(lot, 'line', None)
def _get_report_insurance_fee(self):
for fee in self.fees or []:
product = getattr(fee, 'product', None)
name = ((getattr(product, 'name', '') or '')).strip().lower()
if 'insurance' in name:
return fee
return None
@staticmethod
def _format_report_amount(value):
if value in (None, ''):
return ''
value = Decimal(str(value or 0)).quantize(Decimal('0.01'))
return format(value, 'f')
@property
def report_product_name(self):
line = self._get_report_trade_line()
product = getattr(line, 'product', None) if line else None
if product:
return product.name or ''
move = self._get_report_primary_move()
product = getattr(move, 'product', None) if move else None
return getattr(product, 'name', '') or ''
@property
def report_product_description(self):
line = self._get_report_trade_line()
product = getattr(line, 'product', None) if line else None
if product:
return product.description or ''
move = self._get_report_primary_move()
product = getattr(move, 'product', None) if move else None
return getattr(product, 'description', '') or ''
@property
def report_insurance_footer_ref(self):
return self.bl_number or self.number or ''
@property
def report_insurance_certificate_number(self):
return self.bl_number or self.number or ''
@property
def report_insurance_account_of(self):
line = self._get_report_trade_line()
trade = getattr(line, 'sale', None) or getattr(line, 'purchase', None)
party = getattr(trade, 'party', None) if trade else None
if party:
return party.rec_name or ''
return getattr(self.supplier, 'rec_name', '') or ''
@property
def report_insurance_goods_description(self):
name = self.report_product_name
description = self.report_product_description
if description and description != name:
return ' - '.join(part for part in [name, description] if part)
return name or description
@property
def report_insurance_loading_port(self):
return getattr(self.from_location, 'name', '') or ''
@property
def report_insurance_discharge_port(self):
return getattr(self.to_location, 'name', '') or ''
@property
def report_insurance_transport(self):
if self.vessel and self.vessel.vessel_name:
return self.vessel.vessel_name
return self.transport_type or ''
@property
def report_insurance_amount(self):
fee = self._get_report_insurance_fee()
if not fee:
return ''
currency = getattr(fee, 'currency', None)
currency_text = (
getattr(currency, 'rec_name', None)
or getattr(currency, 'code', None)
or getattr(currency, 'symbol', None)
or '')
amount = self._format_report_amount(fee.get_amount())
return ' '.join(part for part in [currency_text, amount] if part)
@property
def report_insurance_surveyor(self):
if self.controller:
return self.controller.rec_name or ''
fee = self._get_report_insurance_fee()
supplier = getattr(fee, 'supplier', None) if fee else None
return getattr(supplier, 'rec_name', '') or ''
@property
def report_insurance_issue_place_and_date(self):
Date = Pool().get('ir.date')
address = None
if self.company and getattr(self.company, 'party', None):
address = self.company.party.address_get()
place = (
getattr(address, 'city', None)
or getattr(self.company.party, 'rec_name', None)
if self.company and getattr(self.company, 'party', None) else ''
) or ''
today = Date.today()
date_text = today.strftime('%d-%m-%Y') if today else ''
return ', '.join(part for part in [place, date_text] if part)
def get_rec_name(self, name=None): def get_rec_name(self, name=None):
if self.number: if self.number:
@@ -1888,7 +2015,7 @@ class Revaluate(Wizard):
return 'end' return 'end'
class RevaluateStart(ModelView): class RevaluateStart(ModelView):
"Revaluate" "Revaluate"
__name__ = 'account.revaluate.start' __name__ = 'account.revaluate.start'
revaluation_date = fields.Date( revaluation_date = fields.Date(
@@ -1902,5 +2029,64 @@ class RevaluateStart(ModelView):
return Date.today() return Date.today()
@classmethod @classmethod
def default_delete_after(cls): def default_delete_after(cls):
return False return False
class ShipmentTemplateReportMixin:
@classmethod
def _get_purchase_trade_configuration(cls):
Configuration = Pool().get('purchase_trade.configuration')
configurations = Configuration.search([], limit=1)
return configurations[0] if configurations else None
@classmethod
def _get_action_report_path(cls, action):
if isinstance(action, dict):
return action.get('report') or ''
return getattr(action, 'report', '') or ''
@classmethod
def _resolve_template_path(cls, field_name, default_prefix):
config = cls._get_purchase_trade_configuration()
template = getattr(config, field_name, '') if config else ''
template = (template or '').strip()
if not template:
raise UserError('No template found')
if '/' not in template:
return f'{default_prefix}/{template}'
return template
@classmethod
def _get_resolved_action(cls, action):
report_path = cls._resolve_configured_report_path(action)
if isinstance(action, dict):
resolved = dict(action)
resolved['report'] = report_path
return resolved
setattr(action, 'report', report_path)
return action
@classmethod
def _execute(cls, records, header, data, action):
resolved_action = cls._get_resolved_action(action)
return super()._execute(records, header, data, resolved_action)
class ShipmentShippingReport(ShipmentTemplateReportMixin, BaseSupplierShipping):
__name__ = 'stock.shipment.in.shipping'
@classmethod
def _resolve_configured_report_path(cls, action):
return cls._resolve_template_path(
'shipment_shipping_report_template', 'stock')
class ShipmentInsuranceReport(ShipmentTemplateReportMixin, BaseSupplierShipping):
__name__ = 'stock.shipment.in.insurance'
@classmethod
def _resolve_configured_report_path(cls, action):
return cls._resolve_template_path(
'shipment_insurance_report_template', 'stock')

View File

@@ -56,10 +56,22 @@ this repository contains the full copyright notices and license terms. -->
<field name="model">stock.shipment.in,-1</field> <field name="model">stock.shipment.in,-1</field>
<field name="action" ref="act_vf"/> <field name="action" ref="act_vf"/>
</record> </record>
<record model="ir.action.url" id="url_vessel_finder"> <record model="ir.action.url" id="url_vessel_finder">
<field name="name">Find Vessel</field> <field name="name">Find Vessel</field>
<field name="url">https://www.vesselfinder.com</field> <field name="url">https://www.vesselfinder.com</field>
</record> </record>
<record model="ir.action.report" id="report_shipment_in_insurance">
<field name="name">Insurance</field>
<field name="model">stock.shipment.in</field>
<field name="report_name">stock.shipment.in.insurance</field>
<field name="report">stock/insurance.fodt</field>
</record>
<record model="ir.action.keyword" id="report_shipment_in_insurance_keyword">
<field name="keyword">form_print</field>
<field name="model">stock.shipment.in,-1</field>
<field name="action" ref="report_shipment_in_insurance"/>
</record>
<record model="ir.action.wizard" id="act_update_sof"> <record model="ir.action.wizard" id="act_update_sof">
<field name="name">Update with SoF PDF</field> <field name="name">Update with SoF PDF</field>
@@ -126,4 +138,4 @@ this repository contains the full copyright notices and license terms. -->
id="menu_revaluate"/> id="menu_revaluate"/>
</data> </data>
</tryton> </tryton>

View File

@@ -419,6 +419,96 @@ class PurchaseTradeTestCase(ModuleTestCase):
}), }),
'purchase/purchase_melya.fodt') 'purchase/purchase_melya.fodt')
def test_shipment_reports_use_templates_from_configuration(self):
'shipment report paths are resolved from purchase_trade configuration'
shipping_report = Pool().get('stock.shipment.in.shipping', type='report')
insurance_report = Pool().get('stock.shipment.in.insurance', type='report')
config_model = Mock()
config_model.search.return_value = [
Mock(
shipment_shipping_report_template='si_custom.fodt',
shipment_insurance_report_template='insurance_custom.fodt',
)
]
with patch(
'trytond.modules.purchase_trade.stock.Pool'
) as PoolMock:
PoolMock.return_value.get.return_value = config_model
self.assertEqual(
shipping_report._resolve_configured_report_path({
'name': 'Shipping instructions',
'report': 'stock/si.fodt',
}),
'stock/si_custom.fodt')
self.assertEqual(
insurance_report._resolve_configured_report_path({
'name': 'Insurance',
'report': 'stock/insurance.fodt',
}),
'stock/insurance_custom.fodt')
def test_shipment_insurance_helpers_use_fee_and_controller(self):
'shipment insurance helpers read insurance fee and shipment context'
ShipmentIn = Pool().get('stock.shipment.in')
shipment = ShipmentIn()
shipment.number = 'IN/0001'
shipment.bl_number = 'BL-001'
shipment.from_location = Mock(name='LIVERPOOL')
shipment.to_location = Mock(name='LE HAVRE')
shipment.vessel = Mock(vessel_name='MV ATLANTIC')
shipment.controller = Mock(rec_name='CONTROL UNION')
shipment.supplier = Mock(rec_name='MELYA SA')
sale_party = Mock(rec_name='SGT FR')
sale = Mock(party=sale_party)
product = Mock(name='COTTON UPLAND', description='RAW WHITE COTTON')
line = Mock(product=product, sale=sale)
lot = Mock(sale_line=line, line=None)
move = Mock(lot=lot, product=product)
shipment.incoming_moves = [move]
shipment.moves = [move]
insurance_fee = Mock()
insurance_fee.product = Mock(name='Insurance')
insurance_fee.currency = Mock(rec_name='USD')
insurance_fee.get_amount.return_value = Decimal('1234.56')
insurance_fee.supplier = Mock(rec_name='HELVETIA')
shipment.fees = [insurance_fee]
with patch(
'trytond.modules.purchase_trade.stock.Pool'
) as PoolMock:
date_model = Mock()
date_model.today.return_value = datetime.date(2026, 4, 6)
config_model = Mock()
PoolMock.return_value.get.side_effect = lambda name: {
'ir.date': date_model,
'purchase_trade.configuration': config_model,
}[name]
shipment.company = Mock(
party=Mock(
rec_name='MELYA SA',
address_get=Mock(return_value=Mock(city='GENEVA')),
)
)
self.assertEqual(
shipment.report_insurance_certificate_number, 'BL-001')
self.assertEqual(
shipment.report_insurance_account_of, 'SGT FR')
self.assertEqual(
shipment.report_insurance_goods_description,
'COTTON UPLAND - RAW WHITE COTTON')
self.assertEqual(
shipment.report_insurance_amount, 'USD 1234.56')
self.assertEqual(
shipment.report_insurance_surveyor, 'CONTROL UNION')
self.assertEqual(
shipment.report_insurance_issue_place_and_date,
'GENEVA, 06-04-2026')
def test_sale_report_multi_line_helpers_aggregate_all_lines(self): def test_sale_report_multi_line_helpers_aggregate_all_lines(self):
'sale report helpers aggregate quantity, price lines and shipment periods' 'sale report helpers aggregate quantity, price lines and shipment periods'
Sale = Pool().get('sale.sale') Sale = Pool().get('sale.sale')
@@ -466,6 +556,27 @@ class PurchaseTradeTestCase(ModuleTestCase):
'USC 70.2500 PER POUND (SEVENTY USC AND TWENTY FIVE CENTS) ON ICE Cotton #2 MAY 2026', 'USC 70.2500 PER POUND (SEVENTY USC AND TWENTY FIVE CENTS) ON ICE Cotton #2 MAY 2026',
]) ])
def test_report_product_fields_expose_name_and_description(self):
'sale and invoice templates use stable product name/description helpers'
Sale = Pool().get('sale.sale')
Invoice = Pool().get('account.invoice')
product = Mock(name='COTTON UPLAND', description='RAW WHITE COTTON')
sale_line = Mock(product=product)
invoice_line = Mock(product=product)
sale = Sale()
sale.lines = [sale_line]
invoice = Invoice()
invoice.lines = [invoice_line]
invoice._get_report_trade_line = Mock(return_value=sale_line)
self.assertEqual(sale.report_product_name, 'COTTON UPLAND')
self.assertEqual(sale.report_product_description, 'RAW WHITE COTTON')
self.assertEqual(invoice.report_product_name, 'COTTON UPLAND')
self.assertEqual(invoice.report_product_description, 'RAW WHITE COTTON')
def test_contract_factory_uses_one_line_per_selected_source(self): def test_contract_factory_uses_one_line_per_selected_source(self):
'matched multi-lot contract creation keeps one generated line per source lot' 'matched multi-lot contract creation keeps one generated line per source lot'
contract_detail = Mock(quantity=Decimal('2000')) contract_detail = Mock(quantity=Decimal('2000'))

View File

@@ -19,4 +19,10 @@
<separator id="purchase_templates" string="Purchase" colspan="4"/> <separator id="purchase_templates" string="Purchase" colspan="4"/>
<label name="purchase_report_template"/> <label name="purchase_report_template"/>
<field name="purchase_report_template" colspan="3"/> <field name="purchase_report_template" colspan="3"/>
<separator id="shipment_templates" string="Shipment" colspan="4"/>
<label name="shipment_shipping_report_template"/>
<field name="shipment_shipping_report_template" colspan="3"/>
<label name="shipment_insurance_report_template"/>
<field name="shipment_insurance_report_template" colspan="3"/>
</form> </form>

View File

@@ -1763,8 +1763,8 @@
<text:p text:style-name="P25" loext:marker-style-name="T39"/> <text:p text:style-name="P25" loext:marker-style-name="T39"/>
<text:p text:style-name="P24" loext:marker-style-name="T39"/> <text:p text:style-name="P24" loext:marker-style-name="T39"/>
<text:p text:style-name="P24" loext:marker-style-name="T39"/> <text:p text:style-name="P24" loext:marker-style-name="T39"/>
<text:p text:style-name="P39" loext:marker-style-name="T26"><text:span text:style-name="T26"><text:s text:c="2"/></text:span><text:span text:style-name="T42"><text:placeholder text:placeholder-type="text">&lt;sale.lines[0].product.name if sale.lines and sale.lines[0].product else &apos;&apos;&gt;</text:placeholder></text:span></text:p> <text:p text:style-name="P39" loext:marker-style-name="T26"><text:span text:style-name="T26"><text:s text:c="2"/></text:span><text:span text:style-name="T42"><text:placeholder text:placeholder-type="text">&lt;sale.report_product_name or &apos;&apos;&gt;</text:placeholder></text:span></text:p>
<text:p text:style-name="P30" loext:marker-style-name="T26"/> <text:p text:style-name="P30" loext:marker-style-name="T26"><text:span text:style-name="T42"><text:placeholder text:placeholder-type="text">&lt;sale.report_product_description or &apos;&apos;&gt;</text:placeholder></text:span></text:p>
<text:p text:style-name="P27" loext:marker-style-name="T42"><text:span text:style-name="T42"><text:s/></text:span></text:p> <text:p text:style-name="P27" loext:marker-style-name="T42"><text:span text:style-name="T42"><text:s/></text:span></text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau1.B2" office:value-type="string"> <table:table-cell table:style-name="Tableau1.B2" office:value-type="string">
@@ -1803,7 +1803,7 @@
<text:p text:style-name="P2"/> <text:p text:style-name="P2"/>
<text:p text:style-name="P7">PAYMENT TERMS:<text:tab/><text:placeholder text:placeholder-type="text">&lt;sale.payment_term.description if sale.payment_term else &apos;&apos;&gt;</text:placeholder></text:p> <text:p text:style-name="P7">PAYMENT TERMS:<text:tab/><text:placeholder text:placeholder-type="text">&lt;sale.payment_term.description if sale.payment_term else &apos;&apos;&gt;</text:placeholder></text:p>
<text:p text:style-name="P2"/> <text:p text:style-name="P2"/>
<text:p text:style-name="P8">Bank: UBS SWITZERLAND AG</text:p> <text:p text:style-name="P8">BANK: UBS SWITZERLAND AG</text:p>
<text:p text:style-name="P8">Case Postale</text:p> <text:p text:style-name="P8">Case Postale</text:p>
<text:p text:style-name="P8">CH-1211 Geneve 2</text:p> <text:p text:style-name="P8">CH-1211 Geneve 2</text:p>
<text:p text:style-name="P2"/> <text:p text:style-name="P2"/>

1075
modules/stock/insurance.fodt Normal file

File diff suppressed because it is too large Load Diff