Multi-currency: Exchange Rate in Journal Entry

This commit is contained in:
Nabin Hait 2015-09-09 18:43:12 +05:30
parent 6c3ff3e2ed
commit e3ae05aabd
14 changed files with 456 additions and 246 deletions

View File

@ -153,17 +153,18 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
party_condition = "" party_condition = ""
# get final outstanding amt # get final outstanding amt
bal = flt(frappe.db.sql("""select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0)) bal = flt(frappe.db.sql("""
select sum(ifnull(debit_in_account_currency, 0)) - sum(ifnull(credit_in_account_currency, 0))
from `tabGL Entry` from `tabGL Entry`
where against_voucher_type=%s and against_voucher=%s where against_voucher_type=%s and against_voucher=%s
and account = %s {0}""".format(party_condition), and account = %s {0}""".format(party_condition),
(against_voucher_type, against_voucher, account))[0][0] or 0.0) (against_voucher_type, against_voucher, account))[0][0] or 0.0)
if against_voucher_type == 'Purchase Invoice': if against_voucher_type == 'Purchase Invoice':
bal = -bal bal = -bal
elif against_voucher_type == "Journal Entry": elif against_voucher_type == "Journal Entry":
against_voucher_amount = flt(frappe.db.sql(""" against_voucher_amount = flt(frappe.db.sql("""
select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0)) select sum(ifnull(debit_in_account_currency, 0)) - sum(ifnull(credit_in_account_currency, 0))
from `tabGL Entry` where voucher_type = 'Journal Entry' and voucher_no = %s from `tabGL Entry` where voucher_type = 'Journal Entry' and voucher_no = %s
and account = %s and ifnull(against_voucher, '') = '' {0}""" and account = %s and ifnull(against_voucher, '') = '' {0}"""
.format(party_condition), (against_voucher, account))[0][0]) .format(party_condition), (against_voucher, account))[0][0])

View File

