Wednesday, April 1, 2026
3 changes · saas-18.2
Resolved issues and error corrections
This update fixes an error in how Pakistan payroll taxes are calculated for employees earning over 2.2 million annually. The system was incorrectly adding tax amounts instead of replacing them at each income bracket, resulting in overstated tax calculations. This fix ensures employees are taxed according to official Pakistan tax bracket rules.
Original PR description
Currently, payslip computation for Pakistan localization calculates incorrect tax when the yearly cost exceeds 2,200,000. ### **Steps to Reproduce:** 1) Install…
Currently, payslip computation for Pakistan localization calculates incorrect tax when the yearly cost exceeds 2,200,000. ### **Steps to Reproduce:** 1) Install `l10n_pk_hr_payroll_account`,`hr_contract_salary` with demo data. 2) Switch to PK company. 3) Create an employee and a running contract with yearly cost 2,200,001 4) Create a payslip and compute it from the Salary Computation tab. ### **Observed Behavior:** 'Tax Bracket Yearly' is computed as `122000.24` ### **Expected Behavior:** 'Tax Bracket Yearly' should be `116000.24` ### **Root Cause:** since [commit](https://github.com/odoo/enterprise/pull/98345/commits/62f5e216518d83317618d7dbc0be4db92d1881a3), the tax computation relies on [_l10n_pk_get_tax](https://github.com/odoo/enterprise/blob/a9656336583a4d5c5b12d4d6120ec62ba1cf9151/l10n_pk_hr_payroll/models/hr_payslip.py#L9-L20) , In this method, the `result` is incorrectly accumulated with `fix` when iterating through brackets, leading to an inflated tax value. [official pakistan document](https://download1.fbr.gov.pk/Docs/20258181281745641WHT-RateCard.pdf) ### **Fix:** Use `result = fix` instead of `result += fix` so that the cumulative tax is correctly reset at each bracket. **opw-5979265** Forward-Port-Of: odoo/enterprise#110939
This fix resolves critical errors that prevented users from validating inventory pickings and viewing product quantity information when their database had many storage locations. The system was generating excessively complex database queries that caused memory exhaustion. By reverting a previous change, the system now handles these operations efficiently, allowing warehouse staff to complete their daily inventory tasks without system failures.
Original PR description
This reverts [1] With enabled valuation and in case of a DB with many locations, it is currently impossible to validate a picking or open the on hand quantity smart button: it will lead to a…
This reverts [1]
With enabled valuation and in case of a DB with many locations, it is currently
impossible to validate a picking or open the on hand quantity smart button:
it will lead to a traceback, for instance:
```
Traceback (most recent call last):
[...]
File "/home/odoo/src/odoo/addons/stock/models/stock_picking.py", line 1432, in button_validate
pickings_to_backorder.with_context(cancel_backorder=False)._action_done()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[...]
File "/home/odoo/src/odoo/addons/stock_account/models/product.py", line 205, in _prepare_valuation_layer_field_values
"total_value": avg_cost * self.sudo(False)._with_valuation_context().qty_available if avg_cost else 0
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[...]
File "/home/odoo/src/odoo/addons/stock/models/product.py", line 172, in _compute_quantities_dict
moves_in_res = {product.id: product_qty for product, product_qty in Move._read_group(domain_move_in_todo, ['product_id'], ['product_qty:sum'])}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[...]
File "/home/odoo/src/odoo/odoo/sql_db.py", line 371, in execute
res = self._obj.execute(query, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
psycopg2.errors.SyntaxError: memory exhausted at or near "("
LINE 1: ...((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((...
```
[1] https://github.com/odoo/odoo/commit/c71c21647d468bd1f2e3261b6b612a060c4b6461
OPW-6083436
Forward-Port-Of: odoo/odoo#256799This fix resolves a crash that occurred in the Point of Sale system when scanning GS1-formatted barcodes for products with multiple variants. The system was incorrectly trying to process lot numbers as product barcodes, causing the application to fail. The fix ensures the correct product information is passed through the system so variant selection works properly.
Original PR description
**Steps to reproduce:** * Install `point_of_sale` module. * Go to Settings: * Enable Lots & Serial Numbers. * Enable Variants. * Set Barcode Nomenclature to Default GS1 Nomenclature. * Create a…
**Steps to reproduce:**
* Install `point_of_sale` module.
* Go to Settings:
* Enable Lots & Serial Numbers.
* Enable Variants.
* Set Barcode Nomenclature to Default GS1 Nomenclature.
* Create a product:
* Enable Track Inventory set to By Lots.
* Under Attributes & Variants:
* Add an attribute with two values and save.
* Generate product variants:
* Open one variant and set barcode to 5123648695416.
* Update inventory:
* Go to the main product (template).
* Update On Hand Quantity:
* Update On Hand Quantity with a lot/serial number:
010512364869541610784512.
* Select the variant with the defined barcode.
* Under Point of Sale tab:
* Set a POS Category.
* Open a POS session and scan:
010512364869541610784512.
**Observed behavior:**
* Scanning the GS1 barcode in POS raises a traceback:
*TypeError: Cannot read properties of undefined (reading
'product_template_attribute_value_ids')*.
**Cause:**
[Scans GS1 barcode: 010512364869541610784512]
│
├─ ProductScreen._barcodeGS1Action(parsed_results)
│ • product = await _getProductByBarcode(productBarcode) ✅ found
│ • calls `addLineToCurrentOrder(vals, { code: lotBarcode })`
│ ⚠️ only `lotBarcode` passed, `productBarcode` discarded
│
├─ PosStore.addLineToCurrentOrder() → addLineToOrder()
│ • product has variants → isConfigurable() = true
│
├─ PosStore.handleConfigurableProduct()
│ • calls openConfigurator(productTemplate, { ...opts })
│ opts = { code: lotBarcode }
│
└─ PosStore.openConfigurator()
• opts.code = lotBarcode → truthy → enters if(opts.code) branch
• getBy("barcode", opts.code.base_code)
• getBy("barcode", "784512") ← "784512" is a LOT number, not a product barcode!
→ returns undefined ❌
• product packaging lookup also fails → undefined ❌
• product = undefined
│
└─ attributeLinesValues.map(values =>
values.filter(value =>
product.product_template_attribute_value_ids.includes(value)
^^^^^^^ undefined → 💥 TypeError
**Fix:**
* Pass the product from `handleConfigurableProduct` to the configurator.
* If no product is found using `opts.code`, use the passed product
instead.
---
opw-6031909