Monday, December 22, 2025
7 changes · saas-18.3
New functionality added to Odoo
This update adds support for Guatemalan tax regulations, specifically related to Factura Especial (FESP) transactions. It includes new accounts and tax groups to handle withholding taxes for VAT and ISR, ensuring compliance with local legal requirements. This change is crucial for businesses operating in Guatemala.
Original PR description
**PURPOSE** - In Guatemala, a Factura Especial (FESP) is a legal mechanism established in Art. 52 of the VAT Law. - To achieve this functionality, we need to create withholding taxes. **SPECIFICATION** - Added new accounts for VAT and ISR withholdings. - Added new tax groups for VAT and ISR. - Added new taxes with negative values in withholding. task-5026698 see - https://github.com/odoo/enterprise/pull/96007 Forward-Port-Of: odoo/odoo#229493
This update adds support for a special Guatemalan invoice type (FESP) required by local regulations. It allows businesses to record purchases without supplier invoices, correctly calculating and tracking withholdings (VAT and ISR) for accurate accounting and reporting to the SAT. This ensures compliance with Guatemalan tax laws.
Original PR description
### PURPOSE - In Guatemala, a Factura Especial (FESP) is a legal mechanism established in Art. 52 of the VAT Law. - Generate Factura Especial (FESP) when registering a purchase without a supplier…
### PURPOSE - In Guatemala, a Factura Especial (FESP) is a legal mechanism established in Art. 52 of the VAT Law. - Generate Factura Especial (FESP) when registering a purchase without a supplier invoice. - Include all required data: supplier as receiver, transaction details, and the retention complement (100% VAT + ISR withholding). - Ensure proper accounting: supplier payable = net after retentions, taxes withheld = recorded as liabilities to be paid to SAT. - Fulfill FEL technical requirements (DTE XML, mandatory phrase, retention complement, see example attached). ### SPECIFICATION - Added flow for FESP (Factura Especial) document type in vendor bills. - Automatically added Phrase Type 5, Scenario 1 (as required by SAT). - Enforced mandatory data by raising UserError if FESP is selected but no withholding taxes are set on the product lines. - Added complement generation for withheld taxes (IVA, ISR) with base, rate, and amounts. - Allow users to send a document to SAT in case of FESP. - Added required details in FEL XML for FESP. task-5026698 see - https://github.com/odoo/odoo/pull/229493 Forward-Port-Of: odoo/enterprise#96007
Enhancements to existing features
This update enhances the self-ordering QR codes by displaying the table number directly within the QR code image. This makes it much easier for staff to quickly identify which table a customer's order belongs to, improving order accuracy and efficiency. This change addresses a previous difficulty in recognizing QR codes.
Original PR description
Before this commit: ====================== It was difficult to identify which table a QR code belonged to when viewing the generated QR code PDFs. After this commit: ====================== The table number is now displayed between the Odoo logo in each table’s QR code, making it easier to recognize and differentiate table QR codes. Task-5217734
Resolved issues and error corrections
This update resolves an issue where deleting a shopfloor instruction suggestion caused errors in the system. The fix ensures that adding a new suggestion after deleting one works smoothly, preventing a traceback. This improves the reliability of the shopfloor instruction suggestion process, allowing users to efficiently manage and update work orders.
Original PR description
**BUG:** Traceback when **suggesting** deleting a BOM step from the shopfoor. **STEPS TO REPRODUCE:** - Open a shopfloor MO (with PLM installed) -- Add a suggestion step (MO > cog> Update…
**BUG:** Traceback when **suggesting** deleting a BOM step from the shopfoor. **STEPS TO REPRODUCE:** - Open a shopfloor MO (with PLM installed) -- Add a suggestion step (MO > cog> Update instructions > Improvement Suggestion > Add a step). -- Add a second suggestion step after the first one. -- Delete the second suggestion step (MO > cog> Update instructions > Improvement Suggestion > Delete a step). -- Add a third suggest suggestion step after the second one we just suggested deleting. -- > Traceback **ORIGIN:** First, when adding the suggestions: - 2 Quality Check (QC) are created on the **new_bom_id** in `add_quality_check_from_tablet.save()` - 2 Quality Point (QP) are also created in `add_check_in_chain()`, (only in mrp_workorder_plm override) - The 2nd new QC is linked to previous QC in `_insert_in_chain` Secondly, when deleting the 2nd added suggestion (_on the same MO, as suggestions are linked to the new bom_id and wont appear on other MOs until ECO is validated_): - The QP of the second QC is deleted (but the QC itself is not deleted) here: https://github.com/odoo/enterprise/blob/f91b0c8c41f40a71cbea3cd4f5ccc6873af3c004/mrp_workorder_plm/wizard/propose_change.py#L72-L74 Finally, when adding a new suggestion after the one we just suggested deleting, in `_add_check_in_chain`, a traceback happens by trying to access the QP point we deleted in the resequencing part of `_add_check_in_chain` here: https://github.com/odoo/enterprise/blob/eb716c18944ec50c9c8c74a2888ed5f3032a7b08/mrp_workorder_plm/models/mrp_workorder.py#L62-L63 **FIX:** We accept that not all QCs must have QPs `[0]` -> `[:1]` (see note on another approach idea) changing ```diff - point = check.point_id if check.point_id.operation_id == operation else points.filtered(lambda p: p._get_sync_values() == check.point_id._get_sync_values())[0] + point = check.point_id if check.point_id.operation_id == operation else points.filtered(lambda p: p._get_sync_values() == check.point_id._get_sync_values())[:1] ``` **NOTES:** -1 Another fix could have been to delete the QC at the same time as the QP but I did not find any `remove_from_chain` function to safely remove the QC from the chain of QC. Along those lines we could rethink the sequencing / resequencing of QC and QP as the logic seems to differ between both. -2 Added some comments to remove the field and the line setting the `is_deleted` field in master as it was not used anywhere in the code (the color highlighting in the ECO is done with `<list decoration-danger="change_type=='remove'" ...>`) ticket #5180122 Forward-Port-Of: odoo/enterprise#101366
This update resolves an issue where portal users couldn't update lead data after a recent security change. The team implemented a temporary workaround using 'sudo()' to grant necessary write access, ensuring portal users can now modify lead information as intended. This maintains seamless data synchronization between the portal and the CRM.
Original PR description
## Steps to reproduce: - Install 'website_crm_partner_assign' module. - Create a partner X with a partner level. - Save and go to "Opportunities". - Create an new opportunity. - Edit it and set the…
## Steps to reproduce: - Install 'website_crm_partner_assign' module. - Create a partner X with a partner level. - Save and go to "Opportunities". - Create an new opportunity. - Edit it and set the partner X as the assigned partner - Grant the partner x portal access and change his password. - Logout then login with the partner X credentials. - Go to "My account" page and click on "Opportunities" - Select the opportunity Y and edit the revenue or another field. - Traceback on save. (Or no reaction, popup traceback from notification) ### Issue: Since the commit ed94e84, we've removed the write access for portal partner users to the leads to avoid unexpected behaviors. However, this is provoking `update_lead_portal` to not be able to update the lead anymore, since we will not have direct access to modify the lead. ### Solution: To fix this, we will follow same approach as in `update_contact_details_from_portal` and use `sudo()` to update the lead from the portal. We are already checking the portal access at the beginning of the method as `self._assert_portal_write_access()`, so we are sure that only authorized users will be able to update the lead. opw-2764563 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#237599
This update corrects a previous issue where manually entered serial numbers in the barcode app were automatically assigned to the current company. This prevented the use of these serial numbers across different companies. The fix removes this automatic assignment, allowing serial numbers to be used regardless of the company, aligning with current Odoo functionality.
Original PR description
## Context In the barcode app (`stock_barcode`), users can update inventory counts by scanning a product's barcode or by manually entering the barcode. ## Issue When the barcode is entered manually,…
## Context In the barcode app (`stock_barcode`), users can update inventory counts by scanning a product's barcode or by manually entering the barcode. ## Issue When the barcode is entered manually, the lot/serial number is created with the *Company* field set to the current company. This causes issues when working with intercompany flows, because lots with a company assigned cannot be used by other companies. This behavior is also inconsistent with the other ways of updating a company's inventory. In fact, the following flows create serial/lot numbers with no company assigned: - Inventory / Products / Products / *Forecasted Report* or *On Hand* - Inventory / Operations / Adjustments / Physical Inventory - Barcode / Inventory Count / Add product (add the serial number from the *Inventory Count* screen, **not** by clicking on the cogwheel in the top-right corner) ## Cause The line assigning a `company_id` was added by https://github.com/odoo/enterprise/commit/c0151bce3c60c69e7cadeb719a81c4a702b71c34. At the time, that behavior was consistent with the backend behavior, as the `company_id` of a lot/serial number would always be set to `self.env.company`. In fact, the feature allowing a lot/serial to be shared among multiple companies was introduced later, in saas-17.2 (https://github.com/odoo/odoo/commit/99b39b72c7e65e85af6f06dcb6b02867623f3f69). This last commit adds a compute method for the `stock.lot.company_id` field: https://github.com/odoo/odoo/blob/6026866900fd0ac1bf6495ae249cd08f56c85342/addons/stock/models/stock_lot.py#L130-L136 Since then, lot/serial numbers shouldn't be created with a `company_id`, as this restrict other companies to use those numbers. Users can always add a company to a lot/serial number later if necessary. ## Solution The line assigning a `company_id` to the `stock.lot` can be removed, as it does not reflect the current behavior (saas-17.2+). Nowadays, a `company_id` should be set **only** if the user wants a lot/serial number to be used by a specific company; it should not be the default behavior. ## Steps to reproduce 1. Install *Barcode* (`stock_barcode`). 2. In Inventory / Configuration / Settings, enable *Lots & Serial Numbers*. 3. In Settings / Users & Companies / Companies, create a second company. Use either company for the following steps. 4. Create a product tracked *By Unique Serial Number*. 5. Open the Barcode app, then click *Inventory Count*. 6. Scan your product (or add it manually, but **do not** set the *Serial/Lot Number*). 7. Scan "SN001" (or add it manually through the cogwheel menu), then click *Apply*. 8. Go to Inventory / Products / Lots / Serial Numbers. 9. The serial number created from the Barcode app is assigned to the current company. opw-5264216 Forward-Port-Of: odoo/enterprise#102130
This update resolves a bug where the cursor jumps to the end of the input after using the backspace button on the mobile VoIP softphone. The issue stemmed from an outdated configuration within the keypad's input handling, now corrected to ensure proper cursor positioning. This improves the user experience for mobile VoIP calls.
Original PR description
Steps to reproduce: - Open the VoIP softphone on a mobile device - Enter a number - Place the cursor in the middle of the number - Tap on the *odoo* backspace button => The character before the…
Steps to reproduce:
- Open the VoIP softphone on a mobile device
- Enter a number
- Place the cursor in the middle of the number
- Tap on the *odoo* backspace button
=> The character before the cursor is removed but then the cursor jumps
to the end of the input.
Note: this also happens when trying to add a number in the middle of
the typed number, using the softphone buttons, but this message focuses
the explanation on the backspace button.
Commit [1] introduced the bug while revamping VoIP and its keypad.
Before that commit, there was a simple `t-on-click` defined on that
backspace button. After the update, that `t-on-click` is still there but
alongside a weird `t-on-touchend.prevent="(ev) => ev.target.click()"`,
which is actually there to prevent zoom-in behavior on double-tap,
although, retesting it does not seem necessary (at least on Android).
In any case, this is the original cause of the bug.
Since [2], the keypad input is using the mail's `useSelection` hook,
which, among other things, manages what happens on click outside of the
input. Before [1], this happened when clicking on the backspace button:
1. The click is handled during its *capture* phase by the `useSelection`
hook. It checks if clicked location should be considered, the answer
is yes.
2. The next part of the handler is done in the next microtask (as the
check is done asynchronously (?? that looks like a bad idea, but
that's another issue)).
3. That "in the next microtask" part occurs before the event starts
bubbling: the capture handler saves the cursor position as being at
the end of the input (?? not sure why, but that's another issue).
4. The click is handled during its *bubbling* phase by the backspace
button's `t-on-click`, which removes the character before the cursor,
and sets the cursor position accordingly for the `useSelection` hook.
The actual cursor position is untouched since [3] on mobile "because
otherwise it would open the mobile keyboard", but there are other
ways that would have prevented that I think... to confirm later for
master via task-5366961 (this actually causes issues in HOOT tests
but that's another issue).
5. The dialer/numpad component handles the input's focus/cursor. For
that, it forces a focus and ask the `useSelection` hook to "restore
the selection", which "restores" it to what step (4) asked.
After [1], this changed to:
1'. Same as step (1)
2'. Same as step (2)
3'. As the click was simulated instead of being the "natural" one
triggered by the browser touchend handling, the `t-on-click` handler
is called now, before the "in the next microtask" part of the
capture handler is done. That means what step (4) did happens now.
4'. Now what step (3) did happens now.
5'. Same as step (5)... but since step (3) and (4) were basically
swapped, the cursor is now restored as the way it was last saved:
at the end of the input (again don't know why step the
`useSelection` hook would want to save it like that though).
There are multiple solutions to fix this:
A. Remove the `t-on-touchend` handler, letting the browser do what it
naturally does. Although, it might be needed to prevent the mentioned
zoom behaviors on some phones?
B. Review why the `useSelection` hook wants to save the cursor at the
end of the input on external click, the point is valid but I am not
sure that should be this hook's job to enforce it.
C. Review why the `useSelection` hook wants to check if the click has to
be considered asynchronously, there should be a better way.
D. Configure the `useSelection` hook to consider a click on the
backspace button as to be ignored, as handled manually by its own
handlers anyway.
Option (A) should probably be done, by confirming zoom behaviors can be
prevented another way, but it cannot be done in stable anyway. The (B)
and (C) options should be investigated but would also not be stable to
change; also that would modify an exposed hook's behavior so more risky.
Option (D) can probably be done either way and is targeted on fixing the
bug described only, so this is the solution this commit went for.
In master, option (A) will be investigated in the forward-ported version
of this fix.
However... the bug was actually solved 3 months after [1], at [4] thanks
to secret option (E): not removing the `t-on-touchend` but changing it
entirely to call the same handler as the `t-on-click` one. A bit more
stable than option (A) but still not stable.
However... that solution (E) was broken 1 month later, again, by commit
[5] which destroyed step (5) while fixing an unrelated bug. Without that
step, the input cursor is not repositioned after OWL changes the value,
and by default OWL places it back at the end.
The solution is to restore step (5): the problem was that we were
checking if the user was not typing in another input before re-focusing
the keypad input... but the code considered the keypad input itself as
"another input". This commit still adds solution (D) on top of fixing
that, for good measures.
Note that in 19.0+, there is at least another cursor-related bugs,
related to commit [6]. It will be fixed in the forward-port of this one
as they need each other's fix to both work. Really there should be
better ways to handle that cursor position in OWL... might be done in a
future refactoring.
This commit adds a test to hopefully keep the bug fixed, as inspired by
commit [7].
[1]: https://github.com/odoo/enterprise/commit/52b3065993c41c6b7c65dda586a66fdd865b3afd
[2]: https://github.com/odoo/enterprise/commit/2e8f18801156a8069e26fb3d61d4f8d84893e891
[3]: https://github.com/odoo/odoo/commit/adc5448adf863b99b9b2be29985e560f5c12dbd4
[4]: https://github.com/odoo/enterprise/commit/668467678312632b5b9ecf234280690151bf3078
[5]: https://github.com/odoo/enterprise/commit/db82135fd73d5077fc26be7206105192a845c2bc
[6]: https://github.com/odoo/enterprise/commit/a06c02e8e163ed052c1c4d25a56bea9b6409abde
[7]: https://github.com/odoo/enterprise/commit/613ef7332b0d21e947871e9d33b68d069f1412c2
Related to task-5366961