diff --git a/modules/purchase_trade/__init__.py b/modules/purchase_trade/__init__.py
index 2374193..afa8840 100755
--- a/modules/purchase_trade/__init__.py
+++ b/modules/purchase_trade/__init__.py
@@ -280,6 +280,7 @@ def register():
invoice.PurchaseReport,
stock.ShipmentShippingReport,
stock.ShipmentInsuranceReport,
+ stock.ShipmentCOOReport,
stock.ShipmentPackingListReport,
module='purchase_trade', type_='report')
diff --git a/modules/purchase_trade/configuration.py b/modules/purchase_trade/configuration.py
index 8e9d024..503fc2a 100644
--- a/modules/purchase_trade/configuration.py
+++ b/modules/purchase_trade/configuration.py
@@ -25,6 +25,8 @@ class Configuration(ModelSingleton, ModelSQL, ModelView):
'report_shipment_in_shipping', 'Shipping instructions'),
('shipment_insurance_report_label', 'purchase_trade',
'report_shipment_in_insurance', 'Insurance'),
+ ('shipment_coo_report_label', 'purchase_trade',
+ 'report_shipment_in_coo', 'COO'),
('shipment_packing_list_report_label', 'purchase_trade',
'report_shipment_in_packing_list', 'Packing List'),
)
@@ -52,6 +54,8 @@ class Configuration(ModelSingleton, ModelSQL, ModelView):
shipment_shipping_report_label = fields.Char("Shipping Menu Label")
shipment_insurance_report_template = fields.Char("Insurance Template")
shipment_insurance_report_label = fields.Char("Insurance Menu Label")
+ shipment_coo_report_template = fields.Char("COO Template")
+ shipment_coo_report_label = fields.Char("COO Menu Label")
shipment_packing_list_report_template = fields.Char("Packing List Template")
shipment_packing_list_report_label = fields.Char(
"Packing List Menu Label")
diff --git a/modules/purchase_trade/stock.py b/modules/purchase_trade/stock.py
index 2a4c259..64d9ec1 100755
--- a/modules/purchase_trade/stock.py
+++ b/modules/purchase_trade/stock.py
@@ -792,6 +792,86 @@ class ShipmentIn(metaclass=PoolMeta):
def report_packing_net_weight(self):
net, _ = self._get_report_weight_totals()
return self._format_report_quantity(net)
+
+ @property
+ def report_coo_exporter(self):
+ company = getattr(self, 'company', None)
+ party = getattr(company, 'party', None) if company else None
+ if not party:
+ return ''
+ address = party.address_get() if hasattr(party, 'address_get') else None
+ lines = [getattr(party, 'rec_name', None) or getattr(party, 'name', None) or '']
+ if address and getattr(address, 'full_address', None):
+ lines.append(address.full_address)
+ return '\n'.join(filter(None, lines))
+
+ @property
+ def report_coo_consignee(self):
+ trade = self._get_report_trade()
+ party = getattr(trade, 'party', None) if trade else None
+ if not party:
+ return ''
+ address = party.address_get() if hasattr(party, 'address_get') else None
+ lines = [getattr(party, 'rec_name', None) or getattr(party, 'name', None) or '']
+ if address and getattr(address, 'full_address', None):
+ lines.append(address.full_address)
+ return '\n'.join(filter(None, lines))
+
+ @property
+ def report_coo_number(self):
+ return getattr(self, 'reference', None) or self.number or ''
+
+ @property
+ def report_coo_transport(self):
+ parts = []
+ if self.bl_number:
+ parts.append(f"B/L {self.bl_number}")
+ ship_name = self.report_packing_ship_name
+ if ship_name:
+ parts.append(ship_name)
+ if self.booking:
+ parts.append(f"Booking {self.booking}")
+ return ' - '.join(parts)
+
+ @property
+ def report_coo_origin_country(self):
+ return self.report_packing_origin or ''
+
+ @property
+ def report_coo_observations(self):
+ parts = []
+ contract = self.report_packing_contract_number
+ if contract:
+ parts.append(f"Contract: {contract}")
+ if self.note:
+ parts.append(self.note)
+ return '\n'.join(filter(None, parts))
+
+ @property
+ def report_coo_goods_description(self):
+ parts = [self.report_product_name, self.report_product_description]
+ if self.container:
+ container_numbers = ', '.join(
+ filter(None, (getattr(c, 'container_no', None) or '' for c in self.container)))
+ if container_numbers:
+ parts.append(f"Container(s): {container_numbers}")
+ return '\n'.join(filter(None, parts))
+
+ @property
+ def report_coo_net_weight(self):
+ return self.report_packing_net_weight
+
+ @property
+ def report_coo_gross_weight(self):
+ return self.report_packing_gross_weight
+
+ @property
+ def report_coo_issue_date(self):
+ Date = Pool().get('ir.date')
+ today = Date.today()
+ if not today:
+ return ''
+ return today.strftime('%d-%m-%Y')
def get_rec_name(self, name=None):
if self.number:
@@ -2310,3 +2390,12 @@ class ShipmentPackingListReport(ShipmentTemplateReportMixin, BaseSupplierShippin
def _resolve_configured_report_path(cls, action):
return cls._resolve_template_path(
'shipment_packing_list_report_template', 'stock')
+
+
+class ShipmentCOOReport(ShipmentTemplateReportMixin, BaseSupplierShipping):
+ __name__ = 'stock.shipment.in.coo'
+
+ @classmethod
+ def _resolve_configured_report_path(cls, action):
+ return cls._resolve_template_path(
+ 'shipment_coo_report_template', 'stock')
diff --git a/modules/purchase_trade/stock.xml b/modules/purchase_trade/stock.xml
index 99a2eec..8a0e02d 100755
--- a/modules/purchase_trade/stock.xml
+++ b/modules/purchase_trade/stock.xml
@@ -78,6 +78,18 @@ this repository contains the full copyright notices and license terms. -->
+
+ COO
+ stock.shipment.in
+ stock.shipment.in.coo
+ stock/coo.fodt
+
+
+ form_print
+ stock.shipment.in,-1
+
+
+
Packing List
stock.shipment.in
diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py
index adb3a4a..3afdcbc 100644
--- a/modules/purchase_trade/tests/test_module.py
+++ b/modules/purchase_trade/tests/test_module.py
@@ -1077,12 +1077,14 @@ class PurchaseTradeTestCase(ModuleTestCase):
'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')
+ coo_report = Pool().get('stock.shipment.in.coo', type='report')
packing_report = Pool().get('stock.shipment.in.packing_list', 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',
+ shipment_coo_report_template='coo_custom.fodt',
shipment_packing_list_report_template='packing_list_custom.fodt',
)
]
@@ -1104,6 +1106,12 @@ class PurchaseTradeTestCase(ModuleTestCase):
'report': 'stock/insurance.fodt',
}),
'stock/insurance_custom.fodt')
+ self.assertEqual(
+ coo_report._resolve_configured_report_path({
+ 'name': 'COO',
+ 'report': 'stock/coo.fodt',
+ }),
+ 'stock/coo_custom.fodt')
self.assertEqual(
packing_report._resolve_configured_report_path({
'name': 'Packing List',
@@ -1125,6 +1133,7 @@ class PurchaseTradeTestCase(ModuleTestCase):
purchase_report_label='',
shipment_shipping_report_label='',
shipment_insurance_report_label='',
+ shipment_coo_report_label='Certificate of Origin',
shipment_packing_list_report_label='',
)
action_sale = Mock(spec=['name'])
@@ -1147,6 +1156,8 @@ class PurchaseTradeTestCase(ModuleTestCase):
action_shipping.name = 'Shipping instructions'
action_insurance = Mock(spec=['name'])
action_insurance.name = 'Insurance'
+ action_coo = Mock(spec=['name'])
+ action_coo.name = 'COO'
action_packing = Mock(spec=['name'])
action_packing.name = 'Packing List'
actions = {
@@ -1160,7 +1171,8 @@ class PurchaseTradeTestCase(ModuleTestCase):
8: action_purchase,
9: action_shipping,
10: action_insurance,
- 11: action_packing,
+ 11: action_coo,
+ 12: action_packing,
}
model_data = Mock()
@@ -1188,6 +1200,7 @@ class PurchaseTradeTestCase(ModuleTestCase):
[actions[2]], {'name': 'Draft'},
[actions[7]], {'name': 'Packing Slip'},
[actions[6]], {'name': 'Wire Order'},
+ [actions[11]], {'name': 'Certificate of Origin'},
))
def test_shipment_insurance_helpers_use_fee_and_controller(self):
diff --git a/modules/purchase_trade/view/template_configuration_form.xml b/modules/purchase_trade/view/template_configuration_form.xml
index 945e5d2..70932f7 100644
--- a/modules/purchase_trade/view/template_configuration_form.xml
+++ b/modules/purchase_trade/view/template_configuration_form.xml
@@ -51,6 +51,10 @@
+
+
+
+
diff --git a/modules/stock/coo.fodt b/modules/stock/coo.fodt
new file mode 100644
index 0000000..ae6e592
--- /dev/null
+++ b/modules/stock/coo.fodt
@@ -0,0 +1,328 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Exportateur
+ Exporteur / Esportatore / Exporter
+ <records[0].report_coo_exporter or ''>
+
+
+
+
+
+
+ No. / Nr. : <records[0].report_coo_number or ''>
+ CERTIFICAT D'ORIGINE
+ URSPRUNGSZEUGNIS
+ CERTIFICATO D'ORIGINE
+ CERTIFICATE OF ORIGIN
+
+
+
+
+
+
+ Destinataire
+ Empfänger / Destinatario / Consignee
+ <records[0].report_coo_consignee or ''>
+
+
+
+
+ CONFÉDÉRATION SUISSE
+ SCHWEIZERISCHE EIDGENOSSENSCHAFT
+ CONFEDERAZIONE SVIZZERA
+ SWISS CONFEDERATION
+
+
+
+
+
+
+ Informations relatives au transport (mention facultative)
+ Angaben über die Beförderung (Ausfüllung freigestellt)
+ Informazioni riguardanti il trasporto (indicazione facoltativa)
+ Particulars of transport (optional declaration)
+ <records[0].report_coo_transport or ''>
+
+
+
+ Pays d'origine
+ Ursprungsland / Paese d'origine / Country of origin
+ <records[0].report_coo_origin_country or ''>
+
+ Observations
+ Bemerkungen / Osservazioni / Observations
+ <records[0].report_coo_observations or ''>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Marques, numéros, nombre et nature des colis ; désignation des marchandises
+ Zeichen, Nummern, Anzahl und Art der Packstücke; Warenbezeichnung
+ Marche, numeri, numero e natura dei colli; designazione delle merci
+ Marks, numbers, number and kind of packages; description of the goods
+
+
+ Poids net
+ Nettogewicht
+ Peso netto
+ Net weight
+ kg, l, m², etc.
+
+
+
+
+
+
+ <records[0].report_coo_goods_description or ''>
+
+
+
+ <records[0].report_coo_net_weight or ''>
+ <records[0].report_coo_gross_weight or ''>
+
+
+
+
+ Poids brut
+ Bruttogewicht
+ Peso lordo
+ Gross weight
+
+
+
+
+
+
+
+
+
+
+
+
+
+ La Chambre de commerce soussignée certifie l'origine des marchandises désignées ci-dessus
+ Die unterzeichnete Handelskammer bescheinigt den Ursprung oben bezeichneter Ware
+ La sottoscritta Camera di commercio certifica l'origine delle merci summenzionate
+ The undersigned Chamber of commerce certifies the origin of the above mentioned goods
+
+
+
+
+
+
+
+
+
+ Genève, le <records[0].report_coo_issue_date or ''>
+
+
+ Chambre de commerce, d'industrie et des services de Genève
+ Genfer Industrie-, Dienstleistungs- und Handelskammer
+ Camera di commercio, dell'industria e dei servizi di Ginevra
+ Chamber of commerce, industry and services of Geneva
+
+
+
+
+
+
+
+
+
+
+