Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e24ab72
fix: copy project from first row to new rows (backport #53295) (#54620)
mergify[bot] Apr 29, 2026
9db03bc
fix(selling): blanket order ordered qty recalculation on sales order …
mergify[bot] Apr 29, 2026
d6f2ff6
fix: show correct status in Serial No Ledger (backport #54567) (#54626)
mergify[bot] Apr 29, 2026
808214f
perf: max recursion depth error in serial no (backport #54629) (#54631)
mergify[bot] Apr 29, 2026
48ebb4c
feat(ux): Naming series dialog (#54554)
nishkagosalia Apr 29, 2026
2e43801
Merge pull request #54635 from frappe/mergify/bp/version-16-hotfix/pr…
nishkagosalia Apr 29, 2026
7bd360a
fix: py error on sales forecast doctype (backport #54641) (#54643)
mergify[bot] Apr 29, 2026
6dbc17d
fix: dont show serial/batch button when PR is submitted (backport #54…
mergify[bot] Apr 29, 2026
19a8ebe
fix(payment_entry): convert the date args to string type before escap…
mergify[bot] Apr 29, 2026
86cf256
fix: correct project filter in buying doctypes (backport #54644) (#54…
mergify[bot] Apr 29, 2026
b300159
fix: use RecoverableErrors isinstance check for repost timeout status…
mergify[bot] Apr 29, 2026
d3c893d
fix: skip depreciation rescheduling when asset is fully depreciated o…
khushi8112 Apr 29, 2026
07a957c
fix: skip rescheduling only for asset being disposed
khushi8112 Apr 29, 2026
bd932da
feat: copy terms attachments to transactions (backport #53403) (#54661)
mergify[bot] Apr 29, 2026
c232f1f
Merge pull request #54659 from frappe/mergify/bp/version-16-hotfix/pr…
khushi8112 Apr 30, 2026
d27cf48
fix: show in and out qty in the stock ledger report for stock recos
rohitwaghchaure Apr 30, 2026
38cfeb1
fix: correct titles set to {customer_name} or {supplier_name} text st…
mergify[bot] Apr 30, 2026
2422237
Merge pull request #54671 from frappe/mergify/bp/version-16-hotfix/pr…
rohitwaghchaure Apr 30, 2026
288cdf3
fix(project): use user.email for invitations and skip disabled users.…
mergify[bot] Apr 30, 2026
126e13b
fix: mark item tax templates as not applicable (backport #54673) (#54…
mergify[bot] Apr 30, 2026
a22d773
fix: Backfill `not_applicable` on Item Tax Template Details for Germa…
mergify[bot] May 1, 2026
0dade2c
fix: incorrect expense account book in purchase return (backport #546…
mergify[bot] May 1, 2026
bca893a
fix: add missing fields in set_currency_labels (backport #54689) (#54…
mergify[bot] May 1, 2026
bbb4e79
fix: set valid_from in created Item Price (backport #54696) (#54700)
mergify[bot] May 2, 2026
18006b9
chore: update POT file (#54710)
frappe-pr-bot May 3, 2026
982810a
fix: accounts and account types in German CoA "SKR 03" (backport #547…
mergify[bot] May 3, 2026
2cd4c1a
fix: error when creating quotation from CRM (backport #54722) (#54725)
mergify[bot] May 4, 2026
e60490d
fix: hide payment and payment request buttons based on permissions in…
mergify[bot] May 5, 2026
0f27881
fix: Remove bom stock report link from manufacturing workspace
nishkagosalia May 5, 2026
c985f94
Merge pull request #54743 from frappe/mergify/bp/version-16-hotfix/pr…
nishkagosalia May 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix: Backfill not_applicable on Item Tax Template Details for Germa…
…n companies (backport #54682) (#54686)

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
fix: Backfill `not_applicable` on Item Tax Template Details for German companies (#54682)
  • Loading branch information
mergify[bot] and barredterra authored May 1, 2026
commit a22d773341faffdad2f3389e77e354e9e0a914f4
1 change: 1 addition & 0 deletions erpnext/patches.txt
Original file line number Diff line number Diff line change
Expand Up @@ -480,3 +480,4 @@ erpnext.patches.v16_0.set_root_type_in_account_categories
erpnext.patches.v16_0.scr_inv_dimension
erpnext.patches.v16_0.packed_item_inv_dimen
erpnext.patches.v16_0.fix_titles
erpnext.patches.v16_0.set_not_applicable_on_german_item_tax_templates
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
import frappe

# Snapshot of the relevant German defaults when this migration was written.
# Migration patches must not read mutable setup data, otherwise future edits to
# country_wise_tax.json would change what this patch does on sites that have not
# run it yet.
#
# For numbered charts, compare account_number + root_type because Account.account_name
# is not unique within a company.
SKR04_NOT_APPLICABLE_7_PERCENT_ACCOUNT_IDS = frozenset(
{
("3801", "Liability"),
("3802", "Liability"),
("3835", "Liability"),
("1401", "Asset"),
("1402", "Asset"),
("1541", "Asset"),
}
)

SKR04_NOT_APPLICABLE_19_PERCENT_ACCOUNT_IDS = frozenset(
{
("3806", "Liability"),
("3804", "Liability"),
("3837", "Liability"),
("1406", "Asset"),
("1404", "Asset"),
("1540", "Asset"),
}
)

SKR03_NOT_APPLICABLE_7_PERCENT_ACCOUNT_IDS = frozenset(
{
("1771", "Liability"),
("1772", "Liability"),
("1785", "Liability"),
("1571", "Asset"),
("1572", "Asset"),
("1541", "Asset"),
}
)

SKR03_NOT_APPLICABLE_19_PERCENT_ACCOUNT_IDS = frozenset(
{
("1776", "Liability"),
("1774", "Liability"),
("1787", "Liability"),
("1576", "Asset"),
("1574", "Asset"),
("1540", "Asset"),
}
)

STANDARD_NOT_APPLICABLE_7_PERCENT_ACCOUNT_LABELS = frozenset(
{
("Umsatzsteuer 7 %", "Liability"),
("Umsatzsteuer aus innergemeinschaftlichem Erwerb", "Liability"),
("Umsatzsteuer nach § 13b UStG", "Liability"),
("Abziehbare Vorsteuer 7 %", "Asset"),
("Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb", "Asset"),
("Abziehbare Vorsteuer nach § 13b UStG", "Asset"),
}
)

STANDARD_NOT_APPLICABLE_19_PERCENT_ACCOUNT_LABELS = frozenset(
{
("Umsatzsteuer 19 %", "Liability"),
("Umsatzsteuer aus innergemeinschaftlichem Erwerb 19 %", "Liability"),
("Umsatzsteuer nach § 13b UStG 19 %", "Liability"),
("Abziehbare Vorsteuer 19 %", "Asset"),
("Abziehbare Vorsteuer aus innergemeinschaftlichem Erwerb 19 %", "Asset"),
("Abziehbare Vorsteuer nach § 13b UStG 19 %", "Asset"),
}
)

STANDARD_WITH_NUMBERS_NOT_APPLICABLE_7_PERCENT_ACCOUNT_IDS = frozenset(
{
("2321", "Liability"),
("2331", "Liability"),
("2341", "Liability"),
("1521", "Asset"),
("1531", "Asset"),
("1541", "Asset"),
}
)

STANDARD_WITH_NUMBERS_NOT_APPLICABLE_19_PERCENT_ACCOUNT_IDS = frozenset(
{
("2320", "Liability"),
("2330", "Liability"),
("2340", "Liability"),
("1520", "Asset"),
("1530", "Asset"),
("1540", "Asset"),
}
)

GERMAN_ITEM_TAX_TEMPLATE_NOT_APPLICABLE_ACCOUNTS = {
"SKR03 mit Kontonummern": {
"identifier_field": "account_number",
"templates": {
"19 %": SKR03_NOT_APPLICABLE_7_PERCENT_ACCOUNT_IDS,
"7 %": SKR03_NOT_APPLICABLE_19_PERCENT_ACCOUNT_IDS,
"0 %": SKR03_NOT_APPLICABLE_7_PERCENT_ACCOUNT_IDS
| SKR03_NOT_APPLICABLE_19_PERCENT_ACCOUNT_IDS
| frozenset({("1588", "Asset")}),
},
},
"SKR04 mit Kontonummern": {
"identifier_field": "account_number",
"templates": {
"19 %": SKR04_NOT_APPLICABLE_7_PERCENT_ACCOUNT_IDS,
"7 %": SKR04_NOT_APPLICABLE_19_PERCENT_ACCOUNT_IDS,
"0 %": SKR04_NOT_APPLICABLE_7_PERCENT_ACCOUNT_IDS
| SKR04_NOT_APPLICABLE_19_PERCENT_ACCOUNT_IDS
| frozenset({("1433", "Asset")}),
},
},
"Standard": {
"identifier_field": "account_name",
"templates": {
"19 %": STANDARD_NOT_APPLICABLE_7_PERCENT_ACCOUNT_LABELS,
"7 %": STANDARD_NOT_APPLICABLE_19_PERCENT_ACCOUNT_LABELS,
"0%": STANDARD_NOT_APPLICABLE_7_PERCENT_ACCOUNT_LABELS
| STANDARD_NOT_APPLICABLE_19_PERCENT_ACCOUNT_LABELS
| frozenset({("Entstandene Einfuhrumsatzsteuer", "Asset")}),
},
},
"Standard with Numbers": {
"identifier_field": "account_number",
"templates": {
"19%": STANDARD_WITH_NUMBERS_NOT_APPLICABLE_7_PERCENT_ACCOUNT_IDS,
"7%": STANDARD_WITH_NUMBERS_NOT_APPLICABLE_19_PERCENT_ACCOUNT_IDS,
"0 %": STANDARD_WITH_NUMBERS_NOT_APPLICABLE_7_PERCENT_ACCOUNT_IDS
| STANDARD_WITH_NUMBERS_NOT_APPLICABLE_19_PERCENT_ACCOUNT_IDS
| frozenset({("1550", "Asset")}),
},
},
}


def update_account_cache(accounts, account_cache):
missing_accounts = set(accounts) - set(account_cache)
if not missing_accounts:
return

for account in frappe.get_all(
"Account",
filters={"name": ("in", tuple(sorted(missing_accounts)))},
fields=["name", "account_name", "account_number", "root_type"],
):
account_cache[account.name] = account


def get_account_identifier(account, identifier_field, account_cache):
cached_account = account_cache.get(account)
if not cached_account:
return None

return cached_account.get(identifier_field), cached_account.root_type


def execute():
"""Backfill `not_applicable` on Item Tax Template Details for German companies.

Before the `not_applicable` flag existed, German default templates used
`tax_rate: 0` to mean "this tax does not apply to the item" (as opposed to
an explicit 0% rate). For each German company, this patch looks up the
historical defaults for its Chart of Accounts and sets
`not_applicable = 1` on detail rows that still match those defaults
(same template title, same zero-rate tax account identifier set, flag still unset),
leaving any user-customised rows untouched.
"""
companies = frappe.get_all(
"Company",
filters={"country": "Germany"},
fields=["name", "chart_of_accounts"],
)
account_cache = {}

for company in companies:
chart = GERMAN_ITEM_TAX_TEMPLATE_NOT_APPLICABLE_ACCOUNTS.get(company.chart_of_accounts)
if not chart:
continue

identifier_field = chart["identifier_field"]
for template_title, target_accounts in chart["templates"].items():
itt_names = frappe.get_all(
"Item Tax Template",
filters={"company": company.name, "title": template_title},
pluck="name",
)
for itt_name in itt_names:
zero_rate_details = frappe.get_all(
"Item Tax Template Detail",
filters={"parent": itt_name, "tax_rate": 0},
fields=["name", "tax_type", "not_applicable"],
)
update_account_cache((d.tax_type for d in zero_rate_details), account_cache)
zero_rate_accounts_by_detail = {
d.name: get_account_identifier(d.tax_type, identifier_field, account_cache)
for d in zero_rate_details
}
if any(identifier is None for identifier in zero_rate_accounts_by_detail.values()):
continue

if set(zero_rate_accounts_by_detail.values()) != target_accounts:
continue

for d in zero_rate_details:
if not d.not_applicable:
frappe.db.set_value(
"Item Tax Template Detail",
d.name,
"not_applicable",
1,
update_modified=False,
)