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>

Reply via email to