Tuesday, September 2, 2025
8 changes · saas-18.2
Resolved issues and error corrections
Partial refunds in Point of Sale now correctly recognize when an order is a refund, even if the reward line itself is not refunded. This prevents customers from losing loyalty points a second time when only some purchased items are refunded.
Original PR description
**Steps to reproduce:** - Make a purchase in POS using a reward such as $1 for every point - Refund this purchase, but not the reward line - The points are deducted again **Problem:** When refunding an order that has some rewards in it, but not refunding the reward line, the loyalty points used for the order will be used again. This only happens if we don't refund the reward line. **Why the fix:** By not refunding the reward line, the order was not treated as a refund, as we only checked if the reward line had a refunded_qty. So if we refund another product, the reward line will still be found, but the refund_qty will be 0, so it is treated as a non-refund line. We now check if the current order is a refund before altering the points. If it is a refund, we do not make the customer pay the points again. opw-4771724
Unbuild operations no longer force their cost to match the original manufacturing order when product costs have changed. Instead, Odoo records a corrective journal entry for any cost difference, keeping inventory valuation and average product costs aligned.
Original PR description
**Current behavior:** Since https://github.com/odoo/odoo/commit/84dda968146d2f3743ab7fc516300e50780725e3, we valuate an unbuild operation by attempting to match the ensuing OUT layer with the IN…
**Current behavior:** Since https://github.com/odoo/odoo/commit/84dda968146d2f3743ab7fc516300e50780725e3, we valuate an unbuild operation by attempting to match the ensuing OUT layer with the IN layer from the original MO. The point being to eliminate a potential valuation imbalance for the manufactured product (might affect cost, etc.). **New behavior** Don't attempt to match an unbuild valuation layer with the original MO valuation layer. If there is some cost difference between build time and unbuild time, make a corrective journal entry for it. **Issue with current behavior** The following sequence: 1. Create Product A with average costing, real-time valuation 2. Create 2 components, avg costing, real-time val 3. Create a BoM for Product A with the components 4. Manufacture 3 units of Product A with different component quantities (can set flexible consumption on BoM) 5. Unbuild the first manufactured unit Results in Product A's cost not matching the expected average cost according to the valuation layers. **Cause of the issue:** Unbuilding the first MO created an out move at the original "build time" cost, but since we've built 2 additional qty, that original cost is not the current average cost- thus the "theoretically current" standard price of the product (sum of layers value divided by remaining qty) is no longer the value we see on the product form. **Fix:** Don't try and match the valuation layers. Aside from issues such as the one described above, it might not actually make functional sense to do so (e.g., FIFO isn't actually adhering to first-in-first-out if we're preferring the original IN layer for an unbuild valuation). Instead we make a journal entry with any excess cost of production (it was actually a solution proposed in the discussion on https://github.com/odoo/odoo/commit/84dda968146d2f3743ab7fc516300e50780725e3 in the first place). Additionally, now that we aren't doing this mapping, we can revert the non-test difference of https://github.com/odoo/odoo/commit/3a69456a291da593748475c86e7efc6234019e47, as this commit was fixing an issue introduced by the change which added the mapping. opw-[4877597](https://www.odoo.com/web#id=4877597&view_type=form&model=project.task) Forward-Port-Of: odoo/odoo#222014 Forward-Port-Of: odoo/odoo#221718
This fix prevents some public-facing pages, such as room booking and kiosk app screens, from appearing blank during loading. It ensures the page can still initialize correctly when a usual page wrapper is missing, improving reliability for affected users.
Original PR description
**Before this PR:** The screen appears blank in places like meeting room booking view, install kiosk app page (events, attendance, rooms, frontdesk), etc. **Version:** Although this issue exists in future versions, it is fixed in the version where public interactions are introduced. **Technical reason:** The issue was introduced by this commit: https://github.com/odoo/odoo/commit/dd13994674d4ef4683f5a4d46a1f604650cfb92b Happens while loading frontend assets. Here, if `#wrapwrap` is absent in dom then interaction service is not started and returned as a null. Now we keep `body` as a fallback of `#wrapwrap`. **After this PR:** The screen will load correctly and will no longer be blank. Task-4915155
Analytic plans are now processed in parent-first order during setup, preventing installation failures when child plans already exist. This helps ensure the Project app installs reliably for databases using hierarchical analytic plans.
Original PR description
When installing the `project` module, `_sync_plan_column(self, model)` is called for all existing analytic plans. The method iterates through `self` in arbitrary order, which means a child plan can…
When installing the `project` module, `_sync_plan_column(self, model)` is called for all existing analytic plans. The method iterates through `self` in arbitrary order, which means a child plan can be processed before its parent. In such a case, the code tries to create a related field pointing to a parent-level column that does not yet exist, leading to errors like: `Field name "x_plan26_id" unknown for related field "x_plan26_id.plan_id"` This happened because `self` was iterated without guaranteeing that parents are processed first. As a result, the related field chain (`.plan_id.parent_id...`) could reference missing intermediate fields. The fix is ordering the recordset by `parent_path`. Steps to reproduce: 1. In Odoo Inspector, search for model `account.analytic.plan`. and go to records. 2. Create a first plan. 3. Create a second plan and set the first plan as its parent. 4. Install the `project` app (triggers `_sync_plan_column`). 5. Observe the crash due to an unknown related field. OPW-5006494 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#224509
The tax report now correctly loads required accounting data when its root report is changed. This prevents a server error and lets accounting users open the report without interruption.
Original PR description
**[FIX] account_reports: ensure join on account_move for tax report base amount calculation** Fixes a server error in the generic tax report where `account_move_line__move_id` was referenced without an explicit join. The fix adds a conditional join on `account_move` to make fields like `always_tax_exigible` available, preventing `UndefinedTable` during SQL execution. Steps to reproduce: 1 - in a fresh db or runbot go to `Accounting > Config > Accounting Reports`. 2 - Open the Tax Report and change the `Root Report` to Balance Sheet. 3 - Save and try to open the tax report. opw-4990771 Forward-Port-Of: odoo/enterprise#91941
Uploading a replacement file for a document now shows progress on the original document instead of creating a duplicate card or row. This makes document updates clearer for users and avoids confusion during request uploads or version management.
Original PR description
Step to reproduce: 1. Upload a file to a request: - Create a Request. - Upload a file for that request. - Another Kanban card / List row is created showing the upload progression. 2. Upload a file into the manage version dialog. - Manage version for an existing document. - Upload a new document. - Another Kanban card / List row is created showing the upload progression. The upload progression should be shown on the existing document. Task-4863051 Forward-Port-Of: odoo/enterprise#87428
This fixes an issue where disabled Urban Piper delivery providers were automatically re-enabled after returning to an active point of sale session. Provider status is now kept consistently in the backend, preventing unwanted online availability and avoiding extra update requests when resuming sales.
Original PR description
Steps to reproduce: - Configure urban piper in pos.config - Open Register - You could see a notification that providers are online on your config - Disable any one provider. - Go to backend. - Click Continue Selling Issue: - Despite disabling the provider, all providers get enabled as soon as we resume the pos.config Cause: - Not updating togglestate properly while going to the backend. - Unnecessary api request when resuming session. Fix: - Not removing the toggleState from local storage as the user go to the backend - When the user resumes the session, restrict api request for location update. - Remove dependency from local storage and handling all through backend only. task- 4962969 Forward-Port-Of: odoo/enterprise#90987
When a blackbox device is unplugged and plugged back in, the system now recognizes it as the same device even if the Raspberry Pi assigns a different connection port. This prevents existing device settings from being lost and avoids duplicate device records.
Original PR description
Before this commit, if a blackbox was unplugged and re-plugged, and it was assigned a different serial port by the Raspberry Pi, it would show up as a new device in the database meaning the existing…
Before this commit, if a blackbox was unplugged and re-plugged, and it was assigned a different serial port by the Raspberry Pi, it would show up as a new device in the database meaning the existing configuration wouldn't work. After this commit, we handle the blackbox as a special case, and if the name of the device matches exactly with our existing blackbox, we update its identifier instead of creating a new device. This does require a new device specific check in the controller which is quite ugly. Another approach would have been to make the identifier of the blackbox equal its FDM ID instead of the serial port, but this was not done for the following reasons: - Changing the identifier format in stable would cause all existing clients' blackboxes to become unconfigured once their IoT box restarts. - Making the identifier different to the serial port would require a hack in the blackbox driver to change its own identifier and update the devices dictionary, since the serial interface assumes all devices use the port as their identifier. task-5055027 Forward-Port-Of: odoo/enterprise#93593