Skip to content

Commit

Permalink
[FIX+IMP] purchase_discount: report + tests + comments + dates
Browse files Browse the repository at this point in the history
* Adjusted purchase.report to new inheritance structure
* Split tests in 2 files
* Added comments about PR for using the hook
* Fix date handling
  • Loading branch information
pedrobaeza committed Aug 8, 2019
1 parent bb85089 commit 8ba4393
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 185 deletions.
5 changes: 2 additions & 3 deletions purchase_discount/models/procurement_rule.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Copyright 2016 ACSONE SA/NV (<http://acsone.eu>)
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from odoo import api, fields, models
from odoo import api, models


class ProcurementRule(models.Model):
Expand All @@ -14,8 +14,7 @@ def _prepare_purchase_order_line(self, product_id, product_qty,
product_id, product_qty, product_uom, values, po, partner)
date = None
if po.date_order:
date = fields.Date.to_string(
fields.Date.from_string(po.date_order))
date = po.date_order.date()
seller = product_id._select_seller(
partner_id=partner,
quantity=product_qty,
Expand Down
8 changes: 5 additions & 3 deletions purchase_discount/models/purchase_order.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Copyright 2004-2009 Tiny SPRL (<http://tiny.be>).
# Copyright 2016 ACSONE SA/NV (<http://acsone.eu>)
# Copyright 2015-2017 Tecnativa - Pedro M. Baeza
# Copyright 2015-2019 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, fields, models
Expand Down Expand Up @@ -61,6 +61,9 @@ def _get_stock_move_price_unit(self):
"""Get correct price with discount replacing current price_unit
value before calling super and restoring it later for assuring
maximum inheritability.
HACK: This is needed while https://github.com/odoo/odoo/pull/29983
is not merged.
"""
price_unit = False
price = self._get_discounted_price_unit()
Expand All @@ -83,8 +86,7 @@ def _onchange_quantity(self):
if self.product_id:
date = None
if self.order_id.date_order:
date = fields.Date.to_string(
fields.Date.from_string(self.order_id.date_order))
date = self.order_id.date_order.date()
seller = self.product_id._select_seller(
partner_id=self.partner_id, quantity=self.product_qty,
date=date, uom_id=self.product_uom)
Expand Down
3 changes: 3 additions & 0 deletions purchase_discount/models/stock_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ def _get_price_unit(self):
"""Get correct price with discount replacing current price_unit
value before calling super and restoring it later for assuring
maximum inheritability.
HACK: This is needed while https://github.com/odoo/odoo/pull/29983
is not merged.
"""
price_unit = False
po_line = self.purchase_line_id
Expand Down
52 changes: 15 additions & 37 deletions purchase_discount/report/purchase_report.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Copyright 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# Copyright 2017 Tecnativa - Pedro M. Baeza
# Copyright 2017-2019 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, fields, models, tools
from odoo import fields, models
import odoo.addons.decimal_precision as dp


Expand All @@ -14,13 +14,19 @@ class PurchaseReport(models.Model):
group_operator="avg",
)

def _select_purchase_discount(self):
return """
, l.discount AS discount
"""
def _select(self):
res = super()._select()
# There are 3 matches
res = res.replace(
'l.price_unit', self._get_discounted_price_unit_exp(),
)
res += ", l.discount AS discount"
return res

def _group_by_purchase_discount(self):
return ", l.discount"
def _group_by(self):
res = super()._group_by()
res += ", l.discount"
return res

def _get_discounted_price_unit_exp(self):
"""Inheritable method for getting the SQL expression used for
Expand All @@ -29,32 +35,4 @@ def _get_discounted_price_unit_exp(self):
:rtype: str
:return: SQL expression for discounted unit price.
"""
return '(1.0 - COALESCE(l.discount, 0.0) / 100.0) * l.price_unit '

@api.model_cr
def init(self):
"""Inject parts in the query with this hack, fetching the query and
recreating it. Query is returned all in upper case and with final ';'.
"""
super(PurchaseReport, self).init()
self._cr.execute("SELECT pg_get_viewdef(%s, true)", (self._table,))
view_def = self._cr.fetchone()[0]
if view_def[-1] == ';': # Remove trailing semicolon
view_def = view_def[:-1]
view_def = view_def.replace(
"FROM purchase_order_line",
"{} FROM purchase_order_line".format(
self._select_purchase_discount()
),
)
view_def += self._group_by_purchase_discount()
# Replace the expression with space for avoiding to replace in the
# group by part
view_def = view_def.replace(
'l.price_unit ', self._get_discounted_price_unit_exp(),
)
# Re-create view
tools.drop_view_if_exists(self._cr, self._table)
self._cr.execute("create or replace view {} as ({})".format(
self._table, view_def,
))
return '(1.0 - COALESCE(l.discount, 0.0) / 100.0) * l.price_unit'
3 changes: 2 additions & 1 deletion purchase_discount/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# (c) 2015 Pedro M. Baeza
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

from . import test_product_supplierinfo_discount
from . import test_purchase_discount
142 changes: 142 additions & 0 deletions purchase_discount/tests/test_product_supplierinfo_discount.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# Copyright 2018 GRAP - Sylvain Legal
# Copyright 2019 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import odoo.tests.common as common
from odoo import fields


class TestProductSupplierinfoDiscount(common.SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.supplierinfo_model = cls.env['product.supplierinfo']
cls.purchase_order_line_model = cls.env['purchase.order.line']
cls.partner_1 = cls.env.ref('base.res_partner_1')
cls.partner_3 = cls.env.ref('base.res_partner_3')
cls.product = cls.env.ref('product.product_product_6')
cls.supplierinfo = cls.supplierinfo_model.create({
'min_qty': 0.0,
'name': cls.partner_3.id,
'product_tmpl_id': cls.product.product_tmpl_id.id,
'discount': 10,
})
cls.supplierinfo2 = cls.supplierinfo_model.create({
'min_qty': 10.0,
'name': cls.partner_3.id,
'product_tmpl_id': cls.product.product_tmpl_id.id,
'discount': 20,
})
cls.purchase_order = cls.env['purchase.order'].create(
{'partner_id': cls.partner_3.id})
cls.po_line_1 = cls.purchase_order_line_model.create(
{'order_id': cls.purchase_order.id,
'product_id': cls.product.id,
'date_planned': fields.Datetime.now(),
'name': 'Test',
'product_qty': 1.0,
'product_uom': cls.env.ref('uom.product_uom_categ_unit').id,
'price_unit': 10.0})

def test_001_purchase_order_partner_3_qty_1(self):
self.po_line_1._onchange_quantity()
self.assertEquals(
self.po_line_1.discount, 10,
"Incorrect discount for product 6 with partner 3 and qty 1: "
"Should be 10%")

def test_002_purchase_order_partner_3_qty_10(self):
self.po_line_1.write({'product_qty': 10})
self.po_line_1._onchange_quantity()
self.assertEquals(
self.po_line_1.discount, 20.0,
"Incorrect discount for product 6 with partner 3 and qty 10: "
"Should be 20%")

def test_003_purchase_order_partner_1_qty_1(self):
self.po_line_1.write({
'partner_id': self.partner_1.id,
'product_qty': 1,
})
self.po_line_1.onchange_product_id()
self.assertEquals(
self.po_line_1.discount, 0.0, "Incorrect discount for product "
"6 with partner 1 and qty 1")

def test_004_prepare_purchase_order_line(self):
procurement_rule = self.env['stock.rule'].create({
'sequence': 20,
'location_id': self.env.ref('stock.stock_location_locations').id,
'picking_type_id': self.env.ref('stock.chi_picking_type_in').id,
'warehouse_id': self.env.ref('stock.warehouse0').id,
'propagate': True,
'procure_method': 'make_to_stock',
'route_sequence': 5.0,
'name': 'YourCompany: Buy',
'route_id': self.env.ref('stock.route_warehouse0_mto').id,
'action': 'buy',
})
po_line_vals = {
'origin': 'SO012:WH: Stock -> Customers MTO',
'product_uom': self.env.ref('uom.product_uom_unit').id,
'product_qty': 50,
'location_id': self.env.ref('stock.stock_location_locations').id,
'company_id': self.env.ref('base.main_company'),
'state': 'confirmed',
'warehouse_id': self.env.ref('stock.warehouse0').id,
'move_dest_id': self.env.ref('stock.stock_location_customers').id,
'message_unread_counter': 0,
'name': 'WH: Stock -> Customers MTO',
'product_id': self.product.id,
'date_planned': fields.Datetime.now(),
'rule_id': procurement_rule.id,
}
res = procurement_rule._prepare_purchase_order_line(
self.product, 50, self.env.ref('uom.product_uom_unit'),
po_line_vals, self.purchase_order, self.supplierinfo.name,
)
self.assertTrue(res.get('discount'), 'Should have a discount key')

def test_005_default_supplierinfo_discount(self):
# Create an original supplierinfo
supplierinfo = self.supplierinfo_model.create({
'min_qty': 0.0,
'name': self.partner_3.id,
'product_tmpl_id': self.product.product_tmpl_id.id,
'discount': 10,
})
# Change the partner and raise onchange function
self.partner_1.default_supplierinfo_discount = 15
supplierinfo.name = self.partner_1
supplierinfo.onchange_name()
self.assertEquals(
supplierinfo.discount, 15, "Incorrect discount for supplierinfo "
" after changing partner that has default discount defined.")

def test_006_supplierinfo_from_purchaseorder(self):
""" Include discount when creating new sellers for a product """
partner = self.env.ref('base.res_partner_3')
product = self.env.ref('product.product_product_8')
self.assertFalse(
self.supplierinfo_model.search([
('name', '=', partner.id),
('product_tmpl_id', '=', product.product_tmpl_id.id)]))
order = self.env['purchase.order'].create({
'partner_id': partner.id,
})
self.purchase_order_line_model.create({
'date_planned': fields.Datetime.now(),
'discount': 40,
'name': product.name,
'price_unit': 10.0,
'product_id': product.id,
'product_qty': 1.0,
'product_uom': product.uom_po_id.id,
'order_id': order.id,
})
order.button_confirm()
seller = self.supplierinfo_model.search([
('name', '=', partner.id),
('product_tmpl_id', '=', product.product_tmpl_id.id)])
self.assertTrue(seller)
self.assertEqual(seller.discount, 40)

0 comments on commit 8ba4393

Please sign in to comment.