fix: Add tds in PO and code cleanup

This commit is contained in:
Deepesh Garg
2020-11-29 21:40:04 +05:30
parent c26de28613
commit d18dde7757
11 changed files with 676 additions and 197 deletions

View File

@@ -12,6 +12,7 @@
"account_head", "account_head",
"col_break_1", "col_break_1",
"description", "description",
"included_in_paid_amount",
"accounting_dimensions_section", "accounting_dimensions_section",
"cost_center", "cost_center",
"dimension_col_break", "dimension_col_break",
@@ -20,9 +21,11 @@
"section_break_9", "section_break_9",
"tax_amount", "tax_amount",
"total", "total",
"allocated_amount",
"column_break_13", "column_break_13",
"base_tax_amount", "base_tax_amount",
"base_total" "base_total",
"base_allocated_amount"
], ],
"fields": [ "fields": [
{ {
@@ -185,12 +188,36 @@
"reqd": 1, "reqd": 1,
"show_days": 1, "show_days": 1,
"show_seconds": 1 "show_seconds": 1
},
{
"default": "0",
"fieldname": "included_in_paid_amount",
"fieldtype": "Check",
"label": "Included In Paid Amount",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "allocated_amount",
"fieldtype": "Currency",
"label": "Allocated Amount",
"options": "currency",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "base_allocated_amount",
"fieldtype": "Currency",
"label": "Allocated Amount (Company Currency)",
"options": "Company:company:default_currency",
"show_days": 1,
"show_seconds": 1
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2020-10-27 20:02:34.734260", "modified": "2020-11-29 19:06:14.666460",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Advance Taxes and Charges", "name": "Advance Taxes and Charges",

View File

@@ -24,15 +24,12 @@
"party_bank_account", "party_bank_account",
"contact_person", "contact_person",
"contact_email", "contact_email",
"tds_details_section",
"apply_tax_withholding_amount",
"column_break_20",
"tax_withholding_category",
"payment_accounts_section", "payment_accounts_section",
"party_balance", "party_balance",
"paid_from", "paid_from",
"paid_from_account_currency", "paid_from_account_currency",
"paid_from_account_balance", "paid_from_account_balance",
"advance_tax_account",
"column_break_18", "column_break_18",
"paid_to", "paid_to",
"paid_to_account_currency", "paid_to_account_currency",
@@ -45,8 +42,10 @@
"base_paid_amount_after_tax", "base_paid_amount_after_tax",
"column_break_21", "column_break_21",
"received_amount", "received_amount",
"received_amount_after_tax",
"target_exchange_rate", "target_exchange_rate",
"base_received_amount", "base_received_amount",
"base_received_amount_after_tax",
"section_break_14", "section_break_14",
"get_outstanding_invoice", "get_outstanding_invoice",
"references", "references",
@@ -61,6 +60,10 @@
"taxes_and_charges_section", "taxes_and_charges_section",
"purchase_taxes_and_charges_template", "purchase_taxes_and_charges_template",
"sales_taxes_and_charges_template", "sales_taxes_and_charges_template",
"column_break_55",
"apply_tax_withholding_amount",
"tax_withholding_category",
"section_break_56",
"taxes", "taxes",
"base_total_taxes_and_charges", "base_total_taxes_and_charges",
"total_taxes_and_charges", "total_taxes_and_charges",
@@ -731,14 +734,6 @@
"fieldtype": "Check", "fieldtype": "Check",
"label": "Custom Remarks" "label": "Custom Remarks"
}, },
{
"depends_on": "eval: doc.payment_type == 'Pay' && doc.party_type == 'Supplier'",
"fieldname": "tds_details_section",
"fieldtype": "Section Break",
"label": "TDS Details",
"show_days": 1,
"show_seconds": 1
},
{ {
"depends_on": "eval:doc.apply_tax_withholding_amount", "depends_on": "eval:doc.apply_tax_withholding_amount",
"fieldname": "tax_withholding_category", "fieldname": "tax_withholding_category",
@@ -750,18 +745,13 @@
}, },
{ {
"default": "0", "default": "0",
"depends_on": "eval:doc.party_type == 'Supplier'",
"fieldname": "apply_tax_withholding_amount", "fieldname": "apply_tax_withholding_amount",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Apply Tax Withholding Amount", "label": "Apply Tax Withholding Amount",
"show_days": 1, "show_days": 1,
"show_seconds": 1 "show_seconds": 1
}, },
{
"fieldname": "column_break_20",
"fieldtype": "Column Break",
"show_days": 1,
"show_seconds": 1
},
{ {
"collapsible": 1, "collapsible": 1,
"fieldname": "taxes_and_charges_section", "fieldname": "taxes_and_charges_section",
@@ -829,6 +819,44 @@
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Paid Amount After Tax (Company Currency)", "label": "Paid Amount After Tax (Company Currency)",
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
"read_only": 1,
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "column_break_55",
"fieldtype": "Column Break",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "section_break_56",
"fieldtype": "Section Break",
"hide_border": 1,
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "advance_tax_account",
"fieldtype": "Link",
"label": "Advance Tax Account",
"options": "Account",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "received_amount_after_tax",
"fieldtype": "Currency",
"label": "Received Amount After Tax",
"options": "paid_to_account_currency",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "base_received_amount_after_tax",
"fieldtype": "Currency",
"label": "Received Amount After Tax (Company Currency)",
"options": "Company:company:default_currency",
"show_days": 1, "show_days": 1,
"show_seconds": 1 "show_seconds": 1
} }
@@ -836,7 +864,7 @@
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-10-25 20:50:14.896628", "modified": "2020-11-29 20:03:57.772062",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Payment Entry", "name": "Payment Entry",

View File

@@ -65,6 +65,7 @@ class PaymentEntry(AccountsController):
self.validate_allocated_amount() self.validate_allocated_amount()
self.validate_paid_invoices() self.validate_paid_invoices()
self.ensure_supplier_is_not_blocked() self.ensure_supplier_is_not_blocked()
self.validate_advance_tax_account()
self.set_status() self.set_status()
def on_submit(self): def on_submit(self):
@@ -310,6 +311,9 @@ class PaymentEntry(AccountsController):
+ "<br><br>" + _("If this is undesirable please cancel the corresponding Payment Entry."), + "<br><br>" + _("If this is undesirable please cancel the corresponding Payment Entry."),
title=_("Warning"), indicator="orange") title=_("Warning"), indicator="orange")
def validate_advance_tax_account(self):
if self.get('taxes') and not self.advance_tax_account:
frappe.throw(_('Please select advance tax account'))
def validate_journal_entry(self): def validate_journal_entry(self):
for d in self.get("references"): for d in self.get("references"):
@@ -396,11 +400,29 @@ class PaymentEntry(AccountsController):
if not self.apply_tax_withholding_amount: if not self.apply_tax_withholding_amount:
return return
reference_doclist = []
net_total = self.paid_amount
included_in_paid_amount = 0
if self.get('references'):
for doc in self.get('references'):
if doc.reference_doctype == 'Purchase Order':
reference_doclist.append(doc.reference_name)
if reference_doclist:
order_amount = frappe.db.get_all('Purchase Order', fields=['sum(net_total)'],
filters = {'name': ('in', reference_doclist), 'docstatus': 1,
'apply_tds': 1}, as_list=1)
if order_amount:
net_total = order_amount[0][0]
included_in_paid_amount = 1
args = frappe._dict({ args = frappe._dict({
'company': self.company, 'company': self.company,
'supplier': self.party, 'supplier': self.party,
'posting_date': self.posting_date, 'posting_date': self.posting_date,
'net_total': self.paid_amount 'net_total': net_total
}) })
tax_withholding_details = get_party_tax_withholding_details(args, self.tax_withholding_category) tax_withholding_details = get_party_tax_withholding_details(args, self.tax_withholding_category)
@@ -408,6 +430,8 @@ class PaymentEntry(AccountsController):
if not tax_withholding_details: if not tax_withholding_details:
return return
tax_withholding_details.update({'included_in_paid_amount': included_in_paid_amount})
accounts = [] accounts = []
for d in self.taxes: for d in self.taxes:
if d.account_head == tax_withholding_details.get("account_head"): if d.account_head == tax_withholding_details.get("account_head"):
@@ -424,18 +448,37 @@ class PaymentEntry(AccountsController):
self.remove(d) self.remove(d)
def set_amounts(self): def set_amounts(self):
self.set_amounts_after_tax() self.set_received_amount()
self.set_amounts_in_company_currency() self.set_amounts_in_company_currency()
self.set_amounts_after_tax()
self.set_total_allocated_amount() self.set_total_allocated_amount()
self.set_unallocated_amount() self.set_unallocated_amount()
self.set_difference_amount() self.set_difference_amount()
def set_received_amount(self):
self.base_received_amount = self.base_paid_amount
def set_amounts_after_tax(self): def set_amounts_after_tax(self):
self.paid_amount_after_tax = flt(flt(self.paid_amount) + flt(self.total_taxes_and_charges), applicable_tax = 0
base_applicable_tax = 0
for tax in self.get('taxes'):
if not tax.included_in_paid_amount:
amount = -1 * tax.tax_amount if tax.add_deduct_tax == 'Deduct' else tax.tax_amount
base_amount = -1 * tax.base_tax_amount if tax.add_deduct_tax == 'Deduct' else tax.base_tax_amount
applicable_tax += amount
base_applicable_tax += base_amount
self.paid_amount_after_tax = flt(flt(self.paid_amount) + flt(applicable_tax),
self.precision("paid_amount_after_tax")) self.precision("paid_amount_after_tax"))
self.base_paid_amount_after_tax = flt(flt(self.paid_amount_after_tax) * flt(self.source_exchange_rate), self.base_paid_amount_after_tax = flt(flt(self.paid_amount_after_tax) * flt(self.source_exchange_rate),
self.precision("base_paid_amount_after_tax")) self.precision("base_paid_amount_after_tax"))
self.received_amount_after_tax = flt(flt(self.received_amount) + flt(applicable_tax),
self.precision("paid_amount_after_tax"))
self.base_received_amount_after_tax = flt(flt(self.received_amount_after_tax) * flt(self.source_exchange_rate),
self.precision("base_paid_amount_after_tax"))
def set_amounts_in_company_currency(self): def set_amounts_in_company_currency(self):
self.base_paid_amount, self.base_received_amount, self.difference_amount = 0, 0, 0 self.base_paid_amount, self.base_received_amount, self.difference_amount = 0, 0, 0
if self.paid_amount: if self.paid_amount:
@@ -465,14 +508,14 @@ class PaymentEntry(AccountsController):
if self.party: if self.party:
total_deductions = sum([flt(d.amount) for d in self.get("deductions")]) total_deductions = sum([flt(d.amount) for d in self.get("deductions")])
if self.payment_type == "Receive" \ if self.payment_type == "Receive" \
and self.base_total_allocated_amount < self.base_received_amount + total_deductions \ and self.base_total_allocated_amount < self.base_received_amount_after_tax + total_deductions \
and self.total_allocated_amount < self.paid_amount + (total_deductions / self.source_exchange_rate): and self.total_allocated_amount < self.paid_amount_after_tax + (total_deductions / self.source_exchange_rate):
self.unallocated_amount = (self.base_received_amount + total_deductions - self.unallocated_amount = (self.received_amount_after_tax + total_deductions -
self.base_total_allocated_amount) / self.source_exchange_rate self.base_total_allocated_amount) / self.source_exchange_rate
elif self.payment_type == "Pay" \ elif self.payment_type == "Pay" \
and self.base_total_allocated_amount < (self.base_paid_amount - total_deductions) \ and self.base_total_allocated_amount < (self.base_paid_amount_after_tax - total_deductions) \
and self.total_allocated_amount < self.received_amount + (total_deductions / self.target_exchange_rate): and self.total_allocated_amount < self.received_amount_after_tax + (total_deductions / self.target_exchange_rate):
self.unallocated_amount = (self.base_paid_amount - (total_deductions + self.unallocated_amount = (self.base_paid_amount_after_tax - (total_deductions +
self.base_total_allocated_amount)) / self.target_exchange_rate self.base_total_allocated_amount)) / self.target_exchange_rate
def set_difference_amount(self): def set_difference_amount(self):
@@ -482,11 +525,11 @@ class PaymentEntry(AccountsController):
base_party_amount = flt(self.base_total_allocated_amount) + flt(base_unallocated_amount) base_party_amount = flt(self.base_total_allocated_amount) + flt(base_unallocated_amount)
if self.payment_type == "Receive": if self.payment_type == "Receive":
self.difference_amount = base_party_amount - self.base_received_amount self.difference_amount = base_party_amount - self.base_received_amount_after_tax
elif self.payment_type == "Pay": elif self.payment_type == "Pay":
self.difference_amount = self.base_paid_amount - base_party_amount self.difference_amount = self.base_paid_amount_after_tax - base_party_amount
else: else:
self.difference_amount = self.base_paid_amount - flt(self.base_received_amount) self.difference_amount = self.base_paid_amount_after_tax - flt(self.base_received_amount_after_tax)
total_deductions = sum([flt(d.amount) for d in self.get("deductions")]) total_deductions = sum([flt(d.amount) for d in self.get("deductions")])
@@ -616,7 +659,7 @@ class PaymentEntry(AccountsController):
gl_entries.append(gle) gl_entries.append(gle)
if self.unallocated_amount: if self.unallocated_amount:
base_unallocated_amount = base_unallocated_amount = self.unallocated_amount * \ base_unallocated_amount = self.unallocated_amount * \
(self.source_exchange_rate if self.payment_type=="Receive" else self.target_exchange_rate) (self.source_exchange_rate if self.payment_type=="Receive" else self.target_exchange_rate)
gle = party_gl_dict.copy() gle = party_gl_dict.copy()
@@ -646,8 +689,8 @@ class PaymentEntry(AccountsController):
"account": self.paid_to, "account": self.paid_to,
"account_currency": self.paid_to_account_currency, "account_currency": self.paid_to_account_currency,
"against": self.party if self.payment_type=="Receive" else self.paid_from, "against": self.party if self.payment_type=="Receive" else self.paid_from,
"debit_in_account_currency": self.received_amount, "debit_in_account_currency": self.received_amount_after_tax,
"debit": self.base_received_amount, "debit": self.base_received_amount_after_tax,
"cost_center": self.cost_center "cost_center": self.cost_center
}, item=self) }, item=self)
) )
@@ -660,8 +703,10 @@ class PaymentEntry(AccountsController):
if self.payment_type == 'Pay': if self.payment_type == 'Pay':
dr_or_cr = "debit" if d.add_deduct_tax == "Add" else "credit" dr_or_cr = "debit" if d.add_deduct_tax == "Add" else "credit"
rev_dr_cr = "credit" if d.add_deduct_tax == "Add" else "debit"
elif self.payment_type == 'Receive': elif self.payment_type == 'Receive':
dr_or_cr = "credit" if d.add_deduct_tax == "Add" else "debit" dr_or_cr = "credit" if d.add_deduct_tax == "Add" else "debit"
rev_dr_cr = "debit" if d.add_deduct_tax == "Add" else "credit"
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
@@ -672,8 +717,18 @@ class PaymentEntry(AccountsController):
if account_currency==self.company_currency \ if account_currency==self.company_currency \
else d.tax_amount, else d.tax_amount,
"cost_center": d.cost_center "cost_center": d.cost_center
}, account_currency, item=d) }, account_currency, item=d))
)
gl_entries.append(
self.get_gl_dict({
"account": self.advance_tax_account,
"against": self.party if self.payment_type=="Receive" else self.paid_from,
rev_dr_cr: d.base_tax_amount,
rev_dr_cr + "_in_account_currency": d.base_tax_amount \
if account_currency==self.company_currency \
else d.tax_amount,
"cost_center": d.cost_center
}, account_currency, item=d))
def add_deductions_gl_entries(self, gl_entries): def add_deductions_gl_entries(self, gl_entries):
for d in self.get("deductions"): for d in self.get("deductions"):