@ -25,16 +25,29 @@ frappe.ui.form.on("Journal Entry", {
// hide /unhide fields based on currency // hide /unhide fields based on currency
erpnext.journal_entry.toggle_fields_based_on_currency(frm); erpnext.journal_entry.toggle_fields_based_on_currency(frm);
},
multi_currency: function(frm) {
erpnext.journal_entry.toggle_fields_based_on_currency(frm);
} }
}) })
erpnext.journal_entry.toggle_fields_based_on_currency = function(frm) { erpnext.journal_entry.toggle_fields_based_on_currency = function(frm) {
var fields = ["debit_in_account_currency", "credit_in_account_currency"]; var fields = ["currency_section", "account_currency", "exchange_rate", "debit", "credit"];
var company_currency = erpnext.get_currency(frm.doc.company);
var grid = frm.get_field("accounts").grid; var grid = frm.get_field("accounts").grid;
grid.set_column_disp(fields, grid.account_currency!=company_currency); if(grid) grid.set_column_disp(fields, frm.doc.multi_currency);
// dynamic label
var field_label_map = {
"debit_in_account_currency": "Debit",
"credit_in_account_currency": "Credit"
};
$.each(field_label_map, function (fieldname, label) {
var df = frappe.meta.get_docfield("Journal Entry Account", fieldname, frm.doc.name);
df.label = frm.doc.multi_currency ? (label + " in Account Currency") : label;
})
} }
erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
@ -62,17 +75,26 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
setup_queries: function() { setup_queries: function() {
var me = this; var me = this;
var company_currency = erpnext.get_currency(me.frm.doc.company);
$.each(["account", "cost_center"], function(i, fieldname) {
me.frm.set_query(fieldname, "accounts", function() { me.frm.set_query("account", "accounts", function(doc, cdt, cdn) {
frappe.model.validate_missing(me.frm.doc, "company"); var filters = {
return { company: me.frm.doc.company,
filters: { is_group: 0
company: me.frm.doc.company, };
is_group: 0 if(!doc.multi_currency) {
} $.extend(filters, {currency: company_currency});
}; }
}); return { filters: filters };
});
me.frm.set_query("cost_center", "accounts", function(doc, cdt, cdn) {
return {
filters: {
company: me.frm.doc.company,
is_group: 0
}
};
}); });
me.frm.set_query("party_type", "accounts", function(doc, cdt, cdn) { me.frm.set_query("party_type", "accounts", function(doc, cdt, cdn) {
@ -151,32 +173,39 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
reference_name: function(doc, cdt, cdn) { reference_name: function(doc, cdt, cdn) {
var d = frappe.get_doc(cdt, cdn); var d = frappe.get_doc(cdt, cdn);
if (d.reference_type==="Purchase Invoice" && !flt(d.debit)) { if(d.reference_name) {
this.get_outstanding('Purchase Invoice', d.reference_name, d); if (d.reference_type==="Purchase Invoice" && !flt(d.debit)) {
} this.get_outstanding('Purchase Invoice', d.reference_name, doc.company, d);
if (d.reference_type==="Sales Invoice" && !flt(d.credit)) { }
this.get_outstanding('Sales Invoice', d.reference_name, d); if (d.reference_type==="Sales Invoice" && !flt(d.credit)) {
} this.get_outstanding('Sales Invoice', d.reference_name, doc.company, d);
if (d.reference_type==="Journal Entry" && !flt(d.credit) && !flt(d.debit)) { }
this.get_outstanding('Journal Entry', d.reference_name, d); if (d.reference_type==="Journal Entry" && !flt(d.credit) && !flt(d.debit)) {
this.get_outstanding('Journal Entry', d.reference_name, doc.company, d);
}
} }
}, },
get_outstanding: function(doctype, docname, child) { get_outstanding: function(doctype, docname, company, child) {
var me = this; var me = this;
var args = { var args = {
"doctype": doctype, "doctype": doctype,
"docname": docname, "docname": docname,
"party": child.party, "party": child.party,
"account": child.account "account": child.account,
"account_currency": child.account_currency,
"company": company
} }
return this.frm.call({ return frappe.call({
child: child, method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_outstanding",
method: "get_outstanding",
args: { args: args}, args: { args: args},
callback: function(r) { callback: function(r) {
cur_frm.cscript.update_totals(me.frm.doc); if(r.message) {
$.each(r.message, function(field, value) {
frappe.model.set_value(child.doctype, child.name, field, value);
})
}
} }
}); });
}, },
@ -325,42 +354,26 @@ frappe.ui.form.on("Journal Entry Account", {
account: d.account, account: d.account,
date: frm.doc.posting_date, date: frm.doc.posting_date,
company: frm.doc.company, company: frm.doc.company,
credited: flt(d.credit_in_account_currency) > 0 ? true : false debit: flt(d.debit_in_account_currency),
credit: flt(d.credit_in_account_currency),
exchange_rate: d.exchange_rate
}, },
callback: function(r) { callback: function(r) {
if(r.message) { if(r.message) {
$.extend(d, r.message[0]); $.extend(d, r.message);
refresh_field('balance', d.name, 'accounts'); refresh_field('accounts');
refresh_field('party_type', d.name, 'accounts');
refresh_field('account_currency', d.name, 'accounts');
if(r.message[1] && (!frm.doc.exchange_rate || frm.doc.exchange_rate == 1.0)) {
frm.set_value("exchange_rate", r.message[1])
}
} }
} }
}); });
} }
}, },
debit_in_account_currency: function(frm, dt, dn) { debit_in_account_currency: function(frm, cdt, cdn) {
var company_currency = erpnext.get_currency(frm.doc.company); erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn);
var row = locals[dt][dn];
var exchange_rate = (row.account_currency==company_currency) ? 1 : frm.doc.exchange_rate;
frappe.model.set_value(dt, dn, "debit",
flt(flt(row.debit_in_account_currency)*exchange_rate), precision("debit", row));
}, },
credit_in_account_currency: function(frm, dt, dn) { credit_in_account_currency: function(frm, cdt, cdn) {
var company_currency = erpnext.get_currency(frm.doc.company); erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn);
var row = locals[dt][dn];
var exchange_rate = (row.account_currency==company_currency) ? 1 : frm.doc.exchange_rate;
frappe.model.set_value(dt, dn, "credit",
flt(flt(row.credit_in_account_currency)*exchange_rate), precision("credit", row));
}, },
debit: function(frm, dt, dn) { debit: function(frm, dt, dn) {
@ -369,9 +382,52 @@ frappe.ui.form.on("Journal Entry Account", {
credit: function(frm, dt, dn) { credit: function(frm, dt, dn) {
cur_frm.cscript.update_totals(frm.doc); cur_frm.cscript.update_totals(frm.doc);
},
exchange_rate: function(frm, cdt, cdn) {
erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn);
} }
}) })
frappe.ui.form.on("Journal Entry Account", "accounts_remove", function(frm) { frappe.ui.form.on("Journal Entry Account", "accounts_remove", function(frm) {
cur_frm.cscript.update_totals(frm.doc); cur_frm.cscript.update_totals(frm.doc);
}); });
erpnext.journal_entry.set_debit_credit_in_company_currency = function(frm, cdt, cdn) {
erpnext.journal_entry.set_exchange_rate(frm, cdt, cdn);
var row = locals[cdt][cdn];
frappe.model.set_value(cdt, cdn, "debit",
flt(flt(row.debit_in_account_currency)*row.exchange_rate), precision("debit", row));
frappe.model.set_value(cdt, cdn, "credit",
flt(flt(row.credit_in_account_currency)*row.exchange_rate), precision("credit", row));
}
erpnext.journal_entry.set_exchange_rate = function(frm, cdt, cdn) {
var company_currency = erpnext.get_currency(frm.doc.company);
var row = locals[cdt][cdn];
if(row.account_currency == company_currency || !frm.doc.multi_currency) {
frappe.model.set_value(cdt, cdn, "exchange_rate", 1);
} else if (!row.exchange_rate || row.account_type == "Bank") {
frappe.call({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_exchange_rate",
args: {
account: row.account,
account_currency: row.account_currency,
company: frm.doc.company,
reference_type: row.reference_type,
reference_name: row.reference_name,
debit: flt(row.debit_in_account_currency),
credit: flt(row.credit_in_account_currency),
exchange_rate: row.exchange_rate
},
callback: function(r) {
if(r.message) {
frappe.model.set_value(cdt, cdn, "exchange_rate", r.message);
}
}
})
}
}

View File

