summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2018-03-01 18:18:16 +0100
committerChristophe Simonis <chs@odoo.com>2018-03-01 18:18:16 +0100
commitbea2238884a0260f00a2f1d6fd85d4d24c5aebe9 (patch)
tree614d3e01c8c5c6e090e00fb1e472fac86e34f978
parent90e48d02f698a28d4c9544082068c7d215fb4aa4 (diff)
parentbc75ec7c1426866550ef26b8fd53294962f5ffd7 (diff)
[MERGE] forward port branch saas-15 up to 9aca5ca19d0
-rw-r--r--models/sale_coupon_program.py17
-rw-r--r--models/sale_order.py18
-rw-r--r--tests/test_free_shipping_reward.py107
3 files changed, 117 insertions, 25 deletions
diff --git a/models/sale_coupon_program.py b/models/sale_coupon_program.py
index d0d1e9ad786..53995810def 100644
--- a/models/sale_coupon_program.py
+++ b/models/sale_coupon_program.py
@@ -22,20 +22,3 @@ class SaleCouponProgram(models.Model):
if self.reward_type == 'free_shipping' and not order.order_line.filtered(lambda line: line.is_delivery):
return {'error': _('The shipping costs are not in the order lines.')}
return super(SaleCouponProgram, self)._check_promo_code(order, coupon_code)
-
- @api.model
- def _filter_on_mimimum_amount(self, order):
- # To get actual total amount of SO without any reward or discount
- # We exclude any line of the order that is a delivery
- # get the round function of the currency: we want to imitate what the sale.order.amount is (computed field)
- round_curr = order.pricelist_id.currency_id.round
- order_lines = order.order_line.filtered(lambda l: not l.is_delivery)
- order_amount = round_curr(sum(order_lines.mapped('price_subtotal')))
- order_tax = round_curr(sum(order_lines.mapped('price_tax')))
- discounted_amount = sum(order_lines.filtered(lambda line: line.is_reward_line).mapped('price_total'))
- untaxed_amount = order_amount - discounted_amount
- return self.filtered(lambda program:
- program.rule_minimum_amount_tax_inclusion == 'tax_included' and
- program._compute_program_amount('rule_minimum_amount', order.currency_id) <= untaxed_amount + order_tax or
- program.rule_minimum_amount_tax_inclusion == 'tax_excluded' and
- program._compute_program_amount('rule_minimum_amount', order.currency_id) <= untaxed_amount)
diff --git a/models/sale_order.py b/models/sale_order.py
index a6968eb5a07..7be352afd52 100644
--- a/models/sale_order.py
+++ b/models/sale_order.py
@@ -1,14 +1,22 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo import models
+from odoo import models, _
class SaleOrder(models.Model):
_inherit = "sale.order"
- def _get_order_lines_untaxed_amount(self):
- """ Returns the untaxed sale order total amount without the rewards and shipping amount"""
- return sum([x.price_subtotal for x in self.order_line.filtered(lambda x: not (x.is_reward_line or x.is_delivery))])
+ def _get_no_effect_on_threshold_lines(self):
+ self.ensure_one()
+ # Do not count shipping and free shipping
+ free_delivery_product = self.env['sale.coupon.program'].search([('reward_type', '=', 'free_shipping')]).mapped('discount_line_product_id')
+ lines = self.order_line.filtered(lambda line: line.is_delivery or line.product_id in free_delivery_product)
+ return lines + super(SaleOrder, self)._get_no_effect_on_threshold_lines()
+
+ def _get_order_lines_tax_included_amount(self):
+ """ Returns the taxes included sale order total amount without the rewards amount"""
+ free_reward_product = self.env['sale.coupon.program'].search([('reward_type', '=', 'product')]).mapped('discount_line_product_id')
+ return sum([x.price_total for x in self.order_line.filtered(lambda x: not (x.is_reward_line or x.is_delivery) or x.product_id in free_reward_product)])
def _get_reward_line_values(self, program):
if program.reward_type == 'free_shipping':
@@ -22,7 +30,7 @@ class SaleOrder(models.Model):
if self.fiscal_position_id:
taxes = self.fiscal_position_id.map_tax(taxes)
return {
- 'name': "Discount: %s" % (program.name),
+ 'name': _("Discount: ") + program.name,
'product_id': program.discount_line_product_id.id,
'price_unit': delivery_line and - delivery_line.price_unit or 0.0,
'product_uom_qty': 1.0,
diff --git a/tests/test_free_shipping_reward.py b/tests/test_free_shipping_reward.py
index 152a7ac7d31..d2ca33038d9 100644
--- a/tests/test_free_shipping_reward.py
+++ b/tests/test_free_shipping_reward.py
@@ -5,6 +5,11 @@ from openerp.addons.sale_coupon.tests.common import TestSaleCouponCommon
class TestSaleCouponProgramRules(TestSaleCouponCommon):
+
+ def setUp(self):
+ super(TestSaleCouponProgramRules, self).setUp()
+ self.iPadMini = self.env.ref('product.product_product_6').copy()
+
# Test a free shipping reward + some expected behavior
# (automatic line addition or removal)
@@ -17,6 +22,7 @@ class TestSaleCouponProgramRules(TestSaleCouponCommon):
'promo_code_usage': 'no_code_needed',
'reward_type': 'free_shipping',
'rule_minimum_amount': 100.0,
+ 'rule_minimum_amount_tax_inclusion': 'tax_included',
'active': True,
})
@@ -46,7 +52,6 @@ class TestSaleCouponProgramRules(TestSaleCouponCommon):
# Test Case 1b: amount is not reached but is on a threshold
# The amount of deliverable product + the one of the delivery exceeds the minimum amount
# yet the program shouldn't be applied
-
# Order price will be 5.75 + 81.74*1.15 = 99.75
order.write({'order_line': [
(0, False, {
@@ -57,7 +62,6 @@ class TestSaleCouponProgramRules(TestSaleCouponCommon):
'price_unit': 81.74,
})
]})
-
order.recompute_coupon_lines()
self.assertEqual(len(order.order_line.ids), 3)
@@ -69,7 +73,7 @@ class TestSaleCouponProgramRules(TestSaleCouponCommon):
'name': 'Product 1',
'product_uom': self.uom_unit.id,
'product_uom_qty': 1.0,
- 'price_unit': 1000
+ 'price_unit': 0.30,
})
]})
@@ -82,3 +86,100 @@ class TestSaleCouponProgramRules(TestSaleCouponCommon):
]})
order.recompute_coupon_lines()
self.assertEqual(len(order.order_line.ids), 3)
+
+ def test_shipping_cost(self):
+ # Free delivery should not be taken into account when checking for minimum required threshold
+ p_minimum_threshold_free_delivery = self.env['sale.coupon.program'].create({
+ 'name': 'free shipping if > 872 tax exl',
+ 'promo_code_usage': 'no_code_needed',
+ 'reward_type': 'free_shipping',
+ 'program_type': 'promotion_program',
+ 'rule_minimum_amount': 872,
+ })
+ p_minimum_threshold_discount = self.env['sale.coupon.program'].create({
+ 'name': '10% reduction if > 872 tax exl',
+ 'promo_code_usage': 'no_code_needed',
+ 'reward_type': 'discount',
+ 'program_type': 'promotion_program',
+ 'discount_type': 'percentage',
+ 'discount_percentage': 10.0,
+ 'rule_minimum_amount': 872,
+ })
+ order = self.empty_order
+ self.iPadMini.taxes_id = self.tax_10pc_incl
+ sol1 = self.env['sale.order.line'].create({
+ 'product_id': self.iPadMini.id,
+ 'name': 'iPad Mini',
+ 'product_uom_qty': 3.0,
+ 'order_id': order.id,
+ })
+ order.recompute_coupon_lines()
+ self.assertEqual(len(order.order_line.ids), 2, "We should get the 10% discount line since we bought 872.73$")
+ order.carrier_id = self.env['delivery.carrier'].search([])[1]
+ order.delivery_set()
+
+ order.recompute_coupon_lines()
+ self.assertEqual(len(order.order_line.ids), 3, "We should get the delivery line but not the free delivery since we are below 872.73$ with the 10% discount")
+
+ p_minimum_threshold_free_delivery.sequence = 10
+ order.recompute_coupon_lines()
+ self.assertEqual(len(order.order_line.ids), 4, "We should get both promotion line since the free delivery will be applied first and won't change the SO total")
+
+ def test_shipping_cost_numbers(self):
+ # Free delivery should not be taken into account when checking for minimum required threshold
+ tax_15pc_excl = self.env['account.tax'].create({
+ 'name': "15% Tax excl",
+ 'amount_type': 'percent',
+ 'amount': 15,
+ })
+ p_minimum_threshold_free_delivery = self.env['sale.coupon.program'].create({
+ 'name': 'free shipping if > 872 tax exl',
+ 'promo_code_usage': 'code_needed',
+ 'promo_code': 'free_shipping',
+ 'reward_type': 'free_shipping',
+ 'program_type': 'promotion_program',
+ 'rule_minimum_amount': 872,
+ })
+ self.p2 = self.env['sale.coupon.program'].create({
+ 'name': 'Buy 4 ipads, get one for free',
+ 'promo_code_usage': 'no_code_needed',
+ 'reward_type': 'product',
+ 'program_type': 'promotion_program',
+ 'reward_product_id': self.iPadMini.id,
+ 'rule_min_quantity': 3,
+ 'rule_products_domain': '[["name","ilike","ipad mini"]]',
+ })
+ order = self.empty_order
+ self.iPadMini.taxes_id = self.tax_10pc_incl
+ sol1 = self.env['sale.order.line'].create({
+ 'product_id': self.iPadMini.id,
+ 'name': 'iPad Mini',
+ 'product_uom_qty': 3.0,
+ 'order_id': order.id,
+ })
+ # The delivery product has 15% tax on dball but not on dbbase. A module is probably adding the tax at some point.
+ # We want that tax to be set so we can be sure it is not added to the order total paid amount used in coupon as
+ # it was wrongly done before.
+ self.env.ref('delivery.delivery_carrier').taxes_id = tax_15pc_excl
+ order.carrier_id = self.env['delivery.carrier'].search([])[1]
+ order.delivery_set()
+ order.recompute_coupon_lines()
+ self.assertEqual(len(order.order_line.ids), 2, "")
+ self.assertEqual(order.reward_amount, 0)
+ # Shipping is 20 + 15%tax
+ self.assertEqual(sum([line.price_total for line in order._get_no_effect_on_threshold_lines()]), 23)
+ self.assertEqual(order.amount_untaxed, 872.73 + 20)
+
+ self.env['sale.coupon.apply.code'].sudo().apply_coupon(order, 'free_shipping')
+ order.recompute_coupon_lines()
+ self.assertEqual(len(order.order_line.ids), 3, "We should get the delivery line and the free delivery since we are below 872.73$ with the 10% discount")
+ self.assertEqual(order.reward_amount, -20)
+ self.assertEqual(sum([line.price_total for line in order._get_no_effect_on_threshold_lines()]), 0)
+ self.assertEqual(order.amount_untaxed, 872.73)
+
+ sol1.product_uom_qty = 4
+ order.recompute_coupon_lines()
+ self.assertEqual(len(order.order_line.ids), 4, "We should get a free iPad Mini")
+ self.assertEqual(order.reward_amount, -20 -290.91)
+ self.assertEqual(sum([line.price_total for line in order._get_no_effect_on_threshold_lines()]), 0)
+ self.assertEqual(order.amount_untaxed, 872.73) \ No newline at end of file