View File

@@ -456,6 +456,8 @@ class PurchaseInvoice(BuyingController):
self.make_tax_gl_entries(gl_entries) self.make_tax_gl_entries(gl_entries)
self.make_internal_transfer_gl_entries(gl_entries) self.make_internal_transfer_gl_entries(gl_entries)
self.allocate_advance_taxes(gl_entries)
gl_entries = make_regional_gl_entries(gl_entries, self) gl_entries = make_regional_gl_entries(gl_entries, self)
gl_entries = merge_similar_entries(gl_entries) gl_entries = merge_similar_entries(gl_entries)
@@ -899,6 +901,46 @@ class PurchaseInvoice(BuyingController):
"cost_center": self.cost_center "cost_center": self.cost_center
}, account_currency, item=self)) }, account_currency, item=self))
def allocate_advance_taxes(self, gl_entries):
tax_map = self.get_tax_map()
for pe in self.get('advances'):
pe = frappe.get_doc('Payment Entry', pe.reference_name)
for tax in pe.get('taxes'):
account_currency = get_account_currency(tax.account_head)
dr_or_cr = "credit" if tax.add_deduct_tax == "Add" else "debit"
rev_dr_cr = "debit" if tax.add_deduct_tax == "Add" else "credit"
unallocated_amount = tax.tax_amount - tax.allocated_amount
if tax_map.get(tax.account_head):
amount = tax_map.get(tax.account_head)
if amount < unallocated_amount:
unallocated_amount = amount
gl_entries.append(
self.get_gl_dict({
"account": tax.account_head,
"against": self.supplier,
dr_or_cr: unallocated_amount,
dr_or_cr + "_in_account_currency": unallocated_amount \
if account_currency==self.company_currency \
else unallocated_amount,
'cost_center': tax.cost_center
}, account_currency, item=tax))
gl_entries.append(
self.get_gl_dict({
"account": pe.advance_tax_account,
"against": self.supplier,
rev_dr_cr: unallocated_amount,
rev_dr_cr + "_in_account_currency": unallocated_amount \
if account_currency==self.company_currency \
else unallocated_amount,
'cost_center': tax.cost_center
}, account_currency, item=tax))
frappe.db.set_value('Advance Taxes and Charges', tax.name, 'allocated_amount', tax.allocated_amount + unallocated_amount)
tax_map[tax.account_head] -= unallocated_amount
def make_payment_gl_entries(self, gl_entries): def make_payment_gl_entries(self, gl_entries):
# Make Cash GL Entries # Make Cash GL Entries
if cint(self.is_paid) and self.cash_bank_account and self.paid_amount: if cint(self.is_paid) and self.cash_bank_account and self.paid_amount:
@@ -1088,9 +1130,9 @@ class PurchaseInvoice(BuyingController):
accounts = [] accounts = []
for d in self.taxes: for d in self.taxes:
if d.account_head == tax_withholding_details.get("account_head") and not d.is_advance_tax: if d.account_head == tax_withholding_details.get("account_head"):
d.update(tax_withholding_details) d.update(tax_withholding_details)
if not d.is_advance_tax:
accounts.append(d.account_head) accounts.append(d.account_head)
if not accounts or tax_withholding_details.get("account_head") not in accounts: if not accounts or tax_withholding_details.get("account_head") not in accounts:

