Skip to Content
Hashem.sa
  • Home
  • Services
  • Odoo Notes
  • About
  • Contact us
  • 0
  • 0
  • ebraheem@brioche.me
  • الْعَرَبيّة English (US)
  • Sign in
  • Contact Us
Hashem.sa
  • 0
  • 0
    • Home
    • Services
    • Odoo Notes
    • About
    • Contact us
  • ebraheem@brioche.me
  • الْعَرَبيّة English (US)
  • Sign in
  • Contact Us

Stop POS Staff Deleting Kitchen-Sent Lines in Odoo 19

Access rights cannot stop it. Here is the reason, and the control that works.
  • All Blogs
  • Odoo Notes
  • Stop POS Staff Deleting Kitchen-Sent Lines in Odoo 19
  • August 18, 2026 by
    Stop POS Staff Deleting Kitchen-Sent Lines in Odoo 19
    Ebraheem Hashem

    A waiter fires four covers to the kitchen, the guest changes their mind, and the waiter clears the line off the ticket. The food is already being cooked. The order that reaches the till is short one item, and the difference walks out of the building. In stock Odoo 19 this takes two taps of the numpad backspace, requires no approval from anyone, and leaves no record that a manager is likely to ever look at.

    The usual fix — take away delete rights on pos.order.line — does not work, and the reason is structural rather than a misconfiguration. The Point of Sale client edits the order in memory and syncs the result, so a removed or emptied line reaches the server as a write, not an unlink. Access rights never get the chance to fire. What does work is a check inside the flow itself: POS Kitchen-Sent Line Lock requires a server-verified employee or manager PIN before a kitchen-sent line can be deleted or reduced, and logs the attempts — accepted and rejected alike.

    Before Sendedit freely, no frictionSendkitchen is cookingDelete or reduce→ server-verified PINEvery decision→ audit log rowCHECKOUT IS NEVER BLOCKED, DELAYED OR ROLLED BACK
    The gate sits after the kitchen send and nowhere else. Corrections before the send stay frictionless.

    What Odoo 19 actually does out of the box

    Press Send in a restaurant POS and Odoo records what went to the kitchen in last_order_preparation_change on pos.order — a JSON blob keyed per line. That field is a synchronisation aid, not a record. When a line is deleted, updateLastOrderChange() removes the corresponding entry: the client's own comment describes checking whether a line has been deleted since it was last sent and, if so, deleting the older change. The evidence tidies itself up.

    Deleting the line calls removeOrderline(), which checks only assertEditable() — and that blocks nothing except orders already finalised. point_of_sale/security/ir.model.access.csv grants group_pos_user full create, read, write and unlink on pos.order.line. There is a hook that could have prevented all of this, disallowLineQuantityChange() in pos_store.js. In 19.0 it returns false and is not overridden anywhere in point_of_sale, pos_restaurant, pos_hr or pos_hr_restaurant. Odoo left the door and never hung a lock on it.

    Odoo does half-guard the case. Long-press a sent line and you get a dialog titled “Cannot edit orderline” — “This orderline has already been sent to the kitchen and cannot be edited.” That blocks the configure dialog. It does not block deleting the line, and it does not block dragging the quantity down. Deleted items do reprint under a CANCELLED heading on the next preparation ticket, which is paper, in the kitchen, and only if somebody triggers another send.

    There is also one native audit, and it is worth knowing about before you buy anything: pos.config.order_edit_tracking, labelled Track orders edits. It is a per-POS boolean, off by default, and appears in none of the 44 POS documentation files shipped with 19.0. Switched on, it posts a chatter message when a line is deleted and sets a has_deleted_line flag the client cannot clear. That is genuinely useful — but it is retrospective, it logs the Odoo user rather than the pos_hr employee who was on shift, and it knows nothing about whether the line had been sent to the kitchen. It tells you afterwards that something happened. It does not ask anyone for permission first.

    Why the obvious workarounds fail

    Access rights. The most-shared forum recipe — uncheck delete on pos.order.line for the POS user group, add an intermediate group, re-parent the inheritance — is publicly reported as not working, across multiple versions. The cleanest explanation on the forum puts it plainly: preventing deletion via access rights does nothing, because the cancel action is, from the ORM's point of view, just another write. You have to catch it in the method.

    pos_hr PINs. Employee PINs exist, but checkPin() is called only from cashier selection. It is a login gate. There is no native “enter a manager PIN to approve this action” flow anywhere in POS 19.0.

    Employee rights tiers. Minimal, Basic and Advanced are too coarse. Minimal cannot press the minus key at all, which also stops legitimate corrections before the send. Nothing in between distinguishes “before the kitchen saw it” from “after”.

    Editing the core JS. One forum user resolved this by hand-editing navbar.xml in core. It works until the next upgrade, and then it is your problem.

    Reviewing reports the next morning. By then the shift is over, the till is counted, and nobody can reconstruct who cleared what. Loss prevention that runs a day late is bookkeeping, not prevention.

    What the module does

    It gates the three gestures that cost money. Removing a sent line from the numpad while it is in quantity mode. Reducing a sent line below the quantity already sent, through the quantity dialog. Deleting or cancelling a draft order that contains sent lines. Each of those requires a valid employee PIN before it proceeds. Those are the paths a waiter uses on a busy floor; a module hooking three specific client actions is not the same as a database-level constraint, and you should read it as a floor control rather than as a guarantee against a determined developer with API access.

    The PIN is verified on the server. Authorisation goes through pos.config.verify_sent_delete_pin, compared with a constant-time check. No employee PIN material is shipped to the browser or compared there, so a cashier cannot read a manager PIN out of the POS client or lift it from devtools. This is the difference between a control and a speed bump — several competing modules in this category do the comparison client-side in under a hundred lines of JavaScript.

    Attempts are logged, accepted and rejected alike. The log lives at Point of Sale → Orders → Sent-Item Deletion Log (eh.pos.sent.delete.log) and records when, which POS and session, which action, and the product or order involved. On accepted attempts it records the authorising employee; a rejected attempt has no verified identity to record, so that field is empty by design. The log is manager-readable and cannot be created, edited or deleted from its own views. Logging is best-effort and can never block or roll back a sale. One honest detail: a successful authorisation opens a short reuse window — about eight seconds — so a manager correcting two lines in a row is not asked twice; the follow-up action inside that window is allowed without a second server call, and therefore without a second log row.

    It fails closed. If the server cannot be reached to verify the PIN, the deletion is blocked — never silently allowed. This has a real consequence worth stating up front: because verification is server-side, authorising a sent-item deletion needs the POS to be online at that moment.

    It never touches checkout. The control applies only to deleting or reducing an already-sent item. It does not block, delay or roll back an actual payment, and offline selling is unaffected.

    Configured per Point of Sale. Two settings: Restrict deletion of sent items, and Manager PIN only — which is on by default, so out of the box only managers can authorise. “Manager” means the POS's Employees with manager access list, falling back to the PoS Manager group if that list is empty, so the control cannot lock an entire restaurant out of its own till. Switch manager-only off and any employee allowed on that POS can authorise with their own PIN, which is what you want where a shift leader is not a system manager.

    What it does not do

    It does not restrict anything before the kitchen sees the item. Correcting a mistyped line before pressing Send stays frictionless, which is deliberate.

    It does not cover discounts, voids after payment, refunds, cash-drawer opens or shift-close controls. Those are a broader loss-prevention problem and a different, larger product.

    It does not work offline for the authorisation step, for the reason given above. And it does not replace order_edit_tracking — you can run both; they answer different questions.

    Requirements: Odoo 19.0, with point_of_sale, pos_hr and pos_restaurant. Multi Employees per Session must be enabled so employee PINs are available, and the relevant employees need a PIN on their HR record. No Enterprise dependency. Published for the 17.0, 18.0 and 19.0 series.

    How to use it

    1. Install the module.
    2. Point of Sale → Settings, pick the POS at the top of the page, and enable Multi Employees per Session.
    3. In the same section, enable Restrict deletion of sent items. Manager PIN only is already on — turn it off if you want shift leaders to authorise with their own PIN. Repeat per POS.
    4. Make sure the employees who should be able to authorise have a PIN set on their HR record (Employee → HR Settings → PIN Code).

    The module ships with tests covering manager-accept, wrong-PIN reject, manager-only filtering, feature-off short-circuit and blank-PIN safety, so you can prove the behaviour on your own rig before you trust it on a Friday service:

    odoo -d <db> -i eh_pos_sent_line_lock --test-enable --stop-after-init

    Where it sits against the alternatives

    The category on 19.0 runs from roughly $24 to $260 and, unusually, not one listing I checked carries a single rating. The cheap end is small client-side patches, some with unresolved “does not work” complaints from confirmed purchasers. The expensive end adds per-action PIN toggles across the whole POS. At $49 this is deliberately narrow: one problem — the kitchen-sent line — solved server-side, with an audit trail.

    FAQ

    Can Odoo access rights stop a POS user deleting an order line?

    No. Removing delete rights on pos.order.line does not work, because the POS client edits the order in memory and syncs it — from the ORM's point of view a cancelled or emptied line is a write, not an unlink. Odoo also grants group_pos_user full create, read, write and unlink on pos.order.line by default. This workaround is widely reported on the forum as ineffective.

    Does Odoo 19 track POS order edits natively?

    Partly. There is an undocumented per-POS setting called Track orders edits (pos.config.order_edit_tracking) that is off by default. When enabled it posts a chatter message when a line is deleted and sets a has_deleted_line flag. It is retrospective rather than preventive, records the Odoo user rather than the POS employee, and carries no kitchen-sent context.

    Doesn't Odoo already block editing a line sent to the kitchen?

    Only partly. Long-pressing a sent line raises a dialog titled “Cannot edit orderline” saying it has already been sent to the kitchen. That blocks the configure and edit dialog. It does not block deleting the line and it does not block reducing its quantity.

    Where does the PIN come from, and can a cashier read it?

    The PIN is the employee PIN on the HR record. It is verified server-side through pos.config.verify_sent_delete_pin with a constant-time comparison, so no PIN material is sent to or compared in the browser and a cashier cannot read a manager PIN out of the POS client. It is a floor control, not a cryptographic barrier — treat POS PINs as you would till codes.

    What happens if the POS goes offline?

    The deletion is blocked. The module fails closed and never silently allows the action. Because verification happens on the server, authorising a sent-item deletion requires the POS to be online at that moment. It never blocks, delays or rolls back an actual checkout.

    Can any employee authorise, or only managers?

    Both are supported, per Point of Sale. Manager PIN only is on by default, so out of the box only managers can authorise — defined as the POS's Employees with manager access list, falling back to the PoS Manager group if that list is empty, so the control can never lock everyone out. Switch it off and any employee allowed on that POS can authorise with their own PIN.

    Get it

    POS Kitchen-Sent Line Lock — Manager PIN + Tamper-Proof Audit — $49 USD, one-time, on the Odoo Apps Store: apps.odoo.com/apps/modules/19.0/eh_pos_sent_line_lock

    Available for the 17.0, 18.0 and 19.0 series. Licensed OPL-1. Includes 90 days of support by email at ebraheem@brioche.me — questions answered within 24 hours. One purchase covers one Odoo major version.

    Built for a live restaurant group in Saudi Arabia running Odoo 19 in production, across real Friday-night services, then generalised for sale.

    POS Kitchen-Sent Line Lock — Manager PIN + Audit

    $49 USD — one-time, on the Odoo Apps Store

    Odoo 17.0, 18.0 and 19.0 · Licensed OPL-1 · 90 days of support included · One purchase covers one Odoo major version.

    Get it on the Odoo Apps StoreAsk a question first

    Need this fitted to your business, not just installed?

    EHC takes on consultancy, projects and ongoing services — Odoo implementation, process and controls design, data migration, and custom development like the module above.

    What EHC doesEmail Ebraheem
    in Odoo Notes
    How to Hide Product Variants on an Odoo 19 Website
    Unpublishing a variant unpublishes the whole product. Here is what actually works.

    Have a system that is not telling you the truth?

    Let's look at it together.

    Email

    ebraheem@brioche.me

    What EHC does

    Services, consultancy and projects

    Written work

    Odoo Notes

    EHC · hashem.sa
    • Home
    • •
    • Services
    • •
    • Odoo Notes
    • •
    • About
    • •
    • Contact
    • •
    • Privacy Policy
    Copyright © EHC · Ibrahim Mahmoud Hashim Trading One Person Company · Unified no. 7037243677
    الْعَرَبيّة | English (US)
    Powered by Odoo - The #1 Open Source eCommerce