Contract clauses

This commit is contained in:
2026-05-31 23:33:25 +02:00
parent d483e7cf69
commit e9a8355587
17 changed files with 639 additions and 16 deletions

View File

@@ -125,6 +125,10 @@ def register():
stock.CharterConditionRate,
stock.CharterCondition,
stock.CharterParty,
purchase.ContractClause,
purchase.ContractTemplate,
purchase.ContractTemplateLine,
purchase.ContractClauseSelection,
purchase.Purchase,
purchase.Line,
purchase.Estimated,
@@ -267,6 +271,7 @@ def register():
purchase.PurchaseCrop,
module='lot', type_='model')
Pool.register(
sale.ContractClauseSelection,
sale.CharterCondition,
sale.Sale,
sale.SaleLine,

View File

@@ -17,10 +17,11 @@ from sql.functions import CurrentTimestamp, DateTrunc, Abs
from trytond.wizard import Button, StateTransition, StateView, Wizard, StateAction
from itertools import chain, groupby
from operator import itemgetter
import datetime
import logging
import json
import jwt
import datetime
import logging
import json
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
@@ -262,6 +263,14 @@ class Purchase(metaclass=PoolMeta):
btb = fields.Many2One('back.to.back',"Back to back")
charter_conditions = fields.One2Many(
'charter.condition', 'purchase', "Charter Conditions")
contract_template = fields.Many2One(
'contract.template', "Contract Template",
domain=[
('direction', 'in', ['both', 'purchase']),
('active', '=', True),
])
contract_clauses = fields.One2Many(
'contract.clause.selection', 'purchase', "Contract Clauses")
bank_accounts = fields.Function(
fields.Many2Many('bank.account', None, None, "Bank Accounts"),
'on_change_with_bank_accounts')
@@ -731,10 +740,36 @@ class Purchase(metaclass=PoolMeta):
if line.price_type == 'efp':
if line.derivatives:
for d in line.derivatives:
line.unit_price = round(Decimal(d.price_index.get_price(Date.today(),line.unit,line.currency,True)),4)
logger.info("EFP_PRICE:%s",line.unit_price)
Line.save([line])
line.unit_price = round(Decimal(d.price_index.get_price(Date.today(),line.unit,line.currency,True)),4)
logger.info("EFP_PRICE:%s",line.unit_price)
Line.save([line])
def _contract_clause_values_from_template(self, direction):
values = []
template = getattr(self, 'contract_template', None)
if not template:
return values
for template_line in sorted(
template.lines or [], key=lambda line: line.sequence or 0):
clause = template_line.clause
if not clause or not clause.matches_contract(self, direction):
continue
values.append(ContractClauseSelection(
sequence=template_line.sequence,
section=template_line.section or clause.category,
clause=clause,
selected=not template_line.optional,
optional=template_line.optional,
))
return values
@fields.depends('contract_template', 'contract_clauses', 'incoterm',
'payment_term', 'lines')
def on_change_contract_template(self):
if self.contract_template:
self.contract_clauses = self._contract_clause_values_from_template(
'purchase')
class PriceComposition(ModelSQL,ModelView):
"Price Composition"
__name__ = 'price.composition'
@@ -786,8 +821,257 @@ class PremiumComposition(ModelSQL, ModelView):
return round(Currency.compute(
currency, amount, contract_currency), 6)
return round(Currency.compute(currency, amount, contract_currency), 6)
class AssayImporter:
CONTRACT_CLAUSE_CATEGORIES = [
(None, ''),
('payment', 'Payment'),
('delivery', 'Delivery'),
('transport', 'Transport'),
('documents', 'Documents'),
('quality', 'Quality'),
('quantity', 'Quantity'),
('price', 'Price'),
('insurance', 'Insurance'),
('title_transfer', 'Title Transfer'),
('charter', 'Charter / Demurrage'),
('tax', 'Tax'),
('sanctions', 'Sanctions'),
('force_majeure', 'Force Majeure'),
('law', 'Law / Arbitration'),
('other', 'Other'),
]
class ContractClause(ModelSQL, ModelView):
"Contract Clause"
__name__ = 'contract.clause'
name = fields.Char("Name", required=True)
category = fields.Selection(CONTRACT_CLAUSE_CATEGORIES, "Category")
direction = fields.Selection([
('both', 'Purchase & Sale'),
('purchase', 'Purchase'),
('sale', 'Sale'),
], "Direction", required=True)
active = fields.Boolean("Active")
version = fields.Char("Version")
language = fields.Char("Language")
source = fields.Char("Source")
text = fields.Text("Text", required=True)
incoterm = fields.Many2One('incoterm.incoterm', "Incoterm")
product = fields.Many2One('product.product', "Product")
payment_term = fields.Many2One(
'account.invoice.payment_term', "Payment Term")
transport_type = fields.Selection([
(None, ''),
('vessel', 'Vessel'),
('truck', 'Truck'),
('other', 'Other'),
], "Transport Type")
cargo_mode = fields.Selection([
(None, ''),
('bulk', 'Bulk'),
('container', 'Container'),
], "Cargo Mode")
variables = fields.Function(
fields.Char("Variables"), 'get_variables')
@staticmethod
def default_active():
return True
@staticmethod
def default_direction():
return 'both'
def get_variables(self, name=None):
variables = sorted(set(re.findall(
r'\[([A-Za-z0-9_]+)\]', self.text or '')))
return ', '.join(variables)
def matches_contract(self, contract, direction):
if self.direction not in ('both', direction):
return False
if (self.incoterm
and getattr(getattr(contract, 'incoterm', None), 'id', None)
!= self.incoterm.id):
return False
if (self.payment_term
and getattr(getattr(contract, 'payment_term', None), 'id', None)
!= self.payment_term.id):
return False
if self.product:
products = {
getattr(getattr(line, 'product', None), 'id', None)
for line in getattr(contract, 'lines', []) or []
if getattr(line, 'type', 'line') == 'line'
}
if self.product.id not in products:
return False
if (self.transport_type
and getattr(contract, 'transport_type', None)
!= self.transport_type):
return False
if self.cargo_mode and getattr(contract, 'cargo_mode', None) != self.cargo_mode:
return False
return True
class ContractTemplate(ModelSQL, ModelView):
"Contract Template"
__name__ = 'contract.template'
name = fields.Char("Name", required=True)
direction = fields.Selection([
('both', 'Purchase & Sale'),
('purchase', 'Purchase'),
('sale', 'Sale'),
], "Direction", required=True)
active = fields.Boolean("Active")
incoterm = fields.Many2One('incoterm.incoterm', "Incoterm")
product = fields.Many2One('product.product', "Product")
payment_term = fields.Many2One(
'account.invoice.payment_term', "Payment Term")
transport_type = fields.Selection([
(None, ''),
('vessel', 'Vessel'),
('truck', 'Truck'),
('other', 'Other'),
], "Transport Type")
cargo_mode = fields.Selection([
(None, ''),
('bulk', 'Bulk'),
('container', 'Container'),
], "Cargo Mode")
lines = fields.One2Many(
'contract.template.line', 'template', "Clauses")
notes = fields.Text("Notes")
@staticmethod
def default_active():
return True
@staticmethod
def default_direction():
return 'both'
def matches_contract(self, contract, direction):
if self.direction not in ('both', direction):
return False
if (self.incoterm
and getattr(getattr(contract, 'incoterm', None), 'id', None)
!= self.incoterm.id):
return False
if (self.payment_term
and getattr(getattr(contract, 'payment_term', None), 'id', None)
!= self.payment_term.id):
return False
if self.product:
products = {
getattr(getattr(line, 'product', None), 'id', None)
for line in getattr(contract, 'lines', []) or []
if getattr(line, 'type', 'line') == 'line'
}
if self.product.id not in products:
return False
if (self.transport_type
and getattr(contract, 'transport_type', None)
!= self.transport_type):
return False
if self.cargo_mode and getattr(contract, 'cargo_mode', None) != self.cargo_mode:
return False
return True
class ContractTemplateLine(ModelSQL, ModelView):
"Contract Template Line"
__name__ = 'contract.template.line'
template = fields.Many2One(
'contract.template', "Template", required=True, ondelete='CASCADE')
sequence = fields.Integer("Sequence")
section = fields.Selection(CONTRACT_CLAUSE_CATEGORIES, "Section")
clause = fields.Many2One('contract.clause', "Clause", required=True)
optional = fields.Boolean("Optional")
@staticmethod
def default_sequence():
return 10
class ContractClauseSelection(ModelSQL, ModelView):
"Contract Clause Selection"
__name__ = 'contract.clause.selection'
purchase = fields.Many2One(
'purchase.purchase', "Purchase", ondelete='CASCADE')
sequence = fields.Integer("Sequence")
section = fields.Selection(CONTRACT_CLAUSE_CATEGORIES, "Section")
clause = fields.Many2One('contract.clause', "Clause", required=True)
selected = fields.Boolean("Selected")
optional = fields.Boolean("Optional")
text_override = fields.Text("Override")
rendered_text = fields.Function(
fields.Text("Rendered Text"), 'get_rendered_text')
@staticmethod
def default_sequence():
return 10
@staticmethod
def default_selected():
return True
def _get_contract(self):
return getattr(self, 'purchase', None) or getattr(self, 'sale', None)
def _get_render_context(self):
contract = self._get_contract()
if not contract:
return {}
lines = [
line for line in getattr(contract, 'lines', []) or []
if getattr(line, 'type', 'line') == 'line']
products = ', '.join(filter(None, [
getattr(getattr(line, 'product', None), 'rec_name', None)
for line in lines]))
quantities = ', '.join(filter(None, [
str(getattr(line, 'quantity', '') or '')
for line in lines]))
units = ', '.join(filter(None, [
getattr(getattr(line, 'unit', None), 'rec_name', None)
for line in lines]))
return {
'Contract_Number': (
getattr(contract, 'reference', None)
or getattr(contract, 'number', None) or ''),
'reference': getattr(contract, 'reference', None) or '',
'party': getattr(getattr(contract, 'party', None), 'rec_name', None) or '',
'company': getattr(getattr(contract, 'company', None), 'rec_name', None) or '',
'currency': getattr(getattr(contract, 'currency', None), 'rec_name', None) or '',
'incoterm': getattr(getattr(contract, 'incoterm', None), 'code', None) or '',
'incoterm_location': getattr(getattr(contract, 'incoterm_location', None), 'rec_name', None) or '',
'payment_term': getattr(getattr(contract, 'payment_term', None), 'rec_name', None) or '',
'product': products,
'quantity': quantities,
'unit': units,
'product_origin': getattr(contract, 'product_origin', None) or '',
'del_from': str(getattr(contract, 'del_from', '') or ''),
'del_to': str(getattr(contract, 'del_to', '') or ''),
}
def get_rendered_text(self, name=None):
text = self.text_override or getattr(self.clause, 'text', '') or ''
context = self._get_render_context()
def replace(match):
key = match.group(1)
return str(context.get(key, match.group(0)))
return re.sub(r'\[([A-Za-z0-9_]+)\]', replace, text)
class AssayImporter:
def __init__(self):
pool = Pool()

View File

@@ -172,6 +172,105 @@ this repository contains the full copyright notices and license terms. -->
<field name="name">premium_composition_form</field>
</record>
<record model="ir.ui.view" id="contract_clause_view_tree">
<field name="model">contract.clause</field>
<field name="type">tree</field>
<field name="name">contract_clause_tree</field>
</record>
<record model="ir.ui.view" id="contract_clause_view_form">
<field name="model">contract.clause</field>
<field name="type">form</field>
<field name="name">contract_clause_form</field>
</record>
<record model="ir.ui.view" id="contract_template_view_tree">
<field name="model">contract.template</field>
<field name="type">tree</field>
<field name="name">contract_template_tree</field>
</record>
<record model="ir.ui.view" id="contract_template_view_form">
<field name="model">contract.template</field>
<field name="type">form</field>
<field name="name">contract_template_form</field>
</record>
<record model="ir.ui.view" id="contract_template_line_view_tree">
<field name="model">contract.template.line</field>
<field name="type">tree</field>
<field name="name">contract_template_line_tree</field>
</record>
<record model="ir.ui.view" id="contract_template_line_view_form">
<field name="model">contract.template.line</field>
<field name="type">form</field>
<field name="name">contract_template_line_form</field>
</record>
<record model="ir.ui.view" id="contract_clause_selection_view_tree">
<field name="model">contract.clause.selection</field>
<field name="type">tree</field>
<field name="name">contract_clause_selection_tree</field>
</record>
<record model="ir.ui.view" id="contract_clause_selection_view_form">
<field name="model">contract.clause.selection</field>
<field name="type">form</field>
<field name="name">contract_clause_selection_form</field>
</record>
<record model="ir.action.act_window" id="act_contract_clause_form">
<field name="name">Contract Clauses</field>
<field name="res_model">contract.clause</field>
</record>
<record model="ir.action.act_window.view" id="act_contract_clause_form_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="contract_clause_view_tree"/>
<field name="act_window" ref="act_contract_clause_form"/>
</record>
<record model="ir.action.act_window.view" id="act_contract_clause_form_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="contract_clause_view_form"/>
<field name="act_window" ref="act_contract_clause_form"/>
</record>
<record model="ir.action.act_window" id="act_contract_template_form">
<field name="name">Contract Templates</field>
<field name="res_model">contract.template</field>
</record>
<record model="ir.action.act_window.view" id="act_contract_template_form_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="contract_template_view_tree"/>
<field name="act_window" ref="act_contract_template_form"/>
</record>
<record model="ir.action.act_window.view" id="act_contract_template_form_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="contract_template_view_form"/>
<field name="act_window" ref="act_contract_template_form"/>
</record>
<record model="ir.model.access" id="access_contract_clause">
<field name="model">contract.clause</field>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.model.access" id="access_contract_template">
<field name="model">contract.template</field>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.model.access" id="access_contract_template_line">
<field name="model">contract.template.line</field>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.model.access" id="access_contract_clause_selection">
<field name="model">contract.clause.selection</field>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.ui.view" id="quality_analysis_view_tree">
<field name="model">quality.analysis</field>
<field name="type">tree</field>
@@ -251,10 +350,22 @@ this repository contains the full copyright notices and license terms. -->
sequence="120"
id="menu_position_bi"/>
<menuitem
<menuitem
parent="purchase_trade.menu_ctrm_other"
sequence="100"
action="act_pur_inv_report_form"
id="menu_pur_inv_report_form"/>
</data>
sequence="100"
action="act_pur_inv_report_form"
id="menu_pur_inv_report_form"/>
<menuitem
name="Contract Clauses"
parent="document_incoming.menu_configuration"
sequence="30"
action="act_contract_clause_form"
id="menu_contract_clause_form"/>
<menuitem
name="Contract Templates"
parent="document_incoming.menu_configuration"
sequence="31"
action="act_contract_template_form"
id="menu_contract_template_form"/>
</data>
</tryton>

View File

@@ -227,6 +227,14 @@ class Sale(metaclass=PoolMeta):
btb = fields.Many2One('back.to.back',"Back to back")
charter_conditions = fields.One2Many(
'charter.condition', 'sale', "Charter Conditions")
contract_template = fields.Many2One(
'contract.template', "Contract Template",
domain=[
('direction', 'in', ['both', 'sale']),
('active', '=', True),
])
contract_clauses = fields.One2Many(
'contract.clause.selection', 'sale', "Contract Clauses")
bank_accounts = fields.Function(
fields.Many2Many('bank.account', None, None, "Bank Accounts"),
'on_change_with_bank_accounts')
@@ -1247,12 +1255,45 @@ class Sale(metaclass=PoolMeta):
line.unit_price = d.price_index.get_price(Date.today(),line.unit,line.currency,True)
Line.save([line])
def _contract_clause_values_from_template(self, direction):
Selection = Pool().get('contract.clause.selection')
values = []
template = getattr(self, 'contract_template', None)
if not template:
return values
for template_line in sorted(
template.lines or [], key=lambda line: line.sequence or 0):
clause = template_line.clause
if not clause or not clause.matches_contract(self, direction):
continue
values.append(Selection(
sequence=template_line.sequence,
section=template_line.section or clause.category,
clause=clause,
selected=not template_line.optional,
optional=template_line.optional,
))
return values
@fields.depends('contract_template', 'contract_clauses', 'incoterm',
'payment_term', 'lines')
def on_change_contract_template(self):
if self.contract_template:
self.contract_clauses = self._contract_clause_values_from_template(
'sale')
class PriceComposition(metaclass=PoolMeta):
__name__ = 'price.composition'
sale_line = fields.Many2One('sale.line',"Sale line")
class ContractClauseSelection(metaclass=PoolMeta):
__name__ = 'contract.clause.selection'
sale = fields.Many2One('sale.sale', "Sale", ondelete='CASCADE')
class CharterCondition(metaclass=PoolMeta):
__name__ = 'charter.condition'

View File

@@ -1946,8 +1946,13 @@ class StatementOfFacts(ModelSQL, ModelView):
timebar_day = fields.Integer("TimeBar")
timebar_warn = fields.Integer("Warning TimeBar")
charter_party = fields.Many2One('stock.charter.party', "Charter Party")
applied_conditions = fields.Function(
fields.One2Many('charter.condition', '', "Available Conditions"),
'get_applied_conditions')
applied_condition = fields.Many2One(
'charter.condition', "Applied Condition")
'charter.condition', "Applied Condition",
domain=[('id', 'in', Eval('applied_conditions', []))],
depends=['applied_conditions'])
owner_charter_conditions = fields.Function(
fields.One2Many('charter.condition', '', "Owner Conditions"),
'get_owner_charter_conditions')
@@ -2021,6 +2026,12 @@ class StatementOfFacts(ModelSQL, ModelView):
return self.shipment.get_sale_charter_conditions(name)
return []
def get_applied_conditions(self, name=None):
return ShipmentIn._unique_condition_ids(
self.get_owner_charter_conditions(name)
+ self.get_purchase_charter_conditions(name)
+ self.get_sale_charter_conditions(name))
@staticmethod
def _rate_category(rate):
rate_type = getattr(rate, 'rate_type', None)

