mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-02 03:39:11 +00:00
Bank reconciliation WIP
This commit is contained in:
@@ -2,7 +2,13 @@
|
|||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
|
|
||||||
frappe.ui.form.on('Bank Transaction', {
|
frappe.ui.form.on('Bank Transaction', {
|
||||||
refresh: function(frm) {
|
onload: function(frm) {
|
||||||
|
frm.set_query('payment_document', 'payment_entries', function(doc, cdt, cdn) {
|
||||||
|
return {
|
||||||
|
"filters": {
|
||||||
|
"name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice"]]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ erpnext.accounts.bankReconciliation = class BankReconciliation {
|
|||||||
|
|
||||||
make_reconciliation_tool() {
|
make_reconciliation_tool() {
|
||||||
const me = this;
|
const me = this;
|
||||||
console.log(me)
|
|
||||||
frappe.model.with_doctype("Bank Transaction", () => {
|
frappe.model.with_doctype("Bank Transaction", () => {
|
||||||
new erpnext.accounts.ReconciliationTool({
|
new erpnext.accounts.ReconciliationTool({
|
||||||
parent: me.parent,
|
parent: me.parent,
|
||||||
@@ -116,7 +115,6 @@ erpnext.accounts.bankTransactionUpload = class bankTransactionUpload {
|
|||||||
no_socketio: true,
|
no_socketio: true,
|
||||||
sample_url: "e.g. http://example.com/somefile.csv",
|
sample_url: "e.g. http://example.com/somefile.csv",
|
||||||
callback: function(attachment, r) {
|
callback: function(attachment, r) {
|
||||||
console.log(r)
|
|
||||||
if (!r.exc && r.message) {
|
if (!r.exc && r.message) {
|
||||||
me.data = r.message;
|
me.data = r.message;
|
||||||
me.setup_transactions_dom();
|
me.setup_transactions_dom();
|
||||||
@@ -432,16 +430,23 @@ erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
|||||||
|
|
||||||
show_dialog(data) {
|
show_dialog(data) {
|
||||||
const me = this;
|
const me = this;
|
||||||
|
|
||||||
|
frappe.db.get_value("Bank Account", me.data.bank_account, "account", (r) => {
|
||||||
|
me.gl_account = r.account;
|
||||||
|
})
|
||||||
|
|
||||||
frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.get_linked_payments',
|
frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.get_linked_payments',
|
||||||
{bank_transaction: data}
|
{bank_transaction: data, freeze:true, freeze_message:__("Finding linked payments")}
|
||||||
)
|
).then((result) => {
|
||||||
.then((result) => {
|
console.log(result)
|
||||||
me.make_dialog(result)
|
me.make_dialog(result)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
make_dialog(data) {
|
make_dialog(data) {
|
||||||
const me = this;
|
const me = this;
|
||||||
|
me.selected_payment = null;
|
||||||
|
|
||||||
const fields = [
|
const fields = [
|
||||||
{
|
{
|
||||||
fieldtype: 'Section Break',
|
fieldtype: 'Section Break',
|
||||||
@@ -459,18 +464,59 @@ erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldtype: 'Link',
|
fieldtype: 'Link',
|
||||||
fieldname: 'payment_entry',
|
fieldname: 'payment_doctype',
|
||||||
options: 'Payment Entry',
|
options: 'DocType',
|
||||||
label: 'Payment Entry',
|
label: 'Payment DocType',
|
||||||
get_query: () => {
|
get_query: () => {
|
||||||
return {
|
return {
|
||||||
filters : [
|
filters : {
|
||||||
["Payment Entry", "ifnull(clearance_date, '')", "=", ""],
|
"name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice"]]
|
||||||
["Payment Entry", "docstatus", "=", 1]
|
}
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fieldtype: 'Column Break',
|
||||||
|
fieldname: 'column_break_1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldtype: 'Dynamic Link',
|
||||||
|
fieldname: 'payment_entry',
|
||||||
|
options: 'payment_doctype',
|
||||||
|
label: 'Payment Document',
|
||||||
|
get_query: () => {
|
||||||
|
let dt = this.dialog.fields_dict.payment_doctype.value;
|
||||||
|
if (dt === "Payment Entry") {
|
||||||
|
return {
|
||||||
|
filters : [
|
||||||
|
["Payment Entry", "ifnull(clearance_date, '')", "=", ""],
|
||||||
|
["Payment Entry", "docstatus", "=", 1]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} else if (dt === "Journal Entry") {
|
||||||
|
return {
|
||||||
|
query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.journal_entry_query",
|
||||||
|
filters : {
|
||||||
|
"bank_account": this.data.bank_account
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (dt === "Sales Invoice") {
|
||||||
|
return {
|
||||||
|
query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.sales_invoices_query"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onchange: function() {
|
||||||
|
if (me.selected_payment !== this.value) {
|
||||||
|
me.selected_payment = this.value;
|
||||||
|
me.display_payment_details(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldtype: 'Section Break',
|
||||||
|
fieldname: 'section_break_3'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fieldtype: 'HTML',
|
fieldtype: 'HTML',
|
||||||
fieldname: 'payment_details'
|
fieldname: 'payment_details'
|
||||||
@@ -479,11 +525,12 @@ erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
|||||||
|
|
||||||
me.dialog = new frappe.ui.Dialog({
|
me.dialog = new frappe.ui.Dialog({
|
||||||
title: __("Choose a corresponding payment"),
|
title: __("Choose a corresponding payment"),
|
||||||
fields: fields
|
fields: fields,
|
||||||
|
size: "large"
|
||||||
});
|
});
|
||||||
|
|
||||||
const proposals_wrapper = me.dialog.fields_dict.payment_proposals.$wrapper;
|
const proposals_wrapper = me.dialog.fields_dict.payment_proposals.$wrapper;
|
||||||
if (data.length > 0) {
|
if (data && data.length > 0) {
|
||||||
data.map(value => {
|
data.map(value => {
|
||||||
proposals_wrapper.append(frappe.render_template("linked_payment_row", value))
|
proposals_wrapper.append(frappe.render_template("linked_payment_row", value))
|
||||||
})
|
})
|
||||||
@@ -494,26 +541,62 @@ erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
|||||||
|
|
||||||
$(me.dialog.body).on('click', '.reconciliation-btn', (e) => {
|
$(me.dialog.body).on('click', '.reconciliation-btn', (e) => {
|
||||||
const payment_entry = $(e.target).attr('data-name');
|
const payment_entry = $(e.target).attr('data-name');
|
||||||
|
const payment_doctype = $(e.target).attr('data-doctype');
|
||||||
frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.reconcile',
|
frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.reconcile',
|
||||||
{bank_transaction: me.bank_entry, payment_entry: payment_entry})
|
{bank_transaction: me.bank_entry, payment_doctype: payment_doctype, payment_entry: payment_entry})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
erpnext.accounts.ReconciliationTool.trigger_list_update();
|
erpnext.accounts.ReconciliationTool.trigger_list_update();
|
||||||
me.dialog.hide();
|
me.dialog.hide();
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
$(me.dialog.body).on('blur', '.input-with-feedback', (e) => {
|
|
||||||
if (e.target.value) {
|
|
||||||
e.preventDefault();
|
|
||||||
me.dialog.fields_dict['payment_details'].$wrapper.empty();
|
|
||||||
frappe.db.get_doc("Payment Entry", e.target.value)
|
|
||||||
.then(doc => {
|
|
||||||
const details_wrapper = me.dialog.fields_dict.payment_details.$wrapper;
|
|
||||||
details_wrapper.append(frappe.render_template("linked_payment_row", doc));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
me.dialog.show();
|
me.dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
display_payment_details(event) {
|
||||||
|
const me = this;
|
||||||
|
if (event.value) {
|
||||||
|
let dt = me.dialog.fields_dict.payment_doctype.value;
|
||||||
|
me.dialog.fields_dict['payment_details'].$wrapper.empty();
|
||||||
|
frappe.db.get_doc(dt, event.value)
|
||||||
|
.then(doc => {
|
||||||
|
let displayed_docs = []
|
||||||
|
if (dt === "Payment Entry") {
|
||||||
|
doc.currency = doc.payment_type == "Receive" ? doc.paid_to_account_currency : doc.paid_from_account_currency;
|
||||||
|
displayed_docs.push(doc);
|
||||||
|
} else if (dt === "Journal Entry") {
|
||||||
|
doc.accounts.forEach(payment => {
|
||||||
|
if (payment.account === me.gl_account) {
|
||||||
|
payment.posting_date = doc.posting_date;
|
||||||
|
payment.party = doc.pay_to_recd_from;
|
||||||
|
payment.reference_no = doc.cheque_no;
|
||||||
|
payment.reference_date = doc.cheque_date;
|
||||||
|
payment.currency = payment.account_currency;
|
||||||
|
payment.paid_amount = payment.credit > 0 ? payment.credit : payment.debit;
|
||||||
|
payment.name = doc.name;
|
||||||
|
displayed_docs.push(payment);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (dt === "Sales Invoice") {
|
||||||
|
doc.payments.forEach(payment => {
|
||||||
|
if (payment.clearance_date === null || payment.clearance_date === "") {
|
||||||
|
payment.posting_date = doc.posting_date;
|
||||||
|
payment.party = doc.customer;
|
||||||
|
payment.reference_no = doc.remarks;
|
||||||
|
payment.currency = doc.currency;
|
||||||
|
payment.paid_amount = payment.amount;
|
||||||
|
payment.name = doc.name;
|
||||||
|
displayed_docs.push(payment);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const details_wrapper = me.dialog.fields_dict.payment_details.$wrapper;
|
||||||
|
displayed_docs.forEach(values => {
|
||||||
|
details_wrapper.append(frappe.render_template("linked_payment_row", values));
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,76 +8,125 @@ from frappe import _
|
|||||||
import difflib
|
import difflib
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
|
from six import iteritems
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def reconcile(bank_transaction, payment_entry):
|
def reconcile(bank_transaction, payment_doctype, payment_entry):
|
||||||
transaction = frappe.get_doc("Bank Transaction", bank_transaction)
|
transaction = frappe.get_doc("Bank Transaction", bank_transaction)
|
||||||
payment_entry = frappe.get_doc("Payment Entry", payment_entry)
|
payment_entry = frappe.get_doc(payment_doctype, payment_entry)
|
||||||
|
|
||||||
if transaction.payment_entry:
|
if transaction.unallocated_amount == 0:
|
||||||
frappe.throw(_("This bank transaction is already linked to a payment entry"))
|
frappe.throw(_("This bank transaction is already fully reconciled"))
|
||||||
|
|
||||||
|
"""
|
||||||
if transaction.credit > 0 and payment_entry.payment_type == "Pay":
|
if transaction.credit > 0 and payment_entry.payment_type == "Pay":
|
||||||
frappe.throw(_("The selected payment entry should be linked with a debitor bank transaction"))
|
frappe.throw(_("The selected payment entry should be linked with a debitor bank transaction"))
|
||||||
|
|
||||||
if transaction.debit > 0 and payment_entry.payment_type == "Receive":
|
if transaction.debit > 0 and payment_entry.payment_type == "Receive":
|
||||||
frappe.throw(_("The selected payment entry should be linked with a creditor bank transaction"))
|
frappe.throw(_("The selected payment entry should be linked with a creditor bank transaction"))
|
||||||
|
"""
|
||||||
|
|
||||||
add_payment_to_transaction(transaction, payment_entry)
|
add_payment_to_transaction(transaction, payment_doctype, payment_entry)
|
||||||
clear_payment_entry(transaction, payment_entry)
|
#clear_payment_entry(transaction, payment_doctype, payment_entry)
|
||||||
|
|
||||||
return 'reconciled'
|
return 'reconciled'
|
||||||
|
|
||||||
def add_payment_to_transaction(transaction, payment_entry):
|
def add_payment_to_transaction(transaction, payment_doctype, payment_entry):
|
||||||
transaction.append("payment_entries", {"payment_entry": payment_entry.name})
|
transaction.append("payment_entries", {"payment_document": payment_doctype, "payment_entry": payment_entry.name})
|
||||||
transaction.save()
|
transaction.save()
|
||||||
|
|
||||||
def clear_payment_entry(transaction, payment_entry):
|
def clear_payment_entry(transaction, payment_doctype, payment_entry):
|
||||||
linked_bank_transactions = frappe.get_all("Bank Transaction", filters={"payment_entry": payment_entry, "docstatus": 1},
|
pass
|
||||||
|
"""
|
||||||
|
linked_bank_transactions = frappe.get_all("Bank Transaction Payments", filters={"payment_entry": payment_entry, "docstatus": 1},
|
||||||
fields=["sum(debit) as debit", "sum(credit) as credit"])
|
fields=["sum(debit) as debit", "sum(credit) as credit"])
|
||||||
|
|
||||||
cleared_amount = (flt(linked_bank_transactions[0].credit) - flt(linked_bank_transactions[0].debit))
|
cleared_amount = (flt(linked_bank_transactions[0].credit) - flt(linked_bank_transactions[0].debit))
|
||||||
|
|
||||||
if cleared_amount == payment_entry.paid_amount:
|
if cleared_amount == payment_entry.paid_amount:
|
||||||
frappe.db.set_value("Payment Entry", payment_entry.name, "clearance_date", transaction.date)
|
frappe.db.set_value(payment_doctype, payment_entry.name, "clearance_date", transaction.date)
|
||||||
|
"""
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_linked_payments(bank_transaction):
|
def get_linked_payments(bank_transaction):
|
||||||
|
|
||||||
transaction = frappe.get_doc("Bank Transaction", bank_transaction)
|
transaction = frappe.get_doc("Bank Transaction", bank_transaction)
|
||||||
|
bank_account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
|
||||||
|
|
||||||
# Get all payment entries with a matching amount
|
# Get all payment entries with a matching amount
|
||||||
amount_matching = check_matching_amount(transaction)
|
amount_matching = check_matching_amount(bank_account, transaction)
|
||||||
print(amount_matching)
|
print(amount_matching)
|
||||||
|
|
||||||
# Get some data from payment entries linked to a corresponding bank transaction
|
# Get some data from payment entries linked to a corresponding bank transaction
|
||||||
description_matching = check_matching_descriptions(transaction)
|
description_matching = get_matching_descriptions_data(bank_account, transaction)
|
||||||
print(description_matching)
|
print(description_matching)
|
||||||
|
|
||||||
"""
|
|
||||||
if amount_matching:
|
if amount_matching:
|
||||||
match = check_amount_vs_description(amount_matching, description_matching)
|
return check_amount_vs_description(amount_matching, description_matching)
|
||||||
if match:
|
|
||||||
return match
|
|
||||||
else:
|
|
||||||
return merge_matching_lists(amount_matching, description_matching)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
linked_payments = get_matching_transactions_payments(description_matching)
|
print("else")
|
||||||
return linked_payments
|
#linked_payments = get_matching_transactions_payments(description_matching)
|
||||||
"""
|
#return linked_payments
|
||||||
|
|
||||||
def check_matching_amount(transaction):
|
def check_matching_amount(bank_account, transaction):
|
||||||
|
payments = []
|
||||||
amount = transaction.credit if transaction.credit > 0 else transaction.debit
|
amount = transaction.credit if transaction.credit > 0 else transaction.debit
|
||||||
payment_type = "Receive" if transaction.credit > 0 else "Pay"
|
|
||||||
|
|
||||||
payments = frappe.get_all("Payment Entry", fields=["name", "paid_amount", "payment_type", "reference_no", "reference_date",
|
payment_type = "Receive" if transaction.credit > 0 else "Pay"
|
||||||
"party", "party_type", "posting_date", "paid_to_account_currency"], filters=[["paid_amount", "like", "{0}%".format(amount)],
|
account_from_to = "paid_to" if transaction.credit > 0 else "paid_from"
|
||||||
["docstatus", "=", "1"], ["payment_type", "=", payment_type], ["ifnull(clearance_date, '')", "=", ""]])
|
currency_field = "paid_to_account_currency as currency" if transaction.credit > 0 else "paid_from_account_currency as currency"
|
||||||
|
payment_entries = frappe.get_all("Payment Entry", fields=["'Payment Entry' as doctype", "name", "paid_amount", "payment_type", "reference_no", "reference_date",
|
||||||
|
"party", "party_type", "posting_date", "{0}".format(currency_field)], filters=[["paid_amount", "like", "{0}%".format(amount)],
|
||||||
|
["docstatus", "=", "1"], ["payment_type", "=", payment_type], ["ifnull(clearance_date, '')", "=", ""], ["{0}".format(account_from_to), "=", "{0}".format(bank_account)]])
|
||||||
|
|
||||||
|
payment_field = "jea.debit_in_account_currency" if transaction.credit > 0 else "jea.credit_in_account_currency"
|
||||||
|
journal_entries = frappe.db.sql("""
|
||||||
|
SELECT
|
||||||
|
'Journal Entry' as doctype, je.name, je.posting_date, je.cheque_no as reference_no,
|
||||||
|
je.pay_to_recd_from as party, je.cheque_date as reference_date, %s as paid_amount
|
||||||
|
FROM
|
||||||
|
`tabJournal Entry Account` as jea
|
||||||
|
JOIN
|
||||||
|
`tabJournal Entry` as je
|
||||||
|
ON
|
||||||
|
jea.parent = je.name
|
||||||
|
WHERE
|
||||||
|
(je.clearance_date is null or je.clearance_date='0000-00-00')
|
||||||
|
AND
|
||||||
|
jea.account = '%s'
|
||||||
|
AND
|
||||||
|
%s like '%s'
|
||||||
|
AND
|
||||||
|
je.docstatus = 1
|
||||||
|
""" % (payment_field, bank_account, payment_field, amount), as_dict=True)
|
||||||
|
|
||||||
|
sales_invoices = frappe.db.sql("""
|
||||||
|
SELECT
|
||||||
|
'Sales Invoice' as doctype, si.name, si.customer as party,
|
||||||
|
si.posting_date, sip.amount as paid_amount
|
||||||
|
FROM
|
||||||
|
`tabSales Invoice Payment` as sip
|
||||||
|
JOIN
|
||||||
|
`tabSales Invoice` as si
|
||||||
|
ON
|
||||||
|
sip.parent = si.name
|
||||||
|
WHERE
|
||||||
|
(sip.clearance_date is null or sip.clearance_date='0000-00-00')
|
||||||
|
AND
|
||||||
|
sip.account = '%s'
|
||||||
|
AND
|
||||||
|
sip.amount like '%s'
|
||||||
|
AND
|
||||||
|
si.docstatus = 1
|
||||||
|
""" % (bank_account, amount), as_dict=True)
|
||||||
|
|
||||||
|
for data in [payment_entries, journal_entries, sales_invoices]:
|
||||||
|
if data:
|
||||||
|
payments.extend(data)
|
||||||
|
|
||||||
return payments
|
return payments
|
||||||
|
|
||||||
def check_matching_descriptions(transaction):
|
def get_matching_descriptions_data(bank_account, transaction):
|
||||||
bank_transactions = frappe.db.sql("""
|
bank_transactions = frappe.db.sql("""
|
||||||
SELECT
|
SELECT
|
||||||
bt.name, bt.description, bt.date, btp.payment_document, btp.payment_entry
|
bt.name, bt.description, bt.date, btp.payment_document, btp.payment_entry
|
||||||
@@ -104,33 +153,42 @@ def check_matching_descriptions(transaction):
|
|||||||
|
|
||||||
document_types = set([x["payment_document"] for x in selection])
|
document_types = set([x["payment_document"] for x in selection])
|
||||||
|
|
||||||
|
links = {}
|
||||||
for document_type in document_types:
|
for document_type in document_types:
|
||||||
print(document_type)
|
links[document_type] = [x["payment_entry"] for x in selection if x["payment_document"]==document_type]
|
||||||
|
|
||||||
|
|
||||||
return selection
|
data = []
|
||||||
|
for key, value in iteritems(links):
|
||||||
|
if key == "Payment Entry":
|
||||||
|
data.extend(frappe.get_all("Payment Entry", filters=[["name", "in", value]], fields=["'Payment Entry' as doctype", "posting_date", "party", "reference_no", "reference_date", "paid_amount"]))
|
||||||
|
if key == "Journal Entry":
|
||||||
|
data.extend(frappe.get_all("Journal Entry", filters=[["name", "in", value]], fields=["'Journal Entry' as doctype", "posting_date", "paid_to_recd_from as party", "cheque_no as reference_no", "cheque_date as reference_date"]))
|
||||||
|
if key == "Sales Invoice":
|
||||||
|
data.extend(frappe.get_all("Sales Invoice", filters=[["name", "in", value]], fields=["'Sales Invoice' as doctype", "posting_date", "customer as party"]))
|
||||||
|
#if key == "Purchase Invoice":
|
||||||
|
# data.append(frappe.get_all("Purchase Invoice", filters=[["name", "in", value]], fields=["posting_date", "customer as party"]))
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
def check_amount_vs_description(amount_matching, description_matching):
|
def check_amount_vs_description(amount_matching, description_matching):
|
||||||
result = []
|
result = []
|
||||||
print(description_matching)
|
|
||||||
print(amount_matching)
|
|
||||||
for match in amount_matching:
|
|
||||||
m = [match for x in description_matching.payment_entries if match["name"]==x["payment_entry"]]
|
|
||||||
result.append(m)
|
|
||||||
print(result)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def merge_matching_lists(amount_matching, description_matching):
|
if description_matching:
|
||||||
|
for am_match in amount_matching:
|
||||||
|
for des_match in description_matching:
|
||||||
|
if am_match["party"] == des_match["party"]:
|
||||||
|
result.append(am_match)
|
||||||
|
continue
|
||||||
|
|
||||||
for match in amount_matching:
|
if hasattr(am_match, "reference_no") and hasattr(des_match, "reference_no"):
|
||||||
if match["name"] in map(itemgetter('payment_entry'), description_matching):
|
if difflib.SequenceMatcher(lambda x: x == " ", am_match["reference_no"], des_match["reference_no"]) > 70:
|
||||||
index = map(itemgetter('payment_entry'), description_matching).index(match["name"])
|
result.append(am_match)
|
||||||
del description_matching[index]
|
|
||||||
|
|
||||||
linked_payments = get_matching_transactions_payments(description_matching)
|
return sorted(result, key = lambda x: x["posting_date"], reverse=True)
|
||||||
|
|
||||||
result = amount_matching.append(linked_payments)
|
else:
|
||||||
return sorted(result, key = lambda x: x["posting_date"], reverse=True)
|
return sorted(amount_matching, key = lambda x: x["posting_date"], reverse=True)
|
||||||
|
|
||||||
def get_matching_transactions_payments(description_matching):
|
def get_matching_transactions_payments(description_matching):
|
||||||
payments = [x["payment_entry"] for x in description_matching]
|
payments = [x["payment_entry"] for x in description_matching]
|
||||||
@@ -145,3 +203,67 @@ def get_matching_transactions_payments(description_matching):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
def journal_entry_query(doctype, txt, searchfield, start, page_len, filters):
|
||||||
|
account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account")
|
||||||
|
|
||||||
|
return frappe.db.sql("""
|
||||||
|
SELECT
|
||||||
|
jea.parent, je.pay_to_recd_from,
|
||||||
|
if(jea.debit_in_account_currency > 0, jea.debit_in_account_currency, jea.credit_in_account_currency)
|
||||||
|
FROM
|
||||||
|
`tabJournal Entry Account` as jea
|
||||||
|
LEFT JOIN
|
||||||
|
`tabJournal Entry` as je
|
||||||
|
ON
|
||||||
|
jea.parent = je.name
|
||||||
|
WHERE
|
||||||
|
(je.clearance_date is null or je.clearance_date='0000-00-00')
|
||||||
|
AND
|
||||||
|
jea.account = %(account)s
|
||||||
|
AND
|
||||||
|
jea.parent like %(txt)s
|
||||||
|
AND
|
||||||
|
je.docstatus = 1
|
||||||
|
ORDER BY
|
||||||
|
if(locate(%(_txt)s, jea.parent), locate(%(_txt)s, jea.parent), 99999),
|
||||||
|
jea.parent
|
||||||
|
LIMIT
|
||||||
|
%(start)s, %(page_len)s""".format(**{
|
||||||
|
'key': searchfield,
|
||||||
|
}), {
|
||||||
|
'txt': "%%%s%%" % txt,
|
||||||
|
'_txt': txt.replace("%", ""),
|
||||||
|
'start': start,
|
||||||
|
'page_len': page_len,
|
||||||
|
'account': account
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def sales_invoices_query(doctype, txt, searchfield, start, page_len, filters):
|
||||||
|
return frappe.db.sql("""
|
||||||
|
SELECT
|
||||||
|
sip.parent, si.customer, sip.amount, sip.mode_of_payment
|
||||||
|
FROM
|
||||||
|
`tabSales Invoice Payment` as sip
|
||||||
|
LEFT JOIN
|
||||||
|
`tabSales Invoice` as si
|
||||||
|
ON
|
||||||
|
sip.parent = si.name
|
||||||
|
WHERE
|
||||||
|
(sip.clearance_date is null or sip.clearance_date='0000-00-00')
|
||||||
|
AND
|
||||||
|
sip.parent like %(txt)s
|
||||||
|
ORDER BY
|
||||||
|
if(locate(%(_txt)s, sip.parent), locate(%(_txt)s, sip.parent), 99999),
|
||||||
|
sip.parent
|
||||||
|
LIMIT
|
||||||
|
%(start)s, %(page_len)s""".format(**{
|
||||||
|
'key': searchfield,
|
||||||
|
}), {
|
||||||
|
'txt': "%%%s%%" % txt,
|
||||||
|
'_txt': txt.replace("%", ""),
|
||||||
|
'start': start,
|
||||||
|
'page_len': page_len
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -23,6 +23,8 @@
|
|||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu reports-dropdown" style="max-height: 300px; overflow-y: auto; right: 0px; left: auto;">
|
<ul class="dropdown-menu reports-dropdown" style="max-height: 300px; overflow-y: auto; right: 0px; left: auto;">
|
||||||
|
<li><a class="new-reconciliation" data-name={{ name }}>{{ __("Reconcile") }}</a></li>
|
||||||
|
<li class="divider"></li>
|
||||||
<li><a class="new-payment" data-name={{ name }}>{{ __("New Payment") }}</a></li>
|
<li><a class="new-payment" data-name={{ name }}>{{ __("New Payment") }}</a></li>
|
||||||
<li><a class="new-invoice" data-name={{ name }}>{{ __("New Invoice") }}</a></li>
|
<li><a class="new-invoice" data-name={{ name }}>{{ __("New Invoice") }}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -4,16 +4,22 @@
|
|||||||
<label class="control-label">{{ name }}</label>
|
<label class="control-label">{{ name }}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-5 ellipsis hidden-xs">
|
<div class="col-xs-5 ellipsis hidden-xs">
|
||||||
<h4>{{ __("Date:") }}</h4><h6> {{ posting_date }}</h6>
|
<h4>{{ __("Date") }}</h4><h6> {%= frappe.datetime.str_to_user(posting_date) %}</h6>
|
||||||
<h4>{{ __("Reference Date:") }}</h4><h6>{{ reference_date }}</h6>
|
{% if (typeof reference_date !== "undefined") %}
|
||||||
|
<h4>{{ __("Reference Date") }}</h4><h6>{%= frappe.datetime.str_to_user(reference_date) %}</h6>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-7 ellipsis list-subject">
|
<div class="col-xs-7 ellipsis list-subject">
|
||||||
<h4>{{ __("Amount:") }}</h4><h6>{{ format_currency(paid_amount, paid_to_account_currency) }}</h6>
|
<h4>{{ __("Amount") }}</h4><h6>{{ format_currency(paid_amount, currency) }}</h6>
|
||||||
<h4>{{ __("Party:") }}</h4><h6>{{ party }}</h6>
|
{% if (typeof party !== "undefined") %}
|
||||||
<h4>{{ __("Reference:") }}</h4><h6>{{ reference_no }}</h6>
|
<h4>{{ __("Party") }}</h4><h6>{{ party }}</h6>
|
||||||
|
{% endif %}
|
||||||
|
{% if (typeof reference_no !== "undefined") %}
|
||||||
|
<h4>{{ __("Reference") }}</h4><h6>{{ reference_no }}</h6>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-right margin-bottom">
|
<div class="text-right margin-bottom">
|
||||||
<button class="btn btn-primary btn-xs reconciliation-btn" data-name={{ name }}>{{ __("Reconcile") }}</button>
|
<button class="btn btn-primary btn-xs reconciliation-btn" data-doctype={{ doctype }} data-name={{ name }}>{{ __("Reconcile") }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user