Browse Source

May 04: [ADD] Initital Commit 'advanced_loyalty_management'

pull/278/merge
RisvanaCybro 1 year ago
parent
commit
76c5001ac1
  1. 47
      advanced_loyalty_management/README.rst
  2. 22
      advanced_loyalty_management/__init__.py
  3. 68
      advanced_loyalty_management/__manifest__.py
  4. 6
      advanced_loyalty_management/doc/RELEASE_NOTES.md
  5. 27
      advanced_loyalty_management/models/__init__.py
  6. 52
      advanced_loyalty_management/models/loyalty_program.py
  7. 78
      advanced_loyalty_management/models/loyalty_reward.py
  8. 34
      advanced_loyalty_management/models/pos_order_line.py
  9. 81
      advanced_loyalty_management/models/pos_refund.py
  10. 43
      advanced_loyalty_management/models/pos_session.py
  11. 64
      advanced_loyalty_management/models/res_partner.py
  12. BIN
      advanced_loyalty_management/static/description/assets/icons/check.png
  13. BIN
      advanced_loyalty_management/static/description/assets/icons/chevron.png
  14. BIN
      advanced_loyalty_management/static/description/assets/icons/cogs.png
  15. BIN
      advanced_loyalty_management/static/description/assets/icons/consultation.png
  16. BIN
      advanced_loyalty_management/static/description/assets/icons/ecom-black.png
  17. BIN
      advanced_loyalty_management/static/description/assets/icons/education-black.png
  18. BIN
      advanced_loyalty_management/static/description/assets/icons/hotel-black.png
  19. BIN
      advanced_loyalty_management/static/description/assets/icons/license.png
  20. BIN
      advanced_loyalty_management/static/description/assets/icons/lifebuoy.png
  21. BIN
      advanced_loyalty_management/static/description/assets/icons/manufacturing-black.png
  22. BIN
      advanced_loyalty_management/static/description/assets/icons/pos-black.png
  23. BIN
      advanced_loyalty_management/static/description/assets/icons/puzzle.png
  24. BIN
      advanced_loyalty_management/static/description/assets/icons/restaurant-black.png
  25. BIN
      advanced_loyalty_management/static/description/assets/icons/service-black.png
  26. BIN
      advanced_loyalty_management/static/description/assets/icons/trading-black.png
  27. BIN
      advanced_loyalty_management/static/description/assets/icons/training.png
  28. BIN
      advanced_loyalty_management/static/description/assets/icons/update.png
  29. BIN
      advanced_loyalty_management/static/description/assets/icons/user.png
  30. BIN
      advanced_loyalty_management/static/description/assets/icons/wrench.png
  31. BIN
      advanced_loyalty_management/static/description/assets/misc/categories.png
  32. BIN
      advanced_loyalty_management/static/description/assets/misc/check-box.png
  33. BIN
      advanced_loyalty_management/static/description/assets/misc/compass.png
  34. BIN
      advanced_loyalty_management/static/description/assets/misc/corporate.png
  35. BIN
      advanced_loyalty_management/static/description/assets/misc/customer-support.png
  36. BIN
      advanced_loyalty_management/static/description/assets/misc/cybrosys-logo.png
  37. BIN
      advanced_loyalty_management/static/description/assets/misc/features.png
  38. BIN
      advanced_loyalty_management/static/description/assets/misc/logo.png
  39. BIN
      advanced_loyalty_management/static/description/assets/misc/pictures.png
  40. BIN
      advanced_loyalty_management/static/description/assets/misc/pie-chart.png
  41. BIN
      advanced_loyalty_management/static/description/assets/misc/right-arrow.png
  42. BIN
      advanced_loyalty_management/static/description/assets/misc/star.png
  43. BIN
      advanced_loyalty_management/static/description/assets/misc/support.png
  44. BIN
      advanced_loyalty_management/static/description/assets/misc/whatsapp.png
  45. BIN
      advanced_loyalty_management/static/description/assets/modules/1.png
  46. BIN
      advanced_loyalty_management/static/description/assets/modules/2.jpg
  47. BIN
      advanced_loyalty_management/static/description/assets/modules/3.png
  48. BIN
      advanced_loyalty_management/static/description/assets/modules/4.png
  49. BIN
      advanced_loyalty_management/static/description/assets/modules/5.jpg
  50. BIN
      advanced_loyalty_management/static/description/assets/modules/6.jpg
  51. BIN
      advanced_loyalty_management/static/description/assets/screenshots/1.png
  52. BIN
      advanced_loyalty_management/static/description/assets/screenshots/10.png
  53. BIN
      advanced_loyalty_management/static/description/assets/screenshots/11.png
  54. BIN
      advanced_loyalty_management/static/description/assets/screenshots/12.png
  55. BIN
      advanced_loyalty_management/static/description/assets/screenshots/13.png
  56. BIN
      advanced_loyalty_management/static/description/assets/screenshots/14.png
  57. BIN
      advanced_loyalty_management/static/description/assets/screenshots/15.png
  58. BIN
      advanced_loyalty_management/static/description/assets/screenshots/16.png
  59. BIN
      advanced_loyalty_management/static/description/assets/screenshots/17.png
  60. BIN
      advanced_loyalty_management/static/description/assets/screenshots/18.png
  61. BIN
      advanced_loyalty_management/static/description/assets/screenshots/19.png
  62. BIN
      advanced_loyalty_management/static/description/assets/screenshots/2.png
  63. BIN
      advanced_loyalty_management/static/description/assets/screenshots/20.png
  64. BIN
      advanced_loyalty_management/static/description/assets/screenshots/21.png
  65. BIN
      advanced_loyalty_management/static/description/assets/screenshots/22.png
  66. BIN
      advanced_loyalty_management/static/description/assets/screenshots/23.png
  67. BIN
      advanced_loyalty_management/static/description/assets/screenshots/24.png
  68. BIN
      advanced_loyalty_management/static/description/assets/screenshots/25.png
  69. BIN
      advanced_loyalty_management/static/description/assets/screenshots/26.png
  70. BIN
      advanced_loyalty_management/static/description/assets/screenshots/27.png
  71. BIN
      advanced_loyalty_management/static/description/assets/screenshots/28.png
  72. BIN
      advanced_loyalty_management/static/description/assets/screenshots/29.png
  73. BIN
      advanced_loyalty_management/static/description/assets/screenshots/3.png
  74. BIN
      advanced_loyalty_management/static/description/assets/screenshots/30.png
  75. BIN
      advanced_loyalty_management/static/description/assets/screenshots/31.png
  76. BIN
      advanced_loyalty_management/static/description/assets/screenshots/32.png
  77. BIN
      advanced_loyalty_management/static/description/assets/screenshots/33.png
  78. BIN
      advanced_loyalty_management/static/description/assets/screenshots/34.png
  79. BIN
      advanced_loyalty_management/static/description/assets/screenshots/35.png
  80. BIN
      advanced_loyalty_management/static/description/assets/screenshots/36.png
  81. BIN
      advanced_loyalty_management/static/description/assets/screenshots/37.png
  82. BIN
      advanced_loyalty_management/static/description/assets/screenshots/38.png
  83. BIN
      advanced_loyalty_management/static/description/assets/screenshots/4.png
  84. BIN
      advanced_loyalty_management/static/description/assets/screenshots/5.png
  85. BIN
      advanced_loyalty_management/static/description/assets/screenshots/6.png
  86. BIN
      advanced_loyalty_management/static/description/assets/screenshots/7.png
  87. BIN
      advanced_loyalty_management/static/description/assets/screenshots/8.png
  88. BIN
      advanced_loyalty_management/static/description/assets/screenshots/9.png
  89. BIN
      advanced_loyalty_management/static/description/assets/screenshots/v16-hero.gif
  90. BIN
      advanced_loyalty_management/static/description/banner.png
  91. BIN
      advanced_loyalty_management/static/description/icon.png
  92. 784
      advanced_loyalty_management/static/description/index.html
  93. 36
      advanced_loyalty_management/static/src/js/pos_change_popup.js
  94. 64
      advanced_loyalty_management/static/src/js/pos_loyalty_deduction.js
  95. 16
      advanced_loyalty_management/static/src/js/pos_loyalty_deduction_receipt.js
  96. 168
      advanced_loyalty_management/static/src/js/pos_order.js
  97. 25
      advanced_loyalty_management/static/src/js/pos_payment_screen.js
  98. 83
      advanced_loyalty_management/static/src/js/pos_ticketscreen.js
  99. 59
      advanced_loyalty_management/static/src/js/reward_popup.js
  100. 171
      advanced_loyalty_management/static/src/js/rewardbutton.js

