Browse Source

[ADD] pos_loyalty: loyalty programs for POS (#185)

* [ADD] pos_loyalty: loyalty programs for POS

* [FIX] Limit to one discount reward per order

* [FIX] Remove unused variables and returns

* [IMP] Refactoring rules loading
pull/175/merge
Gelu 7 years ago
committed by Sylvain LE GAL
parent
commit
4aff4e5807
  1. 58
      pos_loyalty/README.rst
  2. 4
      pos_loyalty/__init__.py
  3. 33
      pos_loyalty/__manifest__.py
  4. 467
      pos_loyalty/i18n/es.po
  5. 466
      pos_loyalty/i18n/pos_loyalty.pot
  6. 9
      pos_loyalty/models/__init__.py
  7. 31
      pos_loyalty/models/loyalty_program.py
  8. 68
      pos_loyalty/models/loyalty_reward.py
  9. 33
      pos_loyalty/models/loyalty_rule.py
  10. 15
      pos_loyalty/models/pos_config.py
  11. 31
      pos_loyalty/models/pos_order.py
  12. 14
      pos_loyalty/models/res_partner.py
  13. 7
      pos_loyalty/security/ir.model.access.csv
  14. 21
      pos_loyalty/static/src/css/pos.css
  15. 453
      pos_loyalty/static/src/js/pos.js
  16. 85
      pos_loyalty/static/src/xml/pos.xml
  17. 83
      pos_loyalty/views/loyalty_program_view.xml
  18. 37
      pos_loyalty/views/loyalty_reward_view.xml
  19. 31
      pos_loyalty/views/loyalty_rule_view.xml
  20. 15
      pos_loyalty/views/pos_config_view.xml
  21. 15
      pos_loyalty/views/pos_order_view.xml
  22. 15
      pos_loyalty/views/res_partner_view.xml
  23. 9
      pos_loyalty/views/templates.xml

58
pos_loyalty/README.rst

@ -0,0 +1,58 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
===============
Loyalty Program
===============
This module allows you to define a loyalty program in the point of sale,
where the customers earn loyalty points and get rewards.
This module is a forward-port to v10 of the pos_loyalty module from Odoo's
saas-6 branch.
The functionality was moved to the Enterprise edition in later versions.
Usage
=====
To use this module, you need to:
* Go to *Point of Sale > Configuration > Loyalty Programs* and define a new loyalty program with specific rules and gifts.
* Assign the loyalty program to the desired Point of Sale.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/{repo_id}/{branch}
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/{project_repo}/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smash it by providing detailed and welcomed feedback.
Credits
=======
Contributors
------------
* RGB Consulting SL (http://www.rgbconsulting.com)
* Forward-port from Odoo SA saas-6 branch
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit https://odoo-community.org.

4
pos_loyalty/__init__.py

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import models

33
pos_loyalty/__manifest__.py

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# Copyright 2004-2010 OpenERP SA
# Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Loyalty Program',
'version': '10.0.1.0.0',
'category': 'Point of Sale',
'license': 'AGPL-3',
'author': "OpenERP SA, "
"RGB Consulting SL, "
"Odoo Community Association (OCA)",
'website': "https://odoo-community.org/",
'depends': ['point_of_sale'],
'data': [
'security/ir.model.access.csv',
'views/templates.xml',
'views/loyalty_program_view.xml',
'views/loyalty_reward_view.xml',
'views/loyalty_rule_view.xml',
'views/pos_config_view.xml',
'views/pos_order_view.xml',
'views/res_partner_view.xml',
],
'qweb': [
'static/src/xml/pos.xml',
],
'installable': True,
}

467
pos_loyalty/i18n/es.po

@ -0,0 +1,467 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * pos_loyalty
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 10.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-23 06:36+0000\n"
"PO-Revision-Date: 2017-06-23 06:36+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_order
msgid "Amount of loyalty points given to the customer for each point of sale order"
msgstr "Cantidad de puntos de fidelidad añadidos al cliente por cada pedido del punto de venta"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_product
msgid "Amount of loyalty points given to the customer per product sold"
msgstr "Cantidad de puntos de fidelidad añadidos al cliente por producto vendido"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_currency
msgid "Amount of loyalty points given to the customer per sold currency"
msgstr "Cantidad de puntos de fidelidad añadidos al cliente por moneda vendida"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_currency
msgid "Amount of points earned per currency"
msgstr "Cantidad de puntos ganados por moneda"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_product
msgid "Amount of points earned per product"
msgstr "Cantidad de puntos ganados por producto"
#. module: pos_loyalty
#: selection:loyalty.rule,type:0
msgid "Category"
msgstr "Categoría"
#. module: pos_loyalty
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action
msgid "Click create to define a Loyalty Program."
msgstr "Haga clic en crear para definir un Programa de Fidelización"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_cost
msgid "Cost of the reward per monetary unit discounted"
msgstr "Coste de la recompensa por unidad monetaria descontada"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_uid
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_uid
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_uid
msgid "Created by"
msgstr "Creado por"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_date
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_date
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_date
msgid "Created on"
msgstr "Creado el"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_cumulative
msgid "Cumulative"
msgstr "Cumulativo"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount
#: selection:loyalty.reward,type:0
msgid "Discount"
msgstr "Descuento"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_product_id
msgid "Discount Product"
msgstr "Producto de descuento"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_max
msgid "Discount limit"
msgstr "Límite de descuento"
#. module: pos_loyalty
#: code:addons/pos_loyalty/models/loyalty_reward.py:59
#, python-format
msgid "Discount product field is mandatory for discount rewards"
msgstr "El campo Producto de descuento es obligatorio para las recompensas de tipo descuento."
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_display_name
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_display_name
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_display_name
msgid "Display Name"
msgstr "Nombre a mostrar"
#. module: pos_loyalty
#: selection:loyalty.reward,type:0
msgid "Gift"
msgstr "Regalo"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_gift_product_id
msgid "Gift Product"
msgstr "Producto de regalo"
#. module: pos_loyalty
#: code:addons/pos_loyalty/models/loyalty_reward.py:52
#, python-format
msgid "Gift product field is mandatory for gift rewards"
msgstr "El campo Producto de regalo es obligatorio para las recompensas de tipo regalo"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_id
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_id
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_id
msgid "ID"
msgstr "ID"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program___last_update
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward___last_update
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule___last_update
msgid "Last Modified on"
msgstr "Última modificación en"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_uid
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_uid
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_uid
msgid "Last Updated by"
msgstr "Última actualización por"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_date
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_date
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_date
msgid "Last Updated on"
msgstr "Última actualización el"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_order_loyalty_points
#: model:ir.model.fields,field_description:pos_loyalty.field_res_partner_loyalty_points
#: model:ir.model.fields,field_description:pos_loyalty.field_res_users_loyalty_points
msgid "Loyalty Points"
msgstr "Puntos de fidelidad"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_loyalty_program_id
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_loyalty_program_id
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_config_loyalty_id
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_form_view
msgid "Loyalty Program"
msgstr "Programa de fidelización"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_name
msgid "Loyalty Program Name"
msgstr "Nombre programa de fidelización"
#. module: pos_loyalty
#: model:ir.actions.act_window,name:pos_loyalty.loyalty_program_action
#: model:ir.ui.menu,name:pos_loyalty.loyalty_program_menu
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_tree_view
#: model:ir.ui.view,arch_db:pos_loyalty.partner_property_form_view
#: model:ir.ui.view,arch_db:pos_loyalty.pos_order_form_view
msgid "Loyalty Programs"
msgstr "Programas de fidelización"
#. module: pos_loyalty
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action
msgid "Loyalty Programs allow you customers to earn points\n"
" and rewards when purchasing from your shops."
msgstr "Los programas de fidelización le permiten a los clientes ganar puntos\n"
" y recompensas al comprar en tus tiendas."
#. module: pos_loyalty
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_reward_form_view
msgid "Loyalty Reward"
msgstr "Recompensa de fidelización"
#. module: pos_loyalty
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_rule_form_view
msgid "Loyalty Rule"
msgstr "Regla de fidelización"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_rounding
msgid "Loyalty point amounts will be rounded to multiples of this value"
msgstr "Los puntos de fidelidad se redondearán a múltiplos de este valor"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_max
msgid "Maximum discounted amount allowed for this discount reward"
msgstr "Importe máximo de descuento permitido para este descuento"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_minimum_points
msgid "Minimum Points"
msgstr "Puntos mínimos"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_minimum_points
msgid "Minimum amount of points the customer must have to qualify for this reward"
msgstr "Cantidad mínima de puntos de cliente para acceder a esta recompensa"
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/js/pos.js:365
#, python-format
msgid "No Rewards Available"
msgstr "No hay recompensas disponibles"
#. module: pos_loyalty
#: model:ir.model,name:pos_loyalty.model_res_partner
msgid "Partner"
msgstr "Empresa"
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/js/pos.js:381
#, python-format
msgid "Please select a reward"
msgstr "Selecciona una recompensa"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_cost
msgid "Point Cost"
msgstr "Coste Puntos"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_product_id
msgid "Point Product"
msgstr "Producto Punto"
#. module: pos_loyalty
#: model:ir.model,name:pos_loyalty.model_pos_order
msgid "Point of Sale Orders"
msgstr "Pedidos del TPV"
#. module: pos_loyalty
#: code:addons/pos_loyalty/models/loyalty_reward.py:67
#, python-format
msgid "Point product field is mandatory for point resale rewards"
msgstr "El campo Producto Punto es obligatorio para recompensas de reventa de puntos"
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/xml/pos.xml:6
#: code:addons/pos_loyalty/static/src/xml/pos.xml:71
#: code:addons/pos_loyalty/static/src/xml/pos.xml:81
#, python-format
msgid "Points"
msgstr "Puntos"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rounding
msgid "Points Rounding"
msgstr "Redondeo Puntos"
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/xml/pos.xml:57
#, python-format
msgid "Points Spent"
msgstr "Puntos Gastados"
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/xml/pos.xml:54
#, python-format
msgid "Points Won"
msgstr "Puntos Ganados"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_currency
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_currency
msgid "Points per currency"
msgstr "Puntos por moneda"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_order
msgid "Points per order"
msgstr "Points per order"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_product
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_product
msgid "Points per product"
msgstr "Puntos por producto"
#. module: pos_loyalty
#: selection:loyalty.rule,type:0
msgid "Product"
msgstr "Producto"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_product_id
msgid "Product that represents a point that is sold by the customer"
msgstr "Producto que representa un punto vendido por el cliente"
#. module: pos_loyalty
#: selection:loyalty.reward,type:0
msgid "Resale"
msgstr "Reventa"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_name
msgid "Reward Name"
msgstr "Nombre recompensa"
#. module: pos_loyalty
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view
msgid "Reward the customer with gifts or discounts for loyalty points"
msgstr "Recompensar al cliente con regalos o descuentos por puntos de fidelidad"
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/xml/pos.xml:25
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_reward_ids
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view
#, python-format
msgid "Rewards"
msgstr "Recompensas"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_name
msgid "Rule Name"
msgstr "Nombre de regla"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rule_ids
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view
msgid "Rules"
msgstr "Reglas"
#. module: pos_loyalty
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view
msgid "Rules define how loyalty points are earned for specific products or categories"
msgstr "Las reglas definen cómo se obtienen puntos de fidelidad para productos o categorías específicos"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_category_id
msgid "Target Category"
msgstr "Categoría afectada"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_product_id
msgid "Target Product"
msgstr "Producto afectado"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_loyalty_program_id
msgid "The Loyalty Program this reward belongs to"
msgstr "El programa de fidelización al que pertenece esta recompensa"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_loyalty_program_id
msgid "The Loyalty Program this rule belongs to"
msgstr "El programa de fidelización al que pertenece esta regla"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_pos_order_loyalty_points
msgid "The amount of Loyalty points awarded to the customer with this order"
msgstr "La cantidad de puntos de fidelidad que el cliente obtiene con este pedido"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_category_id
msgid "The category affected by this rule"
msgstr "La categoría afectada por esta regla"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_type
msgid "The concept this rule applies to"
msgstr "El concepto al que aplica esta regla"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount
msgid "The discount percentage"
msgstr "El porcentaje de descuento"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_res_partner_loyalty_points
#: model:ir.model.fields,help:pos_loyalty.field_res_users_loyalty_points
msgid "The loyalty points the user won as part of a Loyalty Program"
msgstr "Los puntos de fidelidad que el usuario ganó como parte de un Programa de Fidelización"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_pos_config_loyalty_id
msgid "The loyalty program used by this Point of Sale"
msgstr "El programa de fidelización utilizado en este Punto de Venta"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_cumulative
msgid "The points from this rule will be added to points won from other rules with the same concept"
msgstr "Los puntos de esta regla se añadirán a los puntos ganados en otras reglas con el mismo concepto"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_product_id
msgid "The product affected by this rule"
msgstr "El producto afectado por esta regla"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_gift_product_id
msgid "The product given as a reward"
msgstr "El producto utilizado como recompensa"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_product_id
msgid "The product used to apply discounts"
msgstr "El producto utilizado para aplicar descuentos"
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/js/pos.js:366
#, python-format
msgid "There are no rewards available for this customer as part of the loyalty program"
msgstr "No hay recompensas disponibles para este cliente como parte de este programa de fidelización"
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/xml/pos.xml:60
#, python-format
msgid "Total Points"
msgstr "Total Puntos"
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_type
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_type
msgid "Type"
msgstr "Tipo"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_type
msgid "Type of the reward"
msgstr "Tipo de recompensa"
#. module: pos_loyalty
#: model:ir.model,name:pos_loyalty.model_loyalty_program
msgid "loyalty.program"
msgstr "loyalty.program"
#. module: pos_loyalty
#: model:ir.model,name:pos_loyalty.model_loyalty_reward
msgid "loyalty.reward"
msgstr "loyalty.reward"
#. module: pos_loyalty
#: model:ir.model,name:pos_loyalty.model_loyalty_rule
msgid "loyalty.rule"
msgstr "loyalty.rule"
#. module: pos_loyalty
#: model:ir.model,name:pos_loyalty.model_pos_config
msgid "pos.config"
msgstr "Configuración del TPV"

466
pos_loyalty/i18n/pos_loyalty.pot

@ -0,0 +1,466 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * pos_loyalty
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 10.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-23 06:35+0000\n"
"PO-Revision-Date: 2017-06-23 06:35+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_order
msgid "Amount of loyalty points given to the customer for each point of sale order"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_product
msgid "Amount of loyalty points given to the customer per product sold"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_pp_currency
msgid "Amount of loyalty points given to the customer per sold currency"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_currency
msgid "Amount of points earned per currency"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_pp_product
msgid "Amount of points earned per product"
msgstr ""
#. module: pos_loyalty
#: selection:loyalty.rule,type:0
msgid "Category"
msgstr ""
#. module: pos_loyalty
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action
msgid "Click create to define a Loyalty Program."
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_cost
msgid "Cost of the reward per monetary unit discounted"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_uid
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_uid
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_uid
msgid "Created by"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_create_date
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_create_date
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_create_date
msgid "Created on"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_cumulative
msgid "Cumulative"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount
#: selection:loyalty.reward,type:0
msgid "Discount"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_product_id
msgid "Discount Product"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_discount_max
msgid "Discount limit"
msgstr ""
#. module: pos_loyalty
#: code:addons/pos_loyalty/models/loyalty_reward.py:59
#, python-format
msgid "Discount product field is mandatory for discount rewards"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_display_name
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_display_name
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_display_name
msgid "Display Name"
msgstr ""
#. module: pos_loyalty
#: selection:loyalty.reward,type:0
msgid "Gift"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_gift_product_id
msgid "Gift Product"
msgstr ""
#. module: pos_loyalty
#: code:addons/pos_loyalty/models/loyalty_reward.py:52
#, python-format
msgid "Gift product field is mandatory for gift rewards"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_id
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_id
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_id
msgid "ID"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program___last_update
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward___last_update
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule___last_update
msgid "Last Modified on"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_uid
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_uid
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_uid
msgid "Last Updated by"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_write_date
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_write_date
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_write_date
msgid "Last Updated on"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_order_loyalty_points
#: model:ir.model.fields,field_description:pos_loyalty.field_res_partner_loyalty_points
#: model:ir.model.fields,field_description:pos_loyalty.field_res_users_loyalty_points
msgid "Loyalty Points"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_loyalty_program_id
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_loyalty_program_id
#: model:ir.model.fields,field_description:pos_loyalty.field_pos_config_loyalty_id
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view
#: model:ir.ui.view,arch_db:pos_loyalty.pos_config_form_view
msgid "Loyalty Program"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_name
msgid "Loyalty Program Name"
msgstr ""
#. module: pos_loyalty
#: model:ir.actions.act_window,name:pos_loyalty.loyalty_program_action
#: model:ir.ui.menu,name:pos_loyalty.loyalty_program_menu
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_tree_view
#: model:ir.ui.view,arch_db:pos_loyalty.partner_property_form_view
#: model:ir.ui.view,arch_db:pos_loyalty.pos_order_form_view
msgid "Loyalty Programs"
msgstr ""
#. module: pos_loyalty
#: model:ir.actions.act_window,help:pos_loyalty.loyalty_program_action
msgid "Loyalty Programs allow you customers to earn points\n"
" and rewards when purchasing from your shops."
msgstr ""
#. module: pos_loyalty
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_reward_form_view
msgid "Loyalty Reward"
msgstr ""
#. module: pos_loyalty
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_rule_form_view
msgid "Loyalty Rule"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_program_rounding
msgid "Loyalty point amounts will be rounded to multiples of this value"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_max
msgid "Maximum discounted amount allowed for this discount reward"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_minimum_points
msgid "Minimum Points"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_minimum_points
msgid "Minimum amount of points the customermust have to qualify for this reward"
msgstr ""
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/js/pos.js:365
#, python-format
msgid "No Rewards Available"
msgstr ""
#. module: pos_loyalty
#: model:ir.model,name:pos_loyalty.model_res_partner
msgid "Partner"
msgstr ""
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/js/pos.js:381
#, python-format
msgid "Please select a reward"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_cost
msgid "Point Cost"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_point_product_id
msgid "Point Product"
msgstr ""
#. module: pos_loyalty
#: model:ir.model,name:pos_loyalty.model_pos_order
msgid "Point of Sale Orders"
msgstr ""
#. module: pos_loyalty
#: code:addons/pos_loyalty/models/loyalty_reward.py:67
#, python-format
msgid "Point product field is mandatory for point resale rewards"
msgstr ""
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/xml/pos.xml:6
#: code:addons/pos_loyalty/static/src/xml/pos.xml:71
#: code:addons/pos_loyalty/static/src/xml/pos.xml:81
#, python-format
msgid "Points"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rounding
msgid "Points Rounding"
msgstr ""
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/xml/pos.xml:57
#, python-format
msgid "Points Spent"
msgstr ""
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/xml/pos.xml:54
#, python-format
msgid "Points Won"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_currency
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_currency
msgid "Points per currency"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_order
msgid "Points per order"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_pp_product
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_pp_product
msgid "Points per product"
msgstr ""
#. module: pos_loyalty
#: selection:loyalty.rule,type:0
msgid "Product"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_point_product_id
msgid "Product that represents a point that is sold by the customer"
msgstr ""
#. module: pos_loyalty
#: selection:loyalty.reward,type:0
msgid "Resale"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_name
msgid "Reward Name"
msgstr ""
#. module: pos_loyalty
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view
msgid "Reward the customer with gifts or discounts for loyalty points"
msgstr ""
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/xml/pos.xml:25
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_reward_ids
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view
#, python-format
msgid "Rewards"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_name
msgid "Rule Name"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_program_rule_ids
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view
msgid "Rules"
msgstr ""
#. module: pos_loyalty
#: model:ir.ui.view,arch_db:pos_loyalty.loyalty_program_form_view
msgid "Rules define how loyalty points are earned for specific products or categories"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_category_id
msgid "Target Category"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_product_id
msgid "Target Product"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_loyalty_program_id
msgid "The Loyalty Program this reward belongs to"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_loyalty_program_id
msgid "The Loyalty Program this rule belongs to"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_pos_order_loyalty_points
msgid "The amount of Loyalty points awarded to the customer with this order"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_category_id
msgid "The category affected by this rule"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_type
msgid "The concept this rule applies to"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount
msgid "The discount percentage"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_res_partner_loyalty_points
#: model:ir.model.fields,help:pos_loyalty.field_res_users_loyalty_points
msgid "The loyalty points the user won as part of a Loyalty Program"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_pos_config_loyalty_id
msgid "The loyalty program used by this Point of Sale"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_cumulative
msgid "The points from this rule will be added to points won from other rules with the same concept"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_rule_product_id
msgid "The product affected by this rule"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_gift_product_id
msgid "The product given as a reward"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_discount_product_id
msgid "The product used to apply discounts"
msgstr ""
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/js/pos.js:366
#, python-format
msgid "There are no rewards available for this customer as part of the loyalty program"
msgstr ""
#. module: pos_loyalty
#. openerp-web
#: code:addons/pos_loyalty/static/src/xml/pos.xml:60
#, python-format
msgid "Total Points"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_reward_type
#: model:ir.model.fields,field_description:pos_loyalty.field_loyalty_rule_type
msgid "Type"
msgstr ""
#. module: pos_loyalty
#: model:ir.model.fields,help:pos_loyalty.field_loyalty_reward_type
msgid "Type of the reward"
msgstr ""
#. module: pos_loyalty
#: model:ir.model,name:pos_loyalty.model_loyalty_program
msgid "loyalty.program"
msgstr ""
#. module: pos_loyalty
#: model:ir.model,name:pos_loyalty.model_loyalty_reward
msgid "loyalty.reward"
msgstr ""
#. module: pos_loyalty
#: model:ir.model,name:pos_loyalty.model_loyalty_rule
msgid "loyalty.rule"
msgstr ""
#. module: pos_loyalty
#: model:ir.model,name:pos_loyalty.model_pos_config
msgid "pos.config"
msgstr ""

9
pos_loyalty/models/__init__.py

@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import loyalty_program
from . import loyalty_reward
from . import loyalty_rule
from . import pos_config
from . import pos_order
from . import res_partner

31
pos_loyalty/models/loyalty_program.py

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Copyright 2004-2010 OpenERP SA
# Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class LoyaltyProgram(models.Model):
_name = 'loyalty.program'
name = fields.Char(string='Loyalty Program Name', size=32, index=True,
required=True)
pp_currency = fields.Float(string='Points per currency',
help='Amount of loyalty points given to the '
'customer per sold currency')
pp_product = fields.Float(string='Points per product',
help='Amount of loyalty points given to the '
'customer per product sold')
pp_order = fields.Float(string='Points per order',
help='Amount of loyalty points given to the '
'customer for each point of sale order')
rounding = fields.Float(string='Points Rounding', default=1,
help='Loyalty point amounts will be rounded to '
'multiples of this value')
rule_ids = fields.One2many(comodel_name='loyalty.rule',
inverse_name='loyalty_program_id',
string='Rules')
reward_ids = fields.One2many(comodel_name='loyalty.reward',
inverse_name='loyalty_program_id',
string='Rewards')

68
pos_loyalty/models/loyalty_reward.py

@ -0,0 +1,68 @@
# -*- coding: utf-8 -*-
# Copyright 2004-2010 OpenERP SA
# Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models, api, _
from odoo.exceptions import ValidationError
class LoyaltyReward(models.Model):
_name = 'loyalty.reward'
name = fields.Char(string='Reward Name', size=32, index=True,
required=True)
type = fields.Selection(selection=[('gift', 'Gift'),
('discount', 'Discount'),
('resale', 'Resale')],
string='Type', required=True,
help='Type of the reward')
minimum_points = fields.Float(string='Minimum Points',
help='Minimum amount of points the customer'
' must have to qualify for this reward')
point_cost = fields.Float(string='Point Cost',
help='Cost of the reward per monetary unit '
'discounted')
discount = fields.Float(help='The discount percentage')
discount_max = fields.Float(string='Discount limit',
help='Maximum discounted amount allowed for'
'this discount reward')
loyalty_program_id = fields.Many2one(comodel_name='loyalty.program',
string='Loyalty Program',
help='The Loyalty Program this reward'
' belongs to')
gift_product_id = fields.Many2one(comodel_name='product.product',
string='Gift Product',
help='The product given as a reward')
discount_product_id = fields.Many2one(comodel_name='product.product',
string='Discount Product',
help='The product used to apply '
'discounts')
point_product_id = fields.Many2one(comodel_name='product.product',
string='Point Product',
help='Product that represents a point '
'that is sold by the customer')
@api.multi
@api.constrains('type', 'gift_product_id')
def _check_gift_product(self):
for reward in self:
if reward.type == 'gift' and not reward.gift_product_id:
raise ValidationError(
_('Gift product field is mandatory for gift rewards'))
@api.multi
@api.constrains('type', 'discount_product_id')
def _check_discount_product(self):
for reward in self:
if reward.type == 'discount' and not reward.discount_product_id:
raise ValidationError(_('Discount product field is '
'mandatory for discount rewards'))
@api.multi
@api.constrains('type', 'point_product_id')
def _check_point_product(self):
for reward in self:
if reward.type == 'resale' and not reward.point_product_id:
raise ValidationError(_('Point product field is '
'mandatory for point resale rewards'))

33
pos_loyalty/models/loyalty_rule.py

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# Copyright 2004-2010 OpenERP SA
# Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class LoyaltyRule(models.Model):
_name = 'loyalty.rule'
name = fields.Char(string='Rule Name', size=32, index=True, required=True)
type = fields.Selection(selection=[('product', 'Product'),
('category', 'Category')],
string='Type', required=True, default='product',
help='The concept this rule applies to')
cumulative = fields.Boolean(help='The points from this rule will be added '
'to points won from other rules with '
'the same concept')
pp_product = fields.Float(string='Points per product',
help='Amount of points earned per product')
pp_currency = fields.Float(string='Points per currency',
help='Amount of points earned per currency')
loyalty_program_id = fields.Many2one(comodel_name='loyalty.program',
string='Loyalty Program',
help='The Loyalty Program this rule '
'belongs to')
product_id = fields.Many2one(comodel_name='product.product',
string='Target Product',
help='The product affected by this rule')
category_id = fields.Many2one(comodel_name='pos.category',
string='Target Category',
help='The category affected by this rule')

15
pos_loyalty/models/pos_config.py

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# Copyright 2004-2010 OpenERP SA
# Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class PosConfig(models.Model):
_inherit = 'pos.config'
loyalty_id = fields.Many2one(comodel_name='loyalty.program',
string='Loyalty Program',
help='The loyalty program used by this '
'Point of Sale')

31
pos_loyalty/models/pos_order.py

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Copyright 2004-2010 OpenERP SA
# Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models, api
class PosOrder(models.Model):
_inherit = 'pos.order'
loyalty_points = fields.Float(string='Loyalty Points',
help='The amount of Loyalty points awarded '
'to the customer with this order')
@api.model
def _order_fields(self, ui_order):
res = super(PosOrder, self)._order_fields(ui_order)
res['loyalty_points'] = ui_order.get('loyalty_points', 0)
return res
@api.model
def create_from_ui(self, orders):
res = super(PosOrder, self).create_from_ui(orders)
for order in orders:
order_partner = order['data']['partner_id']
order_points = order['data']['loyalty_points']
if order_points != 0 and order_partner:
partner = self.env['res.partner'].browse(order_partner)
partner.loyalty_points += order_points
return res

14
pos_loyalty/models/res_partner.py

@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
# Copyright 2004-2010 OpenERP SA
# Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class ResPartner(models.Model):
_inherit = 'res.partner'
loyalty_points = fields.Float(string='Loyalty Points',
help='The loyalty points the user won as '
'part of a Loyalty Program')

7
pos_loyalty/security/ir.model.access.csv

@ -0,0 +1,7 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_loyalty_program,loyalty.program.user,model_loyalty_program,point_of_sale.group_pos_user,1,0,0,0
access_loyalty_program_manager,loyalty.program.manager,model_loyalty_program,point_of_sale.group_pos_manager,1,1,1,1
access_loyalty_rule,loyalty.rule.user,model_loyalty_rule,point_of_sale.group_pos_user,1,0,0,0
access_loyalty_rule_manager,loyalty.rule.manager,model_loyalty_rule,point_of_sale.group_pos_manager,1,1,1,1
access_loyalty_reward,loyalty.reward.user,model_loyalty_reward,point_of_sale.group_pos_user,1,0,0,0
access_loyalty_reward_manager,loyalty.reward.manager,model_loyalty_reward,point_of_sale.group_pos_manager,1,1,1,1

21
pos_loyalty/static/src/css/pos.css

@ -0,0 +1,21 @@
.pos .order .summary .loyalty-points{
margin-left: 20px;
float: left;
padding: 10px;
max-width: 216px;
text-align: left;
color: #6EC89B;
background: rgba(110, 200, 155, 0.17);
border-radius: 3px;
}
.pos .order .summary .loyalty-points.negative{
color: #C86E6E;
background: rgba(200, 110, 110, 0.17);
}
.pos .order .summary .loyalty-points-total {
border-top: solid 2px;
text-align: center;
padding-top: 4px;
margin-top: 4px;
}

453
pos_loyalty/static/src/js/pos.js

@ -0,0 +1,453 @@
/* Copyright 2004-2010 OpenERP SA
* Copyright 2017 RGB Consulting S.L. (https://www.rgbconsulting.com)
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
odoo.define('pos_loyalty.loyalty_program', function (require){
"use strict"
var models = require('point_of_sale.models');
var screens = require('point_of_sale.screens');
var utils = require('web.utils');
var round_pr = utils.round_precision;
var core = require('web.core');
var QWeb = core.qweb;
var _t = core._t;
models.load_fields('res.partner','loyalty_points');
models.load_models([
{
model: 'loyalty.program',
condition: function(self){ return !!self.config.loyalty_id[0]; },
fields: ['name','pp_currency','pp_product','pp_order','rounding'],
domain: function(self){ return [['id','=',self.config.loyalty_id[0]]]; },
loaded: function(self,loyalties){
self.loyalty = loyalties[0];
},
},{
model: 'loyalty.rule',
condition: function(self){ return !!self.loyalty; },
fields: ['name','type','product_id','category_id','cumulative','pp_product','pp_currency'],
domain: function(self){ return [['loyalty_program_id','=',self.loyalty.id]]; },
loaded: function(self,rules){
self.loyalty.rules = rules;
self.loyalty.rules_by_product_id = {};
self.loyalty.rules_by_category_id = {};
function update_rules(rules, rule, id) {
if (!rules[id]){
rules[id] = [rule];
} else if (rule.cumulative){
rules[id].unshift(rule);
} else {
rules[id].push(rule);
}
}
_.each(rules, function(rule) {
if (rule.type === 'product')
update_rules(self.loyalty.rules_by_product_id, rule, rule.product_id[0])
else if (rule.type === 'category')
update_rules(self.loyalty.rules_by_category_id, rule, rule.category_id[0]);
});
},
},{
model: 'loyalty.reward',
condition: function(self){ return !!self.loyalty; },
fields: ['name','type','minimum_points','gift_product_id','point_cost','discount_product_id','discount','discount_max','point_product_id'],
domain: function(self){ return [['loyalty_program_id','=',self.loyalty.id]]; },
loaded: function(self,rewards){
self.loyalty.rewards = rewards;
self.loyalty.rewards_by_id = {};
for (var i = 0; i < rewards.length;i++) {
self.loyalty.rewards_by_id[rewards[i].id] = rewards[i];
}
},
},
],{'after': 'product.product'});
var _orderline_super = models.Orderline.prototype;
models.Orderline = models.Orderline.extend({
get_reward: function(){
return this.pos.loyalty.rewards_by_id[this.reward_id];
},
set_reward: function(reward){
this.reward_id = reward.id;
},
export_as_JSON: function(){
var json = _orderline_super.export_as_JSON.apply(this, arguments);
json.reward_id = this.reward_id;
return json;
},
init_from_JSON: function(json){
_orderline_super.init_from_JSON.apply(this, arguments);
this.reward_id = json.reward_id;
},
});
var _order_super = models.Order.prototype;
models.Order = models.Order.extend({
/* The total of points won, excluding the points spent on rewards */
get_won_points: function(){
if (!this.pos.loyalty || !this.get_client()) {
return 0;
}
var orderLines = this.get_orderlines();
var rounding = this.pos.loyalty.rounding;
var product_sold = 0;
var total_sold = 0;
var total_points = 0;
for (var i = 0; i < orderLines.length; i++) {
var line = orderLines[i];
var product = line.get_product();
var rules = this.pos.loyalty.rules_by_product_id[product.id] || [];
var overriden = false;
if (line.get_reward()) { // Reward products are ignored
continue;
}
for (var j = 0; j < rules.length; j++) {
var rule = rules[j];
total_points += round_pr(line.get_quantity() * rule.pp_product, rounding);
total_points += round_pr(line.get_price_with_tax() * rule.pp_currency, rounding);
// if affected by a non cumulative rule, skip the others. (non cumulative rules are put
// at the beginning of the list when they are loaded )
if (!rule.cumulative) {
overriden = true;
break;
}
}
// Test the category rules
if ( product.pos_categ_id ) {
var category = this.pos.db.get_category_by_id(product.pos_categ_id[0]);
while (category && !overriden) {
var rules = this.pos.loyalty.rules_by_category_id[category.id] || [];
for (var j = 0; j < rules.length; j++) {
var rule = rules[j];
total_points += round_pr(line.get_quantity() * rule.pp_product, rounding);
total_points += round_pr(line.get_price_with_tax() * rule.pp_currency, rounding);
if (!rule.cumulative) {
overriden = true;
break;
}
}
var _category = category;
category = this.pos.db.get_category_by_id(this.pos.db.get_category_parent_id(category.id));
if (_category === category) {
break;
}
}
}
if (!overriden) {
product_sold += line.get_quantity();
total_sold += line.get_price_with_tax();
}
}
total_points += round_pr( total_sold * this.pos.loyalty.pp_currency, rounding );
total_points += round_pr( product_sold * this.pos.loyalty.pp_product, rounding );
total_points += round_pr( this.pos.loyalty.pp_order, rounding );
return total_points;
},
/* The total number of points spent on rewards */
get_spent_points: function() {
if (!this.pos.loyalty || !this.get_client()) {
return 0;
} else {
var lines = this.get_orderlines();
var rounding = this.pos.loyalty.rounding;
var points = 0;
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
var reward = line.get_reward();
if (reward) {
if (reward.type === 'gift') {
points += round_pr(line.get_quantity() * reward.point_cost, rounding);
} else if (reward.type === 'discount') {
points += reward.point_cost;
} else if (reward.type === 'resale') {
points += (-line.get_quantity());
}
}
}
return points;
}
},
/* The total number of points lost or won after the order is validated */
get_new_points: function() {
if (!this.pos.loyalty || !this.get_client()) {
return 0;
} else {
return round_pr(this.get_won_points() - this.get_spent_points(), this.pos.loyalty.rounding);
}
},
/* The total number of points that the customer will have after this order is validated */
get_new_total_points: function() {
if (!this.pos.loyalty || !this.get_client()) {
return 0;
} else {
return round_pr(this.get_client().loyalty_points + this.get_new_points(), this.pos.loyalty.rounding);
}
},
/* The number of loyalty points currently owned by the customer */
get_current_points: function(){
return this.get_client() ? this.get_client().loyalty_points : 0;
},
/* The total number of points spendable on rewards */
get_spendable_points: function(){
if (!this.pos.loyalty || !this.get_client()) {
return 0;
} else {
return round_pr(this.get_client().loyalty_points - this.get_spent_points(), this.pos.loyalty.rounding);
}
},
has_discount_reward: function(){
var res = false;
var lines = this.get_orderlines();
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
var reward = line.get_reward();
if (reward && reward.type === 'discount') {
res = true;
break;
}
}
return res;
},
/* The list of rewards that the current customer can get */
get_available_rewards: function(){
var client = this.get_client();
if (!client) {
return [];
}
var rewards = [];
var discount_reward_set = this.has_discount_reward();
for (var i = 0; i < this.pos.loyalty.rewards.length; i++) {
var reward = this.pos.loyalty.rewards[i];
if (reward.minimum_points > this.get_spendable_points()) {
continue;
} else if(reward.type === 'gift' &&
reward.point_cost > this.get_spendable_points()) {
continue;
} else if(reward.type === 'discount' &&
(discount_reward_set || reward.point_cost > this.get_spendable_points())){
continue;
}
rewards.push(reward);
}
return rewards;
},
apply_reward: function(reward){
var client = this.get_client();
if (!client) {
return;
} else if (reward.type === 'gift') {
var product = this.pos.db.get_product_by_id(reward.gift_product_id[0]);
if (!product) {
return;
}
this.add_product(product, {
price: 0,
quantity: 1,
merge: false,
extras: { reward_id: reward.id },
});
} else if (reward.type === 'discount') {
var crounding = this.pos.currency.rounding;
var order_total = this.get_total_with_tax();
var discount = round_pr(order_total * reward.discount,crounding);
var discount_max = reward.discount_max
if (discount_max && discount > discount_max ) {
discount = discount_max;
}
var product = this.pos.db.get_product_by_id(reward.discount_product_id[0]);
if (!product) {
return;
}
this.add_product(product, {
price: -discount,
quantity: 1,
merge: false,
extras: { reward_id: reward.id },
});
} else if (reward.type === 'resale') {
var lrounding = this.pos.loyalty.rounding;
var crounding = this.pos.currency.rounding;
var spendable = this.get_spendable_points();
var order_total = this.get_total_with_tax();
var product = this.pos.db.get_product_by_id(reward.point_product_id[0]);
if (!product) {
return;
}
if ( round_pr( spendable * product.price, crounding ) > order_total ) {
spendable = round_pr( Math.floor(order_total / product.price), lrounding);
}
if ( spendable < 0.00001 ) {
return;
}
this.add_product(product, {
quantity: -spendable,
merge: false,
extras: { reward_id: reward.id },
});
}
},
finalize: function(){
var client = this.get_client();
if ( client ) {
client.loyalty_points = this.get_new_total_points();
this.pos.gui.screen_instances.clientlist.partner_cache.clear_node(client.id);
}
_order_super.finalize.apply(this, arguments);
},
export_for_printing: function(){
var json = _order_super.export_for_printing.apply(this, arguments);
if (this.pos.loyalty && this.get_client()) {
json.loyalty = {
rounding: this.pos.loyalty.rounding || 1,
name: this.pos.loyalty.name,
client: this.get_client().name,
points_won : this.get_won_points(),
points_spent: this.get_spent_points(),
points_total: this.get_new_total_points(),
};
}
return json;
},
export_as_JSON: function(){
var json = _order_super.export_as_JSON.apply(this, arguments);
json.loyalty_points = this.get_new_points();
return json;
},
});
var LoyaltyButton = screens.ActionButtonWidget.extend({
template: 'LoyaltyButton',
button_click: function(){
var self = this;
var order = this.pos.get_order();
var client = order.get_client();
if (!client) {
this.gui.show_screen('clientlist');
return;
}
var rewards = order.get_available_rewards();
if (rewards.length === 0) {
this.gui.show_popup('error',{
'title': _t('No Rewards Available'),
'body': _t('There are no rewards available for this customer as part of the loyalty program'),
});
} else if (rewards.length === 1 && this.pos.loyalty.rewards.length === 1) {
order.apply_reward(rewards[0]);
} else {
var list = [];
for (var i = 0; i < rewards.length; i++) {
list.push({
label: rewards[i].name,
item: rewards[i],
});
}
this.gui.show_popup('selection',{
'title': _t('Please select a reward'),
'list': list,
'confirm': function(reward){
order.apply_reward(reward);
},
});
}
},
});
screens.define_action_button({
'name': 'loyalty',
'widget': LoyaltyButton,
'condition': function(){
return this.pos.loyalty && this.pos.loyalty.rewards.length;
},
});
screens.OrderWidget.include({
update_summary: function(){
this._super();
var order = this.pos.get_order();
var $loypoints = $(this.el).find('.summary .loyalty-points');
if(this.pos.loyalty && order.get_client()){
var points_won = order.get_won_points();
var points_spent = order.get_spent_points();
var points_total = order.get_new_total_points();
$loypoints.replaceWith($(QWeb.render('LoyaltyPoints',{
widget: this,
rounding: this.pos.loyalty.rounding,
points_won: points_won,
points_spent: points_spent,
points_total: points_total,
})));
$loypoints = $(this.el).find('.summary .loyalty-points');
$loypoints.removeClass('oe_hidden');
if(points_total < 0){
$loypoints.addClass('negative');
}else{
$loypoints.removeClass('negative');
}
}else{
$loypoints.empty();
$loypoints.addClass('oe_hidden');
}
if (this.pos.loyalty &&
order.get_client() &&
this.getParent().action_buttons &&
this.getParent().action_buttons.loyalty) {
var rewards = order.get_available_rewards();
this.getParent().action_buttons.loyalty.highlight(!!rewards.length);
}
},
});
});

85
pos_loyalty/static/src/xml/pos.xml

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="LoyaltyPoints">
<div class='loyalty-points'>
<div class='loyalty-points-title'>Points</div>
<t t-if='points_won'>
<div class="loyalty-points-won">
<span class='value'>+<t t-esc='widget.format_pr(points_won,rounding)'/></span>
</div>
</t>
<t t-if='points_spent'>
<div class="loyalty-points-spent">
<span class='value'>-<t t-esc='widget.format_pr(points_spent,rounding)'/></span>
</div>
</t>
<div class='loyalty-points-total'>
<span class='value'><t t-esc='widget.format_pr(points_total,rounding)' /></span>
</div>
</div>
</t>
<t t-name="LoyaltyButton">
<div class='control-button'>
<i class='fa fa-star' /> Rewards
</div>
</t>
<t t-extend='OrderWidget'>
<t t-jquery='.summary' t-operation='prepend'>
<div class='loyalty-points oe_hidden'>.</div>
</t>
</t>
<t t-extend='ClientLine'>
<t t-jquery='.client-line' t-operation='append'>
<td>
<t t-esc='widget.format_pr(partner.loyalty_points || 0, widget.pos.loyalty ? widget.pos.loyalty.rounding : 1.0)' />
</td>
</t>
</t>
<t t-extend="XmlReceipt">
<t t-jquery='.before-footer' t-operation='append'>
<t t-if='receipt.loyalty'>
<div class='loyalty' value-decimals='2' value-autoint='on'>
<div>--------------------------------</div>
<br/>
<div size='double-height'><t t-esc='receipt.loyalty.name'/></div>
<br />
<div><t t-esc='receipt.loyalty.client' /></div>
<br/>
<t t-if='receipt.loyalty.points_won'>
<line><left>Points Won</left><right><value><t t-esc='receipt.loyalty.points_won' /></value></right></line>
</t>
<t t-if='receipt.loyalty.points_spent'>
<line><left>Points Spent</left><right><value><t t-esc='receipt.loyalty.points_spent' /></value></right></line>
</t>
<t t-if='receipt.loyalty.points_total'>
<line><left>Total Points</left><right><value><t t-esc='receipt.loyalty.points_total' /></value></right></line>
</t>
<br />
</div>
</t>
</t>
</t>
<t t-extend='ClientDetails'>
<t t-jquery='.client-details-right' t-operation='prepend'>
<div class='client-detail'>
<span class='label'>Points</span>
<span class='detail client-points'>
<t t-esc='widget.format_pr(partner.loyalty_points || 0, widget.pos.loyalty ? widget.pos.loyalty.rounding : 1.0)' />
</span>
</div>
</t>
</t>
<t t-extend='ClientListScreenWidget'>
<t t-jquery='.client-list thead tr' t-operation='append'>
<th>Points</th>
</t>
</t>
</templates>

