fix: post customer withholding as a Deduct tax row, not a deduction
With a deduction row ERPNext treats Paid Amount as cash received and credits the party for paid + deduction, so a gross Paid Amount (what Get Outstanding Invoices fills) over-credited Debtors and posted the gross to the bank. Use the taxes table with add_deduct_tax=Deduct like supplier TDS: Paid Amount is the gross settlement, bank receives paid minus withholding, receivable is debited. Override Payment Entry build_gl_map to flag the bank entry post_net_value so the merged bank line shows the net amount.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import erpnext
|
||||
import frappe
|
||||
from erpnext.accounts.doctype.payment_entry.payment_entry import PaymentEntry
|
||||
from erpnext.accounts.doctype.sales_invoice.sales_invoice import SalesInvoice
|
||||
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import (
|
||||
get_tax_withholding_details,
|
||||
@@ -157,15 +158,31 @@ class ThaiSalesInvoice(SalesInvoice):
|
||||
)
|
||||
|
||||
|
||||
class ThaiPaymentEntry(PaymentEntry):
|
||||
def build_gl_map(self):
|
||||
"""A "Deduct" tax row on a receipt posts bank Dr gross and bank Cr
|
||||
withholding; ERPNext merges them into one entry but only nets it when
|
||||
the bank entry itself carries `post_net_value`. Set it so the bank
|
||||
ledger shows the amount that actually arrived."""
|
||||
gl_entries = super().build_gl_map()
|
||||
if self.payment_type == "Receive" and self.party_type == "Customer" and self.get("taxes"):
|
||||
for entry in gl_entries:
|
||||
if entry.account == self.paid_to:
|
||||
entry.post_net_value = True
|
||||
return gl_entries
|
||||
|
||||
|
||||
def set_customer_withholding(doc, method=None):
|
||||
"""Payment Entry.validate: tax withheld by the customer on a Receive entry
|
||||
becomes a deduction to the company's withholding receivable account.
|
||||
is posted like ERPNext's supplier TDS, as a "Deduct" row in the taxes
|
||||
table against the withholding receivable account.
|
||||
|
||||
Withholding is rate x pre-VAT amount of each allocated reference, prorated
|
||||
by the allocation. `paid_amount` is the cash actually received, so the
|
||||
deduction closes the difference against the gross allocation. Runs after
|
||||
the controller's validate (exchange rates and allocations are final), then
|
||||
re-derives the two amounts that depend on deductions.
|
||||
`paid_amount` is the gross amount settled against the invoices (what
|
||||
"Get Outstanding Invoices" fills in); the bank receives paid minus the
|
||||
withholding (`received_amount_after_tax`). Withholding is rate x pre-VAT
|
||||
amount of each allocated reference, prorated by the allocation. Runs after
|
||||
the controller's validate, then re-runs the tax computation so the row's
|
||||
base amounts and totals are final within this save.
|
||||
"""
|
||||
if doc.party_type != "Customer" or doc.payment_type != "Receive" or not doc.apply_tax_withholding_amount:
|
||||
return
|
||||
@@ -181,20 +198,22 @@ def set_customer_withholding(doc, method=None):
|
||||
frappe.throw(_("Account {0} not found for Company {1}").format(ASSET_ACCOUNT, doc.company))
|
||||
|
||||
amount, description = get_customer_withholding(doc)
|
||||
row = next((d for d in doc.deductions if d.account == account), None)
|
||||
row = next((d for d in doc.taxes if d.account_head == account), None)
|
||||
|
||||
if not amount:
|
||||
if row:
|
||||
doc.remove(row)
|
||||
else:
|
||||
if not row:
|
||||
row = doc.append("deductions", {"account": account})
|
||||
row.amount = amount
|
||||
row = doc.append(
|
||||
"taxes", {"account_head": account, "charge_type": "Actual", "add_deduct_tax": "Deduct"}
|
||||
)
|
||||
row.tax_amount = amount
|
||||
row.description = description
|
||||
row.cost_center = doc.cost_center or erpnext.get_default_cost_center(doc.company)
|
||||
|
||||
doc.set_unallocated_amount()
|
||||
doc.set_difference_amount()
|
||||
doc.apply_taxes()
|
||||
doc.set_amounts_after_tax()
|
||||
|
||||
|
||||
def get_customer_withholding(doc):
|
||||
|
||||
Reference in New Issue
Block a user