[optimize] Payment Reconciliation and Payment Tool
This commit is contained in:
parent
e19abfbe70
commit
d40d1e9a59
@ -6,6 +6,7 @@ import frappe
|
|||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
from frappe import msgprint, _
|
from frappe import msgprint, _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
from erpnext.accounts.utils import get_outstanding_invoices
|
||||||
|
|
||||||
class PaymentReconciliation(Document):
|
class PaymentReconciliation(Document):
|
||||||
def get_unreconciled_entries(self):
|
def get_unreconciled_entries(self):
|
||||||
@ -17,7 +18,7 @@ class PaymentReconciliation(Document):
|
|||||||
dr_or_cr = "credit_in_account_currency" if self.party_type == "Customer" \
|
dr_or_cr = "credit_in_account_currency" if self.party_type == "Customer" \
|
||||||
else "debit_in_account_currency"
|
else "debit_in_account_currency"
|
||||||
|
|
||||||
cond = self.check_condition(dr_or_cr)
|
cond = self.check_condition()
|
||||||
|
|
||||||
bank_account_condition = "t2.against_account like %(bank_cash_account)s" \
|
bank_account_condition = "t2.against_account like %(bank_cash_account)s" \
|
||||||
if self.bank_cash_account else "1=1"
|
if self.bank_cash_account else "1=1"
|
||||||
@ -65,65 +66,11 @@ class PaymentReconciliation(Document):
|
|||||||
|
|
||||||
def get_invoice_entries(self):
|
def get_invoice_entries(self):
|
||||||
#Fetch JVs, Sales and Purchase Invoices for 'invoices' to reconcile against
|
#Fetch JVs, Sales and Purchase Invoices for 'invoices' to reconcile against
|
||||||
non_reconciled_invoices = []
|
|
||||||
dr_or_cr = "debit_in_account_currency" if self.party_type == "Customer" else "credit_in_account_currency"
|
|
||||||
cond = self.check_condition(dr_or_cr)
|
|
||||||
|
|
||||||
invoice_list = frappe.db.sql("""
|
condition = self.check_condition()
|
||||||
select
|
|
||||||
voucher_no, voucher_type, posting_date,
|
|
||||||
ifnull(sum({dr_or_cr}), 0) as invoice_amount
|
|
||||||
from
|
|
||||||
`tabGL Entry`
|
|
||||||
where
|
|
||||||
party_type = %(party_type)s and party = %(party)s
|
|
||||||
and account = %(account)s and {dr_or_cr} > 0 {cond}
|
|
||||||
and (CASE
|
|
||||||
WHEN voucher_type = 'Journal Entry'
|
|
||||||
THEN ifnull(against_voucher, '') = ''
|
|
||||||
ELSE 1=1
|
|
||||||
END)
|
|
||||||
group by voucher_type, voucher_no
|
|
||||||
""".format(**{
|
|
||||||
"cond": cond,
|
|
||||||
"dr_or_cr": dr_or_cr
|
|
||||||
}), {
|
|
||||||
"party_type": self.party_type,
|
|
||||||
"party": self.party,
|
|
||||||
"account": self.receivable_payable_account,
|
|
||||||
}, as_dict=True)
|
|
||||||
|
|
||||||
for d in invoice_list:
|
non_reconciled_invoices = get_outstanding_invoices(self.party_type, self.party,
|
||||||
payment_amount = frappe.db.sql("""
|
self.receivable_payable_account, condition=condition)
|
||||||
select
|
|
||||||
ifnull(sum(ifnull({0}, 0)), 0)
|
|
||||||
from
|
|
||||||
`tabGL Entry`
|
|
||||||
where
|
|
||||||
party_type = %(party_type)s and party = %(party)s
|
|
||||||
and account = %(account)s and {0} > 0
|
|
||||||
and against_voucher_type = %(against_voucher_type)s
|
|
||||||
and ifnull(against_voucher, '') = %(against_voucher)s
|
|
||||||
""".format("credit_in_account_currency" if self.party_type == "Customer"
|
|
||||||
else "debit_in_account_currency"), {
|
|
||||||
"party_type": self.party_type,
|
|
||||||
"party": self.party,
|
|
||||||
"account": self.receivable_payable_account,
|
|
||||||
"against_voucher_type": d.voucher_type,
|
|
||||||
"against_voucher": d.voucher_no
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
payment_amount = payment_amount[0][0] if payment_amount else 0
|
|
||||||
|
|
||||||
if d.invoice_amount - payment_amount > 0.005:
|
|
||||||
non_reconciled_invoices.append({
|
|
||||||
'voucher_no': d.voucher_no,
|
|
||||||
'voucher_type': d.voucher_type,
|
|
||||||
'posting_date': d.posting_date,
|
|
||||||
'invoice_amount': flt(d.invoice_amount),
|
|
||||||
'outstanding_amount': flt(d.invoice_amount - payment_amount, 2)
|
|
||||||
})
|
|
||||||
|
|
||||||
self.add_invoice_entries(non_reconciled_invoices)
|
self.add_invoice_entries(non_reconciled_invoices)
|
||||||
|
|
||||||
@ -210,13 +157,18 @@ class PaymentReconciliation(Document):
|
|||||||
if not invoices_to_reconcile:
|
if not invoices_to_reconcile:
|
||||||
frappe.throw(_("Please select Allocated Amount, Invoice Type and Invoice Number in atleast one row"))
|
frappe.throw(_("Please select Allocated Amount, Invoice Type and Invoice Number in atleast one row"))
|
||||||
|
|
||||||
def check_condition(self, dr_or_cr):
|
def check_condition(self):
|
||||||
cond = self.from_date and " and posting_date >= '" + self.from_date + "'" or ""
|
cond = " and posting_date >= {0}".format(frappe.db.escape(self.from_date)) if self.from_date else ""
|
||||||
cond += self.to_date and " and posting_date <= '" + self.to_date + "'" or ""
|
cond += " and posting_date <= {0}".format(frappe.db.escape(self.to_date)) if self.to_date else ""
|
||||||
|
|
||||||
|
if self.party_type == "Customer":
|
||||||
|
dr_or_cr = "debit_in_account_currency"
|
||||||
|
else:
|
||||||
|
dr_or_cr = "credit_in_account_currency"
|
||||||
|
|
||||||
if self.minimum_amount:
|
if self.minimum_amount:
|
||||||
cond += " and {0} >= %s".format(dr_or_cr) % self.minimum_amount
|
cond += " and `{0}` >= {1}".format(dr_or_cr, flt(self.minimum_amount))
|
||||||
if self.maximum_amount:
|
if self.maximum_amount:
|
||||||
cond += " and {0} <= %s".format(dr_or_cr) % self.maximum_amount
|
cond += " and `{0}` <= {1}".format(dr_or_cr, flt(self.maximum_amount))
|
||||||
|
|
||||||
return cond
|
return cond
|
||||||
|
@ -63,20 +63,18 @@ def get_outstanding_vouchers(args):
|
|||||||
party_account_currency = get_account_currency(args.get("party_account"))
|
party_account_currency = get_account_currency(args.get("party_account"))
|
||||||
company_currency = frappe.db.get_value("Company", args.get("company"), "default_currency")
|
company_currency = frappe.db.get_value("Company", args.get("company"), "default_currency")
|
||||||
|
|
||||||
if args.get("party_type") == "Customer" and args.get("received_or_paid") == "Received":
|
if ((args.get("party_type") == "Customer" and args.get("received_or_paid") == "Paid")
|
||||||
amount_query = "ifnull(debit_in_account_currency, 0) - ifnull(credit_in_account_currency, 0)"
|
or (args.get("party_type") == "Supplier" and args.get("received_or_paid") == "Received")):
|
||||||
elif args.get("party_type") == "Supplier" and args.get("received_or_paid") == "Paid":
|
|
||||||
amount_query = "ifnull(credit_in_account_currency, 0) - ifnull(debit_in_account_currency, 0)"
|
|
||||||
else:
|
|
||||||
frappe.throw(_("Please enter the Against Vouchers manually"))
|
frappe.throw(_("Please enter the Against Vouchers manually"))
|
||||||
|
|
||||||
# Get all outstanding sales /purchase invoices
|
# Get all outstanding sales /purchase invoices
|
||||||
outstanding_invoices = get_outstanding_invoices(amount_query, args.get("party_account"),
|
outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"), args.get("party_account"))
|
||||||
args.get("party_type"), args.get("party"))
|
|
||||||
|
|
||||||
# Get all SO / PO which are not fully billed or aginst which full advance not paid
|
# Get all SO / PO which are not fully billed or aginst which full advance not paid
|
||||||
orders_to_be_billed = get_orders_to_be_billed(args.get("party_type"), args.get("party"),
|
orders_to_be_billed = get_orders_to_be_billed(args.get("party_type"), args.get("party"),
|
||||||
party_account_currency, company_currency)
|
party_account_currency, company_currency)
|
||||||
|
|
||||||
return outstanding_invoices + orders_to_be_billed
|
return outstanding_invoices + orders_to_be_billed
|
||||||
|
|
||||||
def get_orders_to_be_billed(party_type, party, party_account_currency, company_currency):
|
def get_orders_to_be_billed(party_type, party, party_account_currency, company_currency):
|
||||||
|
@ -211,7 +211,7 @@ def update_against_doc(d, jv_obj):
|
|||||||
|
|
||||||
if d['allocated_amt'] < d['unadjusted_amt']:
|
if d['allocated_amt'] < d['unadjusted_amt']:
|
||||||
jvd = frappe.db.sql("""
|
jvd = frappe.db.sql("""
|
||||||
select cost_center, balance, against_account, is_advance,
|
select cost_center, balance, against_account, is_advance,
|
||||||
account_type, exchange_rate, account_currency
|
account_type, exchange_rate, account_currency
|
||||||
from `tabJournal Entry Account` where name = %s
|
from `tabJournal Entry Account` where name = %s
|
||||||
""", d['voucher_detail_no'], as_dict=True)
|
""", d['voucher_detail_no'], as_dict=True)
|
||||||
@ -415,47 +415,63 @@ def get_stock_rbnb_difference(posting_date, company):
|
|||||||
# Amount should be credited
|
# Amount should be credited
|
||||||
return flt(stock_rbnb) + flt(sys_bal)
|
return flt(stock_rbnb) + flt(sys_bal)
|
||||||
|
|
||||||
def get_outstanding_invoices(amount_query, account, party_type, party):
|
def get_outstanding_invoices(party_type, party, account, condition=None):
|
||||||
all_outstanding_vouchers = []
|
outstanding_invoices = []
|
||||||
outstanding_voucher_list = frappe.db.sql("""
|
precision = frappe.get_precision("Sales Invoice", "outstanding_amount")
|
||||||
select
|
|
||||||
voucher_no, voucher_type, posting_date,
|
if party_type=="Customer":
|
||||||
ifnull(sum({amount_query}), 0) as invoice_amount
|
dr_or_cr = "ifnull(debit_in_account_currency, 0) - ifnull(credit_in_account_currency, 0)"
|
||||||
|
payment_dr_or_cr = "ifnull(payment_gl_entry.credit_in_account_currency, 0) - ifnull(payment_gl_entry.debit_in_account_currency, 0)"
|
||||||
|
else:
|
||||||
|
dr_or_cr = "ifnull(credit_in_account_currency, 0) - ifnull(debit_in_account_currency, 0)"
|
||||||
|
payment_dr_or_cr = "ifnull(payment_gl_entry.debit_in_account_currency, 0) - ifnull(payment_gl_entry.credit_in_account_currency, 0)"
|
||||||
|
|
||||||
|
invoice_list = frappe.db.sql("""select
|
||||||
|
voucher_no, voucher_type, posting_date,
|
||||||
|
ifnull(sum({dr_or_cr}), 0) as invoice_amount,
|
||||||
|
(
|
||||||
|
select
|
||||||
|
ifnull(sum(ifnull({payment_dr_or_cr}, 0)), 0)
|
||||||
|
from `tabGL Entry` payment_gl_entry
|
||||||
|
where
|
||||||
|
payment_gl_entry.against_voucher_type = invoice_gl_entry.voucher_type
|
||||||
|
and payment_gl_entry.against_voucher = invoice_gl_entry.voucher_no
|
||||||
|
and payment_gl_entry.party_type = invoice_gl_entry.party_type
|
||||||
|
and payment_gl_entry.party = invoice_gl_entry.party
|
||||||
|
and payment_gl_entry.account = invoice_gl_entry.account
|
||||||
|
and {payment_dr_or_cr} > 0
|
||||||
|
) as payment_amount
|
||||||
from
|
from
|
||||||
`tabGL Entry`
|
`tabGL Entry` invoice_gl_entry
|
||||||
where
|
where
|
||||||
account = %s and party_type=%s and party=%s and {amount_query} > 0
|
party_type = %(party_type)s
|
||||||
and (CASE
|
and party = %(party)s
|
||||||
WHEN voucher_type = 'Journal Entry'
|
and account = %(account)s
|
||||||
THEN ifnull(against_voucher, '') = ''
|
and {dr_or_cr} > 0
|
||||||
ELSE 1=1
|
{condition}
|
||||||
END)
|
and ((voucher_type = 'Journal Entry'
|
||||||
|
and (against_voucher = ''
|
||||||
|
or against_voucher is null))
|
||||||
|
or (voucher_type != 'Journal Entry'))
|
||||||
group by voucher_type, voucher_no
|
group by voucher_type, voucher_no
|
||||||
""".format(amount_query = amount_query), (account, party_type, party), as_dict = True)
|
having (invoice_amount - payment_amount) > 0.005""".format(
|
||||||
|
dr_or_cr = dr_or_cr,
|
||||||
|
payment_dr_or_cr = payment_dr_or_cr,
|
||||||
|
condition = condition or ""
|
||||||
|
), {
|
||||||
|
"party_type": party_type,
|
||||||
|
"party": party,
|
||||||
|
"account": account,
|
||||||
|
}, as_dict=True)
|
||||||
|
|
||||||
for d in outstanding_voucher_list:
|
for d in invoice_list:
|
||||||
payment_amount = frappe.db.sql("""
|
outstanding_invoices.append({
|
||||||
select ifnull(sum({amount_query}), 0)
|
'voucher_no': d.voucher_no,
|
||||||
from
|
'voucher_type': d.voucher_type,
|
||||||
`tabGL Entry`
|
'posting_date': d.posting_date,
|
||||||
where
|
'invoice_amount': flt(d.invoice_amount),
|
||||||
account = %s and party_type=%s and party=%s and {amount_query} < 0
|
'payment_amount': flt(d.payment_amount),
|
||||||
and against_voucher_type = %s and ifnull(against_voucher, '') = %s
|
'outstanding_amount': flt(d.invoice_amount - d.payment_amount, precision)
|
||||||
""".format(**{
|
})
|
||||||
"amount_query": amount_query
|
|
||||||
}), (account, party_type, party, d.voucher_type, d.voucher_no))
|
|
||||||
|
|
||||||
payment_amount = -1*payment_amount[0][0] if payment_amount else 0
|
return outstanding_invoices
|
||||||
precision = frappe.get_precision("Sales Invoice", "outstanding_amount")
|
|
||||||
|
|
||||||
if d.invoice_amount > payment_amount:
|
|
||||||
|
|
||||||
all_outstanding_vouchers.append({
|
|
||||||
'voucher_no': d.voucher_no,
|
|
||||||
'voucher_type': d.voucher_type,
|
|
||||||
'posting_date': d.posting_date,
|
|
||||||
'invoice_amount': flt(d.invoice_amount, precision),
|
|
||||||
'outstanding_amount': flt(d.invoice_amount - payment_amount, precision)
|
|
||||||
})
|
|
||||||
|
|
||||||
return all_outstanding_vouchers
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user