83
pos_loyalty/views/loyalty_program_view.xml

@ -0,0 +1,83 @@
<?xml version="1.0"?>
<odoo>
<record id="loyalty_program_form_view" model="ir.ui.view">
<field name="name">loyalty.program.form</field>
<field name="model">loyalty.program</field>
<field name="arch" type="xml">
<form string="Loyalty Program">
<sheet>
<div class="oe_title">
<label class="oe_edit_only" for="name"/>
<h1>
<field name="name" class="oe_inline"/>
</h1>
</div>
<group>
<group>
<field name="pp_product"/>
<field name="pp_currency"/>
</group>
<group>
<field name="pp_order"/>
<field name="rounding"/>
</group>
</group>
<separator string="Rules" colspan="4"/>
<p>Rules define how loyalty points are earned for specific products or categories</p>
<field name="rule_ids" colspan="4" nolabel="1">
<tree string="Rules">
<field name="name"/>
<field name="pp_product"/>
<field name="pp_currency"/>
<field name="cumulative"/>
</tree>
</field>
<separator string="Rewards" colspan="4"/>
<p>Reward the customer with gifts or discounts for loyalty points</p>
<field name="reward_ids" colspan="4" nolabel="1">
<tree string="Rewards">
<field name="name"/>
<field name="type"/>
</tree>
</field>
</sheet>
</form>
</field>
</record>
<record id="loyalty_program_tree_view" model="ir.ui.view">
<field name="name">loyalty.program.tree</field>
<field name="model">loyalty.program</field>
<field name="arch" type="xml">
<tree string="Loyalty Programs">
<field name="name"/>
</tree>
</field>
</record>
<record id="loyalty_program_action" model="ir.actions.act_window">
<field name="name">Loyalty Programs</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">loyalty.program</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click create to define a Loyalty Program.
</p>
<p>
Loyalty Programs allow you customers to earn points
and rewards when purchasing from your shops.
</p>
</field>
</record>
<menuitem parent="point_of_sale.menu_point_config_product"
action="loyalty_program_action"
id="loyalty_program_menu"
sequence="30"
groups="point_of_sale.group_pos_manager"/>
</odoo>