@ -147,28 +147,6 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "exchange_rate",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Exchange Rate",
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@ -422,6 +400,28 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "multi_currency",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Multi Currency",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@ -1024,7 +1024,7 @@
"is_submittable": 1, "is_submittable": 1,
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"modified": "2015-08-27 16:07:33.265318", "modified": "2015-09-09 02:07:40.980884",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Journal Entry", "name": "Journal Entry",

View File

@ -5,9 +5,9 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe.utils import cstr, flt, fmt_money, formatdate from frappe.utils import cstr, flt, fmt_money, formatdate
from frappe import msgprint, _, scrub from frappe import msgprint, _, scrub
from erpnext.setup.utils import get_company_currency, get_exchange_rate
from erpnext.controllers.accounts_controller import AccountsController from erpnext.controllers.accounts_controller import AccountsController
from erpnext.accounts.utils import get_balance_on from erpnext.accounts.utils import get_balance_on
from erpnext.setup.utils import get_company_currency
class JournalEntry(AccountsController): class JournalEntry(AccountsController):
@ -267,39 +267,37 @@ class JournalEntry(AccountsController):
def validate_multi_currency(self): def validate_multi_currency(self):
alternate_currency = [] alternate_currency = []
for d in self.get("accounts"): for d in self.get("accounts"):
d.account_currency = frappe.db.get_value("Account", d.account, "account_currency") or self.company_currency account = frappe.db.get_value("Account", d.account, ["account_currency", "account_type"], as_dict=1)
d.account_currency = account.account_currency or self.company_currency
d.account_type = account.account_type
if d.account_currency!=self.company_currency and d.account_currency not in alternate_currency: if d.account_currency!=self.company_currency and d.account_currency not in alternate_currency:
alternate_currency.append(d.account_currency) alternate_currency.append(d.account_currency)
if alternate_currency: if alternate_currency:
if not self.multi_currency:
frappe.throw(_("Please check Multi Currency option to allow accounts with other currency"))
if len(alternate_currency) > 1: if len(alternate_currency) > 1:
frappe.throw(_("Only one alternate currency can be used in a single Journal Entry")) frappe.throw(_("Only one alternate currency can be used in a single Journal Entry"))
self.set_exchange_rate() self.set_exchange_rate()
if not self.exchange_rate:
frappe.throw(_("Exchange Rate is mandatory in multi-currency Journal Entry"))
else:
self.exchange_rate = 1.0
for d in self.get("accounts"): for d in self.get("accounts"):
exchange_rate = self.exchange_rate if d.account_currency != self.company_currency else 1 d.debit = flt(flt(d.debit_in_account_currency)*flt(d.exchange_rate), d.precision("debit"))
d.credit = flt(flt(d.credit_in_account_currency)*flt(d.exchange_rate), d.precision("credit"))
d.debit = flt(flt(d.debit_in_account_currency)*exchange_rate, d.precision("debit"))
d.credit = flt(flt(d.credit_in_account_currency)*exchange_rate, d.precision("credit"))
def set_exchange_rate(self): def set_exchange_rate(self):
for d in self.get("accounts"): for d in self.get("accounts"):
if d.account_currency != self.company_currency: if d.account_currency == self.company_currency:
account_type = frappe.db.get_value("Account", d.account, "account_type") d.exchange_rate = 1
if account_type == "Bank" and flt(d.credit_in_account_currency) > 0: elif not d.exchange_rate or d.account_type=="Bank" or \
self.exchange_rate = get_average_exchange_rate(d.account) (d.reference_type in ("Sales Invoice", "Purchase Invoice") and d.reference_name):
break d.exchange_rate = get_exchange_rate(d.account, d.account_currency, self.company,
if not self.exchange_rate: d.reference_type, d.reference_name, d.debit, d.credit, d.exchange_rate)
self.exchange_rate = get_exchange_rate(d.account_currency, self.company_currency)
if not d.exchange_rate:
frappe.throw(_("Row {0}: Exchange Rate is mandatory").format(d.idx))
def create_remarks(self): def create_remarks(self):
r = [] r = []
@ -387,21 +385,21 @@ class JournalEntry(AccountsController):
diff = flt(self.difference, self.precision("difference")) diff = flt(self.difference, self.precision("difference"))
# If any row without amount, set the diff on that row # If any row without amount, set the diff on that row
for d in self.get('accounts'): if diff:
if not d.credit and not d.debit and diff != 0: for d in self.get('accounts'):
if diff>0: if not d.credit_in_account_currency and not d.debit_in_account_currency and diff != 0:
d.credit = diff blank_row = d
elif diff<0:
d.debit = diff if not blank_row:
flag = 1 blank_row = self.append('accounts', {})
# Set the diff in a new row blank_row.exchange_rate = 1
if flag == 0 and diff != 0:
jd = self.append('accounts', {})
if diff>0: if diff>0:
jd.credit = abs(diff) blank_row.credit_in_account_currency = diff
blank_row.credit = diff
elif diff<0: elif diff<0:
jd.debit = abs(diff) blank_row.debit_in_account_currency = abs(diff)
blank_row.debit = abs(diff)
self.validate_debit_and_credit() self.validate_debit_and_credit()
@ -500,10 +498,12 @@ def get_default_bank_cash_account(company, voucher_type, mode_of_payment=None):
account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash", "is_group": 0}) account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash", "is_group": 0})
if account: if account:
account_details = frappe.db.get_value("Account", account, ["account_currency", "account_type"], as_dict=1)
return { return {
"account": account, "account": account,
"balance": get_balance_on(account), "balance": get_balance_on(account),
"account_currency": frappe.db.get_value("Account", account, "account_currency") "account_currency": account_details.account_currency,
"account_type": account_details.account_type
} }
@frappe.whitelist() @frappe.whitelist()
@ -513,31 +513,36 @@ def get_payment_entry_from_sales_invoice(sales_invoice):
si = frappe.get_doc("Sales Invoice", sales_invoice) si = frappe.get_doc("Sales Invoice", sales_invoice)
# exchange rate # exchange rate
if si.company_currency == si.party_account_currency: exchange_rate = get_exchange_rate(si.debit_to, si.party_account_currency, si.company,
exchange_rate = 1 si.doctype, si.name)
else:
exchange_rate = get_exchange_rate(si.party_account_currency, si.company_currency)
jv = get_payment_entry(si) jv = get_payment_entry(si)
jv.remark = 'Payment received against Sales Invoice {0}. {1}'.format(si.name, si.remarks) jv.remark = 'Payment received against Sales Invoice {0}. {1}'.format(si.name, si.remarks)
jv.exchange_rate = exchange_rate
# credit customer # credit customer
jv.get("accounts")[0].account = si.debit_to row1 = jv.get("accounts")[0]
jv.get("accounts")[0].account_currency = si.party_account_currency row1.account = si.debit_to
jv.get("accounts")[0].party_type = "Customer" row1.account_currency = si.party_account_currency
jv.get("accounts")[0].party = si.customer row1.party_type = "Customer"
jv.get("accounts")[0].balance = get_balance_on(si.debit_to) row1.party = si.customer
jv.get("accounts")[0].party_balance = get_balance_on(party=si.customer, party_type="Customer") row1.balance = get_balance_on(si.debit_to)
jv.get("accounts")[0].credit_in_account_currency = si.outstanding_amount row1.party_balance = get_balance_on(party=si.customer, party_type="Customer")
jv.get("accounts")[0].reference_type = si.doctype row1.credit_in_account_currency = si.outstanding_amount
jv.get("accounts")[0].reference_name = si.name row1.reference_type = si.doctype
row1.reference_name = si.name
row1.exchange_rate = exchange_rate
row1.account_type = "Receivable" if si.customer else ""
# debit bank # debit bank
if jv.get("accounts")[1].account_currency == si.party_account_currency: row2 = jv.get("accounts")[1]
jv.get("accounts")[1].debit_in_account_currency = si.outstanding_amount if row2.account_currency == si.party_account_currency:
row2.debit_in_account_currency = si.outstanding_amount
else: else:
jv.get("accounts")[1].debit_in_account_currency = si.outstanding_amount * exchange_rate row2.debit_in_account_currency = si.outstanding_amount * exchange_rate
# set multi currency check
if row1.account_currency != si.company_currency or row2.account_currency != si.company_currency:
jv.multi_currency = 1
return jv.as_dict() return jv.as_dict()
@ -546,31 +551,37 @@ def get_payment_entry_from_purchase_invoice(purchase_invoice):
"""Returns new Journal Entry document as dict for given Purchase Invoice""" """Returns new Journal Entry document as dict for given Purchase Invoice"""
pi = frappe.get_doc("Purchase Invoice", purchase_invoice) pi = frappe.get_doc("Purchase Invoice", purchase_invoice)
if pi.company_currency == pi.party_account_currency: exchange_rate = get_exchange_rate(pi.debit_to, pi.party_account_currency, pi.company,
exchange_rate = 1 pi.doctype, pi.name)
else:
exchange_rate = get_exchange_rate(pi.party_account_currency, pi.company_currency)
jv = get_payment_entry(pi) jv = get_payment_entry(pi)
jv.remark = 'Payment against Purchase Invoice {0}. {1}'.format(pi.name, pi.remarks) jv.remark = 'Payment against Purchase Invoice {0}. {1}'.format(pi.name, pi.remarks)
jv.exchange_rate = exchange_rate jv.exchange_rate = exchange_rate
# credit supplier # credit supplier
jv.get("accounts")[0].account = pi.credit_to row1 = jv.get("accounts")[0]
jv.get("accounts")[0].account_currency = pi.party_account_currency row1.account = pi.credit_to
jv.get("accounts")[0].party_type = "Supplier" row1.account_currency = pi.party_account_currency
jv.get("accounts")[0].party = pi.supplier row1.party_type = "Supplier"
jv.get("accounts")[0].balance = get_balance_on(pi.credit_to) row1.party = pi.supplier
jv.get("accounts")[0].party_balance = get_balance_on(party=pi.supplier, party_type="Supplier") row1.balance = get_balance_on(pi.credit_to)
jv.get("accounts")[0].debit_in_account_currency = pi.outstanding_amount row1.party_balance = get_balance_on(party=pi.supplier, party_type="Supplier")
jv.get("accounts")[0].reference_type = pi.doctype row1.debit_in_account_currency = pi.outstanding_amount
jv.get("accounts")[0].reference_name = pi.name row1.reference_type = pi.doctype
row1.reference_name = pi.name
row1.exchange_rate = exchange_rate
row1.account_type = "Payable" if pi.supplier else ""
# credit bank # credit bank
if jv.get("accounts")[1].account_currency == pi.party_account_currency: row2 = jv.get("accounts")[1]
jv.get("accounts")[1].credit_in_account_currency = pi.outstanding_amount if row2.account_currency == pi.party_account_currency:
row2.credit_in_account_currency = pi.outstanding_amount
else: else:
jv.get("accounts")[1].credit_in_account_currency = pi.outstanding_amount * exchange_rate row2.credit_in_account_currency = pi.outstanding_amount * exchange_rate
# set multi currency check
if row1.account_currency != pi.company_currency or row2.account_currency != pi.company_currency:
jv.multi_currency = 1
return jv.as_dict() return jv.as_dict()
@ -590,37 +601,39 @@ def get_payment_entry_from_sales_order(sales_order):
party_account = get_party_account(so.company, so.customer, "Customer") party_account = get_party_account(so.company, so.customer, "Customer")
party_account_currency = frappe.db.get_value("Account", party_account, "account_currency") party_account_currency = frappe.db.get_value("Account", party_account, "account_currency")
company_currency = get_company_currency(so.company)
if so.company_currency == party_account_currency: exchange_rate = get_exchange_rate(party_account, party_account_currency, so.company)
exchange_rate = 1
else: if party_account_currency == so.company_currency:
exchange_rate = get_exchange_rate(party_account_currency, so.company_currency)
jv.exchange_rate = exchange_rate
if party_account_currency == company_currency:
amount = flt(so.base_grand_total) - flt(so.advance_paid) amount = flt(so.base_grand_total) - flt(so.advance_paid)
else: else:
amount = flt(so.grand_total) - flt(so.advance_paid) amount = flt(so.grand_total) - flt(so.advance_paid)
# credit customer # credit customer
jv.get("accounts")[0].account = party_account row1 = jv.get("accounts")[0]
jv.get("accounts")[0].account_currency = party_account_currency row1.account = party_account
jv.get("accounts")[0].party_type = "Customer" row1.account_currency = party_account_currency
jv.get("accounts")[0].party = so.customer row1.party_type = "Customer"
jv.get("accounts")[0].balance = get_balance_on(party_account) row1.party = so.customer
jv.get("accounts")[0].party_balance = get_balance_on(party=so.customer, party_type="Customer") row1.balance = get_balance_on(party_account)
jv.get("accounts")[0].credit_in_account_currency = amount row1.party_balance = get_balance_on(party=so.customer, party_type="Customer")
jv.get("accounts")[0].reference_type = so.doctype row1.credit_in_account_currency = amount
jv.get("accounts")[0].reference_name = so.name row1.reference_type = so.doctype
jv.get("accounts")[0].is_advance = "Yes" row1.reference_name = so.name
row1.is_advance = "Yes"
row1.exchange_rate = exchange_rate
row1.account_type = "Receivable"
# debit bank # debit bank
if jv.get("accounts")[1].account_currency == party_account_currency: row2 = jv.get("accounts")[1]
jv.get("accounts")[1].debit_in_account_currency = amount if row2.account_currency == party_account_currency:
row2.debit_in_account_currency = amount
else: else:
jv.get("accounts")[1].debit_in_account_currency = amount * exchange_rate row2.debit_in_account_currency = amount * exchange_rate
# set multi currency check
if row1.account_currency != so.company_currency or row2.account_currency != so.company_currency:
jv.multi_currency = 1
return jv.as_dict() return jv.as_dict()
@ -639,36 +652,38 @@ def get_payment_entry_from_purchase_order(purchase_order):
party_account = get_party_account(po.company, po.supplier, "Supplier") party_account = get_party_account(po.company, po.supplier, "Supplier")
party_account_currency = frappe.db.get_value("Account", party_account, "account_currency") party_account_currency = frappe.db.get_value("Account", party_account, "account_currency")
company_currency = get_company_currency(po.company)
if po.company_currency == party_account_currency: exchange_rate = get_exchange_rate(party_account, party_account_currency, po.company)
exchange_rate = 1
else:
exchange_rate = get_exchange_rate(party_account_currency, po.company_currency)
jv.exchange_rate = exchange_rate if party_account_currency == po.company_currency:
if party_account_currency == company_currency:
amount = flt(po.base_grand_total) - flt(po.advance_paid) amount = flt(po.base_grand_total) - flt(po.advance_paid)
else: else:
amount = flt(po.grand_total) - flt(po.advance_paid) amount = flt(po.grand_total) - flt(po.advance_paid)
# credit customer # credit customer
jv.get("accounts")[0].account = party_account row1 = jv.get("accounts")[0]
jv.get("accounts")[0].party_type = "Supplier" row1.account = party_account
jv.get("accounts")[0].party = po.supplier row1.party_type = "Supplier"
jv.get("accounts")[0].balance = get_balance_on(party_account) row1.party = po.supplier
jv.get("accounts")[0].party_balance = get_balance_on(party=po.supplier, party_type="Supplier") row1.balance = get_balance_on(party_account)
jv.get("accounts")[0].debit_in_account_currency = amount row1.party_balance = get_balance_on(party=po.supplier, party_type="Supplier")
jv.get("accounts")[0].reference_type = po.doctype row1.debit_in_account_currency = amount
jv.get("accounts")[0].reference_name = po.name row1.reference_type = po.doctype
jv.get("accounts")[0].is_advance = "Yes" row1.reference_name = po.name
row1.is_advance = "Yes"
row1.exchange_rate = exchange_rate
row1.account_type = "Payable"
# debit bank # debit bank
if jv.get("accounts")[1].account_currency == party_account_currency: row2 = jv.get("accounts")[1]
jv.get("accounts")[1].credit_in_account_currency = amount if row2.account_currency == party_account_currency:
row2.credit_in_account_currency = amount
else: else:
jv.get("accounts")[1].credit_in_account_currency = amount * exchange_rate row2.credit_in_account_currency = amount * exchange_rate
# set multi currency check
if row1.account_currency != po.company_currency or row2.account_currency != po.company_currency:
jv.multi_currency = 1
return jv.as_dict() return jv.as_dict()
@ -687,6 +702,9 @@ def get_payment_entry(doc):
d2.account = bank_account["account"] d2.account = bank_account["account"]
d2.balance = bank_account["balance"] d2.balance = bank_account["balance"]
d2.account_currency = bank_account["account_currency"] d2.account_currency = bank_account["account_currency"]
d2.account_type = bank_account["account_type"]
d2.exchange_rate = get_exchange_rate(bank_account["account"],
bank_account["account_currency"], doc.company)
return jv return jv
@ -712,27 +730,37 @@ def get_outstanding(args):
if not frappe.has_permission("Account"): if not frappe.has_permission("Account"):
frappe.msgprint(_("No Permission"), raise_exception=1) frappe.msgprint(_("No Permission"), raise_exception=1)
args = eval(args) args = eval(args)
company_currency = get_company_currency(args.get("company"))
if args.get("doctype") == "Journal Entry": if args.get("doctype") == "Journal Entry":
condition = " and party=%(party)s" if args.get("party") else "" condition = " and party=%(party)s" if args.get("party") else ""
against_jv_amount = frappe.db.sql(""" against_jv_amount = frappe.db.sql("""
select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0)) select sum(ifnull(debit_in_account_currency, 0)) - sum(ifnull(credit_in_account_currency, 0))
from `tabJournal Entry Account` where parent=%(docname)s and account=%(account)s {0} from `tabJournal Entry Account` where parent=%(docname)s and account=%(account)s {0}
and ifnull(reference_type, '')=''""".format(condition), args) and ifnull(reference_type, '')=''""".format(condition), args)
against_jv_amount = flt(against_jv_amount[0][0]) if against_jv_amount else 0 against_jv_amount = flt(against_jv_amount[0][0]) if against_jv_amount else 0
amount_field = "credit_in_account_currency" if against_jv_amount > 0 else "debit_in_account_currency"
return { return {
("credit" if against_jv_amount > 0 else "debit"): abs(against_jv_amount) amount_field: abs(against_jv_amount)
} }
elif args.get("doctype") == "Sales Invoice": elif args.get("doctype") in ("Sales Invoice", "Purchase Invoice"):
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", args["docname"], "outstanding_amount")) invoice = frappe.db.get_value(args["doctype"], args["docname"],
["outstanding_amount", "conversion_rate"], as_dict=1)
exchange_rate = invoice.conversion_rate if (args.get("account_currency") != company_currency) else 1
if args["doctype"] == "Sales Invoice":
amount_field = "credit_in_account_currency" \
if flt(invoice.outstanding_amount) > 0 else "debit_in_account_currency"
else:
amount_field = "debit_in_account_currency" \
if flt(invoice.outstanding_amount) > 0 else "credit_in_account_currency"
return { return {
("credit" if outstanding_amount > 0 else "debit"): abs(outstanding_amount) amount_field: abs(flt(invoice.outstanding_amount)),
} "exchange_rate": exchange_rate
elif args.get("doctype") == "Purchase Invoice":
outstanding_amount = flt(frappe.db.get_value("Purchase Invoice", args["docname"], "outstanding_amount"))
return {
("debit" if outstanding_amount > 0 else "credit"): abs(outstanding_amount)
} }
@frappe.whitelist() @frappe.whitelist()
@ -753,7 +781,7 @@ def get_party_account_and_balance(company, party_type, party):
} }
@frappe.whitelist() @frappe.whitelist()
def get_account_balance_and_party_type(account, date, company, credited=False): def get_account_balance_and_party_type(account, date, company, debit=None, credit=None, exchange_rate=None):
"""Returns dict of account balance and party type to be set in Journal Entry on selection of account.""" """Returns dict of account balance and party type to be set in Journal Entry on selection of account."""
if not frappe.has_permission("Account"): if not frappe.has_permission("Account"):
frappe.msgprint(_("No Permission"), raise_exception=1) frappe.msgprint(_("No Permission"), raise_exception=1)
@ -768,19 +796,37 @@ def get_account_balance_and_party_type(account, date, company, credited=False):
else: else:
party_type = "" party_type = ""
exchange_rate = None
if account_details.account_currency != company_currency:
if account_details.account_type == "Bank" and credited:
exchange_rate = get_average_exchange_rate(account)
else:
exchange_rate = get_exchange_rate(account_details.account_currency, company_currency)
grid_values = { grid_values = {
"balance": get_balance_on(account, date), "balance": get_balance_on(account, date),
"party_type": party_type, "party_type": party_type,
"account_type": account_details.account_type,
"account_currency": account_details.account_currency or company_currency, "account_currency": account_details.account_currency or company_currency,
"exchange_rate": get_exchange_rate(account, account_details.account_currency,
company, debit=debit, credit=credit, exchange_rate=exchange_rate)
} }
return grid_values, exchange_rate return grid_values
@frappe.whitelist()
def get_exchange_rate(account, account_currency, company,
reference_type=None, reference_name=None, debit=None, credit=None, exchange_rate=None):
from erpnext.setup.utils import get_exchange_rate
company_currency = get_company_currency(company)
account_details = frappe.db.get_value("Account", account, ["account_type", "root_type"], as_dict=1)
if account_currency != company_currency:
if reference_type in ("Sales Invoice", "Purchase Invoice") and reference_name:
exchange_rate = frappe.db.get_value(reference_type, reference_name, "conversion_rate")
elif account_details.account_type == "Bank" and \
((account_details.root_type == "Asset" and flt(credit) > 0) or
(account_details.root_type == "Liability" and debit)):
exchange_rate = get_average_exchange_rate(account)
if not exchange_rate:
exchange_rate = get_exchange_rate(account_currency, company_currency)
else:
exchange_rate = 1
return exchange_rate
def get_average_exchange_rate(account): def get_average_exchange_rate(account):
exchange_rate = 0 exchange_rate = 0

