Wednesday, January 7, 2026
12 changes · 18.0
Resolved issues and error corrections
This update ensures the Verifactu QR code is consistently included on order reprints for Spanish retail transactions. Previously, the QR code was missing after the initial order settlement but reappeared when reprinting. This fix guarantees compliance with local regulations and provides accurate receipts for customers.
Original PR description
Step to reproduce: - install `l10n_es_edi_verifactu_pos` - start pos after switching company for `es` - settle order, notice verifactu QR code is present in receipt - from orders menu, reprint the receipt Observation: - when we reprint the order, qr code is missing Cause: - `l10n_es_edi_verifactu_qr_code` is not always present in order - it is added later in `_postPushOrderResolve` hook (hence first time, qr code is present) - when reprinting the invoice, this method is not called, so it is not printed Fix: - patch `ReprintReceiptButton` to always fetch `l10n_es_edi_verifactu_qr_code` - so data is always present before printing opw-5403886 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#240359
This update fixes issues with QR code generation in the Point of Sale (POS) system, specifically related to invoice reprints and journal onboarding. It ensures that QR codes appear correctly on reprinted invoices when errors occur with ZATCA invoicing, and that POS receipts display the appropriate QR code based on invoicing settings.
Original PR description
Ensure proper handling of QR code generation and POS EDI behavior by fixing multiple issues across invoice reprints and journal onboarding. QR codes now correctly appear on reprinted invoices when…
Ensure proper handling of QR code generation and POS EDI behavior by fixing multiple issues across invoice reprints and journal onboarding. QR codes now correctly appear on reprinted invoices when journal problems occur during order confirmation. POS correctly falls back to the Phase 1 flow when the journal is not onboarded and electronic invoicing is not enabled. Additionally, POS receipts now display the proper Phase 1 QR code whenever the EDI module is installed. Problem 1: If ZATCA does not properly receive the invoice generated from a POS order (wrong onboarding, wrong details on company, etc.) the invoice printed from POS will not contain the QR code, even after successfully resubmitting the invoice to ZATCA, load the order and reprint the invoice to see this Testing the fix: Change the VAT number on the company to be faulty, create a POS order, Fix the VAT number and resubmit the invoice, load the POS order and reprint invoice, it will now show the QR code. Problem 2: When disabling the E-invoicing for a phase 2 journal, the POS receipt will still try to print the phase 2 QR code but the system will flag it as 'not legal' leaving the POS receipt empty, when it should instead print the phase 1 QR code Testing the fix: On the journal, disable the E-invoicing, and create a POS order, it will now show the phase 1 QR code on the receipt task-5032474 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves an issue where credit notes with allowances issued more than 6 days after the original invoice would fail to process through ECpay. The fix removes the outdated 'AllowanceDate' parameter and ensures 'InvoiceRemark' is only populated when a customer reference is provided, improving compatibility with ECpay's requirements.
Original PR description
**AllowanceDate**: l10n_tw_edi_ecpay has an issue on Credit Notes (Allowances). When we `_l10n_tw_edi_generate_issue_allowance_json()`, we send the `l10n_tw_edi_invoice_create_date` which is was set…
**AllowanceDate**:
l10n_tw_edi_ecpay has an issue on Credit Notes (Allowances).
When we `_l10n_tw_edi_generate_issue_allowance_json()`, we send the
`l10n_tw_edi_invoice_create_date` which is was set to the associated
invoices creation date, and not the Allowance's creation date.
This creates a potential issue where allowances issued more than 6 days
after the original invoice would bounce back from ECpay with errors.
To be consistent with invoices send to ECPay, we do not send the
`AllowanceDate` parameter at all
Manual Testing/Verification:
1. Create an invoice that has a `l10n_tw_edi_invoice_create_date`,
visible in the Invoice's ECPay tab more than 6 days ago. (Requires
sending to ECPay via the custom wizard via the "Send" button)
2. Create a credit note from the invoice and send to ECPay.
3a. Before this, see that an error would appear.
3b. Now, there would be no error
*InvoiceRemark*:
When Customer Reference `ref` is not set, the code sets the parameter
value as `False`, displaying it's string on the e-invoice and official
printout. We only set the parameter if there exists the `ref` now,
eliminating the issue.
Tests:
1. (both cases) undo the `account_move.py` changes and run the tests.
task-[5455847](https://www.odoo.com/odoo/project/967/tasks/5455847)
---
# New test failed output
<img width="1458" height="353" alt="image" src="https://github.com/user-attachments/assets/77df8e51-5005-4d99-985c-71757c0f62a6" />
```bash
07:47:53,055 ERROR l10n_tw_edi_ecpay-demo-vy2vd3s0 odoo.addons.l10n_tw_edi_ecpay.tests.test_edi: FAIL: L10nTWITestEdi.test_01_can_generate_file
Traceback (most recent call last):
File "/home/odoo/odev/worktrees/18.0-l10n_tw_edi_ecpay-fix-allowance-date-erle/odoo/addons/l10n_tw_edi_ecpay/tests/test_edi.py", line 61, in test_01_can_generate_file
self.assertIsInstance(json_data["InvoiceRemark"], str)
~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: False is not an instance of <class 'str'>
07:48:02,516 ERROR l10n_tw_edi_ecpay-demo-vy2vd3s0 odoo.addons.l10n_tw_edi_ecpay.tests.test_edi: FAIL: L10nTWITestEdi.test_13_b2b_refund_upload_deadline_restriction
Traceback (most recent call last):
File "/home/odoo/odev/virtualenvs/18.0/lib/python3.13/site-packages/freezegun/api.py", line 885, in wrapper
result = func(*args, **kwargs)
File "/home/odoo/odev/worktrees/18.0-l10n_tw_edi_ecpay-fix-allowance-date-erle/odoo/addons/l10n_tw_edi_ecpay/tests/test_edi.py", line 430, in test_13_b2b_refund_upload_deadline_restriction
self.assertNotIn("AllowanceDate", json_data,
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
"B2B Allowances should not include AllowanceDate to avoid >6 day limit errors."
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
AssertionError: 'AllowanceDate' unexpectedly found in {'MerchantID': '1234', 'Details': [{'OriginalInvoiceNumber': 'AB11100099', 'OriginalInvoiceDate': '2025-01-06', 'OriginalSequenceNumber': 0, 'ItemName':
'product_a', 'ItemCount': 1.0, 'ItemPrice': 1000.0, 'ItemAmount': 1000.0}], 'TotalAmount': 1000.0, 'TaxAmount': 50.0, 'CustomerEmail': 'partner_b@tsointsoin', 'AllowanceDate': '2025-01-06 15:00:00'} : B2B
Allowances should not include AllowanceDate to avoid >6 day limit errors.
```
---
Things to think about:
- FWP
- [ ] 19.0
- [ ] masterThis update ensures that inventory tracking changes are correctly enforced when a product's type is altered, preventing potential stock discrepancies. Previously, a change in product type could be saved without triggering the necessary checks, leading to incorrect inventory calculations. This fix restores the expected behavior of raising an error when attempting to change a product's type after it has been used in stock movements.
Original PR description
## Description of the issue/feature this PR addresses: `compute_is_storable` is called when the `type` value is modified but the `write` function is never called when the value is set using the…
## Description of the issue/feature this PR addresses: `compute_is_storable` is called when the `type` value is modified but the `write` function is never called when the value is set using the `is_storable` attribute. Updating `is_storable` using a `write` ensure that an exception is raised when move line exists. But this fix addresses the symptom, not the underlying issue. So why ? Is it related to the cache or unit test environment ? ## Current behavior before PR: In a Unit test, If you convert a consumable and storable product to a service, no exception is raised, even with existing stock moves. Unlike the previous version of Odoo (<15.0), where an exception was raised when the product type was changed and stock movements existed, detection now occurs if the ‘is_storable’ status is changed. However, this detection is not triggered if the value of ‘is_storable’ is defined by its attribute. ## Desired behavior after PR is merged: An exception must be raised (like Odoo 14.0) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves an issue where order completion with UrbanPiper resulted in an 'undefined street' error. The fix ensures the system correctly checks if a customer is assigned before completing the order, preventing this error and allowing users to successfully mark orders as ready and print receipts after removing the customer.
Original PR description
Steps to produce: ==== - Place an online delivery order through urbanpiper - Edit the order and remove customer - Complete the order as Marks as Ready - Print Reciept Issue: ==== - TB occurs stating undefined street Fix: ==== - Check whether partner is assigned or not task-5407001
This update ensures that loyalty promotions are consistently visible across multiple POS devices connected to the same restaurant. Previously, a promotion wouldn't appear when a second user accessed a table with an existing order. The fix corrects a synchronization issue to ensure all promotions are displayed accurately.
Original PR description
When two users were connected to the same POS Restaurant, if one of them created an order on a table with a ‘Buy X, Get Y’ promotion, that promotion was not visible on the first opening of that table by the other user. Steps to reproduce: ------------------- * Configure a “buy X get Y” program * Open two pos-session on the same bar/restaurant In the first session: * Create on order that triggers the program * Go back to floor screen In the second session: * Open the table with the order > Observation: Only the products are in the order without the promo Why the fix: ------------ pos_restaurant_loyalty: Move updateRewards() back before super.setTable(...). Calling it afterward could remove rewards because the synced order wasn't fully loaded yet. pos_loyalty: Prevent _postProcessLoyalty from crashing when a synced reward line still lacks a coupon. We simply skip those lines until the coupon is available. opw-5185559
This update fixes a bug where Odoo created duplicate calendar events when syncing Google and Microsoft Outlook accounts. The issue stemmed from a missing link between calendar events, now resolved by storing a universal event ID to ensure accurate synchronization and prevent endless duplication.
Original PR description
When users sync the same calendar meeting from both Google Calendar and Microsoft Outlook, Odoo creates duplicate events that multiply with each sync cycle. ### Reproduction steps 1. User A connects…
When users sync the same calendar meeting from both Google Calendar and Microsoft Outlook, Odoo creates duplicate events that multiply with each sync cycle. ### Reproduction steps 1. User A connects their Google Calendar account to Odoo 2. User B connects their Microsoft Outlook account to Odoo 3. User A creates a meeting in Google Calendar and invites User B 4. User A syncs Google Calendar - the event is created in Odoo 5. User B syncs Microsoft Outlook - a duplicate event is created in Odoo instead of linking to the existing one 6. Continue syncing both accounts periodically 7. Observe: duplicates multiply with each sync cycle, flooding both calendars vents appear and multiply in both calendars ### Root cause When a calendar event is created in Google Calendar or Microsoft Outlook, each service assigns it two identifiers: a service-specific ID (google_id or microsoft_id) and a universa identifier called iCalUID. The iCalUID is part of the iCalendar standard and remains constant across different calendar systems for the same event. When User A syncs from Google Calendar, the google_calendar module retrieves the event including both the Google-specific ID and the iCalUID. However, the module only stores the google_id in Odoo's database. The iCalUID is received but never persisted to any field. When User B syncs from Microsoft Outlook, the microsoft_calendar module retrieves the same meeting and stores both microsoft_id and ms_universal_event_id (containing the iCalUID). When searching for existing events, it queries for records matching either field. Since the Google-synced event has neither field populated, the search finds nothing and creates a second calendar.event record. On the next Google sync, the google_calendar module sees the Microsoft-created event (which has no google_id) and interprets it as a new Odoo event requiring upload to Google. It creates a new event in Google Calendar, causing User A to see a duplicate. Subsequent Microsoft syncs propagate the duplicate back to Outlook. This cycle repeats indefinitely: eac module treats events from the other system as new, creating exponentially growing duplicates with every sync operation. The fundamental problem is that google_calendar never stores the iCalUID, breaking the universal matching mechanism the iCalendar standard provides. ### Fix rationale A new bridge module, `google_microsoft_calendar`, is introduced to ensure the `iCalUID` acts as the definitive link between the two services. First, the module intercepts the Google synchronization process to persist the `iCalUID`. When an event arrives from Google, its `iCalUID` is now explicitly saved into the `ms_universal_event_id` field on the Odoo record. This ensures that events originating from Google are recognized by the Microsoft module during its sync. Second, the Google synchronization logic is enhanced to perform a lookup by this universal ID. Before creating a new event, the system checks if an existing record already has the matching `ms_universal_event_id`. If a match is found (indicating the event was already created by Outlook), the system links the incoming Google ID to that existing record. This ensures that regardless of which provider syncs first, Odoo recognizes the event as the same entity, preventing the creation of duplicates and breaking the synchronization loop. opw-5045720
This update corrects a bug where putting items into a package from the SML view resulted in the package being incorrectly located. The fix addresses an issue where the system incorrectly used the SML's default location when creating the new package, preventing it from being found. This ensures accurate package tracking within the stock management system.
Original PR description
Putting in pack from the SML view leads to package incorrectly located To reproduce the issue: 1. In Settings, enable "Package" 2. Confirm a delivery with 2 available products 3. Open the SML thanks…
Putting in pack from the SML view leads to package incorrectly located To reproduce the issue: 1. In Settings, enable "Package" 2. Confirm a delivery with 2 available products 3. Open the SML thanks to the smart button 4. Tick a line > Put in pack 5. On the second line, in "Destination Package", look for the package Error: it is impossible to find it When opening the SML thanks to the smart button, we also load a lot of default values: https://github.com/odoo/odoo/blob/1492abd8c6bcfdbc48f730f6767b177aeff54bf7/addons/stock/models/stock_picking.py#L1203-L1221 Those are (obviously) SML specific. However, this context is used when putting in pack. This is a problem since `location_id` is also the field name of a package. As a result, the ORM defines the location of the new package with the default value, i.e. the source location of the SML. This is incorrect. One consequence of this bug is the step 5 of the above use case. When looking for a package, a domain checks its location: https://github.com/odoo/odoo/blob/35feed47622b279abf8e593d8190ea36b64d32fd/addons/stock/models/stock_move_line.py#L51-L55 It must be either `False` or equal to the dest loc, which is not the case with the created package. Now... About the solution. It's probably difficult to do something more hacky. However, it's not too invasive in the code and all user will take benefit from it once the commit is deployed. On master, we will discuss with both frameworks to negotiate/find something more elegant. OPW-5215243
This update fixes a potential issue where expired or fully-signed job offers could be accessed and incorrectly re-signed. The system now prevents access to these offers, ensuring data integrity and a smoother applicant experience. An SQL constraint has also been added to prevent invalid validity dates.
Original PR description
This commit improves the offer validation logic to avoid invalid or unintended signature attempts. Fixes included: - Block access to offers that are already fully signed, preventing applicants from reopening the link and unintentionally reverting the offer to a partially signed state. - Add an SQL constraint on the `validity` field to disallow negative values, ensuring that expired/invalid offers cannot be accessed due to incorrect validity data. These changes ensure that expired or fully processed offers no longer expose active signature links and that offer validity is consistently enforced at the database level. task-5405456 Forward-Port-Of: odoo/enterprise#101834
A technical issue was causing an error when processing large SEPA credit transfers. This update corrects a misinterpretation of the maximum payment amount, ensuring payments up to €9,999,999.99 are processed correctly. This resolves a potential disruption to financial transactions.
Original PR description
**Steps to reproduce:** - Create a vendor payment with the amount 88888888.88 in euros - Set the payment method to SEPA Credit Transfer - Create a vendor batch paymentand set its payment method to SEPA Credit Transfer - Add the created payment to the batch payment - Validate the batch payment **Issue:** An error message pops up, indicating that the payment amount exceeds the maximum amount 99999999.99 for payments in Euros. This not the case since 88888888.88 < 99999999.99 **Solution:** Make sure the number of digits in the payment amount is strictly greater than the max digits instead of greater than or equal opw-5428415 Forward-Port-Of: odoo/enterprise#103349
This update fixes an issue where invoices could incorrectly retain accounts from their original company after changing the invoice's company and journal. The fix ensures that invoices accurately reflect the correct company and account when switching company branches. This prevents posting errors and maintains financial accuracy.
Original PR description
This issue was already fixed in this PR: https://github.com/odoo/odoo/pull/234357 But that was revert because there was a bug with company branches ### Steps to reproduce: - Create Company A and Company B - Create an invoice on Company A with one line having an account in Company A - On the same invoice, change the company to Company B and change the journal to a journal of Company B - Save, then confirm the invoice. ### Issue: The invoice, now belonging to Company B, still has the same account from company A, and we are able to post it on the journal from company B opw-5167958
This pull request addresses visual issues in the website editor, specifically preventing blurry countdown canvases and text overlap with icons. The changes ensure a sharper, more reliable experience for users when editing website content, particularly with countdown timers and image snippets.
Original PR description
## [FIX] website: prevent blurry countdown canvas and text on zoom [Commit 1] Steps to reproduce: - Go to Website -> Edit Mode - Add a Countdown snippet (size: "Small") - Save and zoom in/out, the countdown canvas and text appears blurry The countdown was rendered at a low resolution, which caused it to blur when zooming. This fix updates the canvas to draw at the proper resolution so the countdown remains sharp at any zoom level. ## [FIX] web_editor: prevent text overlap with icon [Commit 2] Steps to reproduce: - Go to Website -> Edit Mode - Add a Image snippet - Enter a long text in search bar: Issue: 1. Text overlaps with search icon. 2. Selecting the "Photos (via Unsplash)" option causes the text to overlap the dropdown icon. The fix adjusts the end padding to provide sufficient spacing between the text and the icons. task-[4771268](https://www.odoo.com/odoo/project/974/tasks/4771268) Forward-Port-Of: odoo/odoo#213373