37
pos_loyalty/views/loyalty_reward_view.xml

@ -0,0 +1,37 @@
<?xml version="1.0"?>
<odoo>
<record id="loyalty_reward_form_view" model="ir.ui.view">
<field name="name">loyalty.reward.form</field>
<field name="model">loyalty.reward</field>
<field name="arch" type="xml">
<form string="Loyalty Reward">
<div class="oe_title">
<label class="oe_edit_only" for="name"/>
<h1>
<field name="name" class="oe_inline"/>
</h1>
</div>
<group>
<field name="type"/>
</group>
<group >
<field name="gift_product_id"
attrs="{'invisible':[('type','!=','gift')], 'required':[('type','=','gift')]}"/>
<field name="discount"
attrs="{'invisible':[('type','!=','discount')]}"/>
<field name="discount_max"
attrs="{'invisible':[('type','!=','discount')]}"/>
<field name="discount_product_id"
attrs="{'invisible':[('type','!=','discount')], 'required':[('type','=','discount')]}"/>
<field name="point_product_id"
attrs="{'invisible': [('type','!=','resale')], 'required': [('type','=','resale')]}"/>
</group>
<group>
<field name="point_cost"
attrs="{'invisible':[('type','=','resale')]}"/>
<field name="minimum_points"/>
</group>
</form>
</field>
</record>
</odoo>