View File

@@ -174,6 +174,40 @@ class PurchaseTradeTestCase(ModuleTestCase):
sof._applied_compensation_amount(), Decimal('-12000.00'))
self.assertEqual(sof.compensation_type, 'demurrage')
def test_contract_clause_variables_and_rendering_use_contract_context(self):
'contract clauses expose placeholders and render from purchase context'
clause = purchase_module.ContractClause()
clause.name = 'Payment'
clause.direction = 'both'
clause.text = (
'Buyer pays [party] under [incoterm] for [product] '
'contract [Contract_Number].')
self.assertEqual(
clause.get_variables('variables'),
'Contract_Number, incoterm, party, product')
selection = purchase_module.ContractClauseSelection()
selection.clause = clause
selection.purchase = Mock(
reference='PUR-001',
party=Mock(rec_name='Supplier Ltd'),
company=Mock(rec_name='Company SA'),
currency=Mock(rec_name='USD'),
incoterm=Mock(code='FOB'),
incoterm_location=None,
payment_term=None,
product_origin='',
lines=[
Mock(type='line', product=Mock(rec_name='Steel'), quantity=10,
unit=Mock(rec_name='MT')),
],
)
self.assertEqual(
selection.get_rendered_text('rendered_text'),
'Buyer pays Supplier Ltd under FOB for Steel contract PUR-001.')
@with_transaction()
def test_add_physical_lot_defaults_hidden_premium_and_chunk_key(self):
'add physical lot works when hidden tree fields are not loaded'

