Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Payment Entry): splitting outstanding rows as per payment terms (backport #27946) #28221

Merged
Changes from all commits
Commits
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
44 changes: 25 additions & 19 deletions erpnext/accounts/doctype/payment_entry/payment_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ def update_payment_schedule(self, cancel=0):
invoice_paid_amount_map[invoice_key]['outstanding'] = term.outstanding
invoice_paid_amount_map[invoice_key]['discounted_amt'] = ref.total_amount * (term.discount / 100)

for key, allocated_amount in iteritems(invoice_payment_amount_map):
for idx, (key, allocated_amount) in enumerate(iteritems(invoice_payment_amount_map), 1):
if not invoice_paid_amount_map.get(key):
frappe.throw(_('Payment term {0} not used in {1}').format(key[0], key[1]))

Expand All @@ -407,7 +407,7 @@ def update_payment_schedule(self, cancel=0):
(allocated_amount - discounted_amt, discounted_amt, allocated_amount, key[1], key[0]))
else:
if allocated_amount > outstanding:
frappe.throw(_('Cannot allocate more than {0} against payment term {1}').format(outstanding, key[0]))
frappe.throw(_('Row #{0}: Cannot allocate more than {1} against payment term {2}').format(idx, outstanding, key[0]))

if allocated_amount and outstanding:
frappe.db.sql("""
Expand Down Expand Up @@ -1053,12 +1053,6 @@ def get_outstanding_reference_documents(args):
party_account_currency = get_account_currency(args.get("party_account"))
company_currency = frappe.get_cached_value('Company', args.get("company"), "default_currency")

# Get negative outstanding sales /purchase invoices
negative_outstanding_invoices = []
if args.get("party_type") not in ["Student", "Employee"] and not args.get("voucher_no"):
negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"), args.get("party"),
args.get("party_account"), args.get("company"), party_account_currency, company_currency)

# Get positive outstanding sales /purchase invoices/ Fees
condition = ""
if args.get("voucher_type") and args.get("voucher_no"):
Expand Down Expand Up @@ -1105,6 +1099,12 @@ def get_outstanding_reference_documents(args):
orders_to_be_billed = get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"),
args.get("party"), args.get("company"), party_account_currency, company_currency, filters=args)

# Get negative outstanding sales /purchase invoices
negative_outstanding_invoices = []
if args.get("party_type") not in ["Student", "Employee"] and not args.get("voucher_no"):
negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"), args.get("party"),
args.get("party_account"), party_account_currency, company_currency, condition=condition)

data = negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed

if not data:
Expand Down Expand Up @@ -1137,22 +1137,26 @@ def split_invoices_based_on_payment_terms(outstanding_invoices):
'invoice_amount': flt(d.invoice_amount),
'outstanding_amount': flt(d.outstanding_amount),
'payment_amount': payment_term.payment_amount,
'payment_term': payment_term.payment_term,
'allocated_amount': payment_term.outstanding
'payment_term': payment_term.payment_term
}))

outstanding_invoices_after_split = []
if invoice_ref_based_on_payment_terms:
for idx, ref in invoice_ref_based_on_payment_terms.items():
voucher_no = outstanding_invoices[idx]['voucher_no']
voucher_type = outstanding_invoices[idx]['voucher_type']
voucher_no = ref[0]['voucher_no']
voucher_type = ref[0]['voucher_type']

frappe.msgprint(_("Spliting {} {} into {} rows as per payment terms").format(
frappe.msgprint(_("Spliting {} {} into {} row(s) as per Payment Terms").format(
voucher_type, voucher_no, len(ref)), alert=True)

outstanding_invoices.pop(idx - 1)
outstanding_invoices += invoice_ref_based_on_payment_terms[idx]
outstanding_invoices_after_split += invoice_ref_based_on_payment_terms[idx]

existing_row = list(filter(lambda x: x.get('voucher_no') == voucher_no, outstanding_invoices))
index = outstanding_invoices.index(existing_row[0])
outstanding_invoices.pop(index)

return outstanding_invoices
outstanding_invoices_after_split += outstanding_invoices
return outstanding_invoices_after_split

def get_orders_to_be_billed(posting_date, party_type, party,
company, party_account_currency, company_currency, cost_center=None, filters=None):
Expand Down Expand Up @@ -1219,7 +1223,7 @@ def get_orders_to_be_billed(posting_date, party_type, party,
return order_list

def get_negative_outstanding_invoices(party_type, party, party_account,
company, party_account_currency, company_currency, cost_center=None):
party_account_currency, company_currency, cost_center=None, condition=None):
voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"
supplier_condition = ""
if voucher_type == "Purchase Invoice":
Expand All @@ -1241,19 +1245,21 @@ def get_negative_outstanding_invoices(party_type, party, party_account,
`tab{voucher_type}`
where
{party_type} = %s and {party_account} = %s and docstatus = 1 and
company = %s and outstanding_amount < 0
outstanding_amount < 0
{supplier_condition}
{condition}
order by
posting_date, name
""".format(**{
"supplier_condition": supplier_condition,
"condition": condition,
"rounded_total_field": rounded_total_field,
"grand_total_field": grand_total_field,
"voucher_type": voucher_type,
"party_type": scrub(party_type),
"party_account": "debit_to" if party_type == "Customer" else "credit_to",
"cost_center": cost_center
}), (party, party_account, company), as_dict=True)
}), (party, party_account), as_dict=True)


@frappe.whitelist()
Expand Down