diff --git a/sale_commission_product_criteria_domain/README.rst b/sale_commission_product_criteria_domain/README.rst
new file mode 100644
index 000000000..e69de29bb
diff --git a/sale_commission_product_criteria_domain/__init__.py b/sale_commission_product_criteria_domain/__init__.py
new file mode 100644
index 000000000..0650744f6
--- /dev/null
+++ b/sale_commission_product_criteria_domain/__init__.py
@@ -0,0 +1 @@
+from . import models
diff --git a/sale_commission_product_criteria_domain/__manifest__.py b/sale_commission_product_criteria_domain/__manifest__.py
new file mode 100644
index 000000000..f3b0f3a87
--- /dev/null
+++ b/sale_commission_product_criteria_domain/__manifest__.py
@@ -0,0 +1,26 @@
+# © 2023 ooops404
+# License AGPL-3 - See https://www.gnu.org/licenses/agpl-3.0.html
+{
+ "name": "Sale Commission Product Criteria Domain",
+ "version": "14.0.1.0.0",
+ "author": "Ilyas," "Ooops404," "Odoo Community Association (OCA)",
+ "contributors": ["Ilyas"],
+ "maintainers": ["ilyasProgrammer"],
+ "website": "https://github.com/OCA/commission",
+ "category": "Sales Management",
+ "license": "AGPL-3",
+ "depends": [
+ "sale_commission_product_criteria",
+ "web_domain_field",
+ ],
+ "demo": [
+ "demo/demo_data.xml",
+ ],
+ "data": [
+ "views/views.xml",
+ "security/ir.model.access.csv",
+ ],
+ "application": False,
+ "installable": True,
+ "auto_install": False,
+}
diff --git a/sale_commission_product_criteria_domain/demo/demo_data.xml b/sale_commission_product_criteria_domain/demo/demo_data.xml
new file mode 100644
index 000000000..faa6da478
--- /dev/null
+++ b/sale_commission_product_criteria_domain/demo/demo_data.xml
@@ -0,0 +1,132 @@
+
+
+
+
+ Based on Rules Restricted
+ product_restricted
+
+
+
+
+ Spain
+
+
+
+
+ Italy
+
+
+
+
+
+
+
+ sol
+ 3_global
+ fixed
+ 10
+
+
+
+
+
+
+ sol
+ 2_product_category
+ fixed
+ 20
+
+
+
+
+
+
+
+ sol
+ 1_product
+ percentage
+ 5
+
+
+
+
+
+
+
+ sol
+ 0_product_variant
+ percentage
+ 15
+
+
+
+
+
+
+ Agent Rules Restricted Italy
+ True
+ True
+
+
+
+
+ Agent Rules Restricted Spain
+ True
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sale_commission_product_criteria_domain/models/__init__.py b/sale_commission_product_criteria_domain/models/__init__.py
new file mode 100644
index 000000000..8aa51beed
--- /dev/null
+++ b/sale_commission_product_criteria_domain/models/__init__.py
@@ -0,0 +1,6 @@
+from . import commission
+from . import commission_group
+from . import partner
+from . import account_invoice_line_agent
+from . import sale_order_line_agent
+from . import sale_commission_line_mixin
diff --git a/sale_commission_product_criteria_domain/models/account_invoice_line_agent.py b/sale_commission_product_criteria_domain/models/account_invoice_line_agent.py
new file mode 100644
index 000000000..3d24b65c8
--- /dev/null
+++ b/sale_commission_product_criteria_domain/models/account_invoice_line_agent.py
@@ -0,0 +1,28 @@
+# © 2023 ooops404
+# License AGPL-3 - See https://www.gnu.org/licenses/agpl-3.0.html
+from odoo import api, models
+
+
+class AccountInvoiceLineAgent(models.Model):
+ _inherit = "account.invoice.line.agent"
+
+ @api.depends(
+ "object_id.price_subtotal",
+ "object_id.product_id.commission_free",
+ "commission_id",
+ )
+ def _compute_amount(self):
+ for line in self:
+ if (
+ line.commission_id
+ and line.commission_id.commission_type == "product_restricted"
+ ):
+ inv_line = line.object_id
+ line.amount = line._get_single_commission_amount(
+ line.commission_id,
+ inv_line.price_subtotal,
+ inv_line.product_id,
+ inv_line.quantity,
+ )
+ else:
+ super(AccountInvoiceLineAgent, line)._compute_amount()
diff --git a/sale_commission_product_criteria_domain/models/commission.py b/sale_commission_product_criteria_domain/models/commission.py
new file mode 100644
index 000000000..c280d9535
--- /dev/null
+++ b/sale_commission_product_criteria_domain/models/commission.py
@@ -0,0 +1,81 @@
+# © 2023 ooops404
+# License AGPL-3 - See https://www.gnu.org/licenses/agpl-3.0.html
+from odoo import api, fields, models
+
+
+class SaleCommission(models.Model):
+ _inherit = "sale.commission"
+
+ commission_type = fields.Selection(
+ selection_add=[("product_restricted", "Product criteria (with restrictions)")],
+ ondelete={"product_restricted": "set default"},
+ )
+
+
+class CommissionItem(models.Model):
+ _inherit = "commission.item"
+
+ commission_id = fields.Many2one(
+ "sale.commission",
+ string="Commission Type",
+ domain=[("commission_type", "in", ["product", "product_restricted"])],
+ required=True,
+ )
+ sale_commission_type = fields.Selection(
+ related="commission_id.commission_type", readonly=True
+ )
+ group_id = fields.Many2one(
+ "commission.items.group",
+ ondelete="restrict",
+ )
+
+ def write(self, values):
+ res = super().write(values)
+ if self.group_id and not self.group_id.commission_ids.ids:
+ self.group_id.commission_ids = [(6, 0, self.commission_id.ids)]
+ if self.commission_id.commission_type != "product_restricted" and self.group_id:
+ self.group_id = False
+ return res
+
+
+class CommissionItemAgent(models.Model):
+ _name = "commission.item.agent"
+ _description = "Commission Item Agent"
+
+ _sql_constraints = [
+ (
+ "commission_item_unique_agent",
+ "UNIQUE(partner_id, agent_id)",
+ "You can only add one time each agent into Commission "
+ "Items Groups Restrictions table.",
+ )
+ ]
+
+ partner_agent_ids = fields.Many2many(related="partner_id.agent_ids")
+ agent_group_ids = fields.Many2many(
+ "commission.items.group", compute="_compute_agent_group_ids"
+ )
+ agent_id = fields.Many2one(
+ "res.partner", domain='[("id", "in", partner_agent_ids)]', required=True
+ )
+ partner_id = fields.Many2one(
+ "res.partner", domain=[("agent", "=", False)], required=True
+ )
+ group_ids = fields.Many2many(
+ "commission.items.group",
+ domain="[('id', 'in', agent_group_ids)]",
+ string="Commission Items Groups Restrictions",
+ required=True,
+ )
+
+ @api.depends("agent_id")
+ def _compute_agent_group_ids(self):
+ for rec in self:
+ if rec.agent_id.allowed_commission_group_ids:
+ dom = ("group_id", "in", rec.agent_id.allowed_commission_group_ids.ids)
+ else:
+ dom = ("group_id", "!=", False)
+ items = self.env["commission.item"].search(
+ [("commission_id", "=", rec.agent_id.commission_id.id), dom]
+ )
+ rec.agent_group_ids = [(6, 0, items.mapped("group_id").ids)]
diff --git a/sale_commission_product_criteria_domain/models/commission_group.py b/sale_commission_product_criteria_domain/models/commission_group.py
new file mode 100644
index 000000000..e0746fa0b
--- /dev/null
+++ b/sale_commission_product_criteria_domain/models/commission_group.py
@@ -0,0 +1,70 @@
+# © 2023 ooops404
+# License AGPL-3 - See https://www.gnu.org/licenses/agpl-3.0.html
+from odoo import _, api, exceptions, fields, models
+
+
+class CommissionItemsGroup(models.Model):
+ _name = "commission.items.group"
+ _description = "Commission Items Group"
+ _sql_constraints = [
+ (
+ "unique_cig_name",
+ "UNIQUE(name)",
+ "Commission items group with such name already exists. "
+ "Name must be unique.",
+ )
+ ]
+
+ name = fields.Char(required=True)
+ commission_ids = fields.Many2many(
+ "sale.commission",
+ compute="_compute_commission_ids",
+ domain=[("commission_type", "=", "product_restricted")],
+ readonly=True,
+ store=True,
+ )
+ item_ids = fields.One2many(
+ "commission.item", "group_id", string="Items", readonly=True
+ )
+ agents_count = fields.Integer(compute="_compute_agents_count")
+
+ @api.depends("item_ids")
+ def _compute_commission_ids(self):
+ for rec in self:
+ rec.commission_ids = [(6, 0, rec.item_ids.mapped("commission_id").ids)]
+
+ def unlink(self):
+ if self.item_ids:
+ raise exceptions.ValidationError(
+ _(
+ "You can not delete this commission group since "
+ "there is related to it commission items."
+ )
+ )
+ return super().unlink()
+
+ def _compute_agents_count(self):
+ res_partner_obj = self.env["res.partner"]
+ for rec in self:
+ self.agents_count = res_partner_obj.search_count(
+ [
+ ("agent", "=", True),
+ ("allowed_commission_group_ids", "in", rec.ids),
+ ]
+ )
+
+ def action_open_related_agents(self):
+ agent_ids = self.env["res.partner"].search(
+ [
+ ("agent", "=", True),
+ ("allowed_commission_group_ids", "in", self.ids),
+ ]
+ )
+ return {
+ "name": _("Commission Group Agents"),
+ "type": "ir.actions.act_window",
+ "view_mode": "tree",
+ "res_model": "res.partner",
+ "context": self.env.context,
+ "domain": [("id", "in", agent_ids.ids)],
+ }
diff --git a/sale_commission_product_criteria_domain/models/partner.py b/sale_commission_product_criteria_domain/models/partner.py
new file mode 100644
index 000000000..0d6e0c9fe
--- /dev/null
+++ b/sale_commission_product_criteria_domain/models/partner.py
@@ -0,0 +1,68 @@
+# © 2023 ooops404
+# License AGPL-3 - See https://www.gnu.org/licenses/agpl-3.0.html
+import json
+
+from odoo import api, fields, models
+
+
+class ResPartner(models.Model):
+ _inherit = "res.partner"
+
+ apply_commission_restrictions = fields.Boolean("Apply Restrictions")
+ commission_item_agent_ids = fields.One2many(
+ "commission.item.agent", "partner_id", string="Commission Items Groups"
+ )
+ allowed_commission_group_ids = fields.Many2many(
+ "commission.items.group", help="Related only to agents"
+ )
+ allowed_commission_group_ids_domain = fields.Char(
+ compute="_compute_allowed_commission_group_ids_domain",
+ readonly=True,
+ store=False,
+ )
+ commission_type = fields.Selection(related="commission_id.commission_type")
+
+ @api.depends("commission_id")
+ def _compute_allowed_commission_group_ids_domain(self):
+ for rec in self:
+ if rec.agent:
+ allowed_group_ids = rec.commission_id.filtered(
+ lambda x: x.commission_type == "product_restricted"
+ ).item_ids.mapped("group_id")
+ rec.allowed_commission_group_ids_domain = json.dumps(
+ [("id", "in", allowed_group_ids.ids)]
+ )
+ else:
+ rec.allowed_commission_group_ids_domain = False
+
+ @api.onchange("agent_ids")
+ def _onchange_agent_ids(self):
+ for rec in self:
+ exiting_agents = rec.commission_item_agent_ids.mapped("agent_id")
+ to_create = [
+ {"partner_id": rec._origin.id, "agent_id": x._origin.id}
+ for x in rec.agent_ids.filtered(
+ lambda x: x.commission_id.commission_type == "product_restricted"
+ )
+ if x not in exiting_agents.ids
+ ]
+ to_delete = rec.commission_item_agent_ids.filtered(
+ lambda x: x.agent_id.id in (exiting_agents - rec.agent_ids).ids
+ )
+ if to_delete:
+ rec.update(
+ {"commission_item_agent_ids": [(2, dl.id, 0) for dl in to_delete]}
+ )
+ if to_create:
+ rec.update(
+ {"commission_item_agent_ids": [(0, 0, line) for line in to_create]}
+ )
+
+ def write(self, vals):
+ res = super().write(vals)
+ if (
+ self.commission_id.commission_type != "product_restricted"
+ and self.allowed_commission_group_ids
+ ):
+ self.allowed_commission_group_ids = False
+ return res
diff --git a/sale_commission_product_criteria_domain/models/sale_commission_line_mixin.py b/sale_commission_product_criteria_domain/models/sale_commission_line_mixin.py
new file mode 100644
index 000000000..d44075e8f
--- /dev/null
+++ b/sale_commission_product_criteria_domain/models/sale_commission_line_mixin.py
@@ -0,0 +1,65 @@
+# © 2023 ooops404
+# License AGPL-3 - See https://www.gnu.org/licenses/agpl-3.0.html
+from odoo import models
+
+
+class SaleCommissionLineMixin(models.AbstractModel):
+ _inherit = "sale.commission.line.mixin"
+
+ def _get_commission_items(self, commission, product):
+ # Method replaced
+ categ_ids = {}
+ categ = product.categ_id
+ while categ:
+ categ_ids[categ.id] = True
+ categ = categ.parent_id
+ categ_ids = list(categ_ids)
+
+ # Module specific mod:
+ if self.object_id._name == "sale.order.line":
+ partner = self.object_id.order_id.partner_id
+ elif self.object_id._name == "account.move.line":
+ partner = self.object_id.partner_id
+ else:
+ partner = False
+ if partner:
+ group_ids = (
+ partner.commission_item_agent_ids.filtered(
+ lambda x: x.agent_id == self.agent_id
+ )
+ .mapped("group_ids")
+ .ids
+ )
+ else:
+ group_ids = []
+
+ # Select all suitable items. Order by best match
+ # (priority is: all/cat/subcat/product/variant).
+ self.env.cr.execute(
+ """
+ SELECT
+ item.id
+ FROM
+ commission_item AS item
+ LEFT JOIN product_category AS categ ON item.categ_id = categ.id
+ LEFT JOIN commission_item_agent AS cia ON item.group_id = cia.id
+ WHERE
+ (item.product_tmpl_id IS NULL OR item.product_tmpl_id = any(%s))
+ AND (item.product_id IS NULL OR item.product_id = any(%s))
+ AND (item.categ_id IS NULL OR item.categ_id = any(%s))
+ AND (item.commission_id = %s)
+ AND (item.active = TRUE)
+ AND (cia.id IS NULL OR cia.id = any(%s))
+ ORDER BY
+ item.applied_on, item.based_on, categ.complete_name desc
+ """,
+ (
+ product.product_tmpl_id.ids,
+ product.ids,
+ categ_ids,
+ commission._origin.id,
+ group_ids,
+ ),
+ )
+ item_ids = [x[0] for x in self.env.cr.fetchall()]
+ return item_ids
diff --git a/sale_commission_product_criteria_domain/models/sale_order_line_agent.py b/sale_commission_product_criteria_domain/models/sale_order_line_agent.py
new file mode 100644
index 000000000..923fac456
--- /dev/null
+++ b/sale_commission_product_criteria_domain/models/sale_order_line_agent.py
@@ -0,0 +1,26 @@
+# © 2023 ooops404
+# License AGPL-3 - See https://www.gnu.org/licenses/agpl-3.0.html
+from odoo import api, models
+
+
+class SaleOrderLineAgent(models.Model):
+ _inherit = "sale.order.line.agent"
+
+ @api.depends(
+ "object_id.price_subtotal", "object_id.product_id", "object_id.product_uom_qty"
+ )
+ def _compute_amount(self):
+ for line in self:
+ if (
+ line.commission_id
+ and line.commission_id.commission_type == "product_restricted"
+ ):
+ order_line = line.object_id
+ line.amount = line._get_single_commission_amount(
+ line.commission_id,
+ order_line.price_subtotal,
+ order_line.product_id,
+ order_line.product_uom_qty,
+ )
+ else:
+ super(SaleOrderLineAgent, line)._compute_amount()
diff --git a/sale_commission_product_criteria_domain/readme/CONTRIBUTORS.rst b/sale_commission_product_criteria_domain/readme/CONTRIBUTORS.rst
new file mode 100644
index 000000000..c29a9c72e
--- /dev/null
+++ b/sale_commission_product_criteria_domain/readme/CONTRIBUTORS.rst
@@ -0,0 +1,3 @@
+* `Ooops404 `__:
+
+ * Ilyas
diff --git a/sale_commission_product_criteria_domain/readme/DESCRIPTION.rst b/sale_commission_product_criteria_domain/readme/DESCRIPTION.rst
new file mode 100644
index 000000000..30ea93fd3
--- /dev/null
+++ b/sale_commission_product_criteria_domain/readme/DESCRIPTION.rst
@@ -0,0 +1,7 @@
+This module allows to manage the following commission structure use case:
+
+Agent A receives commission 50 when selling product 1 to customer X
+
+Agent A receives commission 20 when selling product 1 to customer Y
+
+This behavior is integrated with both pricelist-like Commission Type structure (sale_commission_product_criteria) and commission by discount (sale_commission_product_criteria_discount)
diff --git a/sale_commission_product_criteria_domain/readme/USAGE.rst b/sale_commission_product_criteria_domain/readme/USAGE.rst
new file mode 100644
index 000000000..72e9f3a9d
--- /dev/null
+++ b/sale_commission_product_criteria_domain/readme/USAGE.rst
@@ -0,0 +1,22 @@
+Go to Sales > Commission management > Commission Type Items Groups
+
+Create one or more new Groups, eg. “Italy” and “Spain”
+
+Create new Commission type, select type “Product Criteria (with restrictions)”, eg: “Southern Europe”
+
+Add lines to Commission type; for each line one Group must be set, eg.
+
+ Product: Conference Chair, value: $20, group: Italy
+
+ Product: Conference Chair, value: $10, group: Spain
+
+
+Go to Agent A, assign Commission type: “Southern Europe” > add “Allowed Commission Groups”: “Italy”, “Spain”
+
+In this way, we are allowing Commission type lines for both “Spain” and “Italy” to be applied to this agent.
+
+Go to customer X, set agent: “Agent A” > in table “Commission items group” set group “Spain”
+
+Go to customer Y, set agent: “Agent A” > in table “Commission items group” set group “Italy”
+
+On sales for customer X, only Commission type lines with group “Spain” will be applied to agent; on sales for customer Y, only Commission type lines with group “Italy” will be applied to agent.
diff --git a/sale_commission_product_criteria_domain/security/ir.model.access.csv b/sale_commission_product_criteria_domain/security/ir.model.access.csv
new file mode 100644
index 000000000..ada09650e
--- /dev/null
+++ b/sale_commission_product_criteria_domain/security/ir.model.access.csv
@@ -0,0 +1,5 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+cia1,cia1,model_commission_item_agent,sales_team.group_sale_manager,1,1,1,1
+cia2,cia2,model_commission_item_agent,sales_team.group_sale_salesman,1,1,0,0
+cig1,cig1,model_commission_items_group,sales_team.group_sale_manager,1,1,1,1
+cig2,cig2,model_commission_items_group,sales_team.group_sale_salesman,1,1,0,0
diff --git a/sale_commission_product_criteria_domain/static/description/icon.png b/sale_commission_product_criteria_domain/static/description/icon.png
new file mode 100644
index 000000000..3a0328b51
Binary files /dev/null and b/sale_commission_product_criteria_domain/static/description/icon.png differ
diff --git a/sale_commission_product_criteria_domain/tests/__init__.py b/sale_commission_product_criteria_domain/tests/__init__.py
new file mode 100644
index 000000000..110b0564c
--- /dev/null
+++ b/sale_commission_product_criteria_domain/tests/__init__.py
@@ -0,0 +1 @@
+from . import test_sale_commission_product_criteria_domain
diff --git a/sale_commission_product_criteria_domain/tests/test_sale_commission_product_criteria_domain.py b/sale_commission_product_criteria_domain/tests/test_sale_commission_product_criteria_domain.py
new file mode 100644
index 000000000..96ef954cf
--- /dev/null
+++ b/sale_commission_product_criteria_domain/tests/test_sale_commission_product_criteria_domain.py
@@ -0,0 +1,320 @@
+# Copyright 2023 - ooops404
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+import odoo.exceptions
+from odoo.tests.common import SavepointCase
+
+
+class TestSaleCommissionDomain(SavepointCase):
+ @classmethod
+ def setUpClass(cls):
+ super(TestSaleCommissionDomain, cls).setUpClass()
+ cls.commission_model = cls.env["sale.commission"]
+ cls.company = cls.env.ref("base.main_company")
+ cls.res_partner_model = cls.env["res.partner"]
+ cls.azure = cls.env.ref("base.res_partner_12") # Azure
+ cls.deco = cls.env.ref("base.res_partner_2") # Deco
+ cls.partner2 = cls.env.ref("base.res_partner_10") # The Jackson Group
+ cls.sale_order_model = cls.env["sale.order"]
+ cls.advance_inv_model = cls.env["sale.advance.payment.inv"]
+ cls.settle_model = cls.env["sale.commission.settlement"]
+ cls.make_settle_model = cls.env["sale.commission.make.settle"]
+ cls.make_inv_model = cls.env["sale.commission.make.invoice"]
+ cls.product_1 = cls.env.ref("product.product_product_1")
+ cls.product_4 = cls.env.ref("product.product_product_4")
+ cls.product_5 = cls.env.ref("product.product_product_5")
+ cls.product_6 = cls.env.ref("product.product_product_6")
+ # Acoustic Bloc Screens
+ cls.product_product_25 = cls.env.ref("product.product_product_25")
+ cls.product_1.write({"invoice_policy": "order"})
+ cls.product_4.write({"invoice_policy": "order"})
+ cls.product_5.write({"invoice_policy": "order"})
+ cls.product_product_25.write({"invoice_policy": "order"})
+ cls.product_6.write({"commission_free": True, "invoice_policy": "order"})
+ cls.product_template_4 = cls.env.ref(
+ "product.product_product_4_product_template"
+ ) # Customizable Desk (CONFIG)
+ cls.product_template_4.write({"invoice_policy": "order"})
+ cls.pt_11 = cls.env.ref("product.product_product_11_product_template")
+ cls.journal = cls.env["account.journal"].search(
+ [("type", "=", "purchase")], limit=1
+ )
+ cls.rules_commission_id = cls.env.ref(
+ "sale_commission_product_criteria.demo_commission_rules"
+ )
+ cls.com_item_1 = cls.env.ref(
+ "sale_commission_product_criteria.demo_commission_rules_item_1"
+ )
+ cls.com_item_2 = cls.env.ref(
+ "sale_commission_product_criteria.demo_commission_rules_item_2"
+ )
+ cls.com_item_3 = cls.env.ref(
+ "sale_commission_product_criteria.demo_commission_rules_item_3"
+ )
+ cls.com_item_4 = cls.env.ref(
+ "sale_commission_product_criteria.demo_commission_rules_item_4"
+ )
+ cls.demo_crr_item_1 = cls.env.ref(
+ "sale_commission_product_criteria_domain.demo_crr_item_1"
+ )
+ cls.demo_cig_spain = cls.env.ref(
+ "sale_commission_product_criteria_domain.demo_cig_spain"
+ )
+ cls.demo_cig_italy = cls.env.ref(
+ "sale_commission_product_criteria_domain.demo_cig_italy"
+ )
+ cls.demo_agent_rules_restricted_italy = cls.env.ref(
+ "sale_commission_product_criteria_domain.demo_agent_rules_restricted_italy"
+ )
+ cls.demo_agent_rules_restricted_spain = cls.env.ref(
+ "sale_commission_product_criteria_domain.demo_agent_rules_restricted_spain"
+ )
+ cls.demo_commission_rules_restrict = cls.env.ref(
+ "sale_commission_product_criteria_domain.demo_commission_rules_restrict"
+ )
+ cls.demo_commission_rules = cls.env.ref(
+ "sale_commission_product_criteria.demo_commission_rules"
+ )
+ cls.demo_commission = cls.env.ref("sale_commission.demo_commission")
+ cls.conf_chair_config_id = cls.env.ref(
+ "product.product_product_11_product_template"
+ )
+ cls.cia_azure = cls.env.ref("sale_commission_product_criteria_domain.cia_azure")
+ cls.res_partner_tiny_sale_agent = cls.env.ref(
+ "sale_commission.res_partner_tiny_sale_agent"
+ )
+
+ def test_commission_domain_demo_cases(self):
+ # Azure Spain Office furn. - Category
+ so = self._create_sale_order(self.product_5, self.azure)
+ so.recompute_lines_agents()
+ so.action_confirm()
+ invoice = self._invoice_sale_order(so)
+ invoice.recompute_lines_agents()
+ so.order_line.agent_ids._compute_amount()
+ invoice.line_ids.agent_ids._compute_amount()
+ self.assertEqual(so.order_line.agent_ids.fixed_amount, 20)
+ self.assertEqual(invoice.line_ids.agent_ids.amount, 20)
+
+ # Azure Spain Customizable Desk (CONFIG) - Product Template
+ so = self._create_sale_order(
+ self.product_template_4.product_variant_id, self.azure
+ )
+ so.recompute_lines_agents()
+ so.action_confirm()
+ invoice = self._invoice_sale_order(so)
+ invoice.recompute_lines_agents()
+ so.order_line.agent_ids._compute_amount()
+ invoice.line_ids.agent_ids._compute_amount()
+ self.assertEqual(so.order_line.agent_ids.percent_amount, 5)
+ self.assertEqual(invoice.line_ids.agent_ids.amount, 50)
+
+ # Azure Spain Variant: Customizable Desk (CONFIG) (Steel, White) - Variant
+ so = self._create_sale_order(self.product_4, self.azure)
+ so.recompute_lines_agents()
+ so.action_confirm()
+ invoice = self._invoice_sale_order(so)
+ invoice.recompute_lines_agents()
+ so.order_line.agent_ids._compute_amount()
+ invoice.line_ids.agent_ids._compute_amount()
+ self.assertEqual(so.order_line.agent_ids.percent_amount, 15)
+ self.assertEqual(invoice.line_ids.agent_ids.amount, 150)
+
+ # Deco Italy - All products
+ so = self._create_sale_order(self.product_product_25, self.deco)
+ so.recompute_lines_agents()
+ so.action_confirm()
+ invoice = self._invoice_sale_order(so)
+ invoice.recompute_lines_agents()
+ so.order_line.agent_ids._compute_amount()
+ invoice.line_ids.agent_ids._compute_amount()
+ self.assertEqual(so.order_line.agent_ids.fixed_amount, 10)
+ self.assertEqual(invoice.line_ids.agent_ids.amount, 10)
+
+ def test_commission_domain(self):
+ # group must have commission of CI
+ self.demo_crr_item_1.group_id.commission_ids = False
+ self.demo_crr_item_1.write({"sequence": 2})
+ self.assertTrue(self.demo_crr_item_1.group_id.commission_ids)
+
+ # count related agents
+ self.demo_cig_italy._compute_agents_count()
+ # self.assertEqual(demo_cig_italy.agents_count, 1)
+
+ # if commission is not type of restricted then CI must have no group
+ self.demo_crr_item_1.commission_id = self.demo_commission_rules
+ self.demo_crr_item_1.write({"sequence": 3})
+ self.assertFalse(self.demo_crr_item_1.group_id)
+
+ # commission.item.agent: check agent_group_ids computed properly
+ self.cia_azure._compute_agent_group_ids()
+ self.assertTrue(self.cia_azure.agent_group_ids)
+
+ # commission.item.agent: check agent_group_ids is False when agent got no rules
+ self.cia_azure.agent_id = self.res_partner_tiny_sale_agent
+ self.cia_azure._compute_agent_group_ids()
+ self.assertFalse(self.cia_azure.agent_group_ids)
+
+ # false, when commission is not product_restricted
+ self.res_partner_tiny_sale_agent.write(
+ {
+ "allowed_commission_group_ids": [(6, 0, self.demo_cig_spain.ids)],
+ }
+ )
+ self.assertFalse(self.res_partner_tiny_sale_agent.allowed_commission_group_ids)
+
+ # check some partners compute methods
+ self.azure._onchange_agent_ids()
+ self.azure._compute_allowed_commission_group_ids_domain()
+ self.assertFalse(self.azure.allowed_commission_group_ids_domain)
+ self.demo_agent_rules_restricted_italy._compute_allowed_commission_group_ids_domain()
+ self.assertTrue(
+ self.demo_agent_rules_restricted_italy.allowed_commission_group_ids_domain
+ )
+
+ # trigger window action
+ action = self.demo_cig_spain.action_open_related_agents()
+ self.assertEqual(type(action), dict)
+
+ # you cant delete it having related CIs
+ with self.assertRaises(exception=odoo.exceptions.ValidationError):
+ self.demo_cig_spain.unlink()
+
+ #
+ self.env["commission.items.group"].create({"name": "Delete Me"}).unlink()
+
+ # computes was modified to consider new commission type: product_restricted
+ so = self._create_sale_order(self.product_4, self.azure)
+ so.recompute_lines_agents()
+ so.action_confirm()
+ invoice = self._invoice_sale_order(so)
+ invoice.recompute_lines_agents()
+ so.order_line.agent_ids._compute_amount()
+ invoice.line_ids.agent_ids._compute_amount()
+ self.assertEqual(so.order_line.agent_ids.amount, 150)
+ self.assertEqual(invoice.line_ids.agent_ids.amount, 150)
+
+ #
+ tst_partner = so.partner_id.copy({})
+ tst_partner.commission_item_agent_ids = [(6, 0, self.demo_cig_italy.ids)]
+ so.partner_id = tst_partner
+ so.order_line.agent_ids.agent_id = self.demo_agent_rules_restricted_italy
+ res = so.order_line.agent_ids._get_single_commission_amount(
+ self.demo_commission_rules_restrict,
+ 1,
+ self.conf_chair_config_id.product_variant_id,
+ 1,
+ )
+ self.assertEqual(res, 20)
+
+ # computes was modified to consider new commission type: product_restricted
+ self.demo_agent_rules_restricted_italy.commission_id = (
+ self.demo_commission_rules_restrict
+ )
+ so = self._create_sale_order(self.product_5, self.azure)
+ so.recompute_lines_agents()
+ so.action_confirm()
+ invoice = self._invoice_sale_order(so)
+ invoice.recompute_lines_agents()
+ so.order_line.agent_ids._compute_amount()
+ invoice.line_ids.agent_ids._compute_amount()
+ self.assertEqual(so.order_line.agent_ids.amount, 20)
+ self.assertEqual(invoice.line_ids.agent_ids.amount, 20)
+
+ # computes was modified to consider new commission type: product_restricted
+ self.product_5.commission_free = True
+ so = self._create_sale_order(self.product_5, self.azure)
+ so.recompute_lines_agents()
+ so.action_confirm()
+ invoice = self._invoice_sale_order(so)
+ invoice.recompute_lines_agents()
+ so.order_line.agent_ids._compute_amount()
+ invoice.line_ids.agent_ids._compute_amount()
+ self.assertEqual(so.order_line.agent_ids.amount, 0)
+ self.assertEqual(invoice.line_ids.agent_ids.amount, 0)
+
+ # computes was modified to consider new commission type: product_restricted
+ self.azure.agent_ids.commission_id = self.demo_commission_rules
+ so = self._create_sale_order(self.product_6, self.azure)
+ so.recompute_lines_agents()
+ so.action_confirm()
+ invoice = self._invoice_sale_order(so)
+ invoice.recompute_lines_agents()
+ so.order_line.agent_ids._compute_amount()
+ invoice.line_ids.agent_ids._compute_amount()
+ self.assertEqual(so.order_line.agent_ids.amount, 0)
+ self.assertEqual(invoice.line_ids.agent_ids.amount, 0)
+
+ # computes was modified to consider new commission type: product_restricted
+ so = self._create_sale_order(self.product_1, self.azure)
+ so.recompute_lines_agents()
+ so.action_confirm()
+ invoice = self._invoice_sale_order(so)
+ invoice.recompute_lines_agents()
+ so.order_line.agent_ids._compute_amount()
+ invoice.line_ids.agent_ids._compute_amount()
+ self.assertEqual(so.order_line.agent_ids.amount, 15)
+ self.assertEqual(invoice.line_ids.agent_ids.amount, 15)
+
+ # discount net_amount percentage
+ self.demo_agent_rules_restricted_spain.commission_id = (
+ self.demo_commission_rules_restrict
+ )
+ self.azure.commission_item_agent_ids.group_ids = [
+ (6, 0, self.demo_cig_spain.ids)
+ ]
+ so = self._create_sale_order(self.pt_11.product_variant_id, self.azure)
+ so.order_line.discount = 20
+ so.recompute_lines_agents()
+ so.action_confirm()
+ so.order_line.agent_ids.commission_id.item_ids.commission_type = "percentage"
+ so.order_line.agent_ids._compute_amount()
+ invoice.line_ids.agent_ids.commission_id = self.demo_commission_rules_restrict
+ invoice.line_ids.agent_ids.commission_id.amount_base_type = "net_amount"
+ invoice.line_ids.agent_ids.commission_id.item_ids.commission_type = "percentage"
+ invoice.line_ids.agent_ids._compute_amount()
+ self.assertEqual(so.order_line.agent_ids.amount, 0)
+ self.assertEqual(invoice.line_ids.agent_ids.amount, 0)
+
+ # no commission items
+ self.demo_commission_rules_restrict.item_ids.unlink()
+ so = self._create_sale_order(self.pt_11.product_variant_id, self.azure)
+ so.recompute_lines_agents()
+ so.action_confirm()
+ so.order_line.agent_ids._compute_amount()
+ invoice.line_ids.agent_ids._compute_amount()
+ self.assertEqual(so.order_line.agent_ids.amount, 0)
+ self.assertEqual(invoice.line_ids.agent_ids.amount, 0)
+
+ def _create_sale_order(self, product, partner):
+ return self.sale_order_model.create(
+ {
+ "partner_id": partner.id,
+ "order_line": [
+ (
+ 0,
+ 0,
+ {
+ "name": product.name,
+ "product_id": product.id,
+ "product_uom_qty": 1.0,
+ "product_uom": product.uom_id.id,
+ "price_unit": 1000,
+ },
+ )
+ ],
+ }
+ )
+
+ def _invoice_sale_order(self, sale_order, date=None):
+ old_invoices = sale_order.invoice_ids
+ wizard = self.advance_inv_model.create({"advance_payment_method": "delivered"})
+ wizard.with_context(
+ {
+ "active_model": "sale.order",
+ "active_ids": [sale_order.id],
+ "active_id": sale_order.id,
+ }
+ ).create_invoices()
+ invoice = sale_order.invoice_ids - old_invoices
+ invoice.flush()
+ return invoice
diff --git a/sale_commission_product_criteria_domain/views/views.xml b/sale_commission_product_criteria_domain/views/views.xml
new file mode 100644
index 000000000..06355af79
--- /dev/null
+++ b/sale_commission_product_criteria_domain/views/views.xml
@@ -0,0 +1,219 @@
+
+
+
+
+ res.partner.form.agent.inherit
+ res.partner
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ commission.item.agent.form
+ commission.item.agent
+
+
+
+
+
+
+
+ commission.item.agent.tree
+ commission.item.agent
+
+
+
+
+
+
+
+
+
+
+
+
+
+ commission.item.tree.inherit
+ commission.item
+
+
+
+
+
+
+
+
+
+
+ commission.item.form.inherit
+ commission.item
+
+
+
+
+
+
+
+
+
+
+ commission.items.group.form
+ commission.items.group
+
+
+
+
+
+
+ commission.items.group.tree
+ commission.items.group
+
+
+
+
+
+
+
+
+
+ Commission Type Items Groups
+ ir.actions.act_window
+ commission.items.group
+ tree,form
+
+
+
+
+ sale.commission.form.view.mod.inherit
+ sale.commission
+
+
+
+
+ {'invisible': [('commission_type', 'not in', ['product','product_restricted'])]}
+
+
+
+
+
+
+
+
+
+ sale.commission.form.view.inherit
+ sale.commission
+
+
+
+
+ {'invisible': [('commission_type', 'in', ['product','product_restricted'])]}
+
+
+
+
+
+
+
+