mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-26 08:24:47 +00:00
WIP
This commit is contained in:
@@ -6,7 +6,7 @@ frappe.ui.form.on('Bank Transaction', {
|
|||||||
frm.set_query('payment_document', 'payment_entries', function(doc, cdt, cdn) {
|
frm.set_query('payment_document', 'payment_entries', function(doc, cdt, cdn) {
|
||||||
return {
|
return {
|
||||||
"filters": {
|
"filters": {
|
||||||
"name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice"]]
|
"name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice", "Expense Claim"]]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,13 +13,12 @@ class BankTransaction(Document):
|
|||||||
self.unallocated_amount = abs(flt(self.credit) - flt(self.debit))
|
self.unallocated_amount = abs(flt(self.credit) - flt(self.debit))
|
||||||
|
|
||||||
def on_update_after_submit(self):
|
def on_update_after_submit(self):
|
||||||
linked_payments = [x.payment_entry for x in self.payment_entries]
|
allocated_amount = reduce(lambda x, y: flt(x) + flt(y), [x.allocated_amount for x in self.payment_entries])
|
||||||
|
frappe.log_error(allocated_amount)
|
||||||
|
|
||||||
if linked_payments:
|
if allocated_amount:
|
||||||
allocated_amount = frappe.get_all("Payment Entry", filters=[["name", "in", linked_payments]], fields=["sum(paid_amount) as total"])
|
frappe.db.set_value(self.doctype, self.name, "allocated_amount", flt(allocated_amount))
|
||||||
|
frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.credit) - flt(self.debit)) - flt(allocated_amount))
|
||||||
frappe.db.set_value(self.doctype, self.name, "allocated_amount", flt(allocated_amount[0].total))
|
|
||||||
frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.credit) - flt(self.debit)) - flt(allocated_amount[0].total))
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
frappe.db.set_value(self.doctype, self.name, "allocated_amount", 0)
|
frappe.db.set_value(self.doctype, self.name, "allocated_amount", 0)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
import json
|
import json
|
||||||
from frappe.utils import getdate
|
from frappe.utils import getdate
|
||||||
|
from frappe.utils.dateutils import parse_date
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def upload_bank_statement():
|
def upload_bank_statement():
|
||||||
@@ -47,7 +48,7 @@ def create_bank_entries(columns, data, bank_account):
|
|||||||
"doctype": "Bank Transaction"
|
"doctype": "Bank Transaction"
|
||||||
})
|
})
|
||||||
bank_transaction.update(fields)
|
bank_transaction.update(fields)
|
||||||
bank_transaction.date = getdate(bank_transaction.date)
|
bank_transaction.date = getdate(parse_date(bank_transaction.date))
|
||||||
bank_transaction.bank_account = bank_account
|
bank_transaction.bank_account = bank_account
|
||||||
bank_transaction.insert()
|
bank_transaction.insert()
|
||||||
bank_transaction.submit()
|
bank_transaction.submit()
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"remember_last_selected_value": 0,
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
@@ -73,7 +73,39 @@
|
|||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"remember_last_selected_value": 0,
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 1,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"translatable": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "allocated_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 1,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Allocated Amount",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
@@ -90,7 +122,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2018-11-28 12:34:41.685571",
|
"modified": "2018-12-06 10:57:02.635141",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Bank Transaction Payments",
|
"name": "Bank Transaction Payments",
|
||||||
|
|||||||
@@ -3401,6 +3401,38 @@
|
|||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "clearance_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"hidden": 1,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Clearance Date",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"translatable": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
"allow_in_quick_entry": 0,
|
"allow_in_quick_entry": 0,
|
||||||
@@ -4726,7 +4758,11 @@
|
|||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"menu_index": 0,
|
"menu_index": 0,
|
||||||
|
<<<<<<< 31cb24f48d6d57cd8ab6991622c174390f6c2c51
|
||||||
"modified": "2019-01-07 16:51:59.800081",
|
"modified": "2019-01-07 16:51:59.800081",
|
||||||
|
=======
|
||||||
|
"modified": "2018-12-06 09:00:41.508642",
|
||||||
|
>>>>>>> WIP
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Invoice",
|
"name": "Purchase Invoice",
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ erpnext.accounts.bankReconciliation = class BankReconciliation {
|
|||||||
constructor(wrapper) {
|
constructor(wrapper) {
|
||||||
this.page = frappe.ui.make_app_page({
|
this.page = frappe.ui.make_app_page({
|
||||||
parent: wrapper,
|
parent: wrapper,
|
||||||
title: 'Bank Reconciliation',
|
title: __("Bank Reconciliation"),
|
||||||
single_column: true
|
single_column: true
|
||||||
});
|
});
|
||||||
this.parent = wrapper;
|
this.parent = wrapper;
|
||||||
this.page = this.parent.page;
|
this.page = this.parent.page;
|
||||||
|
|
||||||
this.make();
|
|
||||||
this.add_plaid_btn();
|
this.add_plaid_btn();
|
||||||
|
this.make();
|
||||||
}
|
}
|
||||||
|
|
||||||
make() {
|
make() {
|
||||||
@@ -44,9 +44,12 @@ erpnext.accounts.bankReconciliation = class BankReconciliation {
|
|||||||
const me = this;
|
const me = this;
|
||||||
frappe.db.get_value("Plaid Settings", "Plaid Settings", "enabled", (r) => {
|
frappe.db.get_value("Plaid Settings", "Plaid Settings", "enabled", (r) => {
|
||||||
if (r && r.enabled == "1") {
|
if (r && r.enabled == "1") {
|
||||||
|
me.plaid_status = "active"
|
||||||
me.parent.page.add_inner_button(__('Link a new bank account'), function() {
|
me.parent.page.add_inner_button(__('Link a new bank account'), function() {
|
||||||
new erpnext.accounts.plaidLink(this)
|
new erpnext.accounts.plaidLink(this)
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
me.plaid_status = "inactive"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -60,10 +63,14 @@ erpnext.accounts.bankReconciliation = class BankReconciliation {
|
|||||||
me.clear_page_content();
|
me.clear_page_content();
|
||||||
new erpnext.accounts.bankTransactionUpload(me);
|
new erpnext.accounts.bankTransactionUpload(me);
|
||||||
}, true)
|
}, true)
|
||||||
me.page.add_action_item(__("Synchronize this account"), function() {
|
|
||||||
me.clear_page_content();
|
if (me.plaid_status==="active") {
|
||||||
new erpnext.accounts.bankTransactionSync(me);
|
me.page.add_action_item(__("Synchronize this account"), function() {
|
||||||
}, true)
|
me.clear_page_content();
|
||||||
|
new erpnext.accounts.bankTransactionSync(me);
|
||||||
|
}, true)
|
||||||
|
}
|
||||||
|
|
||||||
me.page.add_action_item(__("Reconcile this account"), function() {
|
me.page.add_action_item(__("Reconcile this account"), function() {
|
||||||
me.clear_page_content();
|
me.clear_page_content();
|
||||||
me.make_reconciliation_tool();
|
me.make_reconciliation_tool();
|
||||||
@@ -79,7 +86,7 @@ erpnext.accounts.bankReconciliation = class BankReconciliation {
|
|||||||
make_reconciliation_tool() {
|
make_reconciliation_tool() {
|
||||||
const me = this;
|
const me = this;
|
||||||
frappe.model.with_doctype("Bank Transaction", () => {
|
frappe.model.with_doctype("Bank Transaction", () => {
|
||||||
new erpnext.accounts.ReconciliationTool({
|
erpnext.accounts.ReconciliationList = new erpnext.accounts.ReconciliationTool({
|
||||||
parent: me.parent,
|
parent: me.parent,
|
||||||
doctype: "Bank Transaction"
|
doctype: "Bank Transaction"
|
||||||
});
|
});
|
||||||
@@ -310,11 +317,13 @@ erpnext.accounts.ReconciliationTool = class ReconciliationTool extends frappe.vi
|
|||||||
constructor(opts) {
|
constructor(opts) {
|
||||||
super(opts);
|
super(opts);
|
||||||
this.show();
|
this.show();
|
||||||
|
console.log(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_defaults() {
|
setup_defaults() {
|
||||||
super.setup_defaults();
|
super.setup_defaults();
|
||||||
|
|
||||||
|
this.page_title = __("Bank Reconciliation");
|
||||||
this.doctype = 'Bank Transaction';
|
this.doctype = 'Bank Transaction';
|
||||||
this.fields = ['date', 'description', 'debit', 'credit', 'currency']
|
this.fields = ['date', 'description', 'debit', 'credit', 'currency']
|
||||||
|
|
||||||
@@ -374,11 +383,6 @@ erpnext.accounts.ReconciliationTool = class ReconciliationTool extends frappe.vi
|
|||||||
me.$result.append(frappe.render_template("bank_transaction_header"));
|
me.$result.append(frappe.render_template("bank_transaction_header"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static trigger_list_update() {
|
|
||||||
const reconciliation_list = erpnext.accounts.ReconciliationTool;
|
|
||||||
reconciliation_list && reconciliation_list.on_update();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
||||||
@@ -400,6 +404,11 @@ erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
|||||||
me.show_dialog($(this).attr("data-name"));
|
me.show_dialog($(this).attr("data-name"));
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$(me.row).on('click', '.new-reconciliation', function() {
|
||||||
|
me.bank_entry = $(this).attr("data-name");
|
||||||
|
me.show_dialog($(this).attr("data-name"));
|
||||||
|
})
|
||||||
|
|
||||||
$(me.row).on('click', '.new-payment', function() {
|
$(me.row).on('click', '.new-payment', function() {
|
||||||
me.bank_entry = $(this).attr("data-name");
|
me.bank_entry = $(this).attr("data-name");
|
||||||
me.new_payment();
|
me.new_payment();
|
||||||
@@ -438,7 +447,6 @@ erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
|||||||
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, freeze:true, freeze_message:__("Finding linked payments")}
|
{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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -470,7 +478,7 @@ erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
|||||||
get_query: () => {
|
get_query: () => {
|
||||||
return {
|
return {
|
||||||
filters : {
|
filters : {
|
||||||
"name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice"]]
|
"name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice", "Expense Claim"]]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -504,6 +512,20 @@ erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
|||||||
return {
|
return {
|
||||||
query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.sales_invoices_query"
|
query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.sales_invoices_query"
|
||||||
}
|
}
|
||||||
|
} else if (dt === "Purchase Invoice") {
|
||||||
|
return {
|
||||||
|
filters : [
|
||||||
|
["Purchase Invoice", "ifnull(clearance_date, '')", "=", ""],
|
||||||
|
["Purchase Invoice", "docstatus", "=", 1]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} else if (dt === "Expense Claim") {
|
||||||
|
return {
|
||||||
|
filters : [
|
||||||
|
["Expense Claim", "ifnull(clearance_date, '')", "=", ""],
|
||||||
|
["Expense Claim", "docstatus", "=", 1]
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onchange: function() {
|
onchange: function() {
|
||||||
@@ -531,6 +553,7 @@ erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
|||||||
|
|
||||||
const proposals_wrapper = me.dialog.fields_dict.payment_proposals.$wrapper;
|
const proposals_wrapper = me.dialog.fields_dict.payment_proposals.$wrapper;
|
||||||
if (data && data.length > 0) {
|
if (data && data.length > 0) {
|
||||||
|
proposals_wrapper.append(frappe.render_template("linked_payment_header"));
|
||||||
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))
|
||||||
})
|
})
|
||||||
@@ -543,9 +566,11 @@ erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
|||||||
const payment_entry = $(e.target).attr('data-name');
|
const payment_entry = $(e.target).attr('data-name');
|
||||||
const payment_doctype = $(e.target).attr('data-doctype');
|
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_doctype: payment_doctype, payment_entry: payment_entry})
|
{bank_transaction: me.bank_entry, payment_doctype: payment_doctype, payment_name: payment_entry})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
erpnext.accounts.ReconciliationTool.trigger_list_update();
|
setTimeout(function(){
|
||||||
|
erpnext.accounts.ReconciliationList.refresh();
|
||||||
|
}, 2000);
|
||||||
me.dialog.hide();
|
me.dialog.hide();
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -592,6 +617,7 @@ erpnext.accounts.ReconciliationRow = class ReconciliationRow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const details_wrapper = me.dialog.fields_dict.payment_details.$wrapper;
|
const details_wrapper = me.dialog.fields_dict.payment_details.$wrapper;
|
||||||
|
details_wrapper.append(frappe.render_template("linked_payment_header"));
|
||||||
displayed_docs.forEach(values => {
|
displayed_docs.forEach(values => {
|
||||||
details_wrapper.append(frappe.render_template("linked_payment_row", values));
|
details_wrapper.append(frappe.render_template("linked_payment_row", values));
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -11,41 +11,77 @@ from frappe.utils import flt
|
|||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def reconcile(bank_transaction, payment_doctype, payment_entry):
|
def reconcile(bank_transaction, payment_doctype, payment_name):
|
||||||
transaction = frappe.get_doc("Bank Transaction", bank_transaction)
|
transaction = frappe.get_doc("Bank Transaction", bank_transaction)
|
||||||
payment_entry = frappe.get_doc(payment_doctype, payment_entry)
|
payment_entry = frappe.get_doc(payment_doctype, payment_name)
|
||||||
|
|
||||||
|
account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
|
||||||
|
gl_entry = frappe.get_doc("GL Entry", dict(account=account, voucher_type=payment_doctype, voucher_no=payment_name))
|
||||||
|
|
||||||
if transaction.unallocated_amount == 0:
|
if transaction.unallocated_amount == 0:
|
||||||
frappe.throw(_("This bank transaction is already fully reconciled"))
|
frappe.throw(_("This bank transaction is already fully reconciled"))
|
||||||
|
|
||||||
"""
|
if transaction.credit > 0 and gl_entry.credit > 0:
|
||||||
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 gl_entry.debit > 0:
|
||||||
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_doctype, payment_entry)
|
add_payment_to_transaction(transaction, payment_entry, gl_entry)
|
||||||
#clear_payment_entry(transaction, payment_doctype, payment_entry)
|
clear_payment_entry(transaction, payment_entry, gl_entry)
|
||||||
|
|
||||||
return 'reconciled'
|
return 'reconciled'
|
||||||
|
|
||||||
def add_payment_to_transaction(transaction, payment_doctype, payment_entry):
|
def add_payment_to_transaction(transaction, payment_entry, gl_entry):
|
||||||
transaction.append("payment_entries", {"payment_document": payment_doctype, "payment_entry": payment_entry.name})
|
transaction.append("payment_entries", {
|
||||||
|
"payment_document": payment_entry.doctype,
|
||||||
|
"payment_entry": payment_entry.name,
|
||||||
|
"allocated_amount": gl_entry.credit if gl_entry.credit > 0 else gl_entry.debit
|
||||||
|
})
|
||||||
transaction.save()
|
transaction.save()
|
||||||
|
|
||||||
def clear_payment_entry(transaction, payment_doctype, payment_entry):
|
def clear_payment_entry(transaction, payment_entry, gl_entry):
|
||||||
pass
|
linked_bank_transactions = frappe.db.sql("""
|
||||||
"""
|
SELECT
|
||||||
linked_bank_transactions = frappe.get_all("Bank Transaction Payments", filters={"payment_entry": payment_entry, "docstatus": 1},
|
bt.credit, bt.debit
|
||||||
fields=["sum(debit) as debit", "sum(credit) as credit"])
|
FROM
|
||||||
|
`tabBank Transaction Payments` as btp
|
||||||
|
LEFT JOIN
|
||||||
|
`tabBank Transaction` as bt on btp.parent=bt.name
|
||||||
|
WHERE
|
||||||
|
btp.payment_document = '%s'
|
||||||
|
AND
|
||||||
|
btp.payment_entry = '%s'
|
||||||
|
AND
|
||||||
|
bt.docstatus = 1
|
||||||
|
""" % (payment_entry.doctype, payment_entry.name), as_dict=True)
|
||||||
|
|
||||||
cleared_amount = (flt(linked_bank_transactions[0].credit) - flt(linked_bank_transactions[0].debit))
|
amount_cleared = (flt(linked_bank_transactions[0].credit) - flt(linked_bank_transactions[0].debit))
|
||||||
|
amount_to_be_cleared = (flt(gl_entry.credit) - flt(gl_entry.debit))
|
||||||
|
|
||||||
if cleared_amount == payment_entry.paid_amount:
|
if payment_entry.doctype == "Payment Entry":
|
||||||
frappe.db.set_value(payment_doctype, payment_entry.name, "clearance_date", transaction.date)
|
clear_simple_entry(amount_cleared, amount_to_be_cleared, payment_entry, transaction)
|
||||||
"""
|
|
||||||
|
elif payment_entry.doctype == "Journal Entry":
|
||||||
|
clear_simple_entry(amount_cleared, amount_to_be_cleared, payment_entry, transaction)
|
||||||
|
|
||||||
|
elif payment_entry.doctype == "Sales Invoice":
|
||||||
|
clear_sales_invoice(amount_cleared, amount_to_be_cleared, payment_entry, transaction)
|
||||||
|
|
||||||
|
elif payment_entry.doctype == "Purchase Invoice":
|
||||||
|
clear_simple_entry(amount_cleared, amount_to_be_cleared, payment_entry, transaction)
|
||||||
|
|
||||||
|
elif payment_entry.doctype == "Expense Claim":
|
||||||
|
clear_simple_entry(amount_cleared, amount_to_be_cleared, payment_entry, transaction)
|
||||||
|
|
||||||
|
def clear_simple_entry(amount_cleared, amount_to_be_cleared, payment_entry, transaction):
|
||||||
|
if amount_cleared == amount_to_be_cleared:
|
||||||
|
frappe.db.set_value(payment_entry.doctype, payment_entry.name, "clearance_date", transaction.date)
|
||||||
|
|
||||||
|
def clear_sales_invoice(amount_cleared, amount_to_be_cleared, payment_entry, transaction):
|
||||||
|
if amount_cleared == amount_to_be_cleared:
|
||||||
|
frappe.db.set_value("Sales Invoice Payment", dict(parenttype=payment_entry.doctype,
|
||||||
|
parent=payment_entry.name), "clearance_date", transaction.date)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_linked_payments(bank_transaction):
|
def get_linked_payments(bank_transaction):
|
||||||
@@ -63,10 +99,11 @@ def get_linked_payments(bank_transaction):
|
|||||||
if amount_matching:
|
if amount_matching:
|
||||||
return check_amount_vs_description(amount_matching, description_matching)
|
return check_amount_vs_description(amount_matching, description_matching)
|
||||||
|
|
||||||
|
elif description_matching:
|
||||||
|
return sorted(description_matching, key = lambda x: x["posting_date"], reverse=True)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print("else")
|
return []
|
||||||
#linked_payments = get_matching_transactions_payments(description_matching)
|
|
||||||
#return linked_payments
|
|
||||||
|
|
||||||
def check_matching_amount(bank_account, transaction):
|
def check_matching_amount(bank_account, transaction):
|
||||||
payments = []
|
payments = []
|
||||||
@@ -147,10 +184,12 @@ def get_matching_descriptions_data(bank_account, transaction):
|
|||||||
if bank_transaction.description:
|
if bank_transaction.description:
|
||||||
seq=difflib.SequenceMatcher(lambda x: x == " ", transaction.description, bank_transaction.description)
|
seq=difflib.SequenceMatcher(lambda x: x == " ", transaction.description, bank_transaction.description)
|
||||||
|
|
||||||
if seq.ratio() > 0.5:
|
if seq.ratio() > 0.6:
|
||||||
bank_transaction["ratio"] = seq.ratio()
|
bank_transaction["ratio"] = seq.ratio()
|
||||||
selection.append(bank_transaction)
|
selection.append(bank_transaction)
|
||||||
|
|
||||||
|
print(selection)
|
||||||
|
|
||||||
document_types = set([x["payment_document"] for x in selection])
|
document_types = set([x["payment_document"] for x in selection])
|
||||||
|
|
||||||
links = {}
|
links = {}
|
||||||
@@ -165,9 +204,11 @@ def get_matching_descriptions_data(bank_account, transaction):
|
|||||||
if key == "Journal Entry":
|
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"]))
|
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":
|
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"]))
|
data.extend(frappe.get_all("Sales Invoice", filters=[["name", "in", value]], fields=["'Sales Invoice' as doctype", "posting_date", "customer_name as party"]))
|
||||||
#if key == "Purchase Invoice":
|
if key == "Purchase Invoice":
|
||||||
# data.append(frappe.get_all("Purchase Invoice", filters=[["name", "in", value]], fields=["posting_date", "customer as party"]))
|
data.append(frappe.get_all("Purchase Invoice", filters=[["name", "in", value]], fields=["'Purchase Invoice' as doctype", "posting_date", "supplier_name as party"]))
|
||||||
|
if key == "Purchase Invoice":
|
||||||
|
data.append(frappe.get_all("Expense Claim", filters=[["name", "in", value]], fields=["'Expense Claim' as doctype", "posting_date", "employee_name as party"]))
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@@ -178,14 +219,18 @@ def check_amount_vs_description(amount_matching, description_matching):
|
|||||||
for am_match in amount_matching:
|
for am_match in amount_matching:
|
||||||
for des_match in description_matching:
|
for des_match in description_matching:
|
||||||
if am_match["party"] == des_match["party"]:
|
if am_match["party"] == des_match["party"]:
|
||||||
result.append(am_match)
|
if am_match not in result:
|
||||||
continue
|
result.append(am_match)
|
||||||
|
continue
|
||||||
|
|
||||||
if hasattr(am_match, "reference_no") and hasattr(des_match, "reference_no"):
|
if hasattr(am_match, "reference_no") and hasattr(des_match, "reference_no"):
|
||||||
if difflib.SequenceMatcher(lambda x: x == " ", am_match["reference_no"], des_match["reference_no"]) > 70:
|
if difflib.SequenceMatcher(lambda x: x == " ", am_match["reference_no"], des_match["reference_no"]) > 70:
|
||||||
result.append(am_match)
|
if am_match not in result:
|
||||||
|
result.append(am_match)
|
||||||
return sorted(result, key = lambda x: x["posting_date"], reverse=True)
|
if result:
|
||||||
|
return sorted(result, key = lambda x: x["posting_date"], reverse=True)
|
||||||
|
else:
|
||||||
|
return sorted(amount_matching, key = lambda x: x["posting_date"], reverse=True)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return sorted(amount_matching, key = lambda x: x["posting_date"], reverse=True)
|
return sorted(amount_matching, key = lambda x: x["posting_date"], reverse=True)
|
||||||
@@ -222,7 +267,7 @@ def journal_entry_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
AND
|
AND
|
||||||
jea.account = %(account)s
|
jea.account = %(account)s
|
||||||
AND
|
AND
|
||||||
jea.parent like %(txt)s
|
(jea.parent like %(txt)s or je.pay_to_recd_from like %(txt)s)
|
||||||
AND
|
AND
|
||||||
je.docstatus = 1
|
je.docstatus = 1
|
||||||
ORDER BY
|
ORDER BY
|
||||||
@@ -253,7 +298,7 @@ def sales_invoices_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
WHERE
|
WHERE
|
||||||
(sip.clearance_date is null or sip.clearance_date='0000-00-00')
|
(sip.clearance_date is null or sip.clearance_date='0000-00-00')
|
||||||
AND
|
AND
|
||||||
sip.parent like %(txt)s
|
(sip.parent like %(txt)s or si.customer like %(txt)s)
|
||||||
ORDER BY
|
ORDER BY
|
||||||
if(locate(%(_txt)s, sip.parent), locate(%(_txt)s, sip.parent), 99999),
|
if(locate(%(_txt)s, sip.parent), locate(%(_txt)s, sip.parent), 99999),
|
||||||
sip.parent
|
sip.parent
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<div class="transaction-header">
|
||||||
|
<div class="level list-row list-row-head text-muted small">
|
||||||
|
<div class="col-xs-3 col-sm-2 ellipsis">
|
||||||
|
{{ __("Payment Name") }}
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-3 col-sm-2 ellipsis">
|
||||||
|
{{ __("Reference Date") }}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2 ellipsis hidden-xs">
|
||||||
|
{{ __("Amount") }}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2 ellipsis hidden-xs">
|
||||||
|
{{ __("Party") }}
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-3 col-sm-2 ellipsis">
|
||||||
|
{{ __("Reference Number") }}
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-2 col-sm-2">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -1,25 +1,36 @@
|
|||||||
<div class="grid-row">
|
<div class="list-row">
|
||||||
<div class="row">
|
<div>
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-3 col-sm-2 ellipsis">
|
||||||
<label class="control-label">{{ name }}</label>
|
{{ name }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-5 ellipsis hidden-xs">
|
<div class="col-xs-3 col-sm-2 ellipsis">
|
||||||
<h4>{{ __("Date") }}</h4><h6> {%= frappe.datetime.str_to_user(posting_date) %}</h6>
|
|
||||||
{% if (typeof reference_date !== "undefined") %}
|
{% if (typeof reference_date !== "undefined") %}
|
||||||
<h4>{{ __("Reference Date") }}</h4><h6>{%= frappe.datetime.str_to_user(reference_date) %}</h6>
|
{%= frappe.datetime.str_to_user(reference_date) %}
|
||||||
|
{% else %}
|
||||||
|
{% if (typeof posting_date !== "undefined") %}
|
||||||
|
{%= frappe.datetime.str_to_user(posting_date) %}
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-7 ellipsis list-subject">
|
<div class="col-sm-2 ellipsis hidden-xs">
|
||||||
<h4>{{ __("Amount") }}</h4><h6>{{ format_currency(paid_amount, currency) }}</h6>
|
{{ format_currency(paid_amount, currency) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2 ellipsis hidden-xs">
|
||||||
{% if (typeof party !== "undefined") %}
|
{% if (typeof party !== "undefined") %}
|
||||||
<h4>{{ __("Party") }}</h4><h6>{{ party }}</h6>
|
{{ party }}
|
||||||
{% endif %}
|
|
||||||
{% if (typeof reference_no !== "undefined") %}
|
|
||||||
<h4>{{ __("Reference") }}</h4><h6>{{ reference_no }}</h6>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-right margin-bottom">
|
<div class="col-xs-3 col-sm-2 ellipsis">
|
||||||
<button class="btn btn-primary btn-xs reconciliation-btn" data-doctype={{ doctype }} data-name={{ name }}>{{ __("Reconcile") }}</button>
|
{% if (typeof reference_no !== "undefined") %}
|
||||||
|
{{ reference_no }}
|
||||||
|
{% else %}
|
||||||
|
{{ "" }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-2 col-sm-2">
|
||||||
|
<div class="text-right margin-bottom">
|
||||||
|
<button class="btn btn-primary btn-xs reconciliation-btn" data-doctype="{{ doctype }}" data-name="{{ name }}">{{ __("Reconcile") }}</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -35,6 +35,11 @@ def get_data():
|
|||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Amazon MWS Settings",
|
"name": "Amazon MWS Settings",
|
||||||
"description": _("Connect Amazon with ERPNext"),
|
"description": _("Connect Amazon with ERPNext"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Plaid Settings",
|
||||||
|
"description": _("Connect your bank accounts to ERPNext"),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:doc.enabled==1",
|
"depends_on": "eval:(doc.enabled==1)&&(!doc.__islocal)",
|
||||||
"fieldname": "connect_btn",
|
"fieldname": "connect_btn",
|
||||||
"fieldtype": "Button",
|
"fieldtype": "Button",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2018-11-15 17:37:48.531027",
|
"modified": "2018-12-07 10:28:10.837885",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "ERPNext Integrations",
|
"module": "ERPNext Integrations",
|
||||||
"name": "Plaid Settings",
|
"name": "Plaid Settings",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
|
"allow_events_in_timeline": 0,
|
||||||
"allow_guest_to_view": 0,
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
@@ -843,6 +844,38 @@
|
|||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "clearance_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Clearance Date",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"translatable": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
"allow_in_quick_entry": 0,
|
"allow_in_quick_entry": 0,
|
||||||
@@ -1153,7 +1186,7 @@
|
|||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"menu_index": 0,
|
"menu_index": 0,
|
||||||
"modified": "2018-08-21 14:44:42.340662",
|
"modified": "2018-12-06 09:43:25.056554",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Expense Claim",
|
"name": "Expense Claim",
|
||||||
|
|||||||
Reference in New Issue
Block a user