Browse Source

Nov 4 [UPDT] Updated 'service_charges_pos'

pull/347/head
AjmalCybro 6 months ago
parent
commit
6be5ae82ab
  1. 3
      service_charges_pos/__manifest__.py
  2. 8
      service_charges_pos/doc/RELEASE_NOTES.md
  3. 98
      service_charges_pos/models/pos_config.py
  4. 36
      service_charges_pos/models/pos_session.py
  5. 75
      service_charges_pos/models/res_config_settings.py
  6. 10
      service_charges_pos/static/src/js/pos_load_data.js
  7. 132
      service_charges_pos/static/src/js/service_charge_button.js
  8. 10
      service_charges_pos/static/src/xml/ServiceChargeButton.xml
  9. 12
      service_charges_pos/static/src/xml/service_charge_button.xml
  10. 26
      service_charges_pos/views/pos_config_views.xml
  11. 50
      service_charges_pos/views/res_config_settings_views.xml

3
service_charges_pos/__manifest__.py

@ -37,9 +37,8 @@
], ],
'assets': { 'assets': {
'point_of_sale._assets_pos': [ '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/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'], 'images': ['static/description/banner.png'],

8
service_charges_pos/doc/RELEASE_NOTES.md

@ -1,5 +1,5 @@
## Module <service_charges_pos> ## Module <service_charges_pos>
#### 18.01.2024 #### 02.11.2024
#### Version 17.0.1.0.0 #### Version 17.0.1.0.1
#### ADD #### FIX
- Initial commit for Service Charges POS Bug fixes for Service Charges POS

98
service_charges_pos/models/pos_config.py

@ -19,56 +19,70 @@
# If not, see <http://www.gnu.org/licenses/>. # If not, see <http://www.gnu.org/licenses/>.
# #
################################################################################ ################################################################################
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): class PosConfig(models.Model):
"""Inherited POS Configuration""" """
To inherit model pos.config
"""
_inherit = 'pos.config' _inherit = 'pos.config'
is_session = fields.Boolean(string="Session", is_service_charges = fields.Boolean("Service Charges")
compute='_compute_check_session', visibility_type = fields.Selection([
help="Check it is for sessions", ) ('global', 'Global'),
is_service_charges = fields.Boolean(string="Service Charges", ('session', 'Session')],
help="Enable to add service charge") string='Visibility', default='global',
charge_type = fields.Selection( help="Can choose visibility of service charges.")
[('amount', 'Amount'),
('percentage', 'Percentage')],
string='Type', default='amount',
help="Can choose charge percentage or amount")
service_charge = fields.Float(string='Service Charge', 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', service_product_id = fields.Many2one('product.product',
string='Service Product', string='Service Product',
domain="[('available_in_pos', '=', " domain="[('sale_ok', '=', True)]",
"True),"
"('sale_ok', '=', True), "
"('type', '=', 'service')]",
help="Service Product") 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): def _get_special_products(self):
"""To check the service charge is set up for session wise or res = super()._get_special_products()
globally""" return res | self.env['pos.config'].search(
for record in self: []).mapped('service_product_id')
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
@api.onchange('is_service_charges') def _get_available_product_domain(self):
def onchange_is_service_charges(self): domain = super()._get_available_product_domain()
"""When the service charge is enabled set service product return OR([domain, [('id', '=', self.service_product_id.id)]])
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

36
service_charges_pos/models/pos_session.py

@ -23,28 +23,20 @@ from odoo import models
class PosSession(models.Model): class PosSession(models.Model):
"""Inherited POS Session"""
_inherit = 'pos.session' _inherit = 'pos.session'
def _pos_ui_models_to_load(self): def _get_pos_ui_product_product(self, params):
"""Supering the function for loading res.config.settings to pos result = super()._get_pos_ui_product_product(params)
session""" service_product_id = self.config_id.service_product_id.id
result = super()._pos_ui_models_to_load() product_ids_set = {product['id'] for product in result}
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_res_config_settings(self, params): if self.config_id.is_service_charges and (
"""Returns the model""" service_product_id) not in product_ids_set:
return self.env['res.config.settings'].sudo().search_read( product_model = self.env['product.product'].with_context(
**params['search_params'] **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

75
service_charges_pos/models/res_config_settings.py

@ -23,55 +23,38 @@ from odoo import api, fields, models
class ResConfigSettings(models.TransientModel): class ResConfigSettings(models.TransientModel):
"""Inherited Configuration Settings""" _inherit = 'res.config.settings'
_inherit = "res.config.settings"
enable_service_charge = fields.Boolean(string="Service Charges", # pos.config fields
config_parameter="service_charges_" pos_is_service_charges = fields.Boolean(
"pos.enable_service" related='pos_config_id.is_service_charges', readonly=False)
"_charge", pos_visibility_type = fields.Selection([
help="Enable to add service charge")
visibility = fields.Selection([
('global', 'Global'), ('global', 'Global'),
('session', 'Session')], ('session', 'Session')],
default='global', string="Visibility", related='pos_config_id.visibility_type',
config_parameter="service_charges_pos.visibility", readonly=False)
help='Setup the Service charge globally or per session') pos_service_charge = fields.Float(related='pos_config_id.service_charge',
global_selection = fields.Selection([ 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'), ('amount', 'Amount'),
('percentage', 'Percentage')], ('percentage', 'Percentage')],
string='Type', default='amount', related='pos_config_id.service_charge_type',
config_parameter="service_charges_pos.global_selection", readonly=False)
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')
@api.onchange('enable_service_charge') @api.depends('company_id', 'pos_is_service_charges', 'pos_config_id')
def onchange_enable_service_charge(self): def _compute_pos_service_product_id(self):
"""When the service charge is enabled set service product and amount default_product = self.env.ref(
by default in globally""" "point_of_sale.product_product_consumable",
service_charges =self.env['pos.config'].search([]) raise_if_not_found=False) or self.env['product.product']
if self.enable_service_charge: for res_config in self:
service_charges.is_service_charges = True service_product = res_config.pos_config_id.service_product_id or (
if not self.global_product_id: default_product)
self.global_product_id = self.env[ if (res_config.pos_is_service_charges) and (
'product.product'].search([ not service_product.company_id or (
('available_in_pos', '=', True), service_product.company_id) == res_config.company_id):
('sale_ok', '=', True), res_config.pos_service_product_id = service_product
('type', '=', 'service') else:
], limit=1) res_config.pos_service_product_id = False
self.global_charge = 10.0
else:
self.global_product_id = False
self.global_charge = 0.0

10
service_charges_pos/static/src/js/pos_load_data.js

@ -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"];
}
});

132
service_charges_pos/static/src/js/service_charge_button.js

@ -1,100 +1,72 @@
/** @odoo-module */ /** @odoo-module **/
import { Component } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks"; import { _t } from "@web/core/l10n/translation";
import { ProductScreen } from "@point_of_sale/app/screens/product_screen/product_screen"; import { ProductScreen } from "@point_of_sale/app/screens/product_screen/product_screen";
import { usePos } from "@point_of_sale/app/store/pos_hook"; import { useService } from "@web/core/utils/hooks";
import { ErrorPopup } from "@point_of_sale/app/errors/popups/error_popup";
import { NumberPopup } from "@point_of_sale/app/utils/input_popups/number_popup"; 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 { export class ServiceChargeButton extends Component {
static template = "service_charges_pos.ServiceChargeButton"; static template = "service_charges_pos.ServiceChargeButton";
setup() { setup() {
this.pos = usePos(); this.pos = usePos();
this.popup = useService("popup"); this.popup = useService("popup");
} }
async click() { async click() {
// To show number pop up and service charge applying functions based on conditions. var self = this;
let res_config_settings = this.pos.res_config_settings[this.pos.res_config_settings.length -1] const { confirmed, payload } = await this.popup.add(NumberPopup, {
var global_selection = res_config_settings.global_selection title: _t("Service Charge"),
var global_charge = res_config_settings.global_charge startingValue: this.pos.config.service_charge,
var visibility = res_config_settings.visibility isInputSelected: true,
var global_product = res_config_settings.global_product_id[0] });
var order = this.pos.get_order(); if (confirmed) {
var lines = order.get_orderlines(); const val = Math.max(0, Math.min(100, parseFloat(payload)));
if (visibility == 'global') { if (val > 0) {
var product = this.pos.db.get_product_by_id(global_product) await self.apply_service_charge(val);
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
});
}
}
} }
}
}
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 { } else {
var type = this.pos.config.charge_type var sc_price = order.get_total_with_tax() * val / 100
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
});
}
}
}
} }
order.add_product(product, {
price: sc_price,
tax_ids: []
});
} }
} }
ProductScreen.addControlButton({ ProductScreen.addControlButton({
component: ServiceChargeButton, component: ServiceChargeButton,
condition: function () { condition: function () {
let res_config_settings = this.pos.config.is_service_charges const { is_service_charges, service_product_id } = this.pos.config;
if (res_config_settings) { return is_service_charges && service_product_id;
return this.pos.config.is_service_charges
} else {
return false
}
}, },
}); });

10
service_charges_pos/static/src/xml/ServiceChargeButton.xml

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<!-- Pos button -->
<t t-name="service_charges_pos.ServiceChargeButton" owl="1">
<button class="control-button btn btn-light rounded-0 fw-bolder" t-on-click="() => this.click()">
<i class="fa fa-calculator" role="img" aria-label="Service Charge" title="Service Charge" />
Service Charge
</button>
</t>
</templates>

12
service_charges_pos/static/src/xml/service_charge_button.xml

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="service_charges_pos.ServiceChargeButton">
<span class="control-button btn btn-light rounded-0 fw-bolder" t-on-click="() => this.click()">
<i class="fa fa-calculator"></i>
<span> </span>
<span>Service Charge</span>
</span>
</t>
</templates>

26
service_charges_pos/views/pos_config_views.xml

@ -7,33 +7,25 @@
<field name="inherit_id" ref="point_of_sale.pos_config_view_form"/> <field name="inherit_id" ref="point_of_sale.pos_config_view_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//setting[@id='other_devices']" position="after"> <xpath expr="//setting[@id='other_devices']" position="after">
<field name="is_session" invisible="1"/> <field name="visibility_type" invisible="1"/>
<setting help="Allow service charges on orders" invisible="not is_session"> <setting help="Allow service charges on orders" invisible="visibility_type == 'global'">
<field name="is_service_charges" force_save="1"/> <field name="is_service_charges"/>
<div class="content-group mt16" invisible="not is_service_charges"> <div class="content-group mt16" invisible="not is_service_charges">
<div class="row"> <div class="row">
<label for="charge_type" <label for="service_product_id" class="col-lg-3 o_light_label"/>
class="col-lg-3 o_light_label"/> <field name="service_product_id"/>
<field name="charge_type" widget="radio"
options="{'horizontal': true}"
required="is_service_charges"
/>
</div> </div>
</div> </div>
<div class="content-group mt16" invisible="not is_service_charges"> <div class="content-group mt16" invisible="not is_service_charges">
<div class="row"> <div class="row">
<label for="service_product_id" <label for="service_charge" class="col-lg-3 o_light_label"/>
class="col-lg-3 o_light_label"/> <field name="service_charge"/>
<field name="service_product_id"
required="is_service_charges"
/>
</div> </div>
</div> </div>
<div class="content-group mt16" invisible="not is_service_charges"> <div class="content-group mt16" invisible="not is_service_charges">
<div class="row"> <div class="row">
<label for="service_charge" <label for="service_charge_type" class="col-lg-3 o_light_label"/>
class="col-lg-3 o_light_label"/> <field name="service_charge_type" widget="radio" options="{'horizontal': true}"/>
<field name="service_charge"/>
</div> </div>
</div> </div>
</setting> </setting>

50
service_charges_pos/views/res_config_settings_views.xml

@ -4,45 +4,27 @@
<record id="res_config_settings_view_form" model="ir.ui.view"> <record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.service.charges.pos</field> <field name="name">res.config.settings.view.form.inherit.service.charges.pos</field>
<field name="model">res.config.settings</field> <field name="model">res.config.settings</field>
<field name="inherit_id" <field name="inherit_id" ref="point_of_sale.res_config_settings_view_form"/>
ref="point_of_sale.res_config_settings_view_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//block[@id='pos_interface_section']" position="inside"> <xpath expr="//block[@id='pos_pricing_section']" position="inside">
<setting help="Allow service charges on orders"> <setting help="Adds a button to set a service charge.">
<field name="enable_service_charge"/> <field name="pos_is_service_charges" readonly="pos_has_active_session"/>
<div class="content-group mt16" invisible="not enable_service_charge"> <div class="content-group mt16" invisible="not pos_is_service_charges">
<div class="row"> <div class="row">
<label string="Visibility" for="visibility" class="col-lg-3 o_light_label"/> <label string="Visibility" for="pos_visibility_type" class="col-lg-3 o_light_label"/>
<field name="visibility" widget="radio" <field name="pos_visibility_type" widget="radio" options="{'horizontal': true}"/>
options="{'horizontal': true}"
required="enable_service_charge"
/>
</div> </div>
</div> <div class="row" invisible="pos_visibility_type == 'session'">
<div class="content-group mt16" invisible="not enable_service_charge or (visibility == 'session')"> <label string="Service Product" for="pos_service_product_id" class="col-lg-3 o_light_label"/>
<div class="row"> <field name="pos_service_product_id" required="pos_is_service_charges"/>
<label for="global_selection"
class="col-lg-3 o_light_label"/>
<field name="global_selection" widget="radio"
options="{'horizontal': true}"
required="enable_service_charge"
/>
</div> </div>
</div> <div class="row" invisible="pos_visibility_type == 'session'">
<div class="content-group mt16" invisible="not enable_service_charge or (visibility == 'session')"> <label string="Charge Type" for="pos_service_charge_type" class="col-lg-3 o_light_label"/>
<div class="row"> <field name="pos_service_charge_type" widget="radio" options="{'horizontal': true}"/>
<label for="global_product_id"
class="col-lg-3 o_light_label"/>
<field name="global_product_id"
required="enable_service_charge"
/>
</div> </div>
</div> <div class="row" invisible="pos_visibility_type == 'session'">
<div class="content-group mt16" invisible="not enable_service_charge or (visibility == 'session')"> <label string="Service Charge" for="pos_service_charge" class="col-lg-3 o_light_label"/>
<div class="row"> <field name="pos_service_charge"/>
<label for="global_charge"
class="col-lg-3 o_light_label"/>
<field name="global_charge"/>
</div> </div>
</div> </div>
</setting> </setting>

Loading…
Cancel
Save