View File

@@ -28,8 +28,7 @@
"base_tax_amount", "base_tax_amount",
"base_total", "base_total",
"base_tax_amount_after_discount_amount", "base_tax_amount_after_discount_amount",
"item_wise_tax_detail", "item_wise_tax_detail"
"is_advance_tax"
], ],
"fields": [ "fields": [
{ {
@@ -250,22 +249,12 @@
"fieldtype": "Column Break", "fieldtype": "Column Break",
"show_days": 1, "show_days": 1,
"show_seconds": 1 "show_seconds": 1
},
{
"default": "0",
"fieldname": "is_advance_tax",
"fieldtype": "Check",
"hidden": 1,
"label": "Is Advance Tax",
"read_only": 1,
"show_days": 1,
"show_seconds": 1
} }
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2020-10-25 18:24:43.487567", "modified": "2020-11-29 19:11:58.826078",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Taxes and Charges", "name": "Purchase Taxes and Charges",

View File

@@ -842,6 +842,8 @@ class SalesInvoice(SellingController):
self.make_tax_gl_entries(gl_entries) self.make_tax_gl_entries(gl_entries)
self.make_internal_transfer_gl_entries(gl_entries) self.make_internal_transfer_gl_entries(gl_entries)
self.allocate_advance_taxes(gl_entries)
self.make_item_gl_entries(gl_entries) self.make_item_gl_entries(gl_entries)
# merge gl entries before adding pos entries # merge gl entries before adding pos entries
@@ -911,6 +913,46 @@ class SalesInvoice(SellingController):
"cost_center": self.cost_center "cost_center": self.cost_center
}, account_currency, item=self)) }, account_currency, item=self))
def allocate_advance_taxes(self, gl_entries):
tax_map = self.get_tax_map()
for pe in self.get('advances'):
pe = frappe.get_doc('Payment Entry', pe.reference_name)
for tax in pe.get('taxes'):
account_currency = get_account_currency(tax.account_head)
dr_or_cr = "debit" if tax.add_deduct_tax == "Add" else "credit"
rev_dr_cr = "credit" if tax.add_deduct_tax == "Add" else "debit"
unallocated_amount = tax.tax_amount - tax.allocated_amount
if tax_map.get(tax.account_head):
amount = tax_map.get(tax.account_head)
if amount < unallocated_amount:
unallocated_amount = amount
gl_entries.append(
self.get_gl_dict({
"account": tax.account_head,
"against": self.customer,
dr_or_cr: unallocated_amount,
dr_or_cr + "_in_account_currency": unallocated_amount \
if account_currency==self.company_currency \
else unallocated_amount,
'cost_center': tax.cost_center
}, account_currency, item=tax))
gl_entries.append(
self.get_gl_dict({
"account": pe.advance_tax_account,
"against": self.customer,
rev_dr_cr: unallocated_amount,
rev_dr_cr + "_in_account_currency": unallocated_amount \
if account_currency==self.company_currency \
else unallocated_amount,
'cost_center': tax.cost_center
}, account_currency, item=tax))
frappe.db.set_value('Advance Taxes and Charges', tax.name, 'allocated_amount', tax.allocated_amount + unallocated_amount)
tax_map[tax.account_head] -= unallocated_amount
def make_item_gl_entries(self, gl_entries): def make_item_gl_entries(self, gl_entries):
# income account gl entries # income account gl entries
for item in self.get("items"): for item in self.get("items"):