31
pos_loyalty/views/loyalty_rule_view.xml

@ -0,0 +1,31 @@
<?xml version="1.0"?>
<odoo>
<record id="loyalty_rule_form_view" model="ir.ui.view">
<field name="name">loyalty.rule.form</field>
<field name="model">loyalty.rule</field>
<field name="arch" type="xml">
<form string="Loyalty Rule">
<div class="oe_title">
<label class="oe_edit_only" for="name"/>
<h1>
<field name="name" class="oe_inline"/>
</h1>
</div>
<group>
<group>
<field name="type"/>
</group>
<group>
<field name="product_id" attrs="{'invisible': [('type','!=','product')], 'required': [('type','=','product')]}"/>
<field name="category_id" attrs="{'invisible': [('type','!=','category')], 'required': [('type','=','category')]}"/>
</group>
</group>
<group col="6">
<field name="pp_product"/>
<field name="pp_currency"/>
<field name="cumulative"/>
</group>
</form>
</field>
</record>
</odoo>

15
pos_loyalty/views/pos_config_view.xml

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<odoo>
<record id="pos_config_form_view" model="ir.ui.view">
<field name="name">pos.config.form</field>
<field name="model">pos.config</field>
<field name="inherit_id" ref="point_of_sale.view_pos_config_form"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='receipt']" position="after">
<group string="Loyalty Program" col="4">
<field name="loyalty_id"/>
</group>
</xpath>
</field>
</record>
</odoo>

