diff --git a/modules/trade_finance/__init__.py b/modules/trade_finance/__init__.py
index 92b2408..f8db5d4 100644
--- a/modules/trade_finance/__init__.py
+++ b/modules/trade_finance/__init__.py
@@ -13,6 +13,7 @@ from . import (
fx,
operational,
facility,
+ constraint_type,
)
@@ -36,7 +37,9 @@ def register():
fx.FxFeeder,
operational.BlockingReason,
operational.ChargeType,
+ facility.FacilityStatus,
facility.Facility,
+ facility.FacilityCurrency,
facility.FacilityCovenant,
facility.FacilityLimit,
facility.FacilityLimitHaircut,
@@ -48,6 +51,7 @@ def register():
facility.FacilityCap,
facility.FacilityCapHaircut,
facility.FacilityConstraint,
+ constraint_type.ConstraintType,
module='trade_finance', type_='model')
Pool.register(
fx.PriceCalendar,
diff --git a/modules/trade_finance/constraint_type.py b/modules/trade_finance/constraint_type.py
new file mode 100644
index 0000000..cba3f8e
--- /dev/null
+++ b/modules/trade_finance/constraint_type.py
@@ -0,0 +1,24 @@
+# This file is part of Tradon. The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+
+from trytond.model import ModelSQL, ModelView, fields
+from trytond.pyson import Eval
+
+__all__ = ['ConstraintType']
+
+
+class ConstraintType(ModelSQL, ModelView):
+ 'Constraint Type'
+ __name__ = 'trade_finance.constraint_type'
+ _rec_name = 'name'
+
+ name = fields.Char('Type', required=True, size=50)
+ model = fields.Many2One('ir.model', 'Table', ondelete='RESTRICT')
+ value_field = fields.Many2One('ir.model.field', 'Value Field',
+ ondelete='RESTRICT',
+ domain=[('model', '=', Eval('model'))],
+ depends=['model'])
+ label_field = fields.Many2One('ir.model.field', 'Label Field',
+ ondelete='RESTRICT',
+ domain=[('model', '=', Eval('model'))],
+ depends=['model'])
diff --git a/modules/trade_finance/constraint_type.xml b/modules/trade_finance/constraint_type.xml
new file mode 100644
index 0000000..9f5dd2f
--- /dev/null
+++ b/modules/trade_finance/constraint_type.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+ trade_finance.constraint_type
+ tree
+
+ constraint_type_tree
+
+
+ trade_finance.constraint_type
+ form
+ constraint_type_form
+
+
+ Constraint Types
+ trade_finance.constraint_type
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ trade_finance.constraint_type
+
+
+
+
+
+
+ trade_finance.constraint_type
+
+
+
+
+
+
+
+ trade_finance.constraint_type
+
+
+
+
+
+
+
+
+
diff --git a/modules/trade_finance/facility.py b/modules/trade_finance/facility.py
index 55cd8d5..215e28a 100644
--- a/modules/trade_finance/facility.py
+++ b/modules/trade_finance/facility.py
@@ -1,14 +1,16 @@
# This file is part of Tradon. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
-from trytond.model import ModelSQL, ModelView, Workflow, fields
+from trytond.model import ModelSQL, ModelView, fields
from trytond.model import sequence_ordered
from trytond.pool import Pool
-from trytond.pyson import Eval, If, Bool
+from trytond.pyson import Eval, Bool
from trytond.exceptions import UserError
__all__ = [
+ 'FacilityStatus',
'Facility',
+ 'FacilityCurrency',
'FacilityCovenant',
'FacilityLimit',
'FacilityLimitHaircut',
@@ -43,20 +45,30 @@ ATTRIBUTE_TYPES = [
('receivable_category', 'Receivable Category'),
]
-FACILITY_STATES = [
- ('draft', 'Draft'),
- ('active', 'Active'),
- ('blocked', 'Blocked'),
- ('cancelled', 'Cancelled'),
- ('closed', 'Closed'),
-]
+
+# ---------------------------------------------------------------------------
+# Facility Status (configurable reference)
+# ---------------------------------------------------------------------------
+
+class FacilityStatus(ModelSQL, ModelView):
+ 'Facility Status'
+ __name__ = 'trade_finance.facility_status'
+ _rec_name = 'name'
+
+ code = fields.Char('Code', required=True)
+ name = fields.Char('Name', required=True)
+ active = fields.Boolean('Active')
+
+ @staticmethod
+ def default_active():
+ return True
# ---------------------------------------------------------------------------
# Facility Header
# ---------------------------------------------------------------------------
-class Facility(Workflow, ModelSQL, ModelView):
+class Facility(ModelSQL, ModelView):
'TF Facility'
__name__ = 'trade_finance.facility'
_rec_name = 'name'
@@ -67,8 +79,8 @@ class Facility(Workflow, ModelSQL, ModelView):
help='Bank or fund providing this facility')
description = fields.Text('Description')
- status = fields.Selection(FACILITY_STATES, 'Status', required=True,
- readonly=True)
+ status = fields.Many2One('trade_finance.facility_status', 'Status',
+ ondelete='RESTRICT')
commitment_status = fields.Selection([
('uncommitted', 'Uncommitted'),
('committed', 'Committed'),
@@ -94,6 +106,8 @@ class Facility(Workflow, ModelSQL, ModelView):
limits = fields.One2Many('trade_finance.facility_limit', 'facility',
'Limits')
+ currencies = fields.One2Many('trade_finance.facility_currency', 'facility',
+ 'Accepted Currencies')
caps = fields.One2Many('trade_finance.facility_cap', 'facility', 'Caps')
covenants = fields.One2Many('trade_finance.facility_covenant', 'facility',
'Covenants')
@@ -101,10 +115,6 @@ class Facility(Workflow, ModelSQL, ModelView):
'facility', 'Facility Constraints',
domain=[('limit', '=', None)])
- @staticmethod
- def default_status():
- return 'draft'
-
@staticmethod
def default_commitment_status():
return 'uncommitted'
@@ -113,48 +123,23 @@ class Facility(Workflow, ModelSQL, ModelView):
def default_is_tpa():
return False
- # Workflow transitions
- _transitions = {
- ('draft', 'active'),
- ('active', 'blocked'),
- ('blocked', 'active'),
- ('active', 'cancelled'),
- ('active', 'closed'),
- ('blocked', 'cancelled'),
- ('blocked', 'closed'),
- }
- _buttons = {
- 'activate': {'invisible': Eval('status') != 'draft'},
- 'block': {'invisible': Eval('status') != 'active'},
- 'unblock': {'invisible': Eval('status') != 'blocked'},
- 'cancel': {'invisible': ~Eval('status').in_(['active', 'blocked'])},
- 'close': {'invisible': ~Eval('status').in_(['active', 'blocked'])},
- }
- @classmethod
- @Workflow.transition('active')
- def activate(cls, facilities):
- pass
+# ---------------------------------------------------------------------------
+# Facility Accepted Currency
+# ---------------------------------------------------------------------------
- @classmethod
- @Workflow.transition('blocked')
- def block(cls, facilities):
- pass
+class FacilityCurrency(ModelSQL, ModelView):
+ 'Facility Currency'
+ __name__ = 'trade_finance.facility_currency'
- @classmethod
- @Workflow.transition('active')
- def unblock(cls, facilities):
- pass
-
- @classmethod
- @Workflow.transition('cancelled')
- def cancel(cls, facilities):
- pass
-
- @classmethod
- @Workflow.transition('closed')
- def close(cls, facilities):
- pass
+ facility = fields.Many2One('trade_finance.facility', 'Facility',
+ required=True, ondelete='CASCADE')
+ currency = fields.Many2One('currency.currency', 'Currency',
+ required=True, ondelete='RESTRICT')
+ fx_haircut_formula = fields.Many2One('trade_finance.haircut_formula',
+ 'FX Haircut Formula', ondelete='RESTRICT')
+ fx_feeder = fields.Many2One('trade_finance.fx_feeder', 'FX Rate Feeder',
+ ondelete='RESTRICT')
# ---------------------------------------------------------------------------
@@ -204,6 +189,7 @@ class FacilityLimit(ModelSQL, ModelView):
'Sub-Limits')
name = fields.Char('Name', required=True)
+ alternative_name = fields.Char('Limit Alternative Name')
financing_type = fields.Many2One('trade_finance.financing_type',
'Financing Type', ondelete='RESTRICT')
amount = fields.Numeric('Amount', digits=(16, 2), required=True)
@@ -213,13 +199,6 @@ class FacilityLimit(ModelSQL, ModelView):
_order = [('sequence', 'ASC'), ('id', 'ASC')]
- is_global = fields.Function(
- fields.Boolean('Global Limit',
- states={'invisible': Bool(Eval('parent'))},
- depends=['parent']),
- 'get_is_global')
- display_name = fields.Function(fields.Char('Name'), 'get_display_name')
-
haircuts = fields.One2Many('trade_finance.facility_limit_haircut', 'limit',
'Haircuts')
currencies = fields.One2Many('trade_finance.facility_limit_currency',
@@ -247,25 +226,27 @@ class FacilityLimit(ModelSQL, ModelView):
values['facility'] = parent.facility.id
return super().create(vlist)
- def get_is_global(self, name):
- return self.parent is None
-
- def get_display_name(self, name):
- level = 0
- current = self
- while current.parent:
- level += 1
- current = current.parent
- prefix = '— ' * level
- return prefix + (self.name or '')
-
@classmethod
def validate(cls, limits):
super().validate(limits)
for limit in limits:
+ limit.check_single_root()
limit.check_amount_vs_parent()
limit.check_children_amounts()
+ def check_single_root(self):
+ if self.parent is None:
+ roots = self.__class__.search([
+ ('facility', '=', self.facility.id),
+ ('parent', '=', None),
+ ('id', '!=', self.id),
+ ])
+ if roots:
+ raise UserError(
+ f"Facility '{self.facility.name}' already has a Global "
+ f"Limit ('{roots[0].name}'). Only one root limit is "
+ f"allowed per facility.")
+
def check_amount_vs_parent(self):
if self.parent and self.amount > self.parent.amount:
raise UserError(
@@ -491,9 +472,7 @@ class FacilityConstraint(ModelSQL, ModelView):
cap = fields.Many2One('trade_finance.facility_cap', 'Cap',
ondelete='CASCADE')
- constraint_type = fields.Selection([
- ('inclusion', 'Inclusion'),
- ('exclusion', 'Exclusion'),
- ], 'Type', required=True)
- attribute = fields.Selection(ATTRIBUTE_TYPES, 'Attribute', required=True)
- value = fields.Char('Value', required=True)
+ constraint_type = fields.Many2One('trade_finance.constraint_type',
+ 'Constraint Type', required=True, ondelete='RESTRICT')
+ is_exclusion = fields.Boolean('Exclusion',
+ help='Checked = Exclusion constraint, unchecked = Inclusion constraint')
diff --git a/modules/trade_finance/facility.xml b/modules/trade_finance/facility.xml
index 4a4afcd..1382dba 100644
--- a/modules/trade_finance/facility.xml
+++ b/modules/trade_finance/facility.xml
@@ -15,6 +15,66 @@
+
+
+
+
+
+ trade_finance.facility_status
+ tree
+
+ facility_status_tree
+
+
+ trade_finance.facility_status
+ form
+ facility_status_form
+
+
+ Facility Statuses
+ trade_finance.facility_status
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ trade_finance.facility_status
+
+
+
+
+
+
+ trade_finance.facility_status
+
+
+
+
+
+
+
+ trade_finance.facility_status
+
+
+
+
+
+
+
@@ -75,6 +135,32 @@
+
+
+
+
+
+ trade_finance.facility_currency
+ tree
+
+ facility_currency_tree
+
+
+ trade_finance.facility_currency
+
+
+
+
+
+
+ trade_finance.facility_currency
+
+
+
+
+
+
+
diff --git a/modules/trade_finance/tryton.cfg b/modules/trade_finance/tryton.cfg
index 328deab..6848bac 100644
--- a/modules/trade_finance/tryton.cfg
+++ b/modules/trade_finance/tryton.cfg
@@ -9,3 +9,4 @@ depends:
xml:
reference.xml
facility.xml
+ constraint_type.xml
diff --git a/modules/trade_finance/view/constraint_type_form.xml b/modules/trade_finance/view/constraint_type_form.xml
new file mode 100644
index 0000000..73c68c6
--- /dev/null
+++ b/modules/trade_finance/view/constraint_type_form.xml
@@ -0,0 +1,12 @@
+
diff --git a/modules/trade_finance/view/constraint_type_tree.xml b/modules/trade_finance/view/constraint_type_tree.xml
new file mode 100644
index 0000000..8fd8540
--- /dev/null
+++ b/modules/trade_finance/view/constraint_type_tree.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/modules/trade_finance/view/facility_constraint_tree.xml b/modules/trade_finance/view/facility_constraint_tree.xml
index 8d882ba..dd51296 100644
--- a/modules/trade_finance/view/facility_constraint_tree.xml
+++ b/modules/trade_finance/view/facility_constraint_tree.xml
@@ -1,5 +1,4 @@
-
-
+
diff --git a/modules/trade_finance/view/facility_currency_tree.xml b/modules/trade_finance/view/facility_currency_tree.xml
new file mode 100644
index 0000000..859f9f9
--- /dev/null
+++ b/modules/trade_finance/view/facility_currency_tree.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/modules/trade_finance/view/facility_form.xml b/modules/trade_finance/view/facility_form.xml
index 586cfe7..4bc6377 100644
--- a/modules/trade_finance/view/facility_form.xml
+++ b/modules/trade_finance/view/facility_form.xml
@@ -30,8 +30,13 @@
+
+
+
-
+
diff --git a/modules/trade_finance/view/facility_limit_form.xml b/modules/trade_finance/view/facility_limit_form.xml
index 569a01a..c49dbfe 100644
--- a/modules/trade_finance/view/facility_limit_form.xml
+++ b/modules/trade_finance/view/facility_limit_form.xml
@@ -2,6 +2,8 @@