feat: enforce PIN on order load and improve employee attribution logic for POS orders
This commit is contained in:
parent
1d7162cf61
commit
16e5e25c76
@ -5,6 +5,7 @@ This Odoo 19 module enhances the security and auditability of the Point of Sale
|
||||
## Features
|
||||
|
||||
- **Mandatory PIN on Table Selection**: Prevents unauthorized access to tables. Every table selection triggers a PIN prompt to identify the employee taking the order.
|
||||
- **Mandatory PIN on Load Order**: Enforces PIN entry when a draft order is loaded/resumed from the Orders tab (`TicketScreen`).
|
||||
- **Mandatory PIN on Payment**: Requires PIN authentication before processing payments to ensure the transaction is handled by an authorized employee.
|
||||
- **Role-Based Payment Gating**: Cross-checks employee roles (using `pos_employee_role`) to prevent roles like 'waiter' from processing payments.
|
||||
- **Order Attribution**:
|
||||
@ -15,6 +16,7 @@ This Odoo 19 module enhances the security and auditability of the Point of Sale
|
||||
- Hides the "Course" button on the POS UI.
|
||||
- Hides the "Transfer Course" button on the POS UI.
|
||||
- Hides the save order for later (upload icon) button from the POS UI.
|
||||
- Hides the "Set Table" button from Register/Direct Sale orders.
|
||||
|
||||
## Dependencies
|
||||
|
||||
|
||||
21
static/src/app/models/pos_order.js
Normal file
21
static/src/app/models/pos_order.js
Normal file
@ -0,0 +1,21 @@
|
||||
import { PosOrder } from "@point_of_sale/app/models/pos_order";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(PosOrder.prototype, {
|
||||
setup(vals) {
|
||||
super.setup(...arguments);
|
||||
if (vals.employee_id) {
|
||||
this.original_employee_id = this.models["hr.employee"].get(vals.employee_id.id || vals.employee_id) || vals.employee_id;
|
||||
} else if (this.employee_id) {
|
||||
this.original_employee_id = this.employee_id;
|
||||
}
|
||||
},
|
||||
|
||||
serializeForORM(opts = {}) {
|
||||
const data = super.serializeForORM(opts);
|
||||
if (this.original_employee_id) {
|
||||
data.employee_id = this.original_employee_id.id || this.original_employee_id;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
});
|
||||
@ -4,6 +4,9 @@
|
||||
<xpath expr="//button[hasclass('pay-order-button')]" position="attributes">
|
||||
<attribute name="t-if">pos.canPay</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//button[hasclass('set-table')]" position="replace">
|
||||
<!-- Hidden "Set Table" button on Register order -->
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
<t t-name="pos_custom_access.ProductScreen" t-inherit="point_of_sale.ProductScreen" t-inherit-mode="extension">
|
||||
|
||||
26
static/src/app/screens/ticket_screen/ticket_screen.js
Normal file
26
static/src/app/screens/ticket_screen/ticket_screen.js
Normal file
@ -0,0 +1,26 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { TicketScreen } from "@point_of_sale/app/screens/ticket_screen/ticket_screen";
|
||||
|
||||
patch(TicketScreen.prototype, {
|
||||
async setOrder(order) {
|
||||
// Enforce PIN entry when loading/selecting an order from the TicketScreen (Orders tab)
|
||||
const cashier = await this.pos._selectCashierByPin();
|
||||
if (!cashier) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pos.setCashier(cashier);
|
||||
|
||||
// Ensure the order has its original employee id preserved when loading
|
||||
if (order) {
|
||||
if (!order.original_employee_id) {
|
||||
order.original_employee_id = order.employee_id || cashier;
|
||||
}
|
||||
order.uiState.is_authorized = true;
|
||||
}
|
||||
|
||||
return super.setOrder(order);
|
||||
}
|
||||
});
|
||||
@ -67,6 +67,39 @@ patch(PosStore.prototype, {
|
||||
return super.pay();
|
||||
},
|
||||
|
||||
createNewOrder() {
|
||||
const order = super.createNewOrder(...arguments);
|
||||
if (order && this.config.module_pos_hr) {
|
||||
order.original_employee_id = this.getCashier();
|
||||
}
|
||||
return order;
|
||||
},
|
||||
|
||||
setCashier(employee) {
|
||||
super.setCashier(...arguments);
|
||||
const order = this.getOrder();
|
||||
if (order && !order.getOrderlines().length) {
|
||||
order.original_employee_id = employee;
|
||||
}
|
||||
},
|
||||
|
||||
addLineToCurrentOrder(vals, opt = {}, configure = true) {
|
||||
const order = this.getOrder();
|
||||
if (order && !order.original_employee_id) {
|
||||
order.original_employee_id = order.employee_id || this.getCashier();
|
||||
}
|
||||
|
||||
const res = super.addLineToCurrentOrder(...arguments);
|
||||
|
||||
if (order && order.original_employee_id) {
|
||||
order.employee_id = order.original_employee_id;
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
|
||||
|
||||
|
||||
async _selectCashierByPin() {
|
||||
if (!this.config.module_pos_hr) {
|
||||
return this.getCashier();
|
||||
|
||||
14
static/src/app/utils/order_payment_validation.js
Normal file
14
static/src/app/utils/order_payment_validation.js
Normal file
@ -0,0 +1,14 @@
|
||||
import OrderPaymentValidation from "@point_of_sale/app/utils/order_payment_validation";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(OrderPaymentValidation.prototype, {
|
||||
async validateOrder(isForceValidate) {
|
||||
const originalEmployeeId = this.order.original_employee_id || this.order.employee_id;
|
||||
|
||||
await super.validateOrder(...arguments);
|
||||
|
||||
if (originalEmployeeId) {
|
||||
this.order.employee_id = originalEmployeeId;
|
||||
}
|
||||
},
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user