View File

@@ -0,0 +1,34 @@
<?xml version="1.0"?>
<form>
<label name="name"/>
<field name="name"/>
<label name="category"/>
<field name="category"/>
<label name="direction"/>
<field name="direction"/>
<label name="active"/>
<field name="active"/>
<label name="version"/>
<field name="version"/>
<label name="language"/>
<field name="language"/>
<label name="source"/>
<field name="source"/>
<newline/>
<label name="incoterm"/>
<field name="incoterm"/>
<label name="product"/>
<field name="product"/>
<label name="payment_term"/>
<field name="payment_term"/>
<label name="transport_type"/>
<field name="transport_type"/>
<label name="cargo_mode"/>
<field name="cargo_mode"/>
<newline/>
<label name="variables"/>
<field name="variables"/>
<newline/>
<label name="text"/>
<field name="text" colspan="3"/>
</form>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0"?>
<form>
<label name="sequence"/>
<field name="sequence"/>
<label name="section"/>
<field name="section"/>
<label name="clause"/>
<field name="clause"/>
<label name="selected"/>
<field name="selected"/>
<label name="optional"/>
<field name="optional"/>
<label name="text_override"/>
<field name="text_override" colspan="3"/>
<label name="rendered_text"/>
<field name="rendered_text" colspan="3"/>
</form>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0"?>
<tree>
<field name="sequence"/>
<field name="section"/>
<field name="clause"/>
<field name="selected"/>
<field name="optional"/>
</tree>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<tree>
<field name="name"/>
<field name="category"/>
<field name="direction"/>
<field name="incoterm"/>
<field name="product"/>
<field name="payment_term"/>
<field name="active"/>
</tree>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0"?>
<form>
<label name="name"/>
<field name="name"/>
<label name="direction"/>
<field name="direction"/>
<label name="active"/>
<field name="active"/>
<newline/>
<label name="incoterm"/>
<field name="incoterm"/>
<label name="product"/>
<field name="product"/>
<label name="payment_term"/>
<field name="payment_term"/>
<label name="transport_type"/>
<field name="transport_type"/>
<label name="cargo_mode"/>
<field name="cargo_mode"/>
<notebook colspan="4">
<page string="Clauses" id="clauses">
<field name="lines" colspan="4" mode="tree,form" view_ids="purchase_trade.contract_template_line_view_tree,purchase_trade.contract_template_line_view_form"/>
</page>
<page string="Notes" id="notes">
<field name="notes" colspan="4"/>
</page>
</notebook>
</form>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0"?>
<form>
<label name="sequence"/>
<field name="sequence"/>
<label name="section"/>
<field name="section"/>
<label name="clause"/>
<field name="clause"/>
<label name="optional"/>
<field name="optional"/>
</form>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0"?>
<tree>
<field name="sequence"/>
<field name="section"/>
<field name="clause"/>
<field name="optional"/>
</tree>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0"?>
<tree>
<field name="name"/>
<field name="direction"/>
<field name="incoterm"/>
<field name="product"/>
<field name="payment_term"/>
<field name="active"/>
</tree>

