Skip to content

Commit

Permalink
fix: better gls for purchases with tax witholding (#42743)
Browse files Browse the repository at this point in the history
* fix: better gls for purchases with tax witholding

* test: test case for purchase invoice gl entries with tax witholding

* fix: use flag `_skip_merge` instead of skipping merge based on against account

* test: fix test `test_single_threshold_tds` for newer implementation

(cherry picked from commit e3cd653)
  • Loading branch information
vorasmit authored and mergify[bot] committed Nov 9, 2024
1 parent 4cde77d commit 705a26a
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 27 deletions.
81 changes: 56 additions & 25 deletions erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,7 @@ def get_gl_entries(self, warehouse_account=None):

self.make_tax_gl_entries(gl_entries)
self.make_internal_transfer_gl_entries(gl_entries)
self.make_gl_entries_for_tax_withholding(gl_entries)

gl_entries = make_regional_gl_entries(gl_entries, self)

Expand Down Expand Up @@ -896,32 +897,37 @@ def make_supplier_gl_entry(self, gl_entries):
)

if grand_total and not self.is_internal_transfer():
against_voucher = self.name
if self.is_return and self.return_against and not self.update_outstanding_for_self:
against_voucher = self.return_against
self.add_supplier_gl_entry(gl_entries, base_grand_total, grand_total)

def add_supplier_gl_entry(
self, gl_entries, base_grand_total, grand_total, against_account=None, remarks=None, skip_merge=False
):
against_voucher = self.name
if self.is_return and self.return_against and not self.update_outstanding_for_self:
against_voucher = self.return_against

# Did not use base_grand_total to book rounding loss gle
gl = {
"account": self.credit_to,
"party_type": "Supplier",
"party": self.supplier,
"due_date": self.due_date,
"against": against_account or self.against_expense_account,
"credit": base_grand_total,
"credit_in_account_currency": base_grand_total
if self.party_account_currency == self.company_currency
else grand_total,
"against_voucher": against_voucher,
"against_voucher_type": self.doctype,
"project": self.project,
"cost_center": self.cost_center,
"_skip_merge": skip_merge,
}

# Did not use base_grand_total to book rounding loss gle
gl_entries.append(
self.get_gl_dict(
{
"account": self.credit_to,
"party_type": "Supplier",
"party": self.supplier,
"due_date": self.due_date,
"against": self.against_expense_account,
"credit": base_grand_total,
"credit_in_account_currency": base_grand_total
if self.party_account_currency == self.company_currency
else grand_total,
"against_voucher": against_voucher,
"against_voucher_type": self.doctype,
"project": self.project,
"cost_center": self.cost_center,
},
self.party_account_currency,
item=self,
)
)
if remarks:
gl["remarks"] = remarks

gl_entries.append(self.get_gl_dict(gl, self.party_account_currency, item=self))

def make_item_gl_entries(self, gl_entries):
# item gl entries
Expand Down Expand Up @@ -1413,6 +1419,31 @@ def make_internal_transfer_gl_entries(self, gl_entries):
)
)

def make_gl_entries_for_tax_withholding(self, gl_entries):
"""
Tax withholding amount is not part of supplier invoice.
Separate supplier GL Entry for correct reporting.
"""
if not self.apply_tds:
return

for row in self.get("taxes"):
if not row.is_tax_withholding_account or not row.tax_amount:
continue

base_tds_amount = row.base_tax_amount_after_discount_amount
tds_amount = row.tax_amount_after_discount_amount

self.add_supplier_gl_entry(gl_entries, base_tds_amount, tds_amount)
self.add_supplier_gl_entry(
gl_entries,
-base_tds_amount,
-tds_amount,
against_account=row.account_head,
remarks=_("TDS Deducted"),
skip_merge=True,
)

def make_payment_gl_entries(self, gl_entries):
# Make Cash GL Entries
if cint(self.is_paid) and self.cash_bank_account and self.paid_amount:
Expand Down
55 changes: 55 additions & 0 deletions erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -1544,6 +1544,61 @@ def test_purchase_invoice_advance_taxes(self):
payment_entry.load_from_db()
self.assertEqual(payment_entry.taxes[0].allocated_amount, 0)

def test_purchase_gl_with_tax_withholding_tax(self):
company = "_Test Company"

tds_account_args = {
"doctype": "Account",
"account_name": "TDS Payable",
"account_type": "Tax",
"parent_account": frappe.db.get_value(
"Account", {"account_name": "Duties and Taxes", "company": company}
),
"company": company,
}

tds_account = create_account(**tds_account_args)
tax_withholding_category = "Test TDS - 194 - Dividends - Individual"

# Update tax withholding category with current fiscal year and rate details
create_tax_witholding_category(tax_withholding_category, company, tds_account)

# create a new supplier to test
supplier = create_supplier(
supplier_name="_Test TDS Advance Supplier",
tax_withholding_category=tax_withholding_category,
)

pi = make_purchase_invoice(
supplier=supplier.name,
rate=3000,
qty=1,
item="_Test Non Stock Item",
do_not_submit=1,
)
pi.apply_tds = 1
pi.tax_withholding_category = tax_withholding_category
pi.save()
pi.submit()

self.assertEqual(pi.taxes[0].tax_amount, 300)
self.assertEqual(pi.taxes[0].account_head, tds_account)

gl_entries = frappe.get_all(
"GL Entry",
filters={"voucher_no": pi.name, "voucher_type": "Purchase Invoice", "account": "Creditors - _TC"},
fields=["account", "against", "debit", "credit"],
)

for gle in gl_entries:
if gle.debit:
# GL Entry with TDS Amount
self.assertEqual(gle.against, tds_account)
self.assertEqual(gle.debit, 300)
else:
# GL Entry with Purchase Invoice Amount
self.assertEqual(gle.credit, 3000)

def test_provisional_accounting_entry(self):
setup_provisional_accounting()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,17 @@ def test_single_threshold_tds(self):
self.assertEqual(pi.grand_total, 18000)

# check gl entry for the purchase invoice
gl_entries = frappe.db.get_all("GL Entry", filters={"voucher_no": pi.name}, fields=["*"])
gl_entries = frappe.db.get_all(
"GL Entry",
filters={"voucher_no": pi.name},
fields=["account", "sum(debit) as debit", "sum(credit) as credit"],
group_by="account",
)
self.assertEqual(len(gl_entries), 3)
for d in gl_entries:
if d.account == pi.credit_to:
self.assertEqual(d.credit, 18000)
self.assertEqual(d.credit, 20000)
self.assertEqual(d.debit, 2000)
elif d.account == pi.items[0].get("expense_account"):
self.assertEqual(d.debit, 20000)
elif d.account == pi.taxes[0].get("account_head"):
Expand Down
4 changes: 4 additions & 0 deletions erpnext/accounts/general_ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,10 @@ def merge_similar_entries(gl_map, precision=None):
merge_properties = get_merge_properties(accounting_dimensions)

for entry in gl_map:
if entry._skip_merge:
merged_gl_map.append(entry)
continue

entry.merge_key = get_merge_key(entry, merge_properties)
# if there is already an entry in this account then just add it
# to that entry
Expand Down

0 comments on commit 705a26a

Please sign in to comment.