Wednesday, March 18, 2026
17 changes · 19.0
Resolved issues and error corrections
Fixes an issue where employee time off accruals could stop increasing even when the remaining balance was still below the plan cap. This ensures employees who regularly use leave continue receiving the correct new leave days, avoiding incorrect future leave availability.
Original PR description
Accrual plan for leave days gets blocked, even when the remaining leave balance is below the cap. As a result, no additional leaves are accrued beyond a certain point, even though they should be. #…
Accrual plan for leave days gets blocked, even when the remaining leave balance is below the cap. As a result, no additional leaves are accrued beyond a certain point, even though they should be.
# Steps to reproduce:
Go to time off app
* Create a new leave type.
* Create a new accrual plan with:
- one milestone :
- 2 days accrued per month
- Cap: 10 days
- start accruing 1 days after
- No expiration
- Carry over: All
* Create and validate a leave allocation
- 1 year ago
- new leave type
- new accrual plan
* Take the maximum number of leaves available.
* Advance the computer calendar by 1 year.
* Again, take the maximum number of leaves.
* Advance the computer calendar by another year.
* Try to take a future leave.
-> Issue: It’s not possible to take a future leave, the number of accrued days has stopped increasing. The accrual plan appears blocked.
Objective : The accrual plan should continue to allocate leave days even if leaves have been consumed regularly, as long as the remaining leaves are under the cap.
## Issue
Before going further: the property `leaves_taken` of the `hr.leave.allocation` is supposed to contain the number of leaves this allocation cover until "today".
In the `_test_get_allocation_future_leaves1` added test, in the last line of the test :
`assert_virtual_leaves_equal(self, leave_type_day, 2, self.employee_emp, date='2023-02-01')`
When calling `get_allocation_data` with a `target_date` set in the future, the result is wrong. Here is how it works :
`get_allocation_data`
...
.....`_get_consumed_leaves` (1)
...........`_get_future_leaves_on` (2)
...............`_process_accrual_plans` (3)
....................`_compute_leaves` (4)
.........................`_get_consumed_leaves` (5)
..............................`get_future_leaves_on` (6)
...................................`process_accrual_plans` (7)
**A)** The method **(2)** try to calculate the added number of days each allocation will have on `target_date`. So it creates a copy of the allocation in memory using the 'new' method:
`fake_allocation = self.env['hr.leave.allocation'].with_context(default_date_from=accrual_date).new(origin=self)`
It will then update it to `target_date` using `_process_accrual_plans` and will return the difference of days between the
updated `fake_allocation` and the current allocation (`self`)
**B)** Before iterating over each accrual date, the `_process_accrual_plans` **(3)** will get the `leaves_taken` property which is a computed field. It will trigger `_compute_leaves`.
**C)** The method **(4)** will call `_get_consumed_leaves`, and so the nightmare begins.
**D)** The method **(6)** will create a second `fake_allocation` based on the origin of the first `fake_allocation` (see **A)**).
**E)** This time, `_process_accrual_plans` **(7)** will also look at the `leaves_taken`, but won't trigger the `_compute_leaves` probably because the current allocation is a `fake_allocation` of a `fake_allocation`, and one property of the `new` method is that `Two new records with the same origin record are considered equal.`. Therefore, the `leaves_taken` is considered to be already computed (but it's not).
So `_process_accrual_plans` read the `leaves_taken` which is 0 (probably the default value of `leaves_taken`), but it should be 20 !
**F)** As the value of `leaves_taken` is wrong, the fake_allocation n°2 is also wrong, and its `number_of_day` is 10 but the `number_of_days` of the origin allocation is 20. So `get_future_leaves_on` **(6)** will return -10 which makes no sense, and all the previous calls computations will be wrong. And the final `virtual_remaining_leaves` value will be 0 instead of 2.
## Source of the issue
In the `_process_accrual_plans` method, for each allocation, `leaves_taken` is only computed once at the start of the loop over the allocation "important" dates (see `nextcall` property of `hr.leave.allocation`). At this moment, the method calculates the `leaves_taken` the allocation will have on the `accrual_date` parameter. Yet, this property can change depending on the date the allocation is on (`nextcall` property) which leads to some issues in the computation of the `allocation.number_of_days`.
## Solution
For each allocation, compute the `leaves_taken` at every iteration trough the values of `nextcall`. BUT, this can trigger an infinite loop as computing `leaves_taken` calls `_get_consumed_leaves` which calls `_get_future_leaves_on`, which calls `_process_accrual_plans` ... To avoid this, this PR add the context variable `precomputed_allocations` (will be converted into a function parameter in master) which will prevent `_get_consumed_leaves` from calling `_get_future_leaves_on` for the allocations already up to date (contained by this very `precomputed_allocations` context variable).
opw-4934391
opw-5226806
Forward-Port-Of: odoo/odoo#239836
Forward-Port-Of: odoo/odoo#250057
Forward-Port-Of: odoo/odoo#243812This fix prevents attendance records from crashing when employees in UTC+ time zones have consecutive full-day attendances. It also ensures overtime entries are properly removed when related attendance records are deleted, improving payroll and attendance accuracy.
Original PR description
Steps to reproduce (singleton crash): Create an employee in a UTC+ timezone (e.g. Asia/Shanghai or Australia/Adelaide) with an overtime ruleset containing a paid rule. Generate work entries for a…
Steps to reproduce (singleton crash): Create an employee in a UTC+ timezone (e.g. Asia/Shanghai or Australia/Adelaide) with an overtime ruleset containing a paid rule. Generate work entries for a period, then create two consecutive midnight-to-midnight attendances in the employee's local timezone. Creating the second attendance crashes with: "ValueError: Expected singleton: hr.attendance.overtime.line(...)". Steps to reproduce (stale overtime lines): With the same setup, delete the attendance after it generated overtime lines. The overtime lines remain in the database instead of being removed. The singleton crash occurred because `end_of_day` in `_get_overtime_intervals` was computed as a naive datetime, implicitly treated as UTC. For UTC+ timezones, the actual local end of day is earlier than UTC midnight. As a result, overtime intervals were computed with a stop time extending past the real local midnight into UTC time. When consecutive attendances were processed together, these extended intervals overlapped. The `Intervals` class (`keep_distinct=True`) merges overlapping intervals into a single entry with a multi-record recordset as payload. The subsequent `overtime.rule_ids.work_entry_type_id` and `overtime.status` calls expected a singleton but received a multi-record set, causing the crash. The same multi-record issue also affected the iteration in `_set_real_overtime_intervals` and the overtime work entry loop in `_get_attendance_intervals`. The stale overtime lines issue occurred because `_get_overtimes_to_update_domain` built its search date range from raw UTC `.date()` values instead of the employee's local timezone. For UTC+ employees whose attendance spans local midnight, the overtime line is dated in the next local calendar day. Since the domain was derived from UTC dates, that next local day fell outside the search range, so the overtime line was never found and deleted when the attendance was removed. Additionally, `_get_localized_times` called `.astimezone()` on naive UTC datetimes without first localizing them, producing incorrect local times for the same reason. Solution: - In `_get_overtimes_to_update_domain`, localize check_in/check_out to the employee's timezone before computing the overtime search date range (with a ±1 day buffer) so overtime lines for dates that only exist in local time are correctly included in the delete-and-recreate cycle. - Fix `_get_localized_times` to call `utc.localize()` on naive UTC datetimes before converting to the employee's timezone. opw-5931665
This fix prevents an access error that could block non-admin manufacturing users from completing production when work center cost lines are linked to work orders. It keeps the existing cost distribution and permission rules intact while allowing the normal Produce All workflow to finish successfully.
Original PR description
Issue before this commit: ========================= Clicking Produce All on a Manufacturing Order as a user with Manufacturing and Timesheet rights raised an AccessError. During Manufacturing Order…
Issue before this commit: ========================= Clicking Produce All on a Manufacturing Order as a user with Manufacturing and Timesheet rights raised an AccessError. During Manufacturing Order completion, Odoo creates analytic lines for work center cost distribution and links them to the work order through the wc_analytic_account_line_ids Many2many field. With the stricter ORM security checks, linking records in a Many2many field requires read access to those records. Since analytic lines are created using sudo() but the relation update runs under the current user's permissions, the operation fails due to timesheet-related record rules. Steps to Reproduce: ========================= 1. Install mrp_account and hr_timesheet modules. 2. Create a Work Center with an analytic distribution. 3. Create a Product with a Bill of Materials (BoM) that includes a work order using the created Work Center. 4. Log in as a non-admin user with Manufacturing and Timesheet permissions. 5. Create and confirm a Manufacturing Order for that product. 6. Click Produce All. Cause of the Issue: ========================= Analytic lines are created with sudo(), but when linking them to the work order through the Many2many field wc_analytic_account_line_ids, the ORM checks whether the current user has read access to those records. Due to timesheet record rules restricting access to analytic lines, the linking operation raises an AccessError. With This Commit: ========================= This commit allows users to complete Manufacturing Orders without encountering access errors when analytic lines are linked to work orders, while preserving the existing analytic distribution and security logic. For Reference: [Security checks on Many2many](https://github.com/odoo/odoo/pull/217277/changes#diff-720a85988e5f3afc3b2596b9521964ef4a99e03e5b1ea8bea2e8ee476187526aR1467) Steps To Reporduce: [Video Link](https://drive.google.com/file/d/1HsZjpFSsnsYxZ4xwM8CBDeLhlcIHIP5t/view) opw-5971807
The point of sale setup now ignores operation types from archived warehouses. This prevents upgrade failures and avoids using obsolete warehouse settings that are no longer relevant to active POS operations.
Original PR description
revert the commit as when we fetch archived warehouse's pos type it will raise error for other source or destination loction for newly created stock operation type like even functinally also there is…
revert the commit
as when we fetch archived warehouse's pos type
it will raise error for other source or destination loction for newly created stock operation type like
even functinally also there is no need to fetch
archived warehouse's operation type.
```
quality Control
cross Dock,
Storage type
```
we got this error during upgrade :
```
File "/home/odoo/src/odoo/saas-17.4/odoo/sql_db.py", line 347, in execute
res = self._obj.execute(query, params)
psycopg2.errors.NotNullViolation: null value in column "default_location_src_id" of relation "stock_picking_type" violates not-null constraint
DETAIL: Failing row contains (33, 0, 28, 56, null, null, null, 4, null, null, 1, 1, 1, QC, internal, at_confirm, FBAQC, ask, {"en_US": "Quality Control"}, null, f, f, t, null, f, null, 2024-10-16 05:14:53.18448, 2024-10-16 05:14:53.18448, optional, optional, no, optional, null, null, t, null, null, 2x7xprice, 4x12_lots, pdf, null, null, null, null, null, null, null, null, null, t, null).
```
due to this two fix:
https://github.com/odoo/odoo/pull/151719/commits
https://github.com/odoo/odoo/pull/175838/files
so we need to avoid to fetch archived warehouse's picking type.
ref:
odoo/upgrade#6631
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
Forward-Port-Of: odoo/odoo#191652
Forward-Port-Of: odoo/odoo#185244This fixes an issue in Point of Sale where returning from a receipt to the product screen could show the wrong order. The change keeps the selected order in sync with the screen navigation, helping cashiers continue with the intended ticket and reducing checkout confusion.
Original PR description
When navigating via `showDefault` from the ReceiptScreen to the ProductScreen, the route and URL update correctly but `selectedOrderUuid` remains pointing to the previous (receipt) order. Since ProductScreen resolves `currentOrder` through `pos.getOrder()` (which relies on `selectedOrderUuid`), it ends up displaying the stale order instead of the one specified in the route params. Update `selectedOrderUuid` from `routeParams.orderUuid` at the start of `navigate()` so that `getOrder()` and `setScreenData` both operate on the correct order. opw-6014753 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Companies can now receive self-billing invoices through the standard Peppol accounting setup without needing an extra module. The update also removes an invoice reception option intended only for government use, helping prevent incorrect service configuration.
Original PR description
Everybody is now able to receive self billing invoices even without the additional module. So the service should be added to the base module. Also remove xRechung because users are not supposed to receive it, only government. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#254341
This fixes employee document shortcuts opening with the public website domain when a separate website address is configured. Users are now sent to the intended system address, avoiding broken or misleading document links.
Original PR description
Steps to reproduce: --------------------------------- 1. Install `documents_hr` and `website_documents` modules 2. Go to website > configuration > websites 3. In My Website set any arbitary domain…
Steps to reproduce: --------------------------------- 1. Install `documents_hr` and `website_documents` modules 2. Go to website > configuration > websites 3. In My Website set any arbitary domain (e.g. https://test.com) 4. Open any employee record 5. Click on Documents smart button Observation: --------------------------------- It will try to open employee's documents with the website's domain, e.g. `https://test.com/odoo/documents/xyz` Issue: --------------------------------- After the following commit: odoo@46c43c1 the smart button redirects to the document folder via an access token. The `access_url` is computed using `get_base_url()`, which is overridden by the website module to return the website domain instead of the system base URL. https://github.com/odoo/odoo/blob/f6cf0d067e5f30e2b22ea513071cd7c5e3d9f44c/addons/website/models/ir_model.py#L10-L36 Solution: --------------------------------- Added a context-based check to `get_base_url()`. When the context key `use_config_parameter_domain` is set, and the record has a `website_id` field, the system base URL from the configuration parameters is used instead of the website domain. This allows any model to explicitly rely on the configured base URL when required NOTE: No module installs `hr`, `documents` and `website`, so test case is not possible without bridge module of all three Related Enterprise PR: https://github.com/odoo/enterprise/pull/106478 opw-5471683
Portal users can now submit website forms that create project tasks without seeing an access error on the confirmation page. This keeps the task creation flow working smoothly for external users while preserving the existing access restrictions.
Original PR description
Currently, submitting a website form that creates a task crash for portal users on the confirmation page. ### **Steps to reproduce:** 1) Install website_project with demo data 2) Create a website…
Currently, submitting a website form that creates a task crash for portal users on the confirmation page. ### **Steps to reproduce:** 1) Install website_project with demo data 2) Create a website form that creates a task 3) Set a project on the form 4) Submit the form as a portal user ### **Error:** `AccessError: You do not have enough rights to access the field project_privacy_visibility on Task (project.task)` ### **Root Cause:** The confirmation template evaluates `task.project_privacy_visibility` in a t-if condition at [1]. since [commit](https://github.com/odoo/odoo/pull/203891/changes/17664b3f118491f954dd6a810521ce5865d51a43), project task restricts portal users to a whitelist of fields defined by [_portal_accessible_fields()](https://github.com/odoo/odoo/blob/b9e3ca44ceb2b0b35b5e91a06f2905e042aa7f89/addons/project/models/project_task.py#L1015-L1019). Field access is then validated in [_has_field_access()](https://github.com/odoo/odoo/blob/b9e3ca44ceb2b0b35b5e91a06f2905e042aa7f89/addons/project/models/project_task.py#L1021-L1031), which denies read access to fields not present in this whitelist. `project_privacy_visibility` is not part of the portal readable fields list. When the template tries to read it, _has_field_access() rejects the operation and raises an AccessError. [1]- https://github.com/odoo/odoo/blob/b9e3ca44ceb2b0b35b5e91a06f2905e042aa7f89/addons/website_project/views/project_portal_project_task_template.xml#L13-L16 ### **Fix:** Use `sudo()` when reading `project_privacy_visibility` in the template to avoid the portal field access restriction. **opw-6010622** Forward-Port-Of: odoo/odoo#254099
The French FEC accounting export now streams the file as it is downloaded instead of holding the entire export in memory. This helps large companies export very large accounting files without running into memory errors.
Original PR description
On large databases (millions of account moves), The FEC exported file can be huge. This resulted in memory error since at some point we have the entire file in memory. This commit aims to overcome this issue by streaming the content of the file to the user. task-5404142 Forward-Port-Of: odoo/odoo#247889 Forward-Port-Of: odoo/odoo#240981
Deleting a row or column in the HTML editor now keeps the editing area active and places the cursor in a sensible nearby cell. This makes follow-up actions like Undo work reliably and reduces confusion when editing tables.
Original PR description
**Current behavior before PR:** When a user deletes a row or column from table menu, the editor loses focus. As a result, actions like Undo do not behave as expected and require multiple attempts to restore the original table state. This breaks the editing flow, causes confusion when performing table-related actions. **Desired behavior after PR:** This PR ensures that editable is focused after deleting row or column from table menu. This commit also makes sure that selection is set properly and hint is visible on empty cell after deleting the column. Enterprise PR: https://github.com/odoo/enterprise/pull/109034 task-5725593 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#249070 Forward-Port-Of: odoo/odoo#245433
This fixes a notification gap where people subscribed to the Purchases journal did not receive emails when vendor bills arrived by email while digitization was turned off. Subscribers will now be notified regardless of whether OCR processing runs or succeeds, helping teams avoid missed vendor bill communications.
Original PR description
When vendor bills digitization is deactivated, subscribers to the "Purchases" journal are not notified when a vendor bill is sent to the email alias set on the "Purchases" journal Steps to reproduce:…
When vendor bills digitization is deactivated, subscribers to the "Purchases" journal are not notified when a vendor bill is sent to the email alias set on the "Purchases" journal Steps to reproduce: 1. Install Accounting 2. Go to Settings > Accounting > Digitization and set Vendor Bills to "Do not digitize" 3. Go to Settings > Technical > Email > Alias Domains and create a new alias domain (e.g. "odoo.com") 4. Go to Settings > Technical > Email > Incoming Mail Servers and create a new incoming mail server (e.g. "megu@odoo.com", you may need to setup POP access on your email address and create an app password, see https://support.google.com/mail/answer/7104828) 5. Go to Accounting > Configuration > Journals and open journal "Purchases" 6. Go to Advanced Settings tab and set the Email Alias and the Send Copy To fields (e.g. "megu@odoo.com" for both) 7. Send a mail with an attachment to the email alias set on the "Purchases" journal 8. Go to the previously created incoming mail server and click on Fetch Now 9. Go to Settings > Email > Technical > Emails 10. No email has been sent to the subscriber of the "Purchases" journal Issue: `_extend_with_attachments` returns None if the OCR import failed https://github.com/odoo/odoo/blob/b44295bb6ce621ff87cbc96860492650d90d0ad7/addons/account/models/account_document_import_mixin.py#L340-L349 which prevents the call to method `_notify_invoice_subscribers` Solution: Send an email regardless of the result of the OCR import opw-5914096
This update corrects a bug in the DIAN invoice processing workflow. Previously, the system incorrectly deleted the original invoice document, potentially leading to data loss. The fix ensures the correct invoice document is protected, preventing accidental deletion during the update process.
Original PR description
**PROBLEM** In some configurations, `_l10n_co_dian_cron_update_event_status()` would delete the original document of the invoice. **CAUSE** The logic that tried to exclude the original document from the code that unlinks duplicated documents is wrong. It protect the oldest document of `self` instead of `move`. So the document of the move we are currently working on is not protected, and could be deleted. **STEP TO REPRODUCE** 1. Setup DIAN. 2. Create multiples invoices and send them to DIAN. 3. Run _l10n_co_dian_cron_update_event_status() If the original document of the invoice have the same commercial_status as some other document, it could be destroyed. opw-5447147
This update resolves issues where overtime calculations were incorrect due to timezone discrepancies, leading to crashes and orphaned overtime records. The fix ensures accurate overtime intervals are generated and handled, regardless of the employee's location, improving data integrity and reliability.
Original PR description
Steps to reproduce (singleton crash): Create an employee in a UTC+ timezone (e.g. Asia/Shanghai or Australia/Adelaide) with an overtime ruleset containing a paid rule. Generate work entries for a…
Steps to reproduce (singleton crash): Create an employee in a UTC+ timezone (e.g. Asia/Shanghai or Australia/Adelaide) with an overtime ruleset containing a paid rule. Generate work entries for a period, then create two consecutive midnight-to-midnight attendances in the employee's local timezone. Creating the second attendance crashes with: "ValueError: Expected singleton: hr.attendance.overtime.line(...)". Steps to reproduce (stale overtime lines): With the same setup, delete the attendance after it generated overtime lines. The overtime lines remain in the database instead of being removed. The singleton crash occurred because `end_of_day` in `_get_overtime_intervals` was computed as a naive datetime, implicitly treated as UTC. For UTC+ timezones, the actual local end of day is earlier than UTC midnight. As a result, overtime intervals were computed with a stop time extending past the real local midnight into UTC time. When consecutive attendances were processed together, these extended intervals overlapped. The `Intervals` class (`keep_distinct=True`) merges overlapping intervals into a single entry with a multi-record recordset as payload. The subsequent `overtime.rule_ids.work_entry_type_id` and `overtime.status` calls expected a singleton but received a multi-record set, causing the crash. The same multi-record issue also affected the iteration in `_set_real_overtime_intervals` and the overtime work entry loop in `_get_attendance_intervals`. The stale overtime lines issue occurred because `_get_overtimes_to_update_domain` (hr_attendance) built its search date range from raw UTC `.date()` values instead of the employee's local timezone. For UTC+ employees whose attendance spans local midnight, the overtime line is dated in the next local calendar day. Since the domain was derived from UTC dates, that next local day fell outside the search range, so the overtime line was never found and deleted when the attendance was removed. Solution: - In `_get_overtime_intervals`, localize `end_of_day` to the employee's timezone before converting to UTC, so overtime intervals are correctly bounded by the local end of day. - In `_set_real_overtime_intervals` and the overtime loop in `_get_attendance_intervals`, iterate over individual records from potentially multi-record `Intervals` payloads to avoid singleton errors. - In `_get_overtimes_to_update_domain` (hr_attendance), localize check_in/check_out to the employee's timezone before computing the date range so overtime lines for dates that only exist in local time are correctly included in the delete-and-recreate cycle. opw-5931665
This update corrects a visual discrepancy between how the AI livechat snippet is displayed in the editor and how it appears to users. The issue stemmed from mismatched code structures, leading to inconsistent rendering. This fix ensures the AI livechat snippet displays correctly across different devices and configurations.
Original PR description
Scenario: - add ai livechat snippet block - switch to mobile - enable "Fallback Button" - save Result: the rendering is different between edition and real usage of AI livechat snippet. Cause: structure and classes don't match Fix: make the structure and classes match. opw-5458575 pr note: I copied `ai_website_livechat.AILivechatComponent` in `ai_website_livechat.s_ai_livechat_edit` but it might make more sense to just render the owl widget with a class that neuter the AI (this way we don't need to update both template at each change)
This update ensures that NACHA payment files accurately reflect the actual account holder's name, rather than the customer's name in Odoo. Prioritizing the bank account holder's name improves payment processing accuracy and compliance with NACHA regulations.
Original PR description
The NACHA entry detail was using the partner's name (res.partner.name) for the Individual Name field. This should instead prioritize the Account Holder Name (acc_holder_name) from the bank account, as this reflects the actual name on the bank account which may differ from the partner's name in Odoo. The code now uses bank.acc_holder_name if set, and falls back to payment.partner_id.name if not set. Forward-Port-Of: odoo/enterprise#108414 Forward-Port-Of: odoo/enterprise#105582
This update ensures that the PIN code is now displayed for both physical and virtual expense cards. Previously, users were blocked from completing transactions using virtual cards (via digital wallets) because they couldn't access the necessary PIN information. This change improves the user experience and ensures seamless payment processing.
Original PR description
Before this commit: - Currently, we show the PIN code for physical expense cards only, not for virtual cards. - In some case transactions are made via virtual cards (through digital wallets) also requires a PIN. The users will be blocked because they currently can't access this information. After this commit: - Now we show the PIN code for both physical and virtual cards. task-5926462
This update resolves a validation error with the ARCA system (used for Argentinian tax compliance) when processing invoices for 'Final Consumers' without VAT/CUIT numbers. The system now correctly sends a 'null' value for the invoice number, aligning with ARCA's requirements and preventing invoice rejection.
Original PR description
**Description of the issue/feature this PR addresses:** This PR fixes a validation error (Code 10015) returned by ARCA (formerly AFIP) when attempting to validate invoices for "Final Consumers"…
**Description of the issue/feature this PR addresses:** This PR fixes a validation error (Code 10015) returned by ARCA (formerly AFIP) when attempting to validate invoices for "Final Consumers" (Consumidor Final) who do not have a VAT/CUIT number assigned. The system currently defaults the DocNro field to 0, which is rejected by the fiscal authority's web service. **Current behavior before PR:** When a contact is marked as "Final Consumer" but lacks a specific ID number (VAT/CUIT), the integration sends DocNro: 0 to ARCA. This triggers Error 10015, as "0" is not considered a valid identification number for this responsibility type, leading to a blocked invoice. **Desired behavior after PR is merged:** For contacts meeting these conditions (Final Consumer without a defined ID), the system will now automatically categorize the transaction as "sigd" (System Identified/Global Data) instead of a standard Final Consumer. By doing this, the DocNro is sent as None (or null), which is the legally accepted format by ARCA for these specific cases, successfully bypassing the validation error.