Branch
[FIX] stock: avoid O(n²) move-line scan when reserving serial products _update_reserved_quantity searches for an updatable move line per reserved quant via `next(l for l in self.move_line_ids if l._reservation_is_updatable(..))`. This scans the (growing) move_line_ids for every quant → O(n²) on a move of n serial units. But stock.move.line._reservation_is_updatable returns False unconditionally for tracking == 'serial', so the scan can never find a candidate and is pure waste.
[FIX] stock: soft correct unsynch between quant and stock.move.line It happens due to many reasons that the `stock.quant` object and `stock.move.line` loose their synchronisation and it could have a difference between the sum of `stock.move.line` and the quantity/reserved quantity on the `stock.quant` It's important to keep tracking why the desycnh happens and to fix all the root causes of it. However, it's hard for the user to clean the data himself or even worst to lock him when it happens (as before 18.0). For quantity: It's not a big deal to have a huge difference between the quantity and all the long time history. As in real life, the inventory adjustement can help to clean the data. For reserved quantity: It's a bigger problem since the user can't edit it. A first step would be to never write it to a negative value (since it should never happen). That way when the user empty the stock, it will also probably clean the reserved quantity. But in case where there is more reservation than on `stock.move.line`. We should also clean it to be able to reserve them. Currently, we will try in the scheduler for that part A last step, could be to create a constraint during test that ensure the synch is never broken and it could raise directly if the developer made a mistake
[FIX] stock: soft correct unsynch between quant and stock.move.line It happens due to many reasons that the `stock.quant` object and `stock.move.line` loose their synchronisation and it could have a difference between the sum of `stock.move.line` and the quantity/reserved quantity on the `stock.quant` It's important to keep tracking why the desycnh happens and to fix all the root causes of it. However, it's hard for the user to clean the data himself or even worst to lock him when it happens (as before 18.0). For quantity: It's not a big deal to have a huge difference between the quantity and all the long time history. As in real life, the inventory adjustement can help to clean the data. For reserved quantity: It's a bigger problem since the user can't edit it. A first step would be to never write it to a negative value (since it should never happen). That way when the user empty the stock, it will also probably clean the reserved quantity. But in case where there is more reservation than on `stock.move.line`. We should also clean it to be able to reserve them. Currently, we will try in the scheduler for that part A last step, could be to create a constraint during test that ensure the synch is never broken and it could raise directly if the developer made a mistake closes odoo/odoo#188201 Signed-off-by: William Henrotin (whe) <whe@odoo.com>
[FIX] pos_loyalty: keep reward lines on a finalized order Steps to reproduce: - Install pos_loyalty + pos_online_payment. - Configure an automatic discount program (e.g. 1% off the order) and an online payment method. - In the POS, add a customer eligible for the program and a product so the discount reward line is added automatically. - Pay the order with the online payment method and let the customer pay. Issue: The receipt printed right after the online payment is missing the loyalty discount line: the total is shown without the discount while the amount actually paid is the discounted amount, so the ticket looks underpaid. Re-printing the order later shows the correct total. With a loyalty program that also gives points, confirming the order additionally raises: ValueError: invalid literal for int() with base 10: 'false' Cause: After a successful online payment the order is rebuilt from the data saved on the server and selected again. Selecting an order triggers `_updateRewards`, which calls `_updateRewardLines` to refresh the applied rewards. On this rebuilt order the reward lines reference a coupon that is no longer in the local cache (its `coupon_id` comes back as `false` for "current" programs that don't persist a coupon), so `_updateRewardLines` removes them and cannot re-apply them. The order then displays a wrong total, and `_postPushOrderResolve` sends that `false` coupon id to `confirm_coupon_programs`, which fails when casting the key to an int. The order is already paid and saved: its reward lines are authoritative and must not be recomputed. Fix: - `_updateRewardLines`: do nothing on a finalized order (paid/done/invoiced) so the rewards saved on the server are kept as-is. - `_postPushOrderResolve`: skip reward lines that have no coupon, so no invalid coupon id is sent to `confirm_coupon_programs`.
[FIX] pos_loyalty: keep reward lines on a finalized order Steps to reproduce: - Install pos_loyalty + pos_online_payment. - Configure an automatic discount program (e.g. 1% off the order) and an online payment method. - In the POS, add a customer eligible for the program and a product so the discount reward line is added automatically. - Pay the order with the online payment method and let the customer pay. Issue: The receipt printed right after the online payment is missing the loyalty discount line: the total is shown without the discount while the amount actually paid is the discounted amount, so the ticket looks underpaid. Re-printing the order later shows the correct total. With a loyalty program that also gives points, confirming the order additionally raises: ValueError: invalid literal for int() with base 10: 'false' Cause: After a successful online payment the order is rebuilt from the data saved on the server and selected again. Selecting an order triggers `_updateRewards`, which calls `_updateRewardLines` to refresh the applied rewards. On this rebuilt order the reward lines reference a coupon that is no longer in the local cache (its `coupon_id` comes back as `false` for "current" programs that don't persist a coupon), so `_updateRewardLines` removes them and cannot re-apply them. The order then displays a wrong total, and `_postPushOrderResolve` sends that `false` coupon id to `confirm_coupon_programs`, which fails when casting the key to an int. The order is already paid and saved: its reward lines are authoritative and must not be recomputed. Fix: - `_updateRewardLines`: do nothing on a finalized order (paid/done/invoiced) so the rewards saved on the server are kept as-is. - `_postPushOrderResolve`: skip reward lines that have no coupon, so no invalid coupon id is sent to `confirm_coupon_programs`.
[FIX] im_livechat: prevent crash and stale window when leaving session Closing a livechat conversation fails when the visitor's guest context is no longer available (the `dgid` cookie expired, was cleared, is blocked as a third-party cookie on an embedded livechat, or the visitor is in private browsing). `/im_livechat/visitor_leave_session` resolves the visitor's `discuss.channel.member` through the `is_self` domain and calls `_rtc_leave_call()` on the result. Without a guest context the lookup returns an empty recordset, so `_rtc_leave_call()` hits `ensure_one()` and raises `Expected singleton: discuss.channel.member()`, returning a 500. The exception also prevents `_close_livechat_session()` from running, so the conversation stays open server-side. In addition, `LivechatService.leaveSession` removed the saved session from the storage in a `finally` block, after awaiting the `visitor_leave_session` RPC. When the visitor leaves the page right after closing the chat, the in-flight request is aborted and the page is torn down before the `finally` runs, so the stale session is restored on the next page load. Only call `_rtc_leave_call()` when a member is found, always close the livechat session afterwards, and clear the saved session synchronously before notifying the server.