diff --git a/addons/sale_coupon/models/mail_compose_message.py b/addons/sale_coupon/models/mail_compose_message.py new file mode 100644 index 00000000000..f9e1a8ffbc0 --- /dev/null +++ b/addons/sale_coupon/models/mail_compose_message.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 MailComposeMessage(models.TransientModel): + _inherit = 'mail.compose.message' + + def send_mail(self, **kwargs): + for wizard in self: + if self._context.get('mark_coupon_as_sent') and wizard.model == 'sale.coupon' and wizard.partner_ids: + self.env[wizard.model].browse(wizard.res_id).state = 'sent' + return super().send_mail(**kwargs) diff --git a/addons/sale_coupon/models/sale_coupon.py b/addons/sale_coupon/models/sale_coupon.py index 934c1367e2f..4a0ae195bfc 100644 --- a/addons/sale_coupon/models/sale_coupon.py +++ b/addons/sale_coupon/models/sale_coupon.py @@ -53,11 +53,14 @@ class SaleCoupon(models.Model): def _check_coupon_code(self, order): message = {} applicable_programs = order._get_applicable_programs() - if self.state in ('used', 'expired') or \ - (self.expiration_date and self.expiration_date < order.date_order.date()): - message = {'error': _('This coupon %s has been used or is expired.') % (self.code)} + if self.state == 'used': + message = {'error': _('This coupon has already been used (%s).') % (self.code)} elif self.state == 'reserved': message = {'error': _('This coupon %s exists but the origin sales order is not validated yet.') % (self.code)} + elif self.state == 'cancel': + message = {'error': _('This coupon has been cancelled (%s).') % (self.code)} + elif self.state == 'expired' or (self.expiration_date and self.expiration_date < order.date_order.date()): + message = {'error': _('This coupon is expired (%s).') % (self.code)} # Minimum requirement should not be checked if the coupon got generated by a promotion program (the requirement should have only be checked to generate the coupon) elif self.program_id.program_type == 'coupon_program' and not self.program_id._filter_on_mimimum_amount(order): message = {'error': _('A minimum of %s %s should be purchased to get the reward') % (self.program_id.rule_minimum_amount, self.program_id.currency_id.name)} diff --git a/addons/sale_coupon/models/sale_coupon_program.py b/addons/sale_coupon/models/sale_coupon_program.py index 82fe37f5346..d7db3360316 100644 --- a/addons/sale_coupon/models/sale_coupon_program.py +++ b/addons/sale_coupon/models/sale_coupon_program.py @@ -43,14 +43,14 @@ class SaleCouponProgram(models.Model): help="A promotion code is a code that is associated with a marketing discount. For example, a retailer might tell frequent customers to enter the promotion code 'THX001' to receive a 10%% discount on their whole order.") promo_applicability = fields.Selection([ ('on_current_order', 'Apply On Current Order'), - ('on_next_order', 'Apply On Next Order')], + ('on_next_order', 'Send a Coupon')], default='on_current_order', string="Applicability") coupon_ids = fields.One2many('sale.coupon', 'program_id', string="Generated Coupons", copy=False) coupon_count = fields.Integer(compute='_compute_coupon_count') order_count = fields.Integer(compute='_compute_order_count') company_id = fields.Many2one('res.company', string="Company", default=lambda self: self.env.company) currency_id = fields.Many2one(string="Currency", related='company_id.currency_id', readonly=True) - validity_duration = fields.Integer(default=1, + validity_duration = fields.Integer(default=30, help="Validity duration for a coupon after its generation") @api.constrains('promo_code') diff --git a/addons/sale_coupon/report/sale_coupon_report_templates.xml b/addons/sale_coupon/report/sale_coupon_report_templates.xml index aa1751f90ed..ad1076a6dc7 100644 --- a/addons/sale_coupon/report/sale_coupon_report_templates.xml +++ b/addons/sale_coupon/report/sale_coupon_report_templates.xml @@ -66,10 +66,12 @@ Barcode
-
+
Logo
-
+
+
+
diff --git a/addons/sale_coupon/views/sale_coupon_program_views.xml b/addons/sale_coupon/views/sale_coupon_program_views.xml index 397f65907b1..1c6d1b8d184 100644 --- a/addons/sale_coupon/views/sale_coupon_program_views.xml +++ b/addons/sale_coupon/views/sale_coupon_program_views.xml @@ -232,12 +232,6 @@ - - - Apply on Current Order - Reward will be applied on current order.
- Apply on Next Order - Generate a coupon for a next order. -
-
diff --git a/addons/sale_coupon/wizard/sale_coupon_apply_code.py b/addons/sale_coupon/wizard/sale_coupon_apply_code.py index fde5b1bdec6..2b9e0e95fc1 100644 --- a/addons/sale_coupon/wizard/sale_coupon_apply_code.py +++ b/addons/sale_coupon/wizard/sale_coupon_apply_code.py @@ -50,5 +50,5 @@ class SaleCouponApplyCode(models.TransientModel): order.applied_coupon_ids += coupon coupon.write({'state': 'used'}) else: - error_status = {'not_found': _('The code %s is invalid') % (coupon_code)} + error_status = {'not_found': _('This coupon is invalid (%s).') % (coupon_code)} return error_status diff --git a/addons/sale_coupon/wizard/sale_coupon_generate.py b/addons/sale_coupon/wizard/sale_coupon_generate.py index fcca4e65a8f..cadf07e4016 100644 --- a/addons/sale_coupon/wizard/sale_coupon_generate.py +++ b/addons/sale_coupon/wizard/sale_coupon_generate.py @@ -3,6 +3,7 @@ from odoo import api, fields, models import ast +from odoo.osv import expression class SaleCouponGenerate(models.TransientModel): @@ -15,6 +16,7 @@ class SaleCouponGenerate(models.TransientModel): ('nbr_customer', 'Number of Selected Customers') ], default='nbr_coupon') partners_domain = fields.Char(string="Customer", default='[]') + has_partner_email = fields.Boolean(compute='_compute_has_partner_email') def generate_coupon(self): """Generates the number of coupons entered in wizard field nbr_coupons @@ -29,9 +31,16 @@ class SaleCouponGenerate(models.TransientModel): if self.generation_type == 'nbr_customer' and self.partners_domain: for partner in self.env['res.partner'].search(ast.literal_eval(self.partners_domain)): - vals.update({'partner_id': partner.id}) + vals.update({'partner_id': partner.id, 'state': 'sent' if partner.email else 'new'}) coupon = self.env['sale.coupon'].create(vals) subject = '%s, a coupon has been generated for you' % (partner.name) template = self.env.ref('sale_coupon.mail_template_sale_coupon', raise_if_not_found=False) if template: - template.send_mail(coupon.id, email_values={'email_to': partner.email, 'email_from': self.env.user.email or '', 'subject': subject,}) + email_values = {'email_to': partner.email, 'email_from': self.env.user.email or '', 'subject': subject} + template.send_mail(coupon.id, email_values=email_values, notif_layout='mail.mail_notification_light') + + @api.depends('partners_domain') + def _compute_has_partner_email(self): + for record in self: + domain = expression.AND([safe_eval(record.partners_domain), [('email', '=', False)]]) + record.has_partner_email = self.env['res.partner'].search_count(domain) == 0 diff --git a/addons/sale_coupon/wizard/sale_coupon_generate_views.xml b/addons/sale_coupon/wizard/sale_coupon_generate_views.xml index 449be83e9d1..f1413a2c31a 100644 --- a/addons/sale_coupon/wizard/sale_coupon_generate_views.xml +++ b/addons/sale_coupon/wizard/sale_coupon_generate_views.xml @@ -6,10 +6,14 @@
+ +