195 lines
9.6 KiB
Python
195 lines
9.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from collections import defaultdict
|
|
from odoo import _, models
|
|
from odoo.tools import float_compare
|
|
import base64
|
|
|
|
class PosOrder(models.Model):
|
|
_inherit = 'pos.order'
|
|
|
|
def validate_coupon_programs(self, point_changes, new_codes):
|
|
"""
|
|
This is called upon validating the order in the pos.
|
|
|
|
This will check the balance for any pre-existing coupon to make sure that the rewards are in fact all claimable.
|
|
This will also check that any set code for coupons do not exist in the database.
|
|
"""
|
|
point_changes = {int(k): v for k, v in point_changes.items()}
|
|
coupon_ids_from_pos = set(point_changes.keys())
|
|
coupons = self.env['loyalty.card'].browse(coupon_ids_from_pos).exists().filtered('program_id.active')
|
|
coupon_difference = set(coupons.ids) ^ coupon_ids_from_pos
|
|
if coupon_difference:
|
|
return {
|
|
'successful': False,
|
|
'payload': {
|
|
'message': _('Some coupons are invalid. The applied coupons have been updated. Please check the order.'),
|
|
'removed_coupons': list(coupon_difference),
|
|
}
|
|
}
|
|
for coupon in coupons:
|
|
if float_compare(coupon.points, -point_changes[coupon.id], 2) == -1:
|
|
return {
|
|
'successful': False,
|
|
'payload': {
|
|
'message': _('There are not enough points for the coupon: %s.', coupon.code),
|
|
'updated_points': {c.id: c.points for c in coupons}
|
|
}
|
|
}
|
|
# Check existing coupons
|
|
coupons = self.env['loyalty.card'].search([('code', 'in', new_codes)])
|
|
if coupons:
|
|
return {
|
|
'successful': False,
|
|
'payload': {
|
|
'message': _('The following codes already exist in the database, perhaps they were already sold?\n%s',
|
|
', '.join(coupons.mapped('code'))),
|
|
}
|
|
}
|
|
return {
|
|
'successful': True,
|
|
'payload': {},
|
|
}
|
|
|
|
def confirm_coupon_programs(self, coupon_data):
|
|
"""
|
|
This is called after the order is created.
|
|
|
|
This will create all necessary coupons and link them to their line orders etc..
|
|
|
|
It will also return the points of all concerned coupons to be updated in the cache.
|
|
"""
|
|
get_partner_id = lambda partner_id: partner_id and self.env['res.partner'].browse(partner_id).exists() and partner_id or False
|
|
# Keys are stringified when using rpc
|
|
coupon_data = {int(k): v for k, v in coupon_data.items()}
|
|
|
|
self._check_existing_loyalty_cards(coupon_data)
|
|
# Map negative id to newly created ids.
|
|
coupon_new_id_map = {k: k for k in coupon_data.keys() if k > 0}
|
|
|
|
# Create the coupons that were awarded by the order.
|
|
coupons_to_create = {k: v for k, v in coupon_data.items() if k < 0 and not v.get('giftCardId')}
|
|
coupon_create_vals = [{
|
|
'program_id': p['program_id'],
|
|
'partner_id': get_partner_id(p.get('partner_id', False)),
|
|
'code': p.get('barcode') or self.env['loyalty.card']._generate_code(),
|
|
'points': 0,
|
|
'source_pos_order_id': self.id,
|
|
} for p in coupons_to_create.values()]
|
|
|
|
# Pos users don't have the create permission
|
|
new_coupons = self.env['loyalty.card'].with_context(action_no_send_mail=True).sudo().create(coupon_create_vals)
|
|
|
|
# We update the gift card that we sold when the gift_card_settings = 'scan_use'.
|
|
gift_cards_to_update = [v for v in coupon_data.values() if v.get('giftCardId')]
|
|
updated_gift_cards = self.env['loyalty.card']
|
|
for coupon_vals in gift_cards_to_update:
|
|
gift_card = self.env['loyalty.card'].browse(coupon_vals.get('giftCardId'))
|
|
gift_card.write({
|
|
'points': coupon_vals['points'],
|
|
'source_pos_order_id': self.id,
|
|
'partner_id': get_partner_id(coupon_vals.get('partner_id', False)),
|
|
})
|
|
updated_gift_cards |= gift_card
|
|
|
|
# Map the newly created coupons
|
|
for old_id, new_id in zip(coupons_to_create.keys(), new_coupons):
|
|
coupon_new_id_map[new_id.id] = old_id
|
|
|
|
all_coupons = self.env['loyalty.card'].browse(coupon_new_id_map.keys()).exists()
|
|
lines_per_reward_code = defaultdict(lambda: self.env['pos.order.line'])
|
|
for line in self.lines:
|
|
if not line.reward_identifier_code:
|
|
continue
|
|
lines_per_reward_code[line.reward_identifier_code] |= line
|
|
for coupon in all_coupons:
|
|
if coupon.id in coupon_new_id_map:
|
|
# Coupon existed previously, update amount of points.
|
|
coupon.points += coupon_data[coupon_new_id_map[coupon.id]]['points']
|
|
for reward_code in coupon_data[coupon_new_id_map[coupon.id]].get('line_codes', []):
|
|
lines_per_reward_code[reward_code].coupon_id = coupon
|
|
# Send creation email
|
|
new_coupons.with_context(action_no_send_mail=False)._send_creation_communication()
|
|
# Reports per program
|
|
report_per_program = {}
|
|
coupon_per_report = defaultdict(list)
|
|
# Important to include the updated gift cards so that it can be printed. Check coupon_report.
|
|
for coupon in new_coupons | updated_gift_cards:
|
|
if coupon.program_id not in report_per_program:
|
|
report_per_program[coupon.program_id] = coupon.program_id.communication_plan_ids.\
|
|
filtered(lambda c: c.trigger == 'create').pos_report_print_id
|
|
for report in report_per_program[coupon.program_id]:
|
|
coupon_per_report[report.id].append(coupon.id)
|
|
return {
|
|
'coupon_updates': [{
|
|
'old_id': coupon_new_id_map[coupon.id],
|
|
'id': coupon.id,
|
|
'points': coupon.points,
|
|
'code': coupon.code,
|
|
'program_id': coupon.program_id.id,
|
|
'partner_id': coupon.partner_id.id,
|
|
} for coupon in all_coupons if coupon.program_id.is_nominative],
|
|
'program_updates': [{
|
|
'program_id': program.id,
|
|
'usages': program.total_order_count,
|
|
} for program in all_coupons.program_id],
|
|
'new_coupon_info': [{
|
|
'program_name': coupon.program_id.name,
|
|
'expiration_date': coupon.expiration_date,
|
|
'code': coupon.code,
|
|
} for coupon in new_coupons if (
|
|
coupon.program_id.applies_on == 'future'
|
|
# Don't send the coupon code for the gift card and ewallet programs.
|
|
# It should not be printed in the ticket.
|
|
and coupon.program_id.program_type not in ['gift_card', 'ewallet']
|
|
)],
|
|
'coupon_report': coupon_per_report,
|
|
}
|
|
|
|
def _check_existing_loyalty_cards(self, coupon_data):
|
|
coupon_key_to_modify = []
|
|
for coupon_id, coupon_vals in coupon_data.items():
|
|
partner_id = coupon_vals.get('partner_id', False)
|
|
if partner_id:
|
|
partner_coupons = self.env['loyalty.card'].search(
|
|
[('partner_id', '=', partner_id), ('program_type', '=', 'loyalty')])
|
|
existing_coupon_for_program = partner_coupons.filtered(lambda c: c.program_id.id == coupon_vals['program_id'])
|
|
if existing_coupon_for_program:
|
|
coupon_vals['coupon_id'] = existing_coupon_for_program[0].id
|
|
coupon_key_to_modify.append([coupon_id, existing_coupon_for_program[0].id])
|
|
for old_key, new_key in coupon_key_to_modify:
|
|
coupon_data[new_key] = coupon_data.pop(old_key)
|
|
|
|
def _get_fields_for_order_line(self):
|
|
fields = super(PosOrder, self)._get_fields_for_order_line()
|
|
fields.extend(['is_reward_line', 'reward_id', 'coupon_id', 'reward_identifier_code', 'points_cost'])
|
|
return fields
|
|
|
|
def _add_mail_attachment(self, name, ticket):
|
|
attachment = super()._add_mail_attachment(name, ticket)
|
|
gift_card_programs = self.config_id._get_program_ids().filtered(lambda p: p.program_type == 'gift_card' and
|
|
p.pos_report_print_id)
|
|
if gift_card_programs:
|
|
gift_cards = self.env['loyalty.card'].search([('source_pos_order_id', '=', self.id),
|
|
('program_id', 'in', gift_card_programs.mapped('id'))])
|
|
if gift_cards:
|
|
for program in gift_card_programs:
|
|
filtered_gift_cards = gift_cards.filtered(lambda gc: gc.program_id == program)
|
|
if filtered_gift_cards:
|
|
action_report = program.pos_report_print_id
|
|
report = action_report._render_qweb_pdf(action_report.report_name, filtered_gift_cards.mapped('id'))
|
|
filename = name + '.pdf'
|
|
gift_card_pdf = self.env['ir.attachment'].create({
|
|
'name': filename,
|
|
'type': 'binary',
|
|
'datas': base64.b64encode(report[0]),
|
|
'store_fname': filename,
|
|
'res_model': 'pos.order',
|
|
'res_id': self.ids[0],
|
|
'mimetype': 'application/x-pdf'
|
|
})
|
|
attachment += [(4, gift_card_pdf.id)]
|
|
|
|
return attachment
|