View File

@@ -45,6 +45,14 @@ frappe.ui.form.on("Purchase Order", {
}); });
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype); erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
apply_tds: function(frm) {
if (!frm.doc.apply_tds) {
frm.set_value("tax_withholding_category", '');
} else {
frm.set_value("tax_withholding_category", frm.supplier_tds);
}
} }
}); });

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,7 @@ from erpnext.accounts.party import get_party_account_currency
from six import string_types from six import string_types
from erpnext.stock.doctype.item.item import get_item_defaults from erpnext.stock.doctype.item.item import get_item_defaults
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\ from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\
unlink_inter_company_doc unlink_inter_company_doc
@@ -39,11 +40,18 @@ class PurchaseOrder(BuyingController):
'percent_join_field': 'material_request' 'percent_join_field': 'material_request'
}] }]
def onload(self):
supplier_tds = frappe.db.get_value("Supplier", self.supplier, "tax_withholding_category")
self.set_onload("supplier_tds", supplier_tds)
def validate(self): def validate(self):
super(PurchaseOrder, self).validate() super(PurchaseOrder, self).validate()
self.set_status() self.set_status()
# apply tax withholding only if checked and applicable
self.set_tax_withholding()
self.validate_supplier() self.validate_supplier()
self.validate_schedule_date() self.validate_schedule_date()
validate_for_items(self) validate_for_items(self)
@@ -87,6 +95,33 @@ class PurchaseOrder(BuyingController):
if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')): if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')):
self.validate_rate_with_reference_doc([["Supplier Quotation", "supplier_quotation", "supplier_quotation_item"]]) self.validate_rate_with_reference_doc([["Supplier Quotation", "supplier_quotation", "supplier_quotation_item"]])
def set_tax_withholding(self):
if not self.apply_tds:
return
tax_withholding_details = get_party_tax_withholding_details(self, self.tax_withholding_category)
if not tax_withholding_details:
return
accounts = []
for d in self.taxes:
if d.account_head == tax_withholding_details.get("account_head"):
d.update(tax_withholding_details)
accounts.append(d.account_head)
if not accounts or tax_withholding_details.get("account_head") not in accounts:
self.append("taxes", tax_withholding_details)
to_remove = [d for d in self.taxes
if not d.tax_amount and d.account_head == tax_withholding_details.get("account_head")]
for d in to_remove:
self.remove(d)
# calculate totals again after applying TDS
self.calculate_taxes_and_totals()
def validate_supplier(self): def validate_supplier(self):
prevent_po = frappe.db.get_value("Supplier", self.supplier, 'prevent_pos') prevent_po = frappe.db.get_value("Supplier", self.supplier, 'prevent_pos')
if prevent_po: if prevent_po:

View File

@@ -700,6 +700,7 @@ class AccountsController(TransactionBase):
from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
if self.doctype in ["Sales Invoice", "Purchase Invoice"]: if self.doctype in ["Sales Invoice", "Purchase Invoice"]:
self.update_allocated_advance_taxes()
if frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'): if frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
unlink_ref_doc_from_payment_entries(self) unlink_ref_doc_from_payment_entries(self)
@@ -707,6 +708,35 @@ class AccountsController(TransactionBase):
if frappe.db.get_single_value('Accounts Settings', 'unlink_advance_payment_on_cancelation_of_order'): if frappe.db.get_single_value('Accounts Settings', 'unlink_advance_payment_on_cancelation_of_order'):
unlink_ref_doc_from_payment_entries(self) unlink_ref_doc_from_payment_entries(self)
def get_tax_map(self):
tax_map = {}
for tax in self.get('taxes'):
tax_map.setdefault(tax.account_head, 0.0)
tax_map[tax.account_head] += tax.tax_amount
return tax_map
def update_allocated_advance_taxes(self):
if self.get('advances'):
tax_accounts = [d.account_head for d in self.get('taxes')]
allocated_tax_map = frappe._dict(frappe.get_all('GL Entry', fields=['account', 'sum(credit - debit)'],
filters={'voucher_no': self.name, 'account': ('in', tax_accounts)},
group_by='account', as_list=1))
tax_map = self.get_tax_map()
for pe in self.get('advances'):
pe = frappe.get_doc('Payment Entry', pe.reference_name)
for tax in pe.get('taxes'):
allocated_amount = tax_map.get(tax.account_head) - allocated_tax_map.get(tax.account_head)
if allocated_amount > tax.tax_amount:
allocated_amount = tax.tax_amount
if allocated_amount:
frappe.db.set_value('Advance Taxes and Charges', tax.name, 'allocated_amount', tax.allocated_amount - allocated_amount)
tax_map[tax.account_head] -= allocated_amount
allocated_tax_map[tax.account_head] -= allocated_amount
def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield): def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield):
from erpnext.controllers.status_updater import get_allowance_for from erpnext.controllers.status_updater import get_allowance_for
item_allowance = {} item_allowance = {}

