Contract clauses
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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'
|
||||
|
||||
34
modules/purchase_trade/view/contract_clause_form.xml
Normal file
34
modules/purchase_trade/view/contract_clause_form.xml
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
10
modules/purchase_trade/view/contract_clause_tree.xml
Normal file
10
modules/purchase_trade/view/contract_clause_tree.xml
Normal 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>
|
||||
28
modules/purchase_trade/view/contract_template_form.xml
Normal file
28
modules/purchase_trade/view/contract_template_form.xml
Normal 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>
|
||||
11
modules/purchase_trade/view/contract_template_line_form.xml
Normal file
11
modules/purchase_trade/view/contract_template_line_form.xml
Normal 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>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<tree>
|
||||
<field name="sequence"/>
|
||||
<field name="section"/>
|
||||
<field name="clause"/>
|
||||
<field name="optional"/>
|
||||
</tree>
|
||||
9
modules/purchase_trade/view/contract_template_tree.xml
Normal file
9
modules/purchase_trade/view/contract_template_tree.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
Reference in New Issue
Block a user