diff --git a/addons/point_of_sale/models/pos_session.py b/addons/point_of_sale/models/pos_session.py index cc7885fd757..d462ba4a972 100644 --- a/addons/point_of_sale/models/pos_session.py +++ b/addons/point_of_sale/models/pos_session.py @@ -1561,11 +1561,6 @@ class PosSession(models.Model): for session in sessions ]) - message_content = [f"Cash {extras['translatedType']}", f'- Amount: {extras["formattedAmount"]}'] - if reason: - message_content.append(f'- Reason: {reason}') - self.message_post(body=Markup('
\n').join(message_content)) - def get_onboarding_data(self): return { "categories": self._load_model('pos.category'), @@ -2132,6 +2127,7 @@ class PosSession(models.Model): body = 'Action cancelled ({ACTION})'.format(ACTION=action) elif message_type == 'CASH_DRAWER_ACTION': body = 'Cash drawer opened ({ACTION})'.format(ACTION=action) + self.message_post(body=body, author_id=partner_id) def load_product_frontend(self): diff --git a/addons/point_of_sale/static/src/app/navbar/cash_move_popup/cash_move_popup.js b/addons/point_of_sale/static/src/app/navbar/cash_move_popup/cash_move_popup.js index 50a4622a633..eb5ea6ab0b5 100644 --- a/addons/point_of_sale/static/src/app/navbar/cash_move_popup/cash_move_popup.js +++ b/addons/point_of_sale/static/src/app/navbar/cash_move_popup/cash_move_popup.js @@ -65,6 +65,11 @@ export class CashMovePopup extends AbstractAwaitablePopup { reason, extras, ]); + await this.pos.globalState.logEmployeeMessage( + `${_t("Cash")} ${translatedType} - ${_t("Amount")}: ${formattedAmount}`, + "CASH_DRAWER_ACTION" + ); + if (this.hardwareProxy.printer) { const renderedReceipt = renderToElement("point_of_sale.CashMoveReceipt", { _receipt: { diff --git a/addons/point_of_sale/static/src/app/navbar/navbar.js b/addons/point_of_sale/static/src/app/navbar/navbar.js index 4200ecc56e0..786f8c850ee 100644 --- a/addons/point_of_sale/static/src/app/navbar/navbar.js +++ b/addons/point_of_sale/static/src/app/navbar/navbar.js @@ -26,9 +26,7 @@ export class Navbar extends Component { SyncNotification, BackButton, }; - static props = { - showCashMoveButton: Boolean, - }; + static props = {}; setup() { this.pos = usePos(); this.ui = useState(useService("ui")); @@ -49,7 +47,9 @@ export class Navbar extends Component { get customerFacingDisplayButtonIsShown() { return this.pos.globalState.config.iface_customer_facing_display; } - + get showCashMoveButton() { + return Boolean(this.pos.globalState?.config?.cash_control); + } onCashMoveButtonClick() { this.hardwareProxy.openCashbox(_t("Cash in / out")); this.popup.add(CashMovePopup); diff --git a/addons/point_of_sale/static/src/app/navbar/navbar.xml b/addons/point_of_sale/static/src/app/navbar/navbar.xml index decbfe16f96..3aad708165b 100644 --- a/addons/point_of_sale/static/src/app/navbar/navbar.xml +++ b/addons/point_of_sale/static/src/app/navbar/navbar.xml @@ -29,7 +29,7 @@ Orders - diff --git a/addons/point_of_sale/static/src/app/pos_app.js b/addons/point_of_sale/static/src/app/pos_app.js index 9e7fdd14d52..b96e65bd004 100644 --- a/addons/point_of_sale/static/src/app/pos_app.js +++ b/addons/point_of_sale/static/src/app/pos_app.js @@ -33,11 +33,6 @@ export class Chrome extends Component { onMounted(this.props.disableLoader); } - // GETTERS // - - get showCashMoveButton() { - return Boolean(this.pos.globalState?.config?.cash_control); - } /** * Unmounts the tempScreen on error and dispatches the error in a separate * stack so that it can be handled by the error service and display an error diff --git a/addons/point_of_sale/static/src/app/pos_app.xml b/addons/point_of_sale/static/src/app/pos_app.xml index 29cbe15b229..1bfe71f3d37 100644 --- a/addons/point_of_sale/static/src/app/pos_app.xml +++ b/addons/point_of_sale/static/src/app/pos_app.xml @@ -4,7 +4,7 @@
- +
diff --git a/addons/pos_hr/__manifest__.py b/addons/pos_hr/__manifest__.py index e948f9d47db..878180c4382 100644 --- a/addons/pos_hr/__manifest__.py +++ b/addons/pos_hr/__manifest__.py @@ -26,8 +26,6 @@ The actual till still requires one user but an unlimited number of employees can 'pos_hr/static/src/css/pos.css', 'pos_hr/static/src/js/models.js', 'pos_hr/static/src/js/SelectCashierMixin.js', - 'pos_hr/static/src/js/Chrome.js', - 'pos_hr/static/src/js/HeaderLockButton.js', 'pos_hr/static/src/js/CashierName.js', 'pos_hr/static/src/js/LoginScreen.js', 'pos_hr/static/src/js/PaymentScreen.js', diff --git a/addons/pos_hr/models/hr_employee.py b/addons/pos_hr/models/hr_employee.py index 1bd9787ad9d..50304185d55 100644 --- a/addons/pos_hr/models/hr_employee.py +++ b/addons/pos_hr/models/hr_employee.py @@ -25,12 +25,12 @@ class HrEmployee(models.Model): @api.ondelete(at_uninstall=False) def _unlink_except_active_pos_session(self): configs_with_employees = self.env['pos.config'].sudo().search([('module_pos_hr', '=', 'True')]).filtered(lambda c: c.current_session_id) - configs_with_all_employees = configs_with_employees.filtered(lambda c: not c.employee_ids) - configs_with_specific_employees = configs_with_employees.filtered(lambda c: c.employee_ids & self) + configs_with_all_employees = configs_with_employees.filtered(lambda c: not c.basic_employee_ids and not c.advanced_employee_ids) + configs_with_specific_employees = configs_with_employees.filtered(lambda c: (c.basic_employee_ids or c.advanced_employee_ids) & self) if configs_with_all_employees or configs_with_specific_employees: error_msg = _("You cannot delete an employee that may be used in an active PoS session, close the session(s) first: \n") for employee in self: - config_ids = configs_with_all_employees | configs_with_specific_employees.filtered(lambda c: employee in c.employee_ids) + config_ids = configs_with_all_employees | configs_with_specific_employees.filtered(lambda c: employee in c.basic_employee_ids) if config_ids: error_msg += _("Employee: %s - PoS Config(s): %s \n") % (employee.name, ', '.join(config.name for config in config_ids)) diff --git a/addons/pos_hr/models/pos_config.py b/addons/pos_hr/models/pos_config.py index efa05ca6dcf..d1e5104d807 100644 --- a/addons/pos_hr/models/pos_config.py +++ b/addons/pos_hr/models/pos_config.py @@ -1,13 +1,26 @@ # -*- coding: utf-8 -*- -from functools import partial - -from odoo import models, fields +from odoo import models, fields, api class PosConfig(models.Model): _inherit = 'pos.config' - employee_ids = fields.Many2many( - 'hr.employee', string="Employees with access", - help='If left empty, all employees can log in to the PoS session') + basic_employee_ids = fields.Many2many( + 'hr.employee', 'pos_hr_basic_employee_hr_employee', string="Employees with basic access", + help='If left empty, all employees can log in to PoS') + advanced_employee_ids = fields.Many2many( + 'hr.employee', 'pos_hr_advanced_employee_hr_employee', string="Employees with manager access", + help='If left empty, only Odoo users have extended rights in PoS') + + @api.onchange('basic_employee_ids') + def _onchange_basic_employee_ids(self): + for employee in self.basic_employee_ids: + if employee in self.advanced_employee_ids: + self.advanced_employee_ids -= employee + + @api.onchange('advanced_employee_ids') + def _onchange_advanced_employee_ids(self): + for employee in self.advanced_employee_ids: + if employee in self.basic_employee_ids: + self.basic_employee_ids -= employee diff --git a/addons/pos_hr/models/pos_session.py b/addons/pos_hr/models/pos_session.py index df367492f6b..12527bd38b9 100644 --- a/addons/pos_hr/models/pos_session.py +++ b/addons/pos_hr/models/pos_session.py @@ -21,8 +21,10 @@ class PosSession(models.Model): return result def _loader_params_hr_employee(self): - if len(self.config_id.employee_ids) > 0: - domain = ['&', ('company_id', '=', self.config_id.company_id.id), '|', ('user_id', '=', self.user_id.id), ('id', 'in', self.config_id.employee_ids.ids)] + if len(self.config_id.basic_employee_ids) > 0: + domain = [ + '&', ('company_id', '=', self.config_id.company_id.id), + '|', ('user_id', '=', self.user_id.id), ('id', 'in', self.config_id.basic_employee_ids.ids + self.config_id.advanced_employee_ids.ids)] else: domain = [('company_id', '=', self.config_id.company_id.id)] return {'search_params': {'domain': domain, 'fields': ['name', 'id', 'user_id', 'work_contact_id'], 'load': False}} @@ -36,7 +38,10 @@ class PosSession(models.Model): employees_barcode_pin = self.env['hr.employee'].browse(employee_ids).get_barcodes_and_pin_hashed() bp_per_employee_id = {bp_e['id']: bp_e for bp_e in employees_barcode_pin} for employee in employees: - employee['role'] = 'manager' if employee['user_id'] and employee['user_id'] in manager_ids else 'cashier' + if employee['user_id'] and employee['user_id'] in manager_ids or employee['id'] in self.config_id.advanced_employee_ids.ids: + employee['role'] = 'manager' + else: + employee['role'] = 'cashier' employee['barcode'] = bp_per_employee_id[employee['id']]['barcode'] employee['pin'] = bp_per_employee_id[employee['id']]['pin'] diff --git a/addons/pos_hr/models/res_config_settings.py b/addons/pos_hr/models/res_config_settings.py index 286b1928199..a41af4fe489 100644 --- a/addons/pos_hr/models/res_config_settings.py +++ b/addons/pos_hr/models/res_config_settings.py @@ -1,10 +1,25 @@ # -*- coding: utf-8 -*- -from odoo import fields, models +from odoo import fields, models, api class ResConfigSettings(models.TransientModel): _inherit = 'res.config.settings' # pos.config fields - pos_employee_ids = fields.Many2many(related='pos_config_id.employee_ids', readonly=False) + pos_basic_employee_ids = fields.Many2many(related='pos_config_id.basic_employee_ids', readonly=False, + help='If left empty, all employees can log in to PoS') + pos_advanced_employee_ids = fields.Many2many(related='pos_config_id.advanced_employee_ids', readonly=False, + help='If left empty, only Odoo users have extended rights in PoS') + + @api.onchange('pos_basic_employee_ids') + def _onchange_basic_employee_ids(self): + for employee in self.pos_basic_employee_ids: + if employee in self.pos_advanced_employee_ids: + self.pos_advanced_employee_ids -= employee + + @api.onchange('pos_advanced_employee_ids') + def _onchange_advanced_employee_ids(self): + for employee in self.pos_advanced_employee_ids: + if employee in self.pos_basic_employee_ids: + self.pos_basic_employee_ids -= employee diff --git a/addons/pos_hr/static/src/app/navbar.js b/addons/pos_hr/static/src/app/navbar.js index 458099b0580..70559066583 100644 --- a/addons/pos_hr/static/src/app/navbar.js +++ b/addons/pos_hr/static/src/app/navbar.js @@ -1,9 +1,31 @@ /** @odoo-module */ import { Navbar } from "@point_of_sale/app/navbar/navbar"; -import { HeaderLockButton } from "@pos_hr/js/HeaderLockButton"; import { patch } from "@web/core/utils/patch"; -patch(Navbar, "pos_hr.Navbar", { - components: { ...Navbar.components, HeaderLockButton }, +patch(Navbar.prototype, "pos_hr.Navbar", { + get showCashMoveButton() { + const { cashier } = this.pos.globalState; + return this._super(...arguments) && (!cashier || cashier.role == "manager"); + }, + get showCloseSessionButton() { + return ( + !this.pos.globalState.config.module_pos_hr || + (this.pos.globalState.get_cashier().role === "manager" && + this.pos.globalState.get_cashier().user_id) || + this.pos.globalState.get_cashier_user_id() === this.pos.globalState.user.id + ); + }, + get showBackendButton() { + return ( + !this.pos.globalState.config.module_pos_hr || + (this.pos.globalState.get_cashier().role === "manager" && + this.pos.globalState.get_cashier().user_id) || + this.pos.globalState.get_cashier_user_id() === this.pos.globalState.user.id + ); + }, + async showLoginScreen() { + this.pos.globalState.reset_cashier(); + await this.pos.showTempScreen("LoginScreen"); + }, }); diff --git a/addons/pos_hr/static/src/app/navbar.xml b/addons/pos_hr/static/src/app/navbar.xml index 5cad81459e7..68538889ffd 100644 --- a/addons/pos_hr/static/src/app/navbar.xml +++ b/addons/pos_hr/static/src/app/navbar.xml @@ -4,18 +4,22 @@ - !pos.globalState.config.module_pos_hr or pos.globalState.get_cashier().role === 'manager' or pos.globalState.get_cashier_user_id() === pos.globalState.user.id + showBackendButton - !pos.globalState.config.module_pos_hr or pos.globalState.get_cashier().role === 'manager' or pos.globalState.get_cashier_user_id() === pos.globalState.user.id + showCloseSessionButton - + diff --git a/addons/pos_hr/static/src/js/Chrome.js b/addons/pos_hr/static/src/js/Chrome.js deleted file mode 100644 index 7a602646977..00000000000 --- a/addons/pos_hr/static/src/js/Chrome.js +++ /dev/null @@ -1,11 +0,0 @@ -/** @odoo-module */ - -import { Chrome } from "@point_of_sale/app/pos_app"; -import { patch } from "@web/core/utils/patch"; - -patch(Chrome.prototype, "pos_hr.Chrome", { - get showCashMoveButton() { - const { cashier } = this.pos.globalState; - return this._super(...arguments) && (!cashier || cashier.role == "manager"); - }, -}); diff --git a/addons/pos_hr/tests/test_frontend.py b/addons/pos_hr/tests/test_frontend.py index 4f8ab3867b2..f3bc4ab468f 100644 --- a/addons/pos_hr/tests/test_frontend.py +++ b/addons/pos_hr/tests/test_frontend.py @@ -44,7 +44,7 @@ class TestPosHrHttpCommon(TestPointOfSaleHttpCommon): (admin + emp1 + emp2).company_id = cls.env.company cls.main_pos_config.write({ - 'employee_ids': [Command.link(emp1.id), Command.link(emp2.id)] + 'basic_employee_ids': [Command.link(emp1.id), Command.link(emp2.id)] }) diff --git a/addons/pos_hr/views/pos_config.xml b/addons/pos_hr/views/pos_config.xml index f8e306afdda..10740a9b0d0 100644 --- a/addons/pos_hr/views/pos_config.xml +++ b/addons/pos_hr/views/pos_config.xml @@ -8,8 +8,12 @@
-
+
+
diff --git a/addons/pos_hr/views/res_config_settings_views.xml b/addons/pos_hr/views/res_config_settings_views.xml index 6868e696381..7ec8d329419 100644 --- a/addons/pos_hr/views/res_config_settings_views.xml +++ b/addons/pos_hr/views/res_config_settings_views.xml @@ -7,8 +7,12 @@
-
+
+