Wednesday, August 26, 2026
8 changes · master
New functionality added to Odoo
A new biometric attendance foundation lets Odoo receive, store, and process employee punch data from biometric devices. Initial integrations for eSSL and Mantra devices automate attendance creation, reduce duplicate entries, and make future provider additions easier.
Original PR description
- Add a new base module hr_attendance_biometric for common biometric attendance functionality. - Introduce a common transaction model to receive and track biometric punch data. - Store raw biometric…
- Add a new base module hr_attendance_biometric for common biometric attendance functionality. - Introduce a common transaction model to receive and track biometric punch data. - Store raw biometric transactions for audit, troubleshooting, and reprocessing. - Provide a common flow to convert provider-specific punch data into a standard format. - Automatically create Odoo attendance records from processed biometric transactions. - Prevent duplicate attendance records by tracking processed transactions. - Match biometric punches with employees using employee or punch codes. Add provider-specific integrations: - Add hr_attendance_biometric_essl for eSSL Security biometric devices. - Add hr_attendance_biometric_mantra for Mantra Softech biometric devices. - Receive attendance logs from eSSL and Mantra through webhook endpoints. - Convert eSSL and Mantra payloads into the common biometric transaction format. - Process provider transactions through the shared attendance integration flow. This modular approach separates common biometric attendance logic from provider-specific implementations, making the integration easier to maintain and allowing additional biometric providers to be added in the future. Task-6053426
Self-order kiosks can now accept QRIS QR code payments, enabling customers in Indonesia to pay without cashier assistance. The system checks payment status in the backend and updates the kiosk automatically, making unattended kiosk ordering smoother and more reliable.
Original PR description
Add a module letting a self-order kiosk accept QRIS QR code payments. A QR payment in a kiosk has no cashier to confirm it, so the backend decides the outcome and pushes it to the kiosk over the bus. The module ships a provider-agnostic kiosk QR framework (`kiosk_qr_mixin`) supporting both webhook- and polling-driven acquirers, kept free of any QRIS reference so it can move to `pos_self_order` once a second QR provider exists, plus the QRIS provider itself, which polls `l10n_id.qris.transaction` for the result. `point_of_sale` registers QRIS as an `external_qr` provider so it shows up in the payment method setup. task-5352384
This update lets AI agents be set up and managed from a chat-style interface, including their tools, data sources, and triggers. Agents can also create and run automations such as scheduled summaries or follow-ups, making AI workflows easier to configure without technical screens.
Original PR description
This PR introduces agentic automations through the AI app. It also extensively refactors the AI app flow - making the discuss chat view, the main way to change agent configurations. Task-6334162
Enhancements to existing features
Belgian payroll now better supports flexi-job employment workflows, including Dimona notifications, shift-hour capture, and specific wage calculations. This helps businesses stay compliant with Belgian reporting rules while reducing errors around refused notifications and quarter-based contract limits.
Original PR description
Modifications include: - Updated the dimona workflow to support flexi-jobs, including capturing shift hours for same-day contracts. - Added restrictions to prevent automatic dimonas beyond 31 days and block contracts overlapping multiple quarters. - Added support for a new "Flexi Wage" and specific payroll computations. - Implemented anomaly code handling (460/510) to fall back to regular wage computations when a dimona is refused. - Updated the DMfA XML templates and schemas to include the `FlexiNotion` tag for relevant employees. Task Id : 6033394 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
This fixes an error that could stop customers from generating batch payments. The payment file creation process now uses the correct address-cleaning logic, helping users complete payments without disruption.
Original PR description
The aim of this commit is to allow customer to make their batch payment without facing a Traceback. Context: odoo/enterprise@35f5341b9b44cc16eaea311295a064189dd802cb introduced bug during a badly…
The aim of this commit is to allow customer to make their batch payment
without facing a Traceback.
Context:
odoo/enterprise@35f5341b9b44cc16eaea311295a064189dd802cb introduced bug
during a badly handled forward port.
The method was removed in saas-18.3 in favor of a function. The forward-port
was half handled and now surfaces to Odoo's own production.
Generating a batch payment could generates the following Traceback:
```py
File "/home/odoo/src/enterprise/saas-19.3/account_iso20022/models/account_journal_sepa_ct.py", line 69, in _get_PstlAdr
return super()._get_PstlAdr(partner_id, payment_method_code)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/saas-19.3/account_iso20022/models/account_journal.py", line 501, in _get_PstlAdr
CtrySubDvsn.text = self._sepa_sanitize_communication(partner_address['state'][:35])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'account.journal' object has no attribute '_sepa_sanitize_communication'
```
Task-id: None (internal issue)
Forward-Port-Of: odoo/enterprise#129084
Forward-Port-Of: odoo/enterprise#129006Code cleanup and technical improvements
This change restructures how loyalty rewards, gift cards, and eWallets are handled in Point of Sale. Cashiers now claim free product rewards manually, reward lines are clearer at zero price, and the system rechecks loyalty calculations at order validation to improve consistency and prevent misuse.
Original PR description
Enterprise PR-[#127058](https://github.com/odoo/enterprise/pull/127058) Upgrade PR-[#10948](https://github.com/odoo/upgrade/pull/10948) --- Moved the computation of the different loyalty rewards from…
Belgian payroll now better supports flexi-job employment workflows, including shift-hour tracking, Dimona notifications, and dedicated wage calculations. This helps employers stay compliant with Belgian reporting rules while reducing manual corrections when flexi-job declarations are refused or restricted.
Original PR description
Modifications include: - Updated the dimona workflow to support flexi-jobs, including capturing shift hours for same-day contracts. - Added restrictions to prevent automatic dimonas beyond 31 days and block contracts overlapping multiple quarters. - Added support for a new "Flexi Wage" and specific payroll computations. - Implemented anomaly code handling (460/510) to fall back to regular wage computations when a dimona is refused. - Updated the DMfA XML templates and schemas to include the `FlexiNotion` tag for relevant employees. Task Id : 6033394
Calendar meetings with Discuss video links are now created and shown in Discuss ahead of time, so attendees can find planned calls before anyone joins. Users can filter for planned meetings and schedule a future Discuss meeting from the Meetings menu, while recurring meetings and deleted meetings are handled more consistently.
Original PR description
Before this commit, a meeting holding a Discuss video call link had no channel until someone opened `videocall_location`: the meeting was absent from the Discuss "Meetings" tab, and its invitation…
Before this commit, a meeting holding a Discuss video call link had no channel until someone opened `videocall_location`: the meeting was absent from the Discuss "Meetings" tab, and its invitation link only started working once an attendee joined the call. The one way to get a meeting out of Discuss was the "Meeting" button, which starts an ad-hoc group call with no date attached to it. This commit gives such a meeting its channel upfront, on create and as soon as the link is added afterwards, and keeps the two in line: - the channel is named after the meeting and describes when it takes place (the recurrence rule for a recurring meeting, its date and time otherwise), and is pinned for every attendee having a user, so the meeting shows in the "Meetings" tab of each of them; - its avatar shows the day of the meeting rather than the day the channel was created, in the reader's own timezone; - every occurrence of a recurrence shares a single channel, which only goes away with the last of those meetings; - deleting a meeting takes its video call away, unless the channel already hosted a conversation: that one is only unpinned, so the chat history stays reachable from Discuss while the video call drops out of the tab. The channel is resolved from the meeting the recurrence machinery left live, rather than from the edited record: editing a whole recurrence archives the occurrence it was asked from and moves the new values to a freshly recreated one, which would otherwise write back the values from before the edit. The "Meetings" tab gains a "Planned" filter, keeping only the video calls backed by a meeting, and its "Meeting" button becomes a menu offering "Start Now" next to "Schedule for later", which opens a `calendar.event` form prefilled with a 30 minute Discuss video call. The button is a menu whatever the modules contributing to it, so that starting a meeting is always found in the same place. Scheduling is only offered in the webclient, as the form view it opens is not part of the public Discuss page. Both calendar parts come from hooks defined on `MessagingMenu` itself, `extraTabActions` and `extraTabFilters`, rather than from the /discuss/ patch declaring the tab: a bundle contributing to a tab may be patched in before the one declaring it, which would then discard the override. task-6460543 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Enterprise PR-[#127058](https://github.com/odoo/enterprise/pull/127058) Upgrade PR-[#10948](https://github.com/odoo/upgrade/pull/10948) --- Moved the computation of the different loyalty rewards from the pos_order.js model to their specific model files. Now the whole flow is started by `pos_order.recomputeRewards` it will delete all existing rewards on the order, then apply the discounts and auto rewards. The order keeps track of - `_active_rewards` - list of rewards manually claimed by the user, with optional qty and reward product - `_disabled_program_ids` - list of loyalty programs which were manually removed from the order by the user, so they are not automatically recomputed on the next pass - `_active_payment_programs` - the payment programs which are used in the order `pos_order.recomputeReward` will compute all the points that a reward can consume and then call `applyReward` which then decides which orderlines need to be added The frontend will keep the order consistent with the existing loyalty programs in the way they were loaded by the browser, to ensure that the displayed data is consistent while being able to still process loyalty orders while offline. Although the frontend does its own processing of loyalty, the backend will redo the same computations on order validation on `pos_order._process_saved_order` That will call `_process_loyalty` which will recompute based on the orderlines how many points the order is eligible for for each program, and how many points are consumed by each reward. Afterwards it will create the history lines based on its own computation, so that bad clients can't fool the system (and we can later trust to use loyalty programs on the self) The only thing which currently doesn't work offline is selling gift cards or ewallets. Before order validation, if there are any payment cards that need to be created, we do a RPC call to `loyalty_card.create_pos_cards` which will create the cards and send the data back to the client so that the new cards are properly added on the order. --- Here are the big UX changes: 1. Free product rewards used to be automatically added to the cart. In the old flow you would add a product, and if eligible for a free reward, another line with the negative price of the product would show up on the cart (which was the reward). Now free product rewards need to be manually claimed from the control buttons and they always show up as 0 priced order lines. 2. There is no more `Reset Rewards` button. Rewards are either applied on the order or not. The user can at any point remove reward lines from the order through the numpad, which will disable the reward. Disabled rewards can always be added back through the normal `Rewards` button. 3. We used to have a hard rule that rewards can't be claimed unless the client is already paying for something on the order. Now clients can use up their loyalty points and apply rewards without needing to also order something else --- Besides all of that, here is a list of all the tours which needed changes due to the new design, and why those changes were made: test_combo_product_dont_grant_point would create 2 combos of $48 each but then 100% discount would only reduce the total by $46 because the products in the combo have different sales taxes, and then expect the total to be 50. Now it applies the correct $48 so the total should be $48 PosLoyaltySpecificDiscountWithFreeProductTour expected for a free product reward to only be enabled when the product is added to the cart or when the reward button is pressed. Now it's treated as any other automatic reward and the free product is added to the order test_promotion_program_with_loyalty_program added a `trigger: auto` to the program. Otherwise the program is created with `trigger = false`, which can't really be produced in a real DB, unless through direct backend ORM calls or SQL. The new module relies on the trigger value for auto computed rewards. (The old one treated Falsy values as auto) test_ewallet_expiration_date expects the eWallet pay button to be available and then to throw an error dialog when trying to add an expired eWallet. Now the button will just be disabled if no valid eWallets can be added to the current order MultipleGiftWalletProgramsTour, RefundRulesProduct modified since the partner selection popup now launches automatically when an eWallet is added on the order with no partner selected EWalletProgramTour1 & EWalletLoyaltyHistory expected the partner popup to show up only after the pay button is pressed if there is no partner selected for the current order. Now the selection popup will show up as soon as a topup product is added on the order with no partner selected MultiplePhysicalGiftCardProgramSaleTour expects the user to select the program for the card when the product is added to the order, but then after the createManualGiftCard step, it asks the user again to chose a program. This seems like repetitive for no reason. So the new module will keep the program which was selected the first time by the user and skip the 2nd prompt PosLoyaltyFreeProductTour, PosLoyaltyFreeProductTour2, PosLoyaltyTour11.2, PosLoyaltyLoyaltyProgram3, PosLoyaltyTour12, test_loyalty_free_product_rewards_2, PosLoyaltyTour10, test_loyalty_reward_with_variant, test_min_qty_points_awarded, test_multiple_reward_line_free_product, PosOrderClaimReward, PosLoyaltyTour1, PosLoyaltyTour8, assumes the old free product behaviour of negative lines and auto applied rewards. It is changed to follow the new flow of requiring manual redeeming for all free product rewards and using 0 cost lines for all free product rewards PosLoyaltyLoyaltyProgram2: 1. It asserts that loyalty rewards cannot be used unless something is ordered first. Should we still enforce this constraint? 2. The last order total checked whether the reward was still applied by making sure the total is 6.40 (2 pens) and there is no negative line. This assertion doesn't work anymore when rewards have 0 price, so now it uses a doesNotHaveRewardLine method to ensure the reward is not applied PosLoyaltyRewardProductTag tries to claim the same reward 2 times on the same order with different products. This is no longer possible, the product for a reward is locked, only the qty can be changed. This is consistent with sale_loyalty and website_sale_loyalty. PosLoyaltyChangeRewardQty DDD Test Partner starts with 100 points. Adding a reward line automatically adds the maximum claimable qty. Also change the price from negative line to 0 test_buy_x_get_y_reward_qty - updated to apply the free product reward manually PosLoyaltySpecificDiscountTour tries to claim the same 10$ reward twice. The customer has enough points to claim the reward 2 times, but the new module doesn't allow applying the same discount reward multiple times, even if the points would allow. This is consistent with sale_loyalty test_receipt_data_pos_loyalty tries to call a `postProcessLoyalty` which doesn't exist anymore and loyalty is synced automatically after orders are validated test_gift_card_communication - the cards are created through the create_pos_cards method on the loyalty.card. Then the _process_loyalty() method replaces `confirm_coupon_programs` and generates all the history and card data, and then send communications for newly created cards test_loyalty_history - `create_pos_cards` creates the new cards instead of `confirm_coupon_programs`. But it only creates empty cards, which are awarded points only on `_process_loyalty` which is called afterwards. Multiple calls to `_process_loyalty` on the same order are considered duplicate, and will not create any new data on the backend. test_reward_line_tax_grouping_key created a coupons program with an automatic trigger and expected the product to apply the points. Coupon programs can only be `with-code` triggered, and the rules don't generate points, they only enable the points on the coupons. So I changed the program type to `promotion` PosLoyaltyTour2 used the old `Reset Rewards` button which doesn't exist anymore, so the removal and re-apply of rewards is done manually. It also has the same free product reward negative line changes --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr