Friday, November 21, 2025
17 changes · saas-18.4
New functionality added to Odoo
This change adds support for carrying customer and checkout details from the online store into Taiwan e-invoices. It helps ensure invoices are created with the right information automatically, reducing manual entry and the risk of errors.
Original PR description
This module adds extra functions on the website sale for l10n_tw_edi_ecpay, passing values from e-commerce to invoice for creating Taiwan E-invoice task-5122489 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#236548 Forward-Port-Of: odoo/odoo#228989
Enhancements to existing features
This change makes Odoo’s automatic database column conversion more conservative and predictable. It avoids unnecessary background recomputation during upgrades, which helps reduce upgrade time and limits the automatic handling to simpler cases that are less likely to cause issues.
Original PR description
The auto column conversion should be limited to simple and intuitive use cases. It shouldn't trigger the slow ORM recomputation if the field is computed. We always expect an upgrade script to handle…
The auto column conversion should be limited to simple and intuitive use cases. It shouldn't trigger the slow ORM recomputation if the field is computed. We always expect an upgrade script to handle more complex use cases.
This commit introduces two changes:
### 1. Removal of `drop_not_null` during auto column conversion
Before https://github.com/odoo/odoo/commit/50767ef90eadeca2ed05b9400238af8bdbe77fb3 We dropped the not_null constraint because the original column would be renamed. After that commit, we actually don't need to drop the not_null constraint since the `convert_column` will neither convert a not-null value to `null` nor convert 'null' to a not-null value. Keeping the not_null constraint shouldn't block the column convert.
### 2. Removal of `column.clear()`
When a computed/related Float field is changed from `digits=None` to `digits='xxx'`, the `column.clear()` will trigger ORM recomputation during upgrade which is useless since `double precision` to `numeric` is lossless. The recomputation in ORM is slow and should be avoided. If the rerounding is really needed, a sql script is required for upgrade or installation.
The `column.clear()` was originally introduced to avoid `Missing not-null constraint` warnings in specific scenarios:
Case 1 (Upgrade Warning): from saas-18.4 to 19.0
old database: Selection field `l10n_be.export.sdworx.leaves.wizard.reference_year` upgrade: pre-migrate `util.rename_model(cr, "l10n_be.export.sdworx.leaves.wizard", "l10n.be.hr.payroll.export.sdworx")` new database: Integer field `l10n.be.hr.payroll.export.sdworx.reference_year` The column value which was a required stringified integer is auto-converted to an integer.
Case 2 (Installation Warning):
In pos_urban_piper, the required field `pos.config.name` is overridden from `translate=False` to `translate=True`. The column value which was a required text is auto-converted to `'{"en_US": "text"}'::jsonb`
The not_null constraint was previously lost by the `sql.drop_not_null` in `update_db_column` and is not restored by `update_db_notnull` because of the inconsistency between the variable `column['is_nullable']` and the actual not_null constraint in the database.
Thanks to change 1, we will no longer lose the not_null constraint in `update_db_column`. The constraint can be kept even without `column.clear()`.
By removing the `column.clear()`, we also revert the meaning of the `column` variable, which is the column's configuration (dict) before `update_db` if it exists, or `None`
Description of the issue/feature this PR addresses:
Current behavior before PR:
Desired behavior after PR is merged:
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#236299Resolved issues and error corrections
This fix corrects a configuration error in the Uruguayan e-invoicing stock flow that was causing a build failure. It helps ensure stock-related electronic document processing works as expected and avoids interruptions during deployment and validation.
Original PR description
runbot build error id: 234034 Forward-Port-Of: odoo/enterprise#99920
This update clears existing product menu connections in UrbanPiper and runs a fresh synchronization. It helps ensure the menu shown to customers matches the latest Odoo data and reduces issues caused by outdated links.
Original PR description
Following this commit: - Flush out all existing UrbanPiper product menu linkages and performs a fresh menu sync. task-5231247 Forward-Port-Of: odoo/enterprise#98994
This fix prevents Odoo from showing an error traceback when the Egyptian e-invoice service rejects a request and returns a response that cannot be read as JSON. Instead, the error is now handled properly, giving users a smoother and more reliable invoicing experience.
Original PR description
Before this commit: Steps 1) When clients try to download e-invoice for ETA 2) If ETA rejects the request, Odoo fails to parse to JSON 3) a JSONDecodeError exception is raised 4) Odoo doesn't catch it and a traceback is raised => A JSONDecodeError is raised but actually it's not json.decoder.JSONDecodeError, it's actually requests.exceptions.JSONDecodeError as mentioned here https://requests.readthedocs.io/en/latest/api/#requests.JSONDecodeError After this commit: If the request is rejected and Odoo failed to parse the response to JSON the exception is catched properly. opw-5241411 opw-5272195 Forward-Port-Of: odoo/odoo#236672
This change improves compatibility with Swedish cash register blackboxes by checking which protocol version they support during setup. As a result, receipts can be registered without triggering an "unknown message type" error on devices that only support the older protocol version.
Original PR description
The serial protocol used with the Swedish blackbox has 2 versions, with v2 adding some more commands. Before this commit, we assumed that the blackbox was compatible with v2, causing an 'unknown message type' error if it only supported v1. After this commit, we check the protocol version of the blackbox when we initialise the driver, so that we only send compatible commands when we register a receipt. opw-5077448 Forward-Port-Of: odoo/enterprise#99930 Forward-Port-Of: odoo/enterprise#99008
This update prevents the restaurant point of sale from creating a new order too early after a payment when preview skipping is enabled. It avoids errors on the floor plan and makes the checkout flow more reliable when using printers and preset selections.
Original PR description
**Steps to reproduce:** - In the config, click the ePos Printer checkbox - Also check Automatic Receipt Printing and Skip Preview Screen - Put a default preset with Name as it's identification - Go…
**Steps to reproduce:** - In the config, click the ePos Printer checkbox - Also check Automatic Receipt Printing and Skip Preview Screen - Put a default preset with Name as it's identification - Go in the restaurant and make a sale, pay for it - When going back to the floor plan, a traceback appears **Why the fix:** This current problem arises because we are trying to access the current order, but we are on the floor plan, so there is no current order yet. The order is undefined, so we try to access *undefined.floating_order_name* and a traceback appears. But the root issue is deeper than this. In the restaurant, the order is initialized when clicking a table, or when we create a floating order. But when the Skip Preview Screen option is enabled, we try to initialize the order right after the last order has been validated, like we do it in the normal PoS. Doing this, we will try to handle the preset selection way too early, as the order is not fully initialized yet, and we will try to access data that have not been set yet. The current error is not the only one we have with this setup, as other errors also arise if we bypass this specific error. To fix this, we are now only initilizing the new order when we click on a table that has no order or when making a floating order. We do not create a new order after the validation of the last one, even if the Skip Preview Screen option is enabled. This is only true in the restaurant, as we keep on initializing a new order after the validation in the regular PoS. Before this commit, we also tried to create a new order when opening the restaurant from the frontend (see image below), which resulted in a traceback. We now only create a new order if the default screen is different from the Floor Screen. <img width="375" height="249" alt="image" src="https://github.com/user-attachments/assets/e38520f6-81e2-471e-a987-98d9426a6493" /> Starting in version 19.0, there is another waiting screen after paying and before going back to the floor plan, which handles things, so the bug is not present anymore. But the traceback we get when opening the register from the frontend is still present in future versions. opw-5131309
This fix stops users from creating the same RFQ more than once when several tabs or users are working on the same approval. It helps avoid duplicate purchase quantities and prevents accidental over-ordering.
Original PR description
**Problem:** It's possible to click the "Create RFQ's" button more than once, as the user may have multiple tabs open or multiple users are viewing the same record. When this happens, the approval will create or add to an RFQ even if it already did, and this causes double the intended product quantities. **Solution:** The "Create RFQ's" button becomes hidden when purchase_order_count > 0 (i.e. there are linked POs) so we can perform this check within the button's method `action_create_purchase_orders` to prevent RFQ generation (or modification). opw-5227493 Forward-Port-Of: odoo/enterprise#99817 Forward-Port-Of: odoo/enterprise#99706
This update corrects how Italian EDI imports handle “Maggiorazione” discounts on vendor bills and credit notes. It prevents the line total from flipping sign or calculating incorrectly, so imported documents show the right amounts.
Original PR description
Since commit #206238, discounts of type "MG" (Maggiorazione) caused the line total amount sign to flip, leading to incorrect calculations of the total amount. **Steps to reproduce:** - Import a vendor bill/credit note XML (Italian EDI). - Include a line with a Maggiorazione discount. - The line total amount currently appears with the wrong sign and/or amount. Ticket [link](https://www.odoo.com/odoo/project.task/5220218) opw-5220218 Forward-Port-Of: odoo/odoo#236300
This update corrects the invoiced quantity on sales orders when a POS order is refunded from the backend. It ensures the sales order stays accurate after refunds, which helps avoid billing and reporting mismatches.
Original PR description
When doing a refund of a POS order linked to a SO in the backend, the qty_invoiced on the SO line is not updated correctly. Steps to reproduce: ------------------- * Create a SO with 1 quantity of any product * Settle the SO in the PoS * Refund the PoS order from the backend not from the PoS interface * Check the qty_invoiced on the SO line > Observation: The qty_invoiced is still 1 Why the fix: ------------ The method _compute_qty_invoiced was not triggered when the refunding order was paid. So we need to add a new dependency on the function. Note: ----------- In the test we need to flush all before doing the payment of the refund, because if we do not do it, the _compute_qty_invoiced method would be called during the payment. But that is not the case outside of the test. This is just to ensure that the test fails correctly without the fix. opw-4991405 Forward-Port-Of: odoo/odoo#236379 Forward-Port-Of: odoo/odoo#231840
This update corrects how product forecast quantities are calculated after stock moves are completed. Forecasts will now reflect the actual quantity received or delivered, instead of incorrectly using the original requested amount, which could show misleading negative or positive values in the past.
Original PR description
### Steps to reproduce: - Create a storable product - Create a receipt for 100 units of that product - Mark as to do, set the quantity to 50 and validate without backorder - Go to your product form >…
### Steps to reproduce: - Create a storable product - Create a receipt for 100 units of that product - Mark as to do, set the quantity to 50 and validate without backorder - Go to your product form > Forecast #### > The forecast displays a quantity of -50 for every date in the past ### Cause of the issue: The part of the report query relying on done moves is based on the `prodcut_uom_qty` of the move and hence on its demand. However, when the move is 'done' only its quantity should be relevant. #### Note: The same issue happen if you receive more than the demand. That is: - Mark as to do, set the quantity to 150 and validate without backorder - Go to your product form > Forecast #### > The forecast displays a quantity of 50 for every date in the past The issue did not happen prior to 17.0 because validating a move for a quantity that differs from the demand would: - in case quantity < product_uom_qty: split the move in 2: one done move where the demand matches the quantity and one cancelled move with the remaining demand. - in case quantity > product_uom_qty: the demand of the move was updated to match the quantity of the move. This has been changed in f9867a5fa572a15fb89c49c61e569427d6388cbc now, validating a move for a quantity that differs from the demand will keep the demand intact. opw-5152570 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#234576
This fix ensures that additional fields added to pay run forms by localizations are kept when the record is saved. It prevents user-entered values from being lost, which helps maintain accurate payroll data.
Original PR description
In some localizations, extra fields are added in the form view of payruns, these field values are lost due to the way we buildRawRecord
This fix removes an incorrect block when creating a reordering rule for a product in a different company. Previously, kit bills of materials from another company could prevent setup even though they should not apply there.
Original PR description
Steps to reproduce: - Create a storable product "P1" - Add a kit BoM restricted to Company A - Switch to Company B - Try to create an orderpoint for "P1" in Company B Issue: A validation error is raised: "A product with a kit-type bill of materials cannot have a reordering rule." Cause: The check did not consider the company of the BoM, so kit BoMs defined in other companies incorrectly blocked orderpoint creation. Solution: Add the company condition in the BoM search domain to ensure that only BoMs belonging to the same company (or global ones) are considered. opw-5158491 Forward-Port-Of: odoo/odoo#232685
When users press Alt+A from the public website, the editor now opens in a usable translation state whenever the page supports translations. This fixes a confusing case where the editor opened but could not actually translate the page, improving the experience for multilingual websites.
Original PR description
__Before this commit:__ 1. Add a 2nd language to your site 2. Show the website homepage in the 2nd language and be outside the admin backend (no admin navbar at the top of the page) 3. Press Alt+A…
__Before this commit:__ 1. Add a 2nd language to your site 2. Show the website homepage in the 2nd language and be outside the admin backend (no admin navbar at the top of the page) 3. Press Alt+A (the shortcut to open the builder) => The builder opens, but it is unusable. The builder options are the translation options, but the iframe is not in a translatable state. __Cause:__ Pressing Alt+A outside the admin backend just [adds `enable_editor=1` in the URL][1]. When the page is displayed in the 2nd language `data-translatable` is included in the metadata so the translation mode opens. However the iframe relies on the `edit_translations` search param being set to include the translation branding (i.e. `data-oe-translation-source-sha`) which is not the case after pressing Alt+A. __The fix:__ Add `edit_translations` when pressing Alt+A in any case. If the page is translatable, the translation mode will correclty open, otherwise it will be ignored and the edit mode will open instead. NB: By doing this, we bypass the checks in [`attemptStartTranslate`][2] therefore a user who doesn't have the proper access rights will still be able to open the translation mode but they will not be able to do anything. Using those checks would add too much complexity to the code in regards to how niche the feature is anyway. [1]: https://github.com/odoo/odoo/blob/d985ec2e9b61b5e6c36a278654d526aaa5b512e2/addons/website/static/src/js/content/redirect.js#L33 [2]: https://github.com/odoo/odoo/blob/d985ec2e9b61b5e6c36a278654d526aaa5b512e2/addons/website/static/src/client_actions/website_preview/edit_website_systray_item.js#L54 task-5125700
Refunds in Point of Sale now handle serial-numbered products more accurately. When only part of a quantity is refunded, staff can choose which serial numbers to return, and the system preselects the right number by default to make refunds faster and less error-prone.
Original PR description
When refunding an order that contains a product tracked by serial number if you refund less than the total quantity of the product in the order all the serial numbers of the original order would be set anyway. Also you were not able to select the serial numbers to refund. Steps to reproduce: ------------------- * Create product P1, storable, tracked by serial number * Create 2 Serial Numbers SN1, SN2 for P1 * Create a POS order with 2x P1 (SN1, SN2) * Pay and validate the order * Refund the order, set quantity of P1 to 1 * Validate the refund > Observation: The refund order contains P1 with SN1 and SN2, and you cannot edit the serial numbers. Why the fix: ------------ We now allow to select the serial numbers when doing a refund and only show the serial numbers that were in the original order. We also select by default the same number of serial numbers as the quantity to refund. opw-4965171 Forward-Port-Of: odoo/odoo#235514 Forward-Port-Of: odoo/odoo#230778
This fix makes planning analysis reports count time only when a shift actually falls within working hours. It prevents hours from being incorrectly assigned to the wrong month when a shift crosses midnight outside an employee’s schedule.
Original PR description
### Steps to reproduce: - Create an employee with fixed working schedule from 8 to 5 - Create a Planning shift for this employee that starts in a month and ends in the first day of the next month outside of working hours (e.g. Sept30th 8AM -> Oct1st 2AM) - Navigate to Timesheets / Planning analysis reports - Notice October has been taken into consideration in the report's planned hours ### Cause: The query we are using for the timesheets/planning report doesn't take working hours into consideration it only cares about the date. So if the shift ends in October 1st we are taking it into account whether it is inside working hours or not. ### Fix: Add a condition to the where clause to check the working hours and if the record lays in this period or not. opw-5089052 Forward-Port-Of: odoo/enterprise#96846
This fix makes the vendor on-time rate shown in the smart button match the graph and the actual purchase order quantities. It prevents duplicated receipts from inflating totals and gives users a reliable delivery performance view.
Original PR description
**Steps to reproduce:** 1- Install the purchase_stock module. 2- Create a new PO with a new vendor. 3- Add new one product in the purchase order line with quantity > 1. 4- Confirm the PO and go to…
**Steps to reproduce:** 1- Install the purchase_stock module. 2- Create a new PO with a new vendor. 3- Add new one product in the purchase order line with quantity > 1. 4- Confirm the PO and go to the generated receipt. 5- Validate the receipt with less than the ordered quantity, by choosing no backorder. 6- Duplicate the receipt for the remaining quantity and validate it. 7- In vendor form view, the On-time Rate value shown in the smart button differs from the value in the graph. **Issue:** https://github.com/odoo/odoo/blob/e7da32fe67cfe78bc6da8bf5d36a7c584763e3bb/addons/purchase_stock/report/vendor_delay_report.py#L26-L42 - The On-time Rate shown in the smart button does not match the graph. **Example:** - PO Line ordered qty: 10 - First receipt validated: 6 (no backorder) - Duplicated receipt validated: 4 - In vendor form view inside On-time Rate Smart button - Total quantity coming: 14 (incorrect) - Expected total qty for calculation: 10 (from PO line) - On-time delivery rate calculated: **71.43%** - Expected On-time delivery rate: **100%** **Cause:** - The report uses `product_qty` from the stock move. - When a receipt is duplicated and the demand quantity is manually set, `product_qty` is recomputed from this demand value. This leads to a mismatch between the PO line quantity and the aggregated stock move quantities. **NOTE:** In `test_02_vendor_delay_report_partially_cancelled_purchase_order`, added the line:: `purchase_order.order_line.flush_recordset()` - Because we were taking the `partner_id` from the `Purchase Order line` is a stored related field. - The computed value first lives in Odoo’s cache. - It is not written to the database until a flush occurs. - If we immediately call something like _read_group() (which queries the database directly), it won’t see the cached value — only what is persisted in the DB. **Solution:** - Use the purchase order line quantity instead of the stock move’s `product_qty` to ensure consistent and accurate On-time Rate calculation. opw-4991367 Forward-Port-Of: odoo/odoo#236779 Forward-Port-Of: odoo/odoo#225529