Friday, September 11, 2026
25 changes · saas-19.3
Resolved issues and error corrections
Fixes a crash that could prevent users from generating the Peruvian “Inventory and Balance” General Ledger report. The export now keeps the required SUNAT file format while using a safer CSV generation method, so businesses can produce the report reliably.
Original PR description
### Description of the issue/feature this PR addresses: This PR fixes a server crash in the Peruvian localization (l10n_pe_reports_lib) that occurs when generating the "Inventory and Balance" General…
### Description of the issue/feature this PR addresses: This PR fixes a server crash in the Peruvian localization (l10n_pe_reports_lib) that occurs when generating the "Inventory and Balance" General Ledger report. The crash is triggered by strict validation rules within Python's csv module, which rejects the custom line terminator used to fulfill the SUNAT PLE formatting requirements. ### Current behavior before PR: When a user attempts to generate and export the "Inventory and Balance" report, the server crashes with a ValueError: bad delimiter or lineterminator value. This happens because the csv.DictWriter is initialized with lineterminator='|\n' to ensure every row ends with a pipe. Python's underlying csv implementation rejects this, as it expects standard line endings (\r, \n, or \r\n) and throws an error if the delimiter character (|) is included in the terminator string. ### Desired behavior after PR is merged: The "Inventory and Balance" report generates successfully without server errors. The code now uses the standard lineterminator='\n' to satisfy Python's validation rules. To maintain the mandatory trailing pipe (|) at the end of each row required by SUNAT, a dummy empty column (['']) is appended to the field names with restval=''. This prompts the writer to naturally append the final pipe as a column delimiter before the newline, resulting in the exact |\n output format required, safely and reliably. opw-6509674 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#129636
Visitors using an embedded Odoo live chat widget on an external website can now download files sent through the chat. This fixes a browser blocking issue that prevented attachments from opening or downloading, improving the customer support experience without relaxing file access protections.
Original PR description
**Steps to reproduce:** - Install `im_livechat` module - Copy the code from the livechat channel's widget tab - Paste it in an external website `<head>` (e.g., local python webserver on `0.0.0.0`) -…
**Steps to reproduce:**
- Install `im_livechat` module
- Copy the code from the livechat channel's widget tab
- Paste it in an external website `<head>` (e.g., local python webserver on `0.0.0.0`)
- Start a conversation and send a file from odoo
- Try to download it from the external website
- POST request is sent for the download
- Download fails: `CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.`
- Also when the file is a PDF the preview won't open: `404 (File not found)`
**Issue:**
Mix of multiple issues:
- The download is triggered using a POST request instead of a GET request
(see similar issue for the file viewer [1])
- The file route does not provide the required CORS headers, so requests
originating from the external website are blocked by the browser
- PDF files are rooted to the related path of the `pdfjs` fileviewer
(e.g. `http://0.0.0.0:8000/web/static/lib/pdfjs/web/viewer.html?file=...`)
```xml
<!--
Template rendering all the scripts required to execute the Livechat from an external page (which not contain Odoo)
-->
<template id="external_loader" name="Livechat : external_script field of livechat channel">
<!-- the loader -->
<script defer="defer" t-attf-src="{{url}}/im_livechat/loader/{{channel_id}}" type="text/javascript"/>
<!-- js of all the required lib (internal and external) -->
<script defer="defer" t-attf-src="{{url}}/im_livechat/assets_embed.js" type="text/javascript" />
</template>
```
**Fix:**
Make the `downloadFile` helper handle cross-origin URLs by falling back to a native `<a download>` click (like before) when the target route has the same origin as the embedded script. Could use `session.origin` or `new URL(document.currentScript.src).origin` for this. This is done to avoid allowing CORS on the file content route.
The file viewer issue is handled separately by [1].
For the PDF issue we could manually add the origin to the full url everywhere (but we get some `SecurityError` error from the library due to the cross-origin iframe), add the libjs library in the `assets_embed` (not sure it's possible in `im_livechat.assets_embed_external`), or block external PDF preview for now.
[1] https://github.com/odoo/odoo/pull/281330
opw-6444167
Forward-Port-Of: odoo/odoo#287645
Forward-Port-Of: odoo/odoo#286180SEPA payment XML files no longer include an address field that some European banks reject. This helps Austrian, German, and other affected banks accept batch payment files again without manual correction.
Original PR description
### Issue before this commit: Generating a SEPA Credit Transfer XML for certain European banks (e.g., Austrian and German banks) fails because the generated XML contains an unexpected `<CtrySubDvsn>`…
### Issue before this commit: Generating a SEPA Credit Transfer XML for certain European banks (e.g., Austrian and German banks) fails because the generated XML contains an unexpected `<CtrySubDvsn>` tag inside the `<PstlAdr>` node, leading to the rejection of the batch payment file. ### Steps to reproduce the issue: 1. Download Accounting and l10n_at 2. Go to settings and activate SEPA Credit Transfer / ISO20022 3. Go to Journals > Bank > set an account number 4. Create an austrian contact (ex. FK Austria Wien AG) and set in the invoicing tab a bank (ex. AT526000071856851733) and set it trusted 5. Go to Bills, create a new one with the contact created and confirm it 6. Then click 'PAY' and select SEPA Credit Transfer 7. Go to Vendors > Batch Payments 8. Create a new one with: 1. Bank as bank 2. SEPA Credit Transfer as Payment Method 3. Add the bill just created 9. Validate and download the XML 10. See that a wrong tag <CtrySubDvsn> is added. This makes some banks refuse it ### Cause of the issue: External commit 30b023d394a5e4de64873188aa1d5961fecccb10 introduced the `<CtrySubDvsn>` tag to support US and CA requirements. However, the change was incorrectly applied to the common `account_iso20022` file, making it leak into standard European SEPA exports where the tag is not compliant with certain strict banking validation rules. ### Reason to introduce the fix: Revert the generic addition of the `<CtrySubDvsn>` tag in the common ISO20022 XML generation and restrict it only to the specific localizations (US/CA) that require it. This brings the `<PstlAdr>` node back to compliance, allowing Austrian, German, and other European banks to successfully process the files. opw-6523035 Forward-Port-Of: odoo/enterprise#131156 Forward-Port-Of: odoo/enterprise#131090
The media dialog and chatter now handle empty or incomplete image attachments without crashing. This helps users continue working even when an upload was interrupted or an email created a malformed attachment.
Original PR description
Problem: Interrupted uploads or malformed email payloads can create 0-byte binary `ir.attachment` records where the `checksum` is `False`. Accessing the computed `image_src` field on these records…
Problem:
Interrupted uploads or malformed email payloads can create 0-byte binary `ir.attachment` records where the `checksum` is `False`. Accessing the computed `image_src` field on these records triggers a `TypeError: 'bool' object is not subscriptable` when attempting to slice `attachment.checksum[:8]`. This crashes the Media Dialog and Chatter.
Purpose:
Add a fallback boolean guard to `attachment.checksum` inside `_compute_image_src` so that empty attachments evaluate safely to a string ('0') instead of raising a traceback, allowing the UI to render gracefully.
Steps to Reproduce on Runbot:
1. Go to Settings > Technical > Database Structure > Attachments.
2. Create a new record: Name: `test.png`, Type: `File` (Binary), File Content: [leave empty], Is public document: Checked.
3. Open any record with a Chatter (e.g., Contact or CRM Lead) and click "Insert Image" to open the Media Dialog.
4. The system attempts to evaluate `image_src` and throws the `TypeError`.
Notes:
A test (`test_compute_image_src_empty_checksum`) was added to `test_ir_attachment.py`
opw-6482674
Forward-Port-Of: odoo/odoo#287639
Forward-Port-Of: odoo/odoo#287444This fixes an issue where employee expenses could fail to post after switching reimbursement settings and selecting an existing bill. The expense form now resets the conflicting bill option when payment mode changes, helping users complete reimbursement flows without errors.
Original PR description
How to reproduce it: - Install hr_expense module - Create a draft expense and set reimbursement to use company account - Set use existing bill and select an existing bill - Return back to employee account mode and follow flow until trying to post - An error is raised. This error happens because when changing back into employee mode has_existing_bill is still set affecting the domain in the view and the computation of the account not allowing the user to select a correct account until it goes back into company mode and disables has_existing_bill. This commit fixes this issue by disabling this option when changing from payment mode. Since the existing_bill_id is only removed when changing has_existing_bill to false from the UI, the bill value is still kept. Also now the account depends on the payment mode to correctly set the account value when changing from modes. task-6298396 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Slovak electronic invoice routing now uses the DIČ tax identification number for the 0245 Peppol scheme instead of the IČO company registration number. Existing company tax data is preserved during upgrades and kept aligned, reducing failed or misdirected Peppol document delivery for Slovak businesses.
Original PR description
`SK_EN` maps the Peppol scheme `0245` to the IČO, but `0245` designates the DIČ. Slovak parties therefore end up with their company registration number in `cbc:EndpointID schemeID="0245"`, instead of…
`SK_EN` maps the Peppol scheme `0245` to the IČO, but `0245` designates the DIČ. Slovak parties therefore end up with their company registration number in `cbc:EndpointID schemeID="0245"`, instead of their TIN (DIČ) number. These changes removes the scheme from `SK_EN` and adds `SK_TIN` carrying `0245`. The DIČ is deduced from the IČ DPH, as the Slovak VAT number is the DIČ with the `SK` prefix, so existing databases get the correct endpoint without any data entry. `income_tax_id` on `res.company` is kept in sync with the new identifier. It becomes a computed field reading `SK_TIN`, with an inverse writing it back, so both the company form and the partner identifiers always show the same value. It stays `store=True` so the existing column is untouched. The `income_tax_id` will be removed in master. A pre-migrate script seeds `SK_TIN` from the existing `income_tax_id` values before the field is converted. Without it, the recomputation wipes the values already set by users. With it, they survive the upgrade and Peppol routing works immediately. References: - Peppol release notes: https://docs.peppol.eu/poacc/self-billing/3.0/v3.0.1/release-notes/ - Slovak Financial Administration, Peppol Authority: https://www.financnasprava.sk/_img/pfsedit/Dokumenty_PFS/Podnikatelia/Dan_z_pridanej_hodnoty/efaktura/2026/2026.01.23_Peppol_Authority.pdf --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Customers who switch from in-store pickup to a country-specific delivery option now see the correct delivery charge instead of an incorrect free delivery amount. This prevents misleading checkout totals and ensures delivery methods are evaluated using the customer's address when appropriate.
Original PR description
Steps to reproduce: - Install eCommerce and Click & Collect. - Publish Pick up in store with a warehouse whose address is in country A (e.g. United States). - Publish a country-specific delivery…
Steps to reproduce: - Install eCommerce and Click & Collect. - Publish Pick up in store with a warehouse whose address is in country A (e.g. United States). - Publish a country-specific delivery method (Fixed Price, non-zero) limited to country B (e.g. Spain). - On the shop, checkout with a delivery address in country B. - Select Pick up in store, then select the country-specific method. Issue: Selecting the country-specific method keeps Delivery at 0 (Free). The same happens with country-restricted connectors: `/shop/set_delivery_method` never applies the method, so no rate is requested for that switch. Cause: Since saas-19.3, a pickup location replaces `partner_shipping_id` with a generated pickup address. `/shop/set_delivery_method` only calls `_set_delivery_method` if the method is in `_get_delivery_methods()`, which matches on the shipping address. The pickup country makes the country-specific method look unavailable, so it is never applied. The order still has the pickup method (0 delivery), and the summary reports the selected method as Free. Match availability on the customer when shipping is a pickup address, and restore that address before rating the method that is being set. Keep the Based on Rules check so a method with no applicable price rule is not listed after pickup. opw-6493956 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The Point of Sale customer list now avoids loading each row's action menu until it is actually needed. This reduces delays and UI freezes when stores have hundreds of customers, especially on slower devices.
Original PR description
Opening the customer list with a few hundred partners freezes the UI for several seconds on a slow device (~300ms on a desktop, 5.6s with a 6x CPU throttle in the Chrome profiler). Each `PartnerLine`…
Opening the customer list with a few hundred partners freezes the UI for several seconds on a slow device (~300ms on a desktop, 5.6s with a 6x CPU throttle in the Chrome profiler). Each `PartnerLine` instantiates a full `Dropdown` for its "≡" menu. Setting up a `Dropdown` registers about ten lifecycle hooks (`useDropdownNesting`, `useNavigation`, `useDropdownGroup`, `usePopover`, `useEffect`, ...), and each hook registration eagerly allocates two `OwlError` objects to keep a stack trace. Multiplied by hundreds of rows, this dominates the render: ~60% of the click task is spent constructing errors for menus that will never be opened. Render a plain button per row instead and only mount the `Dropdown`, driven by a `useDropdownState`, once that button is clicked. The `Dropdown` opens its popover on mount when its state is already open and is unmounted again when it closes. The placeholder button keeps the classes the `Dropdown` would add to its toggler so the DOM, the styling and the tour selectors (`button.dropdown`) are unchanged. opw-6453848 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#285974
Point of Sale cash register closing messages now include cash in and cash out movements even when the user does not have accounting access. This prevents incorrect closing differences from appearing after the register was closed with the correct cash amount.
Original PR description
Steps to reproduce: - Give a user PoS Administrator rights and no Accounting rights. - As that user, open a session with cash control, sell something paid in cash and do a Cash Out. - Close the…
Steps to reproduce: - Give a user PoS Administrator rights and no Accounting rights. - As that user, open a session with cash control, sell something paid in cash and do a Cash Out. - Close the register. The closing popup shows the expected cash (opening + cash payments - cash out); enter exactly that amount, the popup shows no difference. - Open the closed session: its chatter says "Closing difference: -X", X being the cash out amount, and "Closing expected" is the amount before the cash out. Issue: The closing control data agrees with the user, but the closing message records a cash difference equal to the cash out. Cause: `_compute_cash_balance` sums `statement_line_ids` with the rights of the current user. Cash moves are `account.bank.statement.line` records, which `_inherits` `account.move`, so the account.move record rules apply to them too. For a PoS user the only such rule is `rule_invoice_pos_user` (`pos_order_ids != False`), and a cash move has no PoS order: unless the user is in `account.group_account_invoice`, their own cash moves are filtered out and `cash_register_balance_end` ignores them, while `get_closing_control_data` sums the lines in sudo. Since da8be203ec32 PoS managers can create cash moves without any accounting group, which made this visible: in 18.0 cash in/out required `account.group_account_invoice`, whose `account_move_see_all` rule makes every move readable. The values stored at closing are right by accident: `_validate_session` reads the lines in sudo just before, and the one2many cache is shared between the sudo and non-sudo environments of the same transaction. The message posted by `update_closing_control_state_session` runs in its own transaction and gets the filtered sum. Fix: Read the cash lines in sudo in `_compute_cash_balance`, as `get_closing_control_data`, `get_cash_in_out_list` and `_validate_session` already do. Users with accounting rights see all lines already, so nothing changes for them. opw-6521591 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286308
The customer list now calculates each customer's due amount only once per row and uses the correct linked commercial customer record. This makes opening large customer lists faster and avoids showing the wrong balance when different customers have similar names.
Original PR description
Opening the customer list with a few hundred partners is slow; part of the time is spent in `getPartnerCredit`. The `PartnerLine` template reads `this.partnerInfos` eight times per row, and each call runs `getPartnerCredit` again. For a contact, that method resolves the partner carrying the due by scanning every loaded partner for one named like `parent_name`, so the cost grows with the square of the number of partners. Cache the getter in a template variable so it is evaluated once per row, and resolve the due partner through the loaded `commercial_partner_id` instead of the name scan. This is also what the server sums the dues by, and it no longer picks a wrong homonym. `refreshTotalDueOfPartner` used the same lookup and now shares it. opw-6453848 Forward-Port-Of: odoo/enterprise#130015
The WhatsApp Disconnect button is now hidden for manually configured accounts and limited to the right administrators. This prevents accidental webhook removal that could stop incoming WhatsApp messages while the account still appears connected.
Original PR description
`show_disconnect` was true for any account holding a token, so the Disconnect button showed on manually configured accounts as well. Pressing it unsubscribes the webhook on Meta first, then clears the token, and that write is rejected on a manual account since the credentials are required there. Odoo rolls back, Meta does not, so the account keeps looking configured while incoming messages stop. The compute also read `token`, restricted to WhatsApp administrators, while every internal user has read access on `whatsapp.account`, so opening the account form as a regular user raised an AccessError. The button is now shown only for administrators on onboarded accounts, and `button_disconnect` checks write access, since hiding a button does not stop an RPC call and the request to Meta happens before the write that would have been refused. Task-6544628 Forward-Port-Of: odoo/enterprise#130759
German Point of Sale sessions using Fiskaly can now be closed even when an order customer is an address contact without its own name. The export uses the displayed customer name or a safe fallback, preventing a blocking crash during session closing.
Original PR description
Steps to reproduce: - German PoS with Fiskaly TSS configured - Set a customer that is an address contact (type invoice/delivery/other) on an order; such a contact has no name of its own, it is…
Steps to reproduce: - German PoS with Fiskaly TSS configured - Set a customer that is an address contact (type invoice/delivery/other) on an order; such a contact has no name of its own, it is displayed with its parent's - Close the session Issue: Closing crashes with "TypeError: 'bool' object is not subscriptable" and the session cannot be closed at all. Cause: _get_dsfinvk_cash_point_closing_data builds the DSFinV-K buyer block from partner.name, which is only guarded by "if partner := o.partner_id". res.partner.name is not required: the res_partner_check_name constraint only enforces it for type='contact', so an address contact stores NULL there and partner.name reads as False, which cannot be sliced. Fix: Fall back on complete_name - what the UI displays for those contacts, "Parent Company, Delivery" - and on a literal when even that is empty, since the buyer name is mandatory in the export. Reading name first leaves the exported value untouched for every partner that has one. opw-6518336 Forward-Port-Of: odoo/enterprise#129709
This fixes a compatibility issue where some previously exported guided tours could stop web assets from loading because they included an extra saved field. Existing custom and industry tours can now continue to load normally while their required steps are still checked.
Original PR description
Tours exported between 37b35f18 and d2ee747d carry a stray `url` key. `validate()` throws on any unknown key at `registry.addValidation()` time, which aborts asset loading for those pre-existing custom tours. Add a `"*"` wildcard to the schema: unknown keys are ignored, `steps` is still validated. 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
French electronic reporting responses from the public platform are now processed instead of only being saved as files. Rejected reports are clearly marked with the reason, and users can correct and resend them without losing the original document links.
Original PR description
Flow 10 PPF responses were stored as attachments without being processed. Consequently, rejected reports remained marked as sent, the rejection reason was not shown to users, and corrected reports could not be submitted again. Process the PPF response codes, update the flow state, and log the returned details in the chatter. Keep response attachments separate from the outgoing payload and allow rejected reports to be manually resent with their original moves and a new transmission identifier. no task id Forward-Port-Of: odoo/odoo#287338
This fix helps the HTML editor recover correctly when content is out of date, using the latest version saved on the server instead of stopping with an error. Users are less likely to remain stuck with stale content after concurrent edits or delayed updates.
Original PR description
Before this commit, an editor recovering from a stale document could stop on this error and keep the stale content:
```
Error: Concurency detected while recovering from a stale document. The
last history id of the server is different from the history id received
by the html_field_write event.
at CollaborationOdooPlugin.resetFromServerAndResyncWithPeers
```
This happens because the recovery compares the history id of the record with the one the html_field_write event carried. A write keeps only the last step id in the field, so an event handled after a later write names an id the record no longer holds. As a result, the recovery stops there and the document stays stale.
This commit fixes the issue by taking the history id read from the record as the new server reference, so the editor converges on the document the server holds.
https://runbot.odoo.com/odoo/error/944595
Forward-Port-Of: odoo/odoo#287408This fixes an issue where Time Off requests could incorrectly show 0 days when an automation rule created an activity during saving. The change ensures automated actions no longer interrupt duration calculations, helping employees and managers see accurate leave balances and requests.
Original PR description
Problem: A time off request is saved with a duration of 0 days instead of 1 day as soon as an automation rule on Time Off has an action that creates an activity. Cause: `_compute_field_value` runs…
Problem: A time off request is saved with a duration of 0 days instead of 1 day as soon as an automation rule on Time Off has an action that creates an activity. Cause: `_compute_field_value` runs the actions while the fields of the computation it wraps are still protected and not written yet. On `hr.leave` the actions run from a computation nested in `_compute_date_from_to`, so `date_from` is empty when the activity notification reads `display_name`, and `_compute_duration` stores 0. Setting `date_from` afterwards does not mark `number_of_days` to compute again since it is protected. Solution: Extract the snapshot `_filter_pre` already does into `_keep_to_compute` and wrap the post filter and the actions with it, so the fields depending on the running computation stay to compute. Same treatment as 488419a5ca49 (odoo/odoo#243611) on the pre filter. Steps to reproduce: - Enable the developer mode. - Go to Settings > Technical > Automation Rules and create a rule on the Time Off model with the trigger On create and edit. - Add an action of type Create Activity, set its Responsible to another user, and save. - Go to Time Off > New, pick an employee and a time off type, and request one working day. - Observe that the request shows a duration of 0 days. Ticket [link](https://www.odoo.com/odoo/project.task/6498783) opw-6498783 Forward-Port-Of: odoo/odoo#287536 Forward-Port-Of: odoo/odoo#286791
Point of Sale X/Z reports now calculate category totals in the same tax-inclusive or tax-exclusive way as the displayed order lines. This prevents mismatches between line totals and category totals, making end-of-session reports clearer and more reliable while preserving daily sales report behavior.
Original PR description
The per category totals on X/Z reports would use the same total computation that we use for the daily sales report, but the order lines are shown tax included or excluded based on the config for the database. So we could have a category showing a total which is different from the sum of the order lines on that category. This only shows on X/Z reports, but the daily sale report uses the same data, and always displays the tax excluded prices So here I added an extra 'total_paid' field on the report data, which is used on X/Z reports generation, so the category total matches the order lines on X/Z reports, while keeping the original total which is used for daily reports Task-[6538575](https://www.odoo.com/odoo/project/1737/tasks/6538575) Enterprise PR-[#131110](https://github.com/odoo/enterprise/pull/131110) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix ensures automatic accounting entries are properly balanced and reconciled when changing periods. It prevents leftover journal items from cluttering records and helps keep financial data accurate.
Original PR description
The previous code wasn't reconciling the destination and accrual moves, leaving potentially non-neutral journal items and their counterpart polluting the DB. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279766
This fixes an issue where users could be blocked from saving records when Odoo calculated restricted fields in the background. The change keeps record creation working as expected while preserving field access rules for users without the required permissions.
Original PR description
**Description of the issue/feature this PR addresses:** If a field is `computed`, `precomputed`, and has `groups` defined, an `AccessError` is raised when a user who does not have the required group…
**Description of the issue/feature this PR addresses:** If a field is `computed`, `precomputed`, and has `groups` defined, an `AccessError` is raised when a user who does not have the required group creates a record because the field is precomputed. After this commit https://github.com/odoo/odoo/pull/201565/changes/48521a311a6dc857c3808db70ed359c7866aa125, Odoo checks field access in `__get__`, so an `AccessError` is now raised. If the field is not precomputed, everything works fine. Therefore, this commit prevents the error by using `sudo()` to recompute the value. I have attached a module to demonstrate the issue. **Steps to reproduce the issue:** 1. Install the attached module. [sale_margin_security_test.zip](https://github.com/user-attachments/files/31967357/sale_margin_security_test.zip) 2. Create a sales order and add a product. 3. Try to save the sales order. The AccessError is raised. https://github.com/user-attachments/assets/54c7e4e2-005f-4ced-bb62-22d0e00049d9 For more context, this module is a simple example extracted from the OCA `sale_margin_security` module, which inherits from a mixin and adds groups to the fields: https://github.com/OCA/margin-analysis/pull/285 You can see the error in this PR: https://github.com/OCA/margin-analysis/actions/runs/34254749207/job/102157600233?pr=285#step:8:126 @Tecnativa @pedrobaeza @kmagusiak @rco-odoo @Feyensv, could you please review this? --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287257
Scheduled financial reports now apply the intended company selection instead of including every company by default. This prevents automated report emails from showing data for companies that should not be part of that report.
Original PR description
This commit https://github.com/odoo/odoo/commit/94ef1127dfa8af17795f39590c8a37edfa117994 changed how with_company() works to ensure it only adds a new company to the allowed companies. This made the reports options include all companies when sent through the cron (since crons have every company enabled by default). This commit fixes this issue by relying on the context key allowed_company_ids instead of with_company(). task-6505248
X/Z reports now show category totals that match the displayed order lines, whether prices are configured with or without tax. This avoids confusing discrepancies in point-of-sale closing reports while preserving the daily sales report calculation.
Original PR description
The per category totals on X/Z reports would use the same total computation that we use for the daily sales report, but the order lines are shown tax included or excluded based on the config for the database. So we could have a category showing a total which is different from the sum of the order lines on that category. This only shows on X/Z reports, but the daily sale report uses the same data, and always displays the tax excluded prices So here I added an extra 'total_paid' field on the report data, which is used on X/Z reports generation, so the category total matches the order lines on X/Z reports, while keeping the original total which is used for daily reports Task-[6538575](https://www.odoo.com/odoo/project/1737/tasks/6538575) Community PR-[#286954](https://github.com/odoo/odoo/pull/286954)
This fix prevents Odoo from creating exchange difference entries when users reconcile journal items on accounts where reconciliation is not allowed. The control is now handled at the reconciliation wizard level, reducing incorrect accounting entries and improving financial accuracy.
Original PR description
Repro steps: 1) Create two misc entries with different foreign currency amount and different company currency amounts, on an account with "Allow Reconciliation" disabled (one debit, one credit). 2) Go to Journal Items, select both lines and click Reconcile. Issue: An exchange difference entry is generated. Fix: Move the control of the exchange difference moves creation to the account.reconcile.wizard instead of controling it inside action_reconcile of account.move Related PRs: https://github.com/odoo/enterprise/pull/130541 https://github.com/odoo/enterprise/pull/108362
Fixes an issue where rental returns could fail after stock pickup or return transfers were processed, especially for products tracked by serial number. The system now keeps the pickup and return serial number history in sync when using stock pickings, so users can complete later rental returns reliably.
Original PR description
**Issue** When rental transfers are enabled and rental pickups/returns are processed through stock pickings, it may become impossible to perform a subsequent rental return through the rental return…
**Issue** When rental transfers are enabled and rental pickups/returns are processed through stock pickings, it may become impossible to perform a subsequent rental return through the rental return wizard. **Steps to reproduce** - Activate "Rental Transfers" in the settings - Create a rental product P, tracked by serial number - Create two serial numbers for P - Create and confirm a rental order for 2 units of P - Validate the pickup transfer - Partially validate the return transfer without creating a backorder - Open the rental order and click on "Return" -> The return wizard opens without any available serial number and validation fails with a serial number-related error. **Cause** When clicking on "Return", if there is no pending pickup/return transfer: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/models/sale_order.py#L62-L68 the rental return wizard is opened directly: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_renting/models/sale_order.py#L316 No serial number is prefilled in the wizard because `returned_lot_ids` is empty: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L122-L124 This is because `returnable_lot_ids` is empty as well. `returnable_lot_ids` is computed while generating the wizard lines: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_renting/wizard/rental_processing.py#L38 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_renting/wizard/rental_processing.py#L47-L48 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L99-L106 and `returnable_lots` is empty because both `pickedup_lots` and `returned_lots` are. Those fields are currently only populated through the rental wizard flow: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L42-L43 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L160-L161 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L166-L167 Since this flow uses stock pickings instead of the rental wizard, those fields are never updated, preventing the wizard from determining any returnable serial number. opw-6150305 Forward-Port-Of: odoo/enterprise#126594 Forward-Port-Of: odoo/enterprise#119257
Child contacts for Colombian companies are no longer mistaken for separate companies when they inherit tax information. This restores the expected company-contact display and makes those contacts searchable by the parent company name.
Original PR description
Issue: Colombian child contacts linked to a NIT company are displayed with their standalone name instead of "Company, Contact". Searching Contacts by the company name consequently returns the company…
Issue: Colombian child contacts linked to a NIT company are displayed with their standalone name instead of "Company, Contact". Searching Contacts by the company name consequently returns the company but not its child contacts. Steps to reproduce: - Create a Colombian company with NIT - Add a child contact or address to that company - Filter Contacts by the company name - Observe that the child is displayed separately and is not returned Cause: The Colombian `is_company` computation classifies every partner with a Colombian NIT and qualifying obligations as a company: https://github.com/odoo/enterprise/blob/911686a31d5d3c1539d0dff7d16edf1ce9b101ca/l10n_co_edi/models/res_partner.py#L43-L53 Those fiscal values are commercial fields and are propagated to child contacts. Without checking that the partner is its own commercial entity, children are therefore classified as companies, preventing the standard display name logic from prefixing their parent name. Solution: We need to restrict the Colombian company classification to partners that are their own commercial partner. This preserves the NIT and obligation rules for actual companies while keeping their inherited child records as contacts, restoring both the combined display name and parent name search behavior. opw-6470958 Forward-Port-Of: odoo/enterprise#130373 Forward-Port-Of: odoo/enterprise#128986
Refund lines without a product now suggest the correct type of account based on whether the document is a customer or vendor transaction. This prevents customer credit notes from showing expense accounts and vendor credit notes from showing income accounts, reducing accounting errors for contacts used as both customers and vendors.
Original PR description
Before this commit, when adding a line without a product to an invoice or credit note, `_get_most_frequent_account_for_partner` picked the partner's most-used account, filtered to an income or…
Before this commit, when adding a line without a product to an invoice or credit note, `_get_most_frequent_account_for_partner` picked the partner's most-used account, filtered to an income or expense account depending on `get_inbound_types` and `get_outbound_types`. Those helpers classify move types by cash-flow direction which is correct for choosing a receivable and payable account but wrong for choosing an income ro expense account: they group `in_refund` with `out_invoice` as "inbound", and `out_refund` with `in_invoice` as "outbound". As a result, a Vendor Credit Note line with no product would be filtered to income accounts instead of expense accounts, and a Customer Credit Note line to expense accounts instead of income accounts. This only surfaced for contacts who are both customer and vendor, since the query needs matching history to return a result; otherwise it silently falls back to the journal's default account, masking the bug for ordinary contacts. This commit uses `get_sale_types` and `get_purchase_types` instead, which classify by document side, sale vs. purchase rather than cash-flow direction, matching the classification already used for product-based lines `is_sale_document` and `is_purchase_document` opw-6373124 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278794 Forward-Port-Of: odoo/odoo#276846