Daily updates from Odoo
Wednesday, August 19, 2026
155 changes
15 changes
Resolved issues and error corrections
This change makes an automated image upload test more reliable by giving the system a little more time to detect the uploaded image. It helps prevent occasional false failures in testing, especially when the server is under heavy load.
Original PR description
Before this commit, this image field test sometimes failed because it could not find the image that had just been uploaded. Similarly to [1], we increase the waitFor timeout to 1s. Indeed, uploading an image can take time, and with high CPU usage, it could happen that the default 200ms delay wasn't enough. [1] https://github.com/odoo/odoo/pull/168196 runbot error-242406 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#281200
The live chat statistics section now uses the available screen width more effectively on mobile devices. This removes awkward empty space and makes the interface cleaner and easier to read on smaller screens.
Original PR description
Previously, the live chat statistics section did not use the available width on mobile devices, leaving unnecessary empty space and resulting in an awkward layout. This PR makes the statistics cards take the full available width on mobile, providing a cleaner and more consistent interface. <table> <tr> <th>Before</th> <th>After</th> </tr> <tr> <td> <img width="372" height="805" alt="image" src="https://github.com/user-attachments/assets/6934927b-f744-4c93-b63e-1f49ecd33004" /> </td> <td> <img width="382" height="734" alt="image" src="https://github.com/user-attachments/assets/24f8b7e4-9fe7-4fa0-bf64-5d7917623830" /> </td> </tr> </table> --- Task ID - 6372787 Forward-Port-Of: odoo/odoo#274945
Currently an error occurs when user tries to send a pdf of a invoice to a customer. Steps to replicate: (Make sure to have `python 3.14.4` and `pypdf=5.4.0`) - Install `l10n_sa_edi` with demo and switch to `My Saudi Arabia Company`. - Open invoices and create an invoice with customer and an invoice line. - Click `Send` > Again Click `Send`. Error: ``` AttributeError: 'PageObject' object has no attribute 'getObject' AttributeError: No attribute getObject found in IndirectObject or poi
Original PR description
Currently an error occurs when user tries to send a pdf of a invoice to a customer. Steps to replicate: (Make sure to have `python 3.14.4` and `pypdf=5.4.0`) - Install `l10n_sa_edi` with demo and…
Currently an error occurs when user tries to send a pdf of a invoice to a customer. Steps to replicate: (Make sure to have `python 3.14.4` and `pypdf=5.4.0`) - Install `l10n_sa_edi` with demo and switch to `My Saudi Arabia Company`. - Open invoices and create an invoice with customer and an invoice line. - Click `Send` > Again Click `Send`. Error: ``` AttributeError: 'PageObject' object has no attribute 'getObject' AttributeError: No attribute getObject found in IndirectObject or pointed object ``` - A recent [PR] introduced the old `getObject()` API in the PDF/A conversion code, even though it has been renamed to `get_object()` in the modern pypdf API. - As PyPDF2 1.x compatibility has already been removed, `getObject()` is no longer available and causes the error to log on the terminal. - Please refer to [1] and [2]. [PR]: https://github.com/odoo/odoo/pull/281275 [1]: https://github.com/odoo/odoo/pull/248197/files#diff-f3528e61bb9aa2d24d9b57cddafb7429d21216ba29f9dc7e08c92bb617949911L218 [2]: https://pypdf.readthedocs.io/en/stable/meta/changelog-v1.html#details sentry-7663263079 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282159
`test_prepare_order_vals_rights` builds its PoS user with stock.`group_stock_user`. Until 19.2 `point_of_sale` depended on `stock_account`, so stock was always installed and the xmlid resolved. Since 6a56bd10cec7 split stock out of PoS, the module no longer pulls in stock, and `env.ref `raises "External ID not found in the system" when the module is tested alone. The group was never needed: the test only calls `_prepare_invoice_vals`, which reads the symbol as sudo and touches no stock record
Original PR description
`test_prepare_order_vals_rights` builds its PoS user with stock.`group_stock_user`. Until 19.2 `point_of_sale` depended on `stock_account`, so stock was always installed and the xmlid resolved. Since 6a56bd10cec7 split stock out of PoS, the module no longer pulls in stock, and `env.ref `raises "External ID not found in the system" when the module is tested alone. The group was never needed: the test only calls `_prepare_invoice_vals`, which reads the symbol as sudo and touches no stock record. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282859
The PoS client draws the QR code itself, but `showQR` was feeding it the result of `build_qr_code_url`, which is not a payment payload but the URL of the report rendering one: /report/barcode/?barcode_type=QR&quiet=0&width=128&height=128&value=... Scanning the code therefore gave the bank app a report path instead of the payment data. All methods going through `res.partner.bank` were affected: `sct_qr`, `emv_qr`, `id_qr` and `ch_qr`. Add `build_qr_code_value`, returning the value th
Original PR description
The PoS client draws the QR code itself, but `showQR` was feeding it the result of `build_qr_code_url`, which is not a payment payload but the URL of the report rendering one:
/report/barcode/?barcode_type=QR&quiet=0&width=128&height=128&value=...
Scanning the code therefore gave the bank app a report path instead of the payment data. All methods going through `res.partner.bank` were affected: `sct_qr`, `emv_qr`, `id_qr` and `ch_qr`.
Add `build_qr_code_value`, returning the value the barcode controller would have encoded, and use it in the PoS. This also fixes `default_qr`, the offline fallback. `get_qr_code_url` is renamed to `get_qr_code_value` as it no longer returns a URL.
task-6465442
Forward-Port-Of: odoo/odoo#282220**Steps to reproduce:** - Configure a Belgian company on a database without demo data - Install Accounting - From Accounting settings, activate Peppol - Use "Odoo Demo ID" as "Peppol EAS" **Issue:** The activation fails while tryings to activate Peppol in production mode. As `Odoo Demo ID` is used, it should activate Peppol in demo mode without issue, but the selected value is not taken into account. **Cause:** In this commit https://github.com/odoo/odoo/commit/6f8c2526a00d, `peppol
Original PR description
**Steps to reproduce:** - Configure a Belgian company on a database without demo data - Install Accounting - From Accounting settings, activate Peppol - Use "Odoo Demo ID" as "Peppol EAS" **Issue:**…
**Steps to reproduce:** - Configure a Belgian company on a database without demo data - Install Accounting - From Accounting settings, activate Peppol - Use "Odoo Demo ID" as "Peppol EAS" **Issue:** The activation fails while tryings to activate Peppol in production mode. As `Odoo Demo ID` is used, it should activate Peppol in demo mode without issue, but the selected value is not taken into account. **Cause:** In this commit https://github.com/odoo/odoo/commit/6f8c2526a00d, `peppol_eas` and `peppol_endpoint` have been renamed to `routing_scheme` and `routing_endpoint`. In the process, some logic has been lost. Previously, the "Peppol Registration" wizard had a related field to the `peppol_eas` field of the company partner. When selecting `Odoo Demo ID` in the wizard, it was also updating the related field to `odemo`. After the refactoring, the related field of the wizard has been replaced by a computed stored field without an inverse method. So changing the value in the wizard doesn't impact the `routing_scheme` field of the company partner that is not set to `odemo`. opw-6421240 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Steps to reproduce: - Install `l10n_fr_pdp` and `Accounting` > Switch to `FR Company` - Activate `French electronic invoicing` - Create New Invoice with `FR Company` as Customer - Send > unchecked French E-Invoicing (Demo) Traceback: `AttributeError: 'res.partner' object has no attribute '_get_pdp_receiver_identification_info'` In this REF [PR], we removed the `_get_pdp_receiver_identification_info` method and replaced it with the `l10n_fr_is_pdp` field, but we missed updating it here
Original PR description
Steps to reproduce: - Install `l10n_fr_pdp` and `Accounting` > Switch to `FR Company` - Activate `French electronic invoicing` - Create New Invoice with `FR Company` as Customer - Send > unchecked French E-Invoicing (Demo) Traceback: `AttributeError: 'res.partner' object has no attribute '_get_pdp_receiver_identification_info'` In this REF [PR], we removed the `_get_pdp_receiver_identification_info` method and replaced it with the `l10n_fr_is_pdp` field, but we missed updating it here. Solution: Replaced the removed `_get_pdp_receiver_identification_info` method with `l10n_fr_is_pdp`. [PR]: https://github.com/odoo/odoo/commit/5c3dde7f36609a74ffed8357c11a648d85942bdd#diff-a9b0aba990a93514e74372976dd8c77cda07db893324a0a2fad8a9027ec0b1da opw-6443303
The fix proposed in #274619 was not properly adapted for saas-19.4 and onwards as we changed the class name of the chart menu (see https://github.com/odoo/o-spreadsheet/pull/7861). Task-6441988 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
Original PR description
The fix proposed in #274619 was not properly adapted for saas-19.4 and onwards as we changed the class name of the chart menu (see https://github.com/odoo/o-spreadsheet/pull/7861). Task-6441988 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
Steps to reproduce: 1. Install `l10n_pe` 2. Create and set the current company to the Peru company 3. In mobile view, try to create a contact 4. Fill in the identification number type to RUC Issue: - The field of VAT is collapsed and not visible Cause: - The VAT div `vat_div` is displayed as a flex row (`o_row d-flex`) so the 'add identifier' button sits on the same line as the VAT field. https://github.com/odoo/odoo/blob/7d2d41fdef3446ca118290c1b31287887c0794db/addons/account/vie
Original PR description
Steps to reproduce: 1. Install `l10n_pe` 2. Create and set the current company to the Peru company 3. In mobile view, try to create a contact 4. Fill in the identification number type to RUC Issue: -…
Steps to reproduce:
1. Install `l10n_pe`
2. Create and set the current company to the Peru company
3. In mobile view, try to create a contact
4. Fill in the identification number type to RUC
Issue:
- The field of VAT is collapsed and not visible
Cause:
- The VAT div `vat_div` is displayed as a flex row (`o_row d-flex`) so the 'add identifier' button sits on the same line as the VAT field.
https://github.com/odoo/odoo/blob/7d2d41fdef3446ca118290c1b31287887c0794db/addons/account/views/partner_view.xml#L169-L171
Localizations based on `l10n_latam_base` also put an identification type field (e.g. RUC, DNI) in that same row, before the VAT field.
https://github.com/odoo/odoo/blob/7d2d41fdef3446ca118290c1b31287887c0794db/addons/l10n_latam_base/views/res_partner_view.xml#L14-L21
That identification type field carried the `oe_inline` class, which matched an unrelated, pre-existing mobile-only rule forcing any inline many2one to `width: 100% !important`.
https://github.com/odoo/odoo/blob/7d2d41fdef3446ca118290c1b31287887c0794db/addons/web/static/src/views/form/form_controller.scss#L999-L1001
Inside the flex row this left no space for its sibling, collapsing the VAT value input.
<table>
<tr>
<th width="50%">Before</th>
<th width="50%">After</th>
</tr>
<tr>
<td width="50%">
<img src="https://github.com/user-attachments/assets/12b1774f-2c60-4c89-a348-ccf514528552" width="100%">
</td>
<td width="50%">
<img src="https://github.com/user-attachments/assets/3f1571f1-8e88-41d3-89bb-b9e2ce1e85fc" width="100%">
</td>
</tr>
</table>
Solution:
- Drop the `oe_inline` class from the identification type field in `l10n_latam_base`'s partner view.
opw-6375655
Forward-Port-Of: odoo/odoo#275905Before this commit: --- The company logo is displayed above the background on the customer display. After this commit: --- The company logo is displayed only when there is no background or QR code to display. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281406
Original PR description
Before this commit: --- The company logo is displayed above the background on the customer display. After this commit: --- The company logo is displayed only when there is no background or QR code to display. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281406
Issue: --- Adding a pickup-in-store delivery method to a sales order from the backend `Add shipping` wizard and clicking on the pickup point selector raises: Invalid props for component `LocationSelectorDialog`: `countryId` is not a number. Steps to reproduce: 1- Create a SO with a partner without country set. 2- Enable debug mode. 3- Use `Add shipping` wizard and choose pick-up delivery method. 4- Open the location selector. Cause: --- `PickupLocationMany2OneField.countryId` re
Original PR description
Issue: --- Adding a pickup-in-store delivery method to a sales order from the backend `Add shipping` wizard and clicking on the pickup point selector raises: Invalid props for component `LocationSelectorDialog`: `countryId` is not a number. Steps to reproduce: 1- Create a SO with a partner without country set. 2- Enable debug mode. 3- Use `Add shipping` wizard and choose pick-up delivery method. 4- Open the location selector. Cause: --- `PickupLocationMany2OneField.countryId` returns the `id` of `this.partnerRecord.country_id` which is `false` when the company is not set. This can be fixed by a safe optional chain access. opw-6321167 Forward-Port-Of: odoo/odoo#281720
Issue: --- On the product page, when the image layout is set to grid and only one image is there, the image doesn't take the full width of its container on mobile devices. A empty space appears next to it. Steps to reproduce: 1- Go to a product page with mlutiple images. 2- Switch the image layout from carousel to grid. 3- Remove extra images and keep only one image. 4- Open the page using mobile view in chrome. This can be fixed by forcing `width: 100%` explicitly on the image wrapp
Original PR description
Issue: --- On the product page, when the image layout is set to grid and only one image is there, the image doesn't take the full width of its container on mobile devices. A empty space appears next to it. Steps to reproduce: 1- Go to a product page with mlutiple images. 2- Switch the image layout from carousel to grid. 3- Remove extra images and keep only one image. 4- Open the page using mobile view in chrome. This can be fixed by forcing `width: 100%` explicitly on the image wrapper for `o_grid_solo`. opw-6265732 Forward-Port-Of: odoo/odoo#281728
In this commit: - Ensure event ticket information is preserved during self-order processing and use the configured ticket price when recomputing order line prices. - This prevents ticket prices from being replaced by the product price after proceeding to payment and keeps the amounts consistent across the payment page. Task:6375899 Forward-Port-Of: odoo/odoo#282530 Forward-Port-Of: odoo/odoo#275645
Original PR description
In this commit: - Ensure event ticket information is preserved during self-order processing and use the configured ticket price when recomputing order line prices. - This prevents ticket prices from being replaced by the product price after proceeding to payment and keeps the amounts consistent across the payment page. Task:6375899 Forward-Port-Of: odoo/odoo#282530 Forward-Port-Of: odoo/odoo#275645
Features or functions removed from Odoo
Current behavior before PR: - In [49f01db](https://github.com/odoo-dev/odoo/commit/49f01dbbe7a607b83865cab308e0dc8193ee9f0b), `getDefaultValueFromGlobalFilter` was introduced just for `GlobalFilterInput`. Desired behavior after PR is merged: - `GlobalFilterInput` no longer relies on this function, so remove the unused getter. Task: [6388147](https://www.odoo.com/odoo/project/2328/tasks/6388147) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submi
Original PR description
Current behavior before PR: - In [49f01db](https://github.com/odoo-dev/odoo/commit/49f01dbbe7a607b83865cab308e0dc8193ee9f0b), `getDefaultValueFromGlobalFilter` was introduced just for `GlobalFilterInput`. Desired behavior after PR is merged: - `GlobalFilterInput` no longer relies on this function, so remove the unused getter. Task: [6388147](https://www.odoo.com/odoo/project/2328/tasks/6388147) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277761
Miscellaneous changes
Behavior before: When uploading an animated GIF to fields utilizing image responsive sizing or cropping (such as employee avatars or product images), no downscaling or cropping occurs for sub-variants like 'image_128' or 'image_1024'. The responsive fields replicate the exact file size and data footprint of the original large image, leading to heavy storage overhead and unnecessary frontend asset loading. Behavior after: Animated GIF images scale down and crop correctly to match requested r
Original PR description
Behavior before: When uploading an animated GIF to fields utilizing image responsive sizing or cropping (such as employee avatars or product images), no downscaling or cropping occurs for…
Behavior before: When uploading an animated GIF to fields utilizing image responsive sizing or cropping (such as employee avatars or product images), no downscaling or cropping occurs for sub-variants like 'image_128' or 'image_1024'. The responsive fields replicate the exact file size and data footprint of the original large image, leading to heavy storage overhead and unnecessary frontend asset loading. Behavior after: Animated GIF images scale down and crop correctly to match requested responsive dimensions and aspect ratios. Sub-variants take up significantly less space in the filestore, matching proportional dimensions without dropping or stripping the underlying animation loop. Large images that are smaller than requested boxes are safely left un-upscaled to maximize database deduplication. Root Cause: Historically, a legacy safeguard bypassed GIF resizing and cropping because older versions of the Pillow library did not gracefully handle multi-frame sequential image buffers. As a result, standard 'image.crop()', 'image.thumbnail()', or 'image.resize()' implementations would flatten multi-frame animated sequences down into a single, static first frame or throw dimension/mode mismatches during save operations. Fix: Intercept the image processing pipeline when encountering an asset identified as a GIF where 'is_animated' evaluates to True. Implemented a unified, in-place multi-frame helper routine (`_apply_gif_operation`) using PIL's 'ImageSequence.Iterator' to cleanly step through, normalize to a uniform color mode (RGBA), duplicate, and modify each animation frame individually. This single helper handles sequential workflows for both 'crop' and 'thumbnail' operations while preserving individual frame duration arrays and native loop metadata. Both 'resize' and 'crop_resize' leverage this logic to achieve precise dimensions cleanly. Crucially, upscaling (expanding) is intentionally unsupported for animated GIFs. Forcing a low-resolution, 256-color indexed animation to stretch beyond its native dimensions forces heavy color dithering across every single frame. This breaks the sequential LZW pattern compression, causing the resulting file sizes to skyrocket catastrophically. The logic utilizes thumbnail boundaries to completely block this expansion, protecting the filestore from accidental bloat. Benchmark: -------------------------------------------------------------------------------------------- | GIF size | Variant | Size Before (KB) | Size After (KB) | |---------------|--------------------|--------------------------|-----------------------| | (2.5MB) | image_1024 | 2475.87 | 2475.87 | | | image_128 | 2475.87 | 257.93 | |---------------|--------------------|--------------------------|-----------------------| | (3.8MB) | image_1024 | 3724.93 | 3724.93 | | | image_128 | 3724.93 | 463.62 | |----------------|-------------------|--------------------------|-----------------------| | (442KB) | image_1024 | 432.49 | 432.49 | | | image_128 | 432.49 | 36.14 | |----------------|-------------------|--------------------------|-----------------------| | (3.6MB) | image_1024 | 3491.98 | 3491.98 | | | image_128 | 3491.98 | 1728.25 | |----------------|-------------------|--------------------------|-----------------------| opw-6232841 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#282831 Forward-Port-Of: odoo/odoo#273098
7 changes
Enhancements to existing features
This PR removes weekend days from dynamic update for the iot boxes. This allows to follow the support availabilities Forward-Port-Of: odoo/odoo#282780
Original PR description
This PR removes weekend days from dynamic update for the iot boxes. This allows to follow the support availabilities Forward-Port-Of: odoo/odoo#282780
This commit adds both Python and JS unit tests for the Mollie POS payment method. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282024 Forward-Port-Of: odoo/odoo#281742
Original PR description
This commit adds both Python and JS unit tests for the Mollie POS payment method. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282024 Forward-Port-Of: odoo/odoo#281742
Resolved issues and error corrections
Following this commit: ==== - When a combo is broken down, its items are assigned to their respective courses. - Remove a course when all its items are deleted from the cart. task-6121521 Forward-Port-Of: odoo/odoo#260276
Original PR description
Following this commit: ==== - When a combo is broken down, its items are assigned to their respective courses. - Remove a course when all its items are deleted from the cart. task-6121521 Forward-Port-Of: odoo/odoo#260276
Issue: --- On the product page, when the image layout is set to grid and only one image is there, the image doesn't take the full width of its container on mobile devices. A empty space appears next to it. Steps to reproduce: 1- Go to a product page with mlutiple images. 2- Switch the image layout from carousel to grid. 3- Remove extra images and keep only one image. 4- Open the page using mobile view in chrome. This can be fixed by forcing `width: 100%` explicitly on the image wrapp
Original PR description
Issue: --- On the product page, when the image layout is set to grid and only one image is there, the image doesn't take the full width of its container on mobile devices. A empty space appears next to it. Steps to reproduce: 1- Go to a product page with mlutiple images. 2- Switch the image layout from carousel to grid. 3- Remove extra images and keep only one image. 4- Open the page using mobile view in chrome. This can be fixed by forcing `width: 100%` explicitly on the image wrapper for `o_grid_solo`. opw-6265732 Forward-Port-Of: odoo/odoo#281728
### Issue: In 19.3, the following hoot tests fail with a RunBot error: - "called at right time (when canceling order)" - "called at right time (when canceling order never sent to blackbox)" - "called at right time (when canceling a combo order)" ### Cause: Commit 0dfd71b9f4 removed `close` from `ControlButtonsPopup` as the Dialog patch now handles closing via `this.data.close()` With no remaining props to declare, `static props` was removed entirely Without `static props`, Owl skips a
Original PR description
### Issue: In 19.3, the following hoot tests fail with a RunBot error: - "called at right time (when canceling order)" - "called at right time (when canceling order never sent to blackbox)" - "called…
### Issue:
In 19.3, the following hoot tests fail with a RunBot error:
- "called at right time (when canceling order)"
- "called at right time (when canceling order never sent to blackbox)"
- "called at right time (when canceling a combo order)"
### Cause:
Commit 0dfd71b9f4 removed `close` from `ControlButtonsPopup` as the Dialog patch now handles closing via `this.data.close()` With no remaining props to declare, `static props` was removed entirely
Without `static props`, Owl skips all prop validation but emits: "Component 'ControlButtonsPopup' does not have a
static props description"
`mountWithCleanup` forces `warnIfNoStaticProps` to `true` in hoot tests, causing the tests to fail
`close` is declared as optional since `dialog_service.js` always injects it via `subProps: markRaw({ ...props, close })` at runtime, but the component no longer uses it directly
### Steps to reproduce:
- Install `l10n_be_pos_blackbox`
- Enable Developer mode
- Open the JS test UI
- Run one of the failing tests
runbot-941231
Forward-Port-Of: odoo/odoo#277790In this commit: - The feedback screen was not scaling properly on Android devices and tablet displays, causing content to appear too small or overflow. - Fixed by making the checkmark and text sizes responsive using units so the layout adapts correctly across different screen sizes. Task: 6420543 Forward-Port-Of: odoo/odoo#282539 Forward-Port-Of: odoo/odoo#279328
Original PR description
In this commit: - The feedback screen was not scaling properly on Android devices and tablet displays, causing content to appear too small or overflow. - Fixed by making the checkmark and text sizes responsive using units so the layout adapts correctly across different screen sizes. Task: 6420543 Forward-Port-Of: odoo/odoo#282539 Forward-Port-Of: odoo/odoo#279328
Many users were receiving duplicate vendor bills. The issue was that duplicates were never detected in the receiving flow. Every incoming message returned by the proxy was processed and turned into a new `account.move`, even if it had already been imported previously. This commit filters out messages whose UUID already matches an existing `account.move` before processing them, and acknowledges those duplicates on the IAP side so they are not received again on the next run. task-5930116
Original PR description
Many users were receiving duplicate vendor bills. The issue was that duplicates were never detected in the receiving flow. Every incoming message returned by the proxy was processed and turned into a new `account.move`, even if it had already been imported previously. This commit filters out messages whose UUID already matches an existing `account.move` before processing them, and acknowledges those duplicates on the IAP side so they are not received again on the next run. task-5930116 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282042 Forward-Port-Of: odoo/odoo#274963
9 changes
Enhancements to existing features
Revert the receipt tax summary design back to the 19.0 format, ensuring that the base amount is always displayed for each tax group. Before this commit, when all tax groups shared the same tax base, the base amount was hidden, leading to a flat tax listing. Now, the template always renders the tax groups in the format: "Tax [Name] on [Base Amount] [Tax Amount]" task-id: 6296906 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-
Original PR description
Revert the receipt tax summary design back to the 19.0 format, ensuring that the base amount is always displayed for each tax group. Before this commit, when all tax groups shared the same tax base, the base amount was hidden, leading to a flat tax listing. Now, the template always renders the tax groups in the format: "Tax [Name] on [Base Amount] [Tax Amount]" task-id: 6296906 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270749
Resolved issues and error corrections
***Steps to reproduce*:** * Install the `l10n_din5008` module. * Set up a German Company and set the fiscal location to Germany. * Select the German company and create a new Purchase Journal. * Enable **Self Billing** for the journal. * Create a vendor bill and print the PDF. ***Observed behavior*:** * The printed document displays the regular vendor bill header instead of the self-billing header. ***Cause*:** * The condition required to display the self-billing header was mi
Original PR description
***Steps to reproduce*:** * Install the `l10n_din5008` module. * Set up a German Company and set the fiscal location to Germany. * Select the German company and create a new Purchase Journal. * Enable **Self Billing** for the journal. * Create a vendor bill and print the PDF. ***Observed behavior*:** * The printed document displays the regular vendor bill header instead of the self-billing header. ***Cause*:** * The condition required to display the self-billing header was missing from the report template if self-billing is enabled. ***Fix*:** * Add the missing condition so that the self-billing header is displayed when **Self Billing** is enabled on the journal. * For reference, here is the [Document](https://www.gesetze-im-internet.de/ustg_1980/__14.html) link. Ticket [link](https://www.odoo.com/odoo/project.task/6281066) opw-6281066 Forward-Port-Of: odoo/odoo#282664 Forward-Port-Of: odoo/odoo#272857
## Description When a CI/NIE number fails the check digit validation, the raised error suggests `3:402.010-2 or 93:402.010-1 (CI or NIE)` as the expected format. This is misleading for two reasons: - The colon notation comes from Uruware's technical manual and is not how identity card numbers are written in Uruguay: users write `3.402.010-1` or plain digits (`34020101`). Real users facing the error keep reformatting a number whose check digit is simply wrong, believing the problem is the forma
Original PR description
## Description When a CI/NIE number fails the check digit validation, the raised error suggests `3:402.010-2 or 93:402.010-1 (CI or NIE)` as the expected format. This is misleading for two reasons: -…
## Description When a CI/NIE number fails the check digit validation, the raised error suggests `3:402.010-2 or 93:402.010-1 (CI or NIE)` as the expected format. This is misleading for two reasons: - The colon notation comes from Uruware's technical manual and is not how identity card numbers are written in Uruguay: users write `3.402.010-1` or plain digits (`34020101`). Real users facing the error keep reformatting a number whose check digit is simply wrong, believing the problem is the format. - The CI example shown is itself an **invalid** number: the check digit of `3.402.010` is `1`, not `2` — the module's own test suite (`l10n_uy/tests/test_check_vat.py`) uses `3:402.010-2` as an invalid sample. This was reported by an Uruguayan eCommerce user who lost sales because buyers interpreted the message as requiring an unusual format that does not exist in Uruguay. ## Change Replace the examples with valid numbers written in the notations actually used in Uruguay, and clarify that separators are optional — which is exactly what `_l10n_uy_ci_nie_is_valid()` already accepts (it strips `:. ,-` before checking the verification digit): ``` 3.402.010-1 or 34020101 (CI), 93.402.010-1 (NIE); dots and dash are optional ``` Only the `expected_format` string changes; the validation logic is untouched. Existing tests only assert the fixed part of the message (`The CI/NIE number.*does not seem to be valid`), so they are unaffected. Forward-Port-Of: odoo/odoo#282489
Steps to reproduce: - Install Point of Sale without the Restaurant module - Open a session and scan the barcode of a product Issue: The product is never added to the order, the client crashes with "TypeError: this.pos.autoCourseAllocation is not a function". Cause: b86126bbfb17105323a8ac972cb5062b95325fc4 moved autoCourseAllocation and cleanAutoCourseAllocation out of ProductScreen (point_of_sale) into the PosStore patch of pos_restaurant, but kept the two call sites in point_of_sale's
Original PR description
Steps to reproduce: - Install Point of Sale without the Restaurant module - Open a session and scan the barcode of a product Issue: The product is never added to the order, the client crashes with…
Steps to reproduce: - Install Point of Sale without the Restaurant module - Open a session and scan the barcode of a product Issue: The product is never added to the order, the client crashes with "TypeError: this.pos.autoCourseAllocation is not a function". Cause: b86126bbfb17105323a8ac972cb5062b95325fc4 moved autoCourseAllocation and cleanAutoCourseAllocation out of ProductScreen (point_of_sale) into the PosStore patch of pos_restaurant, but kept the two call sites in point_of_sale's ProductScreen._barcodeProductAction, now routed through this.pos. Both methods therefore only exist when pos_restaurant is installed, so on a plain shop configuration the call throws. The other call site, ProductScreen.addProductToOrder, is patched in pos_restaurant itself, which is why only the barcode path is affected. Runbot installs every module, so the patch is always loaded there and the crash went unnoticed. Also restore the argument forwarding in the pos_restaurant PosOrder.removeOrderline patch introduced by the same commit: it declares deep but called super.removeOrderline(line), dropping it. PosStore.breakCombo is the only caller passing deep=false. opw-6478112 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282919
task-6468432 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
Original PR description
task-6468432 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
Before this commit, the full composer tour can fail on the step that drops a file on the composer, waiting for a `.o-Dropzone` that never shows. This happens because the channel mention list is sometimes still open when the tour drags the file in. The composer gets no dropzone then, as a dropzone only shows when the UI active element contains its target, and the open mention list is the UI active element. The dropzone is only updated on the drag events, therefore closing the mention list neve
Original PR description
Before this commit, the full composer tour can fail on the step that drops a file on the composer, waiting for a `.o-Dropzone` that never shows. This happens because the channel mention list is sometimes still open when the tour drags the file in. The composer gets no dropzone then, as a dropzone only shows when the UI active element contains its target, and the open mention list is the UI active element. The dropzone is only updated on the drag events, therefore closing the mention list never brings it back. Note that the same race is reported on saas-19.1, where the tour crashes on `dispatchEvent` of null instead, as the `dragFiles` helper there queries the dropzone once where `dropFiles` waits for it. This commit waits for the mention list to close before the drag. https://runbot.odoo.com/odoo/error/946097 Forward-Port-Of: odoo/odoo#282716
### Issue before this commit: When generating an electronic invoice (e.g., ZUGFeRD/Factur-X) with a 0% tax from a non-EEA supplier (e.g., Switzerland) to an EEA customer (e.g., Germany), the XML tax <ram:CategoryCode> is incorrectly set to 'E' (Exempt) instead of 'G' (Export). ### Steps to reproduce the issue: 1. Download Accounting and l10n_ch 2. Set the VAT for the CH company 3. Create an invoice for a German customer with 0% tax setted (for which you have to set as electronic invoicing
Original PR description
### Issue before this commit: When generating an electronic invoice (e.g., ZUGFeRD/Factur-X) with a 0% tax from a non-EEA supplier (e.g., Switzerland) to an EEA customer (e.g., Germany), the XML tax…
### Issue before this commit: When generating an electronic invoice (e.g., ZUGFeRD/Factur-X) with a 0% tax from a non-EEA supplier (e.g., Switzerland) to an EEA customer (e.g., Germany), the XML tax <ram:CategoryCode> is incorrectly set to 'E' (Exempt) instead of 'G' (Export). ### Steps to reproduce the issue: 1. Download Accounting and l10n_ch 2. Set the VAT for the CH company 3. Create an invoice for a German customer with 0% tax setted (for which you have to set as electronic invoicing the ZUGFeRD template into the Accounting tab of his contact) 4. Send it and see that the tag <ram:CategoryCode> is setted as E instead of G ### Cause of the issue: The logic assigning the 'G' and 'K' tax category codes was only triggered if the supplier was located within the EEA. If the supplier was outside the EEA, the code bypassed this block entirely and fell back to the default 'E' code for 0% taxes. ### Reason to introduce the fix: Update the condition to trigger when either the supplier or the customer is in the EEA. This ensures that cross-border transactions involving at least one EEA party correctly evaluate and apply the 'G' (Export outside the EU) category code. Also the case supplier not in eea with VAT filled in + customer in eea + RC tax with amount != 0 is fixed now (letter G reported instead of S). ### Documentation: [eInvoicing technical guidance document_v1.pdf](https://github.com/user-attachments/files/30831749/eInvoicing.technical.guidance.document_v1.pdf) opw-6407399 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282497 Forward-Port-Of: odoo/odoo#281245
Steps to reproduce: --- - Install `website_sale` module. - Enable `Product Variants` and `Prevent Sale of Zero Priced Product` in settings. - Create new attribute > set `Variant Creation` as `Never` and also add value with extra price. - Create a product with sales price = 0, assign the attribute, and publish it. - As a public user (incognito), try to add the product to the cart. Issue: --- - In terminal error `The given product does not exist therefore it cannot be added to cart` is
Original PR description
Steps to reproduce: --- - Install `website_sale` module. - Enable `Product Variants` and `Prevent Sale of Zero Priced Product` in settings. - Create new attribute > set `Variant Creation` as `Never`…
Steps to reproduce: --- - Install `website_sale` module. - Enable `Product Variants` and `Prevent Sale of Zero Priced Product` in settings. - Create new attribute > set `Variant Creation` as `Never` and also add value with extra price. - Create a product with sales price = 0, assign the attribute, and publish it. - As a public user (incognito), try to add the product to the cart. Issue: --- - In terminal error `The given product does not exist therefore it cannot be added to cart` is raised. Root cause: --- - In `_is_add_to_cart_allowed()`[1], the method calls `_get_contextual_price()` [2] to check if the product's price is zero when `prevent_zero_price_sale` is enabled. - However, `_get_contextual_price()` is called without the no-variant attribute values in the context, so it does not account for their `price_extra`. For a product with list price as 0 and attribute with extra price, the price is incorrectly computed as 0, causing `_is_add_to_cart_allowed()` to return `False`. Solution: --- - Before calling `_is_add_to_cart_allowed()`, set the product's context with the no-variant attribute values via `_get_product_price_context()`, so that `_get_contextual_price()` correctly includes the price extra in its computation. [1]https://github.com/odoo/odoo/blob/bbafbbd8950ec7123ab652851ede5479484eee26/addons/website_sale/controllers/cart.py#L117-L120 [2]https://github.com/odoo/odoo/blob/bbafbbd8950ec7123ab652851ede5479484eee26/addons/website_sale/models/product_product.py#L149-L150 opw-6365566 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282705 Forward-Port-Of: odoo/odoo#278620
Steps to produce: --- - Install `sales` module. - Go to Settings and enable `Units of Measure and Packaging`. - Set a long name for `units` UoM. - Create a Sale Order and add a product via the catalog. Issue: --- - Long UoM names are not fully visible in the catalog view. Root cause: --- - The outer `<div>` has `d-flex` but lacks `w-100`, causing it to overflow its container. Solution: --- - Added `w-100` to the outer `<div>` to prevent overflow. - Adjusted the quantity s
Original PR description
Steps to produce: --- - Install `sales` module. - Go to Settings and enable `Units of Measure and Packaging`. - Set a long name for `units` UoM. - Create a Sale Order and add a product via the…
Steps to produce: --- - Install `sales` module. - Go to Settings and enable `Units of Measure and Packaging`. - Set a long name for `units` UoM. - Create a Sale Order and add a product via the catalog. Issue: --- - Long UoM names are not fully visible in the catalog view. Root cause: --- - The outer `<div>` has `d-flex` but lacks `w-100`, causing it to overflow its container. Solution: --- - Added `w-100` to the outer `<div>` to prevent overflow. - Adjusted the quantity selector layout for better visibility. Before: --- <img width="388" height="141" alt="image" src="https://github.com/user-attachments/assets/dafae08a-3c9d-4163-8894-daa2e4d26f62" /> After: --- <img width="382" height="154" alt="image" src="https://github.com/user-attachments/assets/abd6f034-be4b-49bf-be9c-c9779de0f30d" /> Enterprise PR: https://github.com/odoo/enterprise/pull/121139 opw-6253382 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282565 Forward-Port-Of: odoo/odoo#267118
8 changes
Enhancements to existing features
Some generic validation errors raised by core account models lack enough context to identify which record caused the issue, making FEC imports harder to troubleshoot. This commit improves the two error cases identified for this use case: - `account.account._check_account_code` now includes the invalid account code in the error message. - `account.move.write` now includes the move name/reference and displays human-readable field labels instead of technical field names when attempting to modi
Original PR description
Some generic validation errors raised by core account models lack enough context to identify which record caused the issue, making FEC imports harder to troubleshoot. This commit improves the two…
Some generic validation errors raised by core account models lack enough context to identify which record caused the issue, making FEC imports harder to troubleshoot. This commit improves the two error cases identified for this use case: - `account.account._check_account_code` now includes the invalid account code in the error message. - `account.move.write` now includes the move name/reference and displays human-readable field labels instead of technical field names when attempting to modify read-only fields on posted entries. Although motivated by FEC import, these are generic core validations, so the improvements are implemented at the source to benefit all callers rather than only the FEC import flow. Enrichment is scoped to the two cases above, other constraints/errors across these models are intentionally left unchanged for now, since editing core error messages more broadly should be done deliberately and on a case-by-case basis, not as a blanket rewrite task-5346068 Forward-Port-Of: odoo/odoo#281746
This PR handles 2 cases : ===== PART 1 ===== Self-billing bill sequences should be unique per partner, as implemented in v19+. This PR backports that behavior to 17.0. ===== PART 2 ===== Previously, the `is_self_billing` option on `account.journal` was available only for purchase journals. This caused an issue when importing a self-billing invoice into a regular sales journal with quick edit mode (accounting firm) enabled. In such cases, the newly created invoices would use the self-
Original PR description
This PR handles 2 cases : ===== PART 1 ===== Self-billing bill sequences should be unique per partner, as implemented in v19+. This PR backports that behavior to 17.0. ===== PART 2 ===== Previously, the `is_self_billing` option on `account.journal` was available only for purchase journals. This caused an issue when importing a self-billing invoice into a regular sales journal with quick edit mode (accounting firm) enabled. In such cases, the newly created invoices would use the self-billing sequence pattern, leading to traceability issues. This PR allows the creation of self-billing sales journals to prevent this issue. task-6103142 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282062 Forward-Port-Of: odoo/odoo#259935
Resolved issues and error corrections
Currently, when the user attempts to create a delivery operation for a class X document type, the system prompts the user to provide values for the CAI and CAI Expiration Date fields. ## Steps to produce: - Install `l10n_ar_stock` with demo data - Switch Company to `(AR) Exento` - Create a warehouse - Configuration > Operation Types > Delivery Orders - Set Document Type to `'(94) MAILING X' `and try to save ## Observed Behavior: The fields 'CAI' and 'CAI Expiration Date', which repre
Original PR description
Currently, when the user attempts to create a delivery operation for a class X document type, the system prompts the user to provide values for the CAI and CAI Expiration Date fields. ## Steps to…
Currently, when the user attempts to create a delivery operation for a class X document type, the system prompts the user to provide values for the CAI and CAI Expiration Date fields. ## Steps to produce: - Install `l10n_ar_stock` with demo data - Switch Company to `(AR) Exento` - Create a warehouse - Configuration > Operation Types > Delivery Orders - Set Document Type to `'(94) MAILING X' `and try to save ## Observed Behavior: The fields 'CAI' and 'CAI Expiration Date', which represent the authorization code and expiration date issued by the government, are currently configured as required fields. **Expected Behavior:** As specified on the [government site](https://www.argentina.gob.ar/normativa/nacional/resoluci%C3%B3n-1415-2003-81316/actualizacion#:~:text=Los%20datos%20indicados%20en%20el%20inciso%20a%29%2C%20puntos%207%2C%2010%2C%2011%2C%2012%20y%2013%2C%20s%C3%B3lo%20ser%C3%A1n%20para%20los%20remitos%20clase%20%27R%27%2E): > > 12. Printing authorization code, preceded by the acronym 'CAI No. ...'. > 13. Expiration date of the receipt, preceded by the legend 'Expiration Date ...' > > 'The data indicated in section a), points 7, 10, 11, 12 and 13, will only be for 'R' class delivery notes.' These statements indicate that the information mentioned in points 12 and 13, including the **CAI** and **CAI Expiration Date** fields, is applicable only to **'R'** class delivery notes. Therefore, for class X delivery notes, these fields should be optional rather than required. ## Root Cause: According to [1], the field is configured as a required field when a Document Type ID is selected. This configuration causes the **CAI** and **CAI Expiration Date** fields to become mandatory, regardless of the document type requirements defined by the government specification. [1]- https://github.com/odoo/odoo/blob/62b05c4ea61942072b6b1fb420fe3efedb11ed14/addons/l10n_ar_stock/views/stock_picking_type_views.xml#L11-L16 ## Solution: Apply constraints that align with the government specifications, allowing the CAI and CAI Expiration Date fields to remain optional for document types where they are not required. opw-6359503 Forward-Port-Of: odoo/odoo#275533
Before this commit, the full composer tour can fail on the step that drops a file on the composer, waiting for a `.o-Dropzone` that never shows. This happens because the channel mention list is sometimes still open when the tour drags the file in. The composer gets no dropzone then, as a dropzone only shows when the UI active element contains its target, and the open mention list is the UI active element. The dropzone is only updated on the drag events, therefore closing the mention list neve
Original PR description
Before this commit, the full composer tour can fail on the step that drops a file on the composer, waiting for a `.o-Dropzone` that never shows. This happens because the channel mention list is sometimes still open when the tour drags the file in. The composer gets no dropzone then, as a dropzone only shows when the UI active element contains its target, and the open mention list is the UI active element. The dropzone is only updated on the drag events, therefore closing the mention list never brings it back. Note that the same race is reported on saas-19.1, where the tour crashes on `dispatchEvent` of null instead, as the `dragFiles` helper there queries the dropzone once where `dropFiles` waits for it. This commit waits for the mention list to close before the drag. https://runbot.odoo.com/odoo/error/946097 Forward-Port-Of: odoo/odoo#282716
Issue: --- Authorize payment tokenization doesn't work. Steps: 1- Setup authorize payment provider. 2- Using portal page, add a new payment method for the user. The created payment method is not saved. Cause: --- The issue was introduced in efc2788dfccd13ee6feb309430ff57e49664ff97. Before that, we were calling `_tokenize` before voiding the tx. In that PR, the `_tokenize` call was moved to `_process()`, after `_apply_updates()`. So now what happens is that we void the tx, then ca
Original PR description
Issue: --- Authorize payment tokenization doesn't work. Steps: 1- Setup authorize payment provider. 2- Using portal page, add a new payment method for the user. The created payment method is not…
Issue: --- Authorize payment tokenization doesn't work. Steps: 1- Setup authorize payment provider. 2- Using portal page, add a new payment method for the user. The created payment method is not saved. Cause: --- The issue was introduced in efc2788dfccd13ee6feb309430ff57e49664ff97. Before that, we were calling `_tokenize` before voiding the tx. In that PR, the `_tokenize` call was moved to `_process()`, after `_apply_updates()`. So now what happens is that we void the tx, then call `_tokenize()`. Inside tokenize we try to create a customer profile, which fails because the tx is already voided. Fix: --- We can fix it by calling `_tokenize()` once before voiding the tx. The redundant tokenize call inside the general payment tx `_process` is rendered ineffective by two safeguards: 1- There is a check for `tx.tokenize`, which neutralizes double tokenization: https://github.com/odoo/odoo/blob/fffd987cc98d1ea0cd04e24dda2ed8b64a219cdc/addons/payment/models/payment_transaction.py#L754-L755 https://github.com/odoo/odoo/blob/fffd987cc98d1ea0cd04e24dda2ed8b64a219cdc/addons/payment/models/payment_transaction.py#L893-L896 2- If `token_id` is already set, no token value is returned: https://github.com/odoo/odoo/blob/fffd987cc98d1ea0cd04e24dda2ed8b64a219cdc/addons/payment_authorize/models/payment_transaction.py#L237-L243 opw-6426847 Forward-Port-Of: odoo/odoo#281014
Before this commit, "mesh peer to peer connections" fails at random on a loaded machine, counting fewer connections than its ten users make: [toBe] expected values to be strictly equal > Expected: 90 > Received: 81 This happens because the test counts the peers as soon as its addPeer calls resolve. addPeer awaits the readiness promise of the peer, which also resolves, with false, when that peer is disconnected. A connection slow to open reaches the recovery watchdog, which te
Original PR description
Before this commit, "mesh peer to peer connections" fails at random on a loaded machine, counting fewer connections than its ten users make:
[toBe] expected values to be strictly equal
> Expected: 90
> Received: 81
This happens because the test counts the peers as soon as its addPeer calls resolve. addPeer awaits the readiness promise of the peer, which also resolves, with false, when that peer is disconnected. A connection slow to open reaches the recovery watchdog, which tells the other side to drop the peer, drops it locally and adds it back without awaiting it. The awaited promises can therefore all be settled while recovered peers are still connecting.
This commit waits for the mesh to reach its full size before counting, so that a recovery in flight no longer decides the result. With the browser CPU throttled, the test fails about half of its runs before this commit, and none after.
Forward-Port-Of: odoo/odoo#282719## Current behavior: On a Monday–Friday working schedule, a Daily accrual plan that is based on worked time grants accrued time on Saturday as well, even though Saturday is not a working day. The employee accrues on 6 days per week instead of 5 (Sunday is correctly skipped. Only Saturday is wrong). ## Expected behavior: The employee accrues only on the 5 working days (Mon–Fri) → 5 grants per week. Saturday and Sunday should add nothing. ## Setup: - Working schedule: Standard 40h/week, M
Original PR description
## Current behavior: On a Monday–Friday working schedule, a Daily accrual plan that is based on worked time grants accrued time on Saturday as well, even though Saturday is not a working day. The…
## Current behavior: On a Monday–Friday working schedule, a Daily accrual plan that is based on worked time grants accrued time on Saturday as well, even though Saturday is not a working day. The employee accrues on 6 days per week instead of 5 (Sunday is correctly skipped. Only Saturday is wrong). ## Expected behavior: The employee accrues only on the 5 working days (Mon–Fri) → 5 grants per week. Saturday and Sunday should add nothing. ## Setup: - Working schedule: Standard 40h/week, Monday–Friday, 08:00–17:00. - All timezones set to Australia/Brisbane (UTC+10) and matching: employee, working schedule, and user are all the same timezone. - Accrual plan milestone: accrue 5 Hours, Daily, "At the end of the accrual period", "Based on worked time = Yes". ## Steps to reproduce: - Create the working schedule and accrual plan above, with the calendar timezone set to Australia/Brisbane. - Assign the accrual allocation to an employee, Starting on a Monday. - On the Time Off dashboard, use "Balance at the (date)" to project the balance day by day across a weekend (Friday → Saturday → Sunday → Monday). ## Cause of the issue: Accrual period boundaries were built as naive UTC midnights instead of local calendar midnights. ## Fix: Localize accrual period boundaries in the employee/resource timezone before calling resource calendar APIs. This bug is reproducible in multiple versions. PRs for: - v19.0: https://github.com/odoo/odoo/pull/279029 - v18.0: https://github.com/odoo/odoo/pull/279036 opw-6316062 Forward-Port-Of: odoo/odoo#279029
**Steps to reproduce:** 1. Install Sales and payment_authorize modules 2. Enable "Online Payment" in the settings and Configure the payment method to be Authorize.net 3. Create a sale order, confirm it and create the invoice 4. Pay the invoice with an eCheck (ACH) payment method through the Authorize.net provider 5. Wait for the payment to be settled by Authorize.net (_around 24 hours_) 6. Initiate a refund of the payment **Issue:** The refund fails with error `E00003: "The 'AnetApi/xm
Original PR description
**Steps to reproduce:** 1. Install Sales and payment_authorize modules 2. Enable "Online Payment" in the settings and Configure the payment method to be Authorize.net 3. Create a sale order, confirm…
**Steps to reproduce:** 1. Install Sales and payment_authorize modules 2. Enable "Online Payment" in the settings and Configure the payment method to be Authorize.net 3. Create a sale order, confirm it and create the invoice 4. Pay the invoice with an eCheck (ACH) payment method through the Authorize.net provider 5. Wait for the payment to be settled by Authorize.net (_around 24 hours_) 6. Initiate a refund of the payment **Issue:** The refund fails with error `E00003: "The 'AnetApi/xml/v1/schema/AnetApiSchema.xsd:cardNumber' element is invalid - The value XX is invalid according to its datatype 'String' - The actual length is less than the MinLength value` **Expected behavior:** The refund should be processed successfully regardless of whether the original payment was made by credit card or eCheck (ACH) **Why this happens:** - The `refund()` method in `AuthorizeAPI` builds the refund request using a `creditCard` payment payload - When the original transaction was an ACH/eCheck payment, the `creditCard` key is absent from the transaction details returned by Authorize.net - The resulting request is rejected by Authorize.net because it does not satisfy the minimum length constraint for `cardNumber` **Fix:** - Detects whether the original payment used `creditCard` or `bankAccount` from the transaction details and build the appropriate payload according to Authorize.net API documentation: https://developer.authorize.net/api/reference/index.html#payment-transactions-credit-a-bank-account opw-6359726 Forward-Port-Of: odoo/odoo#277742
5 changes
Resolved issues and error corrections
Steps to produce: --- - Install the `Sales` module. - In Settings, enable `Automatic Invoice`. - Also enable the Demo payment provider. - Create a sale order with a total of `800` and confirm it. - Generate a payment link for `200` from the gear icon and pay it. - Generate a second payment link for `300` and pay it. - Generate a final payment link for the remaining `300` and pay it. Issue: --- - After the first payment (200), an `invoice of 200` is created. Correct. - After the sec
Original PR description
Steps to produce: --- - Install the `Sales` module. - In Settings, enable `Automatic Invoice`. - Also enable the Demo payment provider. - Create a sale order with a total of `800` and confirm it. -…
Steps to produce: --- - Install the `Sales` module. - In Settings, enable `Automatic Invoice`. - Also enable the Demo payment provider. - Create a sale order with a total of `800` and confirm it. - Generate a payment link for `200` from the gear icon and pay it. - Generate a second payment link for `300` and pay it. - Generate a final payment link for the remaining `300` and pay it. Issue: --- - After the first payment (200), an `invoice of 200` is created. Correct. - After the second payment (300), an` invoice of 500` is created instead of 300. - After the third payment (300), an `invoice of 100` is created instead of 300. Root cause: --- - The down payment invoice uses `order.amount_paid`, the cumulative sum of all transactions on the order, instead of the amount of the latest payment. This causes invoices to be sized off the running total instead of the individual payment delta. Fix: --- - Compute the invoice amount as `order.amount_paid - order.amount_invoiced` (the unpaid) instead of passing the cumulative `amount_paid` directly. opw-6324036 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273099
Before this commit, the full composer tour can fail on the step that drops a file on the composer, waiting for a `.o-Dropzone` that never shows. This happens because the channel mention list is sometimes still open when the tour drags the file in. The composer gets no dropzone then, as a dropzone only shows when the UI active element contains its target, and the open mention list is the UI active element. The dropzone is only updated on the drag events, therefore closing the mention list neve
Original PR description
Before this commit, the full composer tour can fail on the step that drops a file on the composer, waiting for a `.o-Dropzone` that never shows. This happens because the channel mention list is sometimes still open when the tour drags the file in. The composer gets no dropzone then, as a dropzone only shows when the UI active element contains its target, and the open mention list is the UI active element. The dropzone is only updated on the drag events, therefore closing the mention list never brings it back. Note that the same race is reported on saas-19.1, where the tour crashes on `dispatchEvent` of null instead, as the `dragFiles` helper there queries the dropzone once where `dropFiles` waits for it. This commit waits for the mention list to close before the drag. https://runbot.odoo.com/odoo/error/946097 Forward-Port-Of: odoo/odoo#282716
Calling `/shop/payment/validate` as a portal user with an empty cart confirms the empty sale order. Steps to reproduce: - Sign in as a portal user. - Add a product to the cart. - Remove the product. - Go to `/shop/payment/validate`. - The empty sale order is confirmed. opw-6430637 Forward-Port-Of: odoo/odoo#282335 Forward-Port-Of: odoo/odoo#280924
Original PR description
Calling `/shop/payment/validate` as a portal user with an empty cart confirms the empty sale order. Steps to reproduce: - Sign in as a portal user. - Add a product to the cart. - Remove the product. - Go to `/shop/payment/validate`. - The empty sale order is confirmed. opw-6430637 Forward-Port-Of: odoo/odoo#282335 Forward-Port-Of: odoo/odoo#280924
When the FIFO vacuum creates the "Expenses Revaluation" journal entry for an anglo-saxon delivery whose cost is adjusted by a later receipt, the JE was built using `env.company` instead of the company of the vacuumed SVL. Steps to reproduce: - Enable multi-company and activate anglo-saxon accounting on two companies A and B. - In company B, on the product category: set FIFO costing + Automated valuation, and set the stock input / stock output / stock valuation accounts and the stock journa
Original PR description
When the FIFO vacuum creates the "Expenses Revaluation" journal entry for an anglo-saxon delivery whose cost is adjusted by a later receipt, the JE was built using `env.company` instead of the…
When the FIFO vacuum creates the "Expenses Revaluation" journal entry for an anglo-saxon delivery whose cost is adjusted by a later receipt, the JE was built using `env.company` instead of the company of the vacuumed SVL. Steps to reproduce: - Enable multi-company and activate anglo-saxon accounting on two companies A and B. - In company B, on the product category: set FIFO costing + Automated valuation, and set the stock input / stock output / stock valuation accounts and the stock journal. The Stock Output account must have "Allow Reconciliation" enabled. - In company B, on the product: set an Expense Account and set the Cost (e.g. 10.0) this is the price the delivery will be valued at while the stock is negative. The product must have no quantity on hand in company B. - While working in company B, sell and deliver 1 unit of that product: the delivery is valued at 10.0 and creates a negative valuation layer. - Still in company B, create and post the customer invoice of that sale, so the Stock Output line of the delivery entry gets reconciled with the Stock Output line of the anglo-saxon COGS entry of the invoice. - Switch the active company to A, and from there create a purchase order of that product for company B at a different price (e.g. 15.0), then validate the linked receipt into company B's warehouse. - The vacuum compensates the negative layer, but the resulting "Expenses Revaluation of ..." journal entry is posted in company A instead of company B. This fix forces the company context to `vacuum_svl.company_id` when fetching the product accounts and preparing the move lines so the JE is always created in the company of the SVL being vacuumed. opw-6066970 opw-6419188 Forward-Port-Of: odoo/odoo#259133
### Issue: When multiple partners share the same email address, `_mail_find_partner_from_emails` may resolve to the wrong partner when the input is a formatted email like "`Name <email>`" This affects use cases like email templates using `{{object.company_id.email_formatted}}` as sender, where the wrong company partner could be selected ### Cause: The lookup in `done_partners` only matched on `email_normalized`, which cannot distinguish partners sharing the same email but with different
Original PR description
### Issue: When multiple partners share the same email address, `_mail_find_partner_from_emails` may resolve to the wrong partner when the input is a formatted email like "`Name <email>`" This…
### Issue:
When multiple partners share the same email address, `_mail_find_partner_from_emails` may resolve to the wrong partner when the input is a formatted email like "`Name <email>`"
This affects use cases like email templates using `{{object.company_id.email_formatted}}` as sender, where the wrong company partner could be selected
### Cause:
The lookup in `done_partners` only matched on `email_normalized`, which cannot distinguish partners sharing the same email but with different names
The `email_formatted` field carries both name and email, allowing an exact match when the input is a formatted email
### Steps to reproduce:
- Install `account`
- Create an Email Template (Applies to: account.move, From: {{object.company_id.email_formatted}})
- Create a second company B with the same email as the default (e.g. info@yourcompany.com)
- In Settings (logged in as company B), set a Fiscal Position (e.g. US Taxable)
- Create an Invoice on company B
- In the chatter, click Send message, click the expand arrows button, use the three dots menu to select the template
- Send and check the Sender in the chatter
Before the fix, the sender resolves to the default company even though the invoice belongs to company B
opw-6260992
Forward-Port-Of: odoo/odoo#2695099 changes
Enhancements to existing features
In France, some drom-com (Guadeloupe, Martinique and Réunion) needs to use pdp just like France. So we should add those 3 for the computation of `peppol_eas`, so it will autocomplete to **France FRCTC Electronic Address**. task-6344558 Forward-Port-Of: odoo/odoo#278272
Original PR description
In France, some drom-com (Guadeloupe, Martinique and Réunion) needs to use pdp just like France. So we should add those 3 for the computation of `peppol_eas`, so it will autocomplete to **France FRCTC Electronic Address**. task-6344558 Forward-Port-Of: odoo/odoo#278272
Resolved issues and error corrections
## Current behavior: On a Monday–Friday working schedule, a Daily accrual plan that is based on worked time grants accrued time on Saturday as well, even though Saturday is not a working day. The employee accrues on 6 days per week instead of 5 (Sunday is correctly skipped. Only Saturday is wrong). ## Expected behavior: The employee accrues only on the 5 working days (Mon–Fri) → 5 grants per week. Saturday and Sunday should add nothing. ## Setup: - Working schedule: Standard 40h/week, M
Original PR description
## Current behavior: On a Monday–Friday working schedule, a Daily accrual plan that is based on worked time grants accrued time on Saturday as well, even though Saturday is not a working day. The…
## Current behavior: On a Monday–Friday working schedule, a Daily accrual plan that is based on worked time grants accrued time on Saturday as well, even though Saturday is not a working day. The employee accrues on 6 days per week instead of 5 (Sunday is correctly skipped. Only Saturday is wrong). ## Expected behavior: The employee accrues only on the 5 working days (Mon–Fri) → 5 grants per week. Saturday and Sunday should add nothing. ## Setup: - Working schedule: Standard 40h/week, Monday–Friday, 08:00–17:00. - All timezones set to Australia/Brisbane (UTC+10) and matching: employee, working schedule, and user are all the same timezone. - Accrual plan milestone: accrue 5 Hours, Daily, "At the end of the accrual period", "Based on worked time = Yes". ## Steps to reproduce: - Create the working schedule and accrual plan above, with the calendar timezone set to Australia/Brisbane. - Assign the accrual allocation to an employee, Starting on a Monday. - On the Time Off dashboard, use "Balance at the (date)" to project the balance day by day across a weekend (Friday → Saturday → Sunday → Monday). ## Cause of the issue: Accrual period boundaries were built as naive UTC midnights instead of local calendar midnights. ## Fix: Localize accrual period boundaries in the employee/resource timezone before calling resource calendar APIs. This bug is reproducible in multiple versions. PRs for: - v19.0: https://github.com/odoo/odoo/pull/279029 - v18.0: https://github.com/odoo/odoo/pull/279036 opw-6316062
When the FIFO vacuum creates the "Expenses Revaluation" journal entry for an anglo-saxon delivery whose cost is adjusted by a later receipt, the JE was built using `env.company` instead of the company of the vacuumed SVL. Steps to reproduce: - Enable multi-company and activate anglo-saxon accounting on two companies A and B. - In company B, on the product category: set FIFO costing + Automated valuation, and set the stock input / stock output / stock valuation accounts and the stock journa
Original PR description
When the FIFO vacuum creates the "Expenses Revaluation" journal entry for an anglo-saxon delivery whose cost is adjusted by a later receipt, the JE was built using `env.company` instead of the…
When the FIFO vacuum creates the "Expenses Revaluation" journal entry for an anglo-saxon delivery whose cost is adjusted by a later receipt, the JE was built using `env.company` instead of the company of the vacuumed SVL. Steps to reproduce: - Enable multi-company and activate anglo-saxon accounting on two companies A and B. - In company B, on the product category: set FIFO costing + Automated valuation, and set the stock input / stock output / stock valuation accounts and the stock journal. The Stock Output account must have "Allow Reconciliation" enabled. - In company B, on the product: set an Expense Account and set the Cost (e.g. 10.0) this is the price the delivery will be valued at while the stock is negative. The product must have no quantity on hand in company B. - While working in company B, sell and deliver 1 unit of that product: the delivery is valued at 10.0 and creates a negative valuation layer. - Still in company B, create and post the customer invoice of that sale, so the Stock Output line of the delivery entry gets reconciled with the Stock Output line of the anglo-saxon COGS entry of the invoice. - Switch the active company to A, and from there create a purchase order of that product for company B at a different price (e.g. 15.0), then validate the linked receipt into company B's warehouse. - The vacuum compensates the negative layer, but the resulting "Expenses Revaluation of ..." journal entry is posted in company A instead of company B. This fix forces the company context to `vacuum_svl.company_id` when fetching the product accounts and preparing the move lines so the JE is always created in the company of the SVL being vacuumed. opw-6066970 opw-6419188 Forward-Port-Of: odoo/odoo#259133
When importing UBL invoices that contain document-level allowances or charges with percentage taxes, the tax values were not linked to their corresponding `TaxSubtotal` group (`related_taxes_values`). As a result, the tax correction step (`_import_ubl_invoice_fix_taxes_amounts`) was unaware of document-level taxes, which caused wrong tax corrections. opw-6388544
Original PR description
When importing UBL invoices that contain document-level allowances or charges with percentage taxes, the tax values were not linked to their corresponding `TaxSubtotal` group (`related_taxes_values`). As a result, the tax correction step (`_import_ubl_invoice_fix_taxes_amounts`) was unaware of document-level taxes, which caused wrong tax corrections. opw-6388544
**Steps to reproduce:** (18.0 only) - Go to Contacts app - Pick a contact record - Change Salesperson on contact to Marc Demo - Click on "Send Message" without sending (to show the suggested recipients) - Remove Marc Demo from the followers to ensure he appears in suggested recipient checkboxes - Click the second name on the checkbox list - It will uncheck the first name on the list **Issue:** `t-attf-id="{{ props.recipient.id }}_checkbox"` in `SuggestedRecipients` produces `id="unde
Original PR description
**Steps to reproduce:**
(18.0 only)
- Go to Contacts app
- Pick a contact record
- Change Salesperson on contact to Marc Demo
- Click on "Send Message" without sending (to show the suggested recipients)
- Remove Marc Demo from the followers to ensure he appears in suggested recipient checkboxes
- Click the second name on the checkbox list
- It will uncheck the first name on the list
**Issue:**
`t-attf-id="{{ props.recipient.id }}_checkbox"` in `SuggestedRecipients` produces `id="undefined_checkbox"` and defaults to the same value each time on click.
**Fix:**
As `id` is not defined on the recipient, try to use `props.recipient.persona?.id` instead.
opw-6395530> Replaces https://github.com/odoo/odoo/pull/282286, which GitHub closed automatically after a bad force-push on my side: the branch was pushed from a shallow clone and its head lost its parent commit, leaving no common ancestor with 18.0. A PR in that state cannot be reopened, so this one continues from a clean branch with the exact same change. The review discussion is in that PR, and the rename asked for there is included here. ### Steps to reproduce 1. Go to `Accounting > Customers > Invoi
Original PR description
> Replaces https://github.com/odoo/odoo/pull/282286, which GitHub closed automatically after a bad force-push on my side: the branch was pushed from a shallow clone and its head lost its parent…
> Replaces https://github.com/odoo/odoo/pull/282286, which GitHub closed automatically after a bad force-push on my side: the branch was pushed from a shallow clone and its head lost its parent commit, leaving no common ancestor with 18.0. A PR in that state cannot be reopened, so this one continues from a clean branch with the exact same change. The review discussion is in that PR, and the rename asked for there is included here. ### Steps to reproduce 1. Go to `Accounting > Customers > Invoices` and create an invoice on a given journal, leaving it in draft. For the clearest case, leave it with no invoice line. 2. Go to `Accounting > Configuration > Journals`, open that journal and archive it. 3. `_check_auto_post_draft_entries` raises: *"You can not archive a journal containing draft journal entries. To proceed: 1/ click on the top-right button 'Journal Entries' from this journal form 2/ then filter on 'Draft' entries 3/ select them all and post or delete them through the action menu"*. 4. Follow those steps: click the `Journal Entries` smart button on the journal form. ### Current behaviour The list comes up empty, so the user concludes the error message is wrong, while the draft entries do exist. The instructions cannot be followed: - The smart button opens `action_account_moves_all_a`, which is named **"Journal Items"** and targets **`account.move.line`**, not `account.move`. The label of the button and the name of the action it opens do not match. - That action defaults to `search_default_posted: 1`, so no draft record is listed. - Draft entries with **no line at all** — commonly created through the incoming mail alias of a journal — have no `account.move.line`, so they stay invisible in that view even after switching the filter. - The action menu of a move line list offers no way to post or delete the entries, and the action sets `create: 0`. - The filter is labelled **"Unposted"**, not "Draft". The offending entries are only reachable through `Accounting > Accounting > Journal Entries`, filtering by journal and by "Unposted". ### Expected behaviour The error should point to a view where the records blocking the archiving are actually listed and actionable. ### This PR Two changes, the validation itself is unchanged: - The error message now points to `Accounting > Accounting > Journal Entries` and uses the real filter name, "Unposted". - The smart button of the journal form is renamed to **"Journal Items"**, so its label matches the action it opens and no longer suggests it lists journal entries. This was asked for in the review of the previous PR. Targeted at 18.0 because that is where the misleading message is being hit in practice; it is identical on 19.0 and master. If a translatable string change does not qualify for the stable series, tell me and I will retarget to master.
Due to the following commit: 01efd8cfcce3269ca6b88d549a670b08a90298cb, a division by zero error is raised when a 100% discount is used with a price-included tax. When the discount is 100%, it is impossible to retrieve the original tax amount before discount using a simple multiplication as the current raw_tax_amount_currency is zero. In that case, we need to recompute taxes using the original unit price before discount. opw-6242701 --- I confirm I have signed the CLA and read the PR
Original PR description
Due to the following commit: 01efd8cfcce3269ca6b88d549a670b08a90298cb, a division by zero error is raised when a 100% discount is used with a price-included tax. When the discount is 100%, it is impossible to retrieve the original tax amount before discount using a simple multiplication as the current raw_tax_amount_currency is zero. In that case, we need to recompute taxes using the original unit price before discount. opw-6242701 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
**Steps to reproduce:** - Create a tax that affects the base of the subsequent ones - Create an invoice with this tax and another one on the same line **Issue:** In "_aggregate_base_line_tax_details", the tax amount from the first tax should be included in the following values of the second tax: - raw_total_excluded - raw_total_excluded_currency - target_total_excluded - target_total_excluded_currency - total_excluded - total_excluded_currency But it is not. opw-6235909
Original PR description
**Steps to reproduce:** - Create a tax that affects the base of the subsequent ones - Create an invoice with this tax and another one on the same line **Issue:** In "_aggregate_base_line_tax_details", the tax amount from the first tax should be included in the following values of the second tax: - raw_total_excluded - raw_total_excluded_currency - target_total_excluded - target_total_excluded_currency - total_excluded - total_excluded_currency But it is not. opw-6235909 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Description of the issue this PR addresses: We don't support colspan/rowspan in the editor, so tables containing them can break other functionality that assumes a rectangular grid (equal cell count per row). This PR expand any rowspan/colspan into individual cells on insert. opw-6347233 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Description of the issue this PR addresses: We don't support colspan/rowspan in the editor, so tables containing them can break other functionality that assumes a rectangular grid (equal cell count per row). This PR expand any rowspan/colspan into individual cells on insert. opw-6347233 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
2 changes
Resolved issues and error corrections
Before this commit it was impossible to avoid rendering the full report when an invoice had too many lines. This made it impossible to send some Peppol documents. To avoid this we add a system parameter that stops the document generation and prints a limit-reached page instead, avoiding the wkhtmltopdf time/memory issues. OPW-6352345 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Before this commit it was impossible to avoid rendering the full report when an invoice had too many lines. This made it impossible to send some Peppol documents. To avoid this we add a system parameter that stops the document generation and prints a limit-reached page instead, avoiding the wkhtmltopdf time/memory issues. OPW-6352345 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
### Steps to Reproduce: - Create an applicant (with or without an email address). - Move the applicant to the *Hired* stage. - Create an employee from the applicant. - The employee’s work email is automatically being set to the company email. ### Fix: - Explicitly set work_email to False. - work_email=False is required as we have this compute method: https://github.com/odoo/odoo/blob/d84196003012d68b63b8a1564deb43e43c9ebd68/addons/hr/models/hr_employee_base.py#L200-L204 here work_
Original PR description
### Steps to Reproduce: - Create an applicant (with or without an email address). - Move the applicant to the *Hired* stage. - Create an employee from the applicant. - The employee’s work email is automatically being set to the company email. ### Fix: - Explicitly set work_email to False. - work_email=False is required as we have this compute method: https://github.com/odoo/odoo/blob/d84196003012d68b63b8a1564deb43e43c9ebd68/addons/hr/models/hr_employee_base.py#L200-L204 here work_email and partner's email is being sync. Task: 6124112 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr