fix: v16 compatibility for item_wise_tax_detail in _build_amounts_per_vat_rate#74
Conversation
…ts_per_vat_rate In ERPNext v16, the JSON field `item_wise_tax_detail` on Sales Taxes rows no longer exists. The data is now stored in the Child Table `item_wise_tax_details` (DocType: "Item Wise Tax Detail") on the invoice. This causes `_build_amounts_per_vat_rate` to fail because it only reads the JSON field, which is always None in v16. The fix adds a fallback path: if the JSON field is empty, the function reads from the v16 Child Table instead. The v15 JSON path is preserved as the primary path, so this change is fully backwards-compatible. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three v16-related issues in dsfinv_k_cash_point_closing.py: 1. _build_amounts_per_vat_definition: Same issue as _build_amounts_per_vat_rate (fixed in previous commit). The JSON field `item_wise_tax_detail` on tax rows no longer exists in v16. Added fallback to read from the v16 Child Table `item_wise_tax_details` (DocType: "Item Wise Tax Detail"). The v15 JSON path is preserved as primary, making this fully backwards-compatible. 2. _get_pos_invoices_from_closing: In v15 the POS Closing Entry stores invoice references in the child table field `pos_transactions`. In v16 this was renamed to `pos_invoices`. Added fallback: tries `pos_invoices` first (v16), then `pos_transactions` (v15). 3. _build_cash_point_closing_head: In v16, `posting_date` on POS Closing Entry is a `datetime.date` object instead of a string. This causes `TypeError: Object of type date is not JSON serializable` when sending the payload to the fiskaly DSFINVK API. Fixed by explicitly converting to string via `str(doc.posting_date)`. All three fixes follow the same pattern as the tse_transaction fix: v15 path first, v16 fallback, fully backwards-compatible. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Thanks for your help and this PR 👍 Have you been able to test all the cases listed in the test plan and verify that the changes work as expected in version-16? |
|
Thanks! Yes, we have tested the cases from the test plan on v16:
Unfortunately we don't have a v15 environment to test backwards compatibility, but the code preserves the v15 JSON path as the primary lookup and only falls back to the v16 Child Table — so it should be safe. On a separate note: any thoughts on the two RFCs we opened (#75 SUBMIT DE / ELSTER and #76 SAFE flex)? Would love to hear if these are something you'd consider for the project. |
|
Tahnks and cool for your help😄👍 In the current code, the old v15 path is processed via That’s why I’m wondering whether it’s really correct in the v16 fallback to reduce this Child Table data back to The specific case I’m referring to here would be a v16 POS Invoice with the same POS Invoice Item Row A: name = ROW-1, item_code = COFFEE, net_amount = 10.00 Here, ROW-1 and ROW-2 are technically two separate invoice lines, even though both have the same item_code. The “happy paths” you tested with 19% / 7% / mixed rates are helpful for this, but I think this specific case—where the same item_code appears multiple times across several item rows—needs to be tested separately, because this is where the new v16 data structure differs most significantly from the old JSON logic. A second point concerns the error handling for tax rows: In the previous code, tax rows without usable item_wise_tax_detail were effectively skipped before VAT mapping was enforced. In the current version, it appears as though VAT mapping is resolved as soon as account_head is present—that is, even before it is determined whether the tax row provides any usable detail data for the calculation. Still, great work so far on this important update for full support of v16 👍 |
|
Thanks for the thorough review and great catch on the duplicate Fixes AppliedWe've updated our v16 compatibility patch to address both points: 1. Duplicate
2. Error handling for tax rows without usable data:
Tested with 6 scenarios (all via HTTP with the compat patch active via
Full Module ReviewWhile fixing these, we took the opportunity to review the entire Potential Issues in Original Code
Security AssessmentPositive:
No critical security issues found. The module is well-structured and follows Frappe best practices. Code QualityOverall the architecture is solid — clean provider abstraction, proper error handling, idempotency checks, deduplication on background jobs. The two Happy to discuss any of these findings! 😄 |
|
That's great 👍 |
Addresses two points raised in review of PR Rocket-Quack#74: 1. Duplicate item_code on multiple invoice lines v16 lookup key is now (tax_row_name, item_row_name) instead of (tax_row_name, item_code). Each POS Invoice Item row is processed individually — two lines with the same item_code no longer collapse under one shared key. A separate net_amount_by_row_name dict tracks net amounts per unique row. For the v15 path, net_amount_by_item_code now accumulates with += instead of overwriting on duplicates. 2. Lazy VAT mapping resolution _resolve_vat_code / _resolve_vat_id are now deferred until we actually have relevant detail data to process. Tax rows without usable item_wise_tax_detail data no longer force a mapping lookup — matching the original pre-v16 behavior of silently skipping such rows (tse_transaction.py:243 style continue). Applied symmetrically in both _build_amounts_per_vat_rate (tse_transaction.py) and _build_amounts_per_vat_definition (dsfinv_k_cash_point_closing.py). Tested on v16 with 6 scenarios (all via HTTP): - 19% only - 7% only - Mixed 19% + 7% - Duplicate item_code 19% (2x same item, different amounts) - Duplicate item_code 7% - Duplicate 19% + single 7% (3 lines, 2 with same item_code)
|
Done — pushed commit c885349 to 1. Duplicate
2. Lazy VAT mapping resolution
Applied symmetrically in Regarding the 9 findings from the full-module review: we haven't fixed those yet, since they're separate observations on the original code and weren't part of this PR's scope. We'd be happy to prepare separate PRs for them if you'd like — but only for the ones you actually consider bugs. Some might be intentional design choices we don't have the context for (e.g. the hardcoded |
If you have good suggestions for new PRs feel free to submit them then we can discuss them and their scope. 🙂👍 |
|
Automated tests for communicating with Fiskaly and ensuring functionality for future updates would be helpful if you want to tackle those |
Summary
item_wise_tax_detailon Sales Taxes and Charges rows no longer exists. Tax detail data is now stored in the Child Tableitem_wise_tax_details(DocType: "Item Wise Tax Detail") on the invoice document._build_amounts_per_vat_rate()to silently skip all tax rows (line 243:if not item_wise_tax_detail_json: continue), resulting in"Could not derive VAT amounts"errors when creating TSE transactions on v16.Details
Problem: In v16,
tax_row.item_wise_tax_detailis alwaysNonebecause ERPNext moved this data to a proper Child Table. The original code requires this JSON field and fails without it.Solution: Before iterating tax rows, the function now:
item_wise_tax_detailsChild Table from the invoice (in-memory first, DB fallback)(tax_row_name, item_code) → {rate, amount}Tested with:
Test plan
🤖 Generated with Claude Code