From 53fe92b6fa37a542168a8a49d1d6b8bf06b57073 Mon Sep 17 00:00:00 2001 From: KolushovAlexandr Date: Fri, 21 Feb 2020 16:56:12 +0500 Subject: [PATCH 1/4] :zap: new functionality for garazd_loyalty --- garazd_loyalty/__init__.py | 3 + garazd_loyalty/__manifest__.py | 36 +++ garazd_loyalty/i18n/ru.po | 264 ++++++++++++++++++ garazd_loyalty/models/__init__.py | 6 + garazd_loyalty/models/garazd_loyalty.py | 12 + garazd_loyalty/models/pos_config.py | 9 + garazd_loyalty/models/pos_order.py | 14 + garazd_loyalty/models/res_company.py | 9 + garazd_loyalty/models/res_config.py | 27 ++ garazd_loyalty/models/res_partner.py | 103 +++++++ garazd_loyalty/security/ir.model.access.csv | 3 + garazd_loyalty/security/loyalty_security.xml | 9 + garazd_loyalty/static/description/icon.png | Bin 0 -> 6560 bytes garazd_loyalty/static/src/js/pos_partner.js | 147 ++++++++++ garazd_loyalty/static/src/js/screens.js | 96 +++++++ garazd_loyalty/static/src/xml/pos.xml | 16 ++ .../views/garazd_loyalty_templates.xml | 9 + garazd_loyalty/views/garazd_loyalty_views.xml | 28 ++ garazd_loyalty/views/pos_config_views.xml | 28 ++ garazd_loyalty/views/res_config_views.xml | 30 ++ garazd_loyalty/views/res_partner_views.xml | 43 +++ 21 files changed, 892 insertions(+) create mode 100644 garazd_loyalty/__init__.py create mode 100644 garazd_loyalty/__manifest__.py create mode 100644 garazd_loyalty/i18n/ru.po create mode 100644 garazd_loyalty/models/__init__.py create mode 100644 garazd_loyalty/models/garazd_loyalty.py create mode 100644 garazd_loyalty/models/pos_config.py create mode 100644 garazd_loyalty/models/pos_order.py create mode 100644 garazd_loyalty/models/res_company.py create mode 100644 garazd_loyalty/models/res_config.py create mode 100644 garazd_loyalty/models/res_partner.py create mode 100644 garazd_loyalty/security/ir.model.access.csv create mode 100644 garazd_loyalty/security/loyalty_security.xml create mode 100644 garazd_loyalty/static/description/icon.png create mode 100644 garazd_loyalty/static/src/js/pos_partner.js create mode 100644 garazd_loyalty/static/src/js/screens.js create mode 100644 garazd_loyalty/static/src/xml/pos.xml create mode 100644 garazd_loyalty/views/garazd_loyalty_templates.xml create mode 100644 garazd_loyalty/views/garazd_loyalty_views.xml create mode 100644 garazd_loyalty/views/pos_config_views.xml create mode 100644 garazd_loyalty/views/res_config_views.xml create mode 100644 garazd_loyalty/views/res_partner_views.xml diff --git a/garazd_loyalty/__init__.py b/garazd_loyalty/__init__.py new file mode 100644 index 000000000..cde864bae --- /dev/null +++ b/garazd_loyalty/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models diff --git a/garazd_loyalty/__manifest__.py b/garazd_loyalty/__manifest__.py new file mode 100644 index 000000000..379aab821 --- /dev/null +++ b/garazd_loyalty/__manifest__.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2018 Razumovskyi Yurii +# License OPL-1 (https://www.odoo.com/documentation/user/legal/licenses/licenses.html#odoo-apps). + +{ + 'name': 'Garazd Loyalty Program', + 'version': '12.0.1.0.1', + 'category': 'Sales', + 'author': 'Garazd Creation', + 'website': "https://garazd.biz", + 'license': 'OPL-1', + 'summary': """ + Loyalty Program for Sales + """, + 'description': 'Manage Loyalty Program for Customers', + 'depends': [ + 'base', + 'point_of_sale', + ], + 'data': [ + 'security/ir.model.access.csv', + 'security/loyalty_security.xml', + 'views/garazd_loyalty_templates.xml', + 'views/garazd_loyalty_views.xml', + 'views/res_config_views.xml', + 'views/res_partner_views.xml', + 'views/pos_config_views.xml', + ], + 'qweb': [ + 'static/src/xml/pos.xml', + ], + 'application': False, + 'installable': True, + 'auto_install': False, +} diff --git a/garazd_loyalty/i18n/ru.po b/garazd_loyalty/i18n/ru.po new file mode 100644 index 000000000..a0ea470a0 --- /dev/null +++ b/garazd_loyalty/i18n/ru.po @@ -0,0 +1,264 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * garazd_loyalty +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-06-26 14:33+0000\n" +"PO-Revision-Date: 2018-06-26 14:33+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: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_res_partner_amount_before_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_res_users_amount_before_loyalty +msgid "Amount of purchases" +msgstr "Сумма покупок" + +#. module: garazd_loyalty +#: model:ir.model.fields,help:garazd_loyalty.field_res_partner_amount_before_loyalty +#: model:ir.model.fields,help:garazd_loyalty.field_res_users_amount_before_loyalty +msgid "Amount of purchases before using the loyalty system." +msgstr "Сумма покупок до запуска системы лояльности." + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_res_partner_loyalty_date +#: model:ir.model.fields,field_description:garazd_loyalty.field_res_users_loyalty_date +msgid "Card Issued" +msgstr "Дата выдачи карты" + +#. module: garazd_loyalty +#: model:ir.model,name:garazd_loyalty.model_res_company +msgid "Companies" +msgstr "Компании" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_pos_config_settings_company_id +msgid "Company" +msgstr "Компания" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_garazd_loyalty_create_uid +msgid "Created by" +msgstr "Создал" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_garazd_loyalty_create_date +msgid "Created on" +msgstr "Создано" + +#. module: garazd_loyalty +#: model:ir.ui.view,arch_db:garazd_loyalty.view_sale_config_settings_form_pos_inherit_garazd_loyalty +msgid "Customer Loyalty" +msgstr "Система лояльности для покупателей" + +#. module: garazd_loyalty +#: selection:res.partner,loyalty_type:0 +msgid "Customer discount based on purchases amount" +msgstr "Скидка зависит от суммы покупок клиента" + +#. module: garazd_loyalty +#: model:ir.ui.view,arch_db:garazd_loyalty.view_partner_form_inherit_garazd_loyalty +msgid "Determine Loyalty Level" +msgstr "Определить уровень скидок" + +#. module: garazd_loyalty +#. openerp-web +#: code:addons/garazd_loyalty/static/src/xml/pos.xml:6 +#, python-format +msgid "Discount" +msgstr "Скидка" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_garazd_loyalty_percent +msgid "Discount Percent" +msgstr "Процент скидки" + +#. module: garazd_loyalty +#: selection:res.partner,loyalty_type:0 +msgid "Discount not provided" +msgstr "Скидки не предоставляются" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_res_partner_loyalty_discount +#: model:ir.model.fields,field_description:garazd_loyalty.field_res_users_loyalty_discount +msgid "Discount, %" +msgstr "Cкидка, %" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_garazd_loyalty_display_name +msgid "Display Name" +msgstr "Отображаемое имя" + +#. module: garazd_loyalty +#. openerp-web +#: code:addons/garazd_loyalty/static/src/js/screens.js:56 +#, python-format +msgid "Error: Could not Save Changes" +msgstr "Ошибка: Невозможно сохранить изменения" + +#. module: garazd_loyalty +#: selection:res.partner,loyalty_type:0 +msgid "Fixed customer discount" +msgstr "Фиксированная скидка для клиента" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_garazd_loyalty_id +msgid "ID" +msgstr "ID" + +#. module: garazd_loyalty +#. openerp-web +#: code:addons/garazd_loyalty/static/src/js/screens.js:28 +#, python-format +msgid "Issue a card to the client?" +msgstr "Выдать карту клиенту?" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_garazd_loyalty___last_update +msgid "Last Modified on" +msgstr "Последний раз изменено" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_garazd_loyalty_write_uid +msgid "Last Updated by" +msgstr "Последний раз обновил" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_garazd_loyalty_write_date +msgid "Last Updated on" +msgstr "Последний раз обновлено" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_res_partner_loyalty_id +#: model:ir.model.fields,field_description:garazd_loyalty.field_res_users_loyalty_id +msgid "Level" +msgstr "Уровень" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_garazd_loyalty_name +msgid "Level Name" +msgstr "Наименование уровня" + +#. module: garazd_loyalty +#: model:ir.ui.view,arch_db:garazd_loyalty.view_partner_form_inherit_garazd_loyalty +msgid "Loyalty" +msgstr "Лояльность" + +#. module: garazd_loyalty +#: model:ir.ui.view,arch_db:garazd_loyalty.view_partner_form_inherit_garazd_loyalty +msgid "Loyalty Level" +msgstr "Уровень" + +#. module: garazd_loyalty +#: model:ir.actions.act_window,name:garazd_loyalty.action_loyalty_program +#: model:ir.ui.menu,name:garazd_loyalty.menu_garazd_loyalty +msgid "Loyalty Program" +msgstr "Система лояльности" + +#. module: garazd_loyalty +#: model:res.groups,name:garazd_loyalty.loyalty_group_user +msgid "Loyalty System User" +msgstr "Управление системой лояльности" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_res_partner_loyalty_type +#: model:ir.model.fields,field_description:garazd_loyalty.field_res_users_loyalty_type +msgid "Loyalty Type" +msgstr "Тип системы лояльности" + +#. module: garazd_loyalty +#: model:ir.model.fields,help:garazd_loyalty.field_res_partner_loyalty_type +#: model:ir.model.fields,help:garazd_loyalty.field_res_users_loyalty_type +msgid "Loyalty type for customer." +msgstr "Тип системы лояльности." + +#. module: garazd_loyalty +#: model:res.groups,comment:garazd_loyalty.loyalty_group_user +msgid "Management of the Loyalty System" +msgstr "Управление системой лояльности" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_pos_config_settings_loyalty_approval +msgid "Manager approve Loyalty for Customer." +msgstr "Менеджер утверждает тип скидок для клиента." + +#. module: garazd_loyalty +#. openerp-web +#: code:addons/garazd_loyalty/static/src/js/pos_partner.js:188 +#, python-format +msgid "Minimal Purchases Amount" +msgstr "Набрана минимальная сумма для выдачи карты" + +#. module: garazd_loyalty +#: model:ir.model.fields,help:garazd_loyalty.field_pos_config_settings_amount_for_card +msgid "Minimum One-time Purchase Amount for issuing a discount card." +msgstr "Сумма единоразовой покупки для выдачи дисконтной карты." + +#. module: garazd_loyalty +#. openerp-web +#: code:addons/garazd_loyalty/static/src/js/screens.js:27 +#, python-format +msgid "New Discount Card scanned." +msgstr "Просканирована новая карта клиента." + +#. module: garazd_loyalty +#. openerp-web +#: code:addons/garazd_loyalty/static/src/js/pos_partner.js:189 +#, python-format +msgid "Offer the client a discount card." +msgstr "Предложите клиенту дисконтную карту." + +#. module: garazd_loyalty +#: model:ir.model,name:garazd_loyalty.model_res_partner +msgid "Partner" +msgstr "Партнёр" + +#. module: garazd_loyalty +#: model:ir.model,name:garazd_loyalty.model_pos_order +msgid "Point of Sale Orders" +msgstr "Заказы точки продажи" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_pos_config_settings_amount_for_card +#: model:ir.model.fields,field_description:garazd_loyalty.field_res_company_amount_for_card +msgid "Purchase amount" +msgstr "Минимальная сумма для выдачи карты" + +#. module: garazd_loyalty +#: model:ir.model.fields,field_description:garazd_loyalty.field_garazd_loyalty_amount_from +msgid "Purchases from" +msgstr "Сумма покупок от" + +#. module: garazd_loyalty +#: model:ir.ui.view,arch_db:garazd_loyalty.view_res_partner_filter_inherit_garazd_loyalty +msgid "To approve discount" +msgstr "На утверждение скидок" + +#. module: garazd_loyalty +#. openerp-web +#: code:addons/garazd_loyalty/static/src/js/screens.js:50 +#, python-format +msgid "Your Internet connection is probably down." +msgstr "Возможно нет подключения к интернет." + +#. module: garazd_loyalty +#: model:ir.model,name:garazd_loyalty.model_garazd_dashboard +msgid "garazd.dashboard" +msgstr "garazd.dashboard" + +#. module: garazd_loyalty +#: model:ir.model,name:garazd_loyalty.model_garazd_loyalty +msgid "garazd.loyalty" +msgstr "garazd.loyalty" + +#. module: garazd_loyalty +#: model:ir.model,name:garazd_loyalty.model_pos_config_settings +msgid "pos.config.settings" +msgstr "pos.config.settings" diff --git a/garazd_loyalty/models/__init__.py b/garazd_loyalty/models/__init__.py new file mode 100644 index 000000000..a874d3a4e --- /dev/null +++ b/garazd_loyalty/models/__init__.py @@ -0,0 +1,6 @@ +from . import res_partner +from . import res_company +from . import garazd_loyalty +from . import res_config +from . import pos_config +from . import pos_order diff --git a/garazd_loyalty/models/garazd_loyalty.py b/garazd_loyalty/models/garazd_loyalty.py new file mode 100644 index 000000000..254030d1a --- /dev/null +++ b/garazd_loyalty/models/garazd_loyalty.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +from odoo import fields, models + + +class GarazdLoyalty(models.Model): + _name = "garazd.loyalty" + _description = "Loyalty System Levels" + + name = fields.Char('Level Name') + percent = fields.Integer('Discount Percent') + amount_from = fields.Float('Purchases from') diff --git a/garazd_loyalty/models/pos_config.py b/garazd_loyalty/models/pos_config.py new file mode 100644 index 000000000..c80a1f875 --- /dev/null +++ b/garazd_loyalty/models/pos_config.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- + +from odoo import fields, models + + +class PosOrder(models.Model): + _inherit = "pos.config" + + loyalty_card_offer = fields.Boolean('Offer loyalty card', default=True) diff --git a/garazd_loyalty/models/pos_order.py b/garazd_loyalty/models/pos_order.py new file mode 100644 index 000000000..d309306d7 --- /dev/null +++ b/garazd_loyalty/models/pos_order.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- + +from odoo import api, models + + +class PosOrder(models.Model): + _inherit = "pos.order" + + @api.model + def create(self, values): + pos_order = super(PosOrder, self).create(values) + if pos_order.partner_id: + pos_order.partner_id.set_loyalty_level() + return pos_order diff --git a/garazd_loyalty/models/res_company.py b/garazd_loyalty/models/res_company.py new file mode 100644 index 000000000..9ea3e0d88 --- /dev/null +++ b/garazd_loyalty/models/res_company.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- + +from odoo import models, fields + + +class ResCompany(models.Model): + _inherit = "res.company" + + amount_for_card = fields.Float('Purchase amount') diff --git a/garazd_loyalty/models/res_config.py b/garazd_loyalty/models/res_config.py new file mode 100644 index 000000000..06eac7f87 --- /dev/null +++ b/garazd_loyalty/models/res_config.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +from odoo import api, fields, models + + +class BaseConfiguration(models.TransientModel): + _inherit = "res.config.settings" + + company_id = fields.Many2one('res.company', string='Company', required=True, + default=lambda self: self.env.user.company_id) + amount_for_card = fields.Float( + related='company_id.amount_for_card', + string='Purchase amount', + help='Minimum One-time Purchase Amount for issuing a discount card.', + readonly=False, + ) + loyalty_approval = fields.Boolean('Manager approve Loyalty for Customer.') + + @api.model + def get_default_amount_for_card(self, fields): + amount_for_card = self.env.user.company_id.amount_for_card + return {'amount_for_card': float(amount_for_card) or 0.0} + + @api.multi + def set_amount_for_card(self): + for record in self: + self.env.user.company_id.amount_for_card = record.amount_for_card diff --git a/garazd_loyalty/models/res_partner.py b/garazd_loyalty/models/res_partner.py new file mode 100644 index 000000000..da064ee77 --- /dev/null +++ b/garazd_loyalty/models/res_partner.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2018 Razumovskyi Yurii + +from odoo import models, fields, api, _ +from odoo.exceptions import Warning, UserError + + +class GarazdPartner(models.Model): + _inherit = "res.partner" + + loyalty_date = fields.Datetime( + 'Card Issued', + help='The Date of issue Loyalty card.', + ) + loyalty_type = fields.Selection( + [ + ('none', 'Discount not provided'), + ('fixed', 'Fixed customer discount'), + ('purchase', 'Customer discount based on purchases amount') + ], + string='Loyalty Type', + default='none', + help='Loyalty type for customer.', + ) + loyalty_id = fields.Many2one('garazd.loyalty', string='Level') + loyalty_discount = fields.Integer(string='Discount, %') + amount_before_loyalty = fields.Float( + string='Amount of purchases', + help='Amount of purchases before using the loyalty system.', + ) + + @api.model + def create(self, values): + record = super(GarazdPartner, self).create(values) + if record.barcode: + record.loyalty_date = fields.Datetime.now() + return record + + @api.multi + def write(self, vals): + result = False + for partner in self: + prev_barcode = partner.barcode + result = super(GarazdPartner, partner).write(vals) + if not prev_barcode and partner.barcode: + partner.loyalty_date = fields.Datetime.now() + return result + + @api.onchange('amount_before_loyalty') + def _onchange_amount_before_loyalty(self): + self.ensure_one() + if self.loyalty_type == 'purchase': + self.set_loyalty_level() + + @api.depends('loyalty_id') + def _apply_discount(self): + self.filtered(lambda x: x.loyalty_type == 'purchase').set_loyalty_level() + + @api.onchange('loyalty_type') + def _onchange_loyalty_id(self): + self.ensure_one() + if self.loyalty_type == 'none': + self.write({ + 'loyalty_id': None, + 'loyalty_discount': 0.0, + }) + elif self.loyalty_type == 'fixed': + self.write({ + 'loyalty_id': None, + }) + elif self.loyalty_type == 'purchase': + self.set_loyalty_level() + + @api.multi + def get_purchase_amount(self): + total_amount = 0.0 + for partner in self: + pos_sales = sum(pos_sale.amount_total + for pos_sale in self.env['pos.order'].search( + [('partner_id', '=', partner.id), ('state', 'in', ['paid', 'done'])])) + orders = partner.env['pos.order'].search([ + ('partner_id', '=', partner.id), + ('state', 'in', ['paid', 'done']) + ]) + total_amount += pos_sales + partner.amount_before_loyalty + return total_amount + + @api.multi + def set_loyalty_level(self): + for partner in self.filtered(lambda x: x.customer and x.loyalty_type == 'purchase'): + purchase_amount = partner.get_purchase_amount() + loyalty_levels = self.env['garazd.loyalty'].search([], order="amount_from desc") + for level in loyalty_levels: + if purchase_amount >= level.amount_from: + partner.write({ + 'loyalty_id': level.id, + 'loyalty_discount': level.percent, + }) + partner.update({ + 'loyalty_id': level.id, + 'loyalty_discount': level.percent, + }) + break diff --git a/garazd_loyalty/security/ir.model.access.csv b/garazd_loyalty/security/ir.model.access.csv new file mode 100644 index 000000000..f78530350 --- /dev/null +++ b/garazd_loyalty/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_garazd_loyalty_user,Read-Write-Create access on garazd.loyalty to Base User,model_garazd_loyalty,base.group_user,1,1,1,0 +access_garazd_loyalty_admin,Read-Write-Create-Delete access on garazd.loyalty to Admin User,model_garazd_loyalty,base.group_system,1,1,1,1 diff --git a/garazd_loyalty/security/loyalty_security.xml b/garazd_loyalty/security/loyalty_security.xml new file mode 100644 index 000000000..9ce1b1971 --- /dev/null +++ b/garazd_loyalty/security/loyalty_security.xml @@ -0,0 +1,9 @@ + + + + + Loyalty System User + Management of the Loyalty System + + + diff --git a/garazd_loyalty/static/description/icon.png b/garazd_loyalty/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..614894d7f50f088ab58b4ab1a7625fb94b0aa1e5 GIT binary patch literal 6560 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 literal 0 HcmV?d00001 diff --git a/garazd_loyalty/static/src/js/pos_partner.js b/garazd_loyalty/static/src/js/pos_partner.js new file mode 100644 index 000000000..df08f61a2 --- /dev/null +++ b/garazd_loyalty/static/src/js/pos_partner.js @@ -0,0 +1,147 @@ +odoo.define('garazd_loyalty.pos_partner', function(require){ + "use strict"; + + var models = require('point_of_sale.models'); + var gui = require('point_of_sale.gui'); + var rpc = require('web.rpc'); + var core = require('web.core'); + var _t = core._t; + + + models.load_fields('res.partner',['loyalty_id', 'loyalty_discount']); + models.load_fields('res.company',['amount_for_card']); + models.load_fields('pos.config',['loyalty_card_offer']); + models.load_fields('product.product', ['standard_price', 'vendor_id']); + + + var _super_orderline = models.Orderline.prototype; + models.Orderline = models.Orderline.extend({ + initialize: function(attributes, options){ + this.discount = 0; + _super_orderline.initialize.apply(this, arguments); + }, + get_pricelist_item: function (product_tmpl_id) { + var domain = [ + ['product_tmpl_id','=',product_tmpl_id], + ['pricelist_id','=',this.pos.default_pricelist.id], + ]; + return rpc.query({ + model: 'product.pricelist.item', + method: 'search_read', + args: [domain], + }); + }, + set_discount: function(discount){ + var self = this; + var order = this.order; + var partner; + var new_discount = discount; + + + var domain = [ + '|', + ['product_tmpl_id','=',self.product.product_tmpl_id], + ['product_id','=',self.product.id], + ['pricelist_id','=',self.pos.default_pricelist.id], + ]; + return rpc.query({ + model: 'product.pricelist.item', + method: 'search_read', + args: [domain], + }).then(function(items) { + + + var item = null; + if (items instanceof Array && items.length) { + item = items[0]; + } + + + if(order !== null){ + partner = order.get_client(); + } + + if(partner && partner.loyalty_discount) { + if(!item) { + var product = self.product; + new_discount = Math.min(Math.max(parseFloat(partner.loyalty_discount) || 0, 0),100); + if (product.vendor_id) { + var extra = (product.list_price - (product.standard_price || 0)) * 100 / product.list_price; + if (new_discount >= extra) { + new_discount = 0; + } + } + } else { // Skip if Product has special price in default pricelist + new_discount = 0; + } + } + + var disc = Math.min( + Math.max( + parseFloat(new_discount) || 0, + 0 + ), + 100 + ); + self.discount = disc; + self.discountStr = '' + disc; + self.trigger('change',self); + + }); + }, + }); + + + var _super_order = models.Order.prototype; + models.Order = models.Order.extend({ + + initialize: function (session, attributes) { + this.card_offered = false; + return _super_order.initialize.apply(this, arguments); + }, + + set_client: function(client){ + _super_order.set_client.apply(this, arguments); + this.card_offered = false; + var disc = 0.0; + if(client && client.loyalty_discount){ + disc = client.loyalty_discount; + } + this.get_orderlines().forEach(function(line){ + line.set_discount(disc); + }); + }, + + add_product: function(product, options){ + _super_order.add_product.apply(this, arguments); + var line = this.get_last_orderline(); + var partner = this.get_client(); + if(partner && partner.loyalty_discount){ + var discount = partner.loyalty_discount; + if(discount !== undefined){ + line.set_discount(discount); + } + } + }, + + get_total_with_tax: function() { + var total = _super_order.get_total_with_tax.apply(this, arguments); + var client = this.get_client(); + var amount_for_card = this.pos.company.amount_for_card; + if(this.pos.config.loyalty_card_offer == true && this.pos.gui.get_current_screen()) { + if(amount_for_card > 0.0 && total >= amount_for_card && this.card_offered === false && (!client || client && !client.barcode)) { + this.card_offered = true; + this.pos.gui.show_popup('alert',{ + 'title': _t('Minimal Purchases Amount'), + 'body': _t('Offer the client a discount card.'), + }); + } + } + return total; + }, + + }); + + return models; + +}); diff --git a/garazd_loyalty/static/src/js/screens.js b/garazd_loyalty/static/src/js/screens.js new file mode 100644 index 000000000..55f420ad8 --- /dev/null +++ b/garazd_loyalty/static/src/js/screens.js @@ -0,0 +1,96 @@ +odoo.define('garazd_loyalty.screens', function(require){ + "use strict"; + + var core = require('web.core'); + var screens = require('point_of_sale.screens'); + var gui = require('point_of_sale.gui'); + var rpc = require('web.rpc'); + var QWeb = core.qweb; + var _t = core._t; + + + screens.ScreenWidget.include({ + + barcode_client_action: function(code){ + + var self = this; + var partner = this.pos.db.get_partner_by_barcode(code.code); + var order = this.pos.get_order(); + + if(partner){ + return this._super(code); + } + + var show_code = code.code; + var new_partner_id = null; + + this.gui.show_popup('confirm',{ + 'title': _t('New Discount Card scanned.'), + 'body': _t('Issue a card to the client?'), + confirm: function() { + var client_list_screen = self.gui.screen_instances.clientlist; + var fields = {}; + fields.country_id = self.pos.company.country_id[0] || false; + fields.name = show_code || false; + fields.barcode = show_code || false; + + + rpc.query({ + model: 'res.partner', + method: 'create_from_ui', + args: [fields], + }) + .then(function(partner_id){ + + self.pos.load_new_partners().then(function(){ + var new_partner = self.pos.db.get_partner_by_id(partner_id); + order.set_client(new_partner); + order.card_offered = true; + }); + + },function(err,ev){ + ev.preventDefault(); + var error_body = _t('Your Internet connection is probably down.'); + if (err.data) { + var except = err.data; + error_body = except.arguments && except.arguments[0] || except.message || error_body; + } + self.gui.show_popup('error',{ + 'title': _t('Error: Could not Save Changes'), + 'body': error_body, + }); + contents.on('click','.button.save',function(){ self.save_client_details(partner); }); + }); + + client_list_screen.reload_partners() + + + + + + + + }, + + }); + + return false; + } + + }); + + + + screens.OrderWidget.include({ + set_value: function(val) { + var mode = this.numpad_state.get('mode'); + if(mode != 'discount') { + this._super(val); + } + } + + }); + + return screens; + +}); diff --git a/garazd_loyalty/static/src/xml/pos.xml b/garazd_loyalty/static/src/xml/pos.xml new file mode 100644 index 000000000..61379b963 --- /dev/null +++ b/garazd_loyalty/static/src/xml/pos.xml @@ -0,0 +1,16 @@ + + + + + + Discount + + + + + + + + + + diff --git a/garazd_loyalty/views/garazd_loyalty_templates.xml b/garazd_loyalty/views/garazd_loyalty_templates.xml new file mode 100644 index 000000000..da6f0b7cd --- /dev/null +++ b/garazd_loyalty/views/garazd_loyalty_templates.xml @@ -0,0 +1,9 @@ + + + + diff --git a/garazd_loyalty/views/garazd_loyalty_views.xml b/garazd_loyalty/views/garazd_loyalty_views.xml new file mode 100644 index 000000000..33a5e9f5d --- /dev/null +++ b/garazd_loyalty/views/garazd_loyalty_views.xml @@ -0,0 +1,28 @@ + + + + + + + + + garazd.loyalty.view.tree + garazd.loyalty + + + + + + + + + + diff --git a/garazd_loyalty/views/pos_config_views.xml b/garazd_loyalty/views/pos_config_views.xml new file mode 100644 index 000000000..e53cc492c --- /dev/null +++ b/garazd_loyalty/views/pos_config_views.xml @@ -0,0 +1,28 @@ + + + + + pos.config.view.form.inherit.garazd.loyalty + pos.config + + + +

Loyalty System

+
+
+
+ +
+
+
+
+
+
+
+
+ +
diff --git a/garazd_loyalty/views/res_config_views.xml b/garazd_loyalty/views/res_config_views.xml new file mode 100644 index 000000000..69609ab34 --- /dev/null +++ b/garazd_loyalty/views/res_config_views.xml @@ -0,0 +1,30 @@ + + + + + res.config.settings.view.form.inherit.garazd.loyalty + res.config.settings + + + +

Loyalty System

+
+
+
+
+
+
+
+
+
+
+
+ +
diff --git a/garazd_loyalty/views/res_partner_views.xml b/garazd_loyalty/views/res_partner_views.xml new file mode 100644 index 000000000..676a79df4 --- /dev/null +++ b/garazd_loyalty/views/res_partner_views.xml @@ -0,0 +1,43 @@ + + + + + res.partner.view.form.inherit.garazd.loyalty + res.partner + + + + + + + + + +