diff options
| author | Christophe Simonis <chs@odoo.com> | 2018-03-01 18:18:16 +0100 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2018-03-01 18:18:16 +0100 |
| commit | bea2238884a0260f00a2f1d6fd85d4d24c5aebe9 (patch) | |
| tree | 614d3e01c8c5c6e090e00fb1e472fac86e34f978 | |
| parent | 90e48d02f698a28d4c9544082068c7d215fb4aa4 (diff) | |
| parent | bc75ec7c1426866550ef26b8fd53294962f5ffd7 (diff) | |
[MERGE] forward port branch saas-15 up to 9aca5ca19d0
| -rw-r--r-- | models/sale_coupon_program.py | 17 | ||||
| -rw-r--r-- | models/sale_order.py | 18 | ||||
| -rw-r--r-- | tests/test_free_shipping_reward.py | 107 |
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 |