15
pos_loyalty/views/pos_order_view.xml

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<odoo>
<record id="pos_order_form_view" model="ir.ui.view">
<field name="name">pos.order.form</field>
<field name="model">pos.order</field>
<field name="inherit_id" ref="point_of_sale.view_pos_pos_form"/>
<field name="arch" type="xml">
<xpath expr="//page[@name='extra']" position="inside">
<group name="loyalty" string="Loyalty Programs">
<field name="loyalty_points"/>
</group>
</xpath>
</field>
</record>
</odoo>

15
pos_loyalty/views/res_partner_view.xml

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<odoo>
<record id="partner_property_form_view" model="ir.ui.view">
<field name="name">partner.property.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="point_of_sale.view_partner_property_form"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='point_of_sale']" position="after">
<group name="loyalty" string="Loyalty Programs">
<field name="loyalty_points"/>
</group>
</xpath>
</field>
</record>
</odoo>

9
pos_loyalty/views/templates.xml

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets" inherit_id="point_of_sale.assets">
<xpath expr="." position="inside">
<script type="text/javascript" src="/pos_loyalty/static/src/js/pos.js"></script>
<link rel="stylesheet" href="/pos_loyalty/static/src/css/pos.css"/>
</xpath>
</template>
</odoo>
Loading…
Cancel
Save