[IMP] sale_coupon: coupon layout and usability improve

some layout fixed and confusing string of promo_applicability option is
changed to 'Send a Coupon' form 'Apply On Next Order'.

Task-ID: 2027296
Closes #34620
This commit is contained in:
mgh-odoo
2020-01-31 11:11:56 +00:00
committed by Damien Bouvy
parent 9d9d362d70
commit c2775164ab
8 changed files with 42 additions and 16 deletions
@@ -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)
+6 -3
View File
@@ -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)}
@@ -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')
@@ -66,10 +66,12 @@
<img alt="Barcode" t-att-src="'/report/barcode/Code128/%s' % o.code"/>
<br/>
<div class="mt64">
<div class="col-6 text-right">
<div class="text-center">
<img alt="Logo" t-att-src="'/logo?company=%d' % (o.program_id.company_id)" t-att-alt="'%s' % (o.program_id.company_id.name)" style="border:0px solid transparent; height: 50; width: 200px;" height="50"/>
</div>
<div class="col-6 text-left">
</div>
<div>
<div class="text-center d-inline-block">
<span t-field="o.program_id.company_id.partner_id"
t-options='{"widget": "contact", "fields": ["address", "email"], "no_marker": True}'/>
</div>
@@ -232,12 +232,6 @@
<group>
<field name="promo_applicability" widget="radio"/>
</group>
<group>
<span class="oe_grey">
<b>Apply on Current Order -</b> Reward will be applied on current order.<br/>
<b>Apply on Next Order -</b> Generate a coupon for a next order.
</span>
</group>
</xpath>
</field>
</record>
@@ -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
@@ -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
@@ -6,10 +6,14 @@
<field name="arch" type="xml">
<form string="Generate Coupons">
<group>
<field name="has_partner_email" invisible="1"/>
<field name="generation_type" widget="radio"/>
<field name="partners_domain" attrs="{'invisible': [('generation_type', '!=', 'nbr_customer')]}" widget="domain" options="{'model': 'res.partner'}"/>
<field name="nbr_coupons" attrs="{'invisible': [('generation_type', '!=', 'nbr_coupon')]}"/>
</group>
<div role="alert" class="alert alert-warning" attrs="{'invisible': ['|', ('generation_type', '!=', 'nbr_customer'), ('has_partner_email', '=', True)]}">
Some selected customers do not have an email address and will not receive the coupon.
</div>
<footer>
<button name="generate_coupon" type="object" string="Generate" class="oe_highlight"/>
<button special="cancel" string="Cancel"/>