Tuesday, September 15, 2026
22 changes · saas-19.1
Enhancements to existing features
Peppol-related errors are now shown as separate, easier-to-read messages instead of one technical line. Known error codes are translated into clearer explanations, helping users understand what went wrong and what action may be needed.
Original PR description
Before this commit, Peppol error messages (e.g. Schematron errors) were logged in the chatter as a single unformatted line and without any humanization. The errors were too technical and the user could not easily know what action to take. This PR splits the raw error payload into individual entries, maps known error codes to human-readable explanations, and renders them as an HTML list in the chatter. task-6144909 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283311 Forward-Port-Of: odoo/odoo#265253
Accounting invoices now handle collapsed sections consistently across PDF and XML exports by grouping section totals according to their taxes. This makes invoice presentation and electronic invoice data more accurate and aligned with Sales behavior, reducing confusion for customers and compliance workflows.
Original PR description
Before this commit, collapsing composition in Accounting did not behave the same as in Sales. In Accounting PDFs, when a section was created and its composition was hidden, taxes were removed from…
Before this commit, collapsing composition in Accounting did not behave the same as in Sales. In Accounting PDFs, when a section was created and its composition was hidden, taxes were removed from individual lines and displayed on the section line as a comma-separated list. This commit aligns the behavior with the Sales app: - When collapsing composition, sections are grouped by tax. - When hiding prices, taxes are removed from the section line and kept on each individual line. Also, hiding composition in sections wasn't taken into account while exporting the XML. This commit introduces this behaviour for the XML invoices : - when we export section that hides the composition, we first group the sections by tax, then we create an invoice line with the section's name, with the right tax and amounts calculations. NOTE: This commit does not introduce price hiding in XML exports. task-6101592 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#258959
The VoIP recruitment integration now includes a needed access check in the initial session data. This reduces extra background calls when the web client starts, helping the app load more efficiently.
Original PR description
The voip app needs this group at startup: https://github.com/odoo/enterprise/blob/203c85cade63a6564f5051d318916aaf0ea87df5/voip_hr_recruitment/static/src/softphone/softphone_model_patch.js#L14 This commit adds the group inside the session info to avoid extra RPCs at webclient startup. The exact same thing is done for other voip_* bridge modules task-6565730
Resolved issues and error corrections
This fix prevents an error when users open sale or purchase receipts from Invoice Analysis. Businesses using receipts can now review related records from reporting views without interruption.
Original PR description
When enabling Sale/Purchase Receipts and trying to open the form view from Invoice Analysis, an error occurs. The issue is caused by the `move_type` used in `_where()`, which includes a type that is not defined in the `move_type` field selection. Steps to reproduce: - Enable Sale/Purchase Receipts. - Create a Sale/Purchase Receipt for partner A and confirm it - Go to Invoice Analysis and open the Pivot view - Click on a cell to open partner A's receipt, then try to open the form view - Error Ticket [link](https://www.odoo.com/odoo/project.task/6462153) opw-6462153 Forward-Port-Of: odoo/odoo#288077 Forward-Port-Of: odoo/odoo#282922
Documentation and clarification updates
Mina Adel has signed the Individual Contributor License Agreement, enabling their contributions to be accepted under Odoo's legal requirements. This is an administrative legal update with no impact on product functionality.
Original PR description
Individual Contributor License Agreement signature for Mina Adel (minallegend@gmail.com, https://github.com/minaonlyone). Needed for odoo/enterprise#131352 (19.0). Replaces #287992, whose branch name made runbot diff it against master. Forward-Port-Of: odoo/odoo#288010
The call settings menu now shows the correct name for the selected speaker or audio output device, even when Chrome reports input and output devices with the same default ID. This avoids confusion for users checking or changing their call audio settings.
Original PR description
Steps to reproduce: - Have an input audio device and an output audio device with different names but same device ID. Using Chrome, if the OS only sees one of each, both should have "default" as device ID. (alternatively, modify the code at `updateDevicesList` to simulate having devices of that kind). - Select those devices in the call settings UI, then open the settings UI dropdown again. => The "input" device is properly shown but the "output" device shows the "input" device names (while in fact this is the right one selected in the inner dropdown). This happens since [1]. Before that there were native `<select>` nodes that filtered devices by kind before rendering each option, and the "default" value of Chrome was not really handled. [1]: https://github.com/odoo/odoo/commit/93d0931fba1f467de265200b6a0463cf7edf9534 Related to task-6533808
This fix prevents automated point of sale and restaurant payment checks from failing intermittently when receipt printing encounters an error. By stopping an automatic screen change during the test flow, it improves confidence in continuous testing without changing the customer-facing checkout experience.
Original PR description
The fast-payment tours with automatic receipt printing configure an unreachable printer to exercise the printing-failure path. Once the failed print settles, FeedbackScreen arms a 1500ms timer that auto-navigates to the next order (iface_print_auto). The tour needs to detect the resulting error dialog, confirm it, then click the validation button, all before that timer fires. On a fast machine this comfortably fits, but on a loaded CI runner the sequence can take longer than 1500ms, so the auto-navigation happens first, unmounting the feedback screen before the tour can click ".button.validation" and causing a step timeout that could not be reproduced locally. Click on the feedback screen background right after confirming the dialog to call stopAutomaticSkip() and cancel the pending timer, removing the race entirely. This mirrors the pattern already used in test_automatic_receipt_printing. runbot-946191
This fix prevents product video thumbnails from being sent to Google Merchant Center as extra product images. It also avoids loading unnecessary image data when generating the feed, reducing the risk of memory-related failures for stores with many product images.
Original PR description
Description of the issue/feature this PR addresses: The Google Merchant Center feed builds the extra image URL list of each product, and must skip the `product.image` records holding a video, as…
Description of the issue/feature this PR addresses:
The Google Merchant Center feed builds the extra image URL list of each product, and must skip the `product.image` records holding a video, as their image is only a thumbnail of that video. It filters those out by accessing `image_128`, which is wrong on two counts:
- A video record does have an `image_128`: the thumbnail, fetched from the video URL or uploaded by the user. Video thumbnails were therefore listed in the feed as if they were product images.
- Binary fields are read and base64-encoded in full by default, so the binary content of every extra product image was loaded into memory just to evaluate a truthiness check. On a database with ~4261 products with images, rendering the feed exhausts the worker memory limit and raises an out-of-memory error.
Current behavior before PR:
`_get_extra_image_1920_urls()` keeps every extra image whose `image_128` is set, including video thumbnails, and forces the ORM to fetch and base64-encode the full content of every extra image attachment.
<img width="2038" height="1462" alt="image" src="https://github.com/user-attachments/assets/e3b375e5-ac17-4b5c-b0c3-59264d7e36f7"/>
Desired behavior after PR is merged:
The records are filtered on `video_url`, the field that actually flags a video, so videos are properly excluded and no image binary is read at all.
opw-6513194
Forward-Port-Of: odoo/odoo#286782Validated future time off is now counted when showing an employee's remaining allocated leave. This prevents balances from appearing too high and helps HR teams and employees see a more accurate time-off balance.
Original PR description
**Steps to reproduce:** - Create and validate an allocation of 10 days. - Take and validate a leave of 5 days in the future. - Issue: the allocation's `virtual_remaining_leaves` still shows 10 instead of 5. **Issue:** `hr.leave.allocation._compute_leaves()` calls `_get_consumed_leaves()` with `ignore_future=True`, which filters the leaves domain to `date_from <= today`. A validated future leave is excluded from the query before it can be deducted, even though the allocation grants its days upfront and isn't gated by any accrual plan. This flag was intentionally dropped from this call by (odoo/odoo#193685), then came back by accident via a forward-port of (odoo/odoo#249441). **Solution:** Drop `ignore_future=True` from `_compute_leaves()` Task-6534125 Forward-Port-Of: odoo/odoo#287626
OSS sales for Spain are now assigned to the correct VAT report box, ensuring amounts appear in casilla 123 instead of casilla 124. This improves the accuracy of Spanish VAT reporting for businesses using EU OSS tax flows.
Original PR description
OSS sales were being mapped to mod_303_casilla_124_balance where it should be mapped to mod_303_casilla_123_balance. These amounts must be reported values in casilla 123. This commit updates es_assec, es_common, es_full and es_pymes tax templates from 124 to 123 and updates test_country_tag_from_spain. task-6360387 I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284984
Invoices for customers in the Canary Islands, Ceuta, or Melilla are now reported with the correct Spanish tax regime code instead of a generic one. This improves compliance for businesses issuing invoices to these territories and ensures Verifactu includes the required regime option.
Original PR description
… key 8 When the customer is located in Canary Islands, Ceuta or Melilla, the invoice falls under a different tax territory and the ClaveRegimenEspecialOTrascendencia should be 08. Add the regime key 08 to the clave_regimen_selection in verifactu Previously this case was not checked and invoices were reported with the generic refime code. The regime key 08 is not available in verifactu. task-6372837 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279435
This update prevents access errors when managers view employee org charts or handle expenses across companies they are allowed to work with. It also lets expense team approvers create expenses for their subordinates more reliably in multi-company setups, reducing administrative blockers.
Original PR description
_(updates on July-17th and July-28th for points 2. and 3. in `hr_expense`)_ # Introduction **1\.** A fix to `hr_org_chart` was initially proposed. I think it is mergeable because it fixes the…
_(updates on July-17th and July-28th for points 2. and 3. in `hr_expense`)_ # Introduction **1\.** A fix to `hr_org_chart` was initially proposed. I think it is mergeable because it fixes the user-experience properly like expected in Odoo standard. Other commits are suggested to `hr_expense`. They were designed to allow more flexibility in the management of `hr_employee.company_id` (in multi-company context) and allow not to duplicate the `hr.employee` of each companies of the `res.users`. **2\.** The [FIX] silences a multi-company access error when searching for Expense validators => it seems safe **3\.** The [IMP] largely allow more flexibility for a "Expense: Team Approver" when creating expenses on behalf of its subordinates # 1. in hr_org_chart [FIX] Prevents multi-company error when recursively searching for ancestors. <img width="1035" height="789" alt="image" src="https://github.com/user-attachments/assets/d5517f79-7efc-4223-ae77-0af8b25a3d1e" /> ### Issue description In a multi-company environment, when one of the `hr_employee.company_id` of a hierarchy is not in the allowed companies of a Manager's `res_users.company_ids`, this Manager can view `hr.employee` in the list view but cannot open their forms. This happens when: - `hr_org_chart` module is installed - the Org Chart is displayed on the 1st page of the `hr.employee` form, like when the HR settings "Skills Management" is disabled (in `res.settings`) => thus the whole form becomes inaccessible from the manager When a `hr.employee` form is opened, a multi-company access error is thrown to him, even if the `company_id` of the opened `hr.employee` is in the user's `res_users.company_ids`, because of the hierarchy's `company_id`. It should be expected that the part of the Org Chart which is not allowed to be seen would just be hidden. ### Steps to reproduce Data setup: - Employee "A" in company A - Manager "M" in company A, manager of "Employee A" - Manager of manager "MM" in company A, manager of "Manager M" - And now, in company B (let's say a Holding), the "Director" is manager of "Manager MM" - "Manager M" is only given access access to Company A - the module "hr_org_chart" is installed Actions: - Login with Manager M - Browse to Employees list and try and open the form of "Employee A" (up to tab _"Professional information"_, if it is not the 1st of the notebook) ### Proposed fix This PR re-uses the already existing method `_check_employee` which contains all the logic to solve the issue. Maybe the call to this method was forgotten? This PR simply call this method when finding an ancestor, in the controller of `hr_org_chart`. This fix is thus very limited to the call to the public method `hr_org_chart.get_org_chart()` made by the Org Chart widget. ### Desired behavior after PR is merged The part of the Org Chart not allowed to be seen by "Manager M" is hidden. # 2. hr_expense [FIX] <img width="541" height="415" alt="image" src="https://github.com/user-attachments/assets/d594815b-2b77-4088-878b-9b192b64d6a3" /> ### Issue description As an employee, I click on the button "View Report" on my expense. I get a multi-company access error, preventing me to view and edit my expense report. This is because the manager of the department I belong is in a company I'm not allowed to see. This can also happen just when opening my Expense (instead of Expense Report). ### Current behavior before this PR The employee is blocked to continue editing its Expense or to submit it to a Report. ### Current behavior after this PR The employee can edit and submit its Expense no matter the `company_id` of its hierarchy. Technically: the `can_approve` field on the expense sheet uses a localized `.sudo()` method to bypass multi-company limits when searching if the current user is a validator. # 3. hr_expense [IMP] <img width="1028" height="549" alt="image" src="https://github.com/user-attachments/assets/1096c0d4-d025-46a9-8559-6bab5de71577" /> ### Improvement summary In multi-company environment, allow a "Expense: Team Approver" to create Expenses for its subordinates (`hr_expense.employee_id`) **no matter the `hr_employee.company_id` of its subordinates**. The domain of `hr_expense.employee_id` keeps the security of `check_company=True` => thus the Manager only sees `hr.employee` having their `company_id` in the manager's allowed companies (`res_users.company_ids`). ### Current behavior before this PR Context: a 8-companies environment where the `hr.employee` of each hierarchy chains are splitted in many different companies, like: - top-level (admin board): 1 company - middle management: approx. 2 companies - down level: the other companies The "down level" have `hr.employee` but no `res.users`. The "middle management" have `res.users` and must create the Expenses of their "down level" subordinates on their behalf. Issue: as a manager, as per Odoo proposal, I need to have a `hr.employee` in the same company of my subordinates to be able to create Expense of their behalf. However, this is very inconvenient because as a Manager, I can have employees in various companies. And my own manager it not in the same company than me, so the same issue applies recursively. ### Behavior after this PR is merged The domain of the field `expense_id.employee_id` is more permissive. As a Manager, it allows me to select the Employee I manage in my active company, no matter if I have or not myself a `hr.employee` in this company. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286293 Forward-Port-Of: odoo/odoo#266261
Accounting users in Chilean companies can now upload invoice XML files without needing administrator rights. This prevents failed XML processing and ensures invoices created from uploads include the required electronic document data.
Original PR description
Scenario: - be not an admin but have access to accounting - switch to chilean company - go to customer invoices - click on Upload and upload an XML file Result: an invoice is created, but the XML is not treated because of this permission error: 19.0/l10n_cl_edi/…/account_move.py", line 1078, in _l10n_cl_import_dte invoice.l10n_cl_dte_file = file_data['attachment'] odoo.exceptions.AccessError: You do not have enough rights to access the field "l10n_cl_dte_file" on Journal Entry (account.move). Please contact your system administrator Cause: l10n_cl_dte_file field is only accessible to administrator. opw-6509550 Forward-Port-Of: odoo/enterprise#130416
Malaysia payroll calculations now use the correct SOCSO and Employment Insurance contribution rules, preventing employee SOCSO amounts from being counted twice. This ensures payslips show a more accurate net salary and clearer employer contribution lines.
Original PR description
There was a difference between the actual and expected NET. **Causes** - rules existed for both SOCSO Act 800 and EIS, but Act 800 seems to be the official name of the Employment Insurance System…
There was a difference between the actual and expected NET. **Causes** - rules existed for both SOCSO Act 800 and EIS, but Act 800 seems to be the official name of the Employment Insurance System (source: https://www.perkeso.gov.my/images/dokumen/Rate_of_Contribution_ACT_800.pdf). Keep the ACT 800 one as its matches the expected amount. - there was a double counting of the SOCSO employee contributions (4 and 800) , as `l10n_my_rule_socso_employee` (the sum of both) was added to the total deductions. **Change** Before: 3500/month wage results in a 3108 NET. <img width="1181" height="533" alt="before" src="https://github.com/user-attachments/assets/cdf4420f-e2cf-4dc7-9488-6bde3f1f9961" /> After: 3500/month wage results in a 3090.85 NET: - 6.90 SOCSO Act 800 Employee - 6.90 SOCSO Act 800 Employer - 17.25 SOCSO Act 4 Employee - 60.35 SOCSO Act 4 Employer Which seems consistent with online sources (https://payroll.my/) <img width="1181" height="425" alt="after" src="https://github.com/user-attachments/assets/7fb41186-dbb4-4d7a-ac9a-14fb56efc4bc" /> Other fix: while not affecting the calculation, 'SOCSO Employer Share' appeared as incorrect, the two rules SOCSO_800_EMPLR and SOCSO_4_EMPLR should have the same sign. opw-5976362 Forward-Port-Of: odoo/enterprise#129688 Forward-Port-Of: odoo/enterprise#118138
The expense settings now prevent users from selecting payment methods that do not match the relevant company setup. This helps avoid configuration mistakes that could lead to inconsistent expense payment handling.
Original PR description
Add domain to company_expense_allowed_payment_method_line_ids field to avoid selecting inconsistent data @Tecnativa TT64416 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287131
This fix prevents Odoo from turning the Pay on Site option back on when the website sale collection module is upgraded. Merchants who disabled this payment option will no longer risk customers selecting it at checkout unintentionally, avoiding unpaid orders caused by unexpected configuration changes.
Original PR description
Steps to reproduce: =================== 1. Go to the payment providers and set "Pay on Site" to disabled. 2. Go to Apps, clear the filter, look up "website_sale_collect" and upgrade it. This also…
Steps to reproduce:
===================
1. Go to the payment providers and set "Pay on Site" to disabled.
2. Go to Apps, clear the filter, look up "website_sale_collect" and upgrade it. This also happens on its own, as upgrading any custom module that depends on it upgrades it too.
3. Go back to the payment providers.
=> "Pay on Site" is enabled again, and published as well from 19.0 on. Customers are offered it at checkout and place orders that are never paid, without the merchant ever enabling anything.
Root cause:
===========
`data/payment_provider_data.xml` is loaded in update mode because it carries no `noupdate`, and it hardcodes the state of the provider:
<field name="state">enabled</field>
So every upgrade of the module writes that value back over whatever the merchant configured. Every other provider ships its data with `noupdate="1"` and leaves the state alone, this module is the exception.
The file has been loaded this way since the module was added:
- [1] created the module with an updatable provider record.
Fix:
====
Load the file with `noupdate="1"`. The record is still created, enabled, when the module is installed, it is simply not written again on later upgrades. The flag is read from the file rather than from the `ir.model.data` row, so databases where the provider already exists are covered on their next upgrade, no data migration needed.
[1]: 087c48c4ed2e
opw-6528110
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#286913Users on tablets and other touch devices can now resize list view columns without the action being interrupted by page scrolling. This makes list views easier to adjust and use on touchscreen devices.
Original PR description
Steps to reproduce ================== - Use a tablet (touch screen) - Open any list view - Try to resize a column by dragging the column header's right edge => The resize doesn't work properly: it gets interrupted an we can only move a few pixels at a time Cause of the issue ================== The resize handle relies on pointerdown/pointermove/pointerup to run and stop the drag, but nothing tells the browser to opt out of its native touch gestures. On a tablet, the drag can get hijacked as a page scroll, which fires pointercancel instead of pointerup. That event was not listened to, leaving the pointermove handler attached and the resize state stuck. Solution ======== - Set touch-action: none on the resize handle so a touch drag isn't interpreted as scrolling - Listen to pointercancel to properly stop the resize when the browser takes over the gesture anyway Forward-Port-Of: odoo/odoo#288046
Time off requests now keep the correct duration when an automation creates an approval activity at the same time. This prevents new leave requests from incorrectly showing 0 days or 0 hours, helping HR teams review and approve requests accurately.
Original PR description
Current behavior: -- With an active automation rule (base_automation) whose action creates an activity (e.g. a "Time Off Approval" activity) on hr.leave creation, every newly created time off request…
Current behavior: -- With an active automation rule (base_automation) whose action creates an activity (e.g. a "Time Off Approval" activity) on hr.leave creation, every newly created time off request has a duration of 0 days / 0 hours, regardless of the requested dates. Expected behavior: -- The leave duration is computed from the requested dates, unaffected by the presence of an activity-creating automation rule. Steps to reproduce: -- - Create an automation rule on hr.leave, trigger "On Creation & Update". - Add an action that creates an activity (type "Time Off Approval"). - Create any time off request for an employee with a working schedule. - The request shows a duration of "0 days" (or "0 hours"). Cause of the issue: -- When an automation with a "Create Activity" action runs on leave creation, base_automation schedules the activity after the record is created. Creating the activity reads the leave record, forcing an early flush of its pending computes. At that point date_from/date_to are not yet settled, so the duration compute (number_of_days/number_of_hours) reads empty dates and stores (0, 0). As these are stored fields, they are marked done and never recompute. Fix: -- In create(), after the record is created and its dates are settled, recompute the duration explicitly so any zero stored by an early flush is overwritten with the correct value. opw-6235902 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286749 Forward-Port-Of: odoo/odoo#284373
Odoo now correctly carries the payment reference from imported CII XML invoices onto the generated vendor bill. This helps accounting teams keep vendor bills complete and avoids manual re-entry or follow-up when processing electronic invoices.
Original PR description
### Issue before this commit: When importing a CII XML invoice containing a PaymentReference, the value is not transferred to the generated vendor bill in Odoo. ### Steps to reproduce the issue: 1. Download Accounting 2. Try to import the invoice in the ticket 3. See that in the tab other info the payment reference is not imported ### Cause of the issue: During a previous refactoring (ffbdf29a816d0ff4136488d26b55b9707fc37fc6), the helper function responsible for extracting the payment reference during the import process was omitted. ### Reason to introduce the fix: Add the missing extraction logic to ensure the payment reference is correctly retrieved from the XML and assigned to the Odoo invoice. opw-6530627 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287216
This fixes an issue where multi-day time off for fully flexible employees was shown as only one day. Leave requests now reflect the actual number of calendar days, excluding public holidays when applicable, helping HR and employees see accurate balances and approvals.
Original PR description
Steps to reproduce: ------------------------------------ 1. Install Time off module 2. Create New Fully Flexible Employee 3. Click on the Time off smart button 4. Create time off for multiple days…
Steps to reproduce: ------------------------------------ 1. Install Time off module 2. Create New Fully Flexible Employee 3. Click on the Time off smart button 4. Create time off for multiple days (eg. Mon - Friday) Observation: ------------------------------------ Number of days still shows 1 Days. Issue: ------------------------------------ Issue occurs because `work_time_per_day_mapped` returns one interval per day for standard and flexible schedules in multi-day time off requests, so the interval count correctly matches the number of leave days. https://github.com/odoo/odoo/blob/d73e5662a0af7c549008661f743ba5d51f765339/addons/hr_holidays/models/hr_leave.py#L460-L461 However, for fully flexible schedules, it returns a single interval containing the total hours across all days, causing the leave duration to always be computed as 1 day regardless of the actual number of days requested. Solution: ------------------------------------ For fully flexible employees, count the actual calendar days and subtract public holidays when applicable. opw-6060552 Forward-Port-Of: odoo/odoo#255826
FedEx shipping labels in ZPLII format now download with a standard .zpl file extension instead of being saved as .txt files by the browser. This prevents confusion and helps users send the label directly to compatible label printers without renaming the file.
Original PR description
TL;DR When downloading a `.zplii` shipping label from the chatter on a Delivery Order (using FedEx), the browser automatically adds .txt to the end of the filename, saving it as `.zplii.txt` Step to…
TL;DR
When downloading a `.zplii` shipping label from the chatter on a Delivery Order
(using FedEx), the browser automatically adds .txt to the end of the filename,
saving it as `.zplii.txt`
Step to reproduce:
- install `delivery_fedex_rest` with demo
- open shipping method menu -> Fedex Us -> label format = `zplii` -> save
- create a SO, click on 'Add Shipping",
- select fedex as shipping method -> get rate -> add -> confirm SO
- go to delivery and validate
- notice, in thread, a attachment with ZPLII extension appears
- download (.txt is appended to file)
Issue:
- `fedex_rest_send_shipping` post message with documents with extension as
`fedex_rest_label_file_type` i.e. `ZPLII`
https://github.com/odoo/enterprise/blob/735490d7ba9bdc6d0df7a0bd07c0d4e36d1ed2d4/delivery_fedex_rest/models/delivery_fedex.py#L193-L195
- when the attachment is created for this document , it's mimetype is computed
to be `text/plain` from [guess_mimetype](https://github.com/odoo/odoo/blob/5de4a5f6caee09881e7e147062f9eab9f8916a61/odoo/tools/mimetypes.py#L192) method, as data is plain ASCII code
- moreover, when downloading, [_get_stream_from](https://github.com/odoo/odoo/blob/5de4a5f6caee09881e7e147062f9eab9f8916a61/odoo/addons/base/models/ir_binary.py#L89) tries to guess extension
using [get_extension](https://github.com/odoo/odoo/blob/5de4a5f6caee09881e7e147062f9eab9f8916a61/odoo/tools/mimetypes.py#L210) which return `None` as len('zplii') > 4, [see](https://github.com/odoo/odoo/blob/5de4a5f6caee09881e7e147062f9eab9f8916a61/odoo/tools/mimetypes.py#L221)
- finally, as we got `None`, and mimetype is `text/plain`, `.txt` is appended [here](https://github.com/odoo/odoo/blob/5de4a5f6caee09881e7e147062f9eab9f8916a61/odoo/addons/base/models/ir_binary.py#L149)
Fix:
- we use `zpl` as extension for file instead of `zplii` as there is not
difference between them from printing perspective
- as length of 'zpl' is <=4 , `get_extension` will considered it as valid
opw-6410968
Forward-Port-Of: odoo/enterprise#126620The Point of Sale now ignores deleted coupon records when showing customer loyalty information. This prevents the customer list from crashing after a cashier removes a coupon reward, keeping checkout workflows smooth.
Original PR description
Steps to reproduce: - A coupon program with a coupon assigned to a customer - In the PoS, set that customer on the order - Enter the coupon code, its reward line is added - Remove the reward line -…
Steps to reproduce: - A coupon program with a coupon assigned to a customer - In the PoS, set that customer on the order - Enter the coupon code, its reward line is added - Remove the reward line - Click the customer button Issue: The customer list does not open. The PoS crashes with "TypeError: Cannot read properties of undefined (reading 'id')" raised while rendering PartnerLine. Cause: `partnerId2CouponIds` maps a partner to the ids of its `loyalty.card` records. It is filled at boot and on every `loyalty.card` create, but nothing ever removes an id from it: the models only trigger a create event. Removing the reward line of a code activated coupon deletes that card from the local models (`_setValue` in the order summary), so its id stays in the map while the record is gone. `getLoyaltyCards` pushed `models["loyalty.card"].get(id)` unconditionally, hence an `undefined` entry in the list the PartnerLine template iterates over with `t-key="_loyaltyCard.id"`. Fix: Skip the ids whose record no longer exists. The partner keeps its remaining cards, and the path where no card was deleted is unchanged. The stale id is not pruned from the map: it is reached through the reactive store proxy, and mutating it there would notify subscribers in the middle of a render. opw-6517564 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287503 Forward-Port-Of: odoo/odoo#286971