changeset 575b2649d2ad in modules/commission:default
details:
https://hg.tryton.org/modules/commission?cmd=changeset;node=575b2649d2ad
description:
Add Agent selection
issue8654
review260131002
diffstat:
CHANGELOG | 2 +
__init__.py | 2 +
commission.py | 45 +++++++++++++++++++
commission.xml | 60 ++++++++++++++++++++++++++
party.py | 6 ++-
party.xml | 12 +++++
sale.py | 45 ++++++++++++++++++-
tests/scenario_agent_selection.rst | 77 ++++++++++++++++++++++++++++++++++
tests/test_commission.py | 4 +
tryton.cfg | 1 +
view/agent_selection_form.xml | 16 +++++++
view/agent_selection_list.xml | 9 +++
view/agent_selection_list_sequence.xml | 9 +++
view/party_form.xml | 10 ++++
14 files changed, 294 insertions(+), 4 deletions(-)
diffs (426 lines):
diff -r c9d6060ab329 -r 575b2649d2ad CHANGELOG
--- a/CHANGELOG Mon Feb 24 18:34:54 2020 +0100
+++ b/CHANGELOG Mon Feb 24 18:38:48 2020 +0100
@@ -1,3 +1,5 @@
+* Add Agent selection
+
Version 5.4.0 - 2019-11-04
* Bug fixes (see mercurial logs for details)
diff -r c9d6060ab329 -r 575b2649d2ad __init__.py
--- a/__init__.py Mon Feb 24 18:34:54 2020 +0100
+++ b/__init__.py Mon Feb 24 18:38:48 2020 +0100
@@ -15,6 +15,7 @@
commission.Plan,
commission.PlanLines,
commission.Agent,
+ commission.AgentSelection,
commission.Commission,
commission.CreateInvoiceAsk,
invoice.Invoice,
@@ -23,6 +24,7 @@
product.Template_Agent,
product.Product,
account.Journal,
+ party.Party,
module='commission', type_='model')
Pool.register(
sale.Sale,
diff -r c9d6060ab329 -r 575b2649d2ad commission.py
--- a/commission.py Mon Feb 24 18:34:54 2020 +0100
+++ b/commission.py Mon Feb 24 18:38:48 2020 +0100
@@ -46,6 +46,8 @@
depends=['plan'])
pending_amount = fields.Function(fields.Numeric('Pending Amount',
digits=price_digits), 'get_pending_amount')
+ selections = fields.One2Many(
+ 'commission.agent.selection', 'agent', "Selections")
@staticmethod
def default_company():
@@ -112,6 +114,49 @@
return self.party.account_receivable_used
+class AgentSelection(sequence_ordered(), MatchMixin, ModelSQL, ModelView):
+ "Agent Selection"
+ __name__ = 'commission.agent.selection'
+ agent = fields.Many2One('commission.agent', "Agent", required=True)
+ start_date = fields.Date(
+ "Start Date",
+ domain=[
+ If(Eval('start_date') & Eval('end_date'),
+ ('start_date', '<=', Eval('end_date')),
+ ()),
+ ],
+ depends=['end_date'])
+ end_date = fields.Date(
+ "End Date",
+ domain=[
+ If(Eval('start_date') & Eval('end_date'),
+ ('end_date', '>=', Eval('start_date')),
+ ()),
+ ],
+ depends=['start_date'])
+ party = fields.Many2One(
+ 'party.party', "Party", ondelete='CASCADE', select=True)
+
+ @classmethod
+ def __setup__(cls):
+ super().__setup__()
+ cls._order.insert(0, ('party', 'ASC NULLS LAST'))
+
+ def match(self, pattern):
+ pool = Pool()
+ Date = pool.get('ir.date')
+
+ pattern = pattern.copy()
+ if 'company' in pattern:
+ pattern.pop('company')
+ date = pattern.pop('date', None) or Date.today()
+ if self.start_date and self.start_date > date:
+ return False
+ if self.end_date and self.end_date < date:
+ return False
+ return super().match(pattern)
+
+
class Plan(ModelSQL, ModelView):
'Commission Plan'
__name__ = 'commission.plan'
diff -r c9d6060ab329 -r 575b2649d2ad commission.xml
--- a/commission.xml Mon Feb 24 18:34:54 2020 +0100
+++ b/commission.xml Mon Feb 24 18:38:48 2020 +0100
@@ -81,6 +81,66 @@
<field name="perm_delete" eval="True"/>
</record>
+ <record model="ir.ui.view" id="agent_selection_view_form">
+ <field name="model">commission.agent.selection</field>
+ <field name="type">form</field>
+ <field name="name">agent_selection_form</field>
+ </record>
+
+ <record model="ir.ui.view" id="agent_selection_view_list">
+ <field name="model">commission.agent.selection</field>
+ <field name="type">tree</field>
+ <field name="name">agent_selection_list</field>
+ </record>
+
+ <record model="ir.ui.view" id="agent_selection_view_list_sequence">
+ <field name="model">commission.agent.selection</field>
+ <field name="type">tree</field>
+ <field name="priority" eval="20"/>
+ <field name="name">agent_selection_list_sequence</field>
+ </record>
+
+ <record model="ir.action.act_window" id="act_agent_selections">
+ <field name="name">Selections</field>
+ <field name="res_model">commission.agent.selection</field>
+ <field name="domain"
+ eval="[If(Eval('active_ids', []) == [Eval('active_id')],
('agent', '=', Eval('active_id')), ('agent', 'in', Eval('active_ids')))]"
+ pyson="1"/>
+ </record>
+ <record model="ir.action.act_window.view"
+ id="act_agent_selections_view1">
+ <field name="sequence" eval="10"/>
+ <field name="view" ref="agent_selection_view_list"/>
+ <field name="act_window" ref="act_agent_selections"/>
+ </record>
+ <record model="ir.action.act_window.view"
+ id="act_agent_selections_view2">
+ <field name="sequence" eval="20"/>
+ <field name="view" ref="agent_selection_view_form"/>
+ <field name="act_window" ref="act_agent_selections"/>
+ </record>
+ <record model="ir.action.keyword" id="act_agent_selections_keyword1">
+ <field name="keyword">form_relate</field>
+ <field name="model">commission.agent,-1</field>
+ <field name="action" ref="act_agent_selections"/>
+ </record>
+
+ <record model="ir.model.access" id="access_agent_selection">
+ <field name="model" search="[('model', '=',
'commission.agent.selection')]"/>
+ <field name="perm_read" eval="True"/>
+ <field name="perm_write" eval="False"/>
+ <field name="perm_create" eval="False"/>
+ <field name="perm_delete" eval="False"/>
+ </record>
+ <record model="ir.model.access"
id="access_agent_selection_commission_admin">
+ <field name="model" search="[('model', '=',
'commission.agent.selection')]"/>
+ <field name="group" ref="group_commission_admin"/>
+ <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="plan_view_form">
<field name="model">commission.plan</field>
<field name="type">form</field>
diff -r c9d6060ab329 -r 575b2649d2ad party.py
--- a/party.py Mon Feb 24 18:34:54 2020 +0100
+++ b/party.py Mon Feb 24 18:38:48 2020 +0100
@@ -1,11 +1,15 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.i18n import gettext
+from trytond.model import fields
from trytond.pool import PoolMeta, Pool
from trytond.modules.party.exceptions import EraseError
-__all__ = ['PartyReplace', 'PartyErase']
+
+class Party(metaclass=PoolMeta):
+ __name__ = 'party.party'
+ agents = fields.One2Many('commission.agent.selection', 'party', "Agents")
class PartyReplace(metaclass=PoolMeta):
diff -r c9d6060ab329 -r 575b2649d2ad party.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/party.xml Mon Feb 24 18:38:48 2020 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<tryton>
+ <data>
+ <record model="ir.ui.view" id="party_party_view_form">
+ <field name="model">party.party</field>
+ <field name="inherit" ref="party.party_view_form"/>
+ <field name="name">party_form</field>
+ </record>
+ </data>
+</tryton>
diff -r c9d6060ab329 -r 575b2649d2ad sale.py
--- a/sale.py Mon Feb 24 18:34:54 2020 +0100
+++ b/sale.py Mon Feb 24 18:38:48 2020 +0100
@@ -2,8 +2,8 @@
# this repository contains the full copyright notices and license terms.
-from trytond.pool import PoolMeta
-from trytond.model import fields
+from trytond.pool import PoolMeta, Pool
+from trytond.model import ModelView, Workflow, fields
from trytond.pyson import Eval
@@ -18,7 +18,7 @@
('company', '=', Eval('company', -1)),
],
states={
- 'readonly': Eval('state', '') != 'draft',
+ 'readonly': ~Eval('state').in_(['draft', 'quotation']),
},
depends=['state', 'company'])
@@ -29,6 +29,45 @@
invoice.save()
return invoice
+ @classmethod
+ @ModelView.button
+ @Workflow.transition('quotation')
+ def quote(cls, sales):
+ cls.set_agent(sales)
+ super().quote(sales)
+
+ def _get_agent_pattern(self):
+ pattern = {}
+ pattern['date'] = self.sale_date
+ pattern['company'] = self.company.id
+ pattern['party'] = self.party.id
+ return pattern
+
+ @classmethod
+ def _get_agent_selection_domain(cls, pattern):
+ domain = []
+ if 'company' in pattern:
+ domain.append(('agent.company', '=', pattern['company']))
+ if 'party' in pattern:
+ domain.append(('party', 'in', [None, pattern['party']]))
+ return domain
+
+ @classmethod
+ def set_agent(cls, sales):
+ pool = Pool()
+ AgentSelection = pool.get('commission.agent.selection')
+
+ for sale in sales:
+ if sale.agent:
+ continue
+ pattern = sale._get_agent_pattern()
+ for selection in AgentSelection.search(
+ cls._get_agent_selection_domain(pattern)):
+ if selection.match(pattern):
+ sale.agent = selection.agent
+ break
+ cls.save(sales)
+
class SaleLine(metaclass=PoolMeta):
__name__ = 'sale.line'
diff -r c9d6060ab329 -r 575b2649d2ad tests/scenario_agent_selection.rst
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/scenario_agent_selection.rst Mon Feb 24 18:38:48 2020 +0100
@@ -0,0 +1,77 @@
+========================
+Agent Selection Scenario
+========================
+
+Imports::
+
+ >>> import datetime
+ >>> from dateutil.relativedelta import relativedelta
+ >>> from decimal import Decimal
+ >>> from proteus import Model, Wizard
+ >>> from trytond.tests.tools import activate_modules
+ >>> from trytond.modules.company.tests.tools import create_company, \
+ ... get_company
+ >>> from trytond.modules.account.tests.tools import create_fiscalyear, \
+ ... create_chart, get_accounts
+ >>> today = datetime.date.today()
+ >>> yesterday = today - relativedelta(days=1)
+
+Install commission::
+
+ >>> config = activate_modules(['commission', 'sale'])
+
+Create company::
+
+ >>> _ = create_company()
+ >>> company = get_company()
+
+Create chart of accounts::
+
+ >>> _ = create_chart(company)
+ >>> accounts = get_accounts(company)
+
+Create customer::
+
+ >>> Party = Model.get('party.party')
+ >>> customer = Party(name='Customer')
+ >>> customer.save()
+
+Create agent::
+
+ >>> Agent = Model.get('commission.agent')
+ >>> agent_party = Party(name='Agent')
+ >>> agent_party.save()
+ >>> agent = Agent(party=agent_party)
+ >>> agent.type_ = 'agent'
+ >>> agent.currency = company.currency
+ >>> selection = agent.selections.new()
+ >>> selection.start_date = today
+ >>> selection.party = customer
+ >>> agent.save()
+
+Create sale::
+
+ >>> Sale = Model.get('sale.sale')
+ >>> sale = Sale()
+ >>> sale.party = customer
+ >>> sale.save()
+
+The agent is assigned on quotation::
+
+ >>> sale.agent
+ >>> sale.click('quote')
+ >>> sale.state
+ 'quotation'
+ >>> sale.agent == agent
+ True
+
+Agent is not set for yesterday sales::
+
+ >>> Sale = Model.get('sale.sale')
+ >>> sale = Sale()
+ >>> sale.sale_date = yesterday
+ >>> sale.party = customer
+ >>> sale.click('quote')
+ >>> sale.state
+ 'quotation'
+ >>> sale.agent
diff -r c9d6060ab329 -r 575b2649d2ad tests/test_commission.py
--- a/tests/test_commission.py Mon Feb 24 18:34:54 2020 +0100
+++ b/tests/test_commission.py Mon Feb 24 18:38:48 2020 +0100
@@ -128,4 +128,8 @@
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
+ suite.addTests(doctest.DocFileSuite('scenario_agent_selection.rst',
+ tearDown=doctest_teardown, encoding='utf-8',
+ checker=doctest_checker,
+ optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
return suite
diff -r c9d6060ab329 -r 575b2649d2ad tryton.cfg
--- a/tryton.cfg Mon Feb 24 18:34:54 2020 +0100
+++ b/tryton.cfg Mon Feb 24 18:38:48 2020 +0100
@@ -17,3 +17,4 @@
account.xml
product.xml
message.xml
+ party.xml
diff -r c9d6060ab329 -r 575b2649d2ad view/agent_selection_form.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/view/agent_selection_form.xml Mon Feb 24 18:38:48 2020 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<form>
+ <label name="agent"/>
+ <field name="agent"/>
+ <label name="sequence"/>
+ <field name="sequence"/>
+ <separator string="Criteria" id="criteria" colspan="4"/>
+ <label name="start_date"/>
+ <field name="start_date"/>
+ <label name="end_date"/>
+ <field name="end_date"/>
+ <label name="party"/>
+ <field name="party"/>
+</form>
diff -r c9d6060ab329 -r 575b2649d2ad view/agent_selection_list.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/view/agent_selection_list.xml Mon Feb 24 18:38:48 2020 +0100
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<tree>
+ <field name="party"/>
+ <field name="agent"/>
+ <field name="start_date"/>
+ <field name="end_date"/>
+</tree>
diff -r c9d6060ab329 -r 575b2649d2ad view/agent_selection_list_sequence.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/view/agent_selection_list_sequence.xml Mon Feb 24 18:38:48 2020 +0100
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<tree sequence="sequence">
+ <field name="party"/>
+ <field name="agent"/>
+ <field name="start_date"/>
+ <field name="end_date"/>
+</tree>
diff -r c9d6060ab329 -r 575b2649d2ad view/party_form.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/view/party_form.xml Mon Feb 24 18:38:48 2020 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<!-- The COPYRIGHT file at the top level of this repository contains the full
+ copyright notices and license terms. -->
+<data>
+ <xpath expr="/form/notebook" position="inside">
+ <page id="commissions" string="Commissions">
+ <field name="agents" colspan="4"
view_ids="commission.agent_selection_view_list_sequence"/>
+ </page>
+ </xpath>
+</data>