View File

@@ -40,7 +40,6 @@ class calculate_taxes_and_totals(object):
self.validate_conversion_rate() self.validate_conversion_rate()
self.calculate_item_values() self.calculate_item_values()
self.validate_item_tax_template() self.validate_item_tax_template()
self.apply_advance_taxes()
self.initialize_taxes() self.initialize_taxes()
self.determine_exclusive_rate() self.determine_exclusive_rate()
self.calculate_net_total() self.calculate_net_total()
@@ -684,33 +683,6 @@ class calculate_taxes_and_totals(object):
self.calculate_paid_amount() self.calculate_paid_amount()
def apply_advance_taxes(self):
if cint(self.doc.get('adjust_advance_taxes')):
if self.doc.get('advances'):
payment_entry_list = [d.reference_name for d in self.doc.get('advances')]
advance_taxes = get_advance_taxes(payment_entry_list)
accounts = []
# Remove already added advance taxes if any
for tax in self.doc.get('taxes'):
if tax.is_advance_tax:
self.doc.remove(tax)
else:
accounts.append(tax.account_head)
for tax in advance_taxes:
# Reverse add deduct from payment entry in invoice
if tax.account_head in accounts:
add_deduct_tax = 'Deduct' if tax.add_deduct_tax == 'Add' else 'Add'
tax.update({
'add_deduct_tax': add_deduct_tax,
'category': tax.get('category') or 'Total',
'is_advance_tax': 1,
'charge_type': 'On Net Total' if tax.charge_type == 'On Paid Amount' else tax.charge_type
})
self.doc.append('taxes', tax)
def get_itemised_tax_breakup_html(doc): def get_itemised_tax_breakup_html(doc):
if not doc.taxes: if not doc.taxes:
return return