View File

@ -218,19 +218,20 @@ def make_journal_entry(account1, account2, amount, cost_center=None, exchange_ra
jv.company = "_Test Company" jv.company = "_Test Company"
jv.fiscal_year = "_Test Fiscal Year 2013" jv.fiscal_year = "_Test Fiscal Year 2013"
jv.user_remark = "test" jv.user_remark = "test"
jv.exchange_rate = exchange_rate jv.multi_currency = 1
jv.set("accounts", [ jv.set("accounts", [
{ {
"account": account1, "account": account1,
"cost_center": cost_center, "cost_center": cost_center,
"debit_in_account_currency": amount if amount > 0 else 0, "debit_in_account_currency": amount if amount > 0 else 0,
"credit_in_account_currency": abs(amount) if amount < 0 else 0, "credit_in_account_currency": abs(amount) if amount < 0 else 0,
"exchange_rate": exchange_rate
}, { }, {
"account": account2, "account": account2,
"cost_center": cost_center, "cost_center": cost_center,
"credit_in_account_currency": amount if amount > 0 else 0, "credit_in_account_currency": amount if amount > 0 else 0,
"debit_in_account_currency": abs(amount) if amount < 0 else 0, "debit_in_account_currency": abs(amount) if amount < 0 else 0,
exchange_rate: exchange_rate
} }
]) ])
if save or submit: if save or submit:

View File

@ -38,19 +38,18 @@
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"fieldname": "account_currency", "fieldname": "account_type",
"fieldtype": "Link", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Account Currency", "label": "Account Type",
"no_copy": 1, "no_copy": 0,
"options": "Currency",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 1, "print_hide": 1,
"read_only": 1, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -196,6 +195,96 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": "",
"depends_on": "",
"fieldname": "currency_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Currency",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "account_currency",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Account Currency",
"no_copy": 1,
"options": "Currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "column_break_10",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "exchange_rate",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Exchange Rate",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@ -474,7 +563,7 @@
"is_submittable": 0, "is_submittable": 0,
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"modified": "2015-09-04 03:29:37.127968", "modified": "2015-09-09 12:55:59.270539",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Journal Entry Account", "name": "Journal Entry Account",

View File

@ -216,7 +216,7 @@ class PurchaseInvoice(BuyingController):
'party_type': 'Supplier', 'party_type': 'Supplier',
'party': self.supplier, 'party': self.supplier,
'is_advance' : 'Yes', 'is_advance' : 'Yes',
'dr_or_cr' : 'debit', 'dr_or_cr' : 'debit_in_account_currency',
'unadjusted_amt' : flt(d.advance_amount), 'unadjusted_amt' : flt(d.advance_amount),
'allocated_amt' : flt(d.allocated_amount) 'allocated_amt' : flt(d.allocated_amount)
} }

View File

@ -219,7 +219,8 @@ class TestPurchaseInvoice(unittest.TestCase):
pi.load_from_db() pi.load_from_db()
self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account` self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account`
where reference_type='Purchase Invoice' and reference_name=%s and debit=300""", pi.name)) where reference_type='Purchase Invoice'
and reference_name=%s and debit_in_account_currency=300""", pi.name))
self.assertEqual(pi.outstanding_amount, 1212.30) self.assertEqual(pi.outstanding_amount, 1212.30)

View File

@ -141,6 +141,9 @@
"supplier": "_Test Supplier", "supplier": "_Test Supplier",
"supplier_name": "_Test Supplier" "supplier_name": "_Test Supplier"
}, },
{ {
"bill_no": "NA", "bill_no": "NA",
"buying_price_list": "_Test Price List", "buying_price_list": "_Test Price List",

View File

@ -260,7 +260,7 @@ class SalesInvoice(SellingController):
'party_type': 'Customer', 'party_type': 'Customer',
'party': self.customer, 'party': self.customer,
'is_advance' : 'Yes', 'is_advance' : 'Yes',
'dr_or_cr' : 'credit', 'dr_or_cr' : 'credit_in_account_currency',
'unadjusted_amt' : flt(d.advance_amount), 'unadjusted_amt' : flt(d.advance_amount),
'allocated_amt' : flt(d.allocated_amount) 'allocated_amt' : flt(d.allocated_amount)
} }

View File

@ -661,7 +661,7 @@ class TestSalesInvoice(unittest.TestCase):
where reference_name=%s""", si.name)) where reference_name=%s""", si.name))
self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account` self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account`
where reference_name=%s and credit=300""", si.name)) where reference_name=%s and credit_in_account_currency=300""", si.name))
self.assertEqual(si.outstanding_amount, 261.8) self.assertEqual(si.outstanding_amount, 261.8)

View File

@ -198,21 +198,26 @@ def update_against_doc(d, jv_obj):
jv_detail.set("reference_name", d["against_voucher"]) jv_detail.set("reference_name", d["against_voucher"])
if d['allocated_amt'] < d['unadjusted_amt']: if d['allocated_amt'] < d['unadjusted_amt']:
jvd = frappe.db.sql("""select cost_center, balance, against_account, is_advance jvd = frappe.db.sql("""
from `tabJournal Entry Account` where name = %s""", d['voucher_detail_no']) select cost_center, balance, against_account, is_advance, account_type, exchange_rate
from `tabJournal Entry Account` where name = %s
""", d['voucher_detail_no'], as_dict=True)
# new entry with balance amount # new entry with balance amount
ch = jv_obj.append("accounts") ch = jv_obj.append("accounts")
ch.account = d['account'] ch.account = d['account']
ch.account_type = jvd[0]['account_type']
ch.exchange_rate = jvd[0]['exchange_rate']
ch.party_type = d["party_type"] ch.party_type = d["party_type"]
ch.party = d["party"] ch.party = d["party"]
ch.cost_center = cstr(jvd[0][0]) ch.cost_center = cstr(jvd[0]["cost_center"])
ch.balance = flt(jvd[0][1]) ch.balance = flt(jvd[0]["balance"])
ch.set(d['dr_or_cr'], flt(d['unadjusted_amt']) - flt(d['allocated_amt'])) ch.set(d['dr_or_cr'], flt(d['unadjusted_amt']) - flt(d['allocated_amt']))
ch.set(d['dr_or_cr']== 'debit' and 'credit' or 'debit', 0) ch.set(d['dr_or_cr']== 'debit' and 'credit' or 'debit', 0)
ch.against_account = cstr(jvd[0][2]) ch.against_account = cstr(jvd[0]["against_account"])
ch.reference_type = original_reference_type ch.reference_type = original_reference_type
ch.reference_name = original_reference_name ch.reference_name = original_reference_name
ch.is_advance = cstr(jvd[0][3]) ch.is_advance = cstr(jvd[0]["is_advance"])
ch.docstatus = 1 ch.docstatus = 1
# will work as update after submit # will work as update after submit

