Monday, September 28, 2026
25 changes · saas-19.4
Resolved issues and error corrections
Fixes an accounting issue where removing one partial reconciliation could also remove other related partial reconciliations by mistake. Businesses can now adjust invoices, credit notes, and payments more safely without unintentionally changing separate reconciliations.
Original PR description
Repro steps: 1) Create an invoice I 2) Partially reconcile I with a credit note CN 3) Partially reconcile I with a payment P 4) Unreconcile one of the 2 partials Problem: If you unreconcile one partial, both partials are removed (an exception is when account_accountant is installed, not just account, in that case, unreconciling P works fine, but unreconciling CN, also unreconcilies P still) Root cause: account.move.line.remove_move_reconcile used to unreconcile on move level instead of line level because of this PR https://github.com/odoo/odoo/pull/249536 Solution: The logic in remove_move_reconcile is kept simple, and it only unreconciles on account.move.line level. A new method is also introduced account.move._remove_reconciliation_between_moves to unreconcile on the move level, and this one is used with the account payment field to solve the aforementioned issue. task-6574942 Forward-Port-Of: odoo/odoo#288562
Draft invoices now recalculate totals immediately when switching between tax-exclusive and tax-inclusive modes. This prevents outdated totals from being shown before the invoice is saved, improving billing accuracy and user confidence.
Original PR description
The lines get document_tax_mode through a related field, which is not refreshed on the lines being edited. Switching a draft invoice between Tax Excl. and Tax Incl. therefore left the totals with the amounts of the previous mode until the invoice was saved. task-6596737
Fixes an issue where French employees with time off recorded on a non-working day, such as a Saturday, could prevent their working hours from being changed. The time off now keeps a valid date range, allowing HR teams to update schedules without removing valid leave records.
Original PR description
**Problem:** For a French company, an employee whose working schedule differs from the company's cannot have their Working Hours changed when they have a validated time off that falls on a…
**Problem:** For a French company, an employee whose working schedule differs from the company's cannot have their Working Hours changed when they have a validated time off that falls on a non-working day (e.g. a Saturday). Saving fails with "The operation cannot be completed: The start date must be before or equal to the end date." **Steps to reproduce:** 1. Install l10n_fr_hr_holidays and work in a French company. 2. Set the company Working Hours and a reference (Paid) Time Off type. 3. Give an employee a Monday-to-Friday schedule that differs from the company's. 4. Create a one day Paid Time Off for the employee on a Saturday. 5. Change the employee's Working Hours. **Current behavior:** Saving is rejected by the date_from <= date_to constraint; the Working Hours cannot be changed as long as the weekend time off exists. **Expected behavior:** The Working Hours can be changed and the time off keeps a valid date range. **Cause of the issue:** When the French computation applies, `_get_fr_date_from_to` moves `date_start` forward to the first working day and, in a separate loop, moves `date_target` forward while the next day is a non-working day. The two loops are asymmetric: for a leave lying entirely on non-working days (a single Saturday for a Monday-to-Friday employee) `date_start` is pushed to the following Monday while `date_target` only reaches the Sunday. The pair is then written to `date_from`/`date_to` as Monday > Sunday, violating the date_from <= date_to constraint. **Fix:** A leave that contains no working day has nothing to anchor the "lost days" extension on, so the adjustment must not apply. Detecting the crossed pointers and keeping the leave's original dates preserves a valid range while leaving every leave that contains at least one working day untouched. opw-6348425 Forward-Port-Of: odoo/odoo#285052 Forward-Port-Of: odoo/odoo#278833
Fixed an inventory issue where adding split lines in dropship operations could show an incorrect "Pick From" option and ignore the lot number or expiration date entered by the user. The change ensures newly entered lot details are used as expected, reducing delivery errors for tracked products.
Original PR description
Steps to reproduce 1. In Inventory Settings, enable Lots & Serial Numbers and Expiration Dates. 2. Create a storable product tracked by lot with Expiration Date enabled. 3. Create and confirm a…
Steps to reproduce 1. In Inventory Settings, enable Lots & Serial Numbers and Expiration Dates. 2. Create a storable product tracked by lot with Expiration Date enabled. 3. Create and confirm a dropship of it, then open the move's Detailed Operations. 4. The pre-filled line works: typing a batch and an expiration date creates exactly that lot at validation. 5. To split the quantity, click "Add a line": it opens the "Pick From" popup, and choosing "Create" there creates the lot and attaches it to the line. 6. On that line, edit "Lot/Serial Number" and "Expiration Date", then Validate. -> Expected: the values entered on the line are used. -> Actual: they are ignored; the lot created through "Pick From" is delivered with its own expiration date, the name and date typed on the line have no effect. Issue --- On a create-lots-only non-incoming operation like `Dropship`, `show_quant` is derived from `picking_code` alone, so the "Pick From" quant picker is shown even though the operation only creates lots. Adding a line goes through "Pick From", which creates the lot and attaches its `lot_id` to the move line; from then on the line's `lot_name` and `expiration_date` stay editable but do nothing, since a set `lot_id` is used as-is at validation and the `expiration_date` is recomputed from the lot, so anything typed there is silently dropped. Such an operation has no existing stock to pick from, so `show_quant` is now gated on the lot settings too: "Pick From" is hidden and the line's `lot_name` and `expiration_date` become the only inputs, created into the lot at validation like receipts already do. https://github.com/odoo/odoo/blob/68dcb950df83d70ff2aea0e05c96cc9b57c1a8a9/addons/stock/models/stock_move.py#L646-L647 opw-6530563 Forward-Port-Of: odoo/odoo#290402 Forward-Port-Of: odoo/odoo#287474
Non-admin users with the right to edit products can now upload product images through the media dialog without being blocked by an unrelated admin-only permission check. Uploaded images are correctly linked to the product record, avoiding public or unlinked attachments.
Original PR description
### Description of the issue/feature this PR addresses: Non-admin users with product create rights cannot upload a product image: the media dialog upload fails with "You are not allowed to access…
### Description of the issue/feature this PR addresses: Non-admin users with product create rights cannot upload a product image: the media dialog upload fails with "You are not allowed to access 'View' (ir.ui.view) records". The same defect affects the extra product media widgets used by website_sale. ### Current behavior before PR: ImageFieldWithMediaDialog, X2ManyImageField and X2ManyMediaViewer build their mediaDialogProps without resModel/resId. Both props are optional on MediaDialog, so the upload service posts res_model: undefined to /html_editor/attachment/add_data. The route falls back to its website-editor default of ir.ui.view, and attachment_create marks the attachment public with res_id=False while the access check runs against ir.ui.view, which only administrators pass. ### Desired behavior after PR is merged: The three widgets pass the root form record from record.model.config, so the attachment is created against the edited record, is not public, and the access check applies to the model the user has rights on. opw-6493564 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285903
Opening an order from the Sales report is now faster on databases with many sales lines. The system avoids an expensive report lookup and directly identifies the related order, improving responsiveness for sales reporting users.
Original PR description
Versions -------- - 18.0+ Steps ----- 1. On a database with many sale order lines, open Sales > Reporting > Sales and switch to the list view. 2. Click a line to open its order. Issue ----- Opening the order takes seconds. Cause ----- `action_open_order` reads `order_reference` off the `sale.report` view. The view's `id` is `MIN(sale_order_line.id)`, so reading one record filters on an aggregate. PostgreSQL therefore has to aggregate every sale order line and POS order line before keeping one row. Solution -------- The report id is itself a line primary key, so the order can be resolved without reading the view. Add a `_get_order_reference` hook returning the order from the `sale.order.line` record directly. Forward-Port-Of: odoo/odoo#289755 Forward-Port-Of: odoo/odoo#289143
Users can now click grouped Ticket Analysis graph bars or pivot cells without triggering a server error. The fix correctly links report-only employee, manager, and department groupings to the underlying helpdesk tickets, making the report drill-downs reliable.
Original PR description
Currently, an error occurs on clicking on the graph or the pivot cell if the data is grouped by Employee/Manager/Department. ### **Steps to reproduce** 1) Install helpdesk_timesheet with demo data 2)…
Currently, an error occurs on clicking on the graph or the pivot cell if the data is grouped by Employee/Manager/Department.
### **Steps to reproduce**
1) Install helpdesk_timesheet with demo data
2) Go to Timesheet > Reporting > Ticket Analysis
3) Set group by to Employee
4) Click on any graph bar or pivot cell
### **Error:**
`ValueError: Invalid field helpdesk.ticket.employee_id in condition ('employee_id', '=', 1)`
Root Cause:
The `helpdesk.ticket.report.analysis` model includes specific fields such as `employee_id`, `department_id`, and `employee_parent_id` (see [1]) that are defined for reporting purposes but do not exist on the `helpdesk.ticket` model. When a user clicks a data point to view related tickets, the reporting view passes the current domain directly to the ticket list view. Because `helpdesk.ticket` lacks these fields, the ORM fails to validate the domain, resulting in a server error.
[1]- https://github.com/odoo/enterprise/blob/8d16b647431985dd7c216ae39eea6ca050e04b46/helpdesk_timesheet/report/helpdesk_ticket_report_analysis.py#L15-L17
### **Fix:**
This commit introduces a mixin to intercept the openView call. The mixin maps reporting-specific fields to valid relational paths on the ticket model `(for example, employee_id is transformed into user_id.employee_id)`. This ensures that the domain generated from the report model is compatible with the target ticket model.
**opw-5931273**
Forward-Port-Of: odoo/enterprise#113088
Forward-Port-Of: odoo/enterprise#108503Warranty handling now leaves recurring subscription charges unchanged while still removing charges for covered field service materials or one-time work. This prevents accidental loss of subscription revenue and ensures warranty jobs are billed consistently.
Original PR description
…ce under warranty Steps to Reproduce: - Install Field Service, Sales and Subscriptions - Create a subscription SO with a recurring product with price > 0 - Create a Field Service intervention linked to that SO - Optionally add materials on the same SO linked to the intervention - Enable Under Warranty on the intervention and complete it Issue: Under Warranty resets the unit price of all linked SO lines to 0, including recurring subscription products Fix: Exclude recurring invoice lines in the subscription so under warranty only zeroes non-recurring items, so subscription SOL prices are kept as it is task-6511341
Fixes an error that appeared when users requested a transcription from a recorded phone call. This helps teams using the phone and AI features complete transcription requests without interruption.
Original PR description
Steps to reproduce: - Install phone and AI modules - Configure phone app demo to have recording and transcription forced - Make a fake a phone call to whatever number - Click on the Request Transcription button in the call form Current Behavior: - Traceback pops up Expected Behavior: - No traceback and correct functionality opw-6498749
Fixed an issue where short time off requests on flexible schedules were treated as a full day off. Attendance and Time Off views now reflect only the actual hours taken, preventing inflated overtime reporting.
Original PR description
Problem: On a flexible working schedule, a time off of a few hours (neither a full nor a half day) was treated as a full day off. The Attendance list then reported the whole day's attendance as…
Problem: On a flexible working schedule, a time off of a few hours (neither a full nor a half day) was treated as a full day off. The Attendance list then reported the whole day's attendance as overtime, and the Time Off gantt grayed out the entire day instead of only the leave's hours. Steps to reproduce: 1. Give an employee a flexible working schedule (e.g. 8h/day) with an overtime ruleset based on the contract's expected hours. 2. Record a 2-hour time off, then an 8-hour attendance on the same day. 3. Observe the attendance reports 8 hours of overtime instead of 2. Current behavior: A partial time off makes the whole day count as extra hours. Expected behavior: Only the hours actually taken off reduce the day's expected hours. Cause: For a flexible schedule, _handle_flexible_leave_interval expands a leave to the whole day. The override already narrows full-day and half-day leaves, but any other number of hours fell through to that full-day expansion. The expanded interval is subtracted from the day's expected hours in _work_intervals_batch, so they drop to zero and every worked hour becomes overtime. Fix: A leave of an arbitrary number of hours should only remove the hours it actually covers, so it keeps its requested interval instead of being stretched to the whole day. opw-6291536 Forward-Port-Of: odoo/enterprise#128022 Forward-Port-Of: odoo/enterprise#123778
This fixes a currency rate mismatch between Mexican CFDI invoices and their related payment records when using foreign currencies. Payments now keep the stored official exchange rate when the recalculated value is within an acceptable rounding range, reducing rejected or inconsistent electronic documents.
Original PR description
Issue: Currency rate for payment is recomputed up to 6 digit. However, it may differ from the official one stored in db up to 4 digits. Which creates differencies between invoice and payment rate…
Issue: Currency rate for payment is recomputed up to 6 digit. However, it may differ from the official one stored in db up to 4 digits. Which creates differencies between invoice and payment rate made at the same date. Steps to reproduce: - In MX company, - Enable USD, - Set currency rate for today to 1 USD = 17.4455 MXN - Create a PPD invoice (due date > 40 days) in USD - Add a line with - qty: 1, - unit_price: 3.488 - tax: 16% (default tax) - Send it to CFDI - Create payment - On the invoice Form click on "Update Payment" Current behavior: - In the CFDI sheet, Payment and Invoice XML files will have different currency rates Expected behavior: - In the CFDI sheet, Payment and Invoice XML files will have the same currency rate Cause: PACs require having the payment `amount` to be equal to `currency_amount * currency_rate`. For huge amout it may happen that using the 6 digits rounding of currency rate to compute the amount won't fall exactly on the two digit precision for the amount and payment would be refused. Therefore, for all payment, we recompute a 6 digits precision `currency_rate` from `amount` and `currency_amount` then using it to compute the final amount. However, Banxico (Mexican central Bank) publish rates with a 4 digit precision. Recomputing the currency rate up to 6 digits may slightly change it from the 4 digit precision official currency rate. opw-6411530 Forward-Port-Of: odoo/enterprise#132659 Forward-Port-Of: odoo/enterprise#129700
The Swiss financial reporting module now uses corrected formulas for the Swiss balance sheet. This helps businesses generate more accurate statutory balance sheet reports and reduces the risk of misleading financial totals.
Original PR description
Change some formulas in the Swiss balance sheet task-6379692 Forward-Port-Of: odoo/enterprise#132976 Forward-Port-Of: odoo/enterprise#123895
Submitting a duplicated expense now correctly shows the warning that the expense may already exist. This helps users avoid accidental duplicate reimbursements and improves expense review accuracy.
Original PR description
Steps to reproduce: - install hr_expense_extract - create an expense and submit it - duplicate that expense, and submit it - no warning dialog showed up when one should. Forward-Port-Of: odoo/enterprise#132357
Fixed an issue where selecting a product on a new vendor bill line could fail to save the product and instead place its name in the description. This helps ensure vendor bills reflect the user's chosen products correctly during entry.
Original PR description
Currently, new/virtual account move line records in a vendor bill does not respect the user's product selection. It places the name of the product in the description while leaving the product_id…
Currently, new/virtual account move line records in a vendor bill does not respect the user's product selection. It places the name of the product in the description while leaving the product_id false. This issue only exists in 19.4 due to the altered function [_onchange_name_predictive](https://github.com/odoo/enterprise/pull/117575) and version 20 introduced a [refactor](https://github.com/odoo/odoo/pull/273948) which separates the description and product name from the name field of account.move.line, inherently preventing the bug. To be more specific, when a virtual account.move.line has it's product changed, the product name changes which changes the value of the name field of account.move.line since the field is product name + \n + description. This triggers _onchange_name_predictive which will in turn overwrite the product id, even if no product id was predicted, as shown below: https://github.com/odoo/enterprise/blob/80de210d1db7d73bb13ff7db124b9fa7c2565e53/account_accountant/models/account_move.py#L1043-L1059 This bug does not affect real records as the context 'disable_onchange_name_predictive' is passed for real records, ultimately preventing the overwrites for certain fields as shown here: https://github.com/odoo/enterprise/blob/80de210d1db7d73bb13ff7db124b9fa7c2565e53/account_accountant/models/account_move.py#L1090-L1094 Steps to reproduce: - Install accounting and account_accountant - Create a new vendor bill - Create a new line and select a product Bugfix-6563221
Odoo now safely ignores file upload results when the form or dialog that started the upload has already been closed. This prevents confusing client error popups and avoids leaving uploaded attachments disconnected from their record.
Original PR description
Description of the issue/feature this PR addresses: A file upload through `FileInput` (and therefore every `many2many_binary` field) still calls `onUpload` after the component has been destroyed.…
Description of the issue/feature this PR addresses:
A file upload through `FileInput` (and therefore every `many2many_binary` field) still calls `onUpload` after the component has been destroyed. When the form or dialog holding the field goes away while the upload request is in flight, the response crashes the web client with two "Odoo Client Error" popups and the uploaded attachment is orphaned.
Steps to reproduce on a stock database (19.0, and 17.0 carries the same code):
1. Open an Email Template form (Settings > Technical > Email Templates), page *Options*, field *Attachments*. Any `target="new"` wizard with a `many2many_binary` field shows the same thing, e.g. the Recruitment *Refuse* wizard.
2. Pick a file that takes a moment to upload (a few MB, or a slow connection).
3. Before the file tile appears, leave the form through the breadcrumb, or close the wizard with Escape, its close button, or its action button. Nothing in the field shows that an upload is still running, so users do this routinely.
Current behavior before PR:
When the upload response arrives, two errors are raised:
```
UncaughtPromiseError > Component is destroyed
at webRead <- _loadRecords <- _applyCommands <- addAndRemove
TypeError: Cannot set properties of null (setting 'value')
at FileInput.onFileInputChange
```
Cause: `FileInput` posts the file through the `http` service, which is not protected against a destroyed component (unlike `orm`), so the response still reaches `onFileInputChange` after the component, the field and the form controller are gone. It then calls `onUpload`, which for `Many2ManyBinaryField` links the attachment through the form controller's protected ORM (hence the rejection), and it clears a file input ref that no longer exists (hence the TypeError).
We hit this in production on three different wizards over a few months. The client error logs users saved all carry the same trace, and the audit log shows the dialog's action completing a fraction of a second before the upload landed.
Desired behavior after PR is merged:
After the upload resolves, `onFileInputChange` stops when the component is destroyed: nobody is left to receive the uploaded files, and this matches how the protected services already treat a destroyed component. No error is raised, and `onUpload` is not called.
A Hoot test in `file_input.test.js` mounts a `FileInput` behind a `t-if`, starts an upload, unmounts the input while the upload is pending, resolves the upload, and asserts that `onUpload` was not called. It fails before the fix with the two errors above and passes after.
`master` already guards the ref write through its signal-style refs, but still calls `onUpload` on the destroyed component, so the first error remains there.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#287058
Forward-Port-Of: odoo/odoo#286831AI image editing now checks whether an image format is supported before sending it to the AI provider. If the format is unsupported, such as SVG, the AI receives a note instead of failing, so users get a helpful response rather than an error.
Original PR description
Prior to this commit, the ai image tools did not check the format of the provided image before sending it to the AI provider. While editing a website, selecting an image in a format unsupported by AI…
Prior to this commit, the ai image tools did not check the format of the provided image before sending it to the AI provider. While editing a website, selecting an image in a format unsupported by AI providers (such as an SVG, e.g. the 'Your Logo' image shown in the top left) and choosing to edit it with AI would open a chat window, but the request to the provider would fail once the file was sent, since AI providers only support: {'png', 'jpg', 'jpeg', 'webp', 'gif'}.
This commit adds a format check to the image tools. When the referenced image is in an unsupported format, its raw data is no longer sent to the provider; instead, a text note describing the situation (path and format) is added to the AI's context. This lets the agent handle the request appropriately instead of the call failing outright: it can ask the user to provide the image in a supported format (or a description to recreate it), or proceed normally if the request doesn't actually require reading that image (e.g. generating a new image from scratch).
How to reproduce:
- enable the Website and AI modules.
- open the website, and enter edit mode.
- double click the website logo in the top left ('Your Logo'), then click 'AI'.
- a chat window opens; ask the AI to modify the image.
Current behavior:
- An error is raised, warning of an unsupported file format ('image/svg+xml').
Expected behavior:
- No error. The AI agent recognizes it cannot read the image in its current format and responds accordingly instead of the request failing.
task: 6432373
Forward-Port-Of: odoo/enterprise#129205This fix ensures email links copied from Odoo or external tools paste as proper clickable links in the HTML editor. It prevents pasted mail links from becoming broken links or plain text, reducing editing mistakes in messages and content.
Original PR description
**Current behavior before PR:** **Issue 1:** Steps to reproduce the issue: - Create a mail link in editor. - Copy link via link popover. - Paste it anywhere in editor. - Click on it to open popover. Notice that newly created link is not a correct mail link. **Issue 2:** Steps to reproduce the issue: - Copy a mail URL from google docs or from some other website. - Paste the copied link in editor. Notice that URL is pasted as plain text instead of link. This happens because when a link is copied with HTML content, `handlePasteText` is called after `handlePasteHtml`, and it ends up being pasted as html content. **Desired behavior after PR is merged:** This PR aims to ensure that mail URLs are being pasted correctly in editor. task-6462998 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#290538 Forward-Port-Of: odoo/odoo#282954
This fix ensures Belgian payroll correctly determines when sick leave should become unpaid after the eligible paid period. It prevents incorrect results when an employee's sickness history spans multiple years, improving payroll accuracy and reducing manual corrections.
Original PR description
The legacy check for unpaid sick time off after 30 days was wrong. The relapse period used was always the one from the latest leave, and not adapted if we span multiple years. Instead, we can just look at the l10n_be_sickness_can_relapse field, which is correctly computed. Forward-Port-Of: odoo/enterprise#132389
This fixes Belgian payroll calculations so time credit and extra hours are excluded when checking paid hours. It helps ensure payslips reflect the correct worked days amount and reduces the risk of payroll inaccuracies for employees using time credit.
Original PR description
The method checking if we have enough paid hours was wrongly adapted. We should filter out extra hours and time credit entries as they are not included in the base salary and base hours per week. Forward-Port-Of: odoo/enterprise#132809 Forward-Port-Of: odoo/enterprise#132736
Belgian payroll calculations now prorate PFA variable salary in the same way as base salary. This helps ensure more accurate payroll amounts for employees whose pay period or entitlement requires proportional calculation.
Original PR description
PFA variable salary should be prorated just like the base salary. Forward-Port-Of: odoo/enterprise#132739
This fixes a crash when adding users to payroll groups from the Groups form in Australian Payroll. It also ensures both additions and removals are properly audit-logged, improving reliability and compliance tracking without changing user workflows.
Original PR description
#### Description of the issue/feature this PR addresses:
Adding a user to a group from the Groups form crashes on an Australian Payroll-API database, and removals from that form are never audit-logged.
#### Current behavior before PR:
The audit-logging mixin reads the changed users out of the raw write command with vals.get("user_ids")[0][2], which assumes a 3-element command tuple. The Groups form sends the 2-element (4, id) LINK command, so the write raises an IndexError; UNLINK commands are silently not logged for the same reason.
#### Desired behavior after PR is merged:
Group membership changes made from the Groups form are audit-logged for both additions and removals, regardless of the command used to write user_ids. The mixin reads the members before and after the write instead of interpreting the command. No field, model or method-signature change, so it is safe in stable.
opw-6397011
Forward-Port-Of: odoo/enterprise#132821
Forward-Port-Of: odoo/enterprise#125124India e-Way Bill calculations now account for global discounts applied to invoices. This helps ensure the generated e-Way Bill values match the discounted transaction totals, reducing compliance and reconciliation issues.
Original PR description
Before this commit- We didn't consider, global discount for ewaybill After this commit- We consider the global discount for ewaybill opw-6592878 task-[6596257](https://www.odoo.com/odoo/project/967/tasks/6596257) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#290217
Kenyan eTIMS reporting now excludes taxes that do not have a KRA tax code, such as levies paid to other authorities, from the reported tax-inclusive total. This helps ensure invoices sent to the tax authority reflect only KRA-relevant taxes and avoids overstating eTIMS amounts.
Original PR description
Issue: Non KRA taxes are sent in eTIMS tax total Steps to reproduce: - With l10n_ke_edi_oscu - Create a 2% Tax named CTL with no KRA Tax Code - Create an invoice - Add a line with 16% and CTL taxes - Confirm - Send to eTIMS Current behavior: - eTIMS JSON (unaccessible) is created with 'totAmt' (total_tax_included) including non-KRA Taxes Expected Behavior! - eTIMS JSON 'totAmt' doesn't incldue non-KRA Taxes Note: eTIMS is used to report to Tax Autority, however some "taxes" (e.g. Tourism levy) are paid to other authorities (e.g. Tourism Fund) and shouldn't be included in eTIMS. opw-6456478 Forward-Port-Of: odoo/enterprise#131577
Italian invoices using the Import/Export fiscal position now apply only the intended 0% export tax instead of adding an extra N7 tax. This prevents incorrect tax combinations on invoice lines and improves compliance accuracy for Italian accounting.
Original PR description
Upon Import/Export, the 0% EX N7 tax is added by default on each tax excluded line, as it incorrectly shares the same default Import/Export fiscal position with the standard 0% EX tax. This causes both to be applied simultaneously to a single invoice line. 1. Install Accounting and `l10n_it` 2. Switch to IT company 3. Go to Invoices and create a new one 4. Select the Import/Export fiscal position 5. Add a line with a new product (so it's clean of custom product taxes) 6. Both `0% EX` and `0% EX N7` taxes are applied, instead of just `0% EX` Ticket [link](https://www.odoo.com/odoo/project.task/6518926) opw-6518926 Forward-Port-Of: odoo/odoo#285586
Portal users will no longer see Documents or Knowledge cards when they have no shared content, reducing confusion on the portal home page. Website editors can also manage visibility for these content-based cards even when older database settings marked them as always shown.
Original PR description
Issue: - The Knowledge and Documents cards are visible even when the portal user has no shared content. <img width="1344" height="525" alt="image"…
Issue:
- The Knowledge and Documents cards are visible even when the portal user has no shared content.
<img width="1344" height="525" alt="image" src="https://github.com/user-attachments/assets/b3409ba1-ff1c-4967-8acb-01baa5243f69" />
- No option to hide them with editor
<table style="width: 100%;">
<tr>
<th>Before</th>
<th>After</th>
</tr>
<tr>
<td>
<img src="https://github.com/user-attachments/assets/dfdd3d2e-a91b-4b9c-ab64-fdc6535d0fd1" alt="Before" width="280"/>
</td>
<td>
<img src="https://github.com/user-attachments/assets/001f3f57-c926-4469-9ac2-767586c3ac2c" alt="After" width="280"/>
</td>
</tr>
</table>
Steps to reproduce:
1. Install website, documents, and knowledge
2. Create a portal user and make sure no documents and knowledge article are shared with him.
3. Log in as a portal user
4. The Knowledge and Documents cards are visible (Issue 1)
5. Again login as admin and go to `/my endpoint ex: http://localhost:3000/my`
6. Click on editor and then click documents card
7. documents card and knowledge are not avaialbe for visibility change (Issue 2)
Cause:
- Commit https://github.com/odoo/odoo/commit/513931a5e540f22f37e317f80fd131701cbbc8f0 introduced portal.entry records to back portal
cards. and Commit https://github.com/odoo/enterprise/commit/512c9e49d168a205b8fe2a5ff5384c6a178762e7 defined the Documents and Knowledge
entries with `is_config_card=True` inside `<odoo noupdate="1">` records.
Because these records are loaded with noupdate="1", updating the XML data in
enterprise would not update existing databases.
Now entries are marked as config cards, and config cards are always shown
by should_show_portal_card().
https://github.com/odoo/odoo/blob/181f9aa238ae99e92ada4bc4e7064ea95d2f5b84/addons/portal/views/portal_templates.xml#L261-L264
- This is correct for real configuration cards such as Addresses or Connection & Security, but not for counter cards. A card with a `placeholder_count` represents content and should only be displayed when its counter is positive.
Solution:
- Do not force-display config cards that have a `placeholder_count`.
- Also include counter cards in the portal card visibility editor, even if they are marked as config cards in existing databases.
behavior change:
- Before: any portal.entry with `is_config_card=True` was always visible.
- After: it is always visible only if it has no `placeholder_count` and `is_config_card=True` or any records in them
- Cards with `placeholder_count`, like Documents and Knowledge, are hidden until their counter is positive.
- Before: cards with `is_config_card=True` were excluded from the portal visibility options in Edit.
- After: counter cards are included in the editor visibility options even if `is_config_card=True`
opw-6223044
Forward-Port-Of: odoo/odoo#265797