Daily updates from Odoo
Friday, June 26, 2026
51 changes · saas-19.3
Resolved issues and error corrections
This update prevents the salary configurator from crashing when the company car option is enabled without a car model already selected. It improves reliability for Belgian contract salary setups, especially in databases created without demo data.
Original PR description
## Steps to Reproduce: 1. Install `l10n_be_hr_contract_salary` without demo data. 2. Create a Belgian company and switch to it. 3. Create an employee. 4. Create a contract for the employee. 5. Click Generate Offer and open the Salary Configurator. 6. Enable the 'Company Car (To order)' option. ## Error: `AttributeError: 'NoneType' object has no attribute 'split'` ## Cause: When the salary configurator is used without demo data, no car model is selected. The method assumes that select_wishlist_car_total_depreciated_cost always contains a value and directly calls split() on it, resulting in an error, when the field is None. ## Fix: This commit checks that both the company car option is enabled and a car model has been selected before trying to extract the model ID. sentry-7554712017 Forward-Port-Of: odoo/enterprise#121650 Forward-Port-Of: odoo/enterprise#121138
This change fixes an unstable point-of-sale test that could sometimes look in the wrong order list before an update had fully finished. It improves reliability by making the test wait for the update to complete and by using the correct Paid filter on the ticket screen.
Original PR description
The tour `test_product_level_discount` was failing intermittently because the order status update request was not fully processed before the nextstep executed. As a result, the tour searched for the order in the wrong ticket list. This commit adds a proper wait for the backend request after updating the order status and applies the Paid filter on the ticket screen to ensure the tour searches in the correct order list. Runbot Error: [241140](https://runbot.odoo.com/odoo/runbot.build.error/241140) Forward-Port-Of: odoo/enterprise#109371
This update corrects a Belgian VAT number used in an automated test so it matches the current validation rules. It keeps the test scenario intact while preventing failures caused by stricter third-party validation checks in newer systems.
Original PR description
This commit fixes a Belgian VAT validation check in `test_import_partner_retrieval_bank_account_number` as the provided vat number isn't a valid one. It keeps the spirit of the test by still having vat number mismatch, but with a valid value. The python-stdnum library used for this validation added a stricter check since version 2.2, which is used in Ubuntu Resolute 26.04. References: - https://github.com/arthurdejong/python-stdnum/commit/7ca9b6ce7b1f2b4d1bf164c2af83a8a77bc919d2 runbot-939796 Forward-Port-Of: odoo/odoo#272082
This change prevents the system from creating duplicate draft entries when the scheduled import runs for Belgian SODA files. It restores the previous behavior to avoid repeated imports and reduce confusion in accounting records.
Original PR description
Since this commit: https://github.com/odoo/enterprise/commit/a0c9e9b5c0ed8135d77c343c819c1fa918356794 users are experiencing some duplicate draft move when the cron is running. It's because we don't skip the files when it already exist, we now add a number of imported count. This commit will revert this change to avoid the problem, and we will contact codabox to find a better way to deal with files imported the same month. task-6299508 Forward-Port-Of: odoo/enterprise#121472
The search dialog in bank reconciliation now shows the full reference text instead of cutting it off. The date and balance are also aligned more clearly at the top, making the list easier to scan and compare.
Original PR description
This commit will remove the text-truncate from the reference so that we have it full. Also removing the align item so that the date and balance are on top. no task id Forward-Port-Of: odoo/enterprise#120963
This fix prevents module upgrades from failing for older databases that use the Italian tax reporting package. It removes outdated report entries before the upgrade so the new report formulas can be installed cleanly.
Original PR description
Steps to reproduce: - Create a database with `l10n_it_reports` on a version before PR #264294 - Switch to current `17.0` - Upgrade module `l10n_it` - An error is raised Upgrading a database with `l10n_it_reports` installed raises an error if the database was created before that PR In that PR, we modified the formulas of several report expressions to use subformulas instead of simple aggregations. During upgrade, the ORM attempts to insert the updated expressions while the old ones still exist, violating the UNIQUE constraint on `(report_line_id, label)` in `account.report.expression` Only happens on upgrade, not on a fresh install. A migration script is added to delete the outdated expressions before the upgrade runs Ticket [link](https://www.odoo.com/odoo/project.task/6299385) opw-6299385 Forward-Port-Of: odoo/odoo#271320
This change stops the Point of Sale ticket screen from refunding lines that are already refunds or have been fully refunded. It helps avoid accidental duplicate refunds and keeps refund records accurate.
Original PR description
In the ticket screen, clicking an order line selected it for refund and incremented its quantity without checking whether the line could actually be refunded. As a result, a refund order (whose lines carry a negative quantity) could itself be refunded, and already fully refunded lines could be refunded again. opw-6314527 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271109
The Spanish Mod 349 report now keeps invoices that were paid during the selected period. This fixes an issue where paid invoices could be incorrectly left out of the report, helping ensure the filing is complete and accurate.
Original PR description
The mod349 report engine has been refactored to use tax tags (commit : 5f36778288a1b60245acec74677421666448351f). To avoid redundancies, the query used to get the invoice lines to include is designed to remove the amounts that have been reconciled with a credit note during the selected period. However, the current query removes the lines from any invoice that is reconciled with a move created in the period. As a result, invoices that have been paid in the period are also removed from the report. opw-6250491 Forward-Port-Of: odoo/enterprise#119551
When two restaurant orders are merged into one table, previously sent kitchen quantities are now preserved correctly. This prevents already-prepared items from being shown as new and sent to the kitchen again, avoiding duplicate work and confusion.
Original PR description
When transferring an order to a table that already has an open order, identical products are merged into a single line. If both orders were already sent to the kitchen printer, the merged line was…
When transferring an order to a table that already has an open order, identical products are merged into a single line. If both orders were already sent to the kitchen printer, the merged line was incorrectly marked as new and had to be sent again. Steps to reproduce: ------------------- * Open table 1, add product A (2 units) and product B, send to kitchen * Open table 2, add product A (3 units) and product C, send to kitchen * On table 2, transfer/merge the order to table 1 > Observation: product A shows 2 units as new and must be sent to the kitchen printer again, although all quantities were already sent. Why the fix: ------------ When merging preparation history for identical lines, handlePreparationHistory overwrote the destination sent quantity with the source one instead of summing both. The kitchen diff then treated the missing quantity as new changes. A unit test will be added in 18.3. opw-6246470 Forward-Port-Of: odoo/odoo#271828 Forward-Port-Of: odoo/odoo#267915
Automatic reconciliation now preserves the original payment reference on matched bank statement lines instead of replacing it with the account name. This keeps labels consistent across reconciliation methods and makes it easier for users to identify transactions correctly.
Original PR description
### Issue: When creating an automatic reconciliation rule by assigning the same account to multiple bank statement lines, the rule incorrectly overrides the original payment reference of subsequent…
### Issue: When creating an automatic reconciliation rule by assigning the same account to multiple bank statement lines, the rule incorrectly overrides the original payment reference of subsequent lines with the account name This creates an inconsistent user experience Using the "Set Account" button directly keeps the statement line payment reference as the journal item label However, clicking the automatically generated reconciliation model button replaces that reference with the account name Before the fix, clicking the automated rule button on a third matching line overrides its label with the account name instead of keeping its unique reference ### Cause: In `_create_reconciliation_rule`, when an automatic model is generated, the dictionary used to create the counterpart line explicitly set `label` to `rule_data['account'].name` When a reconciliation model line has a specific label defined, Odoo uses it to replace the statement line `payment_ref` on the generated counterpart move lines Removing this default value allows the system to fall back on the original payment reference ### Steps to reproduce: - Install `account_accountant` - Go to the Bank Reconciliation widget from the Accounting Dashboard - Create 2 statement lines without partners (e.g., Ref: "Test Ref 1" and "Test Ref 2") - Set the same account on both lines using Set Account - This automatically creates a Reconciliation Rule named after the account - Create a 3rd statement line with a matching reference (e.g., "Test Ref 3") - Click the newly available automatic reconciliation button for this line Before the fix, checking the generated entry label shows the account name instead of "Test Ref 3" To check unfold the details, click on the pencil icon of a line opw-6246833 Forward-Port-Of: odoo/enterprise#119133
This update adjusts how French PDP-related records are recalculated so they no longer depend on unrelated company or partner changes. It helps avoid build errors and prevents unnecessary system work when partner information is updated, improving stability and performance.
Original PR description
- This removes dependency on account move fields to company : Build error 939448 - This removes dependency on account move fields to commercial_partner_id fields (avoid recompute all moves on partner info change) Forward-Port-Of: odoo/odoo#271978 Forward-Port-Of: odoo/odoo#269701
The German SKR03 accounting template now points to the correct default accounts for cash discounts. This helps ensure bookkeeping setup uses the right account codes and reduces the risk of misconfigured accounting entries.
Original PR description
The default cash discout accounts referenced in the
German skr03 template used the wrong account codes.
The template has been updated with the right ones.
task-4915939
opw-4909059
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#271886
Forward-Port-Of: odoo/odoo#271024The default cash discount accounts in the German SKR03 template were pointing to the wrong account codes. They have been updated so accounting reports and exports use the correct defaults, reducing the risk of posting or reporting errors.
Original PR description
The default cash discount accounts referenced in the German skr03 template used the wrong account codes. The template has been updated with the right ones. task-4915939 opw-4909059 Forward-Port-Of: odoo/enterprise#121692 Forward-Port-Of: odoo/enterprise#121180
The holiday attestation calculation now uses the correct wage basis when an employee had a long sick leave. This prevents the annual taxable income from being incorrectly set to zero and ensures the employee’s holiday-related amounts are computed accurately.
Original PR description
Problem ---------------------- When an employee takes a long sick leave (more than 30 days), the basic wage on the payslip is set to 0, leading to the holiday attest annual taxable income to be…
Problem ---------------------- When an employee takes a long sick leave (more than 30 days), the basic wage on the payslip is set to 0, leading to the holiday attest annual taxable income to be calculated as 0 * 12, which is incorrect. Reason ------------------- The calculation for the holiday attest uses the last payslip for the employee, and if the employee had leave type LEAVE214, the last payslip has the basic wage set to zero, so the taxable wage that is used in the annual taxable wage calculation is wrong. The monthly wage should be used as the basic wage in the payslip to get the correct computation. Solution ------------------- The GROSS (taxable income) line that is used is computed as (basic wage - ONSS total + BIK), but the basic wage was 0. This commit checks whether the basic wage is 0 and if the time off type was longterm sick leave, and simulates a payslip using the monthly wage from the contract as basic wage to get the accurate computation for the taxable income. task-6237717 Forward-Port-Of: odoo/enterprise#120180
This change prevents an error that could appear when opening the Accounting tab in Studio for contacts with bank accounts. It makes the bank tag component accept the same read-only behavior as the rest of the interface, so the page loads correctly instead of failing.
Original PR description
When opening Studio → Contacts → Accounting Tab, Owl raises the following error: ```py Odoo Client Error Occured on 114697239-saas-19-2-all.runbot254.odoo.com on 2026-06-19 07:01:00 GMT…
When opening Studio → Contacts → Accounting Tab, Owl raises the following error:
```py
Odoo Client Error
Occured on 114697239-saas-19-2-all.runbot254.odoo.com on 2026-06-19 07:01:00 GMT
UncaughtPromiseError > OwlError
Uncaught Promise > Invalid props for component 'BankTag': 'onDelete' is undefined (should be a value)
OwlError: Invalid props for component 'BankTag': 'onDelete' is undefined (should be a value)
Error: Invalid props for component 'BankTag': 'onDelete' is undefined (should be a value)
at Object.validateProps (https://114697239-saas-19-2-all.runbot254.odoo.com/web/assets/5482857/web.assets_web.min.js:1001:67)
at FieldMany2ManyTagsBanks.slot1 (eval at compile (https://114697239-saas-19-2-all.runbot254.odoo.com/web/assets/5482857/web.assets_web.min.js:1387:421), <anonymous>:16:13)
at callSlot (https://114697239-saas-19-2-all.runbot254.odoo.com/web/assets/5482857/web.assets_web.min.js:968:25)
at TagsList.template (eval at compile (https://114697239-saas-19-2-all.runbot254.odoo.com/web/assets/5482857/web.assets_web.min.js:1387:421), <anonymous>:22:30)
at Fiber._render (https://114697239-saas-19-2-all.runbot254.odoo.com/web/assets/5482857/web.assets_web.min.js:797:96)
at Fiber.render (https://114697239-saas-19-2-all.runbot254.odoo.com/web/assets/5482857/web.assets_web.min.js:796:6)
at ComponentNode.initiateRender (https://114697239-saas-19-2-all.runbot254.odoo.com/web/assets/5482857/web.assets_web.min.js:867:47)
```
Note: The error only occurs when the contact has at least one bank accounts (bank_ids) in the Accounting tab.
`FieldMany2ManyTagsBanks` inherits from `Many2ManyTagsField`, whose `getTagProps()` [method](https://github.com/odoo/odoo/blob/saas-19.2/addons/web/static/src/views/fields/many2many_tags/many2many_tags_field.js#L165-L173) intentionally sets `onDelete` to [undefined](https://github.com/odoo/odoo/blob/saas-19.2/addons/web/static/src/views/fields/many2many_tags/many2many_tags_field.js#L168) when the field is rendered in readonly mode.
However, `BankTag` declares `onDelete` as a required [prop](https://github.com/odoo/odoo/blob/saas-19.2/addons/account/static/src/components/many2many_tags_banks/many2many_tags_banks.js#L18). Since Studio renders the field as readonly, `onDelete` is undefined, causing Owl prop validation to fail.
Make `onDelete` optional in `BankTag` to match the behavior of the parent widget and the underlying `BadgeTag` component, which already defines `onDelete` as [optional](https://github.com/odoo/odoo/blob/saas-19.2/addons/web/static/src/core/tags_list/badge_tag.js#L12).
This fixes the Owl error when opening the Accounting tab in Studio.
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#271019When a database field changes from one index type to another, Odoo now replaces the old index instead of silently keeping the outdated one. This helps keep searches fast and reliable after upgrades, especially for records that rely on specialized search indexes.
Original PR description
Description of the issue/feature this PR addresses: `Registry.check_indexes` derives a column index's name as `<table>__<column>_index`, which does **not** encode the access method, and only creates…
Description of the issue/feature this PR addresses:
`Registry.check_indexes` derives a column index's name as `<table>__<column>_index`, which does **not** encode the access method, and only creates the index when no index of that name already exists. It never inspects the access method of an existing index.
As a consequence, changing a field's `index=` kind on an **already-indexed** column is silently ignored on existing databases. For example `account.move.name` was changed from a plain btree index to `index='trigram'`:
```python
name = fields.Char(
...
index='trigram',
)
```
On a fresh database this creates the expected GIN/trigram index. On any database that already had the btree index, the old btree index keeps its name, so `check_indexes` finds the name present and does nothing. The `(=)ilike` searches the trigram index was meant to accelerate keep falling back to sequential scans, with no error or warning.
Current behavior before PR:
### Steps to reproduce
1. Install a module on an existing DB while a `Char` field is `index=True` (btree).
2. Change the field to `index='trigram'` and upgrade the module.
3. `\d <table>` in psql — the index is still `USING btree`, not `USING gin`.
Desired behavior after PR is merged:
`check_indexes` now also reads each existing index's access method (`pg_am.amname`). When the method no longer matches what the field expects (`gin` for trigram, `btree` otherwise), the stale index is dropped and recreated. The drop is issued inside the **same savepoint** as the recreate, so a failed rebuild (e.g. a lock timeout) rolls the drop back and never leaves the column without an index.
Scope: only the access method is reconciled. A change that alters solely the partial predicate (`btree` -> `btree_not_null`) keeps the same method and is intentionally left untouched.
### Notes
- This extends the existing index-management logic in place and keeps the current "keep unexpected index" behaviour for fields that dropped `index=` entirely; only fields that still want an index, of a different method, are rebuilt.
- Trigram rebuilds still require the `pg_trgm` extension; without it the GIN index is skipped exactly as before (`self.has_trigram` guard).
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#272198
Forward-Port-Of: odoo/odoo#268505When a partner’s official data is refreshed in the POS flow, the updated legal information is now correctly shown right away. This avoids POS keeping a temporary name after the government lookup has returned the verified partner details.
Original PR description
Step to reproduce: - install l10n_co_dian and pos - open pos and click on create a new partner from partner list - enter name ex. "temp", identification number, click on form - notice a `refresh…
Step to reproduce: - install l10n_co_dian and pos - open pos and click on create a new partner from partner list - enter name ex. "temp", identification number, click on form - notice a `refresh icon` is visible: click on it. Observation: - the dialog is closed and partner is selected with "temp" name Expected: - with valid government credentials and a valid identification number, the refresh action should also update the partner data on the POS side Cause: - the refresh button triggers the `button_l10n_co_dian_refresh_data` action, which fetches the legal name and email from the government service - although the backend record is correctly updated, the new values are not immediately synchronized with the POS - when the refresh button is clicked, editPartner() first triggers `web_save` using the temporary "temp" name and immediately reads the partner data afterward - the refresh action executes later and updates the contact with the fetched legal information, but the POS is not aware of these subsequent changes Fix: - read the data again if there is any update caused by this action. - this is done by overriding `afterExecuteActionButton` of FormController class opw-6198035 Forward-Port-Of: odoo/enterprise#117527
This update ensures that upgraded databases for the Dominican Republic localization receive the latest chart of accounts, taxes, and tax groups. It prevents missing accounting records after an upgrade, so businesses keep using the correct local accounting setup without manual fixes.
Original PR description
Steps to Reproduce: * Create a database before saas~19.3. * Install to l10n_do and company configured * Upgrade the database to saas~19.3. * Check the Dominican Republic chart of accounts, taxes, and…
Steps to Reproduce:
* Create a database before saas~19.3.
* Install to l10n_do and company configured
* Upgrade the database to saas~19.3.
* Check the Dominican Republic chart of accounts, taxes, and tax groups.
Issue:
* The localization updates introduced in saas~19.3 are not loaded during the upgrade.
* As a result, some Dominican Republic accounts, taxes, and tax groups are missing after the upgrade.
Cause:
* New localization data was introduced for `l10n_do`, but the chart template is not reloaded during the upgrade.
* Consequently, the newly introduced records are never created on upgraded databases.
Related:
https://github.com/odoo/odoo/pull/257233
Fix:
* Reload the Dominican Republic chart template during the upgrade using `account.chart.template.try_loading('do', company)` to ensure all newly
introduced accounts, taxes, and tax groups are created.
opw-6274580
upg-4333738
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-prThis fix lets users record several finished-product serial numbers or lots in a single barcode session during manufacturing. It prevents the last scan from overwriting earlier ones, so production can be validated correctly and the right lot information is saved.
Original PR description
Steps to reproduce ------------------ Serial-tracked finished product: 1. Create a serial-tracked finished product and an un-tracked component. 2. Create a Manufacturing Order with quantity 2 and…
Steps to reproduce ------------------ Serial-tracked finished product: 1. Create a serial-tracked finished product and an un-tracked component. 2. Create a Manufacturing Order with quantity 2 and confirm it. 3. Open the Barcode app, scan the MO, then scan a first serial number SN_X1. 4. Scan a second serial number SN_X2. 5. Validate. Lot-tracked finished product: 1. Create a lot-tracked finished product with a one-component BoM and an existing lot LOT_A. 2. Create a Manufacturing Order and confirm it. 3. Open the Barcode app, scan the MO, then scan the existing lot LOT_A. 4. Scan a different, not-yet-existing lot LOT_B. 5. Validate. Issue ----- Only the last scanned serial is registered on the MO, and validation then fails because the count of producing serials does not match qty_producing for a serial-tracked finished product. updateLine overwrote lot_producing_ids with [args.lot_id] on every scan, so the first serial was dropped when the second one was scanned, and the same branch never staged a freshly typed lot_name, so a brand-new serial typed on a serial-tracked MO was lost before reaching the backend. https://github.com/odoo/enterprise/blob/4a2f1da5466740b7758d1962e5241620845d616b/stock_barcode_mrp/static/src/models/barcode_mrp_model.js#L407 Two behaviours of the shared barcode dispatcher make a single accumulating branch insufficient. The final-product line must keep exposing a producing lot, otherwise the base hasUnassignedQty check counts a scanned serial as zero once a quantity is already set, leaving qty_producing stuck below the demand. https://github.com/odoo/enterprise/blob/f622064871bf55b93890606d16407c50cf4419a6/stock_barcode/static/src/models/barcode_model.js#L1446 But exposing a producing lot makes the dispatcher treat the next serial as a conflicting tracking number, since the base _canOverrideTrackingNumber considers a different lot name non-overridable. https://github.com/odoo/enterprise/blob/f622064871bf55b93890606d16407c50cf4419a6/stock_barcode/static/src/models/barcode_model.js#L796-L798 So the scan is diverted to a new line through the override gate instead of updating the header line. https://github.com/odoo/enterprise/blob/f622064871bf55b93890606d16407c50cf4419a6/stock_barcode/static/src/models/barcode_model.js#L1585 For a lot-tracked finished product the producing lot can be corrected by scanning a different value, but the lot branch only stored a freshly typed value in lot_name and overwrote lot_producing_ids with the single existing lot. https://github.com/odoo/enterprise/blob/4a2f1da5466740b7758d1962e5241620845d616b/stock_barcode_mrp/static/src/models/barcode_mrp_model.js#L404-L407 The header reads its lot from lot_producing_ids whenever that relation is set and only falls back to lot_name when it is empty. https://github.com/odoo/enterprise/blob/4a2f1da5466740b7758d1962e5241620845d616b/stock_barcode_mrp/static/src/components/header.js#L45-L58 The save path only promotes lot_name to a producing lot when lot_producing_ids is empty, so scanning an existing lot then a new one neither displayed nor recorded the new lot and the finished product was produced under the old lot. https://github.com/odoo/enterprise/blob/4a2f1da5466740b7758d1962e5241620845d616b/stock_barcode_mrp/static/src/models/barcode_mrp_model.js#L628 Solution -------- Accumulate scanned serials by appending to lot_producing_ids instead of replacing it, and stage a freshly typed lot_name as a new producing lot when the finished product is tracked by serial, so every serial reaches the backend. Keep the final-product line exposing the last producing lot so each scanned serial is still counted as one unit instead of resetting the quantity to zero once several serials are registered. Override _canOverrideTrackingNumber for the final-product line so a serial scan updates the header line rather than being diverted to a new line, which is the only valid path for the finished product since it is a single header line backed by the lot_producing_ids relation. Persist the producing serials with explicit x2many commands, separating already-existing lots from freshly typed ones, so both are written on the MO. Reject a serial that is already registered on the MO so the same number cannot be produced twice in one session. For a lot-tracked finished product, build a producing lot from the scanned value, using the existing lot or a freshly typed lot name, and store it in lot_producing_ids so the new lot is both displayed and persisted through the same x2many commands as the serial case. Leave the produced quantity unchanged when the scanned lot differs from the one already registered, since replacing the lot is a correction and not an extra unit, and keep incrementing it when the same lot is scanned again. opw-6189620 Forward-Port-Of: odoo/enterprise#116890
When a vendor bill is completed from a purchase order, related invoice details can change. This update ensures early payment discount lines are refreshed or removed correctly so the invoice and journal entries stay aligned.
Original PR description
When a vendor bill is imported and auto-completed from a purchase order, then invoice lines, taxes, fiscal position, and payment terms can change. Existing EPD dynamic lines that lose their epd_key are skipped by sync and keep stale tax tags and amounts, causing mismatches between Invoice Lines and Journal Items. This commit makes EPD sync include keyless existing EPD lines so they are rewritten or removed during dynamic recomputation after PO auto-complete. Journal items remain consistent with the final invoice lines, taxes, and early discount configuration. Ticket [link](https://www.odoo.com/odoo/project.task/6047505) opw-6047505 Forward-Port-Of: odoo/odoo#272267 Forward-Port-Of: odoo/odoo#265539
Installing Stock could previously stop with an error when a database had sales orders in a company that did not yet have a warehouse. This update skips that warehouse check during installation so the module can be installed successfully and existing records are completed without interruption.
Original PR description
Steps to reproduce the bug:
- Have a database with sale_management installed and at least two companies (Company 1 and Company 2)
- Confirm sale orders with storable products under each company
- Install the stock module (which triggers sale_stock as a bridge module)
Problem:
The installation raised a RedirectWarning ("Please create a warehouse for company 2") and aborted. During sale_stock installation, _init_column initialises the new `warehouse_id` column on `sale.order` via SQL. Orders belonging to companies that have no warehouse yet (company 2, since `create_missing_warehouse` only creates one for the first company at that point) remain NULL. The stored-field recompute then calls write(), which fires _check_warehouse. That constraint calls _warehouse_redirect_warning() for each company without a warehouse, raising a RedirectWarning that aborts the install.
opw-6302537
Forward-Port-Of: odoo/odoo#270962
Forward-Port-Of: odoo/odoo#270480This update corrects the color shown in the Timesheets grid when an employee has working hours that include fractions of an hour. It prevents the system from incorrectly marking a row as overtime or under target when the totals are actually correct, improving accuracy and user trust.
Original PR description
## Issue In the Timesheets app, the color of the *Time Spent* cell at the end of a row indicates the current status of the timesheets based on the expected number of working hours. The selected color…
## Issue
In the Timesheets app, the color of the *Time Spent* cell at the end of a row indicates the current status of the timesheets based on the expected number of working hours. The selected color (green/orange/red) is sometimes wrong when an employee has a work schedule with fractional hours.
## Steps to reproduce
1. Install *Timesheets* (`timesheet_grid`)
2. For an employee E, edit the *Standard 40 hours/week* schedule:
- Change *Monday Afternoon* "Work to" column from 17:00 to 17:20.
3. In Timesheets > All Timesheets, go back one week and fill the timesheet for the employee E. We need 8 hours everyday but on Monday, where we need 8 hours and 20 minutes.
4. __The background of the *Time Spent* cell is orange, even though there's no overtime anywhere, and the value in the cell is precisely 40:20, which is the expected amount of hours worked.__
## Cause
When comparing the amount of hours worked and the expected amount of hours, small rounding errors occur. At this point of the execution:
https://github.com/odoo/enterprise/blob/19b7f5a6961dbce7367c07fcc55eea1925832634/timesheet_grid/static/src/views/timesheet_grid/timesheet_grid_renderer.js#L157
We obtain the following values:
```js
> monday = section.cells[1]
> monday.value
8.333333333333336
> workingHours[monday.column.value]
8.333333333333332
> monday.value - workingHours[monday.column.value]
3.552713678800501e-15
```
This small difference differing from 0, the wrong color is selected by `_getSectionTotalCellBgColor`:
https://github.com/odoo/enterprise/blob/19b7f5a6961dbce7367c07fcc55eea1925832634/timesheet_grid/static/src/views/timesheet_grid/timesheet_grid_renderer.js#L160-L172
## Fix
The same issue was fixed elsewhere by https://github.com/odoo/enterprise/commit/3340c0610ae6d7d3087f20da04309512771cc4b7. The same fix is applied here for consistency.
opw-6193181
Forward-Port-Of: odoo/enterprise#121463This fix prevents PoS session closing from failing when the cash difference gain account has a default tax. The system now calculates the tax split correctly up front, so closing cash registers works reliably in countries where these accounts are taxed.
Original PR description
Steps to reproduce ------------------ 1. Set a default tax on the "Cash Difference Gain" account (e.g. a 25% sales tax) -- required in some countries like Denmark (cf 5972690). 2. Open a PoS session,…
Steps to reproduce ------------------ 1. Set a default tax on the "Cash Difference Gain" account (e.g. a 25% sales tax) -- required in some countries like Denmark (cf 5972690). 2. Open a PoS session, count more cash than expected at closing. 3. Try to close the session. -> Error message shows up "The journal entry reached an invalid state..." ... "The journal entry must always have exactly one journal item involving the bank/cash account" What's happening ---------------- PoS creates a bank statement line with the gain account as counterpart, resulting in 2 lines: cash +10, gain -10. Since the gain account has a default tax, `_sync_tax_lines` adds a tax line of -2.5 on top, which makes the move unbalanced by 2.5. Then `_sync_unbalanced_lines` adds a 4th line to fix it, on the line returned by `_get_automatic_balancing_account`, which is `journal.default_account_id`, i.e. the cash account itself for a cash journal. So we end up with 2 lines on that same cash account, which a bank statement line move doesn't allow -> Error. The fix ------- In `_post_statement_difference`, precompute the base and tax split ourselves and build the statement line's `line_ids` directly (e.g. for +10 and a 25% tax: cash +10, gain -8, tax -2). The move is balanced from creation, so `_sync_tax_lines` and `_sync_unbalanced_lines` don't have to touch it. Note that we force the tax computation to be in 'force_price_include' mode, as the counted cash difference is a gross amount (physical money in the drawer). This way the tax is always extracted from the cash amount, regardless of how the tax is configured (included or excluded in price). Same pattern is already used by `hr_expense` (cf `hr_expense.models.account_move_line._compute_totals`). opw-5972690 Forward-Port-Of: odoo/odoo#271921 Forward-Port-Of: odoo/odoo#257892
This change prevents a crash that could happen when loading accounting charts for Spanish templates in certain setup flows. It makes the loading process more robust by avoiding a missing-data lookup, so chart setup and tests complete reliably.
Original PR description
Description of the issue this commit addresses: In single-app and patched chart-template flows, template_data can be provided without a parent key. l10n_es accessed template_data['parent'] in _post_load_data, raising KeyError during chart loading and test setup. --- Desired behavior after this commit is merged: This commit checks ES template ancestry from template_code instead of reading parent from template_data, avoiding KeyError when that key is absent while keeping the post-load logic scoped to ES template chains. --- runbot-[242586](https://runbot.odoo.com/odoo/error/242586) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix removes an unnecessary block that stopped Gemini 3 from being used with tools and structured responses. As a result, AI features can work again for website SEO optimization and for retrying failed AI actions when another provider is unavailable.
Original PR description
Purpose: -------- Gemini models since gemini-3 support requests with tools and structured outputs. The exception in the code is now raised only for gemini-2.5 models. This exception was preventing to use an agent with gemini 3 to optimize SEO in ai_website, or to retry failed ai fields or ai server actions on the saas when the request to openAI failed. Task-6335595
This change cleans up automated Point of Sale test data by removing an unnecessary product tracking setting and consolidating overlapping test cases. It also moves a stock-related test to the Stock POS area so the test suite is better organized and easier to maintain.
Original PR description
*: pos_stock In this commit: --- - Remove the `tracking` field from the HOOT test data. - Remove `test_order_unexisting_lots`, as it is already covered in `pos_stock`. - Move `test_order_existing_lot_gs1_nomenclature` from `point_of_sale` to `pos_stock`, where the stock-related behavior belongs. runbot-941084 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This change lets Odoo keep very small base unit counts without rounding them away, so product reference prices are calculated correctly for large-pack items. It improves pricing accuracy for cases like selling screws in boxes of 10,000 or similar bulk packaging.
Original PR description
**Description of the issue/feature this PR addresses:** The `Product Reference Price` feature in `website_sale` cannot correctly handle products sold in large packs when the reference quantity…
**Description of the issue/feature this PR addresses:** The `Product Reference Price` feature in `website_sale` cannot correctly handle products sold in large packs when the reference quantity requires a very small `base_unit_count`. For example, a product sold as a `box of 10000` screws should be able to use `0.0001` as its `Base Unit Count`, so the reference price can be computed against the box quantity correctly. **Current behavior before PR:** `base_unit_count` uses the default float precision, so values with more than two decimal places are rounded in the product form. When trying to set `Base Unit Count` to `0.0001`, the value is rounded to `0.00` / `0.01`, which makes the Product Reference Price computation incorrect. Steps to reproduce: 1. Go to Settings > Website and enable Product Reference Price. 2. Create or open a product named `Screws`. 3. Set Sales Price to `$ 1.00`. 4. On the product form, set Base Unit Count to `0.0001`. 5. In Custom Unit of Measure, type `box of 10000` and press Create. <img width="1374" height="740" alt="1" src="https://github.com/user-attachments/assets/2d4f7863-b2cd-4c7c-87e1-11526dc50551" /> **Desired behavior after PR is merged:** `base_unit_count` keeps high-precision values such as `0.0001`. This allows `Product Reference Price` to correctly support large-pack scenarios, such as selling screws in a `box of 10000`, by storing `base_unit_count` with unlimited numeric precision. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262579
This update stops popup snippets from being added in places where they should not be available, such as inside other popups. It also ensures the available snippets are refreshed correctly after changes, helping avoid errors and keeping the website editor more reliable.
Original PR description
*: website, website_mass_mailing __Problem__ In some cases, popup snippets can be dropped inside another popup. This shouldn't be possible. Moreover, it produces the following error: `TypeError:…
*: website, website_mass_mailing __Problem__ In some cases, popup snippets can be dropped inside another popup. This shouldn't be possible. Moreover, it produces the following error: `TypeError: Cannot read properties of undefined (reading 'after')`. This can happen in multiple scenarios: - After saving a custom snippet, the snippets are reloaded but `disableUndroppableSnippets` is not called again, although the snippets should be filtered again. - `NewsletterPopupPlugin` registers `.o_newsletter_popup` in the `so_snippet_addition_selector` resource, bypassing the more restrictive `dropzone_selector` of `PopupOptionPlugin`. - Popups are not disabled when the cookie bar is open because we don't take `excludeAncestor` into account in `DisableSnippetsPlugin`. __Fix__ - Trigger an event whenever the snippets are loaded and call `disableUndroppableSnippets` when it is. - Remove the redundant `NewsletterPopupPlugin`. - Filter `dropAreaEls` with `excludeAncestor` in `DisableSnippetsPlugin`. Forward-Port-Of: odoo/odoo#271635 Forward-Port-Of: odoo/odoo#269864
This fix ensures the preview shown for favorite email templates updates correctly when users switch between target models. Previously, the template title changed as expected, but the preview could stay stuck on an older template, which could cause confusion when choosing a mailing layout.
Original PR description
Overview ------ When having a favorite mailing (template) for target model X, and another one for target model Y, and try to create a new mailing for target model X, the theme selector will first…
Overview ------ When having a favorite mailing (template) for target model X, and another one for target model Y, and try to create a new mailing for target model X, the theme selector will first show the template X with the correct title and preview, however when switching to model Y, the theme selector will show the title of the tempalte Y but the preview is always the one of template X. How to reproduce ------ 1. Create a new mailing for a target model X (e.g. `mailing.contact`) 2. Set a content for that mailing (you can choose from the existing themes) 3. Set that mailing as a favorite (using the favorite star button) 4. Create a new mailing for another target model Y. 5. Redo steps 2. and 3. 6. Create a new mailing, and set the target model to X (You should see the mailing X in the theme selector with the correct title and preview) 7. Change the target model to Y. Expected Behavior ------ Both the title and the preview of the mailing X in the theme selector should change into the title and the preivew of mailing Y. Current Behavior ------ The title of the template is changed into the one of Y however the preview remains the one of mailing X. Cause of The Issue ------ After the first mount of the `FavoritePreivew` component, when the template changes in the props, the body content of the preivew is not updated with the new value. Task-6332946 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272065
The Shopee connector now handles customer identifiers that are larger than the older supported range. This prevents errors when creating new contacts and ensures Shopee orders can still be matched to the correct customer.
Original PR description
When the Shopee connector was introduced, Shopee documented `buyer_user_id` as an int32. We therefore store it in an `Integer` field, which maps to a PostgreSQL int32 column. However, feedback showed that Shopee can send ids exceeding the int32 bounds, leading to a traceback when creating new contacts. Shopee has since updated their documentation to confirm the field is actually an int64. Since we are in stable and cannot change the column type, this commit falls back to the `ref` field of the `res.partner` model to store and match Shopee contacts whose identifier doesn't fit within an int32. opw-6325948 See also: - master: https://github.com/odoo/enterprise/pull/121507 - upgrade: https://github.com/odoo/upgrade/pull/10578 Forward-Port-Of: odoo/enterprise#121498
This fix prevents POS down payments from being counted twice when calculating how much is still left to invoice on a sales order. It ensures the final invoice shows the correct remaining amount and avoids negative invoice balances.
Original PR description
Steps to reproduce --- 1. Create and confirm a sale order 2. In the POS, settle it with a down payment and invoice the down payment 3. From the sale order, create and post the final invoice Issue --- The order ends up with a negative amount to invoice. The pos_sale override https://github.com/odoo/odoo/blob/a1bcd917846493d08dd02b63e6110078ff5156a3/addons/pos_sale/models/sale_order.py#L83-L88 always subtracts the amount paid in the POS, which is required before the final invoice because the down payment sits on a separate line the base computation ignores; but once the final invoice is posted that down payment is already deducted through its negated line, so subtracting it again counts it twice and pushes amount to invoice below zero. opw-6261272 Forward-Port-Of: odoo/odoo#269323
This change fixes the Apps > Industries page so filters can be applied again. It improves the way industry listings are prepared in the background, allowing users to narrow down results more easily when browsing apps by industry.
Original PR description
Before this commit, no filter could be applied on Apps > Industries menu, because the module list returned by the appstore was difficult to filter as is. This commit uses the `new` command to create temporary ir.module.module such that any filtering domain can be applied, providing that the filter condition is available from the appstore controller. task-6067092 Forward-Port-Of: odoo/odoo#270005
This fix ensures the pencil button used to suggest forecasted demand stays visible even when the Forecasted Stock row is hidden. It prevents an unrelated display change from hiding an important action in Master Production Schedule, making planning smoother for users.
Original PR description
Steps to reproduce:
1. Install Manufacturing.
2. Enable 'Master Production Schedule' in the Settings.
3. Go to [Manufacturing -> Planning -> Master Production Schedule].
4. Ensure 'Demand Forecast' and 'Forecasted Stock' rows are enabled from the dropdown.
5. Observe the edit pencil button next to 'Forecasted Demand' is visible.
6. Hide 'Forecasted Stock' using the rows filter dropdown.
Issue:
The edit pencil button ("Suggest Forecasted Demand") next to the 'Forecasted Demand' row disappears when the 'Forecasted Stock' row is hidden.
Expected behavior:
The edit pencil visibility should not be affected by the 'Forecasted Stock' row.
opw-6240596
Forward-Port-Of: odoo/enterprise#120208This update prevents the Point of Sale from crashing when a Pine Labs payment is force-cancelled after the terminal has already timed out or been cancelled. It improves the cancellation flow so staff can safely close the payment without seeing an error screen.
Original PR description
**Step to Reproduce:** 1. Open the POS. 2. Add any product to the order. 3. Proceed to the payment screen and select `Pine Labs` as the payment method. 4. Observe that the Pine Labs terminal does not…
**Step to Reproduce:** 1. Open the POS. 2. Add any product to the order. 3. Proceed to the payment screen and select `Pine Labs` as the payment method. 4. Observe that the Pine Labs terminal does not respond and no payment popup appears on the device. 5. Wait until the payment request is cancelled (either manually or due to timeout). 6. Click the `Force Cancel` button. 7. Observe that the POS throws a traceback. **Video:** https://drive.google.com/file/d/1A3QPdby-J12IWgOX_SfCLrauQ_QnbqvG/view **Issue:** When a Pine Labs payment request is cancelled (either through a cancel request or by timeout), clicking the `Force Cancel` button results in a traceback in the POS. **Reason:** During the cancellation flow, the payment line status is updated to `retry` so that the transaction can be marked as cancelled and retried if necessary. Later, when the user clicks `Force Cancel`, `_paymentCancelRequestHandler()` attempts to retrieve the pending Pine Labs payment line using: ```javascript const line = this.pendingPineLabsPaymentLine(); ``` However, `pendingPineLabsPaymentLine()` only returns payment lines whose status is not `retry`, as defined here: https://github.com/odoo/odoo/blob/19.0/addons/point_of_sale/static/src/app/services/pos_store.js#L1820 Since the payment line was already transitioned to the `retry` state during the cancellation flow, no `payment line` is found and `line` becomes `undefined`. The handler subsequently attempts to update the status of this `undefined` `payment line`, resulting in the traceback when `Force Cancel` is executed. **Solution:** Add a condition in `_paymentCancelRequestHandler()` to verify that a payment line is available before attempting to update its status. If no payment line is found, it indicates that the payment line has already been moved to the `retry` state during a previous cancellation attempt. In such cases we clear `pollingTimeout`, `inactivityTimeout` and reset `this.payment_stopped` to `false`. This prevents the traceback while ensuring that the `Force Cancel` flow properly cleans up the pending payment state. opw-6297135 Forward-Port-Of: odoo/odoo#271397 Forward-Port-Of: odoo/odoo#271241
When sending invoices with a custom report attached, the attachment will now keep its own configured filename instead of inheriting the standard invoice’s localized name. This prevents duplicate-looking attachments and makes emailed invoices easier to identify for customers and accounting teams.
Original PR description
Steps to reproduce: * Install `l10n_mx_edi` (or `l10n_sa_edi`). * Go to **Accounting → Customers → Invoices**. * Open **Studio** and, from the top bar, go to **Reports**. * Duplicate the standard…
Steps to reproduce: * Install `l10n_mx_edi` (or `l10n_sa_edi`). * Go to **Accounting → Customers → Invoices**. * Open **Studio** and, from the top bar, go to **Reports**. * Duplicate the standard **Invoice PDF** report. * Open the duplicated report and make any modification to it. * Enable **Developer Mode**. * Go to **Settings → Technical → Actions → Reports** and update the custom report's **Printed Report Name**. * Go to **Settings → Technical → Email → Templates** and create a new invoice email template. * Add the custom report to the template's **Dynamic Reports**. * Create and confirm an invoice for a **Mexican company**. * Click **Send** and select the newly created email template. Observed behavior: * The custom report attachment uses the CFDI-based filename instead of its own report name, making it appear as a duplicate of the standard invoice attachment. Cause: * `_get_placeholder_mail_template_dynamic_attachments_data` relied on the `invoice_report` context key to pass the extra report into `_get_invoice_report_filename`. However, localization overrides (e.g. `l10n_mx_edi`, `l10n_sa_edi`) unconditionally return their own filename without checking the context, so the extra report's `print_report_name` was never evaluated. Fix: * Introduce `_get_invoice_mail_template_dynamic_report_filename` on `account.move` that directly evaluates a given report's `print_report_name`, bypassing the localization override chain. * Call this new method in `_get_placeholder_mail_template_dynamic_attachments_data` instead of the context-based `_get_invoice_report_filename` call. This avoids the need to patch every localization override and cleanly separates the concern of naming dynamic report attachments from the main invoice report filename logic. opw-6228268 Forward-Port-Of: odoo/odoo#271489
This update removes a warning generated by the documentation system when it starts up. It helps keep the code compatible with newer Docutils versions and reduces the risk of future breakage.
Original PR description
Using `Publisher.set_components()` triggers a `PendingDeprecationWarning` stating that the method will be removed in Docutils 2.0. This commit fixes the warning by passing the component names (`reader`, `parser`, and `writer`) directly into the `Publisher` constructor during instantiation, ensuring compatibility with upcoming Docutils versions. runbot-940246 Forward-Port-Of: odoo/odoo#272117
This update fixes a test issue in WhatsApp channels where a seen-status update could be sent before the connection was ready to receive it. As a result, the seen indicator now loads reliably and the test no longer fails intermittently.
Original PR description
The "Allow SeenIndicators in WhatsApp Channels" test delivers the seen update over the bus with `_sendone`, but nothing waited for the websocket to subscribe to the channel first. When the notification was sent before the subscription landed it was dropped, the member's seen_message_id was never updated client-side and the seen indicators never rendered, so the assertion timed out. The current user is a member of the channel, so it is subscribed at connection time: wait for the subscription together with `start()` (listener registered first) before opening the channel and sending the notification. https://runbot.odoo.com/odoo/error/242021 Forward-Port-Of: odoo/enterprise#121857
This change fixes an automated test so it works in databases that only have the Invoicing app installed. It prevents test failures in community setups where the accounting-specific payment state is not available.
Original PR description
The `in_payment` state does not exist in community with only the Invoicing module installed. It is added in `enterprise` in the Accounting module. runbot.build.error-939451 Forward-Port-Of: odoo/odoo#267475
The stock forecast report now converts all incoming and outgoing quantities into the product’s own unit of measure before showing them on the graph. This prevents mixed units from distorting the chart, so the forecast is easier to read and gives a more accurate view of future stock.
Original PR description
When a stock move's UoM differs from the product template's UoM, the report aggregation incorrectly shows data for both UoMs of stock move.quantity on the same graph. All moves should be normalized…
When a stock move's UoM differs from the product template's UoM, the report aggregation incorrectly shows data for both UoMs of stock move.quantity on the same graph. All moves should be normalized to the UoM of the product for which we are viewing the forecast. We can do this with: `m.quantity * move_uom.factor / pt_uom.factor AS quantity` If the UoMs of the stock move and the product template are identical, as is the case most of the time, this simply multiplies by one, and the query behaves exactly as it did before. But if the units are distinct, the move UoM is converted into the product template UoM so that the data for stock move quantity is normalized to one shared unit across the entire forecast graph. **E.g.**: m.quantity == 500g m.UoM == g m.UoM.factor == 1 pt.UoM == kg pt.UoM.factor == 1000 500g * 1 / 1000 ==> .5kg **Steps to Reproduce on Runbot**: 1. Create a product which uses kg and g. 2. Confirm and Validate a receipt for this product (10 kg for example). 3. Confirm a second receipt for this product in the same UoM kg. 4. Confirm and Validate a delivery for this product with UoM g (500 g for example). 5. View the forecasted graph for the product, and you will see that the y axis is scaled on grams ~500, and the current / future stock moves in the report are still scaled based on kg. opw-6234066 Forward-Port-Of: odoo/odoo#272245 Forward-Port-Of: odoo/odoo#266811
This fix prevents the Point of Sale app from crashing when a company has no country set. It makes receipt-related processing more resilient, so users are less likely to encounter an unexpected error during normal operations.
Original PR description
### Description: Fix an unhandled exception linked to `vat_check` by using optional chaining. When a company does not have a country set, accessing `vat_check` throws an error because the parent object is undefined. ### Reference: opw-6321507 ___ I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271853
This update stops the messaging autocomplete from offering a “Create” action when there is no usable recipient text. It prevents accidental creation of blank contacts, avoiding clutter and later errors when those contacts are opened in Contacts.
Original PR description
The chatter recipients input always added a "Create" option to its autocomplete dropdown, even when the field held no text. The feature that introduced this input,…
The chatter recipients input always added a "Create" option to its autocomplete dropdown, even when the field held no text. The feature that introduced this input, https://github.com/odoo/odoo/commit/3b985d2c4239fe702c1a56bef04fc112af39e954, wired that option to create a res.partner straight away. Selecting "Create" with an empty input therefore created a partner with no name, displayed everywhere as "Unnamed". The email popover that opens for a recipient without an address then offered a Discard button, but the empty partner was already saved. The same sequence could be repeated to accumulate nameless contacts, which later raise a missing name error when opened in the Contacts app. Only add the "Create" option when the typed term resolves to a name or an email, in getAutoCompleteSources of recipients_input.js. An input with no usable text has nothing to create from, which matches the standard many2one autocomplete that only offers creation once text is entered. Steps to reproduce: 1. Open any record with a chatter 2. Click "Send message" 3. In the recipients field type a character then delete it, leaving the field empty with the dropdown still open 4. Click the "Create" option 5. On the "What's the email address of Unnamed?" popover, click Discard => A blank "Unnamed" contact is created, and repeating the steps creates more Ticket [link](https://www.odoo.com/odoo/action-4043/5942428) opw-5942428 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#250973
Tax reports now correctly include lines that belong to child taxes inside a tax group. This fixes missing amounts in generic report queries, helping ensure Philippine tax reports are more accurate and complete.
Original PR description
When using group taxes, the base invoice lines only store the parent tax in the `account_move_line_account_tax_rel` table. Because of this, if a child tax within the group contains a specific tax report tag, the generic report query would previously fail to pick up those base lines. This commit updates the SQL join conditions in `l10n_ph_generic_report.py` to also match `account_tax.id` against the child taxes of the linked parent tax using the `account_tax_filiation_rel` table. This ensures that base lines are correctly reported under the tags of their respective child taxes. Task-6278098 Forward-Port-Of: odoo/enterprise#121876 Forward-Port-Of: odoo/enterprise#121596
This update adds validation to ensure the company SIA code used for Italian Ri.Ba. exports is exactly 5 characters long. It prevents batch payment validation from failing with an error when the code is too long, helping users complete payments smoothly.
Original PR description
Currently, the sia_code field on res.company lacks length validation. For Italian Ri.Ba (CBI) exports, this field MUST be exactly 5 characters. If a user enters more (e.g., during initial setup), the Batch Payment validation (specifically the XML file generation) crashes with a traceback. Steps to Reproduce: - Set Company SIA Code to 6+ characters - Create multiple payments with Ri.Ba. method - Create a Ri.Ba Batch Payment - Click 'Validate' Ticket [link](https://www.odoo.com/odoo/project.task/6031062) opw-6031062 Forward-Port-Of: odoo/enterprise#121610
This update fixes a problem that could cause invoices with many section lines to crash when the system tries to calculate line grouping. It prevents unnecessary repeated recalculations, making large invoices more reliable to open and process.
Original PR description
Since PR #223686, `parent_id` became a non-stored field. On complex invoices with many sections, assigning `parent_id` to lines outside the current compute batch in `_compute_parent_id` triggers unwanted cascading recomputes. **Steps to reproduce:** 1. Create an invoice with 200+ sections and at least one product per section. 2. Read `parent_id` for any line. 3. "RecursionError: maximum recursion depth exceeded" is raised. **Fix:** Only assign `parent_id` to lines within the protected compute batch. opw-6302149 Forward-Port-Of: odoo/odoo#271350
The website generator’s page limit message has been rewritten to be more general instead of naming a fixed number. This gives the team more flexibility to adjust page limits later without needing another wording change.
Original PR description
Page limit note fixed by being more general instead of stating a blatant 200. This gives us more leeway to control the nbr of pages IAP side. Forward-Port-Of: odoo/enterprise#121827 Forward-Port-Of: odoo/enterprise#121671
This update ensures taxes defined to apply everywhere continue to work even when no fiscal position is set. It also keeps the tax-related view and totals in sync after fiscal position changes, so users see the right taxes and balances.
Original PR description
A tax created without a fiscal position (empty fiscal_position_ids) is conceptually an "All" tax: it should apply across every fiscal position, including the empty ones used for tax units. Problem…
A tax created without a fiscal position (empty fiscal_position_ids) is conceptually an "All" tax: it should apply across every fiscal position, including the empty ones used for tax units. Problem map_tax drops every tax when the FP has no mapping, including the "All" ones that should pass through. action_open_related_taxes only lists the FP's tax_ids, so "All" taxes are invisible from the FP form. The Taxes stat button is hidden whenever the FP has no tax_ids. action_update_fpos_values invokes the field computes directly, so tax and balance lines fall out of sync after an FP change. Fix map_tax: when the FP has no tax_ids, return the input taxes whose fiscal_position_ids is empty (the "All" ones) instead of an empty recordset. action_open_related_taxes: extend the domain to also include taxes bound to no fiscal position. partner_view: drop the invisible="not tax_ids" guard on the Taxes stat button. action_update_fpos_values: route the deferred computes through _check_balanced and _sync_dynamic_lines so tax lines stay in sync after the update. task-id [6231514](https://www.odoo.com/odoo/project/967/tasks/6231514) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272350 Forward-Port-Of: odoo/odoo#268273
This change corrects a tax test so it no longer treats all taxes the same when a fiscal position is applied. Taxes that are not linked to any fiscal position are now correctly kept, while only taxes tied to a fiscal position are expected to be removed, making the test match real behavior more accurately.
Original PR description
map_tax on an empty fiscal position now preserves taxes with no fiscal_position_ids. Filter those out in test_tax_unit_auto_fiscal_position so the assertion only checks that taxes bound to a fiscal position are dropped by the unit FP. comunity PR: https://github.com/odoo/odoo/pull/268273 task-id 623151 Forward-Port-Of: odoo/enterprise#121889 Forward-Port-Of: odoo/enterprise#121525
This change prevents the Italian POS fiscal printer from getting stuck after printing the first receipt. It removes a timing conflict between receipt printing and the receipt screen, so the printer can continue handling later messages normally without requiring a page reload.
Original PR description
Module: l10n_it_pos Steps to reproduce: - In the POS settings, enable "Automatic Receipt Printing"; - Enable "ePos Printer" to make the "Skip Preview Screen" option appear; - Disable "Skip Preview…
Module: l10n_it_pos Steps to reproduce: - In the POS settings, enable "Automatic Receipt Printing"; - Enable "ePos Printer" to make the "Skip Preview Screen" option appear; - Disable "Skip Preview Screen"; - Disable "ePos Printer"; - Set up an Italian Fiscal Printer; - Open a POS session and process a first order. Issue: After the first receipt, no other messages (price display, receipt, open register) are sent to the fiscal printer. A page reload is required. Cause: When "Automatic Receipt Printing" is true but "Skip Preview Screen" is false, a race condition occurs. `afterOrderValidation` triggers a print job while simultaneously transitioning to the `ReceiptScreen`. When the `ReceiptScreen` mounts, it triggers a second fiscal print job before the first has resolved. This creates a deadlock in `toHtml` of `renderService`, permanently blocking the printer queue. Solution: Since the italian localisation sending the receipt to the fiscal printer is mandatory, the printing route is now tied to the "Skip Preview Screen" option. Enterprise PR: https://github.com/odoo/enterprise/pull/112654 [opw-5979212](https://www.odoo.com/odoo/project/49/tasks/5979212) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271685 Forward-Port-Of: odoo/odoo#256932
This change prevents the Italian fiscal printer from getting stuck after the first receipt in POS. It removes the conflicting receipt-printing path and aligns the receipt flow with the fiscal printer setup so printing continues normally without requiring a page refresh.
Original PR description
Module: l10n_it_pos Steps to reproduce: - In the POS settings, enable "Automatic Receipt Printing"; - Enable "ePos Printer" to make the "Skip Preview Screen" option appear; - Disable "Skip Preview…
Module: l10n_it_pos Steps to reproduce: - In the POS settings, enable "Automatic Receipt Printing"; - Enable "ePos Printer" to make the "Skip Preview Screen" option appear; - Disable "Skip Preview Screen"; - Disable "ePos Printer"; - Set up an Italian Fiscal Printer; - Open a POS session and process a first order. Issue: After the first receipt, no other messages (price display, receipt, open register) are sent to the fiscal printer. A page reload is required. Cause: When "Automatic Receipt Printing" is true but "Skip Preview Screen" is false, a race condition occurs. `afterOrderValidation` triggers a print job while simultaneously transitioning to the `ReceiptScreen`. When the `ReceiptScreen` mounts, it triggers a second fiscal print job before the first has resolved. This creates a deadlock in `toHtml` of `renderService`, permanently blocking the printer queue. Solution: Since the italian localisation sending the receipt to the fiscal printer is mandatory, the printing route is now tied to the "Skip Preview Screen" option. UI settings are adjusted to hide the redundant auto-print checkbox when an IT fiscal printer is configured. Community PR: https://github.com/odoo/odoo/pull/256932 [opw-5979212](https://www.odoo.com/odoo/project/49/tasks/5979212) Forward-Port-Of: odoo/enterprise#121556 Forward-Port-Of: odoo/enterprise#112654
This fix prevents an error when sending Colombian debit notes to DIAN. It removes a field that should not be included in debit note documents, so these documents can be generated and submitted successfully.
Original PR description
Issue: Sending Debit Notes to a tax authority can cause the following error: "ValueError: The following child node is not defined in the template: DebitNote/cbc:BuyerReference" Steps to reproduce on…
Issue: Sending Debit Notes to a tax authority can cause the following error: "ValueError: The following child node is not defined in the template: DebitNote/cbc:BuyerReference" Steps to reproduce on any database with DIAN and Colombian localization: 1. Create a new "Sales" type journal. Then, check the checkbox “Nota de Debito”. 2. Find a res.partner with a ref field, or add a ref field to any partner. 3. Make an invoice using the partner found in step 2. Ensure it uses a tax. Confirm it. 4. Send that invoice to DIAN. 5. Create a Debit Note for that invoice. Use the journal created in step 1. 6. Add a product, price, and tax to the debit note. Confirm it. 7. Send the debit note to DIAN. Explanation: The `_add_invoice_header_nodes` method on the AccountEdiXmlUbl_21 model adds a BuyerReference node unconditionally. (See account_edi_xml_ubl_21.py.) But the DebitNote XML template does not include a BuyerReference element (see ubl_21_debit_note.py). This caused a ValueError when assembling the XML for debit note documents. Solution: The fix overrides this in the Colombian localization by clearing the BuyerReference value when the document type is "debit_note". That way, the node is omitted from the output. opw-6181039 Forward-Port-Of: odoo/enterprise#121458 Forward-Port-Of: odoo/enterprise#121422
This fix ensures that DIAN email templates are translated when a new language is added to a database. It matters because users installing languages after setup will now see these official email templates in their chosen language instead of partially untranslated content.
Original PR description
### Issue: When installing a new language on a database with `l10n_co_dian`, the DIAN email templates are not translated Languages already installed when `l10n_co_dian` is installed are correctly…
### Issue: When installing a new language on a database with `l10n_co_dian`, the DIAN email templates are not translated Languages already installed when `l10n_co_dian` is installed are correctly translated, as the copy happens at that moment Only languages installed afterwards are affected ### Cause: The DIAN email templates are created dynamically via `_create_dian_mail_templates` as copies of the `account` templates Because they are created at runtime, no translations exist for their XML IDs in the `l10n_co_dian` `.po` files The `TranslationImporter` finds nothing to import for them The fix hooks into `_load_module_terms` to sync translations from the source `account` templates to the DIAN ones whenever a new language is installed `TranslationImporter.save()` is used without `force_overwrite`, so existing translations on `noupdate` records are never replaced This is the standard way to push translations while preserving any manually modified values ### Notes: Languages installed before this fix are not updated Only newly installed languages will get the synced translations ### Steps to reproduce: - Install `l10n_co_dian` - Enable Developer Mode in Settings - Install any language (e.g. `fr_FR`) - Go in Settings > Technical > Email > Email Templates - Search for DIAN and open Invoice or Credit Note Before the fix, the DIAN invoice and credit note templates had untranslated name, description and body_html opw-6269979 Forward-Port-Of: odoo/enterprise#120855