Fixed conflict
diff --git a/erpnext/accounts/doctype/account/account.json b/erpnext/accounts/doctype/account/account.json
index 139d684..b2b9179 100644
--- a/erpnext/accounts/doctype/account/account.json
+++ b/erpnext/accounts/doctype/account/account.json
@@ -7,7 +7,7 @@
"description": "Heads (or groups) against which Accounting Entries are made and balances are maintained.",
"docstatus": 0,
"doctype": "DocType",
- "document_type": "Master",
+ "document_type": "Setup",
"fields": [
{
"allow_on_submit": 0,
@@ -170,6 +170,30 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "depends_on": "eval:doc.is_group==0",
+ "fieldname": "account_currency",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Currency",
+ "no_copy": 0,
+ "options": "Currency",
+ "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": "column_break1",
"fieldtype": "Column Break",
"hidden": 0,
@@ -402,7 +426,7 @@
"is_submittable": 0,
"issingle": 0,
"istable": 0,
- "modified": "2015-07-20 03:54:14.297995",
+ "modified": "2015-08-28 17:17:20.899845",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account",
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 46f7520..7f632b1 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -28,6 +28,7 @@
self.validate_warehouse_account()
self.validate_frozen_accounts_modifier()
self.validate_balance_must_be_debit_or_credit()
+ self.validate_account_currency()
def validate_parent(self):
"""Fetch Parent Details and validate parent account"""
@@ -86,6 +87,14 @@
frappe.throw(_("Account balance already in Debit, you are not allowed to set 'Balance Must Be' as 'Credit'"))
elif account_balance < 0 and self.balance_must_be == "Debit":
frappe.throw(_("Account balance already in Credit, you are not allowed to set 'Balance Must Be' as 'Debit'"))
+
+ def validate_account_currency(self):
+ if not self.account_currency:
+ self.account_currency = frappe.db.get_value("Company", self.company, "default_currency")
+
+ elif self.account_currency != frappe.db.get_value("Account", self.name, "account_currency"):
+ if frappe.db.get_value("GL Entry", {"account": self.name}):
+ frappe.throw(_("Currency can not be changed after making entries using some other currency"))
def convert_group_to_ledger(self):
if self.check_if_child_exists():
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
index ce3a7fd..bfb5240 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
@@ -36,7 +36,8 @@
"is_group": is_group,
"root_type": root_type,
"report_type": report_type,
- "account_type": child.get("account_type")
+ "account_type": child.get("account_type"),
+ "account_currency": frappe.db.get_value("Company", company, "default_currency")
})
if root_account:
diff --git a/erpnext/accounts/doctype/account/test_account.py b/erpnext/accounts/doctype/account/test_account.py
index 2a3feda..83516da 100644
--- a/erpnext/accounts/doctype/account/test_account.py
+++ b/erpnext/accounts/doctype/account/test_account.py
@@ -9,36 +9,39 @@
accounts = [
# [account_name, parent_account, is_group]
- ["_Test Account Bank Account", "Bank Accounts", 0, "Bank"],
+ ["_Test Bank", "Bank Accounts", 0, "Bank", None],
+ ["_Test Bank USD", "Bank Accounts", 0, "Bank", "USD"],
+ ["_Test Bank EUR", "Bank Accounts", 0, "Bank", "EUR"],
- ["_Test Account Stock Expenses", "Direct Expenses", 1, None],
- ["_Test Account Shipping Charges", "_Test Account Stock Expenses", 0, "Chargeable"],
- ["_Test Account Customs Duty", "_Test Account Stock Expenses", 0, "Tax"],
- ["_Test Account Insurance Charges", "_Test Account Stock Expenses", 0, "Chargeable"],
- ["_Test Account Stock Adjustment", "_Test Account Stock Expenses", 0, "Stock Adjustment"],
+ ["_Test Account Stock Expenses", "Direct Expenses", 1, None, None],
+ ["_Test Account Shipping Charges", "_Test Account Stock Expenses", 0, "Chargeable", None],
+ ["_Test Account Customs Duty", "_Test Account Stock Expenses", 0, "Tax", None],
+ ["_Test Account Insurance Charges", "_Test Account Stock Expenses", 0, "Chargeable", None],
+ ["_Test Account Stock Adjustment", "_Test Account Stock Expenses", 0, "Stock Adjustment", None],
+ ["_Test Account Tax Assets", "Current Assets", 1, None, None],
+ ["_Test Account VAT", "_Test Account Tax Assets", 0, "Tax", None],
+ ["_Test Account Service Tax", "_Test Account Tax Assets", 0, "Tax", None],
- ["_Test Account Tax Assets", "Current Assets", 1, None],
- ["_Test Account VAT", "_Test Account Tax Assets", 0, "Tax"],
- ["_Test Account Service Tax", "_Test Account Tax Assets", 0, "Tax"],
+ ["_Test Account Reserves and Surplus", "Current Liabilities", 0, None, None],
- ["_Test Account Reserves and Surplus", "Current Liabilities", 0, None],
-
- ["_Test Account Cost for Goods Sold", "Expenses", 0, None],
- ["_Test Account Excise Duty", "_Test Account Tax Assets", 0, "Tax"],
- ["_Test Account Education Cess", "_Test Account Tax Assets", 0, "Tax"],
- ["_Test Account S&H Education Cess", "_Test Account Tax Assets", 0, "Tax"],
- ["_Test Account CST", "Direct Expenses", 0, "Tax"],
- ["_Test Account Discount", "Direct Expenses", 0, None],
- ["_Test Write Off", "Indirect Expenses", 0, None],
+ ["_Test Account Cost for Goods Sold", "Expenses", 0, None, None],
+ ["_Test Account Excise Duty", "_Test Account Tax Assets", 0, "Tax", None],
+ ["_Test Account Education Cess", "_Test Account Tax Assets", 0, "Tax", None],
+ ["_Test Account S&H Education Cess", "_Test Account Tax Assets", 0, "Tax", None],
+ ["_Test Account CST", "Direct Expenses", 0, "Tax", None],
+ ["_Test Account Discount", "Direct Expenses", 0, None, None],
+ ["_Test Write Off", "Indirect Expenses", 0, None, None],
# related to Account Inventory Integration
- ["_Test Account Stock In Hand", "Current Assets", 0, None],
- ["_Test Account Fixed Assets", "Current Assets", 0, None],
+ ["_Test Account Stock In Hand", "Current Assets", 0, None, None],
+ ["_Test Account Fixed Assets", "Current Assets", 0, None, None],
# Receivable / Payable Account
- ["_Test Receivable", "Current Assets", 0, "Receivable"],
- ["_Test Payable", "Current Liabilities", 0, "Payable"],
+ ["_Test Receivable", "Current Assets", 0, "Receivable", None],
+ ["_Test Payable", "Current Liabilities", 0, "Payable", None],
+ ["_Test Receivable USD", "Current Assets", 0, "Receivable", "USD"],
+ ["_Test Payable USD", "Current Liabilities", 0, "Payable", "USD"]
]
for company, abbr in [["_Test Company", "_TC"], ["_Test Company 1", "_TC1"]]:
@@ -48,7 +51,8 @@
"parent_account": parent_account + " - " + abbr,
"company": company,
"is_group": is_group,
- "account_type": account_type
- } for account_name, parent_account, is_group, account_type in accounts])
+ "account_type": account_type,
+ "account_currency": currency
+ } for account_name, parent_account, is_group, account_type, currency in accounts])
return test_objects
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.json b/erpnext/accounts/doctype/gl_entry/gl_entry.json
index 039a3f4..23a44aa 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.json
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.json
@@ -156,7 +156,7 @@
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
- "label": "Debit Amt",
+ "label": "Debit Amount",
"no_copy": 0,
"oldfieldname": "debit",
"oldfieldtype": "Currency",
@@ -180,7 +180,7 @@
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
- "label": "Credit Amt",
+ "label": "Credit Amount",
"no_copy": 0,
"oldfieldname": "credit",
"oldfieldtype": "Currency",
@@ -198,6 +198,75 @@
"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": 0,
+ "options": "Currency",
+ "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": "debit_in_account_currency",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Debit Amount in Account Currency",
+ "no_copy": 0,
+ "options": "currency",
+ "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": "credit_in_account_currency",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Credit Amount in Account Currency",
+ "no_copy": 0,
+ "options": "currency",
+ "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": "against",
"fieldtype": "Text",
"hidden": 0,
@@ -442,7 +511,7 @@
"is_submittable": 0,
"issingle": 0,
"istable": 0,
- "modified": "2015-07-09 15:51:04.986518",
+ "modified": "2015-08-28 17:14:52.661217",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GL Entry",
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index c459628..f89fb62 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -10,6 +10,8 @@
from frappe.model.document import Document
class CustomerFrozen(frappe.ValidationError): pass
+class InvalidCurrency(frappe.ValidationError): pass
+class InvalidAccountCurrency(frappe.ValidationError): pass
class GLEntry(Document):
def validate(self):
@@ -20,6 +22,7 @@
self.check_pl_account()
self.validate_cost_center()
self.validate_party()
+ self.validate_currency()
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'):
self.validate_account_details(adv_adj)
@@ -98,6 +101,25 @@
if not frozen_accounts_modifier in frappe.get_roles():
if frappe.db.get_value(self.party_type, self.party, "is_frozen"):
frappe.throw("{0} {1} is frozen".format(self.party_type, self.party), CustomerFrozen)
+
+ def validate_currency(self):
+ company_currency = frappe.db.get_value("Company", self.company, "default_currency")
+ account_currency = frappe.db.get_value("Account", self.account, "account_currency") or company_currency
+
+ if not self.account_currency:
+ self.account_currency = company_currency
+ if account_currency != self.account_currency:
+ frappe.throw(_("Accounting Entry for {0} can only be made in currency: {1}")
+ .format(self.account, (account_currency or company_currency)), InvalidAccountCurrency)
+
+
+ if self.party_type and self.party:
+ party_account_currency = frappe.db.get_value(self.party_type, self.party, "party_account_currency") \
+ or company_currency
+
+ if party_account_currency != self.account_currency:
+ frappe.throw(_("Accounting Entry for {0}: {1} can only be made in currency: {2}")
+ .format(self.party_type, self.party, party_account_currency), InvalidAccountCurrency)
def validate_balance_type(account, adv_adj=False):
if not adv_adj and account:
diff --git a/erpnext/accounts/doctype/gl_entry/test_gl_entry.py b/erpnext/accounts/doctype/gl_entry/test_gl_entry.py
index 383409c..146d084 100644
--- a/erpnext/accounts/doctype/gl_entry/test_gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/test_gl_entry.py
@@ -11,7 +11,7 @@
frappe.db.set_value("Company", "_Test Company", "round_off_cost_center", "_Test Cost Center - _TC")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
- "_Test Account Bank Account - _TC", 100, "_Test Cost Center - _TC", submit=False)
+ "_Test Bank - _TC", 100, "_Test Cost Center - _TC", submit=False)
jv.get("accounts")[0].debit = 100.01
jv.flags.ignore_validate = True
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index 1e77422..4ed4043 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -2,8 +2,41 @@
// License: GNU General Public License v3. See license.txt
frappe.provide("erpnext.accounts");
+frappe.provide("erpnext.journal_entry");
frappe.require("assets/erpnext/js/utils.js");
+frappe.ui.form.on("Journal Entry", {
+ refresh: function(frm) {
+ erpnext.toggle_naming_series();
+ cur_frm.cscript.voucher_type(frm.doc);
+
+ if(frm.doc.docstatus==1) {
+ cur_frm.add_custom_button(__('View Ledger'), function() {
+ frappe.route_options = {
+ "voucher_no": frm.doc.name,
+ "from_date": frm.doc.posting_date,
+ "to_date": frm.doc.posting_date,
+ "company": frm.doc.company,
+ group_by_voucher: 0
+ };
+ frappe.set_route("query-report", "General Ledger");
+ }, "icon-table");
+ }
+
+ // hide /unhide fields based on currency
+ erpnext.journal_entry.toggle_fields_based_on_currency(frm);
+ }
+})
+
+erpnext.journal_entry.toggle_fields_based_on_currency = function(frm) {
+ var fields = ["debit_in_account_currency", "credit_in_account_currency"];
+
+ var company_currency = erpnext.get_currency(frm.doc.company);
+
+ var grid = frm.get_field("accounts").grid;
+ grid.set_column_disp(fields, grid.account_currency!=company_currency);
+}
+
erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
onload: function() {
this.load_defaults();
@@ -161,8 +194,10 @@
// set difference
if(doc.difference) {
if(doc.difference > 0) {
+ row.credit_in_account_currency = doc.difference;
row.credit = doc.difference;
} else {
+ row.debit_in_account_currency = -doc.difference;
row.debit = -doc.difference;
}
}
@@ -172,24 +207,6 @@
cur_frm.script_manager.make(erpnext.accounts.JournalEntry);
-cur_frm.cscript.refresh = function(doc) {
- erpnext.toggle_naming_series();
- cur_frm.cscript.voucher_type(doc);
-
- if(doc.docstatus==1) {
- cur_frm.add_custom_button(__('View Ledger'), function() {
- frappe.route_options = {
- "voucher_no": doc.name,
- "from_date": doc.posting_date,
- "to_date": doc.posting_date,
- "company": doc.company,
- group_by_voucher: 0
- };
- frappe.set_route("query-report", "General Ledger");
- }, "icon-table");
- }
-}
-
cur_frm.cscript.company = function(doc, cdt, cdn) {
cur_frm.refresh_fields();
erpnext.get_fiscal_year(doc.company, doc.posting_date);
@@ -201,10 +218,10 @@
cur_frm.cscript.update_totals = function(doc) {
var td=0.0; var tc =0.0;
- var el = doc.accounts || [];
- for(var i in el) {
- td += flt(el[i].debit, precision("debit", el[i]));
- tc += flt(el[i].credit, precision("credit", el[i]));
+ var accounts = doc.accounts || [];
+ for(var i in accounts) {
+ td += flt(accounts[i].debit, precision("debit", accounts[i]));
+ tc += flt(accounts[i].credit, precision("credit", accounts[i]));
}
var doc = locals[doc.doctype][doc.name];
doc.total_debit = td;
@@ -213,32 +230,12 @@
refresh_many(['total_debit','total_credit','difference']);
}
-cur_frm.cscript.debit = function(doc,dt,dn) { cur_frm.cscript.update_totals(doc); }
-cur_frm.cscript.credit = function(doc,dt,dn) { cur_frm.cscript.update_totals(doc); }
-
cur_frm.cscript.get_balance = function(doc,dt,dn) {
cur_frm.cscript.update_totals(doc);
return $c_obj(cur_frm.doc, 'get_balance', '', function(r, rt){
cur_frm.refresh();
});
}
-// Get balance
-// -----------
-
-cur_frm.cscript.account = function(doc,dt,dn) {
- var d = locals[dt][dn];
- if(d.account) {
- return frappe.call({
- method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_account_balance_and_party_type",
- args: {account: d.account, date: doc.posting_date},
- callback: function(r) {
- $.extend(d, r.message);
- refresh_field('balance', d.name, 'accounts');
- refresh_field('party_type', d.name, 'accounts');
- }
- });
- }
-}
cur_frm.cscript.validate = function(doc,cdt,cdn) {
cur_frm.cscript.update_totals(doc);
@@ -303,22 +300,78 @@
}
}
-frappe.ui.form.on("Journal Entry Account", "party", function(frm, cdt, cdn) {
- var d = frappe.get_doc(cdt, cdn);
- if(!d.account && d.party_type && d.party) {
- return frm.call({
- method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_party_account_and_balance",
- child: d,
- args: {
- company: frm.doc.company,
- party_type: d.party_type,
- party: d.party
- }
- });
+frappe.ui.form.on("Journal Entry Account", {
+ party: function(frm, cdt, cdn) {
+ var d = frappe.get_doc(cdt, cdn);
+ if(!d.account && d.party_type && d.party) {
+ return frm.call({
+ method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_party_account_and_balance",
+ child: d,
+ args: {
+ company: frm.doc.company,
+ party_type: d.party_type,
+ party: d.party
+ }
+ });
+ }
+ },
+
+ account: function(frm, dt, dn) {
+ var d = locals[dt][dn];
+ if(d.account) {
+ return frappe.call({
+ method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_account_balance_and_party_type",
+ args: {
+ account: d.account,
+ date: frm.doc.posting_date,
+ company: frm.doc.company,
+ credited: flt(d.credit_in_account_currency) > 0 ? true : false
+ },
+ callback: function(r) {
+ if(r.message) {
+ $.extend(d, r.message[0]);
+ refresh_field('balance', d.name, '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) {
+ var company_currency = erpnext.get_currency(frm.doc.company);
+ 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) {
+ var company_currency = erpnext.get_currency(frm.doc.company);
+ 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) {
+ cur_frm.cscript.update_totals(frm.doc);
+ },
+
+ credit: function(frm, dt, dn) {
+ cur_frm.cscript.update_totals(frm.doc);
}
})
frappe.ui.form.on("Journal Entry Account", "accounts_remove", function(frm) {
cur_frm.cscript.update_totals(frm.doc);
-});
-
+});
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json
index 02a9842..ea632f1 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.json
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json
@@ -151,6 +151,28 @@
"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,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "2_add_edit_gl_entries",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1002,7 +1024,7 @@
"is_submittable": 1,
"issingle": 0,
"istable": 0,
- "modified": "2015-08-27 03:19:18.634225",
+ "modified": "2015-08-27 16:07:33.265318",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index f5f22dc..3db1820 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -3,9 +3,9 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import cstr, flt, fmt_money, formatdate, getdate, date_diff
+from frappe.utils import cstr, flt, fmt_money, formatdate
from frappe import msgprint, _, scrub
-from erpnext.setup.utils import get_company_currency
+from erpnext.setup.utils import get_company_currency, get_exchange_rate
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.accounts.utils import get_balance_on
@@ -26,6 +26,7 @@
self.validate_party()
self.validate_cheque_info()
self.validate_entries_for_advance()
+ self.validate_multi_currency()
self.validate_debit_and_credit()
self.validate_against_jv()
self.validate_reference_doc()
@@ -35,6 +36,7 @@
self.validate_expense_claim()
self.validate_credit_debit_note()
self.validate_empty_accounts_table()
+ self.set_account_and_party_balance()
self.set_title()
def on_submit(self):
@@ -144,6 +146,7 @@
self.reference_totals = {}
self.reference_types = {}
+ self.reference_parties = {}
for d in self.get("accounts"):
if not d.reference_type:
@@ -151,8 +154,8 @@
if not d.reference_name:
d.reference_type = None
if d.reference_type and d.reference_name and (d.reference_type in field_dict.keys()):
- dr_or_cr = "credit" if d.reference_type in ("Sales Order", "Sales Invoice") \
- else "debit"
+ dr_or_cr = "credit_in_account_currency" \
+ if d.reference_type in ("Sales Order", "Sales Invoice") else "debit_in_account_currency"
# check debit or credit type Sales / Purchase Order
if d.reference_type=="Sales Order" and flt(d.debit) > 0:
@@ -166,6 +169,8 @@
self.reference_totals[d.reference_name] = 0.0
self.reference_totals[d.reference_name] += flt(d.get(dr_or_cr))
self.reference_types[d.reference_name] = d.reference_type
+ if d.party_type and d.party:
+ self.reference_parties[d.reference_name] = [d.party_type, d.party]
against_voucher = frappe.db.get_value(d.reference_type, d.reference_name,
[scrub(dt) for dt in field_dict.get(d.reference_type)])
@@ -191,23 +196,31 @@
"""Validate totals, stopped and docstatus for orders"""
for reference_name, total in self.reference_totals.iteritems():
reference_type = self.reference_types[reference_name]
+ party_type, party = self.reference_parties.get(reference_name)
if reference_type in ("Sales Order", "Purchase Order"):
- voucher_properties = frappe.db.get_value(reference_type, reference_name,
- ["docstatus", "per_billed", "status", "advance_paid", "base_grand_total"])
+ voucher_properties = frappe.db.get_value(reference_type, reference_name,
+ ["docstatus", "per_billed", "status", "advance_paid",
+ "base_grand_total", "grand_total", "currency"], as_dict=1)
- if voucher_properties[0] != 1:
+ if voucher_properties.docstatus != 1:
frappe.throw(_("{0} {1} is not submitted").format(reference_type, reference_name))
- if flt(voucher_properties[1]) >= 100:
+ if flt(voucher_properties.per_billed) >= 100:
frappe.throw(_("{0} {1} is fully billed").format(reference_type, reference_name))
- if cstr(voucher_properties[2]) == "Stopped":
+ if cstr(voucher_properties.status) == "Stopped":
frappe.throw(_("{0} {1} is stopped").format(reference_type, reference_name))
-
- if flt(voucher_properties[4]) < (flt(voucher_properties[3]) + total):
+
+ party_account_currency = frappe.db.get_value(party_type, party, "party_account_currency")
+ if party_account_currency == self.company_currency:
+ voucher_total = voucher_properties.base_grand_total
+ else:
+ voucher_total = voucher_properties.grand_total
+
+ if flt(voucher_total) < (flt(voucher_properties.advance_paid) + total):
frappe.throw(_("Advance paid against {0} {1} cannot be greater \
- than Grand Total {2}").format(reference_type, reference_name, voucher_properties[4]))
+ than Grand Total {2}").format(reference_type, reference_name, voucher_total))
def validate_invoices(self):
"""Validate totals and docstatus for invoices"""
@@ -216,14 +229,14 @@
if reference_type in ("Sales Invoice", "Purchase Invoice"):
voucher_properties = frappe.db.get_value(reference_type, reference_name,
- ["docstatus", "outstanding_amount"])
+ ["docstatus", "outstanding_amount"], as_dict=1)
- if voucher_properties[0] != 1:
+ if voucher_properties.docstatus != 1:
frappe.throw(_("{0} {1} is not submitted").format(reference_type, reference_name))
- if total and flt(voucher_properties[1]) < total:
- frappe.throw(_("Payment against {0} {1} cannot be greater \
- than Outstanding Amount {2}").format(reference_type, reference_name, voucher_properties[1]))
+ if total and flt(voucher_properties.outstanding_amount) < total:
+ frappe.throw(_("Payment against {0} {1} cannot be greater than Outstanding Amount {2}")
+ .format(reference_type, reference_name, voucher_properties.outstanding_amount))
def set_against_account(self):
accounts_debited, accounts_credited = [], []
@@ -237,13 +250,12 @@
def validate_debit_and_credit(self):
self.total_debit, self.total_credit, self.difference = 0, 0, 0
-
for d in self.get("accounts"):
if d.debit and d.credit:
frappe.throw(_("You cannot credit and debit same account at the same time"))
- self.total_debit = flt(self.total_debit) + flt(d.debit, self.precision("debit", "accounts"))
- self.total_credit = flt(self.total_credit) + flt(d.credit, self.precision("credit", "accounts"))
+ self.total_debit = flt(self.total_debit) + flt(d.debit, d.precision("debit"))
+ self.total_credit = flt(self.total_credit) + flt(d.credit, d.precision("credit"))
self.difference = flt(self.total_debit, self.precision("total_debit")) - \
flt(self.total_credit, self.precision("total_credit"))
@@ -251,6 +263,43 @@
if self.difference:
frappe.throw(_("Total Debit must be equal to Total Credit. The difference is {0}")
.format(self.difference))
+
+ def validate_multi_currency(self):
+ alternate_currency = []
+ for d in self.get("accounts"):
+ d.account_currency = frappe.db.get_value("Account", d.account, "account_currency") or self.company_currency
+
+ if d.account_currency!=self.company_currency and d.account_currency not in alternate_currency:
+ alternate_currency.append(d.account_currency)
+
+ if alternate_currency:
+ if len(alternate_currency) > 1:
+ frappe.throw(_("Only one alternate currency can be used in a single Journal Entry"))
+
+ 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"):
+ exchange_rate = self.exchange_rate if d.account_currency != self.company_currency else 1
+
+ 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):
+ for d in self.get("accounts"):
+ if d.account_currency != self.company_currency:
+ account_type = frappe.db.get_value("Account", d.account, "account_type")
+ if account_type == "Bank" and flt(d.credit_in_account_currency) > 0:
+ self.exchange_rate = get_average_exchange_rate(d.account)
+ break
+ if not self.exchange_rate:
+ self.exchange_rate = get_exchange_rate(d.account_currency, self.company_currency)
+
+
def create_remarks(self):
r = []
@@ -260,15 +309,13 @@
else:
msgprint(_("Please enter Reference date"), raise_exception=frappe.MandatoryError)
- company_currency = get_company_currency(self.company)
-
for d in self.get('accounts'):
if d.reference_type=="Sales Invoice" and d.credit:
- r.append(_("{0} against Sales Invoice {1}").format(fmt_money(flt(d.credit), currency = company_currency), \
+ r.append(_("{0} against Sales Invoice {1}").format(fmt_money(flt(d.credit), currency = self.company_currency), \
d.reference_name))
if d.reference_type=="Sales Order" and d.credit:
- r.append(_("{0} against Sales Order {1}").format(fmt_money(flt(d.credit), currency = company_currency), \
+ r.append(_("{0} against Sales Order {1}").format(fmt_money(flt(d.credit), currency = self.company_currency), \
d.reference_name))
if d.reference_type == "Purchase Invoice" and d.debit:
@@ -276,11 +323,11 @@
from `tabPurchase Invoice` where name=%s""", d.reference_name)
if bill_no and bill_no[0][0] and bill_no[0][0].lower().strip() \
not in ['na', 'not applicable', 'none']:
- r.append(_('{0} against Bill {1} dated {2}').format(fmt_money(flt(d.debit), currency=company_currency), bill_no[0][0],
+ r.append(_('{0} against Bill {1} dated {2}').format(fmt_money(flt(d.debit), currency=self.company_currency), bill_no[0][0],
bill_no[0][1] and formatdate(bill_no[0][1].strftime('%Y-%m-%d'))))
if d.reference_type == "Purchase Order" and d.debit:
- r.append(_("{0} against Purchase Order {1}").format(fmt_money(flt(d.credit), currency = company_currency), \
+ r.append(_("{0} against Purchase Order {1}").format(fmt_money(flt(d.credit), currency = self.company_currency), \
d.reference_name))
if self.user_remark:
@@ -301,10 +348,9 @@
self.set_total_amount(d.debit or d.credit)
def set_total_amount(self, amt):
- company_currency = get_company_currency(self.company)
self.total_amount = amt
from frappe.utils import money_in_words
- self.total_amount_in_words = money_in_words(amt, company_currency)
+ self.total_amount_in_words = money_in_words(amt, self.company_currency)
def make_gl_entries(self, cancel=0, adv_adj=0):
from erpnext.accounts.general_ledger import make_gl_entries
@@ -318,8 +364,11 @@
"party_type": d.party_type,
"party": d.party,
"against": d.against_account,
- "debit": flt(d.debit, self.precision("debit", "accounts")),
- "credit": flt(d.credit, self.precision("credit", "accounts")),
+ "debit": flt(d.debit, d.precision("debit")),
+ "credit": flt(d.credit, d.precision("credit")),
+ "account_currency": d.account_currency,
+ "debit_in_account_currency": flt(d.debit_in_account_currency, d.precision("debit_in_account_currency")),
+ "credit_in_account_currency": flt(d.credit_in_account_currency, d.precision("credit_in_account_currency")),
"against_voucher_type": d.reference_type,
"against_voucher": d.reference_name,
"remarks": self.remark,
@@ -426,6 +475,11 @@
def validate_empty_accounts_table(self):
if not self.get('accounts'):
frappe.throw("Accounts table cannot be blank.")
+
+ def set_account_and_party_balance(self):
+ for d in self.get("accounts"):
+ d.account_balance = get_balance_on(account=d.account, date=self.posting_date)
+ d.party_balance = get_balance_on(party_type=d.party_type, party=d.party, date=self.posting_date)
@frappe.whitelist()
def get_default_bank_cash_account(company, voucher_type, mode_of_payment=None):
@@ -448,7 +502,8 @@
if account:
return {
"account": account,
- "balance": get_balance_on(account)
+ "balance": get_balance_on(account),
+ "account_currency": frappe.db.get_value("Account", account, "account_currency")
}
@frappe.whitelist()
@@ -456,21 +511,33 @@
"""Returns new Journal Entry document as dict for given Sales Invoice"""
from erpnext.accounts.utils import get_balance_on
si = frappe.get_doc("Sales Invoice", sales_invoice)
+
+ # exchange rate
+ if si.company_currency == si.party_account_currency:
+ exchange_rate = 1
+ else:
+ exchange_rate = get_exchange_rate(si.party_account_currency, si.company_currency)
+
jv = get_payment_entry(si)
jv.remark = 'Payment received against Sales Invoice {0}. {1}'.format(si.name, si.remarks)
-
+ jv.exchange_rate = exchange_rate
+
# credit customer
jv.get("accounts")[0].account = si.debit_to
+ jv.get("accounts")[0].account_currency = si.party_account_currency
jv.get("accounts")[0].party_type = "Customer"
jv.get("accounts")[0].party = si.customer
jv.get("accounts")[0].balance = get_balance_on(si.debit_to)
jv.get("accounts")[0].party_balance = get_balance_on(party=si.customer, party_type="Customer")
- jv.get("accounts")[0].credit = si.outstanding_amount
+ jv.get("accounts")[0].credit_in_account_currency = si.outstanding_amount
jv.get("accounts")[0].reference_type = si.doctype
jv.get("accounts")[0].reference_name = si.name
# debit bank
- jv.get("accounts")[1].debit = si.outstanding_amount
+ if jv.get("accounts")[1].account_currency == si.party_account_currency:
+ jv.get("accounts")[1].debit_in_account_currency = si.outstanding_amount
+ else:
+ jv.get("accounts")[1].debit_in_account_currency = si.outstanding_amount * exchange_rate
return jv.as_dict()
@@ -478,21 +545,32 @@
def get_payment_entry_from_purchase_invoice(purchase_invoice):
"""Returns new Journal Entry document as dict for given Purchase Invoice"""
pi = frappe.get_doc("Purchase Invoice", purchase_invoice)
+
+ if pi.company_currency == pi.party_account_currency:
+ exchange_rate = 1
+ else:
+ exchange_rate = get_exchange_rate(pi.party_account_currency, pi.company_currency)
+
jv = get_payment_entry(pi)
jv.remark = 'Payment against Purchase Invoice {0}. {1}'.format(pi.name, pi.remarks)
-
+ jv.exchange_rate = exchange_rate
+
# credit supplier
jv.get("accounts")[0].account = pi.credit_to
+ jv.get("accounts")[0].account_currency = pi.party_account_currency
jv.get("accounts")[0].party_type = "Supplier"
jv.get("accounts")[0].party = pi.supplier
jv.get("accounts")[0].balance = get_balance_on(pi.credit_to)
jv.get("accounts")[0].party_balance = get_balance_on(party=pi.supplier, party_type="Supplier")
- jv.get("accounts")[0].debit = pi.outstanding_amount
+ jv.get("accounts")[0].debit_in_account_currency = pi.outstanding_amount
jv.get("accounts")[0].reference_type = pi.doctype
jv.get("accounts")[0].reference_name = pi.name
# credit bank
- jv.get("accounts")[1].credit = pi.outstanding_amount
+ if jv.get("accounts")[1].account_currency == pi.party_account_currency:
+ jv.get("accounts")[1].credit_in_account_currency = pi.outstanding_amount
+ else:
+ jv.get("accounts")[1].credit_in_account_currency = pi.outstanding_amount * exchange_rate
return jv.as_dict()
@@ -501,6 +579,7 @@
"""Returns new Journal Entry document as dict for given Sales Order"""
from erpnext.accounts.utils import get_balance_on
from erpnext.accounts.party import get_party_account
+
so = frappe.get_doc("Sales Order", sales_order)
if flt(so.per_billed, 2) != 0.0:
@@ -508,23 +587,40 @@
jv = get_payment_entry(so)
jv.remark = 'Advance payment received against Sales Order {0}.'.format(so.name)
- party_account = get_party_account(so.company, so.customer, "Customer")
- amount = flt(so.base_grand_total) - flt(so.advance_paid)
+ party_account = get_party_account(so.company, so.customer, "Customer")
+ 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 = 1
+ else:
+ 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)
+ else:
+ amount = flt(so.grand_total) - flt(so.advance_paid)
# credit customer
jv.get("accounts")[0].account = party_account
+ jv.get("accounts")[0].account_currency = party_account_currency
jv.get("accounts")[0].party_type = "Customer"
jv.get("accounts")[0].party = so.customer
jv.get("accounts")[0].balance = get_balance_on(party_account)
jv.get("accounts")[0].party_balance = get_balance_on(party=so.customer, party_type="Customer")
- jv.get("accounts")[0].credit = amount
+ jv.get("accounts")[0].credit_in_account_currency = amount
jv.get("accounts")[0].reference_type = so.doctype
jv.get("accounts")[0].reference_name = so.name
jv.get("accounts")[0].is_advance = "Yes"
# debit bank
- jv.get("accounts")[1].debit = amount
+ if jv.get("accounts")[1].account_currency == party_account_currency:
+ jv.get("accounts")[1].debit_in_account_currency = amount
+ else:
+ jv.get("accounts")[1].debit_in_account_currency = amount * exchange_rate
return jv.as_dict()
@@ -540,9 +636,22 @@
jv = get_payment_entry(po)
jv.remark = 'Advance payment made against Purchase Order {0}.'.format(po.name)
+
party_account = get_party_account(po.company, po.supplier, "Supplier")
-
- amount = flt(po.base_grand_total) - flt(po.advance_paid)
+ 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 = 1
+ else:
+ exchange_rate = get_exchange_rate(party_account_currency, po.company_currency)
+
+ jv.exchange_rate = exchange_rate
+
+ if party_account_currency == company_currency:
+ amount = flt(po.base_grand_total) - flt(po.advance_paid)
+ else:
+ amount = flt(po.grand_total) - flt(po.advance_paid)
# credit customer
jv.get("accounts")[0].account = party_account
@@ -550,13 +659,16 @@
jv.get("accounts")[0].party = po.supplier
jv.get("accounts")[0].balance = get_balance_on(party_account)
jv.get("accounts")[0].party_balance = get_balance_on(party=po.supplier, party_type="Supplier")
- jv.get("accounts")[0].debit = amount
+ jv.get("accounts")[0].debit_in_account_currency = amount
jv.get("accounts")[0].reference_type = po.doctype
jv.get("accounts")[0].reference_name = po.name
jv.get("accounts")[0].is_advance = "Yes"
# debit bank
- jv.get("accounts")[1].credit = amount
+ if jv.get("accounts")[1].account_currency == party_account_currency:
+ jv.get("accounts")[1].credit_in_account_currency = amount
+ else:
+ jv.get("accounts")[1].credit_in_account_currency = amount * exchange_rate
return jv.as_dict()
@@ -574,6 +686,7 @@
if bank_account:
d2.account = bank_account["account"]
d2.balance = bank_account["balance"]
+ d2.account_currency = bank_account["account_currency"]
return jv
@@ -640,14 +753,41 @@
}
@frappe.whitelist()
-def get_account_balance_and_party_type(account, date):
+def get_account_balance_and_party_type(account, date, company, credited=False):
"""Returns dict of account balance and party type to be set in Journal Entry on selection of account."""
if not frappe.has_permission("Account"):
frappe.msgprint(_("No Permission"), raise_exception=1)
- account_type = frappe.db.get_value("Account", account, "account_type")
- return {
- "balance": get_balance_on(account, date),
- "party_type": {"Receivable":"Customer", "Payable":"Supplier"}.get(account_type, "")
- }
+ company_currency = get_company_currency(company)
+ account_details = frappe.db.get_value("Account", account, ["account_type", "account_currency"], as_dict=1)
+
+ if account_details.account_type == "Receivable":
+ party_type = "Customer"
+ elif account_details.account_type == "Payable":
+ party_type = "Supplier"
+ else:
+ 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 = {
+ "balance": get_balance_on(account, date),
+ "party_type": party_type,
+ "account_currency": account_details.account_currency or company_currency,
+ }
+ return grid_values, exchange_rate
+
+def get_average_exchange_rate(account):
+ exchange_rate = 0
+ bank_balance_in_account_currency = get_balance_on(account)
+ if bank_balance_in_account_currency:
+ bank_balance_in_company_currency = get_balance_on(account, in_account_currency=False)
+ exchange_rate = bank_balance_in_company_currency / bank_balance_in_account_currency
+
+ return exchange_rate
+
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py
index 8995e34..0d9cd24 100644
--- a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py
@@ -101,7 +101,7 @@
self.set_total_expense_zero("2013-02-28")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
- "_Test Account Bank Account - _TC", 40000, "_Test Cost Center - _TC", submit=True)
+ "_Test Bank - _TC", 40000, "_Test Cost Center - _TC", submit=True)
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
@@ -112,7 +112,7 @@
self.set_total_expense_zero("2013-02-28")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
- "_Test Account Bank Account - _TC", 40000, "_Test Cost Center - _TC")
+ "_Test Bank - _TC", 40000, "_Test Cost Center - _TC")
self.assertRaises(BudgetError, jv.submit)
@@ -126,7 +126,7 @@
self.set_total_expense_zero("2013-02-28")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
- "_Test Account Bank Account - _TC", 150000, "_Test Cost Center - _TC")
+ "_Test Bank - _TC", 150000, "_Test Cost Center - _TC")
self.assertRaises(BudgetError, jv.submit)
@@ -136,13 +136,13 @@
self.set_total_expense_zero("2013-02-28")
jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
- "_Test Account Bank Account - _TC", 20000, "_Test Cost Center - _TC", submit=True)
+ "_Test Bank - _TC", 20000, "_Test Cost Center - _TC", submit=True)
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv1.name}))
jv2 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
- "_Test Account Bank Account - _TC", 20000, "_Test Cost Center - _TC", submit=True)
+ "_Test Bank - _TC", 20000, "_Test Cost Center - _TC", submit=True)
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
@@ -165,32 +165,79 @@
def set_total_expense_zero(self, posting_date):
existing_expense = self.get_actual_expense(posting_date)
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
- "_Test Account Bank Account - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True)
+ "_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True)
+
+ def test_multi_currency(self):
+ jv = make_journal_entry("_Test Bank USD - _TC",
+ "_Test Bank - _TC", 100, exchange_rate=50, save=False)
+
+ jv.get("accounts")[1].credit_in_account_currency = 5000
+ jv.submit()
+
+ gl_entries = frappe.db.sql("""select account, account_currency, debit, credit,
+ debit_in_account_currency, credit_in_account_currency
+ from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s
+ order by account asc""", jv.name, as_dict=1)
-def make_journal_entry(account1, account2, amount, cost_center=None, submit=False):
+ self.assertTrue(gl_entries)
+
+ expected_values = {
+ "_Test Bank USD - _TC": {
+ "account_currency": "USD",
+ "debit": 5000,
+ "debit_in_account_currency": 100,
+ "credit": 0,
+ "credit_in_account_currency": 0
+ },
+ "_Test Bank - _TC": {
+ "account_currency": "INR",
+ "debit": 0,
+ "debit_in_account_currency": 0,
+ "credit": 5000,
+ "credit_in_account_currency": 5000
+ }
+ }
+
+ for field in ("account_currency", "debit", "debit_in_account_currency", "credit", "credit_in_account_currency"):
+ for i, gle in enumerate(gl_entries):
+ self.assertEquals(expected_values[gle.account][field], gle[field])
+
+
+
+ # cancel
+ jv.cancel()
+
+ gle = frappe.db.sql("""select name from `tabGL Entry`
+ where voucher_type='Sales Invoice' and voucher_no=%s""", jv.name)
+
+ self.assertFalse(gle)
+
+def make_journal_entry(account1, account2, amount, cost_center=None, exchange_rate=1, save=True, submit=False):
jv = frappe.new_doc("Journal Entry")
jv.posting_date = "2013-02-14"
jv.company = "_Test Company"
jv.fiscal_year = "_Test Fiscal Year 2013"
jv.user_remark = "test"
+ jv.exchange_rate = exchange_rate
jv.set("accounts", [
{
"account": account1,
"cost_center": cost_center,
- "debit": amount if amount > 0 else 0,
- "credit": abs(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,
}, {
"account": account2,
"cost_center": cost_center,
- "credit": amount if amount > 0 else 0,
- "debit": abs(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,
}
])
- jv.insert()
+ if save or submit:
+ jv.insert()
- if submit:
- jv.submit()
+ if submit:
+ jv.submit()
return jv
diff --git a/erpnext/accounts/doctype/journal_entry/test_records.json b/erpnext/accounts/doctype/journal_entry/test_records.json
index f660863..5e25c3c 100644
--- a/erpnext/accounts/doctype/journal_entry/test_records.json
+++ b/erpnext/accounts/doctype/journal_entry/test_records.json
@@ -9,15 +9,15 @@
"account": "_Test Receivable - _TC",
"party_type": "Customer",
"party": "_Test Customer",
- "credit": 400.0,
- "debit": 0.0,
+ "credit_in_account_currency": 400.0,
+ "debit_in_account_currency": 0.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts"
},
{
- "account": "_Test Account Bank Account - _TC",
- "credit": 0.0,
- "debit": 400.0,
+ "account": "_Test Bank - _TC",
+ "credit_in_account_currency": 0.0,
+ "debit_in_account_currency": 400.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts"
}
@@ -40,15 +40,15 @@
"account": "_Test Payable - _TC",
"party_type": "Supplier",
"party": "_Test Supplier",
- "credit": 0.0,
- "debit": 400.0,
+ "credit_in_account_currency": 0.0,
+ "debit_in_account_currency": 400.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts"
},
{
- "account": "_Test Account Bank Account - _TC",
- "credit": 400.0,
- "debit": 0.0,
+ "account": "_Test Bank - _TC",
+ "credit_in_account_currency": 400.0,
+ "debit_in_account_currency": 0.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts"
}
@@ -71,16 +71,16 @@
"account": "_Test Receivable - _TC",
"party_type": "Customer",
"party": "_Test Customer",
- "credit": 0.0,
- "debit": 400.0,
+ "credit_in_account_currency": 0.0,
+ "debit_in_account_currency": 400.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts"
},
{
"account": "Sales - _TC",
"cost_center": "_Test Cost Center - _TC",
- "credit": 400.0,
- "debit": 0.0,
+ "credit_in_account_currency": 400.0,
+ "debit_in_account_currency": 0.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts"
}
diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
index f63722d..85f4109 100644
--- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
+++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
@@ -38,6 +38,29 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "fieldname": "account_currency",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "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": "balance",
"fieldtype": "Currency",
"hidden": 0,
@@ -48,7 +71,7 @@
"no_copy": 1,
"oldfieldname": "balance",
"oldfieldtype": "Data",
- "options": "Company:company:default_currency",
+ "options": "account_currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 1,
@@ -162,7 +185,7 @@
"in_list_view": 0,
"label": "Party Balance",
"no_copy": 0,
- "options": "Company:company:default_currency",
+ "options": "account_currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -198,20 +221,43 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
- "fieldname": "debit",
+ "fieldname": "debit_in_account_currency",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
- "label": "Debit",
+ "label": "Debit in Account Currency",
"no_copy": 0,
+ "options": "account_currency",
+ "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": "debit",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Debit in Company Currency",
+ "no_copy": 1,
"oldfieldname": "debit",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"permlevel": 0,
- "print_hide": 0,
- "read_only": 0,
+ "print_hide": 1,
+ "read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -242,20 +288,43 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
- "fieldname": "credit",
+ "fieldname": "credit_in_account_currency",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
- "label": "Credit",
+ "label": "Credit in Account Currency",
"no_copy": 0,
+ "options": "account_currency",
+ "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": "credit",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Credit in Company Currency",
+ "no_copy": 1,
"oldfieldname": "credit",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"permlevel": 0,
- "print_hide": 0,
- "read_only": 0,
+ "print_hide": 1,
+ "read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -405,7 +474,7 @@
"is_submittable": 0,
"issingle": 0,
"istable": 1,
- "modified": "2015-08-17 02:11:33.991361",
+ "modified": "2015-09-04 03:29:37.127968",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Account",
diff --git a/erpnext/accounts/doctype/payment_tool/payment_tool.js b/erpnext/accounts/doctype/payment_tool/payment_tool.js
index 6eefdb9..5904b99 100644
--- a/erpnext/accounts/doctype/payment_tool/payment_tool.js
+++ b/erpnext/accounts/doctype/payment_tool/payment_tool.js
@@ -55,6 +55,25 @@
}
})
+frappe.ui.form.on("Payment Tool", "party_account", function(frm) {
+ if(frm.doc.party_account) {
+ frm.call({
+ method: "frappe.client.get_value",
+ args: {
+ doctype: "Account",
+ fieldname: "account_currency",
+ filters: { name: frm.doc.party_account },
+ },
+ callback: function(r, rt) {
+ if(r.message) {
+ frm.set_value("party_account_currency", r.message.account_currency);
+ erpnext.payment_tool.check_mandatory_to_set_button(frm);
+ }
+ }
+ });
+ }
+})
+
frappe.ui.form.on("Payment Tool", "company", function(frm) {
erpnext.payment_tool.check_mandatory_to_set_button(frm);
});
@@ -63,10 +82,6 @@
erpnext.payment_tool.check_mandatory_to_set_button(frm);
});
-frappe.ui.form.on("Payment Tool", "party", function(frm) {
- erpnext.payment_tool.check_mandatory_to_set_button(frm);
-});
-
// Fetch bank/cash account based on payment mode
frappe.ui.form.on("Payment Tool", "payment_mode", function(frm) {
return frappe.call({
@@ -158,7 +173,9 @@
method: 'erpnext.accounts.doctype.payment_tool.payment_tool.get_against_voucher_amount',
args: {
"against_voucher_type": row.against_voucher_type,
- "against_voucher_no": row.against_voucher_no
+ "against_voucher_no": row.against_voucher_no,
+ "party_account": self.party_account,
+ "company": self.company
},
callback: function(r) {
if(!r.exc) {
@@ -216,4 +233,4 @@
$.each(["Company", "Party Type", "Party", "Received or Paid"], function(i, field) {
if(!doc[frappe.model.scrub(field)]) frappe.throw(__("Please select {0} first", [field]));
});
-}
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_tool/payment_tool.json b/erpnext/accounts/doctype/payment_tool/payment_tool.json
index e00d9e2..55e7048 100644
--- a/erpnext/accounts/doctype/payment_tool/payment_tool.json
+++ b/erpnext/accounts/doctype/payment_tool/payment_tool.json
@@ -106,7 +106,7 @@
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
- "label": "Column Break 1",
+ "label": "",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
@@ -166,6 +166,29 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "fieldname": "party_account_currency",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Party Account Currency",
+ "no_copy": 1,
+ "options": "Currency",
+ "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,
+ "bold": 0,
+ "collapsible": 0,
"fieldname": "get_outstanding_vouchers",
"fieldtype": "Button",
"hidden": 0,
@@ -306,6 +329,7 @@
"in_list_view": 0,
"label": "Total Payment Amount",
"no_copy": 0,
+ "options": "party_account_currency",
"permlevel": 0,
"print_hide": 0,
"read_only": 1,
@@ -450,7 +474,7 @@
"is_submittable": 0,
"issingle": 1,
"istable": 0,
- "modified": "2015-06-05 11:17:33.843334",
+ "modified": "2015-08-31 18:58:21.813054",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Tool",
diff --git a/erpnext/accounts/doctype/payment_tool/payment_tool.py b/erpnext/accounts/doctype/payment_tool/payment_tool.py
index 4edbebd..924fd1e 100644
--- a/erpnext/accounts/doctype/payment_tool/payment_tool.py
+++ b/erpnext/accounts/doctype/payment_tool/payment_tool.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
-from frappe import _
+from frappe import _, scrub
from frappe.utils import flt
from frappe.model.document import Document
import json
@@ -33,15 +33,18 @@
d1.party_type = self.party_type
d1.party = self.party
d1.balance = get_balance_on(self.party_account)
- d1.set("debit" if self.received_or_paid=="Paid" else "credit", flt(v.payment_amount))
+ d1.set("debit_in_account_currency" if self.received_or_paid=="Paid" \
+ else "credit_in_account_currency", flt(v.payment_amount))
d1.set("reference_type", v.against_voucher_type)
d1.set("reference_name", v.against_voucher_no)
d1.set('is_advance', 'Yes' if v.against_voucher_type in ['Sales Order', 'Purchase Order'] else 'No')
- total_payment_amount = flt(total_payment_amount) + flt(d1.debit) - flt(d1.credit)
+ total_payment_amount = flt(total_payment_amount) + \
+ flt(d1.debit_in_account_currency) - flt(d1.credit_in_account_currency)
d2 = jv.append("accounts")
d2.account = self.payment_account
- d2.set('debit' if total_payment_amount < 0 else 'credit', abs(total_payment_amount))
+ d2.set('debit_in_account_currency' if total_payment_amount < 0 \
+ else 'credit_in_account_currency', abs(total_payment_amount))
if self.payment_account:
d2.balance = get_balance_on(self.payment_account)
@@ -55,11 +58,14 @@
frappe.throw(_("No permission to use Payment Tool"), frappe.PermissionError)
args = json.loads(args)
+
+ party_account_currency = frappe.db.get_value("Account", args.get("party_account"), "account_currency")
+ company_currency = frappe.db.get_value("Company", args.get("company"), "default_currency")
if args.get("party_type") == "Customer" and args.get("received_or_paid") == "Received":
- amount_query = "ifnull(debit, 0) - ifnull(credit, 0)"
+ amount_query = "ifnull(debit_in_account_currency, 0) - ifnull(credit_in_account_currency, 0)"
elif args.get("party_type") == "Supplier" and args.get("received_or_paid") == "Paid":
- amount_query = "ifnull(credit, 0) - ifnull(debit, 0)"
+ amount_query = "ifnull(credit_in_account_currency, 0) - ifnull(debit_in_account_currency, 0)"
else:
frappe.throw(_("Please enter the Against Vouchers manually"))
@@ -68,27 +74,34 @@
args.get("party_type"), args.get("party"))
# 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)
return outstanding_invoices + orders_to_be_billed
-def get_orders_to_be_billed(party_type, party):
+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'
+
+ ref_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
+
orders = frappe.db.sql("""
select
name as voucher_no,
- ifnull(base_grand_total, 0) as invoice_amount,
- (ifnull(base_grand_total, 0) - ifnull(advance_paid, 0)) as outstanding_amount,
+ ifnull({ref_field}, 0) as invoice_amount,
+ (ifnull({ref_field}, 0) - ifnull(advance_paid, 0)) as outstanding_amount,
transaction_date as posting_date
from
- `tab%s`
+ `tab{voucher_type}`
where
- %s = %s
+ {party_type} = %s
and docstatus = 1
and ifnull(status, "") != "Stopped"
- and ifnull(base_grand_total, 0) > ifnull(advance_paid, 0)
+ and ifnull({ref_field}, 0) > ifnull(advance_paid, 0)
and abs(100 - ifnull(per_billed, 0)) > 0.01
- """ % (voucher_type, 'customer' if party_type == "Customer" else 'supplier', '%s'),
- party, as_dict = True)
+ """.format(**{
+ "ref_field": ref_field,
+ "voucher_type": voucher_type,
+ "party_type": scrub(party_type)
+ }), party, as_dict = True)
order_list = []
for d in orders:
@@ -98,13 +111,19 @@
return order_list
@frappe.whitelist()
-def get_against_voucher_amount(against_voucher_type, against_voucher_no):
+def get_against_voucher_amount(against_voucher_type, against_voucher_no, party_account, company):
+ party_account_currency = frappe.db.get_value("Account", party_account, "account_currency")
+ company_currency = frappe.db.get_value("Company", company, "default_currency")
+ ref_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
+
if against_voucher_type in ["Sales Order", "Purchase Order"]:
- select_cond = "base_grand_total as total_amount, ifnull(base_grand_total, 0) - ifnull(advance_paid, 0) as outstanding_amount"
+ select_cond = "{0} as total_amount, ifnull({0}, 0) - ifnull(advance_paid, 0) as outstanding_amount"\
+ .format(ref_field)
elif against_voucher_type in ["Sales Invoice", "Purchase Invoice"]:
- select_cond = "base_grand_total as total_amount, outstanding_amount"
+ select_cond = "{0} as total_amount, outstanding_amount".format(ref_field)
elif against_voucher_type == "Journal Entry":
- select_cond = "total_debit as total_amount"
+ ref_field = "total_debit" if party_account_currency == company_currency else "total_debit/exchange_rate"
+ select_cond = "{0} as total_amount".format(ref_field)
details = frappe.db.sql("""select {0} from `tab{1}` where name = %s"""
.format(select_cond, against_voucher_type), against_voucher_no, as_dict=1)
diff --git a/erpnext/accounts/doctype/payment_tool/test_payment_tool.py b/erpnext/accounts/doctype/payment_tool/test_payment_tool.py
index 321986c..4f1c9e9 100644
--- a/erpnext/accounts/doctype/payment_tool/test_payment_tool.py
+++ b/erpnext/accounts/doctype/payment_tool/test_payment_tool.py
@@ -39,7 +39,7 @@
"party": "_Test Customer 3",
"reference_type": "Sales Order",
"reference_name": so2.name,
- "credit": 1000,
+ "credit_in_account_currency": 1000,
"is_advance": "Yes"
})
@@ -67,7 +67,7 @@
"party": "_Test Customer 3",
"reference_type": si2.doctype,
"reference_name": si2.name,
- "credit": 561.80
+ "credit_in_account_currency": 561.80
})
pi = self.create_voucher(pi_test_records[0], {
@@ -91,7 +91,7 @@
"party": "_Test Customer 3",
"party_account": "_Test Receivable - _TC",
"payment_mode": "Cheque",
- "payment_account": "_Test Account Bank Account - _TC",
+ "payment_account": "_Test Bank - _TC",
"reference_no": "123456",
"reference_date": "2013-02-14"
}
@@ -117,10 +117,10 @@
def create_against_jv(self, test_record, args):
jv = frappe.copy_doc(test_record)
jv.get("accounts")[0].update(args)
- if args.get("debit"):
- jv.get("accounts")[1].credit = args["debit"]
- elif args.get("credit"):
- jv.get("accounts")[1].debit = args["credit"]
+ if args.get("debit_in_account_currency"):
+ jv.get("accounts")[1].credit_in_account_currency = args["debit_in_account_currency"]
+ elif args.get("credit_in_account_currency"):
+ jv.get("accounts")[1].debit_in_account_currency = args["credit_in_account_currency"]
jv.insert()
jv.submit()
@@ -141,7 +141,8 @@
outstanding_entries = get_outstanding_vouchers(json.dumps(args))
for d in outstanding_entries:
- self.assertEquals(flt(d.get("outstanding_amount"), 2), expected_outstanding.get(d.get("voucher_type"))[1])
+ self.assertEquals(flt(d.get("outstanding_amount"), 2),
+ expected_outstanding.get(d.get("voucher_type"))[1])
self.check_jv_entries(doc, outstanding_entries, expected_outstanding)
@@ -156,11 +157,10 @@
paytool.total_payment_amount = 300
new_jv = paytool.make_journal_entry()
-
for jv_entry in new_jv.get("accounts"):
if paytool.party_account == jv_entry.get("account") and paytool.party == jv_entry.get("party"):
- self.assertEquals(100.00,
- jv_entry.get("debit" if paytool.party_type=="Supplier" else "credit"))
+ self.assertEquals(100.00, jv_entry.get("debit_in_account_currency"
+ if paytool.party_type=="Supplier" else "credit_in_account_currency"))
self.assertEquals(jv_entry.reference_name,
expected_outstanding[jv_entry.reference_type][0])
@@ -170,4 +170,6 @@
def clear_table_entries(self):
frappe.db.sql("""delete from `tabGL Entry` where party in ("_Test Customer 3", "_Test Supplier 1")""")
frappe.db.sql("""delete from `tabSales Order` where customer = "_Test Customer 3" """)
+ frappe.db.sql("""delete from `tabSales Invoice` where customer = "_Test Customer 3" """)
frappe.db.sql("""delete from `tabPurchase Order` where supplier = "_Test Supplier 1" """)
+ frappe.db.sql("""delete from `tabPurchase Invoice` where supplier = "_Test Supplier 1" """)
diff --git a/erpnext/accounts/doctype/payment_tool_detail/payment_tool_detail.json b/erpnext/accounts/doctype/payment_tool_detail/payment_tool_detail.json
index 5221f35..7e14608 100644
--- a/erpnext/accounts/doctype/payment_tool_detail/payment_tool_detail.json
+++ b/erpnext/accounts/doctype/payment_tool_detail/payment_tool_detail.json
@@ -87,6 +87,7 @@
"in_list_view": 1,
"label": "Total Amount",
"no_copy": 0,
+ "options": "party_account_currency",
"permlevel": 0,
"print_hide": 0,
"read_only": 1,
@@ -108,6 +109,7 @@
"in_list_view": 1,
"label": "Outstanding Amount",
"no_copy": 0,
+ "options": "party_account_currency",
"permlevel": 0,
"print_hide": 0,
"read_only": 1,
@@ -129,6 +131,7 @@
"in_list_view": 1,
"label": "Payment Amount",
"no_copy": 0,
+ "options": "party_account_currency",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
@@ -146,7 +149,7 @@
"is_submittable": 0,
"issingle": 0,
"istable": 1,
- "modified": "2014-09-11 08:55:34.384017",
+ "modified": "2015-08-31 18:58:35.537060",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Tool Detail",
diff --git a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py
index afff47f..0b59746 100644
--- a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py
+++ b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py
@@ -10,11 +10,11 @@
class TestPeriodClosingVoucher(unittest.TestCase):
def test_closing_entry(self):
- make_journal_entry("_Test Account Bank Account - _TC", "Sales - _TC", 400,
+ make_journal_entry("_Test Bank - _TC", "Sales - _TC", 400,
"_Test Cost Center - _TC", submit=True)
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
- "_Test Account Bank Account - _TC", 600, "_Test Cost Center - _TC", submit=True)
+ "_Test Bank - _TC", 600, "_Test Cost Center - _TC", submit=True)
profit_or_loss = frappe.db.sql("""select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) as balance
from `tabGL Entry` t1, `tabAccount` t2
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 70ebee1..2e3794a 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -75,8 +75,29 @@
me.apply_pricing_rule();
})
},
+
+ credit_to: function() {
+ var me = this;
+ if(this.frm.doc.credit_to) {
+ me.frm.call({
+ method: "frappe.client.get_value",
+ args: {
+ doctype: "Account",
+ fieldname: "account_currency",
+ filters: { name: me.frm.doc.credit_to },
+ },
+ callback: function(r, rt) {
+ if(r.message) {
+ me.frm.set_value("party_account_currency", r.message.account_currency);
+ me.set_dynamic_labels();
+ }
+ }
+ });
+ }
+ },
write_off_amount: function() {
+ this.set_in_company_currency(this.frm.doc, ["write_off_amount"]);
this.calculate_outstanding_amount();
this.frm.refresh_fields();
},
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index ef6cc77..0d4953a 100755
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -1270,30 +1270,6 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
- "fieldname": "total_amount_to_pay",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "label": "Total Amount To Pay",
- "no_copy": 1,
- "oldfieldname": "total_amount_to_pay",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "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": "total_advance",
"fieldtype": "Currency",
"hidden": 0,
@@ -1304,7 +1280,7 @@
"no_copy": 1,
"oldfieldname": "total_advance",
"oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
+ "options": "party_account_currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 1,
@@ -1328,7 +1304,7 @@
"no_copy": 1,
"oldfieldname": "outstanding_amount",
"oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
+ "options": "party_account_currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 1,
@@ -1341,6 +1317,30 @@
{
"allow_on_submit": 0,
"bold": 0,
+ "collapsible": 1,
+ "collapsible_depends_on": "write_off_amount",
+ "depends_on": "grand_total",
+ "fieldname": "write_off",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Write Off",
+ "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": "write_off_amount",
"fieldtype": "Currency",
@@ -1350,7 +1350,7 @@
"in_list_view": 0,
"label": "Write Off Amount",
"no_copy": 1,
- "options": "Company:company:default_currency",
+ "options": "currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 0,
@@ -1364,6 +1364,50 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "fieldname": "base_write_off_amount",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Write Off Amount (Company Currency)",
+ "no_copy": 1,
+ "options": "Company:company:default_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_61",
+ "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,
"depends_on": "eval:flt(doc.write_off_amount)!=0",
"fieldname": "write_off_account",
"fieldtype": "Link",
@@ -1409,29 +1453,6 @@
{
"allow_on_submit": 0,
"bold": 0,
- "collapsible": 0,
- "fieldname": "against_expense_account",
- "fieldtype": "Small Text",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "label": "Against Expense Account",
- "no_copy": 1,
- "oldfieldname": "against_expense_account",
- "oldfieldtype": "Small Text",
- "permlevel": 0,
- "print_hide": 1,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
"collapsible_depends_on": "advances",
"fieldname": "advances_section",
@@ -1752,6 +1773,29 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "fieldname": "party_account_currency",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Party 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,
"default": "No",
"description": "",
"fieldname": "is_opening",
@@ -1801,6 +1845,29 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "fieldname": "against_expense_account",
+ "fieldtype": "Small Text",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Against Expense Account",
+ "no_copy": 1,
+ "oldfieldname": "against_expense_account",
+ "oldfieldtype": "Small Text",
+ "permlevel": 0,
+ "print_hide": 1,
+ "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": "column_break_63",
"fieldtype": "Column Break",
"hidden": 0,
@@ -2175,7 +2242,7 @@
"is_submittable": 1,
"issingle": 0,
"istable": 0,
- "modified": "2015-08-27 03:21:24.432106",
+ "modified": "2015-08-27 16:05:29.519073",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index a43e553..4fac121 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -91,13 +91,16 @@
throw(_("Conversion rate cannot be 0 or 1"))
def validate_credit_to_acc(self):
- account = frappe.db.get_value("Account", self.credit_to, ["account_type", "report_type"], as_dict=True)
+ account = frappe.db.get_value("Account", self.credit_to,
+ ["account_type", "report_type", "account_currency"], as_dict=True)
if account.report_type != "Balance Sheet":
frappe.throw(_("Credit To account must be a Balance Sheet account"))
if self.supplier and account.account_type != "Payable":
frappe.throw(_("Credit To account must be a Payable account"))
+
+ self.party_account_currency = account.account_currency
def check_for_stopped_status(self):
check_list = []
@@ -248,7 +251,7 @@
expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
gl_entries = []
-
+
# parent's gl entry
if self.base_grand_total:
gl_entries.append(
@@ -257,26 +260,32 @@
"party_type": "Supplier",
"party": self.supplier,
"against": self.against_expense_account,
- "credit": self.total_amount_to_pay,
- "remarks": self.remarks,
+ "credit": self.base_grand_total,
+ "credit_in_account_currency": self.base_grand_total \
+ if self.party_account_currency==self.company_currency else self.grand_total,
"against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype,
- })
+ }, self.party_account_currency)
)
# tax table gl entries
valuation_tax = {}
for tax in self.get("taxes"):
if tax.category in ("Total", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount):
+ account_currency = frappe.db.get_value("Account", tax.account_head, "account_currency")
+
+ dr_or_cr = "debit" if tax.add_deduct_tax == "Add" else "credit"
+
gl_entries.append(
self.get_gl_dict({
"account": tax.account_head,
"against": self.supplier,
- "debit": tax.add_deduct_tax == "Add" and tax.base_tax_amount_after_discount_amount or 0,
- "credit": tax.add_deduct_tax == "Deduct" and tax.base_tax_amount_after_discount_amount or 0,
- "remarks": self.remarks,
+ dr_or_cr: tax.base_tax_amount_after_discount_amount,
+ dr_or_cr + "_in_account_currency": tax.base_tax_amount_after_discount_amount \
+ if account_currency==self.company_currency \
+ else tax.tax_amount_after_discount_amount,
"cost_center": tax.cost_center
- })
+ }, account_currency)
)
# accumulate valuation tax
@@ -292,14 +301,16 @@
stock_items = self.get_stock_items()
for item in self.get("items"):
if flt(item.base_net_amount):
+ account_currency = frappe.db.get_value("Account", item.expense_account, "account_currency")
gl_entries.append(
self.get_gl_dict({
"account": item.expense_account,
"against": self.supplier,
"debit": item.base_net_amount,
- "remarks": self.remarks,
+ "debit_in_account_currency": item.base_net_amount \
+ if account_currency==self.company_currency else item.net_amount,
"cost_center": item.cost_center
- })
+ }, account_currency)
)
if auto_accounting_for_stock and self.is_opening == "No" and \
@@ -352,12 +363,28 @@
# writeoff account includes petty difference in the invoice amount
# and the amount that is paid
if self.write_off_account and flt(self.write_off_amount):
+ write_off_account_currency = frappe.db.get_value("Account", self.write_off_account, "account_currency")
+
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": self.credit_to,
+ "party_type": "Supplier",
+ "party": self.supplier,
+ "against": self.write_off_account,
+ "debit": self.base_write_off_amount,
+ "debit_in_account_currency": self.base_write_off_amount \
+ if self.party_account_currency==self.company_currency else self.write_off_amount,
+ "against_voucher": self.return_against if cint(self.is_return) else self.name,
+ "against_voucher_type": self.doctype,
+ }, self.party_account_currency)
+ )
gl_entries.append(
self.get_gl_dict({
"account": self.write_off_account,
"against": self.supplier,
- "credit": flt(self.write_off_amount),
- "remarks": self.remarks,
+ "credit": flt(self.base_write_off_amount),
+ "credit_in_account_currency": self.base_write_off_amount \
+ if write_off_account_currency==self.company_currency else self.write_off_amount,
"cost_center": self.write_off_cost_center
})
)
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 0b74948..2754ee6 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -10,6 +10,7 @@
import frappe.defaults
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory, \
test_records as pr_test_records
+from erpnext.controllers.accounts_controller import InvalidCurrency
test_dependencies = ["Item", "Cost Center"]
test_ignore = ["Serial No"]
@@ -276,6 +277,55 @@
self.assertEquals(expected_values[gle.account][1], gle.credit)
set_perpetual_inventory(0)
+
+ def test_multi_currency_gle(self):
+ set_perpetual_inventory(0)
+
+ pi = make_purchase_invoice(supplier="_Test Supplier USD", credit_to="_Test Payable USD - _TC",
+ currency="USD", conversion_rate=50)
+
+ gl_entries = frappe.db.sql("""select account, account_currency, debit, credit,
+ debit_in_account_currency, credit_in_account_currency
+ from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
+ order by account asc""", pi.name, as_dict=1)
+
+ self.assertTrue(gl_entries)
+
+ expected_values = {
+ "_Test Payable USD - _TC": {
+ "account_currency": "USD",
+ "debit": 0,
+ "debit_in_account_currency": 0,
+ "credit": 12500,
+ "credit_in_account_currency": 250
+ },
+ "_Test Account Cost for Goods Sold - _TC": {
+ "account_currency": "INR",
+ "debit": 12500,
+ "debit_in_account_currency": 12500,
+ "credit": 0,
+ "credit_in_account_currency": 0
+ }
+ }
+
+ for field in ("account_currency", "debit", "debit_in_account_currency", "credit", "credit_in_account_currency"):
+ for i, gle in enumerate(gl_entries):
+ self.assertEquals(expected_values[gle.account][field], gle[field])
+
+
+ # Check for valid currency
+ pi1 = make_purchase_invoice(supplier="_Test Supplier USD", credit_to="_Test Payable USD - _TC",
+ do_not_save=True)
+
+ self.assertRaises(InvalidCurrency, pi1.save)
+
+ # cancel
+ pi.cancel()
+
+ gle = frappe.db.sql("""select name from `tabGL Entry`
+ where voucher_type='Sales Invoice' and voucher_no=%s""", pi.name)
+
+ self.assertFalse(gle)
def make_purchase_invoice(**args):
pi = frappe.new_doc("Purchase Invoice")
diff --git a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json
index c9139d1..f190809 100644
--- a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json
+++ b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json
@@ -117,7 +117,7 @@
"no_copy": 1,
"oldfieldname": "advance_amount",
"oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
+ "options": "party_account_currency",
"permlevel": 0,
"print_hide": 0,
"print_width": "100px",
@@ -143,7 +143,7 @@
"no_copy": 1,
"oldfieldname": "allocated_amount",
"oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
+ "options": "party_account_currency",
"permlevel": 0,
"print_hide": 0,
"print_width": "100px",
@@ -164,7 +164,7 @@
"is_submittable": 0,
"issingle": 0,
"istable": 1,
- "modified": "2014-12-25 16:29:15.176476",
+ "modified": "2015-08-25 17:51:30.274069",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Advance",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index ec84302..5e8d3a5 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -175,6 +175,26 @@
me.apply_pricing_rule();
})
},
+
+ debit_to: function() {
+ var me = this;
+ if(this.frm.doc.debit_to) {
+ me.frm.call({
+ method: "frappe.client.get_value",
+ args: {
+ doctype: "Account",
+ fieldname: "account_currency",
+ filters: { name: me.frm.doc.debit_to },
+ },
+ callback: function(r, rt) {
+ if(r.message) {
+ me.frm.set_value("party_account_currency", r.message.account_currency);
+ me.set_dynamic_labels();
+ }
+ }
+ });
+ }
+ },
allocated_amount: function() {
this.calculate_total_advance();
@@ -183,10 +203,10 @@
write_off_outstanding_amount_automatically: function() {
if(cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
- frappe.model.round_floats_in(this.frm.doc, ["base_grand_total", "paid_amount"]);
+ frappe.model.round_floats_in(this.frm.doc, ["grand_total", "paid_amount"]);
// this will make outstanding amount 0
this.frm.set_value("write_off_amount",
- flt(this.frm.doc.base_grand_total - this.frm.doc.paid_amount - this.frm.doc.total_advance, precision("write_off_amount"))
+ flt(this.frm.doc.grand_total - this.frm.doc.paid_amount - this.frm.doc.total_advance, precision("write_off_amount"))
);
this.frm.toggle_enable("write_off_amount", false);
@@ -199,10 +219,12 @@
},
write_off_amount: function() {
+ this.set_in_company_currency(this.frm.doc, ["write_off_amount"]);
this.write_off_outstanding_amount_automatically();
},
paid_amount: function() {
+ this.set_in_company_currency(this.frm.doc, ["paid_amount"]);
this.write_off_outstanding_amount_automatically();
},
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index cd97a22..0d1b42c 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -1145,7 +1145,7 @@
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
- "label": "Discount",
+ "label": "Additional Discount",
"no_copy": 0,
"permlevel": 0,
"precision": "",
@@ -1448,7 +1448,7 @@
"no_copy": 0,
"oldfieldname": "total_advance",
"oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
+ "options": "party_account_currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 1,
@@ -1472,7 +1472,7 @@
"no_copy": 1,
"oldfieldname": "outstanding_amount",
"oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
+ "options": "party_account_currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 1,
@@ -1663,7 +1663,7 @@
"no_copy": 1,
"oldfieldname": "paid_amount",
"oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
+ "options": "currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 0,
@@ -1676,6 +1676,29 @@
{
"allow_on_submit": 0,
"bold": 0,
+ "collapsible": 0,
+ "fieldname": "base_paid_amount",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Paid Amount (Company Currency)",
+ "no_copy": 1,
+ "options": "Company:company:default_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": 1,
"collapsible_depends_on": "write_off_amount",
"depends_on": "grand_total",
@@ -1710,7 +1733,7 @@
"in_list_view": 0,
"label": "Write Off Amount",
"no_copy": 1,
- "options": "Company:company:default_currency",
+ "options": "currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 0,
@@ -1724,6 +1747,29 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "fieldname": "base_write_off_amount",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Write Off Amount (Company Currency)",
+ "no_copy": 1,
+ "options": "Company:company:default_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,
"depends_on": "is_pos",
"fieldname": "write_off_outstanding_amount_automatically",
"fieldtype": "Check",
@@ -2231,6 +2277,29 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "fieldname": "party_account_currency",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Party 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,
"default": "No",
"description": "",
"fieldname": "is_opening",
@@ -2882,7 +2951,7 @@
"is_submittable": 1,
"issingle": 0,
"istable": 0,
- "modified": "2015-08-27 03:29:14.270731",
+ "modified": "2015-08-27 16:46:11.526089",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 92e3c0d..bce8fe2 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -271,13 +271,16 @@
reconcile_against_document(lst)
def validate_debit_to_acc(self):
- account = frappe.db.get_value("Account", self.debit_to, ["account_type", "report_type"], as_dict=True)
+ account = frappe.db.get_value("Account", self.debit_to,
+ ["account_type", "report_type", "account_currency"], as_dict=True)
if account.report_type != "Balance Sheet":
frappe.throw(_("Debit To account must be a Balance Sheet account"))
if self.customer and account.account_type != "Receivable":
frappe.throw(_("Debit To account must be a Receivable account"))
+
+ self.party_account_currency = account.account_currency
def validate_fixed_asset_account(self):
"""Validate Fixed Asset and whether Income Account Entered Exists"""
@@ -423,15 +426,18 @@
if cint(self.is_pos) == 1:
if flt(self.paid_amount) == 0:
if self.cash_bank_account:
- frappe.db.set(self, 'paid_amount',
- (flt(self.base_grand_total) - flt(self.write_off_amount)))
+ frappe.db.set(self, 'paid_amount',
+ flt(flt(self.grand_total) - flt(self.write_off_amount), self.precision("paid_amount")))
else:
# show message that the amount is not paid
frappe.db.set(self,'paid_amount',0)
frappe.msgprint(_("Note: Payment Entry will not be created since 'Cash or Bank Account' was not specified"))
else:
frappe.db.set(self,'paid_amount',0)
-
+
+ frappe.db.set(self, 'base_paid_amount',
+ flt(self.paid_amount*self.conversion_rate, self.precision("base_paid_amount")))
+
def check_prev_docstatus(self):
for d in self.get('items'):
if d.sales_order and frappe.db.get_value("Sales Order", d.sales_order, "docstatus") != 1:
@@ -470,7 +476,7 @@
from erpnext.accounts.general_ledger import merge_similar_entries
gl_entries = []
-
+
self.make_customer_gl_entry(gl_entries)
self.make_tax_gl_entries(gl_entries)
@@ -487,7 +493,7 @@
return gl_entries
def make_customer_gl_entry(self, gl_entries):
- if self.base_grand_total:
+ if self.grand_total:
gl_entries.append(
self.get_gl_dict({
"account": self.debit_to,
@@ -495,37 +501,42 @@
"party": self.customer,
"against": self.against_income_account,
"debit": self.base_grand_total,
- "remarks": self.remarks,
+ "debit_in_account_currency": self.base_grand_total \
+ if self.party_account_currency==self.company_currency else self.grand_total,
"against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype
- })
+ }, self.party_account_currency)
)
def make_tax_gl_entries(self, gl_entries):
for tax in self.get("taxes"):
if flt(tax.base_tax_amount_after_discount_amount):
+ account_currency = frappe.db.get_value("Account", tax.account_head, "account_currency")
gl_entries.append(
self.get_gl_dict({
"account": tax.account_head,
"against": self.customer,
"credit": flt(tax.base_tax_amount_after_discount_amount),
- "remarks": self.remarks,
+ "credit_in_account_currency": flt(tax.base_tax_amount_after_discount_amount) \
+ if account_currency==self.company_currency else flt(tax.tax_amount_after_discount_amount),
"cost_center": tax.cost_center
- })
+ }, account_currency)
)
def make_item_gl_entries(self, gl_entries):
# income account gl entries
for item in self.get("items"):
if flt(item.base_net_amount):
+ account_currency = frappe.db.get_value("Account", item.income_account, "account_currency")
gl_entries.append(
self.get_gl_dict({
"account": item.income_account,
"against": self.customer,
"credit": item.base_net_amount,
- "remarks": self.remarks,
+ "credit_in_account_currency": item.base_net_amount \
+ if account_currency==self.company_currency else item.net_amount,
"cost_center": item.cost_center
- })
+ }, account_currency)
)
# expense account gl entries
@@ -535,6 +546,7 @@
def make_pos_gl_entries(self, gl_entries):
if cint(self.is_pos) and self.cash_bank_account and self.paid_amount:
+ bank_account_currency = frappe.db.get_value("Account", self.cash_bank_account, "account_currency")
# POS, make payment entries
gl_entries.append(
self.get_gl_dict({
@@ -542,44 +554,50 @@
"party_type": "Customer",
"party": self.customer,
"against": self.cash_bank_account,
- "credit": self.paid_amount,
- "remarks": self.remarks,
+ "credit": self.base_paid_amount,
+ "credit_in_account_currency": self.base_paid_amount \
+ if self.party_account_currency==self.company_currency else self.paid_amount,
"against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype,
- })
+ }, self.party_account_currency)
)
gl_entries.append(
self.get_gl_dict({
"account": self.cash_bank_account,
"against": self.customer,
- "debit": self.paid_amount,
- "remarks": self.remarks,
- })
+ "debit": self.base_paid_amount,
+ "debit_in_account_currency": self.base_paid_amount \
+ if bank_account_currency==self.company_currency else self.paid_amount
+ }, bank_account_currency)
)
def make_write_off_gl_entry(self, gl_entries):
# write off entries, applicable if only pos
if self.write_off_account and self.write_off_amount:
+ write_off_account_currency = frappe.db.get_value("Account", self.write_off_account, "account_currency")
+
gl_entries.append(
self.get_gl_dict({
"account": self.debit_to,
"party_type": "Customer",
"party": self.customer,
"against": self.write_off_account,
- "credit": self.write_off_amount,
- "remarks": self.remarks,
+ "credit": self.base_write_off_amount,
+ "credit_in_account_currency": self.base_write_off_amount \
+ if self.party_account_currency==self.company_currency else self.write_off_amount,
"against_voucher": self.return_against if cint(self.is_return) else self.name,
- "against_voucher_type": self.doctype,
- })
+ "against_voucher_type": self.doctype
+ }, self.party_account_currency)
)
gl_entries.append(
self.get_gl_dict({
"account": self.write_off_account,
"against": self.customer,
- "debit": self.write_off_amount,
- "remarks": self.remarks,
+ "debit": self.base_write_off_amount,
+ "debit_in_account_currency": self.base_write_off_amount \
+ if write_off_account_currency==self.company_currency else self.write_off_amount,
"cost_center": self.write_off_cost_center
- })
+ }, write_off_account_currency)
)
def get_list_context(context=None):
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index c7a992c..e519bd3 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -7,6 +7,8 @@
from frappe.utils import nowdate, add_days, flt
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
+from erpnext.controllers.accounts_controller import InvalidCurrency
+from erpnext.accounts.doctype.gl_entry.gl_entry import InvalidAccountCurrency
class TestSalesInvoice(unittest.TestCase):
def make(self):
@@ -401,7 +403,7 @@
jv.cancel()
self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 561.8)
- def test_sales_invoice_gl_entry_without_aii(self):
+ def test_sales_invoice_gl_entry_without_perpetual_inventory(self):
set_perpetual_inventory(0)
si = frappe.copy_doc(test_records[1])
si.insert()
@@ -433,7 +435,7 @@
self.assertFalse(gle)
- def test_pos_gl_entry_with_aii(self):
+ def test_pos_gl_entry_with_perpetual_inventory(self):
set_perpetual_inventory()
self.make_pos_profile()
@@ -442,8 +444,7 @@
pos = copy.deepcopy(test_records[1])
pos["is_pos"] = 1
pos["update_stock"] = 1
- # pos["posting_time"] = "12:05"
- pos["cash_bank_account"] = "_Test Account Bank Account - _TC"
+ pos["cash_bank_account"] = "_Test Bank - _TC"
pos["paid_amount"] = 600.0
si = frappe.copy_doc(pos)
@@ -474,7 +475,7 @@
[stock_in_hand, 0.0, abs(sle.stock_value_difference)],
[pos["items"][0]["expense_account"], abs(sle.stock_value_difference), 0.0],
[si.debit_to, 0.0, 600.0],
- ["_Test Account Bank Account - _TC", 600.0, 0.0]
+ ["_Test Bank - _TC", 600.0, 0.0]
])
for i, gle in enumerate(sorted(gl_entries, key=lambda gle: gle.account)):
@@ -494,7 +495,7 @@
def make_pos_profile(self):
pos_profile = frappe.get_doc({
- "cash_bank_account": "_Test Account Bank Account - _TC",
+ "cash_bank_account": "_Test Bank - _TC",
"company": "_Test Company",
"cost_center": "_Test Cost Center - _TC",
"currency": "INR",
@@ -513,7 +514,7 @@
if not frappe.db.exists("POS Profile", "_Test POS Profile"):
pos_profile.insert()
- def test_si_gl_entry_with_aii_and_update_stock_with_warehouse_but_no_account(self):
+ def test_si_gl_entry_with_perpetual_inventory_and_update_stock_with_warehouse_but_no_account(self):
set_perpetual_inventory()
frappe.delete_doc("Account", "_Test Warehouse No Account - _TC")
@@ -567,7 +568,7 @@
self.assertFalse(gle)
set_perpetual_inventory(0)
- def test_sales_invoice_gl_entry_with_aii_no_item_code(self):
+ def test_sales_invoice_gl_entry_with_perpetual_inventory_no_item_code(self):
set_perpetual_inventory()
si = frappe.get_doc(test_records[1])
@@ -593,7 +594,7 @@
set_perpetual_inventory(0)
- def test_sales_invoice_gl_entry_with_aii_non_stock_item(self):
+ def test_sales_invoice_gl_entry_with_perpetual_inventory_non_stock_item(self):
set_perpetual_inventory()
si = frappe.get_doc(test_records[1])
si.get("items")[0].item_code = "_Test Non Stock Item"
@@ -841,7 +842,80 @@
self.assertEquals(si.total_taxes_and_charges, 234.44)
self.assertEquals(si.base_grand_total, 859.44)
self.assertEquals(si.grand_total, 859.44)
+
+ def test_multi_currency_gle(self):
+ set_perpetual_inventory(0)
+ si = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
+ currency="USD", conversion_rate=50)
+ gl_entries = frappe.db.sql("""select account, account_currency, debit, credit,
+ debit_in_account_currency, credit_in_account_currency
+ from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
+ order by account asc""", si.name, as_dict=1)
+
+ self.assertTrue(gl_entries)
+
+ expected_values = {
+ "_Test Receivable USD - _TC": {
+ "account_currency": "USD",
+ "debit": 5000,
+ "debit_in_account_currency": 100,
+ "credit": 0,
+ "credit_in_account_currency": 0
+ },
+ "Sales - _TC": {
+ "account_currency": "INR",
+ "debit": 0,
+ "debit_in_account_currency": 0,
+ "credit": 5000,
+ "credit_in_account_currency": 5000
+ }
+ }
+
+ for field in ("account_currency", "debit", "debit_in_account_currency", "credit", "credit_in_account_currency"):
+ for i, gle in enumerate(gl_entries):
+ self.assertEquals(expected_values[gle.account][field], gle[field])
+
+ # cancel
+ si.cancel()
+
+ gle = frappe.db.sql("""select name from `tabGL Entry`
+ where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
+
+ self.assertFalse(gle)
+
+ def test_invalid_currency(self):
+ # Customer currency = USD
+
+ # Transaction currency cannot be INR
+ si1 = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
+ do_not_save=True)
+
+ self.assertRaises(InvalidCurrency, si1.save)
+
+ # Transaction currency cannot be EUR
+ si2 = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
+ currency="EUR", conversion_rate=80, do_not_save=True)
+
+ self.assertRaises(InvalidCurrency, si2.save)
+
+ # Transaction currency only allowed in USD
+ si3 = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
+ currency="USD", conversion_rate=50)
+
+ # Party Account currency must be in USD, as there is existing GLE with USD
+ si4 = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable - _TC",
+ currency="USD", conversion_rate=50, do_not_submit=True)
+
+ self.assertRaises(InvalidAccountCurrency, si4.submit)
+
+ # Party Account currency must be in USD, force customer currency as there is no GLE
+
+ si3.cancel()
+ si5 = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable - _TC",
+ currency="USD", conversion_rate=50, do_not_submit=True)
+
+ self.assertRaises(InvalidAccountCurrency, si5.submit)
def create_sales_invoice(**args):
si = frappe.new_doc("Sales Invoice")
@@ -856,14 +930,15 @@
si.is_pos = args.is_pos
si.is_return = args.is_return
si.return_against = args.return_against
- si.currency="INR"
- si.conversion_rate = 1
+ si.currency=args.currency or "INR"
+ si.conversion_rate = args.conversion_rate or 1
si.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"qty": args.qty or 1,
"rate": args.rate or 100,
+ "income_account": "Sales - _TC",
"expense_account": "Cost of Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC",
"serial_no": args.serial_no
diff --git a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json
index e4c039c..363e323 100644
--- a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json
+++ b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json
@@ -117,7 +117,7 @@
"no_copy": 1,
"oldfieldname": "advance_amount",
"oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
+ "options": "party_account_currency",
"permlevel": 0,
"print_hide": 0,
"print_width": "120px",
@@ -143,7 +143,7 @@
"no_copy": 1,
"oldfieldname": "allocated_amount",
"oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
+ "options": "party_account_currency",
"permlevel": 0,
"print_hide": 0,
"print_width": "120px",
@@ -164,7 +164,7 @@
"is_submittable": 0,
"issingle": 0,
"istable": 1,
- "modified": "2014-12-25 16:30:19.446500",
+ "modified": "2015-08-21 16:22:28.866049",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Advance",
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index 7edd69f..ed2a049 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -27,14 +27,25 @@
gl_map = merge_similar_entries(gl_map)
for entry in gl_map:
- # toggle debit, credit if negative entry
+ # toggle debit, credit if negative entry
if flt(entry.debit) < 0:
entry.credit = flt(entry.credit) - flt(entry.debit)
entry.debit = 0.0
+
+ if flt(entry.debit_in_account_currency) < 0:
+ entry.credit_in_account_currency = \
+ flt(entry.credit_in_account_currency) - flt(entry.debit_in_account_currency)
+ entry.debit_in_account_currency = 0.0
+
if flt(entry.credit) < 0:
entry.debit = flt(entry.debit) - flt(entry.credit)
entry.credit = 0.0
-
+
+ if flt(entry.credit_in_account_currency) < 0:
+ entry.debit_in_account_currency = \
+ flt(entry.debit_in_account_currency) - flt(entry.credit_in_account_currency)
+ entry.credit_in_account_currency = 0.0
+
return gl_map
def merge_similar_entries(gl_map):
@@ -45,7 +56,11 @@
same_head = check_if_in_list(entry, merged_gl_map)
if same_head:
same_head.debit = flt(same_head.debit) + flt(entry.debit)
+ same_head.debit_in_account_currency = \
+ flt(same_head.debit_in_account_currency) + flt(entry.debit_in_account_currency)
same_head.credit = flt(same_head.credit) + flt(entry.credit)
+ same_head.credit_in_account_currency = \
+ flt(same_head.credit_in_account_currency) + flt(entry.credit_in_account_currency)
else:
merged_gl_map.append(entry)
diff --git a/erpnext/accounts/page/accounts_browser/accounts_browser.js b/erpnext/accounts/page/accounts_browser/accounts_browser.js
index 157a924..04e4f63 100644
--- a/erpnext/accounts/page/accounts_browser/accounts_browser.js
+++ b/erpnext/accounts/page/accounts_browser/accounts_browser.js
@@ -214,7 +214,8 @@
'Income Account', 'Tax', 'Chargeable', 'Temporary'].join('\n'),
description: __("Optional. This setting will be used to filter in various transactions.") },
{fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate')},
- {fieldtype:'Link', fieldname:'warehouse', label:__('Warehouse'), options:"Warehouse"}
+ {fieldtype:'Link', fieldname:'warehouse', label:__('Warehouse'), options:"Warehouse"},
+ {fieldtype:'Link', fieldname:'account_currency', label:__('Currency'), options:"Currency"}
]
})
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 250286c..4f49bc0 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -7,10 +7,13 @@
import datetime
from frappe import _, msgprint, scrub
from frappe.defaults import get_user_permissions
-from frappe.utils import add_days, getdate, formatdate, flt, get_first_day, date_diff, nowdate
+from frappe.utils import add_days, getdate, formatdate, get_first_day, date_diff
from erpnext.utilities.doctype.address.address import get_address_display
from erpnext.utilities.doctype.contact.contact import get_contact_details
+class InvalidCurrency(frappe.ValidationError): pass
+class InvalidAccountCurrency(frappe.ValidationError): pass
+
@frappe.whitelist()
def get_party_details(party=None, account=None, party_type="Customer", company=None,
posting_date=None, price_list=None, currency=None, doctype=None):
@@ -141,7 +144,61 @@
"due_date": get_due_date(posting_date, party_type, party, company)
}
return out
-
+
+def validate_accounting_currency(party):
+ company_currency = get_company_currency()
+
+ # set party account currency
+ if not party.party_account_currency:
+ if party.default_currency:
+ party.party_account_currency = party.default_currency
+ elif len(set(company_currency.values())) == 1:
+ party.party_account_currency = company_currency.values()[0]
+
+ party_account_currency_in_db = frappe.db.get_value(party.doctype, party.name, "party_account_currency")
+ if party_account_currency_in_db != party.party_account_currency:
+ existing_gle = frappe.db.get_value("GL Entry", {"party_type": party.doctype,
+ "party": party.name}, ["name", "account_currency"], as_dict=1)
+ if existing_gle:
+ if party_account_currency_in_db:
+ frappe.throw(_("Accounting Currency cannot be changed, as GL Entry exists for this {0}")
+ .format(party.doctype), InvalidCurrency)
+ else:
+ party.party_account_currency = existing_gle.account_currency
+
+
+def validate_party_account(party):
+ company_currency = get_company_currency()
+ if party.party_account_currency:
+ companies_with_different_currency = []
+ for company, currency in company_currency.items():
+ if currency != party.party_account_currency:
+ companies_with_different_currency.append(company)
+
+ for d in party.get("accounts"):
+ if d.company in companies_with_different_currency:
+ companies_with_different_currency.remove(d.company)
+
+ selected_account_currency = frappe.db.get_value("Account", d.account, "account_currency")
+ if selected_account_currency != party.party_account_currency:
+ frappe.throw(_("Account {0} is invalid, account currency must be {1}")
+ .format(d.account, selected_account_currency), InvalidAccountCurrency)
+
+ if companies_with_different_currency:
+ frappe.msgprint(_("Please mention Default {0} Account for the following companies, as accounting currency is different from company's default currency: {1}")
+ .format(
+ "Receivable" if party.doctype=="Customer" else "Payable",
+ "\n" + "\n".join(companies_with_different_currency)
+ )
+ )
+
+def get_company_currency():
+ company_currency = frappe._dict()
+ for d in frappe.get_all("Company", fields=["name", "default_currency"]):
+ company_currency.setdefault(d.name, d.default_currency)
+
+ return company_currency
+
@frappe.whitelist()
def get_party_account(company, party, party_type):
"""Returns the account for the given `party`.
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 19703be..988335f 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _, scrub
-from frappe.utils import getdate, nowdate, flt, cint
+from frappe.utils import getdate, nowdate, flt, cint, cstr
class ReceivablePayableReport(object):
def __init__(self, filters=None):
@@ -30,19 +30,37 @@
if args.get("party_type") == "Supplier":
columns += [_("Bill No") + "::80", _("Bill Date") + ":Date:80"]
- columns += [_("Invoiced Amount") + ":Currency:100", _("Paid Amount") + ":Currency:100",
- _("Outstanding Amount") + ":Currency:100", _("Age") + ":Int:50",
- "0-" + str(self.filters.range1) + ":Currency:100",
- str(self.filters.range1) + "-" + str(self.filters.range2) + ":Currency:100",
- str(self.filters.range2) + "-" + str(self.filters.range3) + ":Currency:100",
- str(self.filters.range3) + _("-Above") + ":Currency:100"
- ]
+ for label in ("Invoiced Amount", "Paid Amount", "Outstanding Amount"):
+ columns.append({
+ "label": label,
+ "fieldtype": "Currency",
+ "options": "currency",
+ "width": 120
+ })
+
+ columns += [_("Age (Days)") + "::80"]
+
+ for label in ("0-" + cstr(self.filters.range1),
+ cstr(self.filters.range1) + "-" + cstr(self.filters.range2),
+ cstr(self.filters.range2) + "-" +cstr(self.filters.range3),
+ cstr(self.filters.range3) + _("-Above")):
+ columns.append({
+ "label": label,
+ "fieldtype": "Currency",
+ "options": "currency",
+ "width": 120
+ })
if args.get("party_type") == "Customer":
columns += [_("Territory") + ":Link/Territory:80"]
if args.get("party_type") == "Supplier":
columns += [_("Supplier Type") + ":Link/Supplier Type:80"]
- columns += [_("Remarks") + "::200"]
+ columns += [{
+ "fieldname": "currency",
+ "label": _("Currency"),
+ "fieldtype": "Data",
+ "width": 100,
+ }, _("Remarks") + "::200"]
return columns
@@ -91,10 +109,11 @@
# customer territory / supplier type
if args.get("party_type") == "Customer":
- row += [self.get_territory(gle.party), gle.remarks]
+ row += [self.get_territory(gle.party)]
if args.get("party_type") == "Supplier":
- row += [self.get_supplier_type(gle.party), gle.remarks]
+ row += [self.get_supplier_type(gle.party)]
+ row += [gle.account_currency, gle.remarks]
data.append(row)
return data
@@ -171,10 +190,17 @@
def get_gl_entries(self, party_type):
if not hasattr(self, "gl_entries"):
conditions, values = self.prepare_conditions(party_type)
- self.gl_entries = frappe.db.sql("""select name, posting_date, account, party_type, party, debit, credit,
- voucher_type, voucher_no, against_voucher_type, against_voucher from `tabGL Entry`
- where docstatus < 2 and party_type=%s {0} order by posting_date, party"""
- .format(conditions), values, as_dict=True)
+
+ if self.filters.get(scrub(party_type)):
+ select_fields = ", debit_in_account_currency as debit, credit_in_account_currency as credit"
+ else:
+ select_fields = ", debit, credit"
+
+ self.gl_entries = frappe.db.sql("""select name, posting_date, account, party_type, party,
+ voucher_type, voucher_no, against_voucher_type, against_voucher, account_currency, remarks {0}
+ from `tabGL Entry`
+ where docstatus < 2 and party_type=%s {1} order by posting_date, party"""
+ .format(select_fields, conditions), values, as_dict=True)
return self.gl_entries
diff --git a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py
index e592f69..7016c46 100644
--- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py
+++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py
@@ -23,7 +23,8 @@
total_debit += flt(d[2])
total_credit += flt(d[3])
- amounts_not_reflected_in_system = frappe.db.sql("""select sum(ifnull(jvd.debit, 0) - ifnull(jvd.credit, 0))
+ amounts_not_reflected_in_system = frappe.db.sql("""
+ select sum(ifnull(jvd.debit_in_account_currency, 0) - ifnull(jvd.credit_in_account_currency, 0))
from `tabJournal Entry Account` jvd, `tabJournal Entry` jv
where jvd.parent = jv.name and jv.docstatus=1 and jvd.account=%s
and jv.posting_date > %s and jv.clearance_date <= %s and ifnull(jv.is_opening, 'No') = 'No'
@@ -38,7 +39,7 @@
data += [
get_balance_row(_("System Balance"), balance_as_per_system),
[""]*len(columns),
- ["", '"' + _("Amounts not reflected in bank") + '"', total_debit, total_credit, "", "", "", ""],
+ ["", '"' + _("Amounts not reflected in bank") + '"', total_debit, total_credit, "", "", "", "", ""],
get_balance_row(_("Amounts not reflected in system"), amounts_not_reflected_in_system),
[""]*len(columns),
get_balance_row(_("Expected balance as per bank"), bank_bal)
@@ -49,13 +50,14 @@
def get_columns():
return [_("Posting Date") + ":Date:100", _("Journal Entry") + ":Link/Journal Entry:220",
_("Debit") + ":Currency:120", _("Credit") + ":Currency:120",
- _("Against Account") + ":Link/Account:200", _("Reference") + "::100", _("Ref Date") + ":Date:110", _("Clearance Date") + ":Date:110"
+ _("Against Account") + ":Link/Account:200", _("Reference") + "::100",
+ _("Ref Date") + ":Date:110", _("Clearance Date") + ":Date:110", _("Currency") + ":Link/Currency:70"
]
def get_entries(filters):
entries = frappe.db.sql("""select
- jv.posting_date, jv.name, jvd.debit, jvd.credit,
- jvd.against_account, jv.cheque_no, jv.cheque_date, jv.clearance_date
+ jv.posting_date, jv.name, jvd.debit_in_account_currency, jvd.credit_in_account_currency,
+ jvd.against_account, jv.cheque_no, jv.cheque_date, jv.clearance_date, jvd.account_currency
from
`tabJournal Entry Account` jvd, `tabJournal Entry` jv
where jvd.parent = jv.name and jv.docstatus=1
@@ -68,6 +70,6 @@
def get_balance_row(label, amount):
if amount > 0:
- return ["", '"' + label + '"', amount, 0, "", "", "", ""]
+ return ["", '"' + label + '"', amount, 0, "", "", "", "", ""]
else:
- return ["", '"' + label + '"', 0, abs(amount), "", "", "", ""]
+ return ["", '"' + label + '"', 0, abs(amount), "", "", "", "", ""]
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 1cc9f4f..fd91929 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -12,9 +12,12 @@
account_details.setdefault(acc.name, acc)
validate_filters(filters, account_details)
+
validate_party(filters)
+
+ filters = set_account_currency(filters)
- columns = get_columns()
+ columns = get_columns(filters)
res = get_result(filters, account_details)
@@ -43,36 +46,77 @@
frappe.throw(_("To filter based on Party, select Party Type first"))
elif not frappe.db.exists(party_type, party):
frappe.throw(_("Invalid {0}: {1}").format(party_type, party))
-
-def get_columns():
- return [_("Posting Date") + ":Date:90", _("Account") + ":Link/Account:200",
- _("Debit") + ":Float:100", _("Credit") + ":Float:100",
+
+def set_account_currency(filters):
+ if not (filters.get("account") or filters.get("party")):
+ return filters
+ else:
+ filters["company_currency"] = frappe.db.get_value("Company", filters.company, "default_currency")
+ account_currency = None
+
+ if filters.get("account"):
+ account_currency = frappe.db.get_value("Account", filters.account, "account_currency")
+ elif filters.get("party"):
+ gle_currency = frappe.db.get_value("GL Entry", {"party_type": filters.party_type,
+ "party": filters.party, "company": filters.company}, "account_currency")
+ if gle_currency:
+ account_currency = gle_currency
+ else:
+ account_currency = frappe.db.get_value(filters.party_type, filters.party, "default_currency")
+
+ filters["account_currency"] = account_currency or filters.company_currency
+
+ if filters.account_currency != filters.company_currency:
+ filters["show_in_account_currency"] = 1
+
+ return filters
+
+def get_columns(filters):
+ columns = [
+ _("Posting Date") + ":Date:90", _("Account") + ":Link/Account:200",
+ _("Debit") + ":Float:100", _("Credit") + ":Float:100"
+ ]
+
+ if filters.get("show_in_account_currency"):
+ columns += [
+ _("Debit") + " (" + filters.account_currency + ")" + ":Float:100",
+ _("Credit") + " (" + filters.account_currency + ")" + ":Float:100"
+ ]
+
+ columns += [
_("Voucher Type") + "::120", _("Voucher No") + ":Dynamic Link/Voucher Type:160",
_("Against Account") + "::120", _("Party Type") + "::80", _("Party") + "::150",
- _("Cost Center") + ":Link/Cost Center:100", _("Remarks") + "::400"]
+ _("Cost Center") + ":Link/Cost Center:100", _("Remarks") + "::400"
+ ]
+
+ return columns
def get_result(filters, account_details):
gl_entries = get_gl_entries(filters)
data = get_data_with_opening_closing(filters, account_details, gl_entries)
- result = get_result_as_list(data)
+ result = get_result_as_list(data, filters)
return result
def get_gl_entries(filters):
+ select_fields = """, sum(ifnull(debit_in_account_currency, 0)) as debit_in_account_currency,
+ sum(ifnull(credit_in_account_currency, 0)) as credit_in_account_currency""" \
+ if filters.get("show_in_account_currency") else ""
+
group_by_condition = "group by voucher_type, voucher_no, account, cost_center" \
if filters.get("group_by_voucher") else "group by name"
gl_entries = frappe.db.sql("""select posting_date, account, party_type, party,
- sum(ifnull(debit, 0)) as debit, sum(ifnull(credit, 0)) as credit,
- voucher_type, voucher_no, cost_center, remarks, against, is_opening
+ sum(ifnull(debit, 0)) as debit, sum(ifnull(credit, 0)) as credit,
+ voucher_type, voucher_no, cost_center, remarks, against, is_opening {select_fields}
from `tabGL Entry`
where company=%(company)s {conditions}
{group_by_condition}
order by posting_date, account"""\
- .format(conditions=get_conditions(filters), group_by_condition=group_by_condition),
- filters, as_dict=1)
+ .format(select_fields=select_fields, conditions=get_conditions(filters),
+ group_by_condition=group_by_condition), filters, as_dict=1)
return gl_entries
@@ -105,35 +149,51 @@
data = []
gle_map = initialize_gle_map(gl_entries)
- opening, total_debit, total_credit, gle_map = get_accountwise_gle(filters, gl_entries, gle_map)
+ opening, total_debit, total_credit, opening_in_account_currency, total_debit_in_account_currency, \
+ total_credit_in_account_currency, gle_map = get_accountwise_gle(filters, gl_entries, gle_map)
# Opening for filtered account
if filters.get("account") or filters.get("party"):
- data += [get_balance_row(_("Opening"), opening), {}]
+ data += [get_balance_row(_("Opening"), opening, opening_in_account_currency), {}]
for acc, acc_dict in gle_map.items():
if acc_dict.entries:
# Opening for individual ledger, if grouped by account
if filters.get("group_by_account"):
- data.append(get_balance_row(_("Opening"), acc_dict.opening))
+ data.append(get_balance_row(_("Opening"), acc_dict.opening,
+ acc_dict.opening_in_account_currency))
data += acc_dict.entries
# Totals and closing for individual ledger, if grouped by account
if filters.get("group_by_account"):
+ account_closing = acc_dict.opening + acc_dict.total_debit - acc_dict.total_credit
+ account_closing_in_account_currency = acc_dict.opening_in_account_currency \
+ + acc_dict.total_debit_in_account_currency - acc_dict.total_credit_in_account_currency
+
data += [{"account": "'" + _("Totals") + "'", "debit": acc_dict.total_debit,
"credit": acc_dict.total_credit},
get_balance_row(_("Closing (Opening + Totals)"),
- (acc_dict.opening + acc_dict.total_debit - acc_dict.total_credit)), {}]
+ account_closing, account_closing_in_account_currency), {}]
# Total debit and credit between from and to date
if total_debit or total_credit:
- data.append({"account": "'" + _("Totals") + "'", "debit": total_debit, "credit": total_credit})
+ data.append({
+ "account": "'" + _("Totals") + "'",
+ "debit": total_debit,
+ "credit": total_credit,
+ "debit_in_account_currency": total_debit_in_account_currency,
+ "credit_in_account_currency": total_credit_in_account_currency
+ })
# Closing for filtered account
if filters.get("account") or filters.get("party"):
+ closing = opening + total_debit - total_credit
+ closing_in_account_currency = opening_in_account_currency + \
+ total_debit_in_account_currency - total_credit_in_account_currency
+
data.append(get_balance_row(_("Closing (Opening + Totals)"),
- (opening + total_debit - total_credit)))
+ closing, closing_in_account_currency))
return data
@@ -142,46 +202,83 @@
for gle in gl_entries:
gle_map.setdefault(gle.account, frappe._dict({
"opening": 0,
+ "opening_in_account_currency": 0,
"entries": [],
"total_debit": 0,
+ "total_debit_in_account_currency": 0,
"total_credit": 0,
- "closing": 0
+ "total_credit_in_account_currency": 0,
+ "closing": 0,
+ "closing_in_account_currency": 0
}))
return gle_map
def get_accountwise_gle(filters, gl_entries, gle_map):
opening, total_debit, total_credit = 0, 0, 0
+ opening_in_account_currency, total_debit_in_account_currency, total_credit_in_account_currency = 0, 0, 0
+
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
for gle in gl_entries:
amount = flt(gle.debit, 3) - flt(gle.credit, 3)
+ amount_in_account_currency = flt(gle.debit_in_account_currency, 3) - flt(gle.credit_in_account_currency, 3)
+
if (filters.get("account") or filters.get("party") or filters.get("group_by_account")) \
and (gle.posting_date < from_date or cstr(gle.is_opening) == "Yes"):
+
gle_map[gle.account].opening += amount
+ if filters.get("show_in_account_currency"):
+ gle_map[gle.account].opening_in_account_currency += amount_in_account_currency
+
if filters.get("account") or filters.get("party"):
opening += amount
+ if filters.get("show_in_account_currency"):
+ opening_in_account_currency += amount_in_account_currency
+
elif gle.posting_date <= to_date:
gle_map[gle.account].entries.append(gle)
gle_map[gle.account].total_debit += flt(gle.debit, 3)
gle_map[gle.account].total_credit += flt(gle.credit, 3)
-
+
total_debit += flt(gle.debit, 3)
total_credit += flt(gle.credit, 3)
+
+ if filters.get("show_in_account_currency"):
+ gle_map[gle.account].total_debit_in_account_currency += flt(gle.debit_in_account_currency, 3)
+ gle_map[gle.account].total_credit_in_account_currency += flt(gle.credit_in_account_currency, 3)
+
+ total_debit_in_account_currency += flt(gle.debit_in_account_currency, 3)
+ total_credit_in_account_currency += flt(gle.credit_in_account_currency, 3)
- return opening, total_debit, total_credit, gle_map
+ return opening, total_debit, total_credit, opening_in_account_currency, \
+ total_debit_in_account_currency, total_credit_in_account_currency, gle_map
-def get_balance_row(label, balance):
- return {
+def get_balance_row(label, balance, balance_in_account_currency=None):
+ balance_row = {
"account": "'" + label + "'",
"debit": balance if balance > 0 else 0,
- "credit": -1*balance if balance < 0 else 0,
+ "credit": -1*balance if balance < 0 else 0
}
+
+ if balance_in_account_currency != None:
+ balance_row.update({
+ "debit_in_account_currency": balance_in_account_currency if balance_in_account_currency > 0 else 0,
+ "credit_in_account_currency": -1*balance_in_account_currency if balance_in_account_currency < 0 else 0
+ })
+
+ return balance_row
-def get_result_as_list(data):
+def get_result_as_list(data, filters):
result = []
for d in data:
- result.append([d.get("posting_date"), d.get("account"), d.get("debit"),
- d.get("credit"), d.get("voucher_type"), d.get("voucher_no"),
- d.get("against"), d.get("party_type"), d.get("party"),
- d.get("cost_center"), d.get("remarks")])
+ row = [d.get("posting_date"), d.get("account"), d.get("debit"), d.get("credit")]
+
+ if filters.get("show_in_account_currency"):
+ row += [d.get("debit_in_account_currency"), d.get("credit_in_account_currency")]
+
+ row += [d.get("voucher_type"), d.get("voucher_no"), d.get("against"),
+ d.get("party_type"), d.get("party"), d.get("cost_center"), d.get("remarks")
+ ]
+
+ result.append(row)
return result
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 51c7916..f0f096e 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -50,7 +50,7 @@
throw(_("{0} '{1}' not in Fiscal Year {2}").format(label, formatdate(date), fiscal_year))
@frappe.whitelist()
-def get_balance_on(account=None, date=None, party_type=None, party=None):
+def get_balance_on(account=None, date=None, party_type=None, party=None, in_account_currency=True):
if not account and frappe.form_dict.get("account"):
account = frappe.form_dict.get("account")
if not date and frappe.form_dict.get("date"):
@@ -102,10 +102,14 @@
(party_type.replace('"', '\\"'), party.replace('"', '\\"')))
if account or (party_type and party):
+ if in_account_currency:
+ select_field = "sum(ifnull(debit_in_account_currency, 0)) - sum(ifnull(credit_in_account_currency, 0))"
+ else:
+ select_field = "sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))"
bal = frappe.db.sql("""
- SELECT sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
+ SELECT {0}
FROM `tabGL Entry` gle
- WHERE %s""" % " and ".join(cond))[0][0]
+ WHERE {1}""".format(select_field, " and ".join(cond)))[0][0]
# if bal is None, return 0
return flt(bal)
@@ -273,7 +277,7 @@
and name in (%s)""" % ', '.join(['%s']*len(account_list)), account_list))
for account, warehouse in account_warehouse.items():
- account_balance = get_balance_on(account, posting_date)
+ account_balance = get_balance_on(account, posting_date, in_account_currency=False)
stock_value = get_stock_value_on(warehouse, posting_date)
if abs(flt(stock_value) - flt(account_balance)) > 0.005:
difference.setdefault(account, flt(stock_value) - flt(account_balance))
@@ -378,7 +382,7 @@
# Balance as per system
stock_rbnb_account = "Stock Received But Not Billed - " + frappe.db.get_value("Company", company, "abbr")
- sys_bal = get_balance_on(stock_rbnb_account, posting_date)
+ sys_bal = get_balance_on(stock_rbnb_account, posting_date, in_account_currency=False)
# Amount should be credited
return flt(stock_rbnb) + flt(sys_bal)
diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.js b/erpnext/buying/doctype/purchase_common/purchase_common.js
index 7693e08..f372cd8 100644
--- a/erpnext/buying/doctype/purchase_common/purchase_common.js
+++ b/erpnext/buying/doctype/purchase_common/purchase_common.js
@@ -157,20 +157,9 @@
},
add_deduct_tax: function(doc, cdt, cdn) {
this.calculate_taxes_and_totals();
- },
-
- calculate_outstanding_amount: function() {
- if(this.frm.doc.doctype == "Purchase Invoice" && this.frm.doc.docstatus < 2) {
- frappe.model.round_floats_in(this.frm.doc, ["base_grand_total", "total_advance", "write_off_amount"]);
- this.frm.doc.total_amount_to_pay = flt(this.frm.doc.base_grand_total - this.frm.doc.write_off_amount,
- precision("total_amount_to_pay"));
- if (!this.frm.doc.is_return) {
- this.frm.doc.outstanding_amount = flt(this.frm.doc.total_amount_to_pay - this.frm.doc.total_advance,
- precision("outstanding_amount"));
- }
- }
}
});
+
cur_frm.add_fetch('project_name', 'cost_center', 'cost_center');
erpnext.buying.get_default_bom = function(frm) {
diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json
index 7f3bf89..e90ffc5 100644
--- a/erpnext/buying/doctype/supplier/supplier.json
+++ b/erpnext/buying/doctype/supplier/supplier.json
@@ -389,8 +389,31 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
- "depends_on": "eval:!doc.__islocal",
- "description": "Mention if non-standard receivable account applicable",
+ "fieldname": "party_account_currency",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Accounting Currency",
+ "no_copy": 0,
+ "options": "Currency",
+ "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,
+ "bold": 0,
+ "collapsible": 0,
+ "depends_on": "",
+ "description": "Mention if non-standard receivable account",
"fieldname": "accounts",
"fieldtype": "Table",
"hidden": 0,
@@ -511,8 +534,8 @@
"is_submittable": 0,
"issingle": 0,
"istable": 0,
- "modified": "2015-08-25 07:14:56.245716",
- "modified_by": "Administrator",
+ "modified": "2015-09-02 16:31:35.050738",
+ "modified_by": "nabin@erpnext.com",
"module": "Buying",
"name": "Supplier",
"owner": "Administrator",
diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py
index af7716b..6ee6b39 100644
--- a/erpnext/buying/doctype/supplier/supplier.py
+++ b/erpnext/buying/doctype/supplier/supplier.py
@@ -8,6 +8,7 @@
from frappe.model.naming import make_autoname
from erpnext.utilities.address_and_contact import load_address_and_contact
from erpnext.utilities.transaction_base import TransactionBase
+from erpnext.accounts.party import validate_accounting_currency, validate_party_account
class Supplier(TransactionBase):
def get_feed(self):
@@ -44,6 +45,9 @@
if frappe.defaults.get_global_default('supp_master_name') == 'Naming Series':
if not self.naming_series:
msgprint(_("Series is mandatory"), raise_exception=1)
+
+ validate_accounting_currency(self)
+ validate_party_account(self)
def get_contacts(self,nm):
if nm:
diff --git a/erpnext/buying/doctype/supplier/test_records.json b/erpnext/buying/doctype/supplier/test_records.json
index dfa5d46..6d01dff 100644
--- a/erpnext/buying/doctype/supplier/test_records.json
+++ b/erpnext/buying/doctype/supplier/test_records.json
@@ -1,14 +1,22 @@
[
{
- "company": "_Test Company",
"doctype": "Supplier",
"supplier_name": "_Test Supplier",
"supplier_type": "_Test Supplier Type"
},
{
- "company": "_Test Company",
"doctype": "Supplier",
"supplier_name": "_Test Supplier 1",
"supplier_type": "_Test Supplier Type"
+ },
+ {
+ "doctype": "Supplier",
+ "supplier_name": "_Test Supplier USD",
+ "supplier_type": "_Test Supplier Type",
+ "party_account_currency": "USD",
+ "accounts": [{
+ "company": "_Test Company",
+ "account": "_Test Payable USD - _TC"
+ }]
}
-]
+]
\ No newline at end of file
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index c7600df..47d7e7a 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -14,8 +14,19 @@
force_item_fields = ("item_group", "barcode", "brand", "stock_uom")
class CustomerFrozen(frappe.ValidationError): pass
+class InvalidCurrency(frappe.ValidationError): pass
class AccountsController(TransactionBase):
+ def __init__(self, arg1, arg2=None):
+ super(AccountsController, self).__init__(arg1, arg2)
+
+ @property
+ def company_currency(self):
+ if not hasattr(self, "__company_currency"):
+ self.__company_currency = get_company_currency(self.company)
+
+ return self.__company_currency
+
def validate(self):
if self.get("_action") and self._action != "update_after_submit":
self.set_missing_values(for_validate=True)
@@ -39,6 +50,7 @@
self.validate_enabled_taxes_and_charges()
self.validate_party()
+ self.validate_currency()
def on_submit(self):
if self.meta.get_field("is_recurring"):
@@ -95,8 +107,6 @@
def set_price_list_currency(self, buying_or_selling):
if self.meta.get_field("currency"):
- company_currency = get_company_currency(self.company)
-
# price list part
fieldname = "selling_price_list" if buying_or_selling.lower() == "selling" \
else "buying_price_list"
@@ -104,22 +114,22 @@
self.price_list_currency = frappe.db.get_value("Price List",
self.get(fieldname), "currency")
- if self.price_list_currency == company_currency:
+ if self.price_list_currency == self.company_currency:
self.plc_conversion_rate = 1.0
elif not self.plc_conversion_rate:
self.plc_conversion_rate = get_exchange_rate(
- self.price_list_currency, company_currency)
+ self.price_list_currency, self.company_currency)
# currency
if not self.currency:
self.currency = self.price_list_currency
self.conversion_rate = self.plc_conversion_rate
- elif self.currency == company_currency:
+ elif self.currency == self.company_currency:
self.conversion_rate = 1.0
elif not self.conversion_rate:
self.conversion_rate = get_exchange_rate(self.currency,
- company_currency)
+ self.company_currency)
def set_missing_item_details(self):
"""set missing item values"""
@@ -187,7 +197,7 @@
if frappe.db.get_value(taxes_and_charges_doctype, self.taxes_and_charges, "disabled"):
frappe.throw(_("{0} '{1}' is disabled").format(taxes_and_charges_doctype, self.taxes_and_charges))
- def get_gl_dict(self, args):
+ def get_gl_dict(self, args, account_currency=None):
"""this method populates the common properties of a gl entry record"""
gl_dict = frappe._dict({
'company': self.company,
@@ -198,11 +208,51 @@
'fiscal_year': self.fiscal_year,
'debit': 0,
'credit': 0,
+ 'debit_in_account_currency': 0,
+ 'credit_in_account_currency': 0,
'is_opening': self.get("is_opening") or "No",
'party_type': None,
'party': None
})
gl_dict.update(args)
+
+ if not account_currency:
+ account_currency = frappe.db.get_value("Account", gl_dict.account, "account_currency")
+
+ self.validate_account_currency(gl_dict.account, account_currency)
+ gl_dict = self.set_balance_in_account_currency(gl_dict, account_currency)
+
+ return gl_dict
+
+ def validate_account_currency(self, account, account_currency=None):
+ if self.doctype == "Journal Entry":
+ return
+ valid_currency = [self.company_currency]
+ if self.get("currency") and self.currency != self.company_currency:
+ valid_currency.append(self.currency)
+
+ if account_currency not in valid_currency:
+ frappe.throw(_("Account {0} is invalid. Account Currency must be {1}")
+ .format(account, " or ".join(valid_currency)))
+
+ def set_balance_in_account_currency(self, gl_dict, account_currency=None):
+ if not (self.get("conversion_rate") or self.get("exchange_rate")) \
+ and account_currency!=self.company_currency:
+ frappe.throw(_("Account: {0} with currency: {1} can not be selected")
+ .format(gl_dict.account, account_currency))
+
+ gl_dict["account_currency"] = self.company_currency if account_currency==self.company_currency \
+ else account_currency
+
+ # set debit/credit in account currency if not provided
+ if flt(gl_dict.debit) and not flt(gl_dict.debit_in_account_currency):
+ gl_dict.debit_in_account_currency = gl_dict.debit if account_currency==self.company_currency \
+ else flt(gl_dict.debit / (self.get("conversion_rate")), 2)
+
+ if flt(gl_dict.credit) and not flt(gl_dict.credit_in_account_currency):
+ gl_dict.credit_in_account_currency = gl_dict.credit if account_currency==self.company_currency \
+ else flt(gl_dict.credit / (self.get("conversion_rate")), 2)
+
return gl_dict
def clear_unallocated_advances(self, childtype, parentfield):
@@ -321,9 +371,9 @@
def set_total_advance_paid(self):
if self.doctype == "Sales Order":
- dr_or_cr = "credit"
+ dr_or_cr = "credit_in_account_currency"
else:
- dr_or_cr = "debit"
+ dr_or_cr = "debit_in_account_currency"
advance_paid = frappe.db.sql("""
select
@@ -331,10 +381,9 @@
from
`tabJournal Entry Account`
where
- reference_type = %s and
- reference_name = %s and
- docstatus = 1 and is_advance = "Yes" """.format(dr_or_cr=dr_or_cr),
- (self.doctype, self.name))
+ reference_type = %s and reference_name = %s
+ and docstatus = 1 and is_advance = "Yes"
+ """.format(dr_or_cr=dr_or_cr), (self.doctype, self.name))
if advance_paid:
advance_paid = flt(advance_paid[0][0], self.precision("advance_paid"))
@@ -357,18 +406,35 @@
if frozen_accounts_modifier in frappe.get_roles():
return
+ party_type, party = self.get_party()
+
+ if party_type:
+ if frappe.db.get_value(party_type, party, "is_frozen"):
+ frappe.throw("{0} {1} is frozen".format(party_type, party), CustomerFrozen)
+
+ def get_party(self):
party_type = None
if self.meta.get_field("customer"):
party_type = 'Customer'
elif self.meta.get_field("supplier"):
party_type = 'Supplier'
-
- if party_type:
- party = self.get(party_type.lower())
- if frappe.db.get_value(party_type, party, "is_frozen"):
- frappe.throw("{0} {1} is frozen".format(party_type, party), CustomerFrozen)
-
+
+ party = self.get(party_type.lower()) if party_type else None
+
+ return party_type, party
+
+ def validate_currency(self):
+ if self.get("currency"):
+ party_type, party = self.get_party()
+ if party_type and party:
+ party_account_currency = frappe.db.get_value(party_type, party, "party_account_currency") \
+ or self.company_currency
+
+ if party_account_currency != self.company_currency and self.currency != party_account_currency:
+ frappe.throw(_("Accounting Entry for {0}: {1} can only be made in currency: {2}")
+ .format(party_type, party, party_account_currency), InvalidCurrency)
+
@frappe.whitelist()
def get_tax_rate(account_head):
return frappe.db.get_value("Account", account_head, "tax_rate")
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 19b5a9b..eccceb0 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -46,22 +46,22 @@
# from warehouse account
self.check_expense_account(detail)
-
+
gl_list.append(self.get_gl_dict({
- "account": warehouse_account[sle.warehouse],
+ "account": warehouse_account[sle.warehouse]["name"],
"against": detail.expense_account,
"cost_center": detail.cost_center,
"remarks": self.get("remarks") or "Accounting Entry for Stock",
- "debit": flt(sle.stock_value_difference, 2)
- }))
+ "debit": flt(sle.stock_value_difference, 2),
+ }, warehouse_account[sle.warehouse]["account_currency"]))
- # to target warehouse / expense account
+ # to target warehouse / expense account
gl_list.append(self.get_gl_dict({
"account": detail.expense_account,
- "against": warehouse_account[sle.warehouse],
+ "against": warehouse_account[sle.warehouse]["name"],
"cost_center": detail.cost_center,
"remarks": self.get("remarks") or "Accounting Entry for Stock",
- "credit": flt(sle.stock_value_difference, 2)
+ "credit": flt(sle.stock_value_difference, 2),
}))
elif sle.warehouse not in warehouse_with_no_account:
warehouse_with_no_account.append(sle.warehouse)
@@ -69,7 +69,7 @@
if warehouse_with_no_account:
msgprint(_("No accounting entries for the following warehouses") + ": \n" +
"\n".join(warehouse_with_no_account))
-
+
return process_gl_map(gl_list)
def get_voucher_details(self, default_expense_account, default_cost_center, sle_map):
@@ -336,6 +336,9 @@
return gl_entries
def get_warehouse_account():
- warehouse_account = dict(frappe.db.sql("""select warehouse, name from tabAccount
- where account_type = 'Warehouse' and ifnull(warehouse, '') != ''"""))
+ warehouse_account = frappe._dict()
+
+ for d in frappe.db.sql("""select warehouse, name, account_currency from tabAccount
+ where account_type = 'Warehouse' and ifnull(warehouse, '') != ''""", as_dict=1):
+ warehouse_account.setdefault(d.warehouse, d)
return warehouse_account
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index d526f66..0fbe22d 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -394,17 +394,21 @@
# NOTE:
# write_off_amount is only for POS Invoice
# total_advance is only for non POS Invoice
-
+ if self.doc.is_return:
+ return
+
+ self.doc.round_floats_in(self.doc, ["grand_total", "total_advance", "write_off_amount"])
+ total_amount_to_pay = flt(self.doc.grand_total - self.doc.total_advance - self.doc.write_off_amount,
+ self.doc.precision("grand_total"))
+
if self.doc.doctype == "Sales Invoice":
- if not self.doc.is_return:
- self.doc.round_floats_in(self.doc, ["base_grand_total", "total_advance", "write_off_amount", "paid_amount"])
- total_amount_to_pay = self.doc.base_grand_total - self.doc.write_off_amount
- self.doc.outstanding_amount = flt(total_amount_to_pay - self.doc.total_advance - self.doc.paid_amount,
- self.doc.precision("outstanding_amount"))
+ self.doc.round_floats_in(self.doc, ["paid_amount"])
+ outstanding_amount = flt(total_amount_to_pay - self.doc.paid_amount, self.doc.precision("outstanding_amount"))
+ elif self.doc.doctype == "Purchase Invoice":
+ outstanding_amount = flt(total_amount_to_pay, self.doc.precision("outstanding_amount"))
+
+ if self.doc.party_account_currency == self.doc.currency:
+ self.doc.outstanding_amount = outstanding_amount
else:
- self.doc.round_floats_in(self.doc, ["total_advance", "write_off_amount"])
- self.doc.total_amount_to_pay = flt(self.doc.base_grand_total - self.doc.write_off_amount,
- self.doc.precision("total_amount_to_pay"))
- if not self.doc.is_return:
- self.doc.outstanding_amount = flt(self.doc.total_amount_to_pay - self.doc.total_advance,
- self.doc.precision("outstanding_amount"))
+ self.doc.outstanding_amount = flt(outstanding_amount * self.doc.conversion_rate,
+ self.doc.precision("outstanding_amount"))
\ No newline at end of file
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index 78729a3..5cf96e9 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -6,6 +6,7 @@
from frappe.utils import cstr, cint
from frappe import msgprint, _
from frappe.model.mapper import get_mapped_doc
+from erpnext.setup.utils import get_exchange_rate
from erpnext.utilities.transaction_base import TransactionBase
@@ -179,7 +180,17 @@
def make_quotation(source_name, target_doc=None):
def set_missing_values(source, target):
quotation = frappe.get_doc(target)
- quotation.currency = None # set it as default from customer
+
+ company_currency = frappe.db.get_value("Company", quotation.company, "default_currency")
+ party_account_currency = frappe.db.get_value("Customer", quotation.customer, "party_account_currency")
+ if company_currency == party_account_currency:
+ exchange_rate = 1
+ else:
+ exchange_rate = get_exchange_rate(party_account_currency, company_currency)
+
+ quotation.currency = party_account_currency or company_currency
+ quotation.conversion_rate = exchange_rate
+
quotation.run_method("set_missing_values")
quotation.run_method("calculate_taxes_and_totals")
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index b5fa71b..90d89fa 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -205,3 +205,4 @@
execute:frappe.db.set_value("Stock Settings", None, "automatically_set_serial_nos_based_on_fifo", 1)
execute:frappe.db.sql("""update `tabProject` set percent_complete=round(percent_complete, 2) where percent_complete is not null""")
erpnext.patches.v6_0.fix_outstanding_amount
+erpnext.patches.v6_0.multi_currency
diff --git a/erpnext/patches/v6_0/multi_currency.py b/erpnext/patches/v6_0/multi_currency.py
new file mode 100644
index 0000000..793a0c2
--- /dev/null
+++ b/erpnext/patches/v6_0/multi_currency.py
@@ -0,0 +1,98 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ # Reload doctype
+ for dt in ("Account", "GL Entry", "Journal Entry",
+ "Journal Entry Account", "Sales Invoice", "Purchase Invoice", "Customer", "Supplier"):
+ frappe.reload_doctype(dt)
+
+ for company in frappe.get_all("Company", fields=["name", "default_currency", "default_receivable_account"]):
+
+ # update currency in account and gl entry as per company currency
+ frappe.db.sql("""update `tabAccount` set account_currency = %s
+ where ifnull(account_currency, '') = '' and company=%s""", (company.default_currency, company.name))
+
+ # update newly introduced field's value in sales / purchase invoice
+ frappe.db.sql("""
+ update
+ `tabSales Invoice`
+ set
+ base_paid_amount=paid_amount,
+ base_write_off_amount=write_off_amount,
+ party_account_currency=%s
+ where company=%s
+ """, (company.default_currency, company.name))
+
+ frappe.db.sql("""
+ update
+ `tabPurchase Invoice`
+ set
+ base_write_off_amount=write_off_amount,
+ party_account_currency=%s
+ where company=%s
+ """, (company.default_currency, company.name))
+
+ # update exchange rate, debit/credit in account currency in Journal Entry
+ frappe.db.sql("""update `tabJournal Entry` set exchange_rate=1""")
+
+ frappe.db.sql("""
+ update
+ `tabJournal Entry Account` jea, `tabJournal Entry` je
+ set
+ debit_in_account_currency=debit,
+ credit_in_account_currency=credit,
+ account_currency=%s
+ where
+ jea.parent = je.name
+ and je.company=%s
+ """, (company.default_currency, company.name))
+
+ # update debit/credit in account currency in GL Entry
+ frappe.db.sql("""
+ update
+ `tabGL Entry`
+ set
+ debit_in_account_currency=debit,
+ credit_in_account_currency=credit,
+ account_currency=%s
+ where
+ company=%s
+ """, (company.default_currency, company.name))
+
+ # Set party account if default currency of party other than company's default currency
+ for dt in ("Customer", "Supplier"):
+ parties = frappe.get_all(dt)
+ for p in parties:
+ # Get party GL Entries
+ party_gle = frappe.db.get_value("GL Entry", {"party_type": dt, "party": p.name,
+ "company": company.name}, ["account", "account_currency"], as_dict=True)
+
+ party = frappe.get_doc(dt, p.name)
+
+ # set party account currency
+ if party_gle or not party.party_account_currency:
+ party.party_account_currency = company.default_currency
+
+ # Add default receivable /payable account if not exists
+ # and currency is other than company currency
+ if party.party_account_currency and party.party_account_currency != company.default_currency:
+ party_account_exists = False
+ for d in party.get("accounts"):
+ if d.company == company.name:
+ party_account_exists = True
+ break
+
+ if not party_account_exists:
+ party_account = party_gle.account if party_gle else company.default_receivable_account
+ if party_account:
+ party.append("accounts", {
+ "company": company.name,
+ "account": party_account
+ })
+
+ party.flags.ignore_mandatory = True
+ party.save()
\ No newline at end of file
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 0b3ca7f..b1b24cf 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -491,5 +491,45 @@
this.frm.doc.total_advance = flt(total_allocated_amount, precision("total_advance"));
this.calculate_outstanding_amount(update_paid_amount);
+ },
+
+ calculate_outstanding_amount: function(update_paid_amount) {
+ // NOTE:
+ // paid_amount and write_off_amount is only for POS Invoice
+ // total_advance is only for non POS Invoice
+ if(this.frm.doc.is_return || this.frm.doc.docstatus > 0) return;
+
+ frappe.model.round_floats_in(this.frm.doc, ["grand_total", "total_advance", "write_off_amount"]);
+
+ var total_amount_to_pay = flt((this.frm.doc.grand_total - this.frm.doc.total_advance
+ - this.frm.doc.write_off_amount), precision("grand_total"));
+
+ if(this.frm.doc.doctype == "Sales Invoice") {
+ frappe.model.round_floats_in(this.frm.doc, ["paid_amount"]);
+
+ if(this.frm.doc.is_pos) {
+ if(!this.frm.doc.paid_amount || update_paid_amount===undefined || update_paid_amount) {
+ this.frm.doc.paid_amount = flt(total_amount_to_pay);
+ }
+ } else {
+ this.frm.doc.paid_amount = 0
+ }
+ this.set_in_company_currency(this.frm.doc, ["paid_amount"]);
+ this.frm.refresh_field("paid_amount");
+ this.frm.refresh_field("base_paid_amount");
+
+ var outstanding_amount = flt(total_amount_to_pay - this.frm.doc.paid_amount,
+ precision("outstanding_amount"));
+
+ } else if(this.frm.doc.doctype == "Purchase Invoice") {
+ var outstanding_amount = flt(total_amount_to_pay, precision("outstanding_amount"));
+ }
+
+ if(this.frm.doc.party_account_currency == this.frm.doc.currency) {
+ this.frm.set_value("outstanding_amount", outstanding_amount);
+ } else {
+ this.frm.set_value("outstanding_amount",
+ flt(outstanding_amount * this.frm.doc.conversion_rate, precision("outstanding_amount")));
+ }
}
})
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index c6b26bc..7f2cee7 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -423,11 +423,14 @@
setup_field_label_map(["base_total", "base_net_total", "base_total_taxes_and_charges",
"base_discount_amount", "base_grand_total", "base_rounded_total", "base_in_words",
"base_taxes_and_charges_added", "base_taxes_and_charges_deducted", "total_amount_to_pay",
- "outstanding_amount", "total_advance", "paid_amount", "write_off_amount"], company_currency);
+ "base_paid_amount", "base_write_off_amount"
+ ], company_currency);
setup_field_label_map(["total", "net_total", "total_taxes_and_charges", "discount_amount",
"grand_total", "taxes_and_charges_added", "taxes_and_charges_deducted",
- "rounded_total", "in_words"], this.frm.doc.currency);
+ "rounded_total", "in_words", "paid_amount", "write_off_amount"], this.frm.doc.currency);
+
+ setup_field_label_map(["outstanding_amount", "total_advance"], this.frm.doc.party_account_currency);
cur_frm.set_df_property("conversion_rate", "description", "1 " + this.frm.doc.currency
+ " = [?] " + company_currency)
@@ -440,7 +443,8 @@
// toggle fields
this.frm.toggle_display(["conversion_rate", "base_total", "base_net_total", "base_total_taxes_and_charges",
"base_taxes_and_charges_added", "base_taxes_and_charges_deducted",
- "base_grand_total", "base_rounded_total", "base_in_words", "base_discount_amount"],
+ "base_grand_total", "base_rounded_total", "base_in_words", "base_discount_amount",
+ "base_paid_amount", "base_write_off_amount"],
this.frm.doc.currency != company_currency);
this.frm.toggle_display(["plc_conversion_rate", "price_list_currency"],
diff --git a/erpnext/public/js/pos/pos.js b/erpnext/public/js/pos/pos.js
index 5f82796..02eeab0 100644
--- a/erpnext/public/js/pos/pos.js
+++ b/erpnext/public/js/pos/pos.js
@@ -473,13 +473,11 @@
}
me.frm.set_value("mode_of_payment", values.mode_of_payment);
- //me.frm.cscript.calculate_taxes_and_totals();
-
- var paid_amount = flt((flt(values.paid_amount) - flt(values.change)) / me.frm.doc.conversion_rate, precision("paid_amount"));
+ var paid_amount = flt((flt(values.paid_amount) - flt(values.change)), precision("paid_amount"));
me.frm.set_value("paid_amount", paid_amount);
-
+
// specifying writeoff amount here itself, so as to avoid recursion issue
- me.frm.set_value("write_off_amount", me.frm.doc.base_grand_total - paid_amount);
+ me.frm.set_value("write_off_amount", me.frm.doc.grand_total - paid_amount);
me.frm.set_value("outstanding_amount", 0);
me.frm.savesubmit(this);
diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js
index ac0f636..9325e72 100644
--- a/erpnext/selling/doctype/customer/customer.js
+++ b/erpnext/selling/doctype/customer/customer.js
@@ -12,7 +12,15 @@
frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal);
- if(!frm.doc.__islocal) erpnext.utils.render_address_and_contact(frm);
+ if(!frm.doc.__islocal) {
+ erpnext.utils.render_address_and_contact(frm);
+ }
+
+ var grid = cur_frm.get_field("sales_team").grid;
+ grid.set_column_disp("allocated_percentage", false);
+ grid.set_column_disp("allocated_amount", false);
+ grid.set_column_disp("incentives", false);
+
})
cur_frm.cscript.onload = function(doc, dt, dn) {
@@ -92,11 +100,17 @@
cur_frm.fields_dict['accounts'].grid.get_field('account').get_query = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
+ var filters = {
+ 'account_type': 'Receivable',
+ 'company': d.company,
+ "is_group": 0
+ };
+
+ if(doc.party_account_currency) {
+ $.extend(filters, {"account_currency": doc.party_account_currency});
+ }
+
return {
- filters: {
- 'account_type': 'Receivable',
- 'company': d.company,
- "is_group": 0
- }
+ filters: filters
}
}
diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json
index 3167a83..d160798 100644
--- a/erpnext/selling/doctype/customer/customer.json
+++ b/erpnext/selling/doctype/customer/customer.json
@@ -273,7 +273,7 @@
"ignore_user_permissions": 1,
"in_filter": 0,
"in_list_view": 0,
- "label": "Currency",
+ "label": "Default Currency",
"no_copy": 1,
"options": "Currency",
"permlevel": 0,
@@ -463,8 +463,31 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
- "depends_on": "eval:!doc.__islocal",
- "description": "Mention if non-standard receivable account applicable",
+ "fieldname": "party_account_currency",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Accounting Currency",
+ "no_copy": 0,
+ "options": "Currency",
+ "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,
+ "bold": 0,
+ "collapsible": 0,
+ "depends_on": "",
+ "description": "Mention if non-standard receivable account",
"fieldname": "accounts",
"fieldtype": "Table",
"hidden": 0,
@@ -567,7 +590,7 @@
"no_copy": 0,
"oldfieldname": "credit_limit",
"oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
+ "options": "",
"permlevel": 1,
"print_hide": 0,
"read_only": 0,
@@ -796,8 +819,8 @@
"is_submittable": 0,
"issingle": 0,
"istable": 0,
- "modified": "2015-08-25 07:09:26.411627",
- "modified_by": "Administrator",
+ "modified": "2015-09-02 16:32:54.474655",
+ "modified_by": "nabin@erpnext.com",
"module": "Selling",
"name": "Customer",
"owner": "Administrator",
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 5cbf243..7ea90f0 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -10,6 +10,7 @@
from erpnext.utilities.transaction_base import TransactionBase
from erpnext.utilities.address_and_contact import load_address_and_contact
+from erpnext.accounts.party import validate_accounting_currency, validate_party_account
from frappe.desk.reportview import build_match_conditions
class Customer(TransactionBase):
@@ -27,12 +28,14 @@
else:
self.name = make_autoname(self.naming_series+'.#####')
- def validate_values(self):
+ def validate_mandatory(self):
if frappe.defaults.get_global_default('cust_master_name') == 'Naming Series' and not self.naming_series:
frappe.throw(_("Series is mandatory"), frappe.MandatoryError)
-
+
def validate(self):
- self.validate_values()
+ self.validate_mandatory()
+ validate_accounting_currency(self)
+ validate_party_account(self)
def update_lead_status(self):
if self.lead_name:
diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py
index dca4bb7..a0a1501 100644
--- a/erpnext/selling/doctype/customer/test_customer.py
+++ b/erpnext/selling/doctype/customer/test_customer.py
@@ -8,6 +8,8 @@
from frappe.test_runner import make_test_records
from erpnext.controllers.accounts_controller import CustomerFrozen
+from erpnext.accounts.party import InvalidCurrency
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
test_ignore = ["Price List"]
@@ -77,4 +79,14 @@
frappe.db.set_value("Customer", "_Test Customer", "is_frozen", 0)
- so.save()
\ No newline at end of file
+ so.save()
+
+ def test_multi_currency(self):
+ customer = frappe.get_doc("Customer", "_Test Customer USD")
+
+ create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
+ currency="USD", conversion_rate=50)
+
+ customer.party_account_currency = "EUR"
+ self.assertRaises(InvalidCurrency, customer.save)
+
\ No newline at end of file
diff --git a/erpnext/selling/doctype/customer/test_records.json b/erpnext/selling/doctype/customer/test_records.json
index e076f7a..060633e 100644
--- a/erpnext/selling/doctype/customer/test_records.json
+++ b/erpnext/selling/doctype/customer/test_records.json
@@ -1,6 +1,5 @@
[
{
- "company": "_Test Company",
"customer_group": "_Test Customer Group",
"customer_name": "_Test Customer",
"customer_type": "Individual",
@@ -8,7 +7,6 @@
"territory": "_Test Territory"
},
{
- "company": "_Test Company",
"customer_group": "_Test Customer Group",
"customer_name": "_Test Customer 1",
"customer_type": "Individual",
@@ -16,7 +14,6 @@
"territory": "_Test Territory"
},
{
- "company": "_Test Company",
"customer_group": "_Test Customer Group",
"customer_name": "_Test Customer 2",
"customer_type": "Individual",
@@ -24,11 +21,22 @@
"territory": "_Test Territory"
},
{
- "company": "_Test Company",
"customer_group": "_Test Customer Group",
"customer_name": "_Test Customer 3",
"customer_type": "Individual",
"doctype": "Customer",
"territory": "_Test Territory"
+ },
+ {
+ "customer_group": "_Test Customer Group",
+ "customer_name": "_Test Customer USD",
+ "customer_type": "Individual",
+ "doctype": "Customer",
+ "territory": "_Test Territory",
+ "party_account_currency": "USD",
+ "accounts": [{
+ "company": "_Test Company",
+ "account": "_Test Receivable USD - _TC"
+ }]
}
]
diff --git a/erpnext/selling/doctype/sales_team/sales_team.json b/erpnext/selling/doctype/sales_team/sales_team.json
index dfd0ff1..1747d2e 100644
--- a/erpnext/selling/doctype/sales_team/sales_team.json
+++ b/erpnext/selling/doctype/sales_team/sales_team.json
@@ -37,31 +37,6 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
- "fieldname": "sales_designation",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "label": "Designation",
- "no_copy": 0,
- "oldfieldname": "sales_designation",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_width": "100px",
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
"fieldname": "contact_no",
"fieldtype": "Data",
"hidden": 1,
@@ -210,7 +185,7 @@
"is_submittable": 0,
"issingle": 0,
"istable": 1,
- "modified": "2013-12-31 19:00:14",
+ "modified": "2015-08-13 16:30:24.146848",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Team",
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 5404947..6a8744a 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -206,30 +206,6 @@
}
},
- calculate_outstanding_amount: function(update_paid_amount) {
- // NOTE:
- // paid_amount and write_off_amount is only for POS Invoice
- // total_advance is only for non POS Invoice
- if(this.frm.doc.doctype == "Sales Invoice" && this.frm.doc.docstatus==0 && !this.frm.doc.is_return) {
- frappe.model.round_floats_in(this.frm.doc, ["base_grand_total", "total_advance", "write_off_amount",
- "paid_amount"]);
- var total_amount_to_pay = this.frm.doc.base_grand_total - this.frm.doc.write_off_amount
- - this.frm.doc.total_advance;
- if(this.frm.doc.is_pos) {
- if(!this.frm.doc.paid_amount || update_paid_amount===undefined || update_paid_amount) {
- this.frm.doc.paid_amount = flt(total_amount_to_pay);
- this.frm.refresh_field("paid_amount");
- }
- } else {
- this.frm.doc.paid_amount = 0
- this.frm.refresh_field("paid_amount");
- }
-
- this.frm.set_value("outstanding_amount", flt(total_amount_to_pay
- - this.frm.doc.paid_amount, precision("outstanding_amount")));
- }
- },
-
calculate_commission: function() {
if(this.frm.fields_dict.commission_rate) {
if(this.frm.doc.commission_rate > 100) {
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index cf47de5..804dc4d 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -34,13 +34,8 @@
if not self.abbr.strip():
frappe.throw(_("Abbreviation is mandatory"))
- self.previous_default_currency = frappe.db.get_value("Company", self.name, "default_currency")
- if self.default_currency and self.previous_default_currency and \
- self.default_currency != self.previous_default_currency and \
- self.check_if_transactions_exist():
- frappe.throw(_("Cannot change company's default currency, because there are existing transactions. Transactions must be cancelled to change the default currency."))
-
self.validate_default_accounts()
+ self.validate_currency()
def validate_default_accounts(self):
for field in ["default_bank_account", "default_cash_account", "default_receivable_account", "default_payable_account",
@@ -51,6 +46,13 @@
if for_company != self.name:
frappe.throw(_("Account {0} does not belong to company: {1}")
.format(self.get(field), self.name))
+
+ def validate_currency(self):
+ self.previous_default_currency = frappe.db.get_value("Company", self.name, "default_currency")
+ if self.default_currency and self.previous_default_currency and \
+ self.default_currency != self.previous_default_currency and \
+ self.check_if_transactions_exist():
+ frappe.throw(_("Cannot change company's default currency, because there are existing transactions. Transactions must be cancelled to change the default currency."))
def on_update(self):
if not frappe.db.sql("""select name from tabAccount
diff --git a/erpnext/setup/doctype/company/test_records.json b/erpnext/setup/doctype/company/test_records.json
index 13cb03e..b6918b3 100644
--- a/erpnext/setup/doctype/company/test_records.json
+++ b/erpnext/setup/doctype/company/test_records.json
@@ -19,7 +19,7 @@
},
{
"abbr": "_TC2",
- "company_name": "_Test Company 3",
+ "company_name": "_Test Company 2",
"default_currency": "EUR",
"country": "Germany",
"doctype": "Company",
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index e7ede65..17194fd 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -10,17 +10,6 @@
this._super();
if (!doc.is_return) {
- if(doc.__onload && !doc.__onload.billing_complete && doc.docstatus==1) {
- // show Make Invoice button only if Delivery Note is not created from Sales Invoice
- var from_sales_invoice = false;
- from_sales_invoice = cur_frm.doc.items.some(function(item) {
- return item.against_sales_invoice ? true : false;
- });
-
- if(!from_sales_invoice)
- cur_frm.add_custom_button(__('Invoice'), this.make_sales_invoice).addClass("btn-primary");
- }
-
if(flt(doc.per_installed, 2) < 100 && doc.docstatus==1)
cur_frm.add_custom_button(__('Installation Note'), this.make_installation_note);
@@ -59,7 +48,16 @@
}
}
+ if(doc.__onload && !doc.__onload.billing_complete && doc.docstatus==1 && !doc.is_return) {
+ // show Make Invoice button only if Delivery Note is not created from Sales Invoice
+ var from_sales_invoice = false;
+ from_sales_invoice = cur_frm.doc.items.some(function(item) {
+ return item.against_sales_invoice ? true : false;
+ });
+ if(!from_sales_invoice)
+ cur_frm.add_custom_button(__('Invoice'), this.make_sales_invoice).addClass("btn-primary");
+ }
erpnext.stock.delivery_note.set_print_hide(doc, dt, dn);
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 1ab866c..85610a4 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -307,23 +307,28 @@
val_rate_db_precision = 6 if cint(d.precision("valuation_rate")) <= 6 else 9
# warehouse account
+ stock_value_diff = flt(flt(d.valuation_rate, val_rate_db_precision) * flt(d.qty)
+ * flt(d.conversion_factor), d.precision("base_net_amount"))
+
gl_entries.append(self.get_gl_dict({
- "account": warehouse_account[d.warehouse],
+ "account": warehouse_account[d.warehouse]["name"],
"against": stock_rbnb,
"cost_center": d.cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "debit": flt(flt(d.valuation_rate, val_rate_db_precision) * flt(d.qty) * flt(d.conversion_factor),
- self.precision("base_net_amount", d))
- }))
+ "debit": stock_value_diff
+ }, warehouse_account[d.warehouse]["account_currency"]))
# stock received but not billed
+ stock_rbnb_currency = frappe.db.get_value("Account", stock_rbnb, "account_currency")
gl_entries.append(self.get_gl_dict({
"account": stock_rbnb,
- "against": warehouse_account[d.warehouse],
+ "against": warehouse_account[d.warehouse]["name"],
"cost_center": d.cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "credit": flt(d.base_net_amount, self.precision("base_net_amount", d))
- }))
+ "credit": flt(d.base_net_amount, d.precision("base_net_amount")),
+ "credit_in_account_currency": flt(d.base_net_amount, d.precision("base_net_amount")) \
+ if stock_rbnb_currency==self.company_currency else flt(d.net_amount, d.precision("net_amount"))
+ }, stock_rbnb_currency))
negative_expense_to_be_booked += flt(d.item_tax_amount)
@@ -331,7 +336,7 @@
if flt(d.landed_cost_voucher_amount):
gl_entries.append(self.get_gl_dict({
"account": expenses_included_in_valuation,
- "against": warehouse_account[d.warehouse],
+ "against": warehouse_account[d.warehouse]["name"],
"cost_center": d.cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"credit": flt(d.landed_cost_voucher_amount)
@@ -340,12 +345,12 @@
# sub-contracting warehouse
if flt(d.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
gl_entries.append(self.get_gl_dict({
- "account": warehouse_account[self.supplier_warehouse],
- "against": warehouse_account[d.warehouse],
+ "account": warehouse_account[self.supplier_warehouse]["name"],
+ "against": warehouse_account[d.warehouse]["name"],
"cost_center": d.cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"credit": flt(d.rm_supp_cost)
- }))
+ }, warehouse_account[self.supplier_warehouse]["account_currency"]))
# divisional loss adjustment
sle_valuation_amount = flt(flt(d.valuation_rate, val_rate_db_precision) * flt(d.qty) * flt(d.conversion_factor),
@@ -358,11 +363,11 @@
if divisional_loss:
gl_entries.append(self.get_gl_dict({
"account": stock_rbnb,
- "against": warehouse_account[d.warehouse],
+ "against": warehouse_account[d.warehouse]["name"],
"cost_center": d.cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"debit": divisional_loss
- }))
+ }, stock_rbnb_currency))
elif d.warehouse not in warehouse_with_no_account or \
d.rejected_warehouse not in warehouse_with_no_account: