Payment against negative invoice, negative outstanding allocation and much more
This commit is contained in:
@@ -193,6 +193,34 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
}, "icon-table");
|
}, "icon-table");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
payment_type: function(frm) {
|
||||||
|
if(frm.doc.payment_type == "Internal Transfer") {
|
||||||
|
$.each(["party", "party_balance", "paid_from", "paid_to",
|
||||||
|
"references", "total_allocated_amount"], function(i, field) {
|
||||||
|
frm.set_value(field, null);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if(!frm.doc.party)
|
||||||
|
frm.set_value("party_type", frm.doc.payment_type=="Receive" ? "Customer" : "Supplier");
|
||||||
|
else
|
||||||
|
frm.events.party(frm);
|
||||||
|
|
||||||
|
if(frm.doc.mode_of_payment)
|
||||||
|
frm.events.mode_of_payment(frm);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
party_type: function(frm) {
|
||||||
|
if(frm.doc.party) {
|
||||||
|
$.each(["party", "party_balance", "paid_from", "paid_to",
|
||||||
|
"paid_from_account_currency", "paid_from_account_balance",
|
||||||
|
"paid_to_account_currency", "paid_to_account_balance",
|
||||||
|
"references", "total_allocated_amount"], function(i, field) {
|
||||||
|
frm.set_value(field, null);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
party: function(frm) {
|
party: function(frm) {
|
||||||
if(frm.doc.payment_type && frm.doc.party_type && frm.doc.party) {
|
if(frm.doc.payment_type && frm.doc.party_type && frm.doc.party) {
|
||||||
@@ -227,18 +255,6 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
payment_type: function(frm) {
|
|
||||||
if(frm.doc.payment_type == "Internal Transfer") {
|
|
||||||
$.each(["party", "party_balance", "paid_from", "paid_to",
|
|
||||||
"references", "total_allocated_amount"], function(i, field) {
|
|
||||||
frm.set_value(field, null);
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
frm.set_value("party_type", frm.doc.payment_type=="Receive" ? "Customer" : "Supplier");
|
|
||||||
frm.events.party(frm);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mode_of_payment: function(frm) {
|
mode_of_payment: function(frm) {
|
||||||
return frappe.call({
|
return frappe.call({
|
||||||
@@ -279,7 +295,7 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
set_account_currency_and_balance: function(frm, account, currency_field,
|
set_account_currency_and_balance: function(frm, account, currency_field,
|
||||||
balance_field, callback_function) {
|
balance_field, callback_function) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_account_currency_and_balance",
|
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_account_details",
|
||||||
args: {
|
args: {
|
||||||
"account": account,
|
"account": account,
|
||||||
"date": frm.doc.posting_date
|
"date": frm.doc.posting_date
|
||||||
@@ -289,11 +305,16 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
frm.set_value(currency_field, r.message['account_currency']);
|
frm.set_value(currency_field, r.message['account_currency']);
|
||||||
frm.set_value(balance_field, r.message['account_balance']);
|
frm.set_value(balance_field, r.message['account_balance']);
|
||||||
|
|
||||||
if(frm.doc.payment_type == "Receive" && currency_field=="paid_to_account_currency"
|
if(frm.doc.payment_type=="Receive" && currency_field=="paid_to_account_currency") {
|
||||||
&& !frm.doc.received_amount && frm.doc.paid_amount) {
|
frm.toggle_reqd(["reference_no", "reference_date"],
|
||||||
|
(r.message['account_type'] == "Bank" ? 1 : 0));
|
||||||
|
if(!frm.doc.received_amount && frm.doc.paid_amount)
|
||||||
frm.events.paid_amount(frm);
|
frm.events.paid_amount(frm);
|
||||||
} else if(frm.doc.payment_type == "Pay" && currency_field=="paid_from_account_currency"
|
} else if(frm.doc.payment_type=="Pay" && currency_field=="paid_from_account_currency") {
|
||||||
&& !frm.doc.paid_amount && frm.doc.received_amount) {
|
frm.toggle_reqd(["reference_no", "reference_date"],
|
||||||
|
(r.message['account_type'] == "Bank" ? 1 : 0));
|
||||||
|
|
||||||
|
if(!frm.doc.paid_amount && frm.doc.received_amount)
|
||||||
frm.events.received_amount(frm);
|
frm.events.received_amount(frm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,16 +441,22 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
},
|
},
|
||||||
callback: function(r, rt) {
|
callback: function(r, rt) {
|
||||||
if(r.message) {
|
if(r.message) {
|
||||||
var total_invoice_outstanding_amount = 0;
|
var total_positive_outstanding = 0;
|
||||||
|
var total_negative_outstanding = 0;
|
||||||
|
|
||||||
$.each(r.message, function(i, d) {
|
$.each(r.message, function(i, d) {
|
||||||
var c = frm.add_child("references");
|
var c = frm.add_child("references");
|
||||||
c.reference_doctype = d.voucher_type;
|
c.reference_doctype = d.voucher_type;
|
||||||
c.reference_name = d.voucher_no;
|
c.reference_name = d.voucher_no;
|
||||||
c.total_amount = d.invoice_amount;
|
c.total_amount = d.invoice_amount;
|
||||||
c.outstanding_amount = d.outstanding_amount;
|
c.outstanding_amount = d.outstanding_amount;
|
||||||
if(!in_list(["Sales Order", "Purchase Order"], d.voucher_type))
|
if(!in_list(["Sales Order", "Purchase Order"], d.voucher_type)) {
|
||||||
total_invoice_outstanding_amount += flt(d.outstanding_amount);
|
if(flt(d.outstanding_amount) > 0)
|
||||||
|
total_positive_outstanding += flt(d.outstanding_amount);
|
||||||
|
else
|
||||||
|
total_negative_outstanding += Math.abs(flt(d.outstanding_amount));
|
||||||
|
}
|
||||||
|
|
||||||
var party_account_currency = frm.doc.payment_type=="Receive" ?
|
var party_account_currency = frm.doc.payment_type=="Receive" ?
|
||||||
frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency;
|
frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency;
|
||||||
|
|
||||||
@@ -439,33 +466,83 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
c.exchange_rate = 1;
|
c.exchange_rate = 1;
|
||||||
}
|
}
|
||||||
if (in_list(['Sales Invoice', 'Purchase Invoice'], d.reference_doctype)){
|
if (in_list(['Sales Invoice', 'Purchase Invoice'], d.reference_doctype)){
|
||||||
c.due_date = d.due_date
|
c.due_date = d.due_date;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if(total_invoice_outstanding_amount > 0) {
|
if((frm.doc.payment_type=="Receive" && frm.doc.party_type=="Customer") ||
|
||||||
var party_amt_field = (frm.doc.payment_type=="Receive") ?
|
(frm.doc.payment_type=="Pay" && frm.doc.party_type=="Supplier")) {
|
||||||
"paid_amount" : "received_amount";
|
if(total_positive_outstanding > total_negative_outstanding)
|
||||||
frm.set_value(party_amt_field, total_invoice_outstanding_amount);
|
frm.set_value("paid_amount",
|
||||||
|
total_positive_outstanding - total_negative_outstanding);
|
||||||
|
} else if (total_negative_outstanding &&
|
||||||
|
(total_positive_outstanding < total_negative_outstanding)) {
|
||||||
|
frm.set_value("received_amount",
|
||||||
|
total_negative_outstanding - total_positive_outstanding);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
frm.events.allocate_party_amount_against_ref_docs(frm,
|
frm.events.allocate_party_amount_against_ref_docs(frm,
|
||||||
(frm.doc.payment_type=="Receive" ? frm.doc.paid_amount : frm.doc.received_amount));
|
(frm.doc.payment_type=="Receive" ? frm.doc.paid_amount : frm.doc.received_amount));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
allocate_party_amount_against_ref_docs: function(frm, amount) {
|
allocate_party_amount_against_ref_docs: function(frm, paid_amount) {
|
||||||
|
var total_positive_outstanding_including_order = 0;
|
||||||
|
var total_negative_outstanding = 0;
|
||||||
|
|
||||||
|
$.each(frm.doc.references || [], function(i, row) {
|
||||||
|
if(flt(row.outstanding_amount) > 0)
|
||||||
|
total_positive_outstanding_including_order += flt(row.outstanding_amount);
|
||||||
|
else
|
||||||
|
total_negative_outstanding += Math.abs(flt(row.outstanding_amount));
|
||||||
|
})
|
||||||
|
|
||||||
|
var allocated_negative_outstanding = 0;
|
||||||
|
if((frm.doc.payment_type=="Receive" && frm.doc.party_type=="Customer") ||
|
||||||
|
(frm.doc.payment_type=="Pay" && frm.doc.party_type=="Supplier")) {
|
||||||
|
if(total_positive_outstanding_including_order > paid_amount) {
|
||||||
|
var remaining_outstanding = total_positive_outstanding_including_order - paid_amount;
|
||||||
|
allocated_negative_outstanding = total_negative_outstanding < remaining_outstanding ?
|
||||||
|
total_negative_outstanding : remaining_outstanding;
|
||||||
|
}
|
||||||
|
|
||||||
|
var allocated_positive_outstanding = paid_amount + allocated_negative_outstanding;
|
||||||
|
} else {
|
||||||
|
if(paid_amount > total_negative_outstanding) {
|
||||||
|
if(total_negative_outstanding == 0) {
|
||||||
|
frappe.msgprint(__("Cannot {0} {1} {2} without any negative outstanding invoice",
|
||||||
|
[frm.doc.payment_type,
|
||||||
|
(frm.doc.party_type=="Customer" ? "to" : "from"), frm.doc.party_type]));
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
frappe.msgprint(__("Paid Amount cannot be greater than total negative outstanding amount {0}", [total_negative_outstanding]));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
allocated_positive_outstanding = total_negative_outstanding - paid_amount;
|
||||||
|
allocated_negative_outstanding = paid_amount +
|
||||||
|
(total_positive_outstanding_including_order < allocated_positive_outstanding ?
|
||||||
|
total_positive_outstanding_including_order : allocated_positive_outstanding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$.each(frm.doc.references || [], function(i, row) {
|
$.each(frm.doc.references || [], function(i, row) {
|
||||||
row.allocated_amount = 0
|
row.allocated_amount = 0
|
||||||
|
|
||||||
if(amount) {
|
if(row.outstanding_amount > 0 && allocated_positive_outstanding > 0) {
|
||||||
if(row.outstanding_amount >= amount) row.allocated_amount = amount;
|
if(row.outstanding_amount >= allocated_positive_outstanding)
|
||||||
|
row.allocated_amount = allocated_positive_outstanding;
|
||||||
else row.allocated_amount = row.outstanding_amount;
|
else row.allocated_amount = row.outstanding_amount;
|
||||||
|
|
||||||
amount -= flt(row.allocated_amount);
|
allocated_positive_outstanding -= flt(row.allocated_amount);
|
||||||
|
} else if (row.outstanding_amount < 0 && allocated_negative_outstanding) {
|
||||||
|
if(Math.abs(row.outstanding_amount) >= allocated_negative_outstanding)
|
||||||
|
row.allocated_amount = -1*allocated_negative_outstanding;
|
||||||
|
else row.allocated_amount = row.outstanding_amount;
|
||||||
|
|
||||||
|
allocated_negative_outstanding -= Math.abs(flt(row.allocated_amount));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
frm.refresh_fields()
|
frm.refresh_fields()
|
||||||
@@ -476,23 +553,13 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
var total_allocated_amount = base_total_allocated_amount = 0.0;
|
var total_allocated_amount = base_total_allocated_amount = 0.0;
|
||||||
$.each(frm.doc.references || [], function(i, row) {
|
$.each(frm.doc.references || [], function(i, row) {
|
||||||
if (row.allocated_amount) {
|
if (row.allocated_amount) {
|
||||||
if (flt(row.allocated_amount) <= row.outstanding_amount) {
|
total_allocated_amount += flt(row.allocated_amount);
|
||||||
total_allocated_amount += flt(row.allocated_amount);
|
base_total_allocated_amount += flt(flt(row.allocated_amount)*flt(row.exchange_rate),
|
||||||
base_total_allocated_amount += flt(flt(row.allocated_amount)*flt(row.exchange_rate),
|
precision("base_paid_amount"));
|
||||||
precision("base_paid_amount"));
|
|
||||||
} else {
|
|
||||||
if(flt(row.allocated_amount) < 0)
|
|
||||||
frappe.throw(__("Row {0}: Allocated amount can not be negative", [row.idx]));
|
|
||||||
else if(flt(row.allocated_amount) > flt(row.outstanding_amount))
|
|
||||||
frappe.throw(__("Row {0}: Allocated Amount cannot be greater than Outstanding Amount",
|
|
||||||
[__(row.idx)]));
|
|
||||||
|
|
||||||
frappe.model.set_value(row.doctype, row.name, "allocated_amount", 0.0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
frm.set_value("total_allocated_amount", total_allocated_amount);
|
frm.set_value("total_allocated_amount", Math.abs(total_allocated_amount));
|
||||||
frm.set_value("base_total_allocated_amount", base_total_allocated_amount);
|
frm.set_value("base_total_allocated_amount", Math.abs(base_total_allocated_amount));
|
||||||
|
|
||||||
frm.events.set_difference_amount(frm);
|
frm.events.set_difference_amount(frm);
|
||||||
},
|
},
|
||||||
@@ -534,7 +601,11 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
|
|
||||||
check_mandatory_to_fetch: function(frm) {
|
check_mandatory_to_fetch: function(frm) {
|
||||||
$.each(["Company", "Party Type", "Party", "payment_type"], function(i, field) {
|
$.each(["Company", "Party Type", "Party", "payment_type"], function(i, field) {
|
||||||
if(!frm.doc[frappe.model.scrub(field)]) frappe.throw(__("Please select {0} first", [field]));
|
if(!frm.doc[frappe.model.scrub(field)]) {
|
||||||
|
frappe.msgprint(__("Please select {0} first", [field]));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -612,6 +683,27 @@ frappe.ui.form.on('Payment Entry Reference', {
|
|||||||
frm.events.validate_reference_document(frm, row);
|
frm.events.validate_reference_document(frm, row);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
reference_name: function(frm, cdt, cdn) {
|
||||||
|
var row = locals[cdt][cdn];
|
||||||
|
return frappe.call({
|
||||||
|
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_reference_details",
|
||||||
|
args: {
|
||||||
|
reference_doctype: row.reference_doctype,
|
||||||
|
reference_name: row.reference_name,
|
||||||
|
party_account_currency: frm.doc.payment_type=="Receive" ?
|
||||||
|
frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency
|
||||||
|
},
|
||||||
|
callback: function(r, rt) {
|
||||||
|
if(r.message) {
|
||||||
|
$.each(r.message, function(field, value) {
|
||||||
|
frappe.model.set_value(cdt, cdn, field, value);
|
||||||
|
})
|
||||||
|
frm.refresh_fields();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
allocated_amount: function(frm) {
|
allocated_amount: function(frm) {
|
||||||
frm.events.set_total_allocated_amount(frm);
|
frm.events.set_total_allocated_amount(frm);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, json
|
import frappe, json
|
||||||
from frappe import _, scrub
|
from frappe import _, scrub, ValidationError
|
||||||
from frappe.utils import flt, comma_or, nowdate
|
from frappe.utils import flt, comma_or, nowdate
|
||||||
from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on
|
from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on
|
||||||
from erpnext.accounts.party import get_party_account
|
from erpnext.accounts.party import get_party_account
|
||||||
@@ -15,6 +15,7 @@ from erpnext.accounts.general_ledger import make_gl_entries
|
|||||||
|
|
||||||
from erpnext.controllers.accounts_controller import AccountsController
|
from erpnext.controllers.accounts_controller import AccountsController
|
||||||
|
|
||||||
|
class InvalidPaymentEntry(ValidationError): pass
|
||||||
|
|
||||||
class PaymentEntry(AccountsController):
|
class PaymentEntry(AccountsController):
|
||||||
def setup_party_account_field(self):
|
def setup_party_account_field(self):
|
||||||
@@ -42,8 +43,9 @@ class PaymentEntry(AccountsController):
|
|||||||
self.validate_reference_documents()
|
self.validate_reference_documents()
|
||||||
self.set_amounts()
|
self.set_amounts()
|
||||||
self.clear_unallocated_reference_document_rows()
|
self.clear_unallocated_reference_document_rows()
|
||||||
self.set_title()
|
self.validate_payment_against_negative_invoice()
|
||||||
self.validate_transaction_reference()
|
self.validate_transaction_reference()
|
||||||
|
self.set_title()
|
||||||
self.set_remarks()
|
self.set_remarks()
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
@@ -51,6 +53,7 @@ class PaymentEntry(AccountsController):
|
|||||||
self.update_advance_paid()
|
self.update_advance_paid()
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
|
self.setup_party_account_field()
|
||||||
self.make_gl_entries(cancel=1)
|
self.make_gl_entries(cancel=1)
|
||||||
self.update_advance_paid()
|
self.update_advance_paid()
|
||||||
|
|
||||||
@@ -78,12 +81,12 @@ class PaymentEntry(AccountsController):
|
|||||||
self.party_account = party_account
|
self.party_account = party_account
|
||||||
|
|
||||||
if self.paid_from and not (self.paid_from_account_currency or self.paid_from_account_balance):
|
if self.paid_from and not (self.paid_from_account_currency or self.paid_from_account_balance):
|
||||||
acc = get_account_currency_and_balance(self.paid_from, self.posting_date)
|
acc = get_account_details(self.paid_from, self.posting_date)
|
||||||
self.paid_from_account_currency = acc.account_currency
|
self.paid_from_account_currency = acc.account_currency
|
||||||
self.paid_from_account_balance = acc.account_balance
|
self.paid_from_account_balance = acc.account_balance
|
||||||
|
|
||||||
if self.paid_to and not (self.paid_to_account_currency or self.paid_to_account_balance):
|
if self.paid_to and not (self.paid_to_account_currency or self.paid_to_account_balance):
|
||||||
acc = get_account_currency_and_balance(self.paid_to, self.posting_date)
|
acc = get_account_details(self.paid_to, self.posting_date)
|
||||||
self.paid_to_account_currency = acc.account_currency
|
self.paid_to_account_currency = acc.account_currency
|
||||||
self.paid_to_account_balance = acc.account_balance
|
self.paid_to_account_balance = acc.account_balance
|
||||||
|
|
||||||
@@ -96,24 +99,12 @@ class PaymentEntry(AccountsController):
|
|||||||
def set_missing_ref_details(self):
|
def set_missing_ref_details(self):
|
||||||
for d in self.get("references"):
|
for d in self.get("references"):
|
||||||
if d.allocated_amount:
|
if d.allocated_amount:
|
||||||
if d.reference_doctype != "Journal Entry":
|
ref_details = get_reference_details(d.reference_doctype,
|
||||||
ref_doc = frappe.get_doc(d.reference_doctype, d.reference_name)
|
d.reference_name, self.party_account_currency)
|
||||||
|
|
||||||
d.due_date = ref_doc.get("due_date")
|
|
||||||
|
|
||||||
if self.party_account_currency == self.company_currency:
|
|
||||||
d.total_amount = ref_doc.base_grand_total
|
|
||||||
d.exchange_rate = 1
|
|
||||||
else:
|
|
||||||
d.total_amount = ref_doc.grand_total
|
|
||||||
d.exchange_rate = ref_doc.get("conversion_rate") or \
|
|
||||||
get_exchange_rate(self.party_account_currency, self.company_currency)
|
|
||||||
|
|
||||||
d.outstanding_amount = ref_doc.get("outstanding_amount") \
|
for field, value in ref_details.items():
|
||||||
if d.reference_doctype in ("Sales Invoice", "Purchase Invoice") \
|
if not d.get(field):
|
||||||
else flt(d.total_amount) - flt(ref_doc.advance_paid)
|
d.set(field, value)
|
||||||
elif not d.exchange_rate:
|
|
||||||
d.exchange_rate = get_exchange_rate(self.party_account_currency, self.company_currency)
|
|
||||||
|
|
||||||
def validate_party_details(self):
|
def validate_party_details(self):
|
||||||
if self.party:
|
if self.party:
|
||||||
@@ -162,6 +153,8 @@ class PaymentEntry(AccountsController):
|
|||||||
valid_reference_doctypes = ("Purchase Order", "Purchase Invoice", "Journal Entry")
|
valid_reference_doctypes = ("Purchase Order", "Purchase Invoice", "Journal Entry")
|
||||||
|
|
||||||
for d in self.get("references"):
|
for d in self.get("references"):
|
||||||
|
if not d.allocated_amount:
|
||||||
|
continue
|
||||||
if d.reference_doctype not in valid_reference_doctypes:
|
if d.reference_doctype not in valid_reference_doctypes:
|
||||||
frappe.throw(_("Reference Doctype must be one of {0}")
|
frappe.throw(_("Reference Doctype must be one of {0}")
|
||||||
.format(comma_or(valid_reference_doctypes)))
|
.format(comma_or(valid_reference_doctypes)))
|
||||||
@@ -172,15 +165,45 @@ class PaymentEntry(AccountsController):
|
|||||||
else:
|
else:
|
||||||
ref_doc = frappe.get_doc(d.reference_doctype, d.reference_name)
|
ref_doc = frappe.get_doc(d.reference_doctype, d.reference_name)
|
||||||
|
|
||||||
if d.reference_doctype != "Journal Entry" \
|
if d.reference_doctype != "Journal Entry":
|
||||||
and self.party != ref_doc.get(scrub(self.party_type)):
|
if self.party != ref_doc.get(scrub(self.party_type)):
|
||||||
frappe.throw(_("{0} {1} does not associated with {2} {3}")
|
frappe.throw(_("{0} {1} does not associated with {2} {3}")
|
||||||
.format(d.reference_doctype, d.reference_name, self.party_type, self.party))
|
.format(d.reference_doctype, d.reference_name, self.party_type, self.party))
|
||||||
|
else:
|
||||||
|
self.validate_journal_entry()
|
||||||
|
|
||||||
|
if d.reference_doctype in ("Sales Invoice", "Purchase Invoice"):
|
||||||
|
ref_party_account = ref_doc.debit_to \
|
||||||
|
if self.party_type=="Customer" else ref_doc.credit_to
|
||||||
|
if ref_party_account != self.party_account:
|
||||||
|
frappe.throw(_("{0} {1} does not associated with Party Account {2}")
|
||||||
|
.format(d.reference_doctype, d.reference_name, self.party_account))
|
||||||
|
|
||||||
if ref_doc.docstatus != 1:
|
if ref_doc.docstatus != 1:
|
||||||
frappe.throw(_("{0} {1} must be submitted")
|
frappe.throw(_("{0} {1} must be submitted")
|
||||||
.format(d.reference_doctype, d.reference_name))
|
.format(d.reference_doctype, d.reference_name))
|
||||||
|
|
||||||
|
def validate_journal_entry(self):
|
||||||
|
for d in self.get("references"):
|
||||||
|
if d.allocated_amount and d.reference_doctype == "Journal Entry":
|
||||||
|
je_accounts = frappe.db.sql("""select debit, credit from `tabJournal Entry Account`
|
||||||
|
where account = %s and party=%s and docstatus = 1 and parent = %s
|
||||||
|
and (reference_type is null or reference_type in ("", "Sales Order", "Purchase Order"))
|
||||||
|
""", (self.party_account, self.party, d.reference_name), as_dict=True)
|
||||||
|
|
||||||
|
if not je_accounts:
|
||||||
|
frappe.throw(_("Row #{0}: Journal Entry {0} does not have account {1} or already matched against another voucher")
|
||||||
|
.format(d.idx, d.reference_name, self.party_account))
|
||||||
|
else:
|
||||||
|
dr_or_cr = "debit" if self.payment_type == "Receive" else "credit"
|
||||||
|
valid = False
|
||||||
|
for jvd in je_accounts:
|
||||||
|
if flt(jvd[dr_or_cr]) > 0:
|
||||||
|
valid = True
|
||||||
|
if not valid:
|
||||||
|
frappe.throw(_("Against Journal Entry {0} does not have any unmatched {1} entry")
|
||||||
|
.format(d.reference_name, dr_or_cr))
|
||||||
|
|
||||||
def set_amounts(self):
|
def set_amounts(self):
|
||||||
self.set_amounts_in_company_currency()
|
self.set_amounts_in_company_currency()
|
||||||
self.set_total_allocated_amount()
|
self.set_total_allocated_amount()
|
||||||
@@ -201,17 +224,15 @@ class PaymentEntry(AccountsController):
|
|||||||
if self.payment_type == "Internal Transfer":
|
if self.payment_type == "Internal Transfer":
|
||||||
return
|
return
|
||||||
|
|
||||||
self.total_allocated_amount, self.base_total_allocated_amount = 0, 0
|
total_allocated_amount, base_total_allocated_amount = 0, 0
|
||||||
for d in self.get("references"):
|
for d in self.get("references"):
|
||||||
if d.allocated_amount:
|
if d.allocated_amount:
|
||||||
if d.reference_doctype not in ("Sales Order", "Purchase Order") \
|
total_allocated_amount += flt(d.allocated_amount)
|
||||||
and d.allocated_amount > d.outstanding_amount:
|
base_total_allocated_amount += flt(flt(d.allocated_amount) * flt(d.exchange_rate),
|
||||||
frappe.throw(_("Row #{0}: Allocated amount cannot be greater than outstanding amount")
|
|
||||||
.format(d.idx))
|
|
||||||
|
|
||||||
self.total_allocated_amount += flt(d.allocated_amount)
|
|
||||||
self.base_total_allocated_amount += flt(flt(d.allocated_amount) * flt(d.exchange_rate),
|
|
||||||
self.precision("base_paid_amount"))
|
self.precision("base_paid_amount"))
|
||||||
|
|
||||||
|
self.total_allocated_amount = abs(total_allocated_amount)
|
||||||
|
self.base_total_allocated_amount = abs(base_total_allocated_amount)
|
||||||
|
|
||||||
def set_unallocated_amount(self):
|
def set_unallocated_amount(self):
|
||||||
self.unallocated_amount = 0;
|
self.unallocated_amount = 0;
|
||||||
@@ -244,6 +265,23 @@ class PaymentEntry(AccountsController):
|
|||||||
frappe.db.sql("""delete from `tabPayment Entry Reference`
|
frappe.db.sql("""delete from `tabPayment Entry Reference`
|
||||||
where parent = %s and allocated_amount = 0""", self.name)
|
where parent = %s and allocated_amount = 0""", self.name)
|
||||||
|
|
||||||
|
def validate_payment_against_negative_invoice(self):
|
||||||
|
if ((self.payment_type=="Pay" and self.party_type=="Customer")
|
||||||
|
or (self.payment_type=="Receive" and self.party_type=="Supplier")):
|
||||||
|
total_negative_outstanding = sum([abs(flt(d.outstanding_amount))
|
||||||
|
for d in self.get("references") if flt(d.outstanding_amount) < 0])
|
||||||
|
|
||||||
|
party_amount = self.paid_amount if self.payment_type=="Receive" else self.received_amount
|
||||||
|
|
||||||
|
if not total_negative_outstanding:
|
||||||
|
frappe.throw(_("Cannot {0} {1} {2} without any negative outstanding invoice")
|
||||||
|
.format(self.payment_type, ("to" if self.party_type=="Customer" else "from"),
|
||||||
|
self.party_type), InvalidPaymentEntry)
|
||||||
|
|
||||||
|
elif party_amount > total_negative_outstanding:
|
||||||
|
frappe.throw(_("Paid Amount cannot be greater than total negative outstanding amount {0}")
|
||||||
|
.format(total_negative_outstanding), InvalidPaymentEntry)
|
||||||
|
|
||||||
def set_title(self):
|
def set_title(self):
|
||||||
if self.payment_type in ("Receive", "Pay"):
|
if self.payment_type in ("Receive", "Pay"):
|
||||||
self.title = self.party
|
self.title = self.party
|
||||||
@@ -313,6 +351,8 @@ class PaymentEntry(AccountsController):
|
|||||||
"account_currency": self.party_account_currency
|
"account_currency": self.party_account_currency
|
||||||
})
|
})
|
||||||
|
|
||||||
|
dr_or_cr = "credit" if self.party_type == "Customer" else "debit"
|
||||||
|
|
||||||
for d in self.get("references"):
|
for d in self.get("references"):
|
||||||
gle = party_gl_dict.copy()
|
gle = party_gl_dict.copy()
|
||||||
gle.update({
|
gle.update({
|
||||||
@@ -323,16 +363,10 @@ class PaymentEntry(AccountsController):
|
|||||||
allocated_amount_in_company_currency = flt(flt(d.allocated_amount) * flt(d.exchange_rate),
|
allocated_amount_in_company_currency = flt(flt(d.allocated_amount) * flt(d.exchange_rate),
|
||||||
self.precision("paid_amount"))
|
self.precision("paid_amount"))
|
||||||
|
|
||||||
if self.payment_type == "Receive":
|
gle.update({
|
||||||
gle.update({
|
dr_or_cr + "_in_account_currency": d.allocated_amount,
|
||||||
"credit_in_account_currency": d.allocated_amount,
|
dr_or_cr: allocated_amount_in_company_currency
|
||||||
"credit": allocated_amount_in_company_currency
|
})
|
||||||
})
|
|
||||||
elif self.payment_type == "Pay":
|
|
||||||
gle.update({
|
|
||||||
"debit_in_account_currency": d.allocated_amount,
|
|
||||||
"debit": allocated_amount_in_company_currency
|
|
||||||
})
|
|
||||||
|
|
||||||
gl_entries.append(gle)
|
gl_entries.append(gle)
|
||||||
|
|
||||||
@@ -341,17 +375,12 @@ class PaymentEntry(AccountsController):
|
|||||||
(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()
|
||||||
if self.payment_type == "Receive":
|
|
||||||
gle.update({
|
|
||||||
"credit_in_account_currency": self.unallocated_amount,
|
|
||||||
"credit": base_unallocated_amount
|
|
||||||
})
|
|
||||||
elif self.payment_type == "Pay":
|
|
||||||
gle.update({
|
|
||||||
"debit_in_account_currency": self.unallocated_amount,
|
|
||||||
"debit": base_unallocated_amount
|
|
||||||
})
|
|
||||||
|
|
||||||
|
gle.update({
|
||||||
|
dr_or_cr + "_in_account_currency": d.unallocated_amount,
|
||||||
|
dr_or_cr: base_unallocated_amount
|
||||||
|
})
|
||||||
|
|
||||||
gl_entries.append(gle)
|
gl_entries.append(gle)
|
||||||
|
|
||||||
def add_bank_gl_entries(self, gl_entries):
|
def add_bank_gl_entries(self, gl_entries):
|
||||||
@@ -406,27 +435,28 @@ def get_outstanding_reference_documents(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")
|
||||||
|
|
||||||
|
# Get negative outstanding sales /purchase invoices
|
||||||
|
total_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
|
||||||
|
|
||||||
|
negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"),
|
||||||
|
args.get("party"), args.get("party_account"), total_field)
|
||||||
|
|
||||||
if ((args.get("party_type") == "Customer" and args.get("payment_type") == "Pay")
|
# Get positive outstanding sales /purchase invoices
|
||||||
or (args.get("party_type") == "Supplier" and args.get("payment_type") == "Received")):
|
|
||||||
|
|
||||||
frappe.throw(_("Please enter the Reference Documents manually"))
|
|
||||||
|
|
||||||
# Get all outstanding sales /purchase invoices
|
|
||||||
outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"),
|
outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"),
|
||||||
args.get("party_account"))
|
args.get("party_account"))
|
||||||
|
|
||||||
for d in outstanding_invoices:
|
for d in outstanding_invoices:
|
||||||
d["exchange_rate"] = 1
|
d["exchange_rate"] = 1
|
||||||
if party_account_currency != company_currency \
|
if party_account_currency != company_currency \
|
||||||
and d.voucher_type in ("Sales Invoice", "Purchase Invoice"):
|
and d.voucher_type in ("Sales Invoice", "Purchase Invoice"):
|
||||||
d["exchange_rate"] = frappe.db.get_value(d.voucher_type, d.voucher_no, "conversion_rate")
|
d["exchange_rate"] = frappe.db.get_value(d.voucher_type, d.voucher_no, "conversion_rate")
|
||||||
|
|
||||||
# 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 negative_outstanding_invoices + 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):
|
||||||
voucher_type = 'Sales Order' if party_type == "Customer" else 'Purchase Order'
|
voucher_type = 'Sales Order' if party_type == "Customer" else 'Purchase Order'
|
||||||
@@ -463,8 +493,31 @@ def get_orders_to_be_billed(party_type, party, party_account_currency, company_c
|
|||||||
|
|
||||||
return order_list
|
return order_list
|
||||||
|
|
||||||
|
def get_negative_outstanding_invoices(party_type, party, party_account, total_field):
|
||||||
|
voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"
|
||||||
|
return frappe.db.sql("""
|
||||||
|
select
|
||||||
|
"{voucher_type}" as voucher_type, name as voucher_no,
|
||||||
|
{total_field} as invoice_amount, outstanding_amount, posting_date,
|
||||||
|
due_date, conversion_rate as exchange_rate
|
||||||
|
from
|
||||||
|
`tab{voucher_type}`
|
||||||
|
where
|
||||||
|
{party_type} = %s and {party_account} = %s and docstatus = 1 and outstanding_amount < 0
|
||||||
|
order by
|
||||||
|
posting_date, name
|
||||||
|
""".format(**{
|
||||||
|
"total_field": total_field,
|
||||||
|
"voucher_type": voucher_type,
|
||||||
|
"party_type": scrub(party_type),
|
||||||
|
"party_account": "debit_to" if party_type=="Customer" else "credit_to"
|
||||||
|
}), (party, party_account), as_dict = True)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_party_details(company, party_type, party, date):
|
def get_party_details(company, party_type, party, date):
|
||||||
|
if not frappe.db.exists(party_type, party):
|
||||||
|
frappe.throw(_("Invalid {0}: {1}").format(party_type, party))
|
||||||
|
|
||||||
party_account = get_party_account(party_type, party, company)
|
party_account = get_party_account(party_type, party, company)
|
||||||
|
|
||||||
account_currency = get_account_currency(party_account)
|
account_currency = get_account_currency(party_account)
|
||||||
@@ -479,10 +532,11 @@ def get_party_details(company, party_type, party, date):
|
|||||||
}
|
}
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_account_currency_and_balance(account, date):
|
def get_account_details(account, date):
|
||||||
return frappe._dict({
|
return frappe._dict({
|
||||||
"account_currency": get_account_currency(account),
|
"account_currency": get_account_currency(account),
|
||||||
"account_balance": get_balance_on(account, date)
|
"account_balance": get_balance_on(account, date),
|
||||||
|
"account_type": frappe.db.get_value("Account", account, "account_type")
|
||||||
})
|
})
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@@ -496,6 +550,34 @@ def get_company_defaults(company):
|
|||||||
.format(frappe.get_meta("Company").get_label(fieldname), company))
|
.format(frappe.get_meta("Company").get_label(fieldname), company))
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_reference_details(reference_doctype, reference_name, party_account_currency):
|
||||||
|
total_amount = outstanding_amount = exchange_rate = None
|
||||||
|
|
||||||
|
if reference_doctype != "Journal Entry":
|
||||||
|
ref_doc = frappe.get_doc(reference_doctype, reference_name)
|
||||||
|
|
||||||
|
if party_account_currency == ref_doc.company_currency:
|
||||||
|
total_amount = ref_doc.base_grand_total
|
||||||
|
exchange_rate = 1
|
||||||
|
else:
|
||||||
|
total_amount = ref_doc.grand_total
|
||||||
|
exchange_rate = ref_doc.get("conversion_rate") or \
|
||||||
|
get_exchange_rate(party_account_currency, ref_doc.company_currency)
|
||||||
|
|
||||||
|
outstanding_amount = ref_doc.get("outstanding_amount") \
|
||||||
|
if reference_doctype in ("Sales Invoice", "Purchase Invoice") \
|
||||||
|
else flt(total_amount) - flt(ref_doc.advance_paid)
|
||||||
|
else:
|
||||||
|
exchange_rate = get_exchange_rate(party_account_currency, ref_doc.company_currency)
|
||||||
|
|
||||||
|
return frappe._dict({
|
||||||
|
"due_date": ref_doc.get("due_date"),
|
||||||
|
"total_amount": total_amount,
|
||||||
|
"outstanding_amount": outstanding_amount,
|
||||||
|
"exchange_rate": exchange_rate
|
||||||
|
})
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=None):
|
def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=None):
|
||||||
@@ -541,13 +623,13 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
|||||||
|
|
||||||
paid_amount = received_amount = 0
|
paid_amount = received_amount = 0
|
||||||
if party_account_currency == bank.account_currency:
|
if party_account_currency == bank.account_currency:
|
||||||
paid_amount = received_amount = outstanding_amount
|
paid_amount = received_amount = abs(outstanding_amount)
|
||||||
elif payment_type == "Receive":
|
elif payment_type == "Receive":
|
||||||
paid_amount = outstanding_amount
|
paid_amount = abs(outstanding_amount)
|
||||||
if bank_amount:
|
if bank_amount:
|
||||||
received_amount = bank_amount
|
received_amount = bank_amount
|
||||||
else:
|
else:
|
||||||
received_amount = outstanding_amount
|
received_amount = abs(outstanding_amount)
|
||||||
if bank_amount:
|
if bank_amount:
|
||||||
paid_amount = bank_amount
|
paid_amount = bank_amount
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import frappe
|
|||||||
import unittest
|
import unittest
|
||||||
from frappe.utils import flt, nowdate
|
from frappe.utils import flt, nowdate
|
||||||
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
||||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry, InvalidPaymentEntry
|
||||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||||
|
|
||||||
@@ -149,6 +149,57 @@ class TestPaymentEntry(unittest.TestCase):
|
|||||||
|
|
||||||
self.validate_gl_entries(pe.name, expected_gle)
|
self.validate_gl_entries(pe.name, expected_gle)
|
||||||
|
|
||||||
|
def test_payment_against_negative_sales_invoice(self):
|
||||||
|
pe1 = frappe.new_doc("Payment Entry")
|
||||||
|
pe1.payment_type = "Pay"
|
||||||
|
pe1.company = "_Test Company"
|
||||||
|
pe1.party_type = "Customer"
|
||||||
|
pe1.party = "_Test Customer"
|
||||||
|
pe1.paid_from = "_Test Cash - _TC"
|
||||||
|
pe1.paid_amount = 100
|
||||||
|
pe1.received_amount = 100
|
||||||
|
|
||||||
|
self.assertRaises(InvalidPaymentEntry, pe1.validate)
|
||||||
|
|
||||||
|
si1 = create_sales_invoice()
|
||||||
|
|
||||||
|
# create full payment entry against si1
|
||||||
|
pe2 = get_payment_entry("Sales Invoice", si1.name, bank_account="_Test Cash - _TC")
|
||||||
|
pe2.insert()
|
||||||
|
pe2.submit()
|
||||||
|
|
||||||
|
# create return entry against si1
|
||||||
|
create_sales_invoice(is_return=1, return_against=si1.name, qty=-1)
|
||||||
|
si1_outstanding = frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount")
|
||||||
|
self.assertEqual(si1_outstanding, -100)
|
||||||
|
|
||||||
|
# pay more than outstanding against si1
|
||||||
|
pe3 = get_payment_entry("Sales Invoice", si1.name, bank_account="_Test Cash - _TC")
|
||||||
|
pe3.paid_amount = pe3.received_amount = 300
|
||||||
|
self.assertRaises(InvalidPaymentEntry, pe3.validate)
|
||||||
|
|
||||||
|
# pay negative outstanding against si1
|
||||||
|
pe3.paid_to = "Debtors - _TC"
|
||||||
|
pe3.paid_amount = pe3.received_amount = 100
|
||||||
|
|
||||||
|
pe3.insert()
|
||||||
|
pe3.submit()
|
||||||
|
|
||||||
|
expected_gle = dict((d[0], d) for d in [
|
||||||
|
["Debtors - _TC", 100, 0, si1.name],
|
||||||
|
["_Test Cash - _TC", 0, 100, None]
|
||||||
|
])
|
||||||
|
|
||||||
|
self.validate_gl_entries(pe3.name, expected_gle)
|
||||||
|
|
||||||
|
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount"))
|
||||||
|
self.assertEqual(outstanding_amount, 0)
|
||||||
|
|
||||||
|
pe3.cancel()
|
||||||
|
self.assertFalse(self.get_gle(pe3.name))
|
||||||
|
|
||||||
|
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount"))
|
||||||
|
self.assertEqual(outstanding_amount, -100)
|
||||||
|
|
||||||
def validate_gl_entries(self, voucher_no, expected_gle):
|
def validate_gl_entries(self, voucher_no, expected_gle):
|
||||||
gl_entries = self.get_gle(voucher_no)
|
gl_entries = self.get_gle(voucher_no)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!doc.is_return && doc.docstatus==1) {
|
if(!doc.is_return && doc.docstatus==1) {
|
||||||
if(doc.outstanding_amount > 0) {
|
if(doc.outstanding_amount != 0) {
|
||||||
this.frm.add_custom_button(__('Payment'), this.make_payment_entry, __("Make"));
|
this.frm.add_custom_button(__('Payment'), this.make_payment_entry, __("Make"));
|
||||||
cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
|
cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,10 +65,14 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(doc.outstanding_amount>0 && !cint(doc.is_return)) {
|
if(doc.outstanding_amount!=0 && !cint(doc.is_return)) {
|
||||||
cur_frm.add_custom_button(__('Payment Request'), this.make_payment_request, __("Make"));
|
|
||||||
cur_frm.add_custom_button(__('Payment'), this.make_payment_entry, __("Make"));
|
cur_frm.add_custom_button(__('Payment'), this.make_payment_entry, __("Make"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(doc.outstanding_amount>0 && !cint(doc.is_return)) {
|
||||||
|
cur_frm.add_custom_button(__('Payment Request'), this.make_payment_request, __("Make"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -160,7 +160,6 @@ def make_round_off_gle(gl_map, debit_credit_diff):
|
|||||||
|
|
||||||
gl_map.append(round_off_gle)
|
gl_map.append(round_off_gle)
|
||||||
|
|
||||||
|
|
||||||
def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
|
def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
|
||||||
adv_adj=False, update_outstanding="Yes"):
|
adv_adj=False, update_outstanding="Yes"):
|
||||||
|
|
||||||
@@ -168,8 +167,12 @@ def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
|
|||||||
check_freezing_date, update_outstanding_amt, validate_frozen_account
|
check_freezing_date, update_outstanding_amt, validate_frozen_account
|
||||||
|
|
||||||
if not gl_entries:
|
if not gl_entries:
|
||||||
gl_entries = frappe.db.sql("""select * from `tabGL Entry`
|
gl_entries = frappe.db.sql("""
|
||||||
|
select account, posting_date, party_type, party,
|
||||||
|
voucher_type, voucher_no, against_voucher_type, against_voucher
|
||||||
|
from `tabGL Entry`
|
||||||
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no), as_dict=True)
|
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no), as_dict=True)
|
||||||
|
|
||||||
if gl_entries:
|
if gl_entries:
|
||||||
check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
|
check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
|
||||||
|
|
||||||
@@ -180,7 +183,7 @@ def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
|
|||||||
validate_frozen_account(entry["account"], adv_adj)
|
validate_frozen_account(entry["account"], adv_adj)
|
||||||
validate_balance_type(entry["account"], adv_adj)
|
validate_balance_type(entry["account"], adv_adj)
|
||||||
validate_expense_against_budget(entry)
|
validate_expense_against_budget(entry)
|
||||||
|
|
||||||
if entry.get("against_voucher") and update_outstanding == 'Yes':
|
if entry.get("against_voucher") and update_outstanding == 'Yes':
|
||||||
update_outstanding_amt(entry["account"], entry.get("party_type"), entry.get("party"), entry.get("against_voucher_type"),
|
update_outstanding_amt(entry["account"], entry.get("party_type"), entry.get("party"), entry.get("against_voucher_type"),
|
||||||
entry.get("against_voucher"), on_cancel=True)
|
entry.get("against_voucher"), on_cancel=True)
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ def validate_party_accounts(doc):
|
|||||||
|
|
||||||
if doc.default_currency and party_account_currency and company_default_currency:
|
if doc.default_currency and party_account_currency and company_default_currency:
|
||||||
if doc.default_currency != party_account_currency and doc.default_currency != company_default_currency:
|
if doc.default_currency != party_account_currency and doc.default_currency != company_default_currency:
|
||||||
frappe.throw(_("Billing currency must be equal to either default comapany's currency or party's payble account currency"))
|
frappe.throw(_("Billing currency must be equal to either default comapany's currency or party account currency"))
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_due_date(posting_date, party_type, party, company):
|
def get_due_date(posting_date, party_type, party, company):
|
||||||
|
|||||||
@@ -458,9 +458,8 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
|
|||||||
and {dr_or_cr} > 0
|
and {dr_or_cr} > 0
|
||||||
{condition}
|
{condition}
|
||||||
and ((voucher_type = 'Journal Entry'
|
and ((voucher_type = 'Journal Entry'
|
||||||
and (against_voucher = ''
|
and (against_voucher = '' or against_voucher is null))
|
||||||
or against_voucher is null))
|
or (voucher_type not in ('Journal Entry', 'Payment Entry')))
|
||||||
or (voucher_type != 'Journal Entry'))
|
|
||||||
group by voucher_type, voucher_no
|
group by voucher_type, voucher_no
|
||||||
having (invoice_amount - payment_amount) > 0.005
|
having (invoice_amount - payment_amount) > 0.005
|
||||||
order by posting_date, name""".format(
|
order by posting_date, name""".format(
|
||||||
@@ -471,10 +470,9 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
|
|||||||
"party_type": party_type,
|
"party_type": party_type,
|
||||||
"party": party,
|
"party": party,
|
||||||
"account": account,
|
"account": account,
|
||||||
}, as_dict=True, debug=1)
|
}, as_dict=True)
|
||||||
|
|
||||||
for d in invoice_list:
|
for d in invoice_list:
|
||||||
print d.voucher_no, d.invoice_amount, d.payment_amount
|
|
||||||
outstanding_invoices.append(frappe._dict({
|
outstanding_invoices.append(frappe._dict({
|
||||||
'voucher_no': d.voucher_no,
|
'voucher_no': d.voucher_no,
|
||||||
'voucher_type': d.voucher_type,
|
'voucher_type': d.voucher_type,
|
||||||
|
|||||||
@@ -995,6 +995,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
var doclist = frappe.model.sync(r.message);
|
var doclist = frappe.model.sync(r.message);
|
||||||
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
|
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
|
||||||
|
// cur_frm.refresh_fields()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user