Wednesday, September 9, 2026
26 changes · saas-19.3
Resolved issues and error corrections
Saving Point of Sale settings now assigns manager employees from the correct company instead of accidentally using employees from the user's currently active company. This prevents cross-company employee links in multi-company setups, while single-company setups are unchanged.
Original PR description
Steps to reproduce: - multi-company database, PoS Manager user with an employee in each company - current company set to company A - open the settings of a PoS configuration belonging to company B…
Steps to reproduce: - multi-company database, PoS Manager user with an employee in each company - current company set to company A - open the settings of a PoS configuration belonging to company B and save Issue: The advanced_employee_ids of company B's PoS now also contains the manager's employee of company A, an employee from another company. Cause: res.config.settings.create() appends the PoS managers' employees with `_get_group_pos_manager().user_ids.employee_id`. res.users.employee_id is computed for the current company (self.env.company), not for the company of the pos.config being edited, so the employees of the active company are linked instead of the PoS company's. pos.config.write() already resolves them with `with_company(config.company_id)` since fccccf6cabe5, but the settings path was left unscoped. Fix: Resolve employee_id with `with_company(config.company_id)` in the settings create, as done in pos.config.write(). Single-company databases are unaffected. opw-6544518 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix prevents Saudi ZATCA invoices from being submitted more than once when users only have read-only access to journals. The system now records the successful submission correctly, reducing duplicate government filings and related operational risk.
Original PR description
**Steps to reproduce:** This issue is hard to reproduce because it requires a live ZATCA connection: - As a user with read-only permission on journals, send an invoice to ZATCA. - You get an access error on the journal, and the invoice is unchanged (You can try sending it again to ZATCA). **Issue:** What happens is: - A user with read-only permission on journals sends an invoice to ZATCA. - If ZATCA responds with a 200 (successfully submitted), we try to write on the field `journal.l10n_sa_latest_submission_hash` - With no write permissions, the write fails and all changes are rolled back (on odoo, not on ZATCA) - We can send the invoice again to ZATCA, resulting in duplicates. **Solution:** - Added a sudo when writing on the field: `journal.l10n_sa_latest_submission_hash` opw-6320179 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286570 Forward-Port-Of: odoo/odoo#278728
Signed quotation PDFs are now posted in a way that customers can still see them but cannot edit or delete them from the portal communication history. This prevents the signed document from being lost before an order is confirmed, especially when payment is pending by wire transfer.
Original PR description
Issue: A customer who signs a quotation can delete the chatter entry containing the generated signed PDF. For quotations awaiting a wire transfer, this can remove the only retrievable snapshot of the…
Issue: A customer who signs a quotation can delete the chatter entry containing the generated signed PDF. For quotations awaiting a wire transfer, this can remove the only retrievable snapshot of the signed quotation before the order is confirmed. Steps to reproduce: - Create a quotation requiring an online signature and payment. - Sign it from the customer portal and select wire transfer. - Delete the "Order signed by ..." entry from the portal communication history. Cause: The signing endpoint posts the generated PDF as a regular customer authored comment. Portal chatter allows customers to update their own comments, and deleting one clears its attachments, so the signed PDF is physically removed. https://github.com/odoo/odoo/blob/e479111294b11058038defc31505cc81ac1f1821/addons/sale/controllers/portal.py#L348-L358 Solution: Classify the signed document entry as an automated comment. This keeps it visible and attributed to the customer while ensuring that both the portal interface and backend message rules treat its content and attachment as immutable. Regular customer comments keep their existing behavior. opw-6466029 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283595
This fixes an issue where a measure defined by a report could disappear from the Measures menu after users deselected it and refreshed or filtered the pivot view. Business users can now reliably reselect report measures, helping reporting views stay consistent during analysis.
Original PR description
TL;DR - we lose the measures from arch after a reload, if removed from activeMeasures Step to reproduce: - install pos, create few orders - go to reporting> orders> switch to pivot view - click the…
TL;DR - we lose the measures from arch after a reload, if removed from activeMeasures Step to reproduce: - install pos, create few orders - go to reporting> orders> switch to pivot view - click the `Measures` dropdown, `Order` is already selected - untick it, then apply some filter so that view reloads (ex order date) - reopen `Measures` dropdown, notice `Order` is missing form measures Cause: - view `view_report_pos_order_pivot` has `<field name="order_id" type="measure"/>` in its pivot view https://github.com/odoo/odoo/blob/f5c68cf0eb2ce6ec96dd4006b28466044af10e33/addons/point_of_sale/views/pos_order_report_view.xml#L10 - `order_id` is M2O field - Measure is compute from present `activeMeasure` and fields of type `["integer", "float", "monetary"]` https://github.com/odoo/odoo/blob/f5c68cf0eb2ce6ec96dd4006b28466044af10e33/addons/web/static/src/views/utils.js#L89-L120 - when the view is first loaded, `activeMeasure` all the fields with `type="measure"` which is directly passed to pivot's model as a metadata https://github.com/odoo/odoo/blob/f5c68cf0eb2ce6ec96dd4006b28466044af10e33/addons/web/static/src/views/pivot/pivot_arch_parser.js#L59-L60 https://github.com/odoo/odoo/blob/f5c68cf0eb2ce6ec96dd4006b28466044af10e33/addons/web/static/src/views/pivot/pivot_view.js#L41 - when we toggled the `order_id` from measure and reloaded, `order_id` is popped from `activeMeasure` and as it's field type is `many2one` it is not considered for `measures` in `computeReportMeasures` Fix: - maintain the measures from arch separately and feed it to `computeReportMeasures` opw-6416196 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286013 Forward-Port-Of: odoo/odoo#278850
Facebook and LinkedIn mentions in social posts are now detected more reliably and linked to the right profiles. Facebook post text is also kept unchanged after publishing, preventing malformed mentions when posts are duplicated.
Original PR description
This commit fixes an issue with the mention regexes for social_facebook as they weren't properly replaced by the initial mechanism. The initial mechanism was introduced by [1]. Now, we check every possible mention and if it is indeed a known mention, then we replace it by the correct link to their profile. [1]: https://github.com/odoo/enterprise/commit/4dacc5fce72687680080f75feef875fbfb3dbd15 task-6026857
The French 2033 B fiscal declaration now includes all required operating expense lines in its total. This helps businesses using the French reports see a more accurate accounting income calculation and avoid understated expenses in the report.
Original PR description
**Steps to reproduce:** - Install the `l10n_fr_reports` module and switch to the FR Company. - Navigate to Invoicing > Reporting > Fiscal Declaration and select `2033 B`. - Observe the formula of `A…
**Steps to reproduce:** - Install the `l10n_fr_reports` module and switch to the FR Company. - Navigate to Invoicing > Reporting > Fiscal Declaration and select `2033 B`. - Observe the formula of `A - Accounting income` > `Operating expenses (II)`. **Observation:** The formula does not include the balances of `FR_2033_B_c244`, `FR_2033_B_c250`, and `FR_2033_B_c252`. **Root Cause:** At [1], the formula for `Operating expenses (II)` is missing the balances of fields `244, 250, and 252`, even though these lines are part of the operating expenses section. **Fix:** This commit ensures that `Operating expenses (II)` displays the correct total balance. **Reference**: <img width="1422" height="490" alt="6482797" src="https://github.com/user-attachments/assets/95b35ac7-f410-413b-8ef9-29f97f16c35a" /> [1]: https://github.com/odoo/enterprise/blob/54bfcbee37a241ae70b9bebb9cf23d76172e18fe/l10n_fr_reports/data/fiscal_declaration/report_2033_B_simplified_profit_loss.xml#L302 opw-6482797
Checkout now correctly allows carts that include free promotional reward items, even when the website blocks regular zero-priced products. This prevents customers from being sent back to the cart unnecessarily when a valid free gift promotion is applied.
Original PR description
As of commit b8e790b2, a cart containing a product priced at 0 while the website forbids the sale of zero-priced products is no longer payable: the customer is redirected back to the cart with a warning. Reward lines were caught by that new rule. A promotion offering a free gift whose product has no sale price adds a reward line priced at 0 to the cart, so the whole cart became unpayable even though nothing was wrong with it. This commit excludes reward lines from the zero-priced rule, the same way delivery lines already are. opw-6526396 Forward-Port-Of: odoo/odoo#287028 Forward-Port-Of: odoo/odoo#286464
Users can now download files opened from the Discuss file viewer without seeing an error. The change fixes a request mismatch so attachments from channel conversations download reliably while preserving the correct file name.
Original PR description
Description of the issue/feature this PR addresses: Downloading an attachment from the file viewer fails with a `405 Method Not Allowed` error when the attachment belongs to a Discuss channel. I've…
Description of the issue/feature this PR addresses:
Downloading an attachment from the file viewer fails with a `405 Method Not Allowed` error when the attachment belongs to a Discuss channel.
I've already submitted a ticket to Odoo: #6430586
Steps to reproduce (on a 18.0 runbot):
1. open Discuss and send an image in a channel
2. click the image to open the file viewer
3. click the download button (either the one in the header or the one in the bottom
toolbar)
The server rejects the request:
```
POST /discuss/channel/1/image/519861?filename=image.png&unique=32647b0f&download=true 405
```
and the user gets a `RPC_ERROR: Arbitrary Uncaught Python Exception` dialog reporting `405 Method Not Allowed`.
Cause: `download()` always issues a POST request, while the routes serving the attachments of a discuss channel only allow GET:
* `/discuss/channel/<int:channel_id>/attachment/<int:attachment_id>`
* `/discuss/channel/<int:channel_id>/image/<int:attachment_id>`
so the request never reaches the controller. Downloading the very same attachment from the attachment card in the conversation still works, because that one is a plain anchor navigation (GET).
This is a regression from fb152985f4b8 ("[FIX] web: download FileViewer files via blob helper"), which routed the file viewer download through `download()` in order to honor the filename sent by the server in the `Content-Disposition` header.
Only 18.0 is affected: saas-18.1 and saas-18.2 do not have the commit that introduced the regression, and from saas-18.3 on, the `urlRoute` override was dropped and channel attachments are served through the standard `/web/content` and /web/image` routes, which are not restricted to GET.
The download is still sent with POST on those branches though, hence forward-porting this up to master.
Current behavior before PR:
Downloading a Discuss channel attachment from the file viewer raises a 405 error and the file is not downloaded. Images and other file types are equally affected.
Desired behavior after PR is merged:
The file is downloaded, keeping the filename advertised by the server. The download is performed with a GET request through `downloadFile()`, which still goes through the blob helper, so the fix of fb152985f4b8 is preserved. This is already the way a file is downloaded from its url in `readonly_file.js`.
Added a test that downloads an image attachment of a channel from the file viewer and asserts the request is a GET on the channel attachment route. It fails before this fix with `POST /discuss/channel/1/image/1`.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#287172
Forward-Port-Of: odoo/odoo#279232This fixes cases where pasted or inserted tables with merged or missing cells could disrupt editor tools. The editor now normalizes those tables into a complete grid, helping table menus and editing actions work consistently.
Original PR description
Description of the issue this PR addresses: We don't support colspan/rowspan in the editor, so tables containing them can break other functionality that assumes a rectangular grid (equal cell count per row). This PR expand any rowspan/colspan into individual cells on insert. opw-6347233 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284159 Forward-Port-Of: odoo/odoo#281114
This fixes a timing issue in German point-of-sale certification where a restaurant table could be blocked while a fiscal certification request was still processing. Staff now only enter the table after that request is complete, making table opening more reliable during sales.
Original PR description
In this commit: ------------------ - The API call is triggered when an order is updated in Fiskaly. - Previously, the request could be awaited while opening a table, blocking the table from opening before the product screen was ready. - Now, the request is awaited before allowing the table click, ensuring the table opens only after the request is completed. Task: 6522079 Forward-Port-Of: odoo/enterprise#130785 Forward-Port-Of: odoo/enterprise#130132
This fixes an issue where approved Time Off accrual allocations could fail after a first milestone was added to an initially empty accrual plan. The change ensures the allocation has a valid starting reference date, so employees can save Time Off requests without encountering an error.
Original PR description
## Steps to Reproduce: - Install the Time Off module. - Create an Accrual Plan without any milestones. - Create an Accrual Allocation using the newly created accrual plan. - Approve the allocation. -…
## Steps to Reproduce: - Install the Time Off module. - Create an Accrual Plan without any milestones. - Create an Accrual Allocation using the newly created accrual plan. - Approve the allocation. - Add a milestone to the accrual plan. - Create a new Time Off request after the allocation start date. - Save the record. ## Error: `TypeError - '>' not supported between instances of 'datetime.date' and 'bool'` ## Cause: `lastcall` is initialized by method `_add_lastcalls()`, which is only called at create and write. When an accrual allocation is created with an accrual plan that has no milestones, `_add_lastcalls()` returns early because `level_ids` is empty, leaving `lastcall` set to `False`. - [1] If a milestone is added later, `lastcall` is compared with `first_level_start_date`, resulting in a comparison between boolean and datetime, which raises an error. ## Fix: When `lastcall` is not set, default it to `first_level_start_date`. [1] - https://github.com/odoo/odoo/blob/27036bea232572ba692fbb95387911eb453266bf/addons/hr_holidays/models/hr_leave_allocation.py#L703-L706 sentry-7615375197 Forward-Port-Of: odoo/odoo#282074 Forward-Port-Of: odoo/odoo#280674
Kit sales now correctly exclude deliveries completed after the selected accrual date when calculating delivered quantities. This prevents orders from appearing as ready to invoice too early, improving accuracy in period-end invoicing and revenue accruals.
Original PR description
When selling a kit, the qty_delivered_at_date was not ignoring moves that were done after the accrual_entry_date. Steps to reproduce: ------------------- * Create a kit with any component and make it's invoice policy "Delivered quantities" * Create a sale order for this kit and confirm it, change the order date to any date in the past * Validate the picking * Go check the "Invoiced to be issued" * Change the accrual_entry_date to a date before the picking was validated > Observation: The order still appears opw-6290222 Forward-Port-Of: odoo/odoo#285932 Forward-Port-Of: odoo/odoo#274745
Fixes an issue where reconciliation entries could receive different labels depending on whether they were created by a user or by the automatic reconciliation process. Labels are now applied using the company's language, helping keep accounting records consistent and easier to understand.
Original PR description
### Problem `label` on `account.reconcile.model.line` is a **translatable** field, but its value is written onto the journal item created when the model is applied (`account.move.line.name`). That…
### Problem
`label` on `account.reconcile.model.line` is a **translatable** field, but its value is
written onto the journal item created when the model is applied (`account.move.line.name`).
That means the label is read in the language of whoever applies the model:
- a user working in another language writes the translated value;
- the auto-reconciliation cron writes the **source** value, since it runs as OdooBot.
So the very same reconcile model ends up writing two different labels on the journal items,
depending on who applied it.
### How it shows up
It becomes visible when a reconcile model is created by **duplicating** an existing one and
the label is then edited while working in a non-source language. The translation holds the
new text, while the source value silently keeps the label of the original model — and the
source value is exactly the one the cron writes. The result is a set of journal items where
some carry the intended label and some carry the label of an unrelated model.
### Fix
The journal item belongs to the company, so the label is read in the **company** language
via a small `_get_aml_label()` helper, instead of the language of the current environment.
It falls back to the current behaviour when the company has no language set.
`_prepare_aml_vals()` is the only place in 18.0 that reads `self.label` for the journal item.
### Test
Adds `TestBankRecWidget.test_auto_reconcile_model_label_uses_company_lang`: a reconcile model
whose line label is translated in the company language, applied by the auto-reconciliation
cron running in the source language, and asserts the journal item carries the company-language
label.
```
odoo -d <db> -u account_accountant --test-enable --stop-after-init \
--test-tags /account_accountant:TestBankRecWidget.test_auto_reconcile_model_label_uses_company_lang
```
Without the fix the test fails with `[{'name': 'Frais bancaires'}] != [{'name': 'Bank fees'}]`;
with the fix it passes. The full `account_accountant` suite was also run on a clean 18.0
database: 203 tests, 0 failed, 0 errors.
Forward-Port-Of: odoo/enterprise#130719
Forward-Port-Of: odoo/enterprise#128433Helpdesk users can now create tickets for teams with automatic assignment without being blocked by Time Off access restrictions. The assignment process still checks who is unavailable, but does so as a system decision so regular helpdesk work is not interrupted.
Original PR description
Before this commit, a helpdesk user creating a ticket on a team that assigns tickets automatically got "You are not allowed to access 'Time Off' (hr.leave) records". This happens because picking the next assignee reads hr.leave as the acting user, to skip the members who are off, and a plain helpdesk user has no access to Time Off. This commit reads the employees of the members and their leaves in sudo, as whom to assign is a system decision. https://runbot.odoo.com/odoo/error/947053 Forward-Port-Of: odoo/enterprise#130796
Dropshipped purchases no longer change the average cost of products that never enter stock. This prevents misleading inventory valuations and negative stock valuation balances after related sales, purchases, invoices, and bills are completed.
Original PR description
stock_*: stock_account, stock_dropshipping, stock_landed_costs **Problem:** dropship moves impact the average cost of products which can lead to negative balance in stock valuation account **Steps to…
stock_*: stock_account, stock_dropshipping, stock_landed_costs **Problem:** dropship moves impact the average cost of products which can lead to negative balance in stock valuation account **Steps to reproduce:** On a new db with no demo data and stock_dropshipping, sale_management and accountant module installed (bug also reproducible in runbot with same steps, but it's easier to see the negative impact on accounting on a new db) : 1) enable dropshipping 2) create a storable product with average perpetual category 3) in the purchase tab set a vendor with a price of 10 4) in the inventory tab select the dropship route 5) create PO for 1 unit @ 5, validate receipt and confirm bill 6) confirm a SO for 1 unit of the product 7) confirm linked PO and validate dropship move 8) confirm invoice and vendor bill -> see how the standard price is now 7.5 9) remove dropship route from the inventory tab of the product 10) confirm a SO for 1 unit of the product 11) validate delivery and confirm invoice 12) open 'inventory valuation' view **Current behavior:** the initial balance of stock valuation is -2.5 **Expected behavior:** it should be 0 (there shouldn't be a negative initial balance if all invoices and bills are confirmed) **Cause of the issue:** The issue happens after step 8) The problem is that the dropship has an impact on the average price of the product but not on the accounting. Before the dropship we have 1 unit in stock @ 5 and the stock valuation account has a balance of 5 (from the bill), so all is good. The dropship then changes the standard price to 7.5. That's because currently, in _run_average_batch() the dropship move first impacts average cost like an incoming move with a value of 10 (at this point we have 1 move @ 10 and 1 @ 5 so average cost is 7.5) https://github.com/odoo/odoo/blob/bcaa8b6b00fa1f16513d680c5187fd424bc7cf8c/addons/stock_account/models/product.py#L493-L500 https://github.com/odoo/odoo/blob/bcaa8b6b00fa1f16513d680c5187fd424bc7cf8c/addons/stock_account/models/product.py#L505-L510 and then it impacts the value as a regular outgoing move (meaning it leaves the inventory at the average cost of 7.5) and does not impact the average cost (which is the basic behaviour of outgoing moves) https://github.com/odoo/odoo/blob/bcaa8b6b00fa1f16513d680c5187fd424bc7cf8c/addons/stock_account/models/product.py#L515-L517 https://github.com/odoo/odoo/blob/60b5b99d569dbe183ef9c980217ccfe9bf243756/addons/stock_account/models/product.py#L522 Therefore after step 8), the standard price is 7.5 and we have a unit in stock so, in the inventory valuation view the ending stock is 7.5$. But the dropship did not impact the stock valuation account so the initial balance is still 5$ and we have lines with credits and debits of 2.5$ in the the stock variation section. After steps 9 to 12, both the initial balance and ending stock decrease by 7.5 (which is expected), leading to a negative initial balance in stock valuation. **fix:** We don't take into account the stock move from dropships in the avco computation **tests:** The fix requires modifications in a few tests: - test_dropship_bill_standard_price_update checks that the bill of a dropship move impacts the standard price, so we delete this test - test_lot_normal_3, the asserts on the total_value still make sense but not those on standard_price - test_dropship_kit_bom_updates_component_standard_price test_average_cost_dropship_in_negative_quantity, test_out_move_validate_as_stock_user: standard price should not be impacted by dropship Task 6515358 Forward-Port-Of: odoo/odoo#285576
Depreciation models can no longer be deleted while they are linked to assets that are still running, paused, or closed. This prevents accounting assets from losing required setup information and becoming impossible to manage later.
Original PR description
**Steps to reproduce:** * Install the **Accounting** (`account`). * Create a **Depreciation Model** (e.g. Linear, 5 years). * Create an asset, assign the depreciation model, and confirm it. * Go to…
**Steps to reproduce:** * Install the **Accounting** (`account`). * Create a **Depreciation Model** (e.g. Linear, 5 years). * Create an asset, assign the depreciation model, and confirm it. * Go to **Accounting → Configuration → Depreciation Models** and delete the model used by the running asset. * Try to **Reset to Draft** on **asset**. **Observed behavior:** * The depreciation model is deleted silently. * The asset's `model_id` FK becomes `NULL`, causing all related fields (`method`, `method_number`, `method_period`, `journal_id`, etc.) to become empty. * Any subsequent attempt to cancel, reset to draft, or delete the asset fails with a **missing required field** error, leaving the asset permanently unmanageable. **Cause:** * `account.depreciation.model` had no `@api.ondelete` guard — deletion was entirely unprotected, unlike `write()` which already blocks edits on models used by running assets. * `model_id` on `account.asset` had no `ondelete` constraint, so the database silently NULLed the FK on model deletion. **Fix:** * Add an `@api.ondelete(at_uninstall=False)` method `_unlink_if_no_running_assets()` on `account.depreciation.model` that raises a `UserError` listing the affected asset names when a deletion is attempted while any linked asset is in `open`, `paused`, or `close` state — mirroring the protection already present in `write()`. opw-6233210 Forward-Port-Of: odoo/enterprise#126979
SEPA direct debit XML files will no longer include an extra identifier field for countries where banks may reject it. The field is now limited to Nordea-related countries where it is required, improving payment file acceptance without changing normal workflows.
Original PR description
### Issue: An unexpected `<SchmeNm><Cd>CUST</Cd></SchmeNm>` node was added inside `<InitgPty><Id><OrgId><Othr>` for all countries Some Italian banks reject SDD files containing this node ### Cause:…
### Issue: An unexpected `<SchmeNm><Cd>CUST</Cd></SchmeNm>` node was added inside `<InitgPty><Id><OrgId><Othr>` for all countries Some Italian banks reject SDD files containing this node ### Cause: https://github.com/odoo/enterprise/commit/3c3c64b511d07fc1ba33c30363972f5b0f7283d6 added `<SchmeNm><Cd>CUST</Cd></SchmeNm>` unconditionally for all countries The original fix was intended for Nordea (Sweden) only, which requires this node explicitly The assumption that other countries would accept it was incorrect ### Steps to reproduce: - Install `account_sepa_direct_debit` and `l10n_it` - Switch to the IT company - In Settings, set SEPA Direct Debit Creditor Identifier to `BE30ZZZ300D000000042` - Create and confirm a Payment (Method: SEPA Direct Debit, any customer and amount) - Create and validate a Batch Payment with that payment - Open the generated PAIN008 XML Before the fix, `<SchmeNm><Cd>CUST</Cd></SchmeNm>` is present opw-6530996 Forward-Port-Of: odoo/enterprise#130304
Cancelled point-of-sale orders and order lines in the German certification flow are now saved and marked as cancellations when sent to Fiskaly. This helps ensure compliant fiscal reporting and avoids mismatches for cancelled sales.
Original PR description
In this commit: --------------- - We now store cancelled retail orders on the server and send the `storno` flag as `true` for cancelled lines and orders to ensure proper handling in Fiskaly. task: 6326042 Relataed PR: https://github.com/odoo/odoo/pull/277648 Forward-Port-Of: odoo/enterprise#130175 Forward-Port-Of: odoo/enterprise#120410
Users sending Colombian DIAN support documents now see a clear message when the required operation mode is not configured. This replaces a confusing server error and helps businesses quickly fix their DIAN setup before resubmitting documents.
Original PR description
**Steps to reproduce:** * Install `l10n_co_dian`. * Configure a company with the Colombian localization. * Set up a DIAN operation mode for Electronic Invoices only (no Support Documents mode). *…
**Steps to reproduce:** * Install `l10n_co_dian`. * Configure a company with the Colombian localization. * Set up a DIAN operation mode for Electronic Invoices only (no Support Documents mode). * Create a vendor bill marked as a Support Document and click **Send to DIAN**. **Observed behavior:** * A cryptic server error is raised: *"TypeError: unsupported operand type(s) for +: 'int' and 'str'"* * No actionable information is shown to the user. **Cause:** * `_add_document_config_vals` assigns `vals['l10n_co_dian_operation_mode']` via `.filtered()`, which returns an empty recordset when no matching operation mode exists. * Accessing a `Char` field on an empty recordset returns `False` (a `bool`, which is a subclass of `int` in Python). * Concatenating `False` with strings in the `sha384` hash calculation raises the `TypeError`. * The missing-mode guard only existed in the commercial events path, not in the main invoice export path. **Fix:** * Raise a descriptive `UserError` that tells the user which mode is missing and where to configure it. opw-6499321 Forward-Port-Of: odoo/enterprise#128935
Completing a field service shift now correctly recalculates the allocated hours linked to that work. This helps ensure planning, timesheet, and sales information stay consistent for accurate reporting and billing.
Original PR description
This reverts commit b642ea4d5d2c0b4bd83c70103f7e8dfa6ef736dd. opw-6542896 Forward-Port-Of: odoo/enterprise#130832
Fixed an issue where changes made to loyalty program rewards could appear to save but then revert when reopened. This ensures promotion and discount updates are preserved, reducing confusion for sales and loyalty program users.
Original PR description
**Steps to reproduce:** 1. Install Sales and Loyalty modules 2. Create a Discount & Loyalty Program (type: Promotion) and save the form 3. Open the Reward modal and edit any values (e.g., 5% discount…
**Steps to reproduce:** 1. Install Sales and Loyalty modules 2. Create a Discount & Loyalty Program (type: Promotion) and save the form 3. Open the Reward modal and edit any values (e.g., 5% discount instead of 10%), save the new changes in the modal and then save the form 4. Re-open the reward modal **Issue:** The updated value (5% discount) is not saved, and the reward reverts to its previous state (10% discount). This issue will occur for any modifications. **Why this happens:** - The write method in `loyalty_program` uses `convert_to_cache` on `reward_ids` to make a constraint check before executing the actual super().write() - A recent commit (https://github.com/odoo/odoo/commit/9c52f6246d24d02457d34df6b559eecf7ec50687) modified `convert_to_cache` to update the cache for `Command.UPDATE` to fix premature computations during `onchange` - This update alters the real record's cache without marking the fields as dirty - When super().write() executes afterwards, the ORM sees the incoming values already match the cache, assumes no changes occurred, and drops the SQL UPDATE **Fix:** - Restrict the cache mutation to only apply to virtual/draft records - This preserves the intended onchange behavior for NewId records while preventing cache corruption on real database records prior to write opw-6527124 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286435
Portal users can now update their electronic invoicing format even after adding a company name to their address. This prevents the field from appearing empty later and helps ensure invoice delivery preferences are retained correctly.
Original PR description
Steps: - Install accounting app. - Login with portal user and set `Company name` on `my/address`. - Try to edit `Electronic Format` field on my details. Issue: - `Electronic Format` field stays empty. Cause: - Since [PR](https://github.com/odoo/odoo/pull/211043) when user set `Company name` on the portal it'll create parent company and since `Electronic Format` is computed from `commercial_partner_id`, so when I update `Electronic format` field on `my/address` it'll set that value on `invoice_edi_format_store` on current address and now when I re-open `my/address` it'll compute `invoice_edi_format` from `commercial_partner_id`'s `invoice_edi_format_store` which is 'none' and it'll set `invoice_edi_format` to False and there is no way portal user can update that company's record Fix: - Update inverse of `Electronic Format` field to properly store invoice_edi_format_store value on commercial partner. Forward-Port-Of: odoo/odoo#286599 Forward-Port-Of: odoo/odoo#277527
Fixes an issue in mail messages where a contact selected by mistake could remain as a hidden recipient after the mention was corrected to a longer name. This prevents unintended notifications and helps ensure only visibly mentioned contacts are contacted.
Original PR description
When a user mentions the wrong partner and corrects it by continuing to type, e.g. picking "John" by mistake, typing further so the text becomes "@ John Doe" and picking "John Doe" in the suggestion…
When a user mentions the wrong partner and corrects it by continuing to type, e.g. picking "John" by mistake, typing further so the text becomes "@ John Doe" and picking "John Doe" in the suggestion popup, the discarded first pick stays in the composer's mentioned partners. On post, mentions are validated by searching the body for "@<name>", and "@ John" is found inside "@ John Doe", so the partner the user tried to replace is kept in the recipients and gets notified even though no mention of them remains visible in the message. Validate mentions from the longest mention text to the shortest, counting the occurrences of each text and blanking them out before looking for shorter ones. A partner whose mention text only appears inside a longer mention is dropped, while distinct partners sharing the same name each consume one occurrence. Steps to reproduce: - Create contacts "John" and "John Doe" - On any record, open the chatter and type "@John", pick "John" by mistake, then keep typing " Doe" and pick "John Doe" in the suggestion popup to correct it - Send the message => The message is also sent to "John" although only "@John Doe" appears in the body. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287122 Forward-Port-Of: odoo/odoo#284239
Peruvian electronic invoices now include cash rounding in the final payable amount sent to SUNAT. This prevents mismatches between the displayed rounding amount and the total amount due, helping ensure compliant invoice XML generation.
Original PR description
Steps to reproduce ------------------ 1. On a peruvian company, set a cash rounding method on an invoice 2. Post the invoice and generate the SUNAT UBL 2.1 XML -> the rounding is in…
Steps to reproduce ------------------ 1. On a peruvian company, set a cash rounding method on an invoice 2. Post the invoice and generate the SUNAT UBL 2.1 XML -> the rounding is in `PayableRoundingAmount` but `PayableAmount` still has the amount before rounding! Why it's happening ------------------ The generic code computes `PayableAmount` from `amount_residual`, and Peru overrides it to be the total tax included of the XML minus the prepaid amounts, because the residual can not be used there. Then odoo/odoo@b847552872ad changed the meaning of the totals. The cash rounding line is not part of the base lines anymore, its amount is kept aside in `cash_rounding_base_amount_currency` and the totals do not contain it anymore. The generic code stays correct because `amount_residual` already has the rounding inside but the Peru total using `tax_inclusive_amount_currency` is now the amount before rounding and this is what ends up in the `PayableAmount`! The fix ------- Add the cash rounding amount when computing the `PayableAmount`. opw-6509677 Forward-Port-Of: odoo/enterprise#130732 Forward-Port-Of: odoo/enterprise#129983
This fix ensures that changes to default values in website form fields are properly remembered by the editor's undo history. Business users editing website forms or translations can now undo value changes reliably, avoiding mismatches between what they see and what is saved on the page.
Original PR description
The `value` property of the elements is not tracked by the history plugin, because `MutationObserver` does not produce mutations for that. This commit uses custom mutations when the `value` is changed, to restore the previous value on undo. Steps to reproduce: - Open website builder - Add a form - Set a "Default Value" on a text field - Press enter (to end preview) - Undo (with the button, or with focus out of the option's input) - Bug: The value shown in the page did not revert with undo Similar bug in translate mode task-6229671 Forward-Port-Of: odoo/odoo#286889 Forward-Port-Of: odoo/odoo#281232
Product identifiers sent to Google Analytics now match the identifiers used in Google Merchant Center feeds. This helps Google Ads correctly connect Shopping ad clicks with purchases, improving attribution and reducing matching warnings.
Original PR description
**Issue:** When google analytics (GA) and google merchant center (GMC) are setup, Google Ads diagonistic reports that item IDs cannot be matched to Merchant Center. **Why this happens:** `order_lines_2_google_api` sets `product.barcode or product.id` for `item_id`, while `product.feed._prepare_gmc_items` defaults to `product.default_code or product.id` for the feed's `id` field. Google Ads/Analytics attribution relies on GA4's `item_id` matching GMC's `id` for the same product to connect Shopping ad clicks to purchase events. **References:** https://support.google.com/merchants/answer/6324405?sjid=15224664355638221483-NC https://support.google.com/google-ads/answer/14943675?hl=en opw-6443326 Forward-Port-Of: odoo/odoo#285010