View File

@@ -58,6 +58,12 @@ this repository contains the full copyright notices and license terms. -->
<page string="Charter Conditions" id="charter_conditions">
<field name="charter_conditions" colspan="4" mode="tree,form" view_ids="purchase_trade.charter_condition_view_tree,purchase_trade.charter_condition_view_form"/>
</page>
<page string="Contract Clauses" col="4" id="contract_clauses">
<label name="contract_template"/>
<field name="contract_template"/>
<newline/>
<field name="contract_clauses" colspan="4" mode="tree,form" view_ids="purchase_trade.contract_clause_selection_view_tree,purchase_trade.contract_clause_selection_view_form"/>
</page>
<page string="Derivative" col="4" id="der">
<field name="derivatives" mode="tree" view_ids="purchase_trade.derivative_view_tree_sequence" height="450"/>
</page>

View File

@@ -58,6 +58,12 @@ this repository contains the full copyright notices and license terms. -->
<page string="Charter Conditions" id="charter_conditions">
<field name="charter_conditions" colspan="4" mode="tree,form" view_ids="purchase_trade.charter_condition_view_tree,purchase_trade.charter_condition_view_form"/>
</page>
<page string="Contract Clauses" col="4" id="contract_clauses">
<label name="contract_template"/>
<field name="contract_template"/>
<newline/>
<field name="contract_clauses" colspan="4" mode="tree,form" view_ids="purchase_trade.contract_clause_selection_view_tree,purchase_trade.contract_clause_selection_view_form"/>
</page>
<page string="Derivative" col="4" id="der">
<field name="derivatives" mode="tree" view_ids="purchase_trade.derivative_view_tree_sequence" height="450"/>
</page>

View File

@@ -3,6 +3,7 @@
<page string="Contract Conditions" id="cs">
<label name="charter_party"/>
<field name="charter_party"/>
<field name="applied_conditions" invisible="1" colspan="4"/>
<newline/>
<label name="applied_condition"/>
<field name="applied_condition"/>