diff --git a/README.md b/README.md
index 9dae9aa..22b409d 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/static/src/app/models/pos_order.js b/static/src/app/models/pos_order.js
new file mode 100644
index 0000000..3ad37de
--- /dev/null
+++ b/static/src/app/models/pos_order.js
@@ -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;
+ }
+});
diff --git a/static/src/app/screens/product_screen/action_pad/action_pad.xml b/static/src/app/screens/product_screen/action_pad/action_pad.xml
index 5baaf78..62c0ed1 100644
--- a/static/src/app/screens/product_screen/action_pad/action_pad.xml
+++ b/static/src/app/screens/product_screen/action_pad/action_pad.xml
@@ -4,6 +4,9 @@
pos.canPay
+
+
+
diff --git a/static/src/app/screens/ticket_screen/ticket_screen.js b/static/src/app/screens/ticket_screen/ticket_screen.js
new file mode 100644
index 0000000..72f84f2
--- /dev/null
+++ b/static/src/app/screens/ticket_screen/ticket_screen.js
@@ -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);
+ }
+});
diff --git a/static/src/app/services/pos_store.js b/static/src/app/services/pos_store.js
index c53e29a..1c2964d 100644
--- a/static/src/app/services/pos_store.js
+++ b/static/src/app/services/pos_store.js
@@ -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();
diff --git a/static/src/app/utils/order_payment_validation.js b/static/src/app/utils/order_payment_validation.js
new file mode 100644
index 0000000..afaf506
--- /dev/null
+++ b/static/src/app/utils/order_payment_validation.js
@@ -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;
+ }
+ },
+});