Skip to content

Commit

Permalink
Merge PR #994 into 12.0
Browse files Browse the repository at this point in the history
Signed-off-by simahawk
  • Loading branch information
OCA-git-bot committed Dec 11, 2019
2 parents f23eb98 + fb83d80 commit e674c96
Show file tree
Hide file tree
Showing 30 changed files with 1,048 additions and 99 deletions.
4 changes: 2 additions & 2 deletions sale_product_set/__init__.py
@@ -1,2 +1,2 @@
from . import models
from . import wizard
from . import models # pragma: no cover
from . import wizard # pragma: no cover
3 changes: 1 addition & 2 deletions sale_product_set/__manifest__.py
Expand Up @@ -6,7 +6,7 @@
'category': 'Sale',
'license': 'AGPL-3',
'author': 'Anybox, Odoo Community Association (OCA)',
'version': '12.0.1.2.0',
'version': '12.0.1.3.0',
'website': 'https://github.com/OCA/sale-workflow',
'summary': "Sale product set",
'depends': [
Expand All @@ -15,7 +15,6 @@
'data': [
'security/ir.model.access.csv',
'security/rule_product_set.xml',
'security/rule_product_set_line.xml',
'views/product_set.xml',
'wizard/product_set_add.xml',
'views/sale_order.xml',
Expand Down
30 changes: 19 additions & 11 deletions sale_product_set/models/product_set.py 100755 → 100644
Expand Up @@ -24,17 +24,25 @@ class ProductSet(models.Model):
default=lambda self: self.env.user.company_id,
ondelete='cascade',
)
partner_id = fields.Many2one(
comodel_name="res.partner",
required=False,
ondelete="cascade",
index=True,
help="You can attache the set to a specific partner "
"or no one. If you don't specify one, "
"it's going to be available for all of them."
)

@api.multi
def name_get(self):
return [
(
product_set.id,
'%s%s'
% (
product_set.ref and '[%s] ' % product_set.ref or '',
product_set.name,
),
)
for product_set in self
]
return [(rec.id, rec._name_get()) for rec in self]

def _name_get(self):
parts = []
if self.ref:
parts.append('[%s]' % self.ref)
parts.append(self.name)
if self.partner_id:
parts.append('@ %s' % self.partner_id.name)
return ' '.join(parts)
13 changes: 12 additions & 1 deletion sale_product_set/security/rule_product_set.xml
@@ -1,5 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>

<record id="product_set_comp_rule" model="ir.rule">
<field name="name">Product Set multi company rule</field>
<field name="model_id" ref="model_product_set"/>
<field name="global" eval="True"/>
<field name="domain_force">
['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]
</field>
</record>

<record id="product_set_line_comp_rule" model="ir.rule">
<field name="name">Product Set Line multi company rule</field>
<field name="model_id" ref="model_product_set_line"/>
Expand All @@ -8,4 +18,5 @@
['|',('product_set_id.company_id','=',False),('product_set_id.company_id','child_of',[user.company_id.id])]
</field>
</record>
</odoo>

</odoo>
11 changes: 0 additions & 11 deletions sale_product_set/security/rule_product_set_line.xml

This file was deleted.

101 changes: 83 additions & 18 deletions sale_product_set/tests/test_product_set.py
Expand Up @@ -2,23 +2,21 @@
# Copyright 2016-2018 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo.tests import common
from odoo import exceptions


class TestProductSet(common.TransactionCase):
class TestProductSet(common.SavepointCase):
""" Test Product set"""

def setUp(self):
super(TestProductSet, self).setUp()
self.sale_order = self.env['sale.order']
self.product_set_add = self.env['product.set.add']
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.sale_order = cls.env['sale.order']
cls.product_set_add = cls.env['product.set.add']

def test_add_set(self):
so = self.env.ref('sale.sale_order_6')
count_lines = len(so.order_line)
untaxed_amount = so.amount_untaxed
tax_amount = so.amount_tax
total_amount = so.amount_total

product_set = self.env.ref(
'sale_product_set.product_set_i5_computer')
# Simulation the opening of the wizard and adding a set on the
Expand All @@ -29,18 +27,19 @@ def test_add_set(self):
so_set.add_set()
# checking our sale order
self.assertEqual(len(so.order_line), count_lines + 3)
# untaxed_amount + ((147*1*0.75)+(2100*1)+(85*2)) * 2
# 0.75 due to a 25% discount on Custom Computer (kit) product
self.assertEqual(so.amount_untaxed, untaxed_amount + 4760.5)
self.assertEqual(so.amount_tax, tax_amount + 0) # without tax
self.assertEqual(so.amount_total, total_amount + 4760.5)
# check all lines are included
for line in product_set.set_line_ids:
order_line = so.order_line.filtered(
lambda x: x.product_id == line.product_id
)
order_line.ensure_one()
self.assertEqual(
order_line.product_uom_qty, line.quantity * so_set.quantity
)

sequence = {}
for line in so.order_line:
sequence[line.product_id.id] = line.sequence
for set_line in product_set.set_line_ids:
if line.product_id.id == set_line.product_id.id:
self.assertEqual(line.product_id.name,
set_line.product_id.name)
# make sure sale order line sequence keep sequence set on set
seq_line1 = sequence.pop(
self.env.ref(
Expand All @@ -57,6 +56,18 @@ def test_add_set(self):
self.assertTrue(max([v for k, v in sequence.items()]) <
seq_line1 < seq_line2 < seq_line3)

def test_delete_set(self):
so = self.env.ref('sale.sale_order_6')
product_set = self.env.ref(
'sale_product_set.product_set_i5_computer')
# Simulation the opening of the wizard and adding a set on the
# current sale order
so_set = self.product_set_add.with_context(
active_id=so.id).create({'product_set_id': product_set.id,
'quantity': 2})
product_set.unlink()
self.assertFalse(so_set.exists())

def test_add_set_on_empty_so(self):
so = self.sale_order.create({
'partner_id': self.ref('base.res_partner_1')})
Expand All @@ -67,3 +78,57 @@ def test_add_set_on_empty_so(self):
'quantity': 2})
so_set.add_set()
self.assertEqual(len(so.order_line), 3)

def test_add_set_non_matching_partner(self):
so = self.sale_order.create({
'partner_id': self.ref('base.res_partner_1')})
product_set = self.env.ref(
'sale_product_set.product_set_i5_computer')
product_set.partner_id = self.ref('base.res_partner_2')
so_set = self.product_set_add.with_context(
active_id=so.id).create({'product_set_id': product_set.id,
'quantity': 2})
with self.assertRaises(exceptions.ValidationError):
so_set.add_set()

def test_add_set_no_update_existing_products(self):
so = self.sale_order.create({
'partner_id': self.ref('base.res_partner_1')})
product_set = self.env.ref(
'sale_product_set.product_set_i5_computer')
so_set = self.product_set_add.with_context(
active_id=so.id).create({'product_set_id': product_set.id,
'quantity': 2})
so_set.add_set()
self.assertEqual(len(so.order_line), 3)
# if we run it again by default the wizard sums up quantities
so_set.add_set()
self.assertEqual(len(so.order_line), 6)
# but we can turn it off
so_set.skip_existing_products = True
so_set.add_set()
self.assertEqual(len(so.order_line), 6)

def test_name(self):
product_set = self.env.ref(
'sale_product_set.product_set_i5_computer')
# no ref
product_set.name = 'Foo'
product_set.ref = ''
self.assertEqual(
product_set.name_get(),
[(product_set.id, 'Foo')]
)
# with ref
product_set.ref = '123'
self.assertEqual(
product_set.name_get(),
[(product_set.id, '[123] Foo')]
)
# with partner
partner = self.env.ref('base.res_partner_1')
product_set.partner_id = partner
self.assertEqual(
product_set.name_get(),
[(product_set.id, '[123] Foo @ %s' % partner.name)]
)
21 changes: 15 additions & 6 deletions sale_product_set/views/product_set.xml
Expand Up @@ -9,6 +9,7 @@
<tree string="Product set">
<field name="ref"/>
<field name="name"/>
<field name="partner_id"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>
Expand All @@ -29,11 +30,17 @@
options="{&quot;terminology&quot;: &quot;archive&quot;}"/>
</button>
</div>
<group>
<field name="name" select="1"/>
<field name="ref"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="set_line_ids">
<group name="main">
<group name="name">
<field name="name" select="1"/>
<field name="ref"/>
</group>
<group name="partner">
<field name="partner_id"/>
<field name="company_id" groups="base.group_multi_company"/>
</group>
<label for="set_line_ids" />
<field name="set_line_ids" nolabel="1">
<tree string="Product set lines" editable="top">
<field name="sequence" widget="handle"/>
<field name="product_id"/>
Expand All @@ -56,6 +63,8 @@
<search string="Product set">
<field name="name" select="True"/>
<field name="ref" select="True"/>
<field name="partner_id"/>
<filter name="group_by_partner_id" string="Partner" domain="[]" context="{'group_by':'partner_id'}"/>
</search>
</field>
</record>
Expand Down Expand Up @@ -86,7 +95,7 @@
</record>

<menuitem id="menu_product_set_config"
parent="sale.menu_sales_config"
parent="sale.product_menu_catalog"
groups="sales_team.group_sale_manager"
sequence="20"
action="act_open_product_set_view"/>
Expand Down
79 changes: 62 additions & 17 deletions sale_product_set/wizard/product_set_add.py
@@ -1,7 +1,7 @@
# Copyright 2015 Anybox S.A.S
# Copyright 2016-2018 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import models, fields, api
from odoo import models, fields, api, exceptions, _
import odoo.addons.decimal_precision as dp


Expand All @@ -10,37 +10,82 @@ class ProductSetAdd(models.TransientModel):
_rec_name = 'product_set_id'
_description = "Wizard model to add product set into a quotation"

order_id = fields.Many2one(
'sale.order', 'Sale Order', required=True,
default=lambda self: self.env.context.get('active_id'),
ondelete='cascade'
)
partner_id = fields.Many2one(
related='order_id.partner_id',
ondelete='cascade'
)
product_set_id = fields.Many2one(
'product.set', 'Product set', required=True)
'product.set', 'Product set',
required=True,
ondelete='cascade'
)
quantity = fields.Float(
digits=dp.get_precision('Product Unit of Measure'), required=True,
default=1)
skip_existing_products = fields.Boolean(
default=False,
help='Enable this to not add new lines '
'for products already included in SO lines.'
)

def _check_partner(self):
if self.product_set_id.partner_id:
if self.product_set_id.partner_id != self.order_id.partner_id:
raise exceptions.ValidationError(_(
"Select a product set assigned to "
"the same partner of the order."
))

@api.multi
def add_set(self):
""" Add product set, multiplied by quantity in sale order line """
so_id = self._context['active_id']
if not so_id:
return
so = self.env['sale.order'].browse(so_id)
self._check_partner()
order_lines = self._prepare_order_lines()
if order_lines:
self.order_id.write({
"order_line": order_lines
})
return order_lines

def _prepare_order_lines(self):
max_sequence = self._get_max_sequence()
order_lines = []
for set_line in self._get_lines():
order_lines.append(
(0, 0,
self.prepare_sale_order_line_data(
set_line, max_sequence=max_sequence))
)
return order_lines

def _get_max_sequence(self):
max_sequence = 0
if so.order_line:
max_sequence = max([line.sequence for line in so.order_line])
sale_order_line_env = self.env['sale.order.line']
sale_order_line = self.env['sale.order.line']
if self.order_id.order_line:
max_sequence = max([
line.sequence for line in self.order_id.order_line
])
return max_sequence

def _get_lines(self):
# hook here to take control on used lines
so_product_ids = self.order_id.order_line.mapped('product_id').ids
for set_line in self.product_set_id.set_line_ids:
sale_order_line |= sale_order_line_env.create(
self.prepare_sale_order_line_data(
so_id, set_line,
max_sequence=max_sequence))
return sale_order_line
if (self.skip_existing_products
and set_line.product_id.id in so_product_ids):
continue
yield set_line

@api.multi
def prepare_sale_order_line_data(self, sale_order_id, set_line,
def prepare_sale_order_line_data(self, set_line,
max_sequence=0):
self.ensure_one()
sale_line = self.env['sale.order.line'].new({
'order_id': sale_order_id,
'order_id': self.order_id.id,
'product_id': set_line.product_id.id,
'product_uom_qty': set_line.quantity * self.quantity,
'product_uom': set_line.product_id.uom_id.id,
Expand Down

0 comments on commit e674c96

Please sign in to comment.