View File

@ -236,8 +236,8 @@ class AccountsController(TransactionBase):
.format(account, " or ".join(valid_currency))) .format(account, " or ".join(valid_currency)))
def set_balance_in_account_currency(self, gl_dict, account_currency=None): def set_balance_in_account_currency(self, gl_dict, account_currency=None):
if not (self.get("conversion_rate") or self.get("exchange_rate")) \ if (not self.get("conversion_rate") and self.doctype!="Journal Entry"
and account_currency!=self.company_currency: and account_currency!=self.company_currency):
frappe.throw(_("Account: {0} with currency: {1} can not be selected") frappe.throw(_("Account: {0} with currency: {1} can not be selected")
.format(gl_dict.account, account_currency)) .format(gl_dict.account, account_currency))

View File

@ -37,18 +37,18 @@ def execute():
""", (company.default_currency, company.name)) """, (company.default_currency, company.name))
# update exchange rate, debit/credit in account currency in Journal Entry # update exchange rate, debit/credit in account currency in Journal Entry
frappe.db.sql("""update `tabJournal Entry` set exchange_rate=1""")
frappe.db.sql(""" frappe.db.sql("""
update update `tabJournal Entry Account` jea
`tabJournal Entry Account` jea, `tabJournal Entry` je set exchange_rate=1,
set
debit_in_account_currency=debit, debit_in_account_currency=debit,
credit_in_account_currency=credit, credit_in_account_currency=credit,
account_currency=%s account_type=(select account_type from `tabAccount` where name=jea.account)
where """)
jea.parent = je.name
and je.company=%s frappe.db.sql("""
update `tabJournal Entry Account` jea, `tabJournal Entry` je
set account_currency=%s
where jea.parent = je.name and je.company=%s
""", (company.default_currency, company.name)) """, (company.default_currency, company.name))
# update debit/credit in account currency in GL Entry # update debit/credit in account currency in GL Entry
@ -87,7 +87,15 @@ def execute():
break break
if not party_account_exists: if not party_account_exists:
party_account = party_gle.account if party_gle else company.default_receivable_account party_account = None
if party_gle:
party_account = party_gle.account
else:
default_receivable_account_currency = frappe.db.get_value("Account",
company.default_receivable_account, "account_currency")
if default_receivable_account_currency != company.default_currency:
party_account = company.default_receivable_account
if party_account: if party_account:
party.append("accounts", { party.append("accounts", {
"company": company.name, "company": company.name,