feat: Thai Tax Withholding Category fixtures with per-company accounts
Add 22 Tax Withholding Category fixtures covering Thailand domestic withholding (Taw.Paw. 4/2528, Sec. 50(2), Sec. 70) with rates and thresholds. Fixtures ship without accounts; on import each Thai company gets "Withholding Tax Payable" (Liability) and "Withholding Tax Receivable" (Asset) created and the payable account linked. Company on_update does the same for companies created later. Site-configured accounts survive fixture re-import on migrate.
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
import frappe
|
||||
|
||||
# Liability: tax we withhold from suppliers and remit on P.N.D.3/53 (linked on every category).
|
||||
# Asset: tax customers withhold from us, creditable against corporate income tax.
|
||||
LIABILITY_ACCOUNT = "Withholding Tax Payable"
|
||||
ASSET_ACCOUNT = "Withholding Tax Receivable"
|
||||
|
||||
# Preferred parent groups by root type; first match wins, else the root account.
|
||||
PARENT_GROUPS = {
|
||||
"Liability": ("Duties and Taxes", "Current Liabilities"),
|
||||
"Asset": ("Tax Assets", "Current Assets"),
|
||||
}
|
||||
|
||||
CATEGORY_FILTERS = {"name": ("like", "WHT %")}
|
||||
|
||||
|
||||
def thai_companies():
|
||||
return frappe.get_all("Company", filters={"country": "Thailand"}, pluck="name")
|
||||
|
||||
|
||||
def get_or_create_account(company, account_name, root_type):
|
||||
name = frappe.db.get_value(
|
||||
"Account", {"company": company, "account_name": account_name, "is_group": 0, "root_type": root_type}
|
||||
)
|
||||
if name:
|
||||
return name
|
||||
|
||||
account = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Account",
|
||||
"company": company,
|
||||
"account_name": account_name,
|
||||
"parent_account": find_parent_group(company, root_type),
|
||||
"root_type": root_type,
|
||||
"account_type": "Tax",
|
||||
"is_group": 0,
|
||||
}
|
||||
).insert(ignore_permissions=True)
|
||||
return account.name
|
||||
|
||||
|
||||
def find_parent_group(company, root_type):
|
||||
for account_name in PARENT_GROUPS[root_type]:
|
||||
parent = frappe.db.get_value(
|
||||
"Account",
|
||||
{"company": company, "account_name": account_name, "is_group": 1, "root_type": root_type},
|
||||
)
|
||||
if parent:
|
||||
return parent
|
||||
|
||||
return frappe.db.get_value(
|
||||
"Account",
|
||||
{"company": company, "root_type": root_type, "is_group": 1, "parent_account": ("is", "not set")},
|
||||
)
|
||||
|
||||
|
||||
def ensure_company_accounts(company):
|
||||
"""Create both withholding accounts for `company`; return the liability account name."""
|
||||
get_or_create_account(company, ASSET_ACCOUNT, "Asset")
|
||||
return get_or_create_account(company, LIABILITY_ACCOUNT, "Liability")
|
||||
|
||||
|
||||
def link_company(category, company, account):
|
||||
"""Append `account` for `company` to the category's accounts table if missing."""
|
||||
if any(row.company == company for row in category.accounts):
|
||||
return False
|
||||
category.append("accounts", {"company": company, "account": account})
|
||||
return True
|
||||
|
||||
|
||||
def prepare_fixture_accounts(doc, method=None):
|
||||
"""Tax Withholding Category fixtures ship without `accounts` (company-specific).
|
||||
|
||||
Fixture import re-inserts the doc on every migrate, so: carry over the rows
|
||||
already configured on this site, then link every Thai company, creating the
|
||||
withholding accounts on first use. Mandatory is relaxed for sites without a
|
||||
Thai company yet (setup wizard not run); `setup_company` links them later.
|
||||
"""
|
||||
doc.flags.ignore_mandatory = True
|
||||
|
||||
if not doc.accounts and frappe.db.exists(doc.doctype, doc.name):
|
||||
for row in frappe.get_all(
|
||||
"Tax Withholding Account",
|
||||
filters={"parent": doc.name, "parenttype": doc.doctype},
|
||||
fields=["company", "account"],
|
||||
order_by="idx",
|
||||
):
|
||||
doc.append("accounts", row)
|
||||
|
||||
for company in thai_companies():
|
||||
if not any(row.company == company for row in doc.accounts):
|
||||
link_company(doc, company, ensure_company_accounts(company))
|
||||
|
||||
|
||||
def setup_company(doc, method=None):
|
||||
"""Company.on_update: create withholding accounts and link every WHT category."""
|
||||
if doc.country != "Thailand" or not frappe.db.exists("Account", {"company": doc.name}):
|
||||
return
|
||||
|
||||
account = ensure_company_accounts(doc.name)
|
||||
for name in frappe.get_all("Tax Withholding Category", filters=CATEGORY_FILTERS, pluck="name"):
|
||||
category = frappe.get_doc("Tax Withholding Category", name)
|
||||
if link_company(category, doc.name, account):
|
||||
category.save(ignore_permissions=True)
|
||||
Reference in New Issue
Block a user