[IMP] website_sale_coupon: garbage collect old order coupon
With this commit, when an ecommerce order is judged abandonned (more than 4 days without being touched, and in draft), we remove its coupon so it is available again. task-2058666 closes odoo/odoo#37441 Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import ir_autovacuum
|
||||
from . import sale_coupon_program
|
||||
from . import sale_order
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class AutoVacuum(models.AbstractModel):
|
||||
_inherit = 'ir.autovacuum'
|
||||
|
||||
@api.model
|
||||
def power_on(self, *args, **kwargs):
|
||||
self.env['sale.order']._garbage_collector(*args, **kwargs)
|
||||
return super(AutoVacuum, self).power_on(*args, **kwargs)
|
||||
@@ -1,5 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, fields, api
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.http import request
|
||||
|
||||
|
||||
@@ -50,7 +52,6 @@ class SaleOrder(models.Model):
|
||||
})
|
||||
order.website_order_line -= program_lines
|
||||
|
||||
|
||||
def _compute_cart_info(self):
|
||||
super(SaleOrder, self)._compute_cart_info()
|
||||
for order in self:
|
||||
@@ -75,3 +76,20 @@ class SaleOrder(models.Model):
|
||||
return self.env['sale.order.line']
|
||||
free_shipping_product_ids = free_shipping_prgs_ids.mapped('discount_line_product_id')
|
||||
return self.order_line.filtered(lambda l: l.product_id in free_shipping_product_ids)
|
||||
|
||||
@api.model
|
||||
def _garbage_collector(self, *args, **kwargs):
|
||||
"""Remove/free coupon from abandonned ecommerce order."""
|
||||
ICP = self.env['ir.config_parameter']
|
||||
validity = ICP.get_param('website_sale_coupon.abandonned_coupon_validity', 4)
|
||||
validity = fields.Datetime.to_string(fields.datetime.now() - timedelta(days=int(validity)))
|
||||
coupon_to_reset = self.env['sale.coupon'].search([
|
||||
('state', '=', 'used'),
|
||||
('sales_order_id.state', '=', 'draft'),
|
||||
('sales_order_id.write_date', '<', validity),
|
||||
('sales_order_id.website_id', '!=', False),
|
||||
])
|
||||
for coupon in coupon_to_reset:
|
||||
coupon.sales_order_id.applied_coupon_ids -= coupon
|
||||
coupon_to_reset.write({'state': 'new'})
|
||||
coupon_to_reset.mapped('sales_order_id').recompute_coupon_lines()
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo.tests import HttpCase, tagged
|
||||
from odoo import fields
|
||||
from odoo.tests import HttpCase, tagged, TransactionCase
|
||||
from odoo.addons.sale.tests.test_sale_product_attribute_value_config import TestSaleProductAttributeValueSetup
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestUi(TestSaleProductAttributeValueSetup, HttpCase):
|
||||
|
||||
post_install = True
|
||||
at_install = False
|
||||
|
||||
def setUp(self):
|
||||
super(TestUi, self).setUp()
|
||||
|
||||
@@ -22,3 +21,78 @@ class TestUi(TestSaleProductAttributeValueSetup, HttpCase):
|
||||
# pre enable "Show # found" option to avoid race condition...
|
||||
self.env.ref("website_sale.search_count_box").write({"active": True})
|
||||
self.start_tour("/", 'shop_sale_coupon', login="admin")
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestWebsiteSaleCoupon(TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestWebsiteSaleCoupon, self).setUp()
|
||||
program = self.env['sale.coupon.program'].create({
|
||||
'name': '10% TEST Discount',
|
||||
'promo_code_usage': 'code_needed',
|
||||
'discount_apply_on': 'on_order',
|
||||
'discount_type': 'percentage',
|
||||
'discount_percentage': 10.0,
|
||||
'program_type': 'coupon_program',
|
||||
})
|
||||
|
||||
self.env['sale.coupon.generate'].with_context(active_id=program.id).create({}).generate_coupon()
|
||||
self.coupon = program.coupon_ids[0]
|
||||
|
||||
self.steve = self.env['res.partner'].create({
|
||||
'name': 'Steve Bucknor',
|
||||
'email': 'steve.bucknor@example.com',
|
||||
})
|
||||
self.empty_order = self.env['sale.order'].create({
|
||||
'partner_id': self.steve.id
|
||||
})
|
||||
|
||||
def test_01_gc_coupon(self):
|
||||
# 1. Simulate a frontend order (website, product)
|
||||
order = self.empty_order
|
||||
order.website_id = self.env['website'].browse(1)
|
||||
self.env['sale.order.line'].create({
|
||||
'product_id': self.env['product.product'].create({
|
||||
'name': 'Product A',
|
||||
'list_price': 100,
|
||||
'sale_ok': True,
|
||||
}).id,
|
||||
'name': 'Product A',
|
||||
'product_uom_qty': 2.0,
|
||||
'order_id': order.id,
|
||||
})
|
||||
|
||||
# 2. Apply the coupon
|
||||
self.env['sale.coupon.apply.code'].with_context(active_id=order.id).create({
|
||||
'coupon_code': self.coupon.code
|
||||
}).process_coupon()
|
||||
order.recompute_coupon_lines()
|
||||
|
||||
self.assertEqual(len(order.applied_coupon_ids), 1, "The coupon should've been applied on the order")
|
||||
self.assertEqual(self.coupon, order.applied_coupon_ids)
|
||||
self.assertEqual(self.coupon.state, 'used')
|
||||
|
||||
# 3. Test recent order -> Should not be removed
|
||||
order._garbage_collector()
|
||||
|
||||
self.assertEqual(len(order.applied_coupon_ids), 1, "The coupon shouldn't have been removed from the order no more than 4 days")
|
||||
self.assertEqual(self.coupon.state, 'used', "Should not have been changed")
|
||||
|
||||
# 4. Test order not older than ICP validity -> Should not be removed
|
||||
ICP = self.env['ir.config_parameter']
|
||||
icp_validity = ICP.create({'key': 'website_sale_coupon.abandonned_coupon_validity', 'value': 5})
|
||||
order.flush()
|
||||
query = """UPDATE %s SET write_date = %%s WHERE id = %%s""" % (order._table,)
|
||||
self.env.cr.execute(query, (fields.Datetime.to_string(fields.datetime.now() - timedelta(days=4, hours=2)), order.id))
|
||||
order._garbage_collector()
|
||||
|
||||
self.assertEqual(len(order.applied_coupon_ids), 1, "The coupon shouldn't have been removed from the order the order is 4 days old but icp validity is 5 days")
|
||||
self.assertEqual(self.coupon.state, 'used', "Should not have been changed (2)")
|
||||
|
||||
# 5. Test order with no ICP and older then 4 default days -> Should be removed
|
||||
icp_validity.unlink()
|
||||
order._garbage_collector()
|
||||
|
||||
self.assertEqual(len(order.applied_coupon_ids), 0, "The coupon should've been removed from the order as more than 4 days")
|
||||
self.assertEqual(self.coupon.state, 'new', "Should have been reset.")
|
||||
|
||||
Reference in New Issue
Block a user