diff --git a/service_charges_pos/__manifest__.py b/service_charges_pos/__manifest__.py index cbe6cf400..0cd936778 100644 --- a/service_charges_pos/__manifest__.py +++ b/service_charges_pos/__manifest__.py @@ -37,9 +37,8 @@ ], 'assets': { 'point_of_sale._assets_pos': [ - 'service_charges_pos/static/src/js/pos_load_data.js', 'service_charges_pos/static/src/js/service_charge_button.js', - 'service_charges_pos/static/src/xml/ServiceChargeButton.xml', + 'service_charges_pos/static/src/xml/service_charge_button.xml', ], }, 'images': ['static/description/banner.png'], diff --git a/service_charges_pos/doc/RELEASE_NOTES.md b/service_charges_pos/doc/RELEASE_NOTES.md index 6aaa54d62..1a5e0f725 100644 --- a/service_charges_pos/doc/RELEASE_NOTES.md +++ b/service_charges_pos/doc/RELEASE_NOTES.md @@ -1,5 +1,5 @@ ## Module -#### 18.01.2024 -#### Version 17.0.1.0.0 -#### ADD -- Initial commit for Service Charges POS +#### 02.11.2024 +#### Version 17.0.1.0.1 +#### FIX +Bug fixes for Service Charges POS diff --git a/service_charges_pos/models/pos_config.py b/service_charges_pos/models/pos_config.py index 1d01c0d25..173f9104f 100644 --- a/service_charges_pos/models/pos_config.py +++ b/service_charges_pos/models/pos_config.py @@ -19,56 +19,70 @@ # If not, see . # ################################################################################ -from odoo import api, fields, models +from odoo import api, fields, models, _ +from odoo.exceptions import UserError +from odoo.osv.expression import OR class PosConfig(models.Model): - """Inherited POS Configuration""" + """ + To inherit model pos.config + """ _inherit = 'pos.config' - is_session = fields.Boolean(string="Session", - compute='_compute_check_session', - help="Check it is for sessions", ) - is_service_charges = fields.Boolean(string="Service Charges", - help="Enable to add service charge") - charge_type = fields.Selection( - [('amount', 'Amount'), - ('percentage', 'Percentage')], - string='Type', default='amount', - help="Can choose charge percentage or amount") + is_service_charges = fields.Boolean("Service Charges") + visibility_type = fields.Selection([ + ('global', 'Global'), + ('session', 'Session')], + string='Visibility', default='global', + help="Can choose visibility of service charges.") service_charge = fields.Float(string='Service Charge', - help="Charge need to apply") + help="Charge need to apply", + default=10.0) service_product_id = fields.Many2one('product.product', string='Service Product', - domain="[('available_in_pos', '=', " - "True)," - "('sale_ok', '=', True), " - "('type', '=', 'service')]", + domain="[('sale_ok', '=', True)]", help="Service Product") + service_charge_type = fields.Selection([ + ('amount', 'Amount'), + ('percentage', 'Percentage')], + string='Type', default='amount', + help="Can choose charge percentage or amount") + + @api.model + def _default_service_charge_on_module_install(self): + configs = self.env['pos.config'].search([]) + open_configs = ( + self.env['pos.session'] + .search(['|', ('state', '!=', 'closed'), ('rescue', '=', True)]) + .mapped('config_id') + ) + # Do not modify configs where an opened session exists. + product = self.env.ref("point_of_sale.product_product_consumable", + raise_if_not_found=False) + for conf in (configs - open_configs): + conf.service_product_id = product if ( + conf.is_service_charges + ) and product and ( + not product.company_id or product.company_id == conf.company_id + ) else False + + def open_ui(self): + for config in self: + if not self.current_session_id and ( + config.is_service_charges + ) and not config.service_product_id: + raise UserError(_( + 'A discount product is needed to use the Service Charge ' + 'feature. Go to Point of Sale > Configuration > Settings ' + 'to set it.')) + return super().open_ui() - def _compute_check_session(self): - """To check the service charge is set up for session wise or - globally""" - for record in self: - check_session = self.env['ir.config_parameter'].sudo().get_param( - 'service_charges_pos.visibility') - if check_session == 'session': - record.is_session = True - else: - record.is_session = False + def _get_special_products(self): + res = super()._get_special_products() + return res | self.env['pos.config'].search( + []).mapped('service_product_id') - @api.onchange('is_service_charges') - def onchange_is_service_charges(self): - """When the service charge is enabled set service product - and amount by default per session""" - if self.is_service_charges: - if not self.service_product_id: - self.service_product_id = self.env[ - 'product.product'].search([ - ('available_in_pos', '=', True), - ('sale_ok', '=', True), ('type', '=', 'service') - ], limit=1) - self.service_charge = 10.0 - else: - self.service_product_id = False - self.service_charge = 0.0 + def _get_available_product_domain(self): + domain = super()._get_available_product_domain() + return OR([domain, [('id', '=', self.service_product_id.id)]]) diff --git a/service_charges_pos/models/pos_session.py b/service_charges_pos/models/pos_session.py index 2a7e17d19..f04fc6a03 100644 --- a/service_charges_pos/models/pos_session.py +++ b/service_charges_pos/models/pos_session.py @@ -23,28 +23,20 @@ from odoo import models class PosSession(models.Model): - """Inherited POS Session""" _inherit = 'pos.session' - def _pos_ui_models_to_load(self): - """Supering the function for loading res.config.settings to pos - session""" - result = super()._pos_ui_models_to_load() - result.append('res.config.settings') - return result - - def _loader_params_res_config_settings(self): - """Returning the field required""" - return { - 'search_params': { - 'fields': ['enable_service_charge', 'visibility', - 'global_selection', 'global_charge', - 'global_product_id'], - }, - } + def _get_pos_ui_product_product(self, params): + result = super()._get_pos_ui_product_product(params) + service_product_id = self.config_id.service_product_id.id + product_ids_set = {product['id'] for product in result} - def _get_pos_ui_res_config_settings(self, params): - """Returns the model""" - return self.env['res.config.settings'].sudo().search_read( - **params['search_params'] - ) + if self.config_id.is_service_charges and ( + service_product_id) not in product_ids_set: + product_model = self.env['product.product'].with_context( + **params['context']) + product = product_model.search_read([( + 'id', '=', service_product_id + )], fields=params['search_params']['fields']) + self._process_pos_ui_product_product(product) + result.extend(product) + return result diff --git a/service_charges_pos/models/res_config_settings.py b/service_charges_pos/models/res_config_settings.py index e24a7ac53..041191c14 100644 --- a/service_charges_pos/models/res_config_settings.py +++ b/service_charges_pos/models/res_config_settings.py @@ -23,55 +23,38 @@ from odoo import api, fields, models class ResConfigSettings(models.TransientModel): - """Inherited Configuration Settings""" - _inherit = "res.config.settings" + _inherit = 'res.config.settings' - enable_service_charge = fields.Boolean(string="Service Charges", - config_parameter="service_charges_" - "pos.enable_service" - "_charge", - help="Enable to add service charge") - visibility = fields.Selection([ + # pos.config fields + pos_is_service_charges = fields.Boolean( + related='pos_config_id.is_service_charges', readonly=False) + pos_visibility_type = fields.Selection([ ('global', 'Global'), ('session', 'Session')], - default='global', string="Visibility", - config_parameter="service_charges_pos.visibility", - help='Setup the Service charge globally or per session') - global_selection = fields.Selection([ + related='pos_config_id.visibility_type', + readonly=False) + pos_service_charge = fields.Float(related='pos_config_id.service_charge', + readonly=False) + pos_service_product_id = fields.Many2one( + 'product.product', + compute='_compute_pos_service_product_id', store=True, readonly=False) + pos_service_charge_type = fields.Selection([ ('amount', 'Amount'), ('percentage', 'Percentage')], - string='Type', default='amount', - config_parameter="service_charges_pos.global_selection", - help='Set the service charge as a amount or percentage') - global_charge = fields.Float(string='Service Charge', - config_parameter="service_charges_pos." - "global_charge", - help='Set a default service charge globally') - global_product_id = fields.Many2one('product.product', - string='Service Product', - domain="[('available_in_pos', '=', " - "True)," - "('sale_ok', '=', True), " - "('type', '=', 'service')]", - config_parameter="service_charges_pos" - ".global_product_id", - help='Set a service product globally') + related='pos_config_id.service_charge_type', + readonly=False) - @api.onchange('enable_service_charge') - def onchange_enable_service_charge(self): - """When the service charge is enabled set service product and amount - by default in globally""" - service_charges =self.env['pos.config'].search([]) - if self.enable_service_charge: - service_charges.is_service_charges = True - if not self.global_product_id: - self.global_product_id = self.env[ - 'product.product'].search([ - ('available_in_pos', '=', True), - ('sale_ok', '=', True), - ('type', '=', 'service') - ], limit=1) - self.global_charge = 10.0 - else: - self.global_product_id = False - self.global_charge = 0.0 + @api.depends('company_id', 'pos_is_service_charges', 'pos_config_id') + def _compute_pos_service_product_id(self): + default_product = self.env.ref( + "point_of_sale.product_product_consumable", + raise_if_not_found=False) or self.env['product.product'] + for res_config in self: + service_product = res_config.pos_config_id.service_product_id or ( + default_product) + if (res_config.pos_is_service_charges) and ( + not service_product.company_id or ( + service_product.company_id) == res_config.company_id): + res_config.pos_service_product_id = service_product + else: + res_config.pos_service_product_id = False diff --git a/service_charges_pos/static/src/js/pos_load_data.js b/service_charges_pos/static/src/js/pos_load_data.js deleted file mode 100644 index 217f966be..000000000 --- a/service_charges_pos/static/src/js/pos_load_data.js +++ /dev/null @@ -1,10 +0,0 @@ -/** @odoo-module */ -import { patch } from "@web/core/utils/patch"; -import { PosStore } from "@point_of_sale/app/store/pos_store"; -patch(PosStore.prototype, { - async _processData(loadedData) { - // To load data to pos session - await super._processData(...arguments); - this.res_config_settings = loadedData["res.config.settings"]; - } -}); diff --git a/service_charges_pos/static/src/js/service_charge_button.js b/service_charges_pos/static/src/js/service_charge_button.js index 9b2bdbdcc..5af969d67 100644 --- a/service_charges_pos/static/src/js/service_charge_button.js +++ b/service_charges_pos/static/src/js/service_charge_button.js @@ -1,100 +1,72 @@ -/** @odoo-module */ -import { Component } from "@odoo/owl"; -import { useService } from "@web/core/utils/hooks"; +/** @odoo-module **/ + +import { _t } from "@web/core/l10n/translation"; import { ProductScreen } from "@point_of_sale/app/screens/product_screen/product_screen"; -import { usePos } from "@point_of_sale/app/store/pos_hook"; -import { ErrorPopup } from "@point_of_sale/app/errors/popups/error_popup"; +import { useService } from "@web/core/utils/hooks"; import { NumberPopup } from "@point_of_sale/app/utils/input_popups/number_popup"; -import { _t } from "@web/core/l10n/translation"; +import { ErrorPopup } from "@point_of_sale/app/errors/popups/error_popup"; +import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/store/pos_hook"; +import { parseFloat } from "@web/views/fields/parsers"; export class ServiceChargeButton extends Component { static template = "service_charges_pos.ServiceChargeButton"; + setup() { this.pos = usePos(); this.popup = useService("popup"); } + async click() { - // To show number pop up and service charge applying functions based on conditions. - let res_config_settings = this.pos.res_config_settings[this.pos.res_config_settings.length -1] - var global_selection = res_config_settings.global_selection - var global_charge = res_config_settings.global_charge - var visibility = res_config_settings.visibility - var global_product = res_config_settings.global_product_id[0] - var order = this.pos.get_order(); - var lines = order.get_orderlines(); - if (visibility == 'global') { - var product = this.pos.db.get_product_by_id(global_product) - if (product === undefined) { - await this.popup.add(ErrorPopup, { - title: _t("No service product found"), - body: _t("The service product seems misconfigured. Make sure it is flagged as 'Can be Sold' and 'Available in Point of Sale'.") - }); - return - } - // Remove existing discounts - lines.filter(line => line.get_product() === product).forEach(line => order.removeOrderline(line)); - const { confirmed, payload } = await this.popup.add(NumberPopup, { - title: _t('Service Charge'), - startingValue: parseInt(global_charge), - isInputSelected: true - }) - if (confirmed) { - if (payload > 0) { - if (global_selection == 'amount') { - order.add_product(product, { - price: payload - }); - } else { - var total_amount = order.get_total_with_tax() - var per_amount = payload / 100 * total_amount - order.add_product(product, { - price: per_amount - }); - } - } + var self = this; + const { confirmed, payload } = await this.popup.add(NumberPopup, { + title: _t("Service Charge"), + startingValue: this.pos.config.service_charge, + isInputSelected: true, + }); + if (confirmed) { + const val = Math.max(0, Math.min(100, parseFloat(payload))); + if (val > 0) { + await self.apply_service_charge(val); } + } + } + + async apply_service_charge(val) { + const order = this.pos.get_order(); + const lines = order.get_orderlines(); + const product = this.pos.db.get_product_by_id(this.pos.config.service_product_id[0]); + if (product === undefined) { + await this.popup.add(ErrorPopup, { + title: _t("No service product found"), + body: _t( + "The service product seems misconfigured. Make sure it is flagged as 'Can be Sold' and 'Available in Point of Sale'." + ), + }); + return; + } + // Remove existing service charges + lines + .filter((line) => line.get_product() === product) + .forEach((line) => order._unlinkOrderline(line)); + // Add service charge + if (this.pos.config.service_charge_type == 'amount') { + var sc_price = val } else { - var type = this.pos.config.charge_type - var product = this.pos.db.get_product_by_id(this.pos.config.service_product_id[0]); - if (product === undefined) { - await this.popup.add(ErrorPopup, { - title: _t("No service product found"), - body: _t("The service product seems misconfigured. Make sure it is flagged as 'Can be Sold' and 'Available in Point of Sale'."), - }); - return; - } - lines.filter(line => line.get_product() === product).forEach(line => order.removeOrderline(line)); - const {confirmed, payload } = await this.popup.add(NumberPopup, { - title: _t('Service Charge'), - startingValue: this.pos.config.service_charge, - isInputSelected: true - }) - if (confirmed) { - if (payload > 0) { - if (type == 'amount') { - order.add_product(product, { - price: payload - }); - } else { - var total_amount = order.get_total_with_tax() - var per_amount = payload / 100 * total_amount - order.add_product(product, { - price: per_amount - }); - } - } - } + var sc_price = order.get_total_with_tax() * val / 100 } + order.add_product(product, { + price: sc_price, + tax_ids: [] + }); } + } + ProductScreen.addControlButton({ component: ServiceChargeButton, condition: function () { - let res_config_settings = this.pos.config.is_service_charges - if (res_config_settings) { - return this.pos.config.is_service_charges - } else { - return false - } + const { is_service_charges, service_product_id } = this.pos.config; + return is_service_charges && service_product_id; }, }); diff --git a/service_charges_pos/static/src/xml/ServiceChargeButton.xml b/service_charges_pos/static/src/xml/ServiceChargeButton.xml deleted file mode 100644 index 96eb62a69..000000000 --- a/service_charges_pos/static/src/xml/ServiceChargeButton.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/service_charges_pos/static/src/xml/service_charge_button.xml b/service_charges_pos/static/src/xml/service_charge_button.xml new file mode 100644 index 000000000..63028a988 --- /dev/null +++ b/service_charges_pos/static/src/xml/service_charge_button.xml @@ -0,0 +1,12 @@ + + + + + + + + Service Charge + + + + diff --git a/service_charges_pos/views/pos_config_views.xml b/service_charges_pos/views/pos_config_views.xml index b24248331..720f9216a 100644 --- a/service_charges_pos/views/pos_config_views.xml +++ b/service_charges_pos/views/pos_config_views.xml @@ -7,33 +7,25 @@ - - - + + +
-
-
-
diff --git a/service_charges_pos/views/res_config_settings_views.xml b/service_charges_pos/views/res_config_settings_views.xml index f76b9f546..4de4fefef 100644 --- a/service_charges_pos/views/res_config_settings_views.xml +++ b/service_charges_pos/views/res_config_settings_views.xml @@ -4,45 +4,27 @@ res.config.settings.view.form.inherit.service.charges.pos res.config.settings - + - - - -
+ + + +
-
-
-
-
-
-
-
-
-
-
-