@ -0,0 +1,50 @@ |
|||
.. 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/15.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: (V17) NIHALA KP, |
|||
(V16) NIHALA KP, |
|||
(V15) Adarsh K, |
|||
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>`__ |
@ -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 |
@ -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/>. |
|||
# |
|||
############################################################################# |
|||
{ |
|||
'name': 'Advanced Loyalty Management', |
|||
'version': '15.0.1.0.0', |
|||
'category': 'Point of Sale', |
|||
'summary': 'Enhanced Loyalty Program Features', |
|||
'description': """In this module, we have incorporated new features such as |
|||
converting changes into loyalty points, displaying claimed rewards history, and |
|||
introducing a new type of reward. These enhancements aim to provide a more |
|||
comprehensive and rewarding experience for customers engaging with the loyalty |
|||
program.""", |
|||
'author': 'Cybrosys Techno Solutions', |
|||
'company': 'Cybrosys Techno Solutions', |
|||
'maintainer': 'Cybrosys Techno Solutions', |
|||
'website': 'https://www.cybrosys.com', |
|||
'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', |
|||
], |
|||
'assets': { |
|||
'point_of_sale.assets': [ |
|||
'advanced_loyalty_management/static/src/js/pos_payment_screen.js', |
|||
'advanced_loyalty_management/static/src/js/pos_change_popup.js', |
|||
'advanced_loyalty_management/static/src/js/pos_order_line.js', |
|||
'advanced_loyalty_management/static/src/js/pos_order.js', |
|||
'advanced_loyalty_management/static/src/js/rewardbutton.js', |
|||
'advanced_loyalty_management/static/src/js/reward_popup.js', |
|||
], |
|||
'web.assets_qweb': [ |
|||
'advanced_loyalty_management/static/src/xml/pos_loyalty_change.xml', |
|||
'advanced_loyalty_management/static/src/xml/pos_change_popup.xml', |
|||
'advanced_loyalty_management/static/src/xml/reward_popup.xml', |
|||
], |
|||
}, |
|||
'images': [ |
|||
'static/description/banner.png', |
|||
], |
|||
'license': 'LGPL-3', |
|||
'installable': True, |
|||
'auto_install': False, |
|||
'application': False, |
|||
} |
@ -0,0 +1,6 @@ |
|||
## Module <advanced_loyalty_management> |
|||
|
|||
#### 23.07.2024 |
|||
#### Version 15.0.1.0.0 |
|||
#### ADD |
|||
- Initial Commit Advanced Loyalty Management |
@ -0,0 +1,25 @@ |
|||
# -*- 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 |
@ -0,0 +1,37 @@ |
|||
# -*- 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 fields, models |
|||
|
|||
|
|||
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") |
@ -0,0 +1,77 @@ |
|||
# -*- 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, fields, models |
|||
|
|||
|
|||
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.model |
|||
def create(self, vals): |
|||
"""creation of new reward product""" |
|||
product = self.env['product.product'].create({ |
|||
'name': vals['name'], |
|||
'detailed_type': 'service', |
|||
'available_in_pos': True, |
|||
}) |
|||
vals['discount_product_id'] = product.id |
|||
return super(LoyaltyReward, self).create(vals) |
@ -0,0 +1,30 @@ |
|||
# -*- 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 fields, models |
|||
|
|||
|
|||
class PosOrderLine(models.Model): |
|||
"""New boolean field is added to filter rewards from order line""" |
|||
_inherit = 'pos.order.line' |
|||
|
|||
is_reward_line = fields.Boolean( |
|||
help="Whether this line is part of a reward or not.") |
@ -0,0 +1,54 @@ |
|||
# -*- 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 in view_partner_form""" |
|||
_inherit = 'res.partner' |
|||
|
|||
def action_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, partner_id): |
|||
"""To check number of times the reward is claimed""" |
|||
order = self.env['pos.order'].search([('partner_id', '=', partner_id)]) |
|||
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 |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 589 B |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 967 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 71 KiB |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 57 KiB |
After Width: | Height: | Size: 83 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 83 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 105 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 83 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 94 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 433 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 9.4 KiB |
@ -0,0 +1,715 @@ |
|||
<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>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 |
|||
Converting Changes into Loyalty Points, Displaying Claimed Rewards History, and |
|||
Introducing a new Type of Reward |
|||
<img src="assets/screenshots/v15-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 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 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 convert the change to loyalty points.To facilitate this, we have introduced |
|||
a new field in the loyalty program for the conversion rate per dollar. |
|||
</h3> |
|||
<img src="assets/screenshots/1.png" class="img-thumbnail"> |
|||
<img src="assets/screenshots/2.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;"> |
|||
Initially, we can select a customer, whose loyalty points are set to zero. |
|||
</h3> |
|||
<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;"> |
|||
Then we can create a sales order directly from the POS interface. |
|||
</h3> |
|||
<img src="assets/screenshots/4.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 create a button under the change to convert the loyalty. |
|||
</h3> |
|||
<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;"> |
|||
When the popup is clicked, the loyalty program allocated for the POS session |
|||
will become visible here.Clicking the ADD button will convert changes, and the |
|||
change amount will reset to zero. |
|||
</h3> |
|||
<img src="assets/screenshots/6.png" class="img-thumbnail"> |
|||
<img src="assets/screenshots/7.png" class="img-thumbnail"> |
|||
<img src="assets/screenshots/8.png" class="img-thumbnail"> |
|||
<img src="assets/screenshots/9.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/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;"> |
|||
In this type of reward, customers can only claim the reward if they are making |
|||
a second purchase or if they have existing loyalty points. |
|||
</h3> |
|||
<img src="assets/screenshots/11.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/12.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/13.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/14.png" class="img-thumbnail"> |
|||
<img src="assets/screenshots/15.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/16.png" class="img-thumbnail"> |
|||
<img src="assets/screenshots/17.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/18.png" class="img-thumbnail"> |
|||
<img src="assets/screenshots/19.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/20.png" class="img-thumbnail"> |
|||
<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;"> |
|||
Next we can see the history of claimed rewards in the customer's page. |
|||
</h3> |
|||
<img src="assets/screenshots/22.png" class="img-thumbnail"> |
|||
<img src="assets/screenshots/23.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/15.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.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/15.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/15.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.jpg"> |
|||
</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/15.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/15.0/product_return_pos/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-radius: 0px;" |
|||
src="assets/modules/5.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/15.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.png"> |
|||
</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 & 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 --> |
@ -0,0 +1,42 @@ |
|||
odoo.define('advanced_loyalty_management.LoyaltyPrograms', function (require) { |
|||
"use strict"; |
|||
|
|||
const AbstractAwaitablePopup = require('point_of_sale.AbstractAwaitablePopup'); |
|||
const Registries = require('point_of_sale.Registries'); |
|||
const rpc = require('web.rpc'); |
|||
const { _t } = require('web.core'); |
|||
|
|||
class LoyaltyPrograms extends AbstractAwaitablePopup { |
|||
constructor() { |
|||
super(...arguments); |
|||
} |
|||
async convertToLoyalty(props, programId) { |
|||
const change = props.change; |
|||
const order = props.Order; |
|||
const loyalty = props.Loyalty |
|||
|
|||
// Resets the change by adjusting the payment
|
|||
if (change > 0) { |
|||
const lastPaymentLine = props.Order.get_paymentlines().slice(-1)[0]; |
|||
if (lastPaymentLine) { |
|||
lastPaymentLine.set_amount(lastPaymentLine.get_amount() - change); |
|||
} |
|||
order.change_to_loyalty = change * loyalty.point_rate; |
|||
} |
|||
|
|||
this.trigger('confirm'); |
|||
} |
|||
} |
|||
|
|||
LoyaltyPrograms.template = 'LoyaltyPrograms'; |
|||
LoyaltyPrograms.defaultProps = { |
|||
confirmText: _t('Confirm'), |
|||
cancelText: _t('Cancel'), |
|||
title: _t('Loyalty Programs'), |
|||
body: '', |
|||
}; |
|||
|
|||
Registries.Component.add(LoyaltyPrograms); |
|||
|
|||
return LoyaltyPrograms; |
|||
}); |
@ -0,0 +1,82 @@ |
|||
odoo.define('advanced_loyalty_management.Order', function(require) { |
|||
"use strict"; |
|||
|
|||
const models = require('point_of_sale.models'); |
|||
const _super_Order = models.Order.prototype; |
|||
const { patch } = require('web.utils'); |
|||
const ProductScreen = require('point_of_sale.ProductScreen'); |
|||
|
|||
|
|||
models.Order = models.Order.extend({ |
|||
initialize: function(attributes, options) { |
|||
_super_Order.initialize.apply(this, arguments); |
|||
if (options?.json?.lines.length === 0) { |
|||
this.additional_redeemed_points = 0; |
|||
this.pointsWon = 0; |
|||
this.selected_reward = null; |
|||
} |
|||
}, |
|||
|
|||
get_won_points: function() { |
|||
const wonPoints = _super_Order.get_won_points.apply(this, arguments); |
|||
if (this.selected_reward && this.selected_reward.reward_type === 'redemption') { |
|||
return Math.max(0, this.pointsWon - this.additional_redeemed_points); |
|||
} |
|||
return wonPoints; |
|||
}, |
|||
|
|||
get_spent_points: function() { |
|||
const spentPoints = _super_Order.get_spent_points.apply(this, arguments); |
|||
return spentPoints + this.additional_redeemed_points; |
|||
}, |
|||
|
|||
get_new_points: function() { |
|||
const newPoints = _super_Order.get_new_points.apply(this, arguments); |
|||
if (this.selected_reward && this.selected_reward.reward_type === 'redemption') { |
|||
return Math.max(0, this.pointsWon - this.additional_redeemed_points); |
|||
} |
|||
return newPoints; |
|||
}, |
|||
// Ensure pointsWon, additional_redeemed_points, selected_reward is also persisted
|
|||
export_as_JSON: function() { |
|||
const json = _super_Order.export_as_JSON.apply(this, arguments); |
|||
json.additional_redeemed_points = this.additional_redeemed_points; |
|||
json.selected_reward = this.selected_reward; |
|||
json.pointsWon = this.pointsWon; |
|||
return json; |
|||
}, |
|||
// Restore pointsWon, additional_redeemed_points, selected_reward
|
|||
init_from_JSON: function(json) { |
|||
_super_Order.init_from_JSON.apply(this, arguments); |
|||
this.additional_redeemed_points = json.additional_redeemed_points || 0; |
|||
this.selected_reward = json.selected_reward || null; |
|||
this.pointsWon = json.pointsWon || 0; |
|||
}, |
|||
|
|||
applyRedeemPoints: function(pointsToRedeem, selectedReward, pointsWon) { |
|||
this.additional_redeemed_points += pointsToRedeem; |
|||
this.selected_reward = selectedReward; |
|||
this.pointsWon = pointsWon; |
|||
}, |
|||
resetRedemptionPoints: function() { |
|||
this.additional_redeemed_points = 0; |
|||
this.pointsWon = 0; |
|||
this.selected_reward = null; |
|||
} |
|||
}); |
|||
// Resets the loyalty points on clicking backspace
|
|||
patch(ProductScreen.prototype, 'advanced_loyalty_management.ProductScreen', { |
|||
_updateSelectedOrderline: function (event) { |
|||
let screen = this._super(...arguments); |
|||
const order = this.env.pos.get_order() |
|||
const selectedLine = order?.selected_orderline?.get_reward()?.reward_type; |
|||
if (selectedLine === 'redemption') { |
|||
order.resetRedemptionPoints(); |
|||
this.render(); |
|||
} |
|||
return screen; |
|||
}, |
|||
}); |
|||
|
|||
return models; |
|||
}); |
@ -0,0 +1,20 @@ |
|||
odoo.define('advanced_loyalty_management.OrderLine', function (require) { |
|||
"use strict"; |
|||
var models = require('point_of_sale.models'); |
|||
var _super_orderline = models.Orderline.prototype; |
|||
|
|||
models.Orderline = models.Orderline.extend({ |
|||
// To include a is_reward_line flag for reward lines, during initialization and JSON export
|
|||
initialize: function(attr, options) { |
|||
_super_orderline.initialize.apply(this, arguments); |
|||
if (options.extras && options.extras.is_reward_line) { |
|||
this.is_reward_line = options.extras.is_reward_line; |
|||
} |
|||
}, |
|||
export_as_JSON: function() { |
|||
var json = _super_orderline.export_as_JSON.apply(this, arguments); |
|||
json.is_reward_line = this.is_reward_line || false; |
|||
return json; |
|||
}, |
|||
}); |
|||
}); |
@ -0,0 +1,38 @@ |
|||
odoo.define('advanced_loyalty_management.ChangeLoyalty', function (require) { |
|||
"use strict"; |
|||
const { patch } = require('web.utils'); |
|||
const PaymentScreenStatus = require('point_of_sale.PaymentScreenStatus'); |
|||
const { Gui } = require('point_of_sale.Gui'); |
|||
|
|||
patch(PaymentScreenStatus.prototype, 'point_of_sale/static/src/js/Screens/PaymentScreen/PaymentScreenStatus.js', { |
|||
async convertLoyalty() { |
|||
var order = this.env.pos.get_order(); |
|||
const result = await Gui.showPopup('LoyaltyPrograms', { |
|||
title: this.env._t('Convert Change'), |
|||
cancelText: this.env._t("Cancel"), |
|||
confirmText: this.env._t("Confirm"), |
|||
Order: order, |
|||
Loyalty: this.env.pos.loyalty, |
|||
LoyaltyPoints: order.get_won_points(), |
|||
change: order.get_change(), |
|||
}); |
|||
}, |
|||
|
|||
showLoyaltyButton: function() { |
|||
var order = this.env.pos.get_order(); |
|||
const showButton = order.get_change() > 0 && order.get_won_points() > 0 |
|||
return showButton; |
|||
}, |
|||
}); |
|||
// Patch the Order prototype to modify get_won_points and adds the change
|
|||
const Order = require('point_of_sale.models').Order; |
|||
patch(Order.prototype, 'advanced_loyalty_management.Order', { |
|||
get_won_points: function () { |
|||
let points = this._super(...arguments); |
|||
if (this.change_to_loyalty) { |
|||
points += this.change_to_loyalty; |
|||
} |
|||
return points; |
|||
}, |
|||
}); |
|||
}); |
@ -0,0 +1,62 @@ |
|||
odoo.define('advanced_loyalty_management.RewardPopup', function (require) { |
|||
"use strict"; |
|||
|
|||
const AbstractAwaitablePopup = require('point_of_sale.AbstractAwaitablePopup'); |
|||
const Registries = require('point_of_sale.Registries'); |
|||
const { _t } = require('web.core'); |
|||
const { hooks } = owl; |
|||
const { useState, useRef } = hooks; |
|||
|
|||
class RewardPopup extends AbstractAwaitablePopup { |
|||
setup() { |
|||
this.state = useState({ |
|||
value: '', |
|||
redeemPoints: '' |
|||
}); |
|||
this.points = useRef("points"); |
|||
} |
|||
|
|||
toRedeem(ev) { |
|||
this.state.redeemPoints = this.points.el.value; |
|||
} |
|||
|
|||
save(props, ev) { |
|||
const pointsToRedeem = parseInt(this.state.redeemPoints); |
|||
if (isNaN(pointsToRedeem)) { |
|||
this.showPopup('ErrorPopup', { |
|||
title: _t('Error'), |
|||
body: _t('Please enter a valid number'), |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
if (props.max_redemption_points < pointsToRedeem) { |
|||
this.showPopup('ErrorPopup', { |
|||
title: _t('Error'), |
|||
body: _t('Points to redeem should be less than Maximum Redemption Point.'), |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
const selectedReward = props.selected_reward; |
|||
selectedReward.pointsToRedeem = parseInt(this.state.redeemPoints); |
|||
const pointsWon = props.order.get_won_points(); |
|||
props.order.point_cost = pointsToRedeem; |
|||
ev.confirm(); |
|||
props.property.apply_reward(selectedReward); |
|||
props.order.applyRedeemPoints(pointsToRedeem, selectedReward, pointsWon); |
|||
} |
|||
} |
|||
|
|||
RewardPopup.template = 'RewardPopup'; |
|||
RewardPopup.defaultProps = { |
|||
confirmText: _t('Confirm'), |
|||
cancelText: _t('Cancel'), |
|||
title: _t('Reward'), |
|||
body: '', |
|||
}; |
|||
|
|||
Registries.Component.add(RewardPopup); |
|||
|
|||
return RewardPopup; |
|||
}); |
@ -0,0 +1,287 @@ |
|||
odoo.define('advanced_loyalty_management.RewardButton', function (require) { |
|||
"use strict"; |
|||
const { patch } = require('web.utils'); |
|||
const { useListener } = require('web.custom_hooks'); |
|||
const RewardButton = require('pos_loyalty.RewardButton'); |
|||
const { Gui } = require('point_of_sale.Gui'); |
|||
const { _t } = require('web.core'); |
|||
const { useState } = owl; |
|||
var models = require('point_of_sale.models'); |
|||
var rpc = require('web.rpc'); |
|||
var utils = require('web.utils'); |
|||
var round_pr = utils.round_precision; |
|||
models.load_fields("loyalty.reward", |
|||
["max_redemption_amount", "redemption_point", "redemption_amount","redemption_frequency","redemption_frequency_unit", |
|||
"redemption_eligibility", "max_redemption_type"]); |
|||
models.load_fields("loyalty.program", |
|||
["point_rate"]); |
|||
|
|||
patch(RewardButton.prototype, "pos_loyalty/static/src/js/RewardButton.js", { |
|||
setup() { |
|||
useListener('click', this.onClick); |
|||
this.state = useState({ |
|||
frequency : 0, |
|||
}); |
|||
}, |
|||
async apply_reward(reward) { |
|||
const order = this.env.pos.get_order(); |
|||
var client = order.get_client(); |
|||
var product, product_price, order_total, spendable; |
|||
var crounding; |
|||
|
|||
if (!client) { |
|||
return; |
|||
} else if (reward.reward_type === 'gift') { |
|||
product = order.pos.db.get_product_by_id(reward.gift_product_id[0]); |
|||
|
|||
if (!product) { |
|||
return; |
|||
} |
|||
|
|||
let options = await order._getAddProductOptions(product); |
|||
await order.add_product(product, { |
|||
...options, |
|||
price: 0, |
|||
quantity: 1, |
|||
merge: false, |
|||
extras: { reward_id: reward.id, price_manually_set: true, is_reward_line: true }, |
|||
}); |
|||
|
|||
} else if (reward.reward_type === 'discount') { |
|||
|
|||
crounding = order.pos.currency.rounding; |
|||
spendable = order.get_spendable_points(); |
|||
order_total = order.get_total_with_tax(); |
|||
var discount = 0; |
|||
|
|||
product = order.pos.db.get_product_by_id(reward.discount_product_id[0]); |
|||
|
|||
if (!product) { |
|||
return; |
|||
} |
|||
|
|||
if (reward.discount_type === "percentage") { |
|||
if (reward.discount_apply_on === "on_order") { |
|||
discount += round_pr(order_total * (reward.discount_percentage / 100), crounding); |
|||
} |
|||
|
|||
if (reward.discount_apply_on === "specific_products") { |
|||
for (var prod of reward.discount_specific_product_ids) { |
|||
var specific_products = order.pos.db.get_product_by_id(prod); |
|||
|
|||
if (!specific_products) |
|||
return; |
|||
|
|||
for (var line of order.get_orderlines()) { |
|||
if (line.product.id === specific_products.id) |
|||
discount += round_pr(line.get_price_with_tax() * (reward.discount_percentage / 100), crounding); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (reward.discount_apply_on === "cheapest_product") { |
|||
var price; |
|||
for (var line of order.get_orderlines()) { |
|||
if ((!price || price > line.get_unit_price()) && line.product.id !== product.id) { |
|||
discount = round_pr(line.get_price_with_tax() * (reward.discount_percentage / 100), crounding); |
|||
price = line.get_unit_price(); |
|||
} |
|||
} |
|||
} |
|||
if (reward.discount_max_amount !== 0 && discount > reward.discount_max_amount) |
|||
discount = reward.discount_max_amount; |
|||
|
|||
let options = await order._getAddProductOptions(product); |
|||
await order.add_product(product, { |
|||
...options, |
|||
price: -discount, |
|||
quantity: 1, |
|||
merge: false, |
|||
extras: { reward_id: reward.id, price_manually_set: true, is_reward_line: true }, |
|||
}); |
|||
} |
|||
if (reward.discount_type == "fixed_amount") { |
|||
let discount_fixed_amount = reward.discount_fixed_amount; |
|||
let point_cost = reward.point_cost; |
|||
let quantity_to_apply = Math.floor(spendable / point_cost); |
|||
let amount_discounted = discount_fixed_amount * quantity_to_apply; |
|||
|
|||
if (amount_discounted > order_total) { |
|||
quantity_to_apply = Math.floor(order_total / discount_fixed_amount); |
|||
} |
|||
|
|||
let options = await order._getAddProductOptions(product); |
|||
await order.add_product(product, { |
|||
...options, |
|||
price: -discount_fixed_amount, |
|||
quantity: quantity_to_apply, |
|||
merge: false, |
|||
extras: { reward_id: reward.id, price_manually_set: true, is_reward_line: true }, |
|||
}); |
|||
} |
|||
} |
|||
// Start of new condition for reward_type 'redemption'
|
|||
else if (reward.reward_type === 'redemption') { |
|||
if (order.get_client() != null) { |
|||
await this.check(reward, order.get_client().id); |
|||
} |
|||
|
|||
if (reward.redemption_frequency > this.state.frequency) { |
|||
product = this.env.pos.db.get_product_by_id(reward.discount_product_id[0]); |
|||
if (!product) { |
|||
return; |
|||
} |
|||
|
|||
let options = await order._getAddProductOptions(product); |
|||
await order.add_product(product, { |
|||
...options, |
|||
price: -reward.pointsToRedeem, |
|||
quantity: 1, |
|||
merge: false, |
|||
extras: { reward_id: reward.id, price_manually_set: true, is_reward_line: true }, |
|||
}); |
|||
} else { |
|||
this.showPopup('ErrorPopup', { |
|||
title: _t("REDEMPTION LIMIT REACHED"), |
|||
body: _t("You have reached the redemption limit for this period."), |
|||
}); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
async check(reward, partnerId){ |
|||
//---To check how many times the reward is claimed
|
|||
let count = 0; |
|||
var checkRedemption = await rpc.query({ |
|||
model:'res.partner', |
|||
method:'check_redemption', |
|||
args:[partnerId] |
|||
}) |
|||
.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]; |
|||
if(reward.redemption_frequency_unit === 'day'){ |
|||
for (let i = 0; i < result[1].length; i++) { |
|||
if (result[1][i] === formattedDate) { |
|||
count ++; |
|||
} |
|||
} |
|||
} |
|||
else if(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.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.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() { |
|||
const order = this.env.pos.get_order(); |
|||
const rewards = order.get_available_rewards(); |
|||
const client = order.get_client(); |
|||
|
|||
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; |
|||
} |
|||
|
|||
let rewardPoints = 0; |
|||
if (client) { |
|||
rewardPoints = client.loyalty_points || 0; |
|||
} |
|||
|
|||
const filteredRewards = rewards.filter(reward => { |
|||
if (reward.reward_type === 'redemption') { |
|||
return rewardPoints > 0; |
|||
} |
|||
return true; |
|||
}); |
|||
|
|||
if (filteredRewards.length === 0) { |
|||
await this.showPopup('ErrorPopup', { |
|||
title: this.env._t('No claimable rewards.'), |
|||
body: this.env._t('There are no rewards claimable for this customer.') |
|||
}); |
|||
return false; |
|||
} |
|||
|
|||
const rewardsList = filteredRewards.map((reward) => ({ |
|||
id: reward.id, |
|||
label: reward.name, |
|||
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_type == "redemption") { |
|||
var points = []; |
|||
if (selectedReward.max_redemption_type == 'points') { |
|||
points.push(selectedReward.max_redemption_amount / selectedReward.redemption_amount); |
|||
} else if (selectedReward.max_redemption_type == 'amount') { |
|||
points.push(selectedReward.max_redemption_amount / selectedReward.redemption_amount); |
|||
} else if (selectedReward.max_redemption_type == 'percent') { |
|||
var totalAmount = order.get_total_with_tax(); |
|||
var maxRedemption = totalAmount * selectedReward.max_redemption_amount / 100; |
|||
points.push(maxRedemption / selectedReward.redemption_amount); |
|||
} |
|||
Gui.showPopup('RewardPopup', { |
|||
title: this.env._t('Reward'), |
|||
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.apply_reward(selectedReward); |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
}) |
|||
}) |
@ -0,0 +1,31 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<templates id="template" xml:space="preserve"> |
|||
<!-- Popup when convert to loyalty is clicked --> |
|||
<t t-name="LoyaltyPrograms" owl="1"> |
|||
<div role="dialog" class="modal-dialog"> |
|||
<div class="popup popup-couponproducts" style="background-color: #ffffff; text-align: center;"> |
|||
<p class="title"> |
|||
<t t-esc="props.title"/> |
|||
</p> |
|||
<div class="body"> |
|||
<div style="margin: 3%; display: inline-block;"> |
|||
<span style="font-size: 25px; font-weight: bold;"> |
|||
<t t-esc="props.Loyalty.name"/> |
|||
</span> |
|||
<button class="button btn btn-lg btn-primary" |
|||
style="margin-top: 10px; padding: 10px; width: 100%; text-align: center; font-weight: bold;" |
|||
t-on-click="() => { convertToLoyalty(props, this); cancel(); }"> |
|||
Add |
|||
</button> |
|||
</div> |
|||
</div> |
|||
<div class="footer footer-flex modal-footer justify-content-end"> |
|||
<div class="button cancel btn btn-lg btn-primary" |
|||
t-on-click="cancel"> |
|||
<t t-esc="props.cancelText"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</templates> |
@ -0,0 +1,17 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<templates id="template" xml:space="preserve"> |
|||
<!--Button is added to convert the change to loyalty points--> |
|||
<t t-inherit="point_of_sale.PaymentScreenStatus" t-inherit-mode="extension"> |
|||
<xpath expr="//div[hasclass('payment-status-change')]" position="after"> |
|||
<t t-if="showLoyaltyButton()"> |
|||
<button class="btn btn-light rounded-0 fw-bolder" |
|||
t-on-click="convertLoyalty" style="font-size: 17px;"> |
|||
<i role="img" aria-label="Custom Button" |
|||
title="Custom Button"/> |
|||
Convert to Loyalty |
|||
</button> |
|||
</t> |
|||
</xpath> |
|||
</t> |
|||
</templates> |
|||
|
@ -0,0 +1,43 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<templates id="template" xml:space="preserve"> |
|||
<!-- Popup displayed when convert to loyalty is clicked --> |
|||
<t t-name="RewardPopup" owl="1"> |
|||
<div role="dialog" class="modal-dialog"> |
|||
<div class="popup popup-couponproducts" style="background-color: #ffffff; text-align: center;"> |
|||
<p class="title"> |
|||
<t t-esc="props.title"/> |
|||
</p> |
|||
<div class="body"> |
|||
<form> |
|||
<table style="width: 100%; border-collapse: collapse; border: 1px solid #ddd;"> |
|||
<tr style="background-color: #f2f2f2;"> |
|||
<th style="padding: 8px; text-align: left;">Max Redemption Points</th> |
|||
<th style="padding: 8px; text-align: left;">To redeem</th> |
|||
</tr> |
|||
<tr> |
|||
<td style="padding: 8px;text-align: left;"> |
|||
<t t-esc="props.max_redemption_points"/> |
|||
</td> |
|||
<td style="padding: 8px;text-align: left;"> |
|||
<input class="w-75 form-control" name="customer" |
|||
t-on-change="() => toRedeem(this)" |
|||
t-ref="points"/> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
</form> |
|||
</div> |
|||
<div class="footer footer-flex modal-footer justify-content-end"> |
|||
<button |
|||
class="button cancel btn btn-lg btn-primary" |
|||
t-on-click="(ev) => save(props,this)" |
|||
string="add">Add</button> |
|||
<div class="button cancel btn btn-lg btn-primary" |
|||
t-on-click="cancel"> |
|||
<t t-esc="props.cancelText"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</templates> |
@ -0,0 +1,24 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<!--New fields added to loyalty.program view--> |
|||
<record id="view_loyalty_program_form" model="ir.ui.view"> |
|||
<field name="name">loyalty.program.view.form.inherit.advanced.loyalty.management</field> |
|||
<field name="model">loyalty.program</field> |
|||
<field name="inherit_id" ref="pos_loyalty.view_loyalty_program_form"/> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//field[@name='points']" position="after"> |
|||
<div class="o_group"> |
|||
<div class="o_col"> |
|||
<label for="point_rate" style="font-weight: bold;"/> |
|||
<div id="point_rate" class="o_row"> |
|||
<field name="point_rate" style="width: 2rem;" class="oe_inline"/> |
|||
<span invisible="" style="font-weight: bold;">Point per</span> |
|||
<field name="change_rate" widget="monetary" class="oe_inline"/> |
|||
<field name="currency_id" invisible="1"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,56 @@ |
|||
<?xml version="1.0" encoding = "utf-8"?> |
|||
<odoo> |
|||
<!--New fields added to Reward form--> |
|||
<record id="view_loyalty_reward_form" model="ir.ui.view"> |
|||
<field name="name"> |
|||
loyalty.reward.view.form.inherit.advanced.loyalty.management |
|||
</field> |
|||
<field name="model">loyalty.reward</field> |
|||
<field name="inherit_id" ref="pos_loyalty.view_loyalty_reward_form"/> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//group[2]/group" position="after"> |
|||
<label for="redemption_point" string="Conditions" |
|||
attrs="{'invisible': [('reward_type','!=','redemption')]}" style="font-weight: bold;"/> |
|||
<group |
|||
attrs="{'invisible': [('reward_type','!=','redemption')]}"> |
|||
<field name="redemption_point" default="1"/> |
|||
<field name="redemption_amount" widget="monetary"/> |
|||
<label for="max_redemption_amount"/> |
|||
<div id="max_redemption_amount" class="o_row"> |
|||
<field name="max_redemption_type" class="oe_inline"/> |
|||
<field name="max_redemption_amount" |
|||
class="oe_inline"/> |
|||
</div> |
|||
<field name="redemption_frequency"/> |
|||
<field name="redemption_frequency_unit"/> |
|||
<field name="redemption_eligibility" widget="monetary"/> |
|||
</group> |
|||
</xpath> |
|||
<xpath expr="//label[@for='discount_type']" position="replace"> |
|||
<label string="Apply Discount" for="discount_type" attrs="{'invisible': [('reward_type', 'in', ('gift','redemption'))]}"/> |
|||
</xpath> |
|||
<xpath expr="//field[@name='discount_product_id']" position="replace"> |
|||
<field name="discount_product_id" string="Discount Product" |
|||
attrs="{ 'invisible':[('reward_type','not in',['discount','redemption'])], |
|||
'required':[('reward_type','==','discount')] }" domain="[('available_in_pos', '=', True)]" |
|||
context="{'default_available_in_pos': '1'}"/> |
|||
</xpath> |
|||
<xpath expr="//field[@name='discount_apply_on']" position="replace"> |
|||
<field name="discount_apply_on" attrs="{'invisible': |
|||
['|', ('reward_type', 'in', ('product', 'gift', 'redemption')), |
|||
('discount_type', '!=', 'percentage')]}" widget="radio"/> |
|||
</xpath> |
|||
<xpath expr="//field[@name='discount_max_amount']" position="replace"> |
|||
<field name="discount_max_amount" class="oe_inline" attrs="{'invisible': |
|||
[('reward_type', '=', 'redemption')]}"/> |
|||
</xpath> |
|||
<xpath expr="//label[@for='discount_max_amount']" position="replace"> |
|||
<label for="discount_max_amount" string="Max Discount Amount" attrs="{'invisible': ['|', ('reward_type', 'in', ('product', 'gift', 'redemption')), ('discount_type', '!=', 'percentage')]}"/> |
|||
</xpath> |
|||
<xpath expr="//span[hasclass('oe_grey')]" position="replace"> |
|||
<span class="oe_grey" attrs="{'invisible': |
|||
[('reward_type', '=', 'redemption')]}">if 0, no limit</span> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,20 @@ |
|||
<?xml version="1.0" encoding = "utf-8"?> |
|||
<odoo> |
|||
<!-- Claimed Rewards smart button is shown in customer's form --> |
|||
<record id="view_partner_form" model="ir.ui.view"> |
|||
<field name="name">res.partner.view.form.inherit.advanced.loyalty.management</field> |
|||
<field name="model">res.partner</field> |
|||
<field name="inherit_id" ref="base.view_partner_form"/> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//button[@name='action_view_sale_order']" |
|||
position="after" create="false"> |
|||
<button name="action_view_claimed_rewards" |
|||
type="object" |
|||
class="oe_stat_button" |
|||
string="Claimed Rewards" |
|||
icon="fa-book"> |
|||
</button> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
</odoo> |