47
advanced_loyalty_management/README.rst

@ -0,0 +1,47 @@
.. image:: https://img.shields.io/badge/license-LGPL--3-green.svg
:target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
Advanced Loyalty Management
===========================
* In this module we can deduct the loyalty points when order is refunded, we can convert the change into loyalty points, History of claimed rewards can be seen in customer's page.And introduced new reward type , in which we can redeem our points.
Configuration
============
- www.odoo.com/documentation/16.0/setup/install.html
- Install our custom addon
Company
-------
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__
License
-------
General Public License, Version 3 (LGPL v3).
(https://www.gnu.org/licenses/lgpl-3.0-standalone.html)
Credits
-------
* Developer: (V16) NIHALA KP, Contact: odoo@cybrosys.com
Contacts
--------
* Mail Contact : odoo@cybrosys.com
* Website : https://cybrosys.com
Bug Tracker
-----------
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
Maintainer
--------
This module is maintained by Cybrosys Technologies.
For support and more information, please visit https://www.cybrosys.com
.. image:: https://cybrosys.com/images/logo.png
:target: https://cybrosys.com"
Further Information
-----------
HTML Description: `<static/description/index.html>`__

22
advanced_loyalty_management/__init__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import models

68
advanced_loyalty_management/__manifest__.py

@ -0,0 +1,68 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
{
'name': 'Advanced Loyalty Management',
'version': '16.0.1.0.0',
'category': 'Point of Sale',
'summary': 'Loyalty deduction on order refund',
'description': """When an order is refunded, any loyalty points gained from
that purchase are also revoked. This means that the points earned through
the refunded transaction will be deducted from the customer's loyalty points
balance.""",
'author': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': 'https://www.cybrosys.com',
'images': [
'static/description/banner.png',
],
'depends': ['point_of_sale','pos_loyalty','base','sale_management'],
'data': [
'views/res_partner_views.xml',
'views/loyalty_rewards_views.xml',
'views/loyalty_program_views.xml',
'views/loyalty_kanban_view.xml',
'views/pos_order_line_views.xml',
],
"assets":
{"point_of_sale.assets":
[
'advanced_loyalty_management/static/src/xml/pos_loyalty_deduction.xml',
'advanced_loyalty_management/static/src/js/pos_loyalty_deduction.js',
'advanced_loyalty_management/static/src/xml/pos_loyalty_receipt.xml',
'advanced_loyalty_management/static/src/js/pos_loyalty_deduction_receipt.js',
'advanced_loyalty_management/static/src/xml/pos_loyalty_change.xml',
'advanced_loyalty_management/static/src/js/pos_ticketscreen.js',
'advanced_loyalty_management/static/src/js/pos_payment_screen.js',
'advanced_loyalty_management/static/src/xml/pos_change_popup.xml',
'advanced_loyalty_management/static/src/js/pos_change_popup.js',
'advanced_loyalty_management/static/src/js/pos_order.js',
'advanced_loyalty_management/static/src/js/rewardbutton.js',
'advanced_loyalty_management/static/src/xml/reward_popup.xml',
'advanced_loyalty_management/static/src/js/reward_popup.js',
]
},
'license': 'LGPL-3',
'installable': True,
'auto_install': False,
'application': False,
}

6
advanced_loyalty_management/doc/RELEASE_NOTES.md

@ -0,0 +1,6 @@
## Module <advanced_loyalty_management>
#### 06.04.2024
#### Version 16.0.1.0.0
#### ADD
- Initial Commit Advanced Loyalty Management

27
advanced_loyalty_management/models/__init__.py

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import loyalty_program
from . import loyalty_reward
from . import res_partner
from . import pos_order_line
from . import pos_refund
from . import pos_session

52
advanced_loyalty_management/models/loyalty_program.py

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import api, models, fields
class LoyaltyProgram(models.Model):
"""to load more fields in loyalty program and loyalty model"""
_inherit = 'loyalty.program'
point_rate = fields.Integer(string='Point Rate',
help="Points corresponding to each unit",
default=1, required=True)
change_rate = fields.Monetary(string='Change Rate', default=1,
readonly=True,
help="Unit of money per points cost")
currency_id = fields.Many2one('res.currency', string='Currency',
default=lambda
self: self.env.user.company_id.currency_id,
help="Symbol of Currency")
@api.model
def convert_loyalty(self, program_id, coupon_id, added_loyalty, partner_id):
"""Change is converted to loyalty"""
if int(coupon_id) < 0:
self.env['loyalty.card'].create({
'program_id': program_id,
'partner_id': partner_id,
'points': added_loyalty
})
else:
loyalty_card = self.env['loyalty.card'].search(
[('id', '=', int(coupon_id))])
loyalty_card.points += added_loyalty

78
advanced_loyalty_management/models/loyalty_reward.py

@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import api, models, fields
class LoyaltyReward(models.Model):
"""To add a new reward type in loyalty reward"""
_inherit = 'loyalty.reward'
reward_type = fields.Selection(selection_add=[
('redemption', 'Redemption')
], ondelete={'redemption': 'set default'},
help="A new reward type is added")
redemption_point = fields.Integer(string='Redemption Point', default=1.0,
readonly=True,
help="No of points redeemed according "
"to the redemption amount")
redemption_amount = fields.Float(string='Maximum Redemption per Point',
default=1.00, required=True,
help="Maximum Redemption per redemption "
"point")
max_redemption_type = fields.Selection(
[('amount', 'Amount'), ('percent', 'Percentage'), ('points', 'Points')],
default="amount",
required=True,
help="Redemption type based on Fixed Amount,percentage or Point wise")
max_redemption_amount = fields.Float(string='Max Redemption Amount',
default=10, required=True,
help="Maximum redemption amount "
"given to an order")
redemption_frequency = fields.Integer(string='Redemption Frequency',
default=1, required=True,
help="Number of times this reward "
"can be claimed")
redemption_frequency_unit = fields.Selection([('day', 'Daily'),
('week', 'Weekly'),
('month', 'Monthly'),
('year', 'Yearly')],
default='day', required=True,
string='Redemption Frequency'
'Unit',
help="Choose the frequency "
"for claiming the reward")
redemption_eligibility = fields.Float(string="Redemption Eligibility",
default=200,
help="points required for claiming "
"the reward")
@api.depends('reward_type', 'reward_product_id', 'discount_mode',
'discount', 'currency_id', 'discount_applicability',
'all_discount_product_ids')
def _compute_description(self):
"""compute description when the reward type is redemption"""
for reward in self:
if reward.reward_type == 'redemption':
reward.description = 'Redemption'
else:
res = super(LoyaltyReward, self)._compute_description()
return res

34
advanced_loyalty_management/models/pos_order_line.py

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import models
class PosOrderLine(models.Model):
"""information about points cost is updated to the front end"""
_inherit = 'pos.order.line'
def _export_for_ui(self, orderline):
"""information about points cost is updated to the front end"""
result = super()._export_for_ui(orderline)
result['points_cost'] = orderline.points_cost
result['coupon_id'] = orderline.coupon_id.id
return result

81
advanced_loyalty_management/models/pos_refund.py

@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import models, fields
class PosOrder(models.Model):
"""To update the loyalty points when order is refunded"""
_inherit = 'pos.order'
check = fields.Boolean(string="check",
help="to check whether any quantity is refunded")
def _compute_order_name(self):
"""Compute the loyalty points when order is refunded"""
res = super()._compute_order_name()
partner_id = self.partner_id
li = [line.mapped('price_subtotal_incl') for line
in self.lines.filtered(lambda x: not x.is_reward_line)]
reward_line = self.refunded_order_ids.lines.filtered(
lambda x: x.is_reward_line)
points_cost = []
for line in reward_line:
dict = {}
dict.update({
line.coupon_id.id: line.points_cost
})
points_cost.append(dict)
if self.refunded_order_ids:
cards = self.env['loyalty.card'].search(
[('partner_id', '=', partner_id.id)])
for program in cards:
if not self.refunded_order_ids.check:
for point in points_cost:
for key, values in point.items():
if program.id == key:
program.points += point[key]
self.refunded_order_ids.check = True
for rule in program.program_id.rule_ids:
if rule.reward_point_mode == 'money':
points_granted = rule.reward_point_amount
reward_points = [sum(sublist) * points_granted for
sublist in li]
program.points += reward_points[0]
elif rule.reward_point_mode == 'order':
reward_points = rule.reward_point_amount
reward_line_ids = len(reward_line)
ordered_qty = sum(self.refunded_order_ids.lines.mapped(
'qty')) - reward_line_ids
refunded_qty = sum(
self.refunded_order_ids.lines.filtered(
lambda x: not x.is_reward_line).mapped(
'refunded_qty'))
if ordered_qty == refunded_qty:
program.points -= reward_points
elif rule.reward_point_mode == 'unit':
points_granted = rule.reward_point_amount
qty = sum(
self.lines.filtered(
lambda x: not x.is_reward_line).mapped('qty'))
reward_points = qty * points_granted
program.points += reward_points
return res

43
advanced_loyalty_management/models/pos_session.py

@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import models
class PosSession(models.Model):
"""to load more fields in loyalty program and loyalty model"""
_inherit = 'pos.session'
def _loader_params_loyalty_program(self):
"""To load more fields in the model loyalty.program"""
result = super()._loader_params_loyalty_program()
result['search_params']['fields'].extend(['point_rate'])
return result
def _loader_params_loyalty_reward(self):
"""to load more fields in the model loyalty.reward"""
result = super()._loader_params_loyalty_reward()
result['search_params']['fields'].extend(
['redemption_point', 'redemption_amount', 'max_redemption_amount',
'redemption_frequency',
'redemption_frequency_unit', 'redemption_eligibility',
'max_redemption_type'])
return result

64
advanced_loyalty_management/models/res_partner.py

@ -0,0 +1,64 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import api, models
class ResPartner(models.Model):
"""Add loyalty card in res.partner form"""
_inherit = 'res.partner'
def action_view_loyalty(self):
"""customers can view their own loyalty points"""
action = self.env['ir.actions.act_window']._for_xml_id(
'loyalty.loyalty_card_action')
all_child = self.with_context(active_test=False).search(
[('id', 'child_of', self.ids)])
action['domain'] = [('partner_id', 'in', all_child.ids)]
action['context'] = {'search_default_active': True}
return action
def view_claimed_rewards(self):
"""a smart button is created to view the claimed the rewards"""
order_id = self.env['pos.order'].search(
[('partner_id', '=', self.id)]).ids
return {
'type': 'ir.actions.act_window',
'name': 'Claimed Rewards',
'view_mode': 'tree,form',
'res_model': 'pos.order.line',
'domain': [('is_reward_line', '=', 'true'),
('order_id', 'in', order_id)],
'context': "{'create': False}"
}
@api.model
def check_redemption(self, pid):
"""to check number of times the reward is claimed"""
order = self.env['pos.order'].search([('partner_id', '=', pid)])
data = []
date = []
order_line = self.env['pos.order.line'].search(
[('is_reward_line', '=', 'true'), ('order_id', 'in', order.ids)])
for line in order_line:
data.append(line.order_id.id)
date.append(line.create_date.date())
return data, date

BIN
advanced_loyalty_management/static/description/assets/icons/check.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
advanced_loyalty_management/static/description/assets/icons/chevron.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

BIN
advanced_loyalty_management/static/description/assets/icons/cogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
advanced_loyalty_management/static/description/assets/icons/consultation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
advanced_loyalty_management/static/description/assets/icons/ecom-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

BIN
advanced_loyalty_management/static/description/assets/icons/education-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

BIN
advanced_loyalty_management/static/description/assets/icons/hotel-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

BIN
advanced_loyalty_management/static/description/assets/icons/license.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
advanced_loyalty_management/static/description/assets/icons/lifebuoy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
advanced_loyalty_management/static/description/assets/icons/manufacturing-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
advanced_loyalty_management/static/description/assets/icons/pos-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

BIN
advanced_loyalty_management/static/description/assets/icons/puzzle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

BIN
advanced_loyalty_management/static/description/assets/icons/restaurant-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

BIN
advanced_loyalty_management/static/description/assets/icons/service-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
advanced_loyalty_management/static/description/assets/icons/trading-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

BIN
advanced_loyalty_management/static/description/assets/icons/training.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

BIN
advanced_loyalty_management/static/description/assets/icons/update.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
advanced_loyalty_management/static/description/assets/icons/user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
advanced_loyalty_management/static/description/assets/icons/wrench.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
advanced_loyalty_management/static/description/assets/misc/categories.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
advanced_loyalty_management/static/description/assets/misc/check-box.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
advanced_loyalty_management/static/description/assets/misc/compass.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
advanced_loyalty_management/static/description/assets/misc/corporate.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
advanced_loyalty_management/static/description/assets/misc/customer-support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
advanced_loyalty_management/static/description/assets/misc/cybrosys-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
advanced_loyalty_management/static/description/assets/misc/features.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

BIN
advanced_loyalty_management/static/description/assets/misc/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
advanced_loyalty_management/static/description/assets/misc/pictures.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
advanced_loyalty_management/static/description/assets/misc/pie-chart.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
advanced_loyalty_management/static/description/assets/misc/right-arrow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

BIN
advanced_loyalty_management/static/description/assets/misc/star.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
advanced_loyalty_management/static/description/assets/misc/support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
advanced_loyalty_management/static/description/assets/misc/whatsapp.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
advanced_loyalty_management/static/description/assets/modules/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
advanced_loyalty_management/static/description/assets/modules/2.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
advanced_loyalty_management/static/description/assets/modules/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
advanced_loyalty_management/static/description/assets/modules/4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
advanced_loyalty_management/static/description/assets/modules/5.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
advanced_loyalty_management/static/description/assets/modules/6.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/10.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/11.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/12.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/14.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/15.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/17.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/18.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/19.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/20.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/21.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/22.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/23.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/24.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/25.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/26.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/27.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/28.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/29.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/30.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/31.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/32.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/33.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/34.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/35.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/36.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/37.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/38.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/7.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/8.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/9.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
advanced_loyalty_management/static/description/assets/screenshots/v16-hero.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

BIN
advanced_loyalty_management/static/description/banner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
advanced_loyalty_management/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

784
advanced_loyalty_management/static/description/index.html

@ -0,0 +1,784 @@
<div style="background-color: #714B67; height: 810px; width: 100%; padding: 15px; position: relative;">
<!-- TITLE BAR -->
<div class="d-flex align-items-center justify-content-between"
style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;">
<img src="assets/misc/cybrosys-logo.png" width="42" height="42"
style="width: 42px; height: 42px;"/>
<div>
<div
style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Community
</div>
<div
style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
<div
style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Odoo.sh
</div>
</div>
</div>
<!-- END OF TITLE BAR -->
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<!-- APP HERO -->
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;">
Advanced Loyalty Management</h1>
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;">
In this module, we have incorporated new features such as
deducting loyalty points upon refund, converting change into
loyalty points, displaying claimed rewards history, and
introducing a new type of reward
<img src="assets/screenshots/v16-hero.gif"
class="img-responsive"
style="width: 100%; margin-left: auto; margin-right: auto;"/>
</div>
</div>
</div>
</div>
<!-- NAVIGATION SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/compass.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Explore This
Module</h2>
</div>
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;">
<div class="col-sm-12 col-md-6 my-3">
<a href="#overview">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn
more about this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#features">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
features of this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#screenshots">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
screenshots for this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
</div>
<!-- END OF NAVIGATION SECTION -->
<!-- OVERVIEW SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="overview">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pie-chart.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Overview
</h2>
</div>
<div class="row"
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 py-4">
In this module, we have implemented the functionality to deduct loyalty
points when an order is refunded. Additionally, we offer the capability
to convert change into loyalty points. Customers can conveniently view
their claimed rewards history on their respective pages. Furthermore,
we've introduced a new reward type, allowing users to redeem their
accumulated points.
</div>
</div>
<!-- END OF OVERVIEW SECTION -->
<!-- FEATURES SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="features">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/features.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Features
</h2>
</div>
<div class="row"
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">We can deduct the Loyalty Points of the customer if the order is refunded.</span>
</div>
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">We can convert the change into Loyalty Points.</span>
</div>
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">History of claimed Rewards can be seen in the customer's page</span>
</div>
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">A new loyalty reward type is introduced, where we can redeem the points</span>
</div>
</div>
</div>
<!-- END OF FEATURES SECTION -->
<!-- SCREENSHOTS SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"
id="screenshots">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pictures.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Screenshots
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
We have the capability to create three distinct loyalty
programs, each with its own set of conditions.
</h3>
<img src="assets/screenshots/1.png" class="img-thumbnail">
<img src="assets/screenshots/2.png" class="img-thumbnail">
<img src="assets/screenshots/3.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Let's explore how it operates on the point of sale (POS) screen
and Receipt
</h3>
<img src="assets/screenshots/4.png" class="img-thumbnail">
<br/>
<img src="assets/screenshots/5.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Now lets check on the customer's page and see its updated on the
customer's loyalty cards
</h3>
<img src="assets/screenshots/7.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Now Lets see How it deducts on refund, We can see the point is
deducted from loyalty 1 and loyalty 3 programs ,
The point is not deducted from the loyalty program (loyalty 2),
Because the condition is based on per order, the points from
that point will be deducted only when the whole order is
refunded
</h3>
<img src="assets/screenshots/8.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Now lets check on the receipt and customer's page and see how it
is updated.
</h3>
<img src="assets/screenshots/9.png" class="img-thumbnail">
<img src="assets/screenshots/10.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Now lets refund the whole order and check how the loyalty points
are deducted.
</h3>
<img src="assets/screenshots/11.png" class="img-thumbnail">
<img src="assets/screenshots/12.png" class="img-thumbnail">
<img src="assets/screenshots/13.png" class="img-thumbnail">
<img src="assets/screenshots/14.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Now lets claim a reward and check How the points are effected.
</h3>
<img src="assets/screenshots/15.png" class="img-thumbnail">
<img src="assets/screenshots/16.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Now lets refund the order and check How the points are effected.
Here we given a warning to prevent the refund of reward line,to
avoid the conflict in calculations of loyalty points.
</h3>
<img src="assets/screenshots/17.png" class="img-thumbnail">
<img src="assets/screenshots/18.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
We can refund the whole quantity and check the how the points
reduced
</h3>
<img src="assets/screenshots/19.png" class="img-thumbnail">
<img src="assets/screenshots/20.png" class="img-thumbnail">
<img src="assets/screenshots/21.png" class="img-thumbnail">
<img src="assets/screenshots/22.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
We can check the next case, that is converting the change to
loyalty points
</h3>
<img src="assets/screenshots/21.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Given a button under the change to show the list of loyalty
programs to which converted loyalty points should added
</h3>
<img src="assets/screenshots/22.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
When the popup is clicked, users can select the loyalty program
to which they wish to allocate their converted points. Upon
selection, the change amount resets to zero.
</h3>
<img src="assets/screenshots/23.png" class="img-thumbnail">
<img src="assets/screenshots/24.png" class="img-thumbnail">
<img src="assets/screenshots/25.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Now let's check new reward type and how its works
</h3>
<img src="assets/screenshots/26.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
In this reward type , the customer can only claim the reward if
the customer is doing the purchase for the second time </h3>
<img src="assets/screenshots/27.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
If the same customer do the purchase for the second time, they are eligible for claiming the reward </h3>
<img src="assets/screenshots/28.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Upon selecting the reward a popup showing how many points we can redeem </h3>
<img src="assets/screenshots/29.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Then we can see that it is applied to reward line </h3>
<img src="assets/screenshots/30.png" class="img-thumbnail">
<img src="assets/screenshots/31.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
If the same customer come again he cannot claim it again, While configuring the rewards , we give the condition Daily 1</h3>
<img src="assets/screenshots/26.png" class="img-thumbnail">
<img src="assets/screenshots/32.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
If maximum redemption amount type is given in percentage, We can redeem the 10% of the order's subtotal</h3>
<img src="assets/screenshots/33.png" class="img-thumbnail">
<img src="assets/screenshots/34.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
If maximum redemption amount type is given in Points, We can redeem that much points as maximum redemption points</h3>
<img src="assets/screenshots/36.png" class="img-thumbnail">
<img src="assets/screenshots/35.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">I
Next we can see the history of claimed rewards in the customer's page.</h3>
<img src="assets/screenshots/37.png" class="img-thumbnail">
<img src="assets/screenshots/38.png" class="img-thumbnail">
</div>
</div>
</div>
<!-- END OF SCREENSHOTS SECTION -->
<!-- RELATED PRODUCTS -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/categories.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Related
Products
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner" style="padding: 30px;">
<div class="carousel-item" style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/advanced_chatter_view/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/1.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/hide_chatter/#"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/2.jpg">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/mail_push_notification/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/3.png">
</div>
</a>
</div>
</div>
<div class="carousel-item active"
style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/activity_reminder/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/4.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/camera_in_discuss/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/5.jpg">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/autosuggestion_in_discuss/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/6.jpg">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev"
style="width:35px; color:#000"> <span
class="carousel-control-prev-icon"><i
class="fa fa-chevron-left"
style="font-size:24px"></i></span>
</a> <a class="carousel-control-next" href="#demo1"
data-slide="next" style="width:35px; color:#000">
<span class="carousel-control-next-icon"><i
class="fa fa-chevron-right"
style="font-size:24px"></i></span>
</a>
</div>
</div>
</div>
<!-- END OF RELATED PRODUCTS -->
<!-- OUR SERVICES -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/star.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Our Services
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/cogs.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Customization</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/wrench.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/lifebuoy.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Support</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/user.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Hire
Odoo
Developer</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/puzzle.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Integration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/update.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Migration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/consultation.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Consultancy</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/training.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/license.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Licensing Consultancy</h6>
</div>
</div>
</div>
<!-- END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/corporate.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Our
Industries
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/trading-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Trading
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easily procure
and
sell your products</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/pos-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
POS
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easy
configuration
and convivial experience</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/education-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Education
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
A platform for
educational management</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/manufacturing-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Manufacturing
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Plan, track and
schedule your operations</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/ecom-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
E-commerce &amp; Website
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Mobile
friendly,
awe-inspiring product pages</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/service-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Service Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Keep track of
services and invoice</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/restaurant-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Restaurant
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Run your bar or
restaurant methodically</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/hotel-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Hotel Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
An
all-inclusive
hotel management application</p>
</div>
</div>
</div>
</div>
<!-- END OF OUR INDUSTRIES -->
<!-- SUPPORT -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/customer-support.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Support
</h2>
</div>
<div class="container mt-5">
<div class="row">
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/support.png" height="48" width="48"
style="width: 42px; height: 42px;"/>
</div>
<div>
<h4>Need Help?</h4>
<p style="line-height: 100%;">Got questions or need help?
Get in touch.</p>
<a href="mailto:odoo@cybrosys.com">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
odoo@cybrosys.com</p>
</a>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/whatsapp.png" height="52" width="52"
style="width: 52px; height: 52px;"/>
</div>
<div>
<h4>WhatsApp</h4>
<p style="line-height: 100%;">Say hi to us on WhatsApp!</p>
<a href="https://api.whatsapp.com/send?phone=918606827707">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
+91 86068
27707</p>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 my-5 d-flex justify-content-center align-items-center">
<img src="assets/misc/logo.png" width="144" height="31"
style="width:144px; height: 31px; margin-top: 40px;"/>
</div>
</div>
</div>
<!-- END OF SUPPORT -->

36
advanced_loyalty_management/static/src/js/pos_change_popup.js

@ -0,0 +1,36 @@
/** @odoo-module **/
import AbstractAwaitablePopup from 'point_of_sale.AbstractAwaitablePopup';
import Registries from 'point_of_sale.Registries';
import { useService } from "@web/core/utils/hooks";
var rpc = require('web.rpc');
class LoyaltyPrograms extends AbstractAwaitablePopup {
convertToLoyalty(props, programId,ev){
//-----Change is converted to loyalty----
var change = props.change
const loyalty = props.Loyalty.filter(point => point.program.id ==programId)[0]
var addedLoyalty = change * loyalty.program.point_rate
props.Order.programToAdd = programId
props.Order.convertToLoyalty = addedLoyalty
props.Order.changeConverted = true
const partner_id = props.Order.partner.id
props.Order.getLoyaltyPoints()
var convertLoyalty = rpc.query({
model:'loyalty.program',
method:'convert_loyalty',
args:[programId,loyalty.couponId,addedLoyalty,partner_id]
})
ev.confirm()
}
}
LoyaltyPrograms.template = 'LoyaltyPrograms';
LoyaltyPrograms.defaultProps = {
confirmText: 'Confirm',
cancelText: 'Cancel',
title: 'Loyalty Programs',
body: '',
};
Registries.Component.add(LoyaltyPrograms);
return LoyaltyPrograms;

64
advanced_loyalty_management/static/src/js/pos_loyalty_deduction.js

@ -0,0 +1,64 @@
/** @odoo-module **/
import OrderSummary from 'point_of_sale.OrderSummary';
import Registries from 'point_of_sale.Registries';
import { round_decimals,round_precision } from 'web.utils';
export const PosLoyaltyDeduction = (OrderSummary) =>
class PosLoyaltyDeduction extends OrderSummary {
deductLoyaltyPoints() {
//----to deduct the loyalty points when the order is refunded---
const order = this.env.pos.get_order();
let refundedLines = order.orderlines.filter((line) => line.refunded_orderline_id != undefined);
let pointsReduced = [];
let newBalance = [];
let programName= [];
let valsList = [];
if(order.couponPointChanges != undefined){
let rewardPoints = JSON.parse(localStorage.getItem('pointsCost'))
for (const pointChange of Object.values(order.getLoyaltyPoints())) {
const { couponId,bal, points, program } = pointChange;
if(couponId > 0){
let loyaltyCard = this.env.pos.couponCache[couponId]
let programs = this.env.pos.program_by_id[loyaltyCard.program_id];
programName.push(programs.name)
let balance = loyaltyCard.balance
let res = 0;
let ruleId = [];
programs.rules.forEach(rule => {
ruleId.push(rule.id)
let totalQuantity = 0;
for (let line of refundedLines) {
const refundedQty = line.pos.toRefundLines[line.refunded_orderline_id]?.orderline?.refundedQty - line.get_quantity()
switch (rule.reward_point_mode) {
case 'money':
res -= round_precision(rule.reward_point_amount * line.get_price_with_tax(), 0.01);
break;
case 'unit':
res -= rule.reward_point_amount * line.get_quantity();
break;
default:
totalQuantity += line.pos.toRefundLines[line.refunded_orderline_id]?.orderline?.qty || 0;
res += totalQuantity === refundedQty ? rule.reward_point_amount : 0;
}
}
})
for(var line of refundedLines){
if(line.pos.toRefundLines[line.refunded_orderline_id]?.orderline?.refundedQty === 0 && rewardPoints.length != 0){
for(var pointscost of rewardPoints){
if (pointscost[couponId]){
res -= pointscost[couponId]
}
}
}
}
let currentBalance = balance - res;
valsList.push({lostPoint: res, newPoint: currentBalance.toFixed(2), programName : programs.name, ruleId:ruleId });
}
}
}
this.env.pos.lostPoints = valsList;
return valsList;
}
}
Registries.Component.extend(OrderSummary, PosLoyaltyDeduction)

16
advanced_loyalty_management/static/src/js/pos_loyalty_deduction_receipt.js

@ -0,0 +1,16 @@
odoo.define('advanced_loyalty_management.pos_loyalty_deduction_receipt', function (require) {
"use strict";
var { Order } = require('point_of_sale.models');
const Registries = require('point_of_sale.Registries');
const DeductedLoyalty = (Order) => class DeductedLoyalty extends Order {
export_for_printing() {
//----to show the deducted points in receipt
var line = super.export_for_printing(...arguments);
var points = this.pos.lostPoints
line.lostPoints = points
return line;
}
}
Registries.Model.extend(Order, DeductedLoyalty);
})

168
advanced_loyalty_management/static/src/js/pos_order.js

@ -0,0 +1,168 @@
/** @odoo-module **/
import { Order, Orderline, PosGlobalState} from 'point_of_sale.models';
import Registries from 'point_of_sale.Registries';
var utils = require('web.utils');
var round_pr = utils.round_precision;
function _newRandomRewardCode() {
return (Math.random() + 1).toString(36).substring(3);
}
const PosLoyaltyOrder = (Order) => class PosLoyaltyOrder extends Order {
getLoyaltyPoints() {
//------change is added to loyalty points---
// map: couponId -> LoyaltyPoints
const loyaltyPoints = {};
for (const pointChange of Object.values(this.couponPointChanges)) {
const { coupon_id, points, program_id } = pointChange;
const program = this.pos.program_by_id[program_id];
if (program.program_type !== "loyalty") {
continue;
}
const loyaltyCard = this.pos.couponCache[coupon_id] || /* or new card */ {
id: coupon_id,
balance: 0,
};
let [won, spent, total] = [0, 0, 0];
var balance = loyaltyCard.balance;
if(this.pos.get_order().convertToLoyalty == undefined){
won += points - this._getPointsCorrection(program);
}
else{
won += points - this._getPointsCorrection(program);
if(program_id === this.pos.get_order().programToAdd){
won += this.pos.get_order().convertToLoyalty
}
}
if (coupon_id !== 0) {
for (const line of this._get_reward_lines()) {
if (line.coupon_id === coupon_id) {
spent += line.points_cost;
}
}
}
total = balance + won - spent;
const name = program.portal_visible ? program.portal_point_name : _t("Points");
loyaltyPoints[coupon_id] = {
won: parseFloat(won.toFixed(2)),
spent: parseFloat(spent.toFixed(2)),
total: parseFloat(total.toFixed(2)),
balance: parseFloat(balance.toFixed(2)),
name,
program,
};
}
return Object.entries(loyaltyPoints).map(([couponId, points]) => ({
couponId,
points,
program: points.program,
}));
}
_getRewardLineValues(args) {
//----a new reward type is added
const reward = args['reward'];
if (reward.reward_type === 'discount') {
return this._getRewardLineValuesDiscount(args);
} else if (reward.reward_type === 'product') {
return this._getRewardLineValuesProduct(args);
}
else if (reward.reward_type === 'redemption'){
return this._getRewardLineValuesRedemption(args)
}
return [];
}
_getRewardLineValuesRedemption(args){
//---configured new reward product
const reward = args["reward"];
const coupon_id = args["coupon_id"];
const rewardAppliesTo = reward.discount_applicability;
let getDiscountable;
getDiscountable = this._getDiscountableOnOrder.bind(this);
let { discountable, discountablePerTax } = getDiscountable(reward);
discountable = Math.min(this.get_total_with_tax(), discountable);
const discount = reward.pointsToRedeem * reward.redemption_amount
const discountProduct = reward.discount_line_product_id;
const rewardCode = _newRandomRewardCode();
const points = this._getRealCouponPoints(args["coupon_id"])
const cost = reward.clear_wallet ? points :reward.pointsToRedeem
return[
{
product: discountProduct,
price: -Math.min(discount),
quantity: 1,
reward_id: reward.id,
is_reward_line: true,
coupon_id: coupon_id,
points_cost: cost,
reward_identifier_code: rewardCode,
merge: false,
tax_ids: [],
},
]
}
get_change(paymentline) {
//----change is converted to loyalty points
if (!paymentline) {
if(this.changeConverted == undefined){
var change =
this.get_total_paid() - this.get_total_with_tax() - this.get_rounding_applied();
}
else{
var change = 0
}
} else {
var change = -this.get_total_with_tax();
var lines = this.paymentlines;
for (var i = 0; i < lines.length; i++) {
change += lines[i].get_amount();
if (lines[i] === paymentline) {
break;
}
}
}
return round_pr(Math.max(0,change), this.pos.currency.rounding);
}
export_as_JSON() {
//---amount returned is changed
var orderLines, paymentLines;
orderLines = [];
this.orderlines.forEach(item => {
return orderLines.push([0, 0, item.export_as_JSON()]);
});
paymentLines = [];
this.paymentlines.forEach(_.bind( function(item) {
return paymentLines.push([0, 0, item.export_as_JSON()]);
}, this));
var json = {
name: this.get_name(),
amount_paid: this.get_total_paid() - this.get_change(),
amount_total: this.get_total_with_tax(),
amount_tax: this.get_total_tax(),
amount_return: this.get_total_paid() - this.get_total_with_tax() - this.get_rounding_applied(),
lines: orderLines,
statement_ids: paymentLines,
pos_session_id: this.pos_session_id,
pricelist_id: this.pricelist ? this.pricelist.id : false,
partner_id: this.get_partner() ? this.get_partner().id : false,
user_id: this.pos.user.id,
uid: this.uid,
sequence_number: this.sequence_number,
creation_date: this.validation_date || this.creation_date, // todo: rename creation_date in master
fiscal_position_id: this.fiscal_position ? this.fiscal_position.id : false,
server_id: this.server_id ? this.server_id : false,
to_invoice: this.to_invoice ? this.to_invoice : false,
to_ship: this.to_ship ? this.to_ship : false,
is_tipped: this.is_tipped || false,
tip_amount: this.tip_amount || 0,
access_token: this.access_token || '',
};
if (!this.is_paid && this.user_id) {
json.user_id = this.user_id;
}
return json;
}
}
Registries.Model.extend(Order, PosLoyaltyOrder);

25
advanced_loyalty_management/static/src/js/pos_payment_screen.js

@ -0,0 +1,25 @@
/** @odoo-module **/
import PaymentScreenStatus from 'point_of_sale.PaymentScreenStatus';
import Registries from 'point_of_sale.Registries' ;
const { Gui } = require('point_of_sale.Gui');
const ChangeLoyalty = (PaymentScreenStatus) =>
class extends PaymentScreenStatus {
convertLoyalty(){
//----A pop is added to choose to which loyalty card the program is added
var order = this.env.pos.get_order()
var loyaltyPoints = order.getLoyaltyPoints()
var change = order.get_change()
if(loyaltyPoints.length != 0){
Gui.showPopup("LoyaltyPrograms", {
title: this.env._t('Convert Change'),
cancelText: this.env._t("Cancel"),
confirmText:this.env._t("Confirm"),
Order:order,
change:change,
Loyalty :loyaltyPoints,
});
}
}
}
Registries.Component.extend(PaymentScreenStatus, ChangeLoyalty)

83
advanced_loyalty_management/static/src/js/pos_ticketscreen.js

@ -0,0 +1,83 @@
odoo.define('advanced_loyalty_management.TicketScreen', function (require) {
'use strict';
const TicketScreen = require('point_of_sale.TicketScreen');
const Registries = require('point_of_sale.Registries');
const { parse } = require('web.field_utils');
const {_t} = require('web.core');
const NumberBuffer = require('point_of_sale.NumberBuffer');
const LoyaltyRefundTicketScreen = (TicketScreen) =>
class extends TicketScreen {
async _onDoRefund() {
//----points cost is stored to local storage when the parent order has reward lines
var res = super._onDoRefund()
let pointsCost = []
var refundOrder = this._state.syncedOrders.cache[this._state.ui.selectedSyncedOrderId]
var rewardLines = refundOrder._get_reward_lines()
for(var line in rewardLines ){
var dict = {}
dict[rewardLines[line].coupon_id] = rewardLines[line].points_cost
pointsCost.push(dict)
}
localStorage.setItem("pointsCost", JSON.stringify(pointsCost))
return res
}
_onUpdateSelectedOrderline({ detail }) {
//----to prevent the return of reward lines
const buffer = detail.buffer;
const order = this.getSelectedSyncedOrder();
if (!order) return NumberBuffer.reset();
let pointsCost = []
var reward_product_id = []
var refundOrder = this._state.syncedOrders.cache[this._state.ui.selectedSyncedOrderId]
var rewardLines = refundOrder._get_reward_lines()
for(var line in rewardLines ){
var dict = {}
dict[rewardLines[line].coupon_id] = rewardLines[line].points_cost
pointsCost.push(dict)
reward_product_id.push(rewardLines[line].product.id)
}
const selectedOrderlineId = this.getSelectedOrderlineId();
const orderline = order.orderlines.find((line) => line.id == selectedOrderlineId);
if (!orderline) return NumberBuffer.reset();
const toRefundDetail = this._getToRefundDetail(orderline);
// When already linked to an order, do not modify the to refund quantity.
if (toRefundDetail.destinationOrderUid) return NumberBuffer.reset();
const refundableQty = toRefundDetail.orderline.qty - toRefundDetail.orderline.refundedQty;
if (refundableQty <= 0) return NumberBuffer.reset();
if (buffer == null || buffer == '') {
toRefundDetail.qty = 0;
} else {
const quantity = Math.abs(parse.float(buffer));
if(orderline.is_reward_line == true || orderline.product.id == reward_product_id[0] -1){
if(quantity > 0){
this.showPopup('ErrorPopup', {
title: _t("REFUND NOT POSSIBLE"),
body: _t(
"You cannot refund a rewarded line",
),
});
}
}
else{
if (quantity > refundableQty) {
NumberBuffer.reset();
this.showPopup('ErrorPopup', {
title: this.env._t('Maximum Exceeded'),
body: _.str.sprintf(
this.env._t(
'The requested quantity to be refunded is higher than the ordered quantity. %s is requested while only %s can be refunded.'
),
quantity,
refundableQty
),
});
} else {
toRefundDetail.qty = quantity;
}
}
}
}
}
Registries.Component.extend(TicketScreen, LoyaltyRefundTicketScreen);
});

59
advanced_loyalty_management/static/src/js/reward_popup.js

@ -0,0 +1,59 @@
/** @odoo-module **/
import AbstractAwaitablePopup from 'point_of_sale.AbstractAwaitablePopup';
import Registries from 'point_of_sale.Registries';
const { useState,useRef } = owl;
import { _t } from 'web.core';
class RewardPopup extends AbstractAwaitablePopup {
setup(){
this.state = useState({
value:'' ,
redeemPoints:''
})
this.points = useRef("points");
}
toRedeem(ev){
ev.state.redeemPoints = ev.points.el.value
}
save(props,ev){
//---after giving the points to redeem, the reward is added to orderline
if(isNaN(ev.state.redeemPoints)){
ev.showPopup('ErrorPopup', {
title: ev.env._t('Error'),
body: ev.env._t('Please enter a valid number'),
});
}else if(ev.props.max_redemption_points < ev.state.redeemPoints){
ev.showPopup('ErrorPopup', {
title: ev.env._t('Error'),
body: ev.env._t('Points to redeem should be less than Maximum Redemption Point.'),
});
}
else{
const selectedReward = props.selected_reward
const pointsWon = props.order.couponPointChanges[selectedReward.coupon_id].points
const order = props.order.access_token
selectedReward.reward.pointsToRedeem = parseInt(ev.state.redeemPoints)
ev.confirm()
props.order.selectedCoupon = selectedReward.coupon_id
props.order.pointsCost = parseInt(ev.state.redeemPoints)
return props.property._applyReward(
selectedReward.reward,
selectedReward.coupon_id,
selectedReward.potentialQty
);
}
}
}
RewardPopup.template = 'RewardPopup';
RewardPopup.defaultProps = {
confirmText: 'Confirm',
cancelText: 'Cancel',
title: 'Loyalty Programs',
body: '',
};
Registries.Component.add(RewardPopup);
return RewardPopup;

171
advanced_loyalty_management/static/src/js/rewardbutton.js

@ -0,0 +1,171 @@
/** @odoo-module **/
import { patch } from "@web/core/utils/patch";
import { RewardButton} from "@pos_loyalty/js/ControlButtons/RewardButton";
import { useListener } from "@web/core/utils/hooks";
const { Gui } = require('point_of_sale.Gui');
const { useState } = owl;
var rpc = require('web.rpc');
patch(RewardButton.prototype, "pos_loyalty_reward", {
setup() {
useListener('click', this.onClick);
this.state = useState({
frequency : 0,
});
},
_mergeFreeProductRewards(freeProductRewards, potentialFreeProductRewards,redemption) {
const result = []
for (const reward of potentialFreeProductRewards) {
if (!freeProductRewards.find(item => item.reward.id === reward.reward.id)) {
result.push(reward);
}
}
for (const rew of redemption){
result.push(rew)
}
return freeProductRewards.concat(result);
},
_getPotentialRewards() {
const order = this.env.pos.get_order();
// Claimable rewards excluding those from eWallet programs.
// eWallet rewards are handled in the eWalletButton.
var pointCheck = false
for (const pointChange of Object.values(order.couponPointChanges)){
if(pointChange.coupon_id > 0){
pointCheck = true
}
}
let rewards = [];
if (order) {
const claimableRewards = order.getClaimableRewards();
rewards = claimableRewards.filter(({ reward }) => reward.program_id.program_type !== 'ewallet');
}
const discountRewards = rewards.filter(({ reward }) => reward.reward_type == 'discount');
const freeProductRewards = rewards.filter(({ reward }) => reward.reward_type == 'product');
const redemption = rewards.filter(({ reward }) => reward.reward_type == 'redemption' && pointCheck == true
&& reward.redemption_frequency > this.state.frequency);
if(order.partner != null){
var checkFrequency = this.check(rewards)
}
const potentialFreeProductRewards = order.getPotentialFreeProductRewards();
return discountRewards.concat(this._mergeFreeProductRewards(freeProductRewards, potentialFreeProductRewards,redemption));
},
async check(rewards){
//---to check how many times the reward is claimed
let count = 0;
const partner_id = this.env.pos.get_order().partner.id
var checkRedemption = await rpc.query({
model:'res.partner',
method:'check_redemption',
args:[partner_id]
}).then((result)=>{
const today = new Date()
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const day = String(today.getDate()).padStart(2, '0');
const formattedDate = `${year}-${month}-${day}`;
const currentWeekStart = new Date(today.getFullYear(), today.getMonth(), today.getDate() - today.getDay());
const currentWeekEnd = new Date(today.getFullYear(), today.getMonth(), today.getDate() + (6 - today.getDay()));
const formattedCurrentWeekStart = currentWeekStart.toISOString().split('T')[0];
const formattedCurrentWeekEnd = currentWeekEnd.toISOString().split('T')[0];
const currentMonthStart = new Date(today.getFullYear(), today.getMonth(), 1);
const currentMonthEnd = new Date(today.getFullYear(), today.getMonth() + 1, 0); // Last day of current month
const formattedCurrentMonthStart = currentMonthStart.toISOString().split('T')[0];
const formattedCurrentMonthEnd = currentMonthEnd.toISOString().split('T')[0];
const currentYearStart = new Date(today.getFullYear(), 0, 1);
const currentYearEnd = new Date(today.getFullYear(), 11, 31);
const formattedCurrentYearStart = currentYearStart.toISOString().split('T')[0];
const formattedCurrentYearEnd = currentYearEnd.toISOString().split('T')[0];
for (const reward of rewards){
if(reward.reward.redemption_frequency_unit === 'day'){
for (let i = 0; i < result[1].length; i++) {
if (result[1][i] === formattedDate) {
count ++;
}
}
}
else if(reward.reward.redemption_frequency_unit === 'week'){
for (let i = 0; i < result[1].length; i++) {
const date =(result[1][i]);
if (date >= formattedCurrentWeekStart && date <= formattedCurrentWeekEnd) {
count++;
}
}
}
else if(reward.reward.redemption_frequency_unit === 'month'){
for (let i = 0; i < result[1].length; i++) {
const date =(result[1][i]);
if (date >= formattedCurrentMonthStart && date <= formattedCurrentMonthEnd) {
count++;
}
}
}
else if(reward.reward.redemption_frequency_unit === 'year'){
for (let i = 0; i < result[1].length; i++) {
const date =(result[1][i]);
if (date >= formattedCurrentYearStart && date <= formattedCurrentYearEnd) {
count ++
}
}
}
}
return count
})
this.state.frequency = checkRedemption
},
async onClick() {
//----change in work flow when reward type is redemption
const rewards = this._getPotentialRewards();
const order = this.env.pos.get_order();
if (rewards.length === 0) {
await this.showPopup('ErrorPopup', {
title: this.env._t('No rewards available.'),
body: this.env._t('There are no rewards claimable for this customer.')
});
return false;
} else {
const rewardsList = rewards.map((reward) => ({
id: reward.reward.id,
label: reward.reward.description,
item: reward,
}));
const { confirmed, payload: selectedReward } = await this.showPopup('SelectionPopup', {
title: this.env._t('Please select a reward'),
list: rewardsList,
});
if (confirmed) {
if(selectedReward.reward.reward_type == "redemption"){
var points = []
if(selectedReward.reward.max_redemption_type == 'points'){
points.push(selectedReward.reward.max_redemption_amount/selectedReward.reward.redemption_amount)
}
else if(selectedReward.reward.max_redemption_type == 'amount'){
points.push(selectedReward.reward.max_redemption_amount/selectedReward.reward.redemption_amount)
}
else if(selectedReward.reward.max_redemption_type == 'percent'){
var totalAmount = order.get_total_with_tax()
var maxRedemption = totalAmount * selectedReward.reward.max_redemption_amount / 100
points.push(maxRedemption/selectedReward.reward.redemption_amount)
}
await Gui.showPopup("RewardPopup", {
title: this.env._t("Redeem Points"),
cancelText: this.env._t("Cancel"),
confirmText:this.env._t("Confirm"),
rewards: rewards,
selected_reward: selectedReward,
order: order,
max_redemption_points : points[0],
property: this
});
}else{
return this._applyReward(selectedReward.reward, selectedReward.coupon_id, selectedReward.potentialQty);
}
}
}
return false;
}
})

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save