Daily updates from Odoo
Friday, August 14, 2026
26 changes · saas-19.1
Security fixes and vulnerability patches
Odoo Sign now verifies that a user can read a record before allowing it to be linked to a signature request. This prevents users from exposing information from records they are not authorized to access by manually changing the linked record.
Original PR description
Version: saas-18.3 Reported issue: 1. Marc Demo creates a sign request from a template whose fields are automatically populated from the linked record. 2. It is sent to himself. He does not have…
Version: saas-18.3 Reported issue: 1. Marc Demo creates a sign request from a template whose fields are automatically populated from the linked record. 2. It is sent to himself. He does not have access to all records of a referenced model (e.g. Sales Orders). 3. The "Linked To" (reference_doc) field is edited afterwards to point to a record the signer does not have access to. By the time it's signed, the value of that record becomes visible - so a user can, simply by changing the linked record, see the value of a record they were never authorized to access. Even a Sign Manager could link a request to a record they have no access to and later see its value through it. Issue: `reference_doc` could be set or changed to any record of any allowed model with no validation that the acting user actually has access to it. In the interface, you can only create a signature request from a record you can see, but editing `reference_doc` manually (via write(), RPC, etc.) was not held to the same rule, making it an easy way to leak information about records outside your normal access. Cause: The only restriction was cosmetic, enforced client-side by the record picker widget filtering its search results. Nothing on the server validated the value being written to `reference_doc`. Fix: `write()` now checks that the acting user has read access to the target record before allowing `reference_doc` to be set, raising a ValidationError otherwise, bringing manual edits in line with what the interface already enforces when creating a request. Forward-Port-Of: odoo/enterprise#127715
Enhancements to existing features
Spreadsheet pivot tables can now include SQL-based computed fields, giving users more ways to build custom analyses directly in spreadsheets. This improves reporting flexibility and helps teams extract more tailored insights without leaving the spreadsheet workflow.
Original PR description
Task: 6442237
Odoo Sign now limits changes to a signer's email address to the person who created the signing request. This helps prevent unintended or unauthorized recipient changes, improving control over who receives and signs documents.
Original PR description
Forward-Port-Of: odoo/enterprise#127582 Forward-Port-Of: odoo/enterprise#126675
Task: 6442237 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Task: 6442237 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
Resolved issues and error corrections
Annotated Deferred Revenue Reports can now be exported to Excel without triggering a server error. This helps accounting users reliably download reports even when the report has annotations and no standard column headers.
Original PR description
**Steps to reproduce:** * Install the **Accounting** module. * Unhide the **Start Date** and **End Date** fields on invoice lines. * Create and post a customer invoice with deferred dates. * Go to…
**Steps to reproduce:** * Install the **Accounting** module. * Unhide the **Start Date** and **End Date** fields on invoice lines. * Create and post a customer invoice with deferred dates. * Go to **Accounting → Reports → Deferred Revenue Report**. * Add an annotation to a deferred revenue line by clicking the **annotate** from three dots next to the account. * Export the report in **XLSX** format. **Observed behavior:** * The export fails with a server error: `UnboundLocalError: cannot access local variable 'annotations_x_offset' where it is not associated with a value` **Cause:** * The variable `annotations_x_offset` is assigned inside the `for header_level_index, header_level in enumerate(options['column_headers'])` loop, which writes the "Annotations" column header for each header level. * The Deferred Revenue Report produces an empty `column_headers` list, so the loop body never executes and `annotations_x_offset` is never assigned. * When the code later tries to write annotation data for each report line, it references the unassigned variable, causing Python to raise `UnboundLocalError`. **Fix:** * Introduce a boolean flag `annotations_header_written = False` before the header loop to explicitly track whether the "Annotations" column header has already been written. * Inside the header loop, set `annotations_header_written = True` after writing the header. * After writing all individual column headers (where `x_offset` already points to the first free column after all data columns), add a fallback: if `report_annotations` is set but `annotations_header_written` is still `False`, assign `annotations_x_offset` from the current `x_offset` and write the "Annotations" header. opw-6354473 Forward-Port-Of: odoo/enterprise#127726 Forward-Port-Of: odoo/enterprise#122768
Australian payroll submissions to the ATO now check that required payslip or employee data is present before submission. Instead of an unexpected system error, users receive a clear validation message, helping payroll teams correct the issue and continue safely.
Original PR description
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module -…
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module - Switch to ``My australian Company`` - Go to Payroll > Configuration > Settings > In Australian Localization, Set BMS ID > Set STP Responsible and his date of birth - Go to Payroll > Reporting > Single Touch Payroll > Create a new record > Set Payment Date > Submit to ATO > Sign & Submit to ATO Traceback: ```py IndexError: tuple index out of range ``` https://github.com/odoo/enterprise/blob/b0e48baaf99bdc4faefd2ffdd3bd5637fb548593/l10n_au_hr_payroll_account/models/l10n_au_stp.py#L228-L233 The traceback occurs because ``_get_fiscal_year_start()`` assumes that the STP record always contains at least one payslip or one employee. When these recordsets are empty, indexing the first element raises an IndexError. Solution: This commit validates that the required payslips or employees are present before the submission and raises a validation error instead of a traceback. Forward-Port-Of: odoo/enterprise#127733 Forward-Port-Of: odoo/enterprise#124096
A payroll-related automated test was failing because it used a Sunday, when employees were not scheduled to work. The date has been changed to a Monday so the test reflects a valid working day and avoids false failures.
Original PR description
The test `test_float_holiday_attest` fails with a ValidationError: "The following employees are not supposed to work during that period". The previous patch (cf. PR odoo/enterprise#107490) froze time to "2026-02-01 08:00:00", which was a Sunday. When validating the leave created for `today`, check of the employee's calendar fails because zero working hours are scheduled on weekends. This commit updates `@freeze_time` to "2026-02-02 08:00:00" (Monday) so the leave validation runs against a valid working day. runbot-240132 runbot-241193 Forward-Port-Of: odoo/enterprise#126391
Historical Luxembourg payslips now use the wage index that was valid at the end of the payslip period, rather than today's index. This helps ensure past payroll calculations remain accurate and consistent with the period being processed.
Original PR description
Historical payslips incorrectly used today's wage index instead of the index active during the payslip period. Now, salary rules evaluate the indexed wage using `payslip.date_to` via the new `_get_l10n_lu_indexed_wage(date)` contract method. Task: 6395557 Forward-Port-Of: odoo/enterprise#125861
Large accounting reports now render fewer hidden rows, reducing page weight and improving responsiveness when users fold sections or search. This helps reports with thousands of lines feel faster and easier to navigate until the newer virtual grid solution is available.
Original PR description
When a report has 1 000+ lines, the DOM gets quite heavy which make DOM operation very slow. To help reduce this, we now will minimize the number of components rendered by removing components that previous were just hidden using "d-none" on the line. This will require more creation and suppression of components but it should make the DOM size smaller so it should help on larger reports where a lot of lines are hidden (by folding back a line, or by using the search bar). opw-6427411 opw-6442756 PR Note: this is only required until saas-19.5/20.0 since the virtual grids are added then which will resolve this issue since the virtual grids only render what's in the view of the user with long paddings on top and bottom so only ~70-80 lines are actually rendered. Forward-Port-Of: odoo/enterprise#127516
Payroll configuration now shows Mexico-specific CFDI settings only when the active company is based in Mexico. This avoids confusing or irrelevant options for companies operating in other countries.
Original PR description
Steps to reproduce: 1. Switch to a non-Mexican company. 2. Go to Payroll > Configuration > Settings. 3. The CFDI settings block is visible. Reason: The CFDI block was missing a country check. Solution: Restrict the CFDI block visibility to Mexican companies. Task-6448440 Forward-Port-Of: odoo/enterprise#127022
Steps to reproduce: - make a few sales in the PoS and refund one of them - close the session - select all those orders, including the refund, and create a consolidated invoice Issue: The invoice is refused with "You cannot validate an invoice with a negative total amount. You should create a credit note instead.", while the total of the selected orders is positive. If a cash rounding method is set on the PoS config, no error is raised but the posted document is a credit note carrying a r
Original PR description
Steps to reproduce: - make a few sales in the PoS and refund one of them - close the session - select all those orders, including the refund, and create a consolidated invoice Issue: The invoice is…
Steps to reproduce: - make a few sales in the PoS and refund one of them - close the session - select all those orders, including the refund, and create a consolidated invoice Issue: The invoice is refused with "You cannot validate an invoice with a negative total amount. You should create a credit note instead.", while the total of the selected orders is positive. If a cash rounding method is set on the PoS config, no error is raised but the posted document is a credit note carrying a rounding line equal to twice the order total (a credit note of 20.00 with a 40.00 "Rounding" line for sales of 10.00 + 20.00 and a refund of 10.00). Cause: _prepare_invoice_vals picked the move type from the presence of a refund in the group instead of its net amount: any group holding an order with is_refund set, or a negative amount_total, became an 'out_refund'. _get_invoice_lines_values then negates the quantities of every order whose direction differs from the move type, so the sales end up as negative lines of a credit note and the document totals -20.00 instead of +20.00. account.move refuses to post it. When invoice_cash_rounding_id is set, the cash rounding line is computed to bring the document back to a total valid for its type, so it absorbs the whole sign error and the wrong credit note is posted silently. Fix: Choose the move type from the net amount_total of the group, as was done up to saas-18.3, and keep is_refund only as the tie-break when that net is zero so a lone zero-total refund still gives a credit note. The sign handling of the lines is unchanged: it already keys on each order's own direction, which is what makes a sale a negative line of a credit note and a refund a negative line of an invoice. opw-6452996 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281703
Steps to reproduce: - Create a "Buy 2 Get 1 free" program whose rule and reward cover three products having the same price - In the PoS, add one unit of each of the three products -> one free product is given - Add three more units of the second product, 6 units in total Issue: Only one free product is given instead of two, the order total is 50 instead of 40. Cause: `_updateRewardLines` deletes the reward lines and re-applies each claimed reward. Beforehand it merges the claims havin
Original PR description
Steps to reproduce: - Create a "Buy 2 Get 1 free" program whose rule and reward cover three products having the same price - In the PoS, add one unit of each of the three products -> one free product…
Steps to reproduce: - Create a "Buy 2 Get 1 free" program whose rule and reward cover three products having the same price - In the PoS, add one unit of each of the three products -> one free product is given - Add three more units of the second product, 6 units in total Issue: Only one free product is given instead of two, the order total is 50 instead of 40. Cause: `_updateRewardLines` deletes the reward lines and re-applies each claimed reward. Beforehand it merges the claims having the same reward and the same price, which is the case for two free products of the same price even when they were claimed for two different products. The merged claim keeps the `_reward_product_id` of the first line only, with a quantity of two. On re-application, `_computeUnclaimedFreeProductQty` only counts in `available` the quantity of that single product, since the other lines are counted only while a reward line is still in the order and they have all just been deleted. It therefore returns 1 and the second free product is lost. Fix: Only merge claims that were made for the same free product. Gift card/ewallet claims have no `_reward_product_id` and claims of a reward having a single reward product all share the same one, so both keep being merged as before. opw-6430385 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282052
Issue: Compare to lot and serial number package are not multi company. It means that the package don't pass from a company to the other. So when a company deliver to another. The delivery will create a quant with the package. However the receipt in the other company will create a new quant without package (or a new package). It means that the quants are never reconcile and it could become difficult to understand what remains in intercompany location and what are artifact from past movements.
Original PR description
Issue: Compare to lot and serial number package are not multi company. It means that the package don't pass from a company to the other. So when a company deliver to another. The delivery will create a quant with the package. However the receipt in the other company will create a new quant without package (or a new package). It means that the quants are never reconcile and it could become difficult to understand what remains in intercompany location and what are artifact from past movements. In order to fix it, we introduce a new system parameter to directly unpack after the delivery. This way the receipt is always without source package and will automatically decrease the quant. opw-6376983 Forward-Port-Of: odoo/odoo#280741 Forward-Port-Of: odoo/odoo#277133
When creating a MO For a product with no variant, it will add an on apply on variant component, even if only one of it's attribute has a values that match with the product on the mo. Steps to reproduce: ------------------- * Create a Product with two never attributes (att1 and att2) * Add values to both attributes * Create a BOM with components with apply on variant for every possibility: - component att1 val1, att2 val1, apply on variant: att1 value 1 att2 value1 - component att1 v
Original PR description
When creating a MO For a product with no variant, it will add an on apply on variant component, even if only one of it's attribute has a values that match with the product on the mo. Steps to…
When creating a MO For a product with no variant, it will add an on apply on variant component, even if only one of it's attribute has a values that match with the product on the mo. Steps to reproduce: ------------------- * Create a Product with two never attributes (att1 and att2) * Add values to both attributes * Create a BOM with components with apply on variant for every possibility: - component att1 val1, att2 val1, apply on variant: att1 value 1 att2 value1 - component att1 val1, att2 val2, apply on variant: att1 value 1 att2 value2 - component att1 val2, att2 val1, apply on variant: att1 value 2 att2 value1 - ... * Add mto and manufacture to the product * Create and confirm a SO for the product variant att1 value 1 and att value 2 -> On the MO every component that as at least one of the values will be present. Observation: ------------- When confirming the SO it will call action_confirm. Since we are in mto, it will create a procurement order of the manufacture type and will create a MO. When creating the workorder, it will call explote on the bom to know all the components: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/mrp/models/mrp_production.py#L626 Each line that does not respect the apply on variant condition will be ignored: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/mrp/models/mrp_bom.py#L450-L451 it will retrieve the line if at least one value from any attribute match: https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/mrp/models/mrp_bom.py#L623-L626 opw-6293259 Forward-Port-Of: odoo/odoo#271351
In this commit: - Ensure event ticket information is preserved during self-order processing and use the configured ticket price when recomputing order line prices. - This prevents ticket prices from being replaced by the product price after proceeding to payment and keeps the amounts consistent across the payment page. Task:6375899
Original PR description
In this commit: - Ensure event ticket information is preserved during self-order processing and use the configured ticket price when recomputing order line prices. - This prevents ticket prices from being replaced by the product price after proceeding to payment and keeps the amounts consistent across the payment page. Task:6375899
Before this commit, the hoot test "keep banner for messages received while scrolled up" failed at random on runbot: ``` Failed to find 1 of ".o-mail-Thread-banner:has(:text('1 new message'))" (Timeout of 10 seconds). Found 0 instead. ``` This happens because the test waits for the scroll position it sets in the DOM only, while the thread copies that position to the record on the scroll event, one animation frame later. Bob's message can arrive in between, when the record still says "bot
Original PR description
Before this commit, the hoot test "keep banner for messages received while scrolled up" failed at random on runbot:
```
Failed to find 1 of ".o-mail-Thread-banner:has(:text('1 new message'))"
(Timeout of 10 seconds). Found 0 instead.
```
This happens because the test waits for the scroll position it sets in the DOM only, while the thread copies that position to the record on the scroll event, one animation frame later. Bob's message can arrive in between, when the record still says "bottom": the counter the banner reads stays frozen at 0 and the message is marked as read on arrival, so the banner never shows.
This commit waits until the record holds that position before posting.
https://runbot.odoo.com/odoo/error/945967
Forward-Port-Of: odoo/odoo#282218Before this commit, deleting a record leaves its id in the relations of a record deleted before it in the same update, and reading one of those relations hands out an entry for a record that is gone. This happens because an update takes a deleted record out of the relations that hold it, but forgets it as soon as it is deleted. However, deleting a record is what queues the deletion of the records it holds: `channelMembers` carries `onDelete: (r) => r.delete()`, so the members of a thread are
Original PR description
Before this commit, deleting a record leaves its id in the relations of a record deleted before it in the same update, and reading one of those relations hands out an entry for a record that is gone. This happens because an update takes a deleted record out of the relations that hold it, but forgets it as soon as it is deleted. However, deleting a record is what queues the deletion of the records it holds: `channelMembers` carries `onDelete: (r) => r.delete()`, so the members of a thread are deleted once the thread is already forgotten, and their ids stay in its `onlineMembers`. This commit fixes the issue by keeping the records deleted by an update known until it ends. Forward-Port-Of: odoo/odoo#282307 Forward-Port-Of: odoo/odoo#281983
The `/shop` product results and facets use different search fields. In particular, facets search raw `website_description` HTML, causing terms such as `weight` to match CSS like `font-weight` and process far more products than are displayed. Use one shared field list for both paths: - `name` - `variants_default_code` - `description_sale` - `description_ecommerce` Stop searching `default_code`, internal `description`, and raw `website_description`. opw-6391984 --- I c
Original PR description
The `/shop` product results and facets use different search fields. In particular, facets search raw `website_description` HTML, causing terms such as `weight` to match CSS like `font-weight` and process far more products than are displayed. Use one shared field list for both paths: - `name` - `variants_default_code` - `description_sale` - `description_ecommerce` Stop searching `default_code`, internal `description`, and raw `website_description`. opw-6391984 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280720
# How to reproduce - Enable dev mode - In the website editor, add a Video Inner Content to the page - Enable atleast one option that is not "Start at" (e.g. Autoplay) - Click on the Video, and in the Style tab, click on Replace # The problem A traceback is shown # Cause When you replace a video, a pop up appears with the different options associated to that video. These options are rendered with the `VideoOption` component : https://github.com/odoo/odoo/blob/46d3fee5812b8406aac22
Original PR description
# How to reproduce - Enable dev mode - In the website editor, add a Video Inner Content to the page - Enable atleast one option that is not "Start at" (e.g. Autoplay) - Click on the Video, and in the…
# How to reproduce - Enable dev mode - In the website editor, add a Video Inner Content to the page - Enable atleast one option that is not "Start at" (e.g. Autoplay) - Click on the Video, and in the Style tab, click on Replace # The problem A traceback is shown # Cause When you replace a video, a pop up appears with the different options associated to that video. These options are rendered with the `VideoOption` component : https://github.com/odoo/odoo/blob/46d3fee5812b8406aac2244baa76b0daeef358c2/addons/html_editor/static/src/main/media/media_dialog/video_selector.js#L9 The props for that component accept a `value`, which type has been changed from `Boolean` to `String` in : https://github.com/odoo/odoo/commit/ae894892e048bcdf9c3efcf41b53b44f2fd9e88b The issue is that some option's value are defined as boolean : https://github.com/odoo/odoo/blob/46d3fee5812b8406aac2244baa76b0daeef358c2/addons/html_editor/static/src/main/media/media_dialog/video_selector.js#L352 So the props validation fail, but only in dev mode : https://github.com/odoo/odoo/blob/46d3fee5812b8406aac2244baa76b0daeef358c2/addons/web/static/lib/owl/owl.js#L3227-L3231 # Proposed solution When changing the options value in the popup, the trucy values are replaced by "00:00", which is why the traceback only appears when replacing the video : https://github.com/odoo/odoo/blob/46d3fee5812b8406aac2244baa76b0daeef358c2/addons/html_editor/static/src/main/media/media_dialog/video_selector.js#L182-L186 We now use the same trucy represetation in `syncOptionsWithUrl()` opw-6369196 Forward-Port-Of: odoo/odoo#276585
In commit 004b56a5c31841bc0bf4a9f17902bbff8d0f509d we added warnings to tell French companies to install the PDP module. When working on commit 720294ee523c6f84d0302e6b7fd634069f72dda7 we noticed the problem that the PDP module is not available without rescanning the available modules ("Update Apps List" in debug mode in the "Apps"). This is fixed in this commit: In case the module is not installed we still show the warning but link to the "Update Apps List" wizard. task-None For
Original PR description
In commit 004b56a5c31841bc0bf4a9f17902bbff8d0f509d we added
warnings to tell French companies to install the PDP module.
When working on commit 720294ee523c6f84d0302e6b7fd634069f72dda7
we noticed the problem that the PDP module is not available
without rescanning the available modules ("Update Apps List" in
debug mode in the "Apps").
This is fixed in this commit:
In case the module is not installed we still show the warning
but link to the "Update Apps List" wizard.
task-None
Forward-Port-Of: odoo/odoo#280209In the sampel dashboard the figures are half transparent to indicate that they are just sample data, but they are still interactive. This commit disable all the pointer events on them. Task: [6467022](https://www.odoo.com/web#id=6467022&cids=1&menu_id=4720&action=333&active_id=2328&model=project.task&view_type=form) 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 rea
Original PR description
In the sampel dashboard the figures are half transparent to indicate that they are just sample data, but they are still interactive. This commit disable all the pointer events on them. Task: [6467022](https://www.odoo.com/web#id=6467022&cids=1&menu_id=4720&action=333&active_id=2328&model=project.task&view_type=form) 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#282179
Steps to reproduce --- 1. Create and confirm a sale order. 2. Create a down payment invoice on it and post it: the down payment line reads "Down Payment (ref: INV/... on ...)". 3. Open that invoice and use Reverse and Create Invoice, then post the newly created draft down payment invoice. 4. Open the sale order: the down payment line has lost its reference and now reads only "Down Payment", and that empty label also carries over to the down payment section when generating the final invoice.
Original PR description
Steps to reproduce --- 1. Create and confirm a sale order. 2. Create a down payment invoice on it and post it: the down payment line reads "Down Payment (ref: INV/... on ...)". 3. Open that invoice…
Steps to reproduce --- 1. Create and confirm a sale order. 2. Create a down payment invoice on it and post it: the down payment line reads "Down Payment (ref: INV/... on ...)". 3. Open that invoice and use Reverse and Create Invoice, then post the newly created draft down payment invoice. 4. Open the sale order: the down payment line has lost its reference and now reads only "Down Payment", and that empty label also carries over to the down payment section when generating the final invoice. Issue --- The down payment line description is built by `_get_downpayment_description`, which only produces the "Down Payment (ref: ... on ...)" label when exactly one customer invoice is linked to the down payment `sale.order.line`, guarded by `len(invoice) == 1`. https://github.com/odoo/odoo/blob/3a5f7431effd4b2b2eb8ce3eed81aaba42fcd8ea/addons/sale/models/sale_order_line.py#L484-L509 Reverse and Create Invoice runs `account.move.reversal.modify_moves`, which copies the reversed invoice with `include_business_fields=True`, so the copied line keeps its `sale_line_ids` and the new draft invoice is attached to the very same down payment line as the reversed original. https://github.com/odoo/odoo/blob/3a5f7431effd4b2b2eb8ce3eed81aaba42fcd8ea/addons/account/wizard/account_move_reversal.py#L142-L149 That down payment line then references two `out_invoice` moves (the reversed one and the re-issued one), so `len(invoice) == 1` is false and the label silently falls back to the bare "Down Payment", losing the reference that the final invoice's down payment section reuses. Going back to the sale order to raise a fresh down payment instead creates a new line, which keeps a single invoice and is why the slower flow is unaffected. The `len(invoice) == 1` guard was introduced in ba954604e529. Discarding the reversed invoice (`payment_state == 'reversed'`) leaves the active re-issued invoice as the single match, so its reference is shown again; when the only linked invoice is itself reversed, the fallback keeps displaying it so existing descriptions are preserved. opw-6353384 Forward-Port-Of: odoo/odoo#277802
Before this commit, a test answering a route with a response of its own, `new Response(stream)`, reads `content-type: application/json` back from it, a header it never set. At the debug log level, the request itself fails: Unexpected token 'o', "[object Rea"... is not valid JSON This happens because the mocked fetch guesses the content type from its result, and a response is neither a string, a `Blob` nor a `FormData`, so it falls back to JSON, on the very headers the response carries.
Original PR description
Before this commit, a test answering a route with a response of its own, `new Response(stream)`, reads `content-type: application/json` back from it, a header it never set. At the debug log level, the request itself fails:
Unexpected token 'o', "[object Rea"... is not valid JSON
This happens because the mocked fetch guesses the content type from its result, and a response is neither a string, a `Blob` nor a `FormData`, so it falls back to JSON, on the very headers the response carries. The response logger then reads the body as text, "[object ReadableStream]" for a stream, and parses it as JSON.
This commit guesses the content type of a raw value only, so a response keeps the headers it was built with.
Forward-Port-Of: odoo/odoo#281968In this commit: - The feedback screen was not scaling properly on Android devices and tablet displays, causing content to appear too small or overflow. - Fixed by making the checkmark and text sizes responsive using units so the layout adapts correctly across different screen sizes. Task: 6420543 Forward-Port-Of: odoo/odoo#279328
Original PR description
In this commit: - The feedback screen was not scaling properly on Android devices and tablet displays, causing content to appear too small or overflow. - Fixed by making the checkmark and text sizes responsive using units so the layout adapts correctly across different screen sizes. Task: 6420543 Forward-Port-Of: odoo/odoo#279328
### Issue: When a company is not connected to the French Electronic Invoicing PDP proxy, the generated XML is missing required notes: `PMT`, `PMD` and `AAB` These notes are required by Factur-X rule `BR-FR-05/BT-22` and their absence causes validation errors on the FNFE validator ### Cause: `_l10n_fr_pdp_get_default_notes` only added the notes when the company was using a PDP proxy type Non-PDP users sending invoices via other means were excluded, which contradicts the French e-invoicing
Original PR description
### Issue: When a company is not connected to the French Electronic Invoicing PDP proxy, the generated XML is missing required notes: `PMT`, `PMD` and `AAB` These notes are required by Factur-X rule `BR-FR-05/BT-22` and their absence causes validation errors on the FNFE validator ### Cause: `_l10n_fr_pdp_get_default_notes` only added the notes when the company was using a PDP proxy type Non-PDP users sending invoices via other means were excluded, which contradicts the French e-invoicing requirements ### Steps to reproduce: - Install `l10n_fr_pdp` and switch to the FR company - In Settings, ensure French Electronic Invoicing is not activated - Create and confirm an invoice (any line with tax) - Send the invoice and open the generated XML Before the fix, the `PMT`, `PMD` and `AAB` notes are missing Activating French Electronic Invoicing would include them opw-6392262 opw-6377507 Forward-Port-Of: odoo/odoo#282031 Forward-Port-Of: odoo/odoo#279966
Documentation and clarification updates
Add the individual CLA signature for Han Zaw Nyein (`HanZawNyein`). This signature covers contributions including odoo/odoo#281412 and odoo/odoo#281415. Forward-Port-Of: odoo/odoo#281609
Original PR description
Add the individual CLA signature for Han Zaw Nyein (`HanZawNyein`). This signature covers contributions including odoo/odoo#281412 and odoo/odoo#281415. Forward-Port-Of: odoo/odoo#281609