commit 1925b23fbd9002375cdbd447519c8288ce7086e3 Author: pgu-odoo Date: Tue Dec 20 14:39:59 2016 +0100 [ADD] sale_coupon_delivery: Allow to offer a free shipping from a coupon diff --git a/__init__.py b/__init__.py new file mode 100644 index 00000000000..81fc81d29c9 --- /dev/null +++ b/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import models diff --git a/__manifest__.py b/__manifest__.py new file mode 100644 index 00000000000..f5a84c3da02 --- /dev/null +++ b/__manifest__.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +{ + 'name': "Sale Coupon Delivery", + 'summary': """Allows to offer free shippings in coupon reward""", + 'description': """Integrate coupon mechanism with shipping costs.""", + 'category': 'Sales', + 'version': '1.0', + 'depends': ['sale_coupon', 'delivery'], + 'data': [ + ], + 'demo': [ + ], + 'auto_install': True, +} diff --git a/models/__init__.py b/models/__init__.py new file mode 100644 index 00000000000..0d67cd44d37 --- /dev/null +++ b/models/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import sale_order +import sale_coupon_program +import sale_coupon_reward \ No newline at end of file diff --git a/models/sale_coupon.py b/models/sale_coupon.py new file mode 100644 index 00000000000..ccde14fcb89 --- /dev/null +++ b/models/sale_coupon.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + + +from odoo import models, _ + + +class SaleCoupon(models.Model): + _inherit = "sale.coupon" + + def _check_coupon_code(self, order): + if self.program_id.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(SaleCoupon, self)._check_coupon_code(order) diff --git a/models/sale_coupon_program.py b/models/sale_coupon_program.py new file mode 100644 index 00000000000..657cbaa179c --- /dev/null +++ b/models/sale_coupon_program.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + + +from odoo import models, _ + + +class SaleCouponProgram(models.Model): + _inherit = "sale.coupon.program" + + def _filter_not_ordered_reward_programs(self, order): + """ + Returns the programs when the reward is actually in the order lines + """ + programs = super(SaleCouponProgram, self)._filter_not_ordered_reward_programs(order) + for program in self: + if program.reward_type == 'free_shipping' and \ + not order.order_line.filtered(lambda line: line.is_delivery): + programs -= program + return programs + + def _check_promo_code(self, order, coupon_code): + 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) + diff --git a/models/sale_coupon_reward.py b/models/sale_coupon_reward.py new file mode 100644 index 00000000000..83be4f11976 --- /dev/null +++ b/models/sale_coupon_reward.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models, _ + + +class SaleCouponReward(models.Model): + _inherit = 'sale.coupon.reward' + _description = "Sales Coupon Reward" + + reward_type = fields.Selection(selection_add=[('free_shipping', 'Free Shipping')]) + + def name_get(self): + result = [] + reward_names = super(SaleCouponReward, self).name_get() + free_shipping_reward_ids = self.filtered(lambda reward: reward.reward_type == 'free_shipping').ids + for res in reward_names: + result.append((res[0], res[0] in free_shipping_reward_ids and _("Free Shipping") or res[1])) + return result diff --git a/models/sale_order.py b/models/sale_order.py new file mode 100644 index 00000000000..3924117d218 --- /dev/null +++ b/models/sale_order.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +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_reward_line_values(self, program): + if program.reward_type == 'free_shipping': + return self._get_reward_values_free_shipping(program) + else: + return super(SaleOrder, self)._get_reward_line_values(program) + + def _get_reward_values_free_shipping(self, program): + return { + 'name': "Discount: %s" % (program.name), + 'product_id': program.discount_line_product_id.id, + 'price_unit': - self.order_line.filtered(lambda x: x.is_delivery).price_unit, + 'product_uom_qty': 1.0, + 'product_uom': program.discount_line_product_id.uom_id.id, + 'order_id': self.id, + 'is_reward_line': True + } + + def _get_lines_unit_prices(self): + return [x.price_unit for x in self.order_line.filtered(lambda x: not x.is_delivery and not x.program_id)] diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000000..3a17aa142c0 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import test_free_shipping_reward \ No newline at end of file diff --git a/tests/test_free_shipping_reward.py b/tests/test_free_shipping_reward.py new file mode 100644 index 00000000000..fc8b6734919 --- /dev/null +++ b/tests/test_free_shipping_reward.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from openerp.addons.sale_coupon.tests.common import TestSaleCouponCommon + + +class TestSaleCouponProgramRules(TestSaleCouponCommon): + # Test a free shipping reward + some expected behavior + # (automatic line addition or removal) + + def test_free_shipping_reward(self): + # Test case 1: The minimum amount is not reached, the reward should + # not be created + self.immediate_promotion_program.active = False + self.env['sale.coupon.program'].create({ + 'name': 'Free Shipping if at least 100 euros', + 'promo_code_usage': 'no_code_needed', + 'reward_type': 'free_shipping', + 'rule_minimum_amount': 100.0, + 'active': True, + }) + + order = self.env['sale.order'].create({ + 'partner_id': self.steve.id, + }) + + order.write({'order_line': [ + (0, False, { + 'product_id': self.product_B.id, + 'name': 'Product B', + 'product_uom': self.uom_unit.id, + 'product_uom_qty': 1.0, + }) + ]}) + self.assertEqual(len(order.order_line.ids), 1) + + order.carrier_id = self.env['delivery.carrier'].search([])[1] + order.delivery_set() + self.assertEqual(len(order.order_line.ids), 2) + + # Test case 2: the amount is sufficient, the shipping should + # be reimbursed + order.write({'order_line': [ + (0, False, { + 'product_id': self.product_A.id, + 'name': 'Product 1', + 'product_uom': self.uom_unit.id, + 'product_uom_qty': 1.0, + 'price_unit': 1000 + }) + ]}) + + self.assertEqual(len(order.order_line.ids), 4) + + # Test case 3: the amount is not sufficient now, the reward should be removed + order.write({'order_line': [ + (2, order.order_line.filtered(lambda line: line.product_id.id == self.product_A.id).id, False) + ]}) + self.assertEqual(len(order.order_line.ids), 2)