Merge branch 'develop'
This commit is contained in:
commit
7523429ded
@ -1,6 +1,6 @@
|
|||||||
# ERPNext - Open source ERP for small and medium-size business [![Build Status](https://travis-ci.org/frappe/erpnext.png)](https://travis-ci.org/frappe/erpnext)
|
# ERPNext - ERP made simple
|
||||||
|
|
||||||
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/frappe/erpnext?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[![Build Status](https://travis-ci.org/frappe/erpnext.png)](https://travis-ci.org/frappe/erpnext) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/frappe/erpnext?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
[https://erpnext.com](https://erpnext.com)
|
[https://erpnext.com](https://erpnext.com)
|
||||||
|
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
__version__ = '6.1.1'
|
__version__ = '6.2.0'
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"description": "Heads (or groups) against which Accounting Entries are made and balances are maintained.",
|
"description": "Heads (or groups) against which Accounting Entries are made and balances are maintained.",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -166,6 +166,30 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"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,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -402,7 +426,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-11 15:51:26",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Account",
|
"name": "Account",
|
||||||
|
@ -7,6 +7,8 @@ from frappe.utils import cstr, cint
|
|||||||
from frappe import throw, _
|
from frappe import throw, _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
class RootNotEditable(frappe.ValidationError): pass
|
||||||
|
|
||||||
class Account(Document):
|
class Account(Document):
|
||||||
nsm_parent_field = 'parent_account'
|
nsm_parent_field = 'parent_account'
|
||||||
|
|
||||||
@ -28,6 +30,7 @@ class Account(Document):
|
|||||||
self.validate_warehouse_account()
|
self.validate_warehouse_account()
|
||||||
self.validate_frozen_accounts_modifier()
|
self.validate_frozen_accounts_modifier()
|
||||||
self.validate_balance_must_be_debit_or_credit()
|
self.validate_balance_must_be_debit_or_credit()
|
||||||
|
self.validate_account_currency()
|
||||||
|
|
||||||
def validate_parent(self):
|
def validate_parent(self):
|
||||||
"""Fetch Parent Details and validate parent account"""
|
"""Fetch Parent Details and validate parent account"""
|
||||||
@ -67,7 +70,7 @@ class Account(Document):
|
|||||||
# does not exists parent
|
# does not exists parent
|
||||||
if frappe.db.exists("Account", self.name):
|
if frappe.db.exists("Account", self.name):
|
||||||
if not frappe.db.get_value("Account", self.name, "parent_account"):
|
if not frappe.db.get_value("Account", self.name, "parent_account"):
|
||||||
throw(_("Root cannot be edited."))
|
throw(_("Root cannot be edited."), RootNotEditable)
|
||||||
|
|
||||||
def validate_frozen_accounts_modifier(self):
|
def validate_frozen_accounts_modifier(self):
|
||||||
old_value = frappe.db.get_value("Account", self.name, "freeze_account")
|
old_value = frappe.db.get_value("Account", self.name, "freeze_account")
|
||||||
@ -87,6 +90,14 @@ class Account(Document):
|
|||||||
elif account_balance < 0 and self.balance_must_be == "Debit":
|
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'"))
|
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):
|
def convert_group_to_ledger(self):
|
||||||
if self.check_if_child_exists():
|
if self.check_if_child_exists():
|
||||||
throw(_("Account with child nodes cannot be converted to ledger"))
|
throw(_("Account with child nodes cannot be converted to ledger"))
|
||||||
|
@ -36,7 +36,8 @@ def create_charts(chart_name, company):
|
|||||||
"is_group": is_group,
|
"is_group": is_group,
|
||||||
"root_type": root_type,
|
"root_type": root_type,
|
||||||
"report_type": report_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:
|
if root_account:
|
||||||
|
@ -9,36 +9,39 @@ def _make_test_records(verbose):
|
|||||||
|
|
||||||
accounts = [
|
accounts = [
|
||||||
# [account_name, parent_account, is_group]
|
# [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 Stock Expenses", "Direct Expenses", 1, None, None],
|
||||||
["_Test Account Shipping Charges", "_Test Account Stock Expenses", 0, "Chargeable"],
|
["_Test Account Shipping Charges", "_Test Account Stock Expenses", 0, "Chargeable", None],
|
||||||
["_Test Account Customs Duty", "_Test Account Stock Expenses", 0, "Tax"],
|
["_Test Account Customs Duty", "_Test Account Stock Expenses", 0, "Tax", None],
|
||||||
["_Test Account Insurance Charges", "_Test Account Stock Expenses", 0, "Chargeable"],
|
["_Test Account Insurance Charges", "_Test Account Stock Expenses", 0, "Chargeable", None],
|
||||||
["_Test Account Stock Adjustment", "_Test Account Stock Expenses", 0, "Stock Adjustment"],
|
["_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 Reserves and Surplus", "Current Liabilities", 0, None, 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],
|
["_Test Account Cost for Goods Sold", "Expenses", 0, None, None],
|
||||||
|
["_Test Account Excise Duty", "_Test Account Tax Assets", 0, "Tax", None],
|
||||||
["_Test Account Cost for Goods Sold", "Expenses", 0, None],
|
["_Test Account Education Cess", "_Test Account Tax Assets", 0, "Tax", None],
|
||||||
["_Test Account Excise Duty", "_Test Account Tax Assets", 0, "Tax"],
|
["_Test Account S&H Education Cess", "_Test Account Tax Assets", 0, "Tax", None],
|
||||||
["_Test Account Education Cess", "_Test Account Tax Assets", 0, "Tax"],
|
["_Test Account CST", "Direct Expenses", 0, "Tax", None],
|
||||||
["_Test Account S&H Education Cess", "_Test Account Tax Assets", 0, "Tax"],
|
["_Test Account Discount", "Direct Expenses", 0, None, None],
|
||||||
["_Test Account CST", "Direct Expenses", 0, "Tax"],
|
["_Test Write Off", "Indirect Expenses", 0, None, None],
|
||||||
["_Test Account Discount", "Direct Expenses", 0, None],
|
|
||||||
["_Test Write Off", "Indirect Expenses", 0, None],
|
|
||||||
|
|
||||||
# related to Account Inventory Integration
|
# related to Account Inventory Integration
|
||||||
["_Test Account Stock In Hand", "Current Assets", 0, None],
|
["_Test Account Stock In Hand", "Current Assets", 0, None, None],
|
||||||
["_Test Account Fixed Assets", "Current Assets", 0, None],
|
["_Test Account Fixed Assets", "Current Assets", 0, None, None],
|
||||||
|
|
||||||
# Receivable / Payable Account
|
# Receivable / Payable Account
|
||||||
["_Test Receivable", "Current Assets", 0, "Receivable"],
|
["_Test Receivable", "Current Assets", 0, "Receivable", None],
|
||||||
["_Test Payable", "Current Liabilities", 0, "Payable"],
|
["_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"]]:
|
for company, abbr in [["_Test Company", "_TC"], ["_Test Company 1", "_TC1"]]:
|
||||||
@ -48,7 +51,8 @@ def _make_test_records(verbose):
|
|||||||
"parent_account": parent_account + " - " + abbr,
|
"parent_account": parent_account + " - " + abbr,
|
||||||
"company": company,
|
"company": company,
|
||||||
"is_group": is_group,
|
"is_group": is_group,
|
||||||
"account_type": account_type
|
"account_type": account_type,
|
||||||
} for account_name, parent_account, is_group, account_type in accounts])
|
"account_currency": currency
|
||||||
|
} for account_name, parent_account, is_group, account_type, currency in accounts])
|
||||||
|
|
||||||
return test_objects
|
return test_objects
|
||||||
|
@ -16,7 +16,9 @@ class AccountsSettings(Document):
|
|||||||
if cint(self.auto_accounting_for_stock):
|
if cint(self.auto_accounting_for_stock):
|
||||||
# set default perpetual account in company
|
# set default perpetual account in company
|
||||||
for company in frappe.db.sql("select name from tabCompany"):
|
for company in frappe.db.sql("select name from tabCompany"):
|
||||||
frappe.get_doc("Company", company[0]).save()
|
company = frappe.get_doc("Company", company[0])
|
||||||
|
company.flags.ignore_permissions = True
|
||||||
|
company.save()
|
||||||
|
|
||||||
# Create account head for warehouses
|
# Create account head for warehouses
|
||||||
warehouse_list = frappe.db.sql("select name, company from tabWarehouse", as_dict=1)
|
warehouse_list = frappe.db.sql("select name, company from tabWarehouse", as_dict=1)
|
||||||
@ -25,4 +27,5 @@ class AccountsSettings(Document):
|
|||||||
frappe.throw(_("Company is missing in warehouses {0}").format(comma_and(warehouse_with_no_company)))
|
frappe.throw(_("Company is missing in warehouses {0}").format(comma_and(warehouse_with_no_company)))
|
||||||
for wh in warehouse_list:
|
for wh in warehouse_list:
|
||||||
wh_doc = frappe.get_doc("Warehouse", wh.name)
|
wh_doc = frappe.get_doc("Warehouse", wh.name)
|
||||||
|
wh_doc.flags.ignore_permissions = True
|
||||||
wh_doc.save()
|
wh_doc.save()
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"description": "Track separate Income and Expense for product verticals or divisions.",
|
"description": "Track separate Income and Expense for product verticals or divisions.",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -298,7 +298,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:55.020690",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Cost Center",
|
"name": "Cost Center",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"description": "**Fiscal Year** represents a Financial Year. All accounting entries and other major transactions are tracked against **Fiscal Year**.",
|
"description": "**Fiscal Year** represents a Financial Year. All accounting entries and other major transactions are tracked against **Fiscal Year**.",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -133,7 +133,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:56.280252",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Fiscal Year",
|
"name": "Fiscal Year",
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -39,7 +39,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2014-10-02 13:35:44.155278",
|
"modified": "2015-09-14 02:55:56.368682",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Fiscal Year Company",
|
"name": "Fiscal Year Company",
|
||||||
|
@ -156,7 +156,7 @@
|
|||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Debit Amt",
|
"label": "Debit Amount",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"oldfieldname": "debit",
|
"oldfieldname": "debit",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
@ -180,7 +180,7 @@
|
|||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Credit Amt",
|
"label": "Credit Amount",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"oldfieldname": "credit",
|
"oldfieldname": "credit",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
@ -194,6 +194,75 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"fieldname": "account_currency",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"label": "Account Currency",
|
||||||
|
"no_copy": 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,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -442,7 +511,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-11 15:51:26",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "GL Entry",
|
"name": "GL Entry",
|
||||||
|
@ -10,6 +10,8 @@ from frappe import _
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
class CustomerFrozen(frappe.ValidationError): pass
|
class CustomerFrozen(frappe.ValidationError): pass
|
||||||
|
class InvalidCurrency(frappe.ValidationError): pass
|
||||||
|
class InvalidAccountCurrency(frappe.ValidationError): pass
|
||||||
|
|
||||||
class GLEntry(Document):
|
class GLEntry(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@ -20,6 +22,7 @@ class GLEntry(Document):
|
|||||||
self.check_pl_account()
|
self.check_pl_account()
|
||||||
self.validate_cost_center()
|
self.validate_cost_center()
|
||||||
self.validate_party()
|
self.validate_party()
|
||||||
|
self.validate_currency()
|
||||||
|
|
||||||
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'):
|
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'):
|
||||||
self.validate_account_details(adv_adj)
|
self.validate_account_details(adv_adj)
|
||||||
@ -99,6 +102,25 @@ class GLEntry(Document):
|
|||||||
if frappe.db.get_value(self.party_type, self.party, "is_frozen"):
|
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)
|
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):
|
def validate_balance_type(account, adv_adj=False):
|
||||||
if not adv_adj and account:
|
if not adv_adj and account:
|
||||||
balance_must_be = frappe.db.get_value("Account", account, "balance_must_be")
|
balance_must_be = frappe.db.get_value("Account", account, "balance_must_be")
|
||||||
@ -131,7 +153,8 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
|
|||||||
party_condition = ""
|
party_condition = ""
|
||||||
|
|
||||||
# get final outstanding amt
|
# get final outstanding amt
|
||||||
bal = flt(frappe.db.sql("""select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
|
bal = flt(frappe.db.sql("""
|
||||||
|
select sum(ifnull(debit_in_account_currency, 0)) - sum(ifnull(credit_in_account_currency, 0))
|
||||||
from `tabGL Entry`
|
from `tabGL Entry`
|
||||||
where against_voucher_type=%s and against_voucher=%s
|
where against_voucher_type=%s and against_voucher=%s
|
||||||
and account = %s {0}""".format(party_condition),
|
and account = %s {0}""".format(party_condition),
|
||||||
@ -141,7 +164,7 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
|
|||||||
bal = -bal
|
bal = -bal
|
||||||
elif against_voucher_type == "Journal Entry":
|
elif against_voucher_type == "Journal Entry":
|
||||||
against_voucher_amount = flt(frappe.db.sql("""
|
against_voucher_amount = flt(frappe.db.sql("""
|
||||||
select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
|
select sum(ifnull(debit_in_account_currency, 0)) - sum(ifnull(credit_in_account_currency, 0))
|
||||||
from `tabGL Entry` where voucher_type = 'Journal Entry' and voucher_no = %s
|
from `tabGL Entry` where voucher_type = 'Journal Entry' and voucher_no = %s
|
||||||
and account = %s and ifnull(against_voucher, '') = '' {0}"""
|
and account = %s and ifnull(against_voucher, '') = '' {0}"""
|
||||||
.format(party_condition), (against_voucher, account))[0][0])
|
.format(party_condition), (against_voucher, account))[0][0])
|
||||||
|
@ -11,7 +11,7 @@ class TestGLEntry(unittest.TestCase):
|
|||||||
frappe.db.set_value("Company", "_Test Company", "round_off_cost_center", "_Test Cost Center - _TC")
|
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",
|
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.get("accounts")[0].debit = 100.01
|
||||||
jv.flags.ignore_validate = True
|
jv.flags.ignore_validate = True
|
||||||
|
@ -2,8 +2,54 @@
|
|||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
frappe.provide("erpnext.accounts");
|
frappe.provide("erpnext.accounts");
|
||||||
|
frappe.provide("erpnext.journal_entry");
|
||||||
frappe.require("assets/erpnext/js/utils.js");
|
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);
|
||||||
|
},
|
||||||
|
|
||||||
|
multi_currency: function(frm) {
|
||||||
|
erpnext.journal_entry.toggle_fields_based_on_currency(frm);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
erpnext.journal_entry.toggle_fields_based_on_currency = function(frm) {
|
||||||
|
var fields = ["currency_section", "account_currency", "exchange_rate", "debit", "credit"];
|
||||||
|
|
||||||
|
var grid = frm.get_field("accounts").grid;
|
||||||
|
if(grid) grid.set_column_disp(fields, frm.doc.multi_currency);
|
||||||
|
|
||||||
|
// dynamic label
|
||||||
|
var field_label_map = {
|
||||||
|
"debit_in_account_currency": "Debit",
|
||||||
|
"credit_in_account_currency": "Credit"
|
||||||
|
};
|
||||||
|
|
||||||
|
$.each(field_label_map, function (fieldname, label) {
|
||||||
|
var df = frappe.meta.get_docfield("Journal Entry Account", fieldname, frm.doc.name);
|
||||||
|
df.label = frm.doc.multi_currency ? (label + " in Account Currency") : label;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
||||||
onload: function() {
|
onload: function() {
|
||||||
this.load_defaults();
|
this.load_defaults();
|
||||||
@ -30,9 +76,20 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
|||||||
setup_queries: function() {
|
setup_queries: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
|
|
||||||
$.each(["account", "cost_center"], function(i, fieldname) {
|
me.frm.set_query("account", "accounts", function(doc, cdt, cdn) {
|
||||||
me.frm.set_query(fieldname, "accounts", function() {
|
var filters = {
|
||||||
frappe.model.validate_missing(me.frm.doc, "company");
|
company: me.frm.doc.company,
|
||||||
|
is_group: 0
|
||||||
|
};
|
||||||
|
if(!doc.multi_currency) {
|
||||||
|
$.extend(filters, {
|
||||||
|
account_currency: frappe.get_doc(":Company", me.frm.doc.company).default_currency
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return { filters: filters };
|
||||||
|
});
|
||||||
|
|
||||||
|
me.frm.set_query("cost_center", "accounts", function(doc, cdt, cdn) {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
company: me.frm.doc.company,
|
company: me.frm.doc.company,
|
||||||
@ -40,7 +97,6 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
me.frm.set_query("party_type", "accounts", function(doc, cdt, cdn) {
|
me.frm.set_query("party_type", "accounts", function(doc, cdt, cdn) {
|
||||||
return {
|
return {
|
||||||
@ -118,32 +174,39 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
|||||||
|
|
||||||
reference_name: function(doc, cdt, cdn) {
|
reference_name: function(doc, cdt, cdn) {
|
||||||
var d = frappe.get_doc(cdt, cdn);
|
var d = frappe.get_doc(cdt, cdn);
|
||||||
|
if(d.reference_name) {
|
||||||
if (d.reference_type==="Purchase Invoice" && !flt(d.debit)) {
|
if (d.reference_type==="Purchase Invoice" && !flt(d.debit)) {
|
||||||
this.get_outstanding('Purchase Invoice', d.reference_name, d);
|
this.get_outstanding('Purchase Invoice', d.reference_name, doc.company, d);
|
||||||
}
|
}
|
||||||
if (d.reference_type==="Sales Invoice" && !flt(d.credit)) {
|
if (d.reference_type==="Sales Invoice" && !flt(d.credit)) {
|
||||||
this.get_outstanding('Sales Invoice', d.reference_name, d);
|
this.get_outstanding('Sales Invoice', d.reference_name, doc.company, d);
|
||||||
}
|
}
|
||||||
if (d.reference_type==="Journal Entry" && !flt(d.credit) && !flt(d.debit)) {
|
if (d.reference_type==="Journal Entry" && !flt(d.credit) && !flt(d.debit)) {
|
||||||
this.get_outstanding('Journal Entry', d.reference_name, d);
|
this.get_outstanding('Journal Entry', d.reference_name, doc.company, d);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
get_outstanding: function(doctype, docname, child) {
|
get_outstanding: function(doctype, docname, company, child) {
|
||||||
var me = this;
|
var me = this;
|
||||||
var args = {
|
var args = {
|
||||||
"doctype": doctype,
|
"doctype": doctype,
|
||||||
"docname": docname,
|
"docname": docname,
|
||||||
"party": child.party,
|
"party": child.party,
|
||||||
"account": child.account
|
"account": child.account,
|
||||||
|
"account_currency": child.account_currency,
|
||||||
|
"company": company
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.frm.call({
|
return frappe.call({
|
||||||
child: child,
|
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_outstanding",
|
||||||
method: "get_outstanding",
|
|
||||||
args: { args: args},
|
args: { args: args},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
cur_frm.cscript.update_totals(me.frm.doc);
|
if(r.message) {
|
||||||
|
$.each(r.message, function(field, value) {
|
||||||
|
frappe.model.set_value(child.doctype, child.name, field, value);
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -161,35 +224,20 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
|||||||
// set difference
|
// set difference
|
||||||
if(doc.difference) {
|
if(doc.difference) {
|
||||||
if(doc.difference > 0) {
|
if(doc.difference > 0) {
|
||||||
|
row.credit_in_account_currency = doc.difference;
|
||||||
row.credit = doc.difference;
|
row.credit = doc.difference;
|
||||||
} else {
|
} else {
|
||||||
|
row.debit_in_account_currency = -doc.difference;
|
||||||
row.debit = -doc.difference;
|
row.debit = -doc.difference;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cur_frm.cscript.update_totals(doc);
|
||||||
},
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
cur_frm.script_manager.make(erpnext.accounts.JournalEntry);
|
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.cscript.company = function(doc, cdt, cdn) {
|
||||||
cur_frm.refresh_fields();
|
cur_frm.refresh_fields();
|
||||||
erpnext.get_fiscal_year(doc.company, doc.posting_date);
|
erpnext.get_fiscal_year(doc.company, doc.posting_date);
|
||||||
@ -201,10 +249,10 @@ cur_frm.cscript.posting_date = function(doc, cdt, cdn){
|
|||||||
|
|
||||||
cur_frm.cscript.update_totals = function(doc) {
|
cur_frm.cscript.update_totals = function(doc) {
|
||||||
var td=0.0; var tc =0.0;
|
var td=0.0; var tc =0.0;
|
||||||
var el = doc.accounts || [];
|
var accounts = doc.accounts || [];
|
||||||
for(var i in el) {
|
for(var i in accounts) {
|
||||||
td += flt(el[i].debit, precision("debit", el[i]));
|
td += flt(accounts[i].debit, precision("debit", accounts[i]));
|
||||||
tc += flt(el[i].credit, precision("credit", el[i]));
|
tc += flt(accounts[i].credit, precision("credit", accounts[i]));
|
||||||
}
|
}
|
||||||
var doc = locals[doc.doctype][doc.name];
|
var doc = locals[doc.doctype][doc.name];
|
||||||
doc.total_debit = td;
|
doc.total_debit = td;
|
||||||
@ -213,32 +261,12 @@ cur_frm.cscript.update_totals = function(doc) {
|
|||||||
refresh_many(['total_debit','total_credit','difference']);
|
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.get_balance = function(doc,dt,dn) {
|
||||||
cur_frm.cscript.update_totals(doc);
|
cur_frm.cscript.update_totals(doc);
|
||||||
return $c_obj(cur_frm.doc, 'get_balance', '', function(r, rt){
|
return $c_obj(cur_frm.doc, 'get_balance', '', function(r, rt){
|
||||||
cur_frm.refresh();
|
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.validate = function(doc,cdt,cdn) {
|
||||||
cur_frm.cscript.update_totals(doc);
|
cur_frm.cscript.update_totals(doc);
|
||||||
@ -303,7 +331,8 @@ cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
frappe.ui.form.on("Journal Entry Account", "party", function(frm, cdt, cdn) {
|
frappe.ui.form.on("Journal Entry Account", {
|
||||||
|
party: function(frm, cdt, cdn) {
|
||||||
var d = frappe.get_doc(cdt, cdn);
|
var d = frappe.get_doc(cdt, cdn);
|
||||||
if(!d.account && d.party_type && d.party) {
|
if(!d.account && d.party_type && d.party) {
|
||||||
return frm.call({
|
return frm.call({
|
||||||
@ -316,9 +345,91 @@ frappe.ui.form.on("Journal Entry Account", "party", function(frm, cdt, cdn) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
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,
|
||||||
|
debit: flt(d.debit_in_account_currency),
|
||||||
|
credit: flt(d.credit_in_account_currency),
|
||||||
|
exchange_rate: d.exchange_rate
|
||||||
|
},
|
||||||
|
callback: function(r) {
|
||||||
|
if(r.message) {
|
||||||
|
$.extend(d, r.message);
|
||||||
|
refresh_field('accounts');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
debit_in_account_currency: function(frm, cdt, cdn) {
|
||||||
|
erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn);
|
||||||
|
},
|
||||||
|
|
||||||
|
credit_in_account_currency: function(frm, cdt, cdn) {
|
||||||
|
erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn);
|
||||||
|
},
|
||||||
|
|
||||||
|
debit: function(frm, dt, dn) {
|
||||||
|
cur_frm.cscript.update_totals(frm.doc);
|
||||||
|
},
|
||||||
|
|
||||||
|
credit: function(frm, dt, dn) {
|
||||||
|
cur_frm.cscript.update_totals(frm.doc);
|
||||||
|
},
|
||||||
|
|
||||||
|
exchange_rate: function(frm, cdt, cdn) {
|
||||||
|
erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
frappe.ui.form.on("Journal Entry Account", "accounts_remove", function(frm) {
|
frappe.ui.form.on("Journal Entry Account", "accounts_remove", function(frm) {
|
||||||
cur_frm.cscript.update_totals(frm.doc);
|
cur_frm.cscript.update_totals(frm.doc);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
erpnext.journal_entry.set_debit_credit_in_company_currency = function(frm, cdt, cdn) {
|
||||||
|
erpnext.journal_entry.set_exchange_rate(frm, cdt, cdn);
|
||||||
|
|
||||||
|
var row = locals[cdt][cdn];
|
||||||
|
|
||||||
|
frappe.model.set_value(cdt, cdn, "debit",
|
||||||
|
flt(flt(row.debit_in_account_currency)*row.exchange_rate), precision("debit", row));
|
||||||
|
frappe.model.set_value(cdt, cdn, "credit",
|
||||||
|
flt(flt(row.credit_in_account_currency)*row.exchange_rate), precision("credit", row));
|
||||||
|
}
|
||||||
|
|
||||||
|
erpnext.journal_entry.set_exchange_rate = function(frm, cdt, cdn) {
|
||||||
|
var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
|
||||||
|
var row = locals[cdt][cdn];
|
||||||
|
|
||||||
|
if(row.account_currency == company_currency || !frm.doc.multi_currency) {
|
||||||
|
frappe.model.set_value(cdt, cdn, "exchange_rate", 1);
|
||||||
|
} else if (!row.exchange_rate || row.account_type == "Bank") {
|
||||||
|
frappe.call({
|
||||||
|
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_exchange_rate",
|
||||||
|
args: {
|
||||||
|
account: row.account,
|
||||||
|
account_currency: row.account_currency,
|
||||||
|
company: frm.doc.company,
|
||||||
|
reference_type: cstr(row.reference_type),
|
||||||
|
reference_name: cstr(row.reference_name),
|
||||||
|
debit: flt(row.debit_in_account_currency),
|
||||||
|
credit: flt(row.credit_in_account_currency),
|
||||||
|
exchange_rate: row.exchange_rate
|
||||||
|
},
|
||||||
|
callback: function(r) {
|
||||||
|
if(r.message) {
|
||||||
|
frappe.model.set_value(cdt, cdn, "exchange_rate", r.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -42,7 +42,7 @@
|
|||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Title",
|
"label": "Title",
|
||||||
"no_copy": 0,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -400,6 +400,28 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"fieldname": "multi_currency",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"label": "Multi Currency",
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -1002,7 +1024,7 @@
|
|||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-11 12:21:50.635624",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Journal Entry",
|
"name": "Journal Entry",
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
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 frappe import msgprint, _, scrub
|
||||||
from erpnext.setup.utils import get_company_currency
|
|
||||||
from erpnext.controllers.accounts_controller import AccountsController
|
from erpnext.controllers.accounts_controller import AccountsController
|
||||||
from erpnext.accounts.utils import get_balance_on
|
from erpnext.accounts.utils import get_balance_on
|
||||||
|
from erpnext.setup.utils import get_company_currency
|
||||||
|
|
||||||
|
|
||||||
class JournalEntry(AccountsController):
|
class JournalEntry(AccountsController):
|
||||||
@ -26,6 +26,7 @@ class JournalEntry(AccountsController):
|
|||||||
self.validate_party()
|
self.validate_party()
|
||||||
self.validate_cheque_info()
|
self.validate_cheque_info()
|
||||||
self.validate_entries_for_advance()
|
self.validate_entries_for_advance()
|
||||||
|
self.validate_multi_currency()
|
||||||
self.validate_debit_and_credit()
|
self.validate_debit_and_credit()
|
||||||
self.validate_against_jv()
|
self.validate_against_jv()
|
||||||
self.validate_reference_doc()
|
self.validate_reference_doc()
|
||||||
@ -35,6 +36,7 @@ class JournalEntry(AccountsController):
|
|||||||
self.validate_expense_claim()
|
self.validate_expense_claim()
|
||||||
self.validate_credit_debit_note()
|
self.validate_credit_debit_note()
|
||||||
self.validate_empty_accounts_table()
|
self.validate_empty_accounts_table()
|
||||||
|
self.set_account_and_party_balance()
|
||||||
self.set_title()
|
self.set_title()
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
@ -144,6 +146,7 @@ class JournalEntry(AccountsController):
|
|||||||
|
|
||||||
self.reference_totals = {}
|
self.reference_totals = {}
|
||||||
self.reference_types = {}
|
self.reference_types = {}
|
||||||
|
self.reference_parties = {}
|
||||||
|
|
||||||
for d in self.get("accounts"):
|
for d in self.get("accounts"):
|
||||||
if not d.reference_type:
|
if not d.reference_type:
|
||||||
@ -151,8 +154,8 @@ class JournalEntry(AccountsController):
|
|||||||
if not d.reference_name:
|
if not d.reference_name:
|
||||||
d.reference_type = None
|
d.reference_type = None
|
||||||
if d.reference_type and d.reference_name and (d.reference_type in field_dict.keys()):
|
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") \
|
dr_or_cr = "credit_in_account_currency" \
|
||||||
else "debit"
|
if d.reference_type in ("Sales Order", "Sales Invoice") else "debit_in_account_currency"
|
||||||
|
|
||||||
# check debit or credit type Sales / Purchase Order
|
# check debit or credit type Sales / Purchase Order
|
||||||
if d.reference_type=="Sales Order" and flt(d.debit) > 0:
|
if d.reference_type=="Sales Order" and flt(d.debit) > 0:
|
||||||
@ -166,6 +169,8 @@ class JournalEntry(AccountsController):
|
|||||||
self.reference_totals[d.reference_name] = 0.0
|
self.reference_totals[d.reference_name] = 0.0
|
||||||
self.reference_totals[d.reference_name] += flt(d.get(dr_or_cr))
|
self.reference_totals[d.reference_name] += flt(d.get(dr_or_cr))
|
||||||
self.reference_types[d.reference_name] = d.reference_type
|
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,
|
against_voucher = frappe.db.get_value(d.reference_type, d.reference_name,
|
||||||
[scrub(dt) for dt in field_dict.get(d.reference_type)])
|
[scrub(dt) for dt in field_dict.get(d.reference_type)])
|
||||||
@ -191,23 +196,31 @@ class JournalEntry(AccountsController):
|
|||||||
"""Validate totals, stopped and docstatus for orders"""
|
"""Validate totals, stopped and docstatus for orders"""
|
||||||
for reference_name, total in self.reference_totals.iteritems():
|
for reference_name, total in self.reference_totals.iteritems():
|
||||||
reference_type = self.reference_types[reference_name]
|
reference_type = self.reference_types[reference_name]
|
||||||
|
party_type, party = self.reference_parties.get(reference_name)
|
||||||
|
|
||||||
if reference_type in ("Sales Order", "Purchase Order"):
|
if reference_type in ("Sales Order", "Purchase Order"):
|
||||||
voucher_properties = frappe.db.get_value(reference_type, reference_name,
|
order = frappe.db.get_value(reference_type, reference_name,
|
||||||
["docstatus", "per_billed", "status", "advance_paid", "base_grand_total"])
|
["docstatus", "per_billed", "status", "advance_paid",
|
||||||
|
"base_grand_total", "grand_total", "currency"], as_dict=1)
|
||||||
|
|
||||||
if voucher_properties[0] != 1:
|
if order.docstatus != 1:
|
||||||
frappe.throw(_("{0} {1} is not submitted").format(reference_type, reference_name))
|
frappe.throw(_("{0} {1} is not submitted").format(reference_type, reference_name))
|
||||||
|
|
||||||
if flt(voucher_properties[1]) >= 100:
|
if flt(order.per_billed) >= 100:
|
||||||
frappe.throw(_("{0} {1} is fully billed").format(reference_type, reference_name))
|
frappe.throw(_("{0} {1} is fully billed").format(reference_type, reference_name))
|
||||||
|
|
||||||
if cstr(voucher_properties[2]) == "Stopped":
|
if cstr(order.status) == "Stopped":
|
||||||
frappe.throw(_("{0} {1} is stopped").format(reference_type, reference_name))
|
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 = order.base_grand_total
|
||||||
|
else:
|
||||||
|
voucher_total = order.grand_total
|
||||||
|
|
||||||
|
if flt(voucher_total) < (flt(order.advance_paid) + total):
|
||||||
frappe.throw(_("Advance paid against {0} {1} cannot be greater \
|
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):
|
def validate_invoices(self):
|
||||||
"""Validate totals and docstatus for invoices"""
|
"""Validate totals and docstatus for invoices"""
|
||||||
@ -215,15 +228,15 @@ class JournalEntry(AccountsController):
|
|||||||
reference_type = self.reference_types[reference_name]
|
reference_type = self.reference_types[reference_name]
|
||||||
|
|
||||||
if reference_type in ("Sales Invoice", "Purchase Invoice"):
|
if reference_type in ("Sales Invoice", "Purchase Invoice"):
|
||||||
voucher_properties = frappe.db.get_value(reference_type, reference_name,
|
invoice = frappe.db.get_value(reference_type, reference_name,
|
||||||
["docstatus", "outstanding_amount"])
|
["docstatus", "outstanding_amount"], as_dict=1)
|
||||||
|
|
||||||
if voucher_properties[0] != 1:
|
if invoice.docstatus != 1:
|
||||||
frappe.throw(_("{0} {1} is not submitted").format(reference_type, reference_name))
|
frappe.throw(_("{0} {1} is not submitted").format(reference_type, reference_name))
|
||||||
|
|
||||||
if total and flt(voucher_properties[1]) < total:
|
if total and flt(invoice.outstanding_amount) < total:
|
||||||
frappe.throw(_("Payment against {0} {1} cannot be greater \
|
frappe.throw(_("Payment against {0} {1} cannot be greater than Outstanding Amount {2}")
|
||||||
than Outstanding Amount {2}").format(reference_type, reference_name, voucher_properties[1]))
|
.format(reference_type, reference_name, invoice.outstanding_amount))
|
||||||
|
|
||||||
def set_against_account(self):
|
def set_against_account(self):
|
||||||
accounts_debited, accounts_credited = [], []
|
accounts_debited, accounts_credited = [], []
|
||||||
@ -237,13 +250,12 @@ class JournalEntry(AccountsController):
|
|||||||
|
|
||||||
def validate_debit_and_credit(self):
|
def validate_debit_and_credit(self):
|
||||||
self.total_debit, self.total_credit, self.difference = 0, 0, 0
|
self.total_debit, self.total_credit, self.difference = 0, 0, 0
|
||||||
|
|
||||||
for d in self.get("accounts"):
|
for d in self.get("accounts"):
|
||||||
if d.debit and d.credit:
|
if d.debit and d.credit:
|
||||||
frappe.throw(_("You cannot credit and debit same account at the same time"))
|
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_debit = flt(self.total_debit) + flt(d.debit, d.precision("debit"))
|
||||||
self.total_credit = flt(self.total_credit) + flt(d.credit, self.precision("credit", "accounts"))
|
self.total_credit = flt(self.total_credit) + flt(d.credit, d.precision("credit"))
|
||||||
|
|
||||||
self.difference = flt(self.total_debit, self.precision("total_debit")) - \
|
self.difference = flt(self.total_debit, self.precision("total_debit")) - \
|
||||||
flt(self.total_credit, self.precision("total_credit"))
|
flt(self.total_credit, self.precision("total_credit"))
|
||||||
@ -252,6 +264,41 @@ class JournalEntry(AccountsController):
|
|||||||
frappe.throw(_("Total Debit must be equal to Total Credit. The difference is {0}")
|
frappe.throw(_("Total Debit must be equal to Total Credit. The difference is {0}")
|
||||||
.format(self.difference))
|
.format(self.difference))
|
||||||
|
|
||||||
|
def validate_multi_currency(self):
|
||||||
|
alternate_currency = []
|
||||||
|
for d in self.get("accounts"):
|
||||||
|
account = frappe.db.get_value("Account", d.account, ["account_currency", "account_type"], as_dict=1)
|
||||||
|
d.account_currency = account.account_currency or self.company_currency
|
||||||
|
d.account_type = account.account_type
|
||||||
|
|
||||||
|
if d.account_currency!=self.company_currency and d.account_currency not in alternate_currency:
|
||||||
|
alternate_currency.append(d.account_currency)
|
||||||
|
|
||||||
|
if alternate_currency:
|
||||||
|
if not self.multi_currency:
|
||||||
|
frappe.throw(_("Please check Multi Currency option to allow accounts with other currency"))
|
||||||
|
|
||||||
|
if len(alternate_currency) > 1:
|
||||||
|
frappe.throw(_("Only one alternate currency can be used in a single Journal Entry"))
|
||||||
|
|
||||||
|
self.set_exchange_rate()
|
||||||
|
|
||||||
|
for d in self.get("accounts"):
|
||||||
|
d.debit = flt(flt(d.debit_in_account_currency)*flt(d.exchange_rate), d.precision("debit"))
|
||||||
|
d.credit = flt(flt(d.credit_in_account_currency)*flt(d.exchange_rate), d.precision("credit"))
|
||||||
|
|
||||||
|
def set_exchange_rate(self):
|
||||||
|
for d in self.get("accounts"):
|
||||||
|
if d.account_currency == self.company_currency:
|
||||||
|
d.exchange_rate = 1
|
||||||
|
elif not d.exchange_rate or d.account_type=="Bank" or \
|
||||||
|
(d.reference_type in ("Sales Invoice", "Purchase Invoice") and d.reference_name):
|
||||||
|
d.exchange_rate = get_exchange_rate(d.account, d.account_currency, self.company,
|
||||||
|
d.reference_type, d.reference_name, d.debit, d.credit, d.exchange_rate)
|
||||||
|
|
||||||
|
if not d.exchange_rate:
|
||||||
|
frappe.throw(_("Row {0}: Exchange Rate is mandatory").format(d.idx))
|
||||||
|
|
||||||
def create_remarks(self):
|
def create_remarks(self):
|
||||||
r = []
|
r = []
|
||||||
if self.cheque_no:
|
if self.cheque_no:
|
||||||
@ -260,15 +307,13 @@ class JournalEntry(AccountsController):
|
|||||||
else:
|
else:
|
||||||
msgprint(_("Please enter Reference date"), raise_exception=frappe.MandatoryError)
|
msgprint(_("Please enter Reference date"), raise_exception=frappe.MandatoryError)
|
||||||
|
|
||||||
company_currency = get_company_currency(self.company)
|
|
||||||
|
|
||||||
for d in self.get('accounts'):
|
for d in self.get('accounts'):
|
||||||
if d.reference_type=="Sales Invoice" and d.credit:
|
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))
|
d.reference_name))
|
||||||
|
|
||||||
if d.reference_type=="Sales Order" and d.credit:
|
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))
|
d.reference_name))
|
||||||
|
|
||||||
if d.reference_type == "Purchase Invoice" and d.debit:
|
if d.reference_type == "Purchase Invoice" and d.debit:
|
||||||
@ -276,11 +321,11 @@ class JournalEntry(AccountsController):
|
|||||||
from `tabPurchase Invoice` where name=%s""", d.reference_name)
|
from `tabPurchase Invoice` where name=%s""", d.reference_name)
|
||||||
if bill_no and bill_no[0][0] and bill_no[0][0].lower().strip() \
|
if bill_no and bill_no[0][0] and bill_no[0][0].lower().strip() \
|
||||||
not in ['na', 'not applicable', 'none']:
|
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'))))
|
bill_no[0][1] and formatdate(bill_no[0][1].strftime('%Y-%m-%d'))))
|
||||||
|
|
||||||
if d.reference_type == "Purchase Order" and d.debit:
|
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))
|
d.reference_name))
|
||||||
|
|
||||||
if self.user_remark:
|
if self.user_remark:
|
||||||
@ -301,10 +346,9 @@ class JournalEntry(AccountsController):
|
|||||||
self.set_total_amount(d.debit or d.credit)
|
self.set_total_amount(d.debit or d.credit)
|
||||||
|
|
||||||
def set_total_amount(self, amt):
|
def set_total_amount(self, amt):
|
||||||
company_currency = get_company_currency(self.company)
|
|
||||||
self.total_amount = amt
|
self.total_amount = amt
|
||||||
from frappe.utils import money_in_words
|
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):
|
def make_gl_entries(self, cancel=0, adv_adj=0):
|
||||||
from erpnext.accounts.general_ledger import make_gl_entries
|
from erpnext.accounts.general_ledger import make_gl_entries
|
||||||
@ -318,8 +362,11 @@ class JournalEntry(AccountsController):
|
|||||||
"party_type": d.party_type,
|
"party_type": d.party_type,
|
||||||
"party": d.party,
|
"party": d.party,
|
||||||
"against": d.against_account,
|
"against": d.against_account,
|
||||||
"debit": flt(d.debit, self.precision("debit", "accounts")),
|
"debit": flt(d.debit, d.precision("debit")),
|
||||||
"credit": flt(d.credit, self.precision("credit", "accounts")),
|
"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_type": d.reference_type,
|
||||||
"against_voucher": d.reference_name,
|
"against_voucher": d.reference_name,
|
||||||
"remarks": self.remark,
|
"remarks": self.remark,
|
||||||
@ -338,21 +385,21 @@ class JournalEntry(AccountsController):
|
|||||||
diff = flt(self.difference, self.precision("difference"))
|
diff = flt(self.difference, self.precision("difference"))
|
||||||
|
|
||||||
# If any row without amount, set the diff on that row
|
# If any row without amount, set the diff on that row
|
||||||
|
if diff:
|
||||||
for d in self.get('accounts'):
|
for d in self.get('accounts'):
|
||||||
if not d.credit and not d.debit and diff != 0:
|
if not d.credit_in_account_currency and not d.debit_in_account_currency and diff != 0:
|
||||||
if diff>0:
|
blank_row = d
|
||||||
d.credit = diff
|
|
||||||
elif diff<0:
|
|
||||||
d.debit = diff
|
|
||||||
flag = 1
|
|
||||||
|
|
||||||
# Set the diff in a new row
|
if not blank_row:
|
||||||
if flag == 0 and diff != 0:
|
blank_row = self.append('accounts', {})
|
||||||
jd = self.append('accounts', {})
|
|
||||||
|
blank_row.exchange_rate = 1
|
||||||
if diff>0:
|
if diff>0:
|
||||||
jd.credit = abs(diff)
|
blank_row.credit_in_account_currency = diff
|
||||||
|
blank_row.credit = diff
|
||||||
elif diff<0:
|
elif diff<0:
|
||||||
jd.debit = abs(diff)
|
blank_row.debit_in_account_currency = abs(diff)
|
||||||
|
blank_row.debit = abs(diff)
|
||||||
|
|
||||||
self.validate_debit_and_credit()
|
self.validate_debit_and_credit()
|
||||||
|
|
||||||
@ -427,6 +474,11 @@ class JournalEntry(AccountsController):
|
|||||||
if not self.get('accounts'):
|
if not self.get('accounts'):
|
||||||
frappe.throw("Accounts table cannot be blank.")
|
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()
|
@frappe.whitelist()
|
||||||
def get_default_bank_cash_account(company, voucher_type, mode_of_payment=None):
|
def get_default_bank_cash_account(company, voucher_type, mode_of_payment=None):
|
||||||
from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
|
from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
|
||||||
@ -446,9 +498,12 @@ def get_default_bank_cash_account(company, voucher_type, mode_of_payment=None):
|
|||||||
account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash", "is_group": 0})
|
account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash", "is_group": 0})
|
||||||
|
|
||||||
if account:
|
if account:
|
||||||
|
account_details = frappe.db.get_value("Account", account, ["account_currency", "account_type"], as_dict=1)
|
||||||
return {
|
return {
|
||||||
"account": account,
|
"account": account,
|
||||||
"balance": get_balance_on(account)
|
"balance": get_balance_on(account),
|
||||||
|
"account_currency": account_details.account_currency,
|
||||||
|
"account_type": account_details.account_type
|
||||||
}
|
}
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@ -456,21 +511,38 @@ def get_payment_entry_from_sales_invoice(sales_invoice):
|
|||||||
"""Returns new Journal Entry document as dict for given Sales Invoice"""
|
"""Returns new Journal Entry document as dict for given Sales Invoice"""
|
||||||
from erpnext.accounts.utils import get_balance_on
|
from erpnext.accounts.utils import get_balance_on
|
||||||
si = frappe.get_doc("Sales Invoice", sales_invoice)
|
si = frappe.get_doc("Sales Invoice", sales_invoice)
|
||||||
|
|
||||||
|
# exchange rate
|
||||||
|
exchange_rate = get_exchange_rate(si.debit_to, si.party_account_currency, si.company,
|
||||||
|
si.doctype, si.name)
|
||||||
|
|
||||||
jv = get_payment_entry(si)
|
jv = get_payment_entry(si)
|
||||||
jv.remark = 'Payment received against Sales Invoice {0}. {1}'.format(si.name, si.remarks)
|
jv.remark = 'Payment received against Sales Invoice {0}. {1}'.format(si.name, si.remarks)
|
||||||
|
|
||||||
# credit customer
|
# credit customer
|
||||||
jv.get("accounts")[0].account = si.debit_to
|
row1 = jv.get("accounts")[0]
|
||||||
jv.get("accounts")[0].party_type = "Customer"
|
row1.account = si.debit_to
|
||||||
jv.get("accounts")[0].party = si.customer
|
row1.account_currency = si.party_account_currency
|
||||||
jv.get("accounts")[0].balance = get_balance_on(si.debit_to)
|
row1.party_type = "Customer"
|
||||||
jv.get("accounts")[0].party_balance = get_balance_on(party=si.customer, party_type="Customer")
|
row1.party = si.customer
|
||||||
jv.get("accounts")[0].credit = si.outstanding_amount
|
row1.balance = get_balance_on(si.debit_to)
|
||||||
jv.get("accounts")[0].reference_type = si.doctype
|
row1.party_balance = get_balance_on(party=si.customer, party_type="Customer")
|
||||||
jv.get("accounts")[0].reference_name = si.name
|
row1.credit_in_account_currency = si.outstanding_amount
|
||||||
|
row1.reference_type = si.doctype
|
||||||
|
row1.reference_name = si.name
|
||||||
|
row1.exchange_rate = exchange_rate
|
||||||
|
row1.account_type = "Receivable" if si.customer else ""
|
||||||
|
|
||||||
# debit bank
|
# debit bank
|
||||||
jv.get("accounts")[1].debit = si.outstanding_amount
|
row2 = jv.get("accounts")[1]
|
||||||
|
if row2.account_currency == si.party_account_currency:
|
||||||
|
row2.debit_in_account_currency = si.outstanding_amount
|
||||||
|
else:
|
||||||
|
row2.debit_in_account_currency = si.outstanding_amount * exchange_rate
|
||||||
|
|
||||||
|
# set multi currency check
|
||||||
|
if row1.account_currency != si.company_currency or row2.account_currency != si.company_currency:
|
||||||
|
jv.multi_currency = 1
|
||||||
|
|
||||||
return jv.as_dict()
|
return jv.as_dict()
|
||||||
|
|
||||||
@ -478,21 +550,38 @@ def get_payment_entry_from_sales_invoice(sales_invoice):
|
|||||||
def get_payment_entry_from_purchase_invoice(purchase_invoice):
|
def get_payment_entry_from_purchase_invoice(purchase_invoice):
|
||||||
"""Returns new Journal Entry document as dict for given Purchase Invoice"""
|
"""Returns new Journal Entry document as dict for given Purchase Invoice"""
|
||||||
pi = frappe.get_doc("Purchase Invoice", purchase_invoice)
|
pi = frappe.get_doc("Purchase Invoice", purchase_invoice)
|
||||||
|
|
||||||
|
exchange_rate = get_exchange_rate(pi.debit_to, pi.party_account_currency, pi.company,
|
||||||
|
pi.doctype, pi.name)
|
||||||
|
|
||||||
jv = get_payment_entry(pi)
|
jv = get_payment_entry(pi)
|
||||||
jv.remark = 'Payment against Purchase Invoice {0}. {1}'.format(pi.name, pi.remarks)
|
jv.remark = 'Payment against Purchase Invoice {0}. {1}'.format(pi.name, pi.remarks)
|
||||||
|
jv.exchange_rate = exchange_rate
|
||||||
|
|
||||||
# credit supplier
|
# credit supplier
|
||||||
jv.get("accounts")[0].account = pi.credit_to
|
row1 = jv.get("accounts")[0]
|
||||||
jv.get("accounts")[0].party_type = "Supplier"
|
row1.account = pi.credit_to
|
||||||
jv.get("accounts")[0].party = pi.supplier
|
row1.account_currency = pi.party_account_currency
|
||||||
jv.get("accounts")[0].balance = get_balance_on(pi.credit_to)
|
row1.party_type = "Supplier"
|
||||||
jv.get("accounts")[0].party_balance = get_balance_on(party=pi.supplier, party_type="Supplier")
|
row1.party = pi.supplier
|
||||||
jv.get("accounts")[0].debit = pi.outstanding_amount
|
row1.balance = get_balance_on(pi.credit_to)
|
||||||
jv.get("accounts")[0].reference_type = pi.doctype
|
row1.party_balance = get_balance_on(party=pi.supplier, party_type="Supplier")
|
||||||
jv.get("accounts")[0].reference_name = pi.name
|
row1.debit_in_account_currency = pi.outstanding_amount
|
||||||
|
row1.reference_type = pi.doctype
|
||||||
|
row1.reference_name = pi.name
|
||||||
|
row1.exchange_rate = exchange_rate
|
||||||
|
row1.account_type = "Payable" if pi.supplier else ""
|
||||||
|
|
||||||
# credit bank
|
# credit bank
|
||||||
jv.get("accounts")[1].credit = pi.outstanding_amount
|
row2 = jv.get("accounts")[1]
|
||||||
|
if row2.account_currency == pi.party_account_currency:
|
||||||
|
row2.credit_in_account_currency = pi.outstanding_amount
|
||||||
|
else:
|
||||||
|
row2.credit_in_account_currency = pi.outstanding_amount * exchange_rate
|
||||||
|
|
||||||
|
# set multi currency check
|
||||||
|
if row1.account_currency != pi.company_currency or row2.account_currency != pi.company_currency:
|
||||||
|
jv.multi_currency = 1
|
||||||
|
|
||||||
return jv.as_dict()
|
return jv.as_dict()
|
||||||
|
|
||||||
@ -501,6 +590,7 @@ def get_payment_entry_from_sales_order(sales_order):
|
|||||||
"""Returns new Journal Entry document as dict for given Sales Order"""
|
"""Returns new Journal Entry document as dict for given Sales Order"""
|
||||||
from erpnext.accounts.utils import get_balance_on
|
from erpnext.accounts.utils import get_balance_on
|
||||||
from erpnext.accounts.party import get_party_account
|
from erpnext.accounts.party import get_party_account
|
||||||
|
|
||||||
so = frappe.get_doc("Sales Order", sales_order)
|
so = frappe.get_doc("Sales Order", sales_order)
|
||||||
|
|
||||||
if flt(so.per_billed, 2) != 0.0:
|
if flt(so.per_billed, 2) != 0.0:
|
||||||
@ -508,23 +598,42 @@ def get_payment_entry_from_sales_order(sales_order):
|
|||||||
|
|
||||||
jv = get_payment_entry(so)
|
jv = get_payment_entry(so)
|
||||||
jv.remark = 'Advance payment received against Sales Order {0}.'.format(so.name)
|
jv.remark = 'Advance payment received against Sales Order {0}.'.format(so.name)
|
||||||
party_account = get_party_account(so.company, so.customer, "Customer")
|
|
||||||
|
|
||||||
|
party_account = get_party_account(so.company, so.customer, "Customer")
|
||||||
|
party_account_currency = frappe.db.get_value("Account", party_account, "account_currency")
|
||||||
|
|
||||||
|
exchange_rate = get_exchange_rate(party_account, party_account_currency, so.company)
|
||||||
|
|
||||||
|
if party_account_currency == so.company_currency:
|
||||||
amount = flt(so.base_grand_total) - flt(so.advance_paid)
|
amount = flt(so.base_grand_total) - flt(so.advance_paid)
|
||||||
|
else:
|
||||||
|
amount = flt(so.grand_total) - flt(so.advance_paid)
|
||||||
|
|
||||||
# credit customer
|
# credit customer
|
||||||
jv.get("accounts")[0].account = party_account
|
row1 = jv.get("accounts")[0]
|
||||||
jv.get("accounts")[0].party_type = "Customer"
|
row1.account = party_account
|
||||||
jv.get("accounts")[0].party = so.customer
|
row1.account_currency = party_account_currency
|
||||||
jv.get("accounts")[0].balance = get_balance_on(party_account)
|
row1.party_type = "Customer"
|
||||||
jv.get("accounts")[0].party_balance = get_balance_on(party=so.customer, party_type="Customer")
|
row1.party = so.customer
|
||||||
jv.get("accounts")[0].credit = amount
|
row1.balance = get_balance_on(party_account)
|
||||||
jv.get("accounts")[0].reference_type = so.doctype
|
row1.party_balance = get_balance_on(party=so.customer, party_type="Customer")
|
||||||
jv.get("accounts")[0].reference_name = so.name
|
row1.credit_in_account_currency = amount
|
||||||
jv.get("accounts")[0].is_advance = "Yes"
|
row1.reference_type = so.doctype
|
||||||
|
row1.reference_name = so.name
|
||||||
|
row1.is_advance = "Yes"
|
||||||
|
row1.exchange_rate = exchange_rate
|
||||||
|
row1.account_type = "Receivable"
|
||||||
|
|
||||||
# debit bank
|
# debit bank
|
||||||
jv.get("accounts")[1].debit = amount
|
row2 = jv.get("accounts")[1]
|
||||||
|
if row2.account_currency == party_account_currency:
|
||||||
|
row2.debit_in_account_currency = amount
|
||||||
|
else:
|
||||||
|
row2.debit_in_account_currency = amount * exchange_rate
|
||||||
|
|
||||||
|
# set multi currency check
|
||||||
|
if row1.account_currency != so.company_currency or row2.account_currency != so.company_currency:
|
||||||
|
jv.multi_currency = 1
|
||||||
|
|
||||||
return jv.as_dict()
|
return jv.as_dict()
|
||||||
|
|
||||||
@ -540,23 +649,41 @@ def get_payment_entry_from_purchase_order(purchase_order):
|
|||||||
|
|
||||||
jv = get_payment_entry(po)
|
jv = get_payment_entry(po)
|
||||||
jv.remark = 'Advance payment made against Purchase Order {0}.'.format(po.name)
|
jv.remark = 'Advance payment made against Purchase Order {0}.'.format(po.name)
|
||||||
party_account = get_party_account(po.company, po.supplier, "Supplier")
|
|
||||||
|
|
||||||
|
party_account = get_party_account(po.company, po.supplier, "Supplier")
|
||||||
|
party_account_currency = frappe.db.get_value("Account", party_account, "account_currency")
|
||||||
|
|
||||||
|
exchange_rate = get_exchange_rate(party_account, party_account_currency, po.company)
|
||||||
|
|
||||||
|
if party_account_currency == po.company_currency:
|
||||||
amount = flt(po.base_grand_total) - flt(po.advance_paid)
|
amount = flt(po.base_grand_total) - flt(po.advance_paid)
|
||||||
|
else:
|
||||||
|
amount = flt(po.grand_total) - flt(po.advance_paid)
|
||||||
|
|
||||||
# credit customer
|
# credit customer
|
||||||
jv.get("accounts")[0].account = party_account
|
row1 = jv.get("accounts")[0]
|
||||||
jv.get("accounts")[0].party_type = "Supplier"
|
row1.account = party_account
|
||||||
jv.get("accounts")[0].party = po.supplier
|
row1.party_type = "Supplier"
|
||||||
jv.get("accounts")[0].balance = get_balance_on(party_account)
|
row1.party = po.supplier
|
||||||
jv.get("accounts")[0].party_balance = get_balance_on(party=po.supplier, party_type="Supplier")
|
row1.balance = get_balance_on(party_account)
|
||||||
jv.get("accounts")[0].debit = amount
|
row1.party_balance = get_balance_on(party=po.supplier, party_type="Supplier")
|
||||||
jv.get("accounts")[0].reference_type = po.doctype
|
row1.debit_in_account_currency = amount
|
||||||
jv.get("accounts")[0].reference_name = po.name
|
row1.reference_type = po.doctype
|
||||||
jv.get("accounts")[0].is_advance = "Yes"
|
row1.reference_name = po.name
|
||||||
|
row1.is_advance = "Yes"
|
||||||
|
row1.exchange_rate = exchange_rate
|
||||||
|
row1.account_type = "Payable"
|
||||||
|
|
||||||
# debit bank
|
# debit bank
|
||||||
jv.get("accounts")[1].credit = amount
|
row2 = jv.get("accounts")[1]
|
||||||
|
if row2.account_currency == party_account_currency:
|
||||||
|
row2.credit_in_account_currency = amount
|
||||||
|
else:
|
||||||
|
row2.credit_in_account_currency = amount * exchange_rate
|
||||||
|
|
||||||
|
# set multi currency check
|
||||||
|
if row1.account_currency != po.company_currency or row2.account_currency != po.company_currency:
|
||||||
|
jv.multi_currency = 1
|
||||||
|
|
||||||
return jv.as_dict()
|
return jv.as_dict()
|
||||||
|
|
||||||
@ -574,6 +701,10 @@ def get_payment_entry(doc):
|
|||||||
if bank_account:
|
if bank_account:
|
||||||
d2.account = bank_account["account"]
|
d2.account = bank_account["account"]
|
||||||
d2.balance = bank_account["balance"]
|
d2.balance = bank_account["balance"]
|
||||||
|
d2.account_currency = bank_account["account_currency"]
|
||||||
|
d2.account_type = bank_account["account_type"]
|
||||||
|
d2.exchange_rate = get_exchange_rate(bank_account["account"],
|
||||||
|
bank_account["account_currency"], doc.company)
|
||||||
|
|
||||||
return jv
|
return jv
|
||||||
|
|
||||||
@ -599,27 +730,37 @@ def get_outstanding(args):
|
|||||||
if not frappe.has_permission("Account"):
|
if not frappe.has_permission("Account"):
|
||||||
frappe.msgprint(_("No Permission"), raise_exception=1)
|
frappe.msgprint(_("No Permission"), raise_exception=1)
|
||||||
args = eval(args)
|
args = eval(args)
|
||||||
|
company_currency = get_company_currency(args.get("company"))
|
||||||
|
|
||||||
if args.get("doctype") == "Journal Entry":
|
if args.get("doctype") == "Journal Entry":
|
||||||
condition = " and party=%(party)s" if args.get("party") else ""
|
condition = " and party=%(party)s" if args.get("party") else ""
|
||||||
|
|
||||||
against_jv_amount = frappe.db.sql("""
|
against_jv_amount = frappe.db.sql("""
|
||||||
select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
|
select sum(ifnull(debit_in_account_currency, 0)) - sum(ifnull(credit_in_account_currency, 0))
|
||||||
from `tabJournal Entry Account` where parent=%(docname)s and account=%(account)s {0}
|
from `tabJournal Entry Account` where parent=%(docname)s and account=%(account)s {0}
|
||||||
and ifnull(reference_type, '')=''""".format(condition), args)
|
and ifnull(reference_type, '')=''""".format(condition), args)
|
||||||
|
|
||||||
against_jv_amount = flt(against_jv_amount[0][0]) if against_jv_amount else 0
|
against_jv_amount = flt(against_jv_amount[0][0]) if against_jv_amount else 0
|
||||||
|
amount_field = "credit_in_account_currency" if against_jv_amount > 0 else "debit_in_account_currency"
|
||||||
return {
|
return {
|
||||||
("credit" if against_jv_amount > 0 else "debit"): abs(against_jv_amount)
|
amount_field: abs(against_jv_amount)
|
||||||
}
|
}
|
||||||
elif args.get("doctype") == "Sales Invoice":
|
elif args.get("doctype") in ("Sales Invoice", "Purchase Invoice"):
|
||||||
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", args["docname"], "outstanding_amount"))
|
invoice = frappe.db.get_value(args["doctype"], args["docname"],
|
||||||
|
["outstanding_amount", "conversion_rate"], as_dict=1)
|
||||||
|
|
||||||
|
exchange_rate = invoice.conversion_rate if (args.get("account_currency") != company_currency) else 1
|
||||||
|
|
||||||
|
if args["doctype"] == "Sales Invoice":
|
||||||
|
amount_field = "credit_in_account_currency" \
|
||||||
|
if flt(invoice.outstanding_amount) > 0 else "debit_in_account_currency"
|
||||||
|
else:
|
||||||
|
amount_field = "debit_in_account_currency" \
|
||||||
|
if flt(invoice.outstanding_amount) > 0 else "credit_in_account_currency"
|
||||||
|
|
||||||
return {
|
return {
|
||||||
("credit" if outstanding_amount > 0 else "debit"): abs(outstanding_amount)
|
amount_field: abs(flt(invoice.outstanding_amount)),
|
||||||
}
|
"exchange_rate": exchange_rate
|
||||||
elif args.get("doctype") == "Purchase Invoice":
|
|
||||||
outstanding_amount = flt(frappe.db.get_value("Purchase Invoice", args["docname"], "outstanding_amount"))
|
|
||||||
return {
|
|
||||||
("debit" if outstanding_amount > 0 else "credit"): abs(outstanding_amount)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@ -640,14 +781,58 @@ def get_party_account_and_balance(company, party_type, party):
|
|||||||
}
|
}
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_account_balance_and_party_type(account, date):
|
def get_account_balance_and_party_type(account, date, company, debit=None, credit=None, exchange_rate=None):
|
||||||
"""Returns dict of account balance and party type to be set in Journal Entry on selection of account."""
|
"""Returns dict of account balance and party type to be set in Journal Entry on selection of account."""
|
||||||
if not frappe.has_permission("Account"):
|
if not frappe.has_permission("Account"):
|
||||||
frappe.msgprint(_("No Permission"), raise_exception=1)
|
frappe.msgprint(_("No Permission"), raise_exception=1)
|
||||||
|
|
||||||
account_type = frappe.db.get_value("Account", account, "account_type")
|
company_currency = get_company_currency(company)
|
||||||
return {
|
account_details = frappe.db.get_value("Account", account, ["account_type", "account_currency"], as_dict=1)
|
||||||
"balance": get_balance_on(account, date),
|
|
||||||
"party_type": {"Receivable":"Customer", "Payable":"Supplier"}.get(account_type, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if account_details.account_type == "Receivable":
|
||||||
|
party_type = "Customer"
|
||||||
|
elif account_details.account_type == "Payable":
|
||||||
|
party_type = "Supplier"
|
||||||
|
else:
|
||||||
|
party_type = ""
|
||||||
|
|
||||||
|
grid_values = {
|
||||||
|
"balance": get_balance_on(account, date),
|
||||||
|
"party_type": party_type,
|
||||||
|
"account_type": account_details.account_type,
|
||||||
|
"account_currency": account_details.account_currency or company_currency,
|
||||||
|
"exchange_rate": get_exchange_rate(account, account_details.account_currency,
|
||||||
|
company, debit=debit, credit=credit, exchange_rate=exchange_rate)
|
||||||
|
}
|
||||||
|
return grid_values
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_exchange_rate(account, account_currency, company,
|
||||||
|
reference_type=None, reference_name=None, debit=None, credit=None, exchange_rate=None):
|
||||||
|
from erpnext.setup.utils import get_exchange_rate
|
||||||
|
company_currency = get_company_currency(company)
|
||||||
|
account_details = frappe.db.get_value("Account", account, ["account_type", "root_type"], as_dict=1)
|
||||||
|
|
||||||
|
if account_currency != company_currency:
|
||||||
|
if reference_type in ("Sales Invoice", "Purchase Invoice") and reference_name:
|
||||||
|
exchange_rate = frappe.db.get_value(reference_type, reference_name, "conversion_rate")
|
||||||
|
elif account_details.account_type == "Bank" and \
|
||||||
|
((account_details.root_type == "Asset" and flt(credit) > 0) or
|
||||||
|
(account_details.root_type == "Liability" and debit)):
|
||||||
|
exchange_rate = get_average_exchange_rate(account)
|
||||||
|
|
||||||
|
if not exchange_rate:
|
||||||
|
exchange_rate = get_exchange_rate(account_currency, company_currency)
|
||||||
|
else:
|
||||||
|
exchange_rate = 1
|
||||||
|
|
||||||
|
return exchange_rate
|
||||||
|
|
||||||
|
def get_average_exchange_rate(account):
|
||||||
|
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
|
||||||
|
@ -101,7 +101,7 @@ class TestJournalEntry(unittest.TestCase):
|
|||||||
self.set_total_expense_zero("2013-02-28")
|
self.set_total_expense_zero("2013-02-28")
|
||||||
|
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
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",
|
self.assertTrue(frappe.db.get_value("GL Entry",
|
||||||
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
|
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
|
||||||
@ -112,7 +112,7 @@ class TestJournalEntry(unittest.TestCase):
|
|||||||
self.set_total_expense_zero("2013-02-28")
|
self.set_total_expense_zero("2013-02-28")
|
||||||
|
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
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)
|
self.assertRaises(BudgetError, jv.submit)
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ class TestJournalEntry(unittest.TestCase):
|
|||||||
self.set_total_expense_zero("2013-02-28")
|
self.set_total_expense_zero("2013-02-28")
|
||||||
|
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
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)
|
self.assertRaises(BudgetError, jv.submit)
|
||||||
|
|
||||||
@ -136,13 +136,13 @@ class TestJournalEntry(unittest.TestCase):
|
|||||||
self.set_total_expense_zero("2013-02-28")
|
self.set_total_expense_zero("2013-02-28")
|
||||||
|
|
||||||
jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
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",
|
self.assertTrue(frappe.db.get_value("GL Entry",
|
||||||
{"voucher_type": "Journal Entry", "voucher_no": jv1.name}))
|
{"voucher_type": "Journal Entry", "voucher_no": jv1.name}))
|
||||||
|
|
||||||
jv2 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
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",
|
self.assertTrue(frappe.db.get_value("GL Entry",
|
||||||
{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
|
{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
|
||||||
@ -165,28 +165,76 @@ class TestJournalEntry(unittest.TestCase):
|
|||||||
def set_total_expense_zero(self, posting_date):
|
def set_total_expense_zero(self, posting_date):
|
||||||
existing_expense = self.get_actual_expense(posting_date)
|
existing_expense = self.get_actual_expense(posting_date)
|
||||||
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
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 make_journal_entry(account1, account2, amount, cost_center=None, submit=False):
|
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)
|
||||||
|
|
||||||
|
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 = frappe.new_doc("Journal Entry")
|
||||||
jv.posting_date = "2013-02-14"
|
jv.posting_date = "2013-02-14"
|
||||||
jv.company = "_Test Company"
|
jv.company = "_Test Company"
|
||||||
jv.fiscal_year = "_Test Fiscal Year 2013"
|
jv.fiscal_year = "_Test Fiscal Year 2013"
|
||||||
jv.user_remark = "test"
|
jv.user_remark = "test"
|
||||||
|
jv.multi_currency = 1
|
||||||
jv.set("accounts", [
|
jv.set("accounts", [
|
||||||
{
|
{
|
||||||
"account": account1,
|
"account": account1,
|
||||||
"cost_center": cost_center,
|
"cost_center": cost_center,
|
||||||
"debit": amount if amount > 0 else 0,
|
"debit_in_account_currency": amount if amount > 0 else 0,
|
||||||
"credit": abs(amount) if amount < 0 else 0,
|
"credit_in_account_currency": abs(amount) if amount < 0 else 0,
|
||||||
|
"exchange_rate": exchange_rate
|
||||||
}, {
|
}, {
|
||||||
"account": account2,
|
"account": account2,
|
||||||
"cost_center": cost_center,
|
"cost_center": cost_center,
|
||||||
"credit": amount if amount > 0 else 0,
|
"credit_in_account_currency": amount if amount > 0 else 0,
|
||||||
"debit": abs(amount) if amount < 0 else 0,
|
"debit_in_account_currency": abs(amount) if amount < 0 else 0,
|
||||||
|
exchange_rate: exchange_rate
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
if save or submit:
|
||||||
jv.insert()
|
jv.insert()
|
||||||
|
|
||||||
if submit:
|
if submit:
|
||||||
|
@ -9,15 +9,15 @@
|
|||||||
"account": "_Test Receivable - _TC",
|
"account": "_Test Receivable - _TC",
|
||||||
"party_type": "Customer",
|
"party_type": "Customer",
|
||||||
"party": "_Test Customer",
|
"party": "_Test Customer",
|
||||||
"credit": 400.0,
|
"credit_in_account_currency": 400.0,
|
||||||
"debit": 0.0,
|
"debit_in_account_currency": 0.0,
|
||||||
"doctype": "Journal Entry Account",
|
"doctype": "Journal Entry Account",
|
||||||
"parentfield": "accounts"
|
"parentfield": "accounts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "_Test Account Bank Account - _TC",
|
"account": "_Test Bank - _TC",
|
||||||
"credit": 0.0,
|
"credit_in_account_currency": 0.0,
|
||||||
"debit": 400.0,
|
"debit_in_account_currency": 400.0,
|
||||||
"doctype": "Journal Entry Account",
|
"doctype": "Journal Entry Account",
|
||||||
"parentfield": "accounts"
|
"parentfield": "accounts"
|
||||||
}
|
}
|
||||||
@ -40,15 +40,15 @@
|
|||||||
"account": "_Test Payable - _TC",
|
"account": "_Test Payable - _TC",
|
||||||
"party_type": "Supplier",
|
"party_type": "Supplier",
|
||||||
"party": "_Test Supplier",
|
"party": "_Test Supplier",
|
||||||
"credit": 0.0,
|
"credit_in_account_currency": 0.0,
|
||||||
"debit": 400.0,
|
"debit_in_account_currency": 400.0,
|
||||||
"doctype": "Journal Entry Account",
|
"doctype": "Journal Entry Account",
|
||||||
"parentfield": "accounts"
|
"parentfield": "accounts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "_Test Account Bank Account - _TC",
|
"account": "_Test Bank - _TC",
|
||||||
"credit": 400.0,
|
"credit_in_account_currency": 400.0,
|
||||||
"debit": 0.0,
|
"debit_in_account_currency": 0.0,
|
||||||
"doctype": "Journal Entry Account",
|
"doctype": "Journal Entry Account",
|
||||||
"parentfield": "accounts"
|
"parentfield": "accounts"
|
||||||
}
|
}
|
||||||
@ -71,16 +71,16 @@
|
|||||||
"account": "_Test Receivable - _TC",
|
"account": "_Test Receivable - _TC",
|
||||||
"party_type": "Customer",
|
"party_type": "Customer",
|
||||||
"party": "_Test Customer",
|
"party": "_Test Customer",
|
||||||
"credit": 0.0,
|
"credit_in_account_currency": 0.0,
|
||||||
"debit": 400.0,
|
"debit_in_account_currency": 400.0,
|
||||||
"doctype": "Journal Entry Account",
|
"doctype": "Journal Entry Account",
|
||||||
"parentfield": "accounts"
|
"parentfield": "accounts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "Sales - _TC",
|
"account": "Sales - _TC",
|
||||||
"cost_center": "_Test Cost Center - _TC",
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
"credit": 400.0,
|
"credit_in_account_currency": 400.0,
|
||||||
"debit": 0.0,
|
"debit_in_account_currency": 0.0,
|
||||||
"doctype": "Journal Entry Account",
|
"doctype": "Journal Entry Account",
|
||||||
"parentfield": "accounts"
|
"parentfield": "accounts"
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,28 @@
|
|||||||
"unique": 0,
|
"unique": 0,
|
||||||
"width": "250px"
|
"width": "250px"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"fieldname": "account_type",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"hidden": 1,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"label": "Account Type",
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -48,7 +70,7 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "balance",
|
"oldfieldname": "balance",
|
||||||
"oldfieldtype": "Data",
|
"oldfieldtype": "Data",
|
||||||
"options": "Company:company:default_currency",
|
"options": "account_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
@ -162,7 +184,7 @@
|
|||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Party Balance",
|
"label": "Party Balance",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Company:company:default_currency",
|
"options": "account_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -173,6 +195,96 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"collapsible_depends_on": "",
|
||||||
|
"depends_on": "",
|
||||||
|
"fieldname": "currency_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"label": "Currency",
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"fieldname": "account_currency",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"label": "Account Currency",
|
||||||
|
"no_copy": 1,
|
||||||
|
"options": "Currency",
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"fieldname": "column_break_10",
|
||||||
|
"fieldtype": "Column Break",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"fieldname": "exchange_rate",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"label": "Exchange Rate",
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -198,20 +310,43 @@
|
|||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"fieldname": "debit",
|
"fieldname": "debit_in_account_currency",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Debit",
|
"label": "Debit in Account Currency",
|
||||||
"no_copy": 0,
|
"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",
|
"oldfieldname": "debit",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 1,
|
||||||
"read_only": 0,
|
"read_only": 1,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
@ -242,20 +377,43 @@
|
|||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"fieldname": "credit",
|
"fieldname": "credit_in_account_currency",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Credit",
|
"label": "Credit in Account Currency",
|
||||||
"no_copy": 0,
|
"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",
|
"oldfieldname": "credit",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 1,
|
||||||
"read_only": 0,
|
"read_only": 1,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
@ -405,7 +563,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2015-08-17 02:11:33.991361",
|
"modified": "2015-09-11 12:55:59.270539",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Journal Entry Account",
|
"name": "Journal Entry Account",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -65,7 +65,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:58.003800",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Mode of Payment",
|
"name": "Mode of Payment",
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# See license.txt
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
# test_records = frappe.get_test_records('Mode of Payment')
|
||||||
|
|
||||||
|
class TestModeofPayment(unittest.TestCase):
|
||||||
|
pass
|
@ -79,6 +79,7 @@ class PaymentReconciliation(Document):
|
|||||||
`tabGL Entry`
|
`tabGL Entry`
|
||||||
where
|
where
|
||||||
party_type = %(party_type)s and party = %(party)s
|
party_type = %(party_type)s and party = %(party)s
|
||||||
|
and voucher_type != "Journal Entry"
|
||||||
and account = %(account)s and {dr_or_cr} > 0 {cond}
|
and account = %(account)s and {dr_or_cr} > 0 {cond}
|
||||||
group by voucher_type, voucher_no
|
group by voucher_type, voucher_no
|
||||||
""".format(**{
|
""".format(**{
|
||||||
|
@ -25,8 +25,14 @@ frappe.ui.form.on("Payment Tool", "onload", function(frm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
frm.set_query("against_voucher_type", "vouchers", function() {
|
frm.set_query("against_voucher_type", "vouchers", function() {
|
||||||
|
if (frm.doc.party_type=="Customer") {
|
||||||
|
var doctypes = ["Sales Order", "Sales Invoice", "Journal Entry"];
|
||||||
|
} else {
|
||||||
|
var doctypes = ["Purchase Order", "Purchase Invoice", "Journal Entry"];
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
filters: {"name": ["in", ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Sales Order", "Purchase Order"]]}
|
filters: { "name": ["in", doctypes] }
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -55,6 +61,25 @@ frappe.ui.form.on("Payment Tool", "party", function(frm) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
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) {
|
frappe.ui.form.on("Payment Tool", "company", function(frm) {
|
||||||
erpnext.payment_tool.check_mandatory_to_set_button(frm);
|
erpnext.payment_tool.check_mandatory_to_set_button(frm);
|
||||||
});
|
});
|
||||||
@ -63,10 +88,6 @@ frappe.ui.form.on("Payment Tool", "received_or_paid", function(frm) {
|
|||||||
erpnext.payment_tool.check_mandatory_to_set_button(frm);
|
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
|
// Fetch bank/cash account based on payment mode
|
||||||
frappe.ui.form.on("Payment Tool", "payment_mode", function(frm) {
|
frappe.ui.form.on("Payment Tool", "payment_mode", function(frm) {
|
||||||
return frappe.call({
|
return frappe.call({
|
||||||
@ -120,6 +141,7 @@ frappe.ui.form.on("Payment Tool", "get_outstanding_vouchers", function(frm) {
|
|||||||
c.against_voucher_no = d.voucher_no;
|
c.against_voucher_no = d.voucher_no;
|
||||||
c.total_amount = d.invoice_amount;
|
c.total_amount = d.invoice_amount;
|
||||||
c.outstanding_amount = d.outstanding_amount;
|
c.outstanding_amount = d.outstanding_amount;
|
||||||
|
c.payment_amount = d.outstanding_amount;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
refresh_field("vouchers");
|
refresh_field("vouchers");
|
||||||
@ -130,41 +152,63 @@ frappe.ui.form.on("Payment Tool", "get_outstanding_vouchers", function(frm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// validate against_voucher_type
|
// validate against_voucher_type
|
||||||
frappe.ui.form.on("Payment Tool Detail", "against_voucher_type", function(frm) {
|
frappe.ui.form.on("Payment Tool Detail", "against_voucher_type", function(frm, cdt, cdn) {
|
||||||
erpnext.payment_tool.validate_against_voucher(frm);
|
var row = frappe.model.get_doc(cdt, cdn);
|
||||||
|
erpnext.payment_tool.validate_against_voucher(frm, row);
|
||||||
});
|
});
|
||||||
|
|
||||||
erpnext.payment_tool.validate_against_voucher = function(frm) {
|
erpnext.payment_tool.validate_against_voucher = function(frm, row) {
|
||||||
$.each(frm.doc.vouchers || [], function(i, row) {
|
var _validate = function(i, row) {
|
||||||
|
if (!row.against_voucher_type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(frm.doc.party_type=="Customer"
|
if(frm.doc.party_type=="Customer"
|
||||||
&& !in_list(["Sales Order", "Sales Invoice", "Journal Entry"], row.against_voucher_type)) {
|
&& !in_list(["Sales Order", "Sales Invoice", "Journal Entry"], row.against_voucher_type)) {
|
||||||
frappe.model.set_value(row.doctype, row.name, "against_voucher_type", "");
|
frappe.model.set_value(row.doctype, row.name, "against_voucher_type", "");
|
||||||
frappe.throw(__("Against Voucher Type must be one of Sales Order, Sales Invoice or Journal Entry"))
|
frappe.msgprint(__("Against Voucher Type must be one of Sales Order, Sales Invoice or Journal Entry"));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(frm.doc.party_type=="Supplier"
|
if(frm.doc.party_type=="Supplier"
|
||||||
&& !in_list(["Purchase Order", "Purchase Invoice", "Journal Entry"], row.against_voucher_type)) {
|
&& !in_list(["Purchase Order", "Purchase Invoice", "Journal Entry"], row.against_voucher_type)) {
|
||||||
frappe.model.set_value(row.doctype, row.name, "against_voucher_type", "");
|
frappe.model.set_value(row.doctype, row.name, "against_voucher_type", "");
|
||||||
frappe.throw(__("Against Voucher Type must be one of Purchase Order, Purchase Invoice or Journal Entry"))
|
frappe.msgprint(__("Against Voucher Type must be one of Purchase Order, Purchase Invoice or Journal Entry"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row) {
|
||||||
|
_validate(0, row);
|
||||||
|
} else {
|
||||||
|
$.each(frm.doc.vouchers || [], _validate);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate against_voucher_type
|
// validate against_voucher_type
|
||||||
frappe.ui.form.on("Payment Tool Detail", "against_voucher_no", function(frm, cdt, cdn) {
|
frappe.ui.form.on("Payment Tool Detail", "against_voucher_no", function(frm, cdt, cdn) {
|
||||||
var row = locals[cdt][cdn];
|
var row = locals[cdt][cdn];
|
||||||
|
if (!row.against_voucher_no) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'erpnext.accounts.doctype.payment_tool.payment_tool.get_against_voucher_amount',
|
method: 'erpnext.accounts.doctype.payment_tool.payment_tool.get_against_voucher_amount',
|
||||||
args: {
|
args: {
|
||||||
"against_voucher_type": row.against_voucher_type,
|
"against_voucher_type": row.against_voucher_type,
|
||||||
"against_voucher_no": row.against_voucher_no
|
"against_voucher_no": row.against_voucher_no,
|
||||||
|
"party_account": frm.doc.party_account,
|
||||||
|
"company": frm.doc.company
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if(!r.exc) {
|
if(!r.exc) {
|
||||||
$.each(r.message, function(k, v) {
|
$.each(r.message, function(k, v) {
|
||||||
frappe.model.set_value(cdt, cdn, k, v);
|
frappe.model.set_value(cdt, cdn, k, v);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frappe.model.set_value(cdt, cdn, "payment_amount", r.message.outstanding_amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -187,7 +231,7 @@ erpnext.payment_tool.set_total_payment_amount = function(frm) {
|
|||||||
} else {
|
} else {
|
||||||
if(row.payment_amount < 0)
|
if(row.payment_amount < 0)
|
||||||
msgprint(__("Row {0}: Payment amount can not be negative", [row.idx]));
|
msgprint(__("Row {0}: Payment amount can not be negative", [row.idx]));
|
||||||
else if(row.payment_amount >= row.outstanding_amount)
|
else if(row.payment_amount > row.outstanding_amount)
|
||||||
msgprint(__("Row {0}: Payment Amount cannot be greater than Outstanding Amount", [__(row.idx)]));
|
msgprint(__("Row {0}: Payment Amount cannot be greater than Outstanding Amount", [__(row.idx)]));
|
||||||
|
|
||||||
frappe.model.set_value(row.doctype, row.name, "payment_amount", 0.0);
|
frappe.model.set_value(row.doctype, row.name, "payment_amount", 0.0);
|
||||||
|
@ -106,7 +106,7 @@
|
|||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Column Break 1",
|
"label": "",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -162,6 +162,29 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"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,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -306,6 +329,7 @@
|
|||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Total Payment Amount",
|
"label": "Total Payment Amount",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
|
"options": "party_account_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
@ -450,7 +474,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-06-05 11:17:33.843334",
|
"modified": "2015-08-31 18:58:21.813054",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Payment Tool",
|
"name": "Payment Tool",
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _, scrub
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
import json
|
import json
|
||||||
@ -33,15 +33,18 @@ class PaymentTool(Document):
|
|||||||
d1.party_type = self.party_type
|
d1.party_type = self.party_type
|
||||||
d1.party = self.party
|
d1.party = self.party
|
||||||
d1.balance = get_balance_on(self.party_account)
|
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_type", v.against_voucher_type)
|
||||||
d1.set("reference_name", v.against_voucher_no)
|
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')
|
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 = jv.append("accounts")
|
||||||
d2.account = self.payment_account
|
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:
|
if self.payment_account:
|
||||||
d2.balance = get_balance_on(self.payment_account)
|
d2.balance = get_balance_on(self.payment_account)
|
||||||
|
|
||||||
@ -56,39 +59,49 @@ def get_outstanding_vouchers(args):
|
|||||||
|
|
||||||
args = json.loads(args)
|
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":
|
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":
|
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:
|
else:
|
||||||
frappe.throw(_("Please enter the Against Vouchers manually"))
|
frappe.throw(_("Please enter the Against Vouchers manually"))
|
||||||
|
|
||||||
# Get all outstanding sales /purchase invoices
|
# Get all outstanding sales /purchase invoices
|
||||||
outstanding_invoices = get_outstanding_invoices(amount_query, args.get("party_account"),
|
outstanding_invoices = get_outstanding_invoices(amount_query, args.get("party_account"),
|
||||||
args.get("party_type"), args.get("party"))
|
args.get("party_type"), args.get("party"), with_journal_entry=False)
|
||||||
|
|
||||||
# Get all SO / PO which are not fully billed or aginst which full advance not paid
|
# Get all SO / PO which are not fully billed or aginst which full advance not paid
|
||||||
orders_to_be_billed = get_orders_to_be_billed(args.get("party_type"), args.get("party"))
|
orders_to_be_billed = get_orders_to_be_billed(args.get("party_type"), args.get("party"),
|
||||||
|
party_account_currency, company_currency)
|
||||||
return outstanding_invoices + orders_to_be_billed
|
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'
|
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("""
|
orders = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
name as voucher_no,
|
name as voucher_no,
|
||||||
ifnull(base_grand_total, 0) as invoice_amount,
|
ifnull({ref_field}, 0) as invoice_amount,
|
||||||
(ifnull(base_grand_total, 0) - ifnull(advance_paid, 0)) as outstanding_amount,
|
(ifnull({ref_field}, 0) - ifnull(advance_paid, 0)) as outstanding_amount,
|
||||||
transaction_date as posting_date
|
transaction_date as posting_date
|
||||||
from
|
from
|
||||||
`tab%s`
|
`tab{voucher_type}`
|
||||||
where
|
where
|
||||||
%s = %s
|
{party_type} = %s
|
||||||
and docstatus = 1
|
and docstatus = 1
|
||||||
and ifnull(status, "") != "Stopped"
|
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
|
and abs(100 - ifnull(per_billed, 0)) > 0.01
|
||||||
""" % (voucher_type, 'customer' if party_type == "Customer" else 'supplier', '%s'),
|
""".format(**{
|
||||||
party, as_dict = True)
|
"ref_field": ref_field,
|
||||||
|
"voucher_type": voucher_type,
|
||||||
|
"party_type": scrub(party_type)
|
||||||
|
}), party, as_dict = True)
|
||||||
|
|
||||||
order_list = []
|
order_list = []
|
||||||
for d in orders:
|
for d in orders:
|
||||||
@ -98,13 +111,19 @@ def get_orders_to_be_billed(party_type, party):
|
|||||||
return order_list
|
return order_list
|
||||||
|
|
||||||
@frappe.whitelist()
|
@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"]:
|
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"]:
|
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":
|
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"""
|
details = frappe.db.sql("""select {0} from `tab{1}` where name = %s"""
|
||||||
.format(select_cond, against_voucher_type), against_voucher_no, as_dict=1)
|
.format(select_cond, against_voucher_type), against_voucher_no, as_dict=1)
|
||||||
|
@ -39,7 +39,7 @@ class TestPaymentTool(unittest.TestCase):
|
|||||||
"party": "_Test Customer 3",
|
"party": "_Test Customer 3",
|
||||||
"reference_type": "Sales Order",
|
"reference_type": "Sales Order",
|
||||||
"reference_name": so2.name,
|
"reference_name": so2.name,
|
||||||
"credit": 1000,
|
"credit_in_account_currency": 1000,
|
||||||
"is_advance": "Yes"
|
"is_advance": "Yes"
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ class TestPaymentTool(unittest.TestCase):
|
|||||||
"party": "_Test Customer 3",
|
"party": "_Test Customer 3",
|
||||||
"reference_type": si2.doctype,
|
"reference_type": si2.doctype,
|
||||||
"reference_name": si2.name,
|
"reference_name": si2.name,
|
||||||
"credit": 561.80
|
"credit_in_account_currency": 561.80
|
||||||
})
|
})
|
||||||
|
|
||||||
pi = self.create_voucher(pi_test_records[0], {
|
pi = self.create_voucher(pi_test_records[0], {
|
||||||
@ -91,7 +91,7 @@ class TestPaymentTool(unittest.TestCase):
|
|||||||
"party": "_Test Customer 3",
|
"party": "_Test Customer 3",
|
||||||
"party_account": "_Test Receivable - _TC",
|
"party_account": "_Test Receivable - _TC",
|
||||||
"payment_mode": "Cheque",
|
"payment_mode": "Cheque",
|
||||||
"payment_account": "_Test Account Bank Account - _TC",
|
"payment_account": "_Test Bank - _TC",
|
||||||
"reference_no": "123456",
|
"reference_no": "123456",
|
||||||
"reference_date": "2013-02-14"
|
"reference_date": "2013-02-14"
|
||||||
}
|
}
|
||||||
@ -117,10 +117,10 @@ class TestPaymentTool(unittest.TestCase):
|
|||||||
def create_against_jv(self, test_record, args):
|
def create_against_jv(self, test_record, args):
|
||||||
jv = frappe.copy_doc(test_record)
|
jv = frappe.copy_doc(test_record)
|
||||||
jv.get("accounts")[0].update(args)
|
jv.get("accounts")[0].update(args)
|
||||||
if args.get("debit"):
|
if args.get("debit_in_account_currency"):
|
||||||
jv.get("accounts")[1].credit = args["debit"]
|
jv.get("accounts")[1].credit_in_account_currency = args["debit_in_account_currency"]
|
||||||
elif args.get("credit"):
|
elif args.get("credit_in_account_currency"):
|
||||||
jv.get("accounts")[1].debit = args["credit"]
|
jv.get("accounts")[1].debit_in_account_currency = args["credit_in_account_currency"]
|
||||||
|
|
||||||
jv.insert()
|
jv.insert()
|
||||||
jv.submit()
|
jv.submit()
|
||||||
@ -141,7 +141,8 @@ class TestPaymentTool(unittest.TestCase):
|
|||||||
outstanding_entries = get_outstanding_vouchers(json.dumps(args))
|
outstanding_entries = get_outstanding_vouchers(json.dumps(args))
|
||||||
|
|
||||||
for d in outstanding_entries:
|
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)
|
self.check_jv_entries(doc, outstanding_entries, expected_outstanding)
|
||||||
|
|
||||||
@ -156,11 +157,10 @@ class TestPaymentTool(unittest.TestCase):
|
|||||||
paytool.total_payment_amount = 300
|
paytool.total_payment_amount = 300
|
||||||
|
|
||||||
new_jv = paytool.make_journal_entry()
|
new_jv = paytool.make_journal_entry()
|
||||||
|
|
||||||
for jv_entry in new_jv.get("accounts"):
|
for jv_entry in new_jv.get("accounts"):
|
||||||
if paytool.party_account == jv_entry.get("account") and paytool.party == jv_entry.get("party"):
|
if paytool.party_account == jv_entry.get("account") and paytool.party == jv_entry.get("party"):
|
||||||
self.assertEquals(100.00,
|
self.assertEquals(100.00, jv_entry.get("debit_in_account_currency"
|
||||||
jv_entry.get("debit" if paytool.party_type=="Supplier" else "credit"))
|
if paytool.party_type=="Supplier" else "credit_in_account_currency"))
|
||||||
self.assertEquals(jv_entry.reference_name,
|
self.assertEquals(jv_entry.reference_name,
|
||||||
expected_outstanding[jv_entry.reference_type][0])
|
expected_outstanding[jv_entry.reference_type][0])
|
||||||
|
|
||||||
@ -170,4 +170,6 @@ class TestPaymentTool(unittest.TestCase):
|
|||||||
def clear_table_entries(self):
|
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 `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 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 Order` where supplier = "_Test Supplier 1" """)
|
||||||
|
frappe.db.sql("""delete from `tabPurchase Invoice` where supplier = "_Test Supplier 1" """)
|
||||||
|
@ -87,6 +87,7 @@
|
|||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Total Amount",
|
"label": "Total Amount",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
|
"options": "party_account_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
@ -108,6 +109,7 @@
|
|||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Outstanding Amount",
|
"label": "Outstanding Amount",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
|
"options": "party_account_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
@ -129,6 +131,7 @@
|
|||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Payment Amount",
|
"label": "Payment Amount",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
|
"options": "party_account_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
@ -146,7 +149,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2014-09-11 08:55:34.384017",
|
"modified": "2015-08-31 18:58:35.537060",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Payment Tool Detail",
|
"name": "Payment Tool Detail",
|
||||||
|
@ -10,11 +10,11 @@ from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journ
|
|||||||
|
|
||||||
class TestPeriodClosingVoucher(unittest.TestCase):
|
class TestPeriodClosingVoucher(unittest.TestCase):
|
||||||
def test_closing_entry(self):
|
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)
|
"_Test Cost Center - _TC", submit=True)
|
||||||
|
|
||||||
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
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
|
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
|
from `tabGL Entry` t1, `tabAccount` t2
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Title",
|
"label": "Title",
|
||||||
"no_copy": 0,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -851,7 +851,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-08-13 14:58:29.194326",
|
"modified": "2015-09-11 12:19:52.242771",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Pricing Rule",
|
"name": "Pricing Rule",
|
||||||
|
@ -76,7 +76,28 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
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() {
|
write_off_amount: function() {
|
||||||
|
this.set_in_company_currency(this.frm.doc, ["write_off_amount"]);
|
||||||
this.calculate_outstanding_amount();
|
this.calculate_outstanding_amount();
|
||||||
this.frm.refresh_fields();
|
this.frm.refresh_fields();
|
||||||
},
|
},
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Title",
|
"label": "Title",
|
||||||
"no_copy": 0,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -1266,30 +1266,6 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"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,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -1304,7 +1280,7 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "total_advance",
|
"oldfieldname": "total_advance",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "Company:company:default_currency",
|
"options": "party_account_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
@ -1328,7 +1304,7 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "outstanding_amount",
|
"oldfieldname": "outstanding_amount",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "Company:company:default_currency",
|
"options": "party_account_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
@ -1338,6 +1314,30 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"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,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -1350,7 +1350,7 @@
|
|||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Write Off Amount",
|
"label": "Write Off Amount",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Company:company:default_currency",
|
"options": "currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
@ -1360,6 +1360,50 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"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,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -1406,29 +1450,6 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"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,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -1748,6 +1769,29 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"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,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -1797,6 +1841,29 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"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,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -2175,7 +2242,7 @@
|
|||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-11 12:21:39.803805",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Invoice",
|
"name": "Purchase Invoice",
|
||||||
|
@ -91,7 +91,8 @@ class PurchaseInvoice(BuyingController):
|
|||||||
throw(_("Conversion rate cannot be 0 or 1"))
|
throw(_("Conversion rate cannot be 0 or 1"))
|
||||||
|
|
||||||
def validate_credit_to_acc(self):
|
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":
|
if account.report_type != "Balance Sheet":
|
||||||
frappe.throw(_("Credit To account must be a Balance Sheet account"))
|
frappe.throw(_("Credit To account must be a Balance Sheet account"))
|
||||||
@ -99,6 +100,8 @@ class PurchaseInvoice(BuyingController):
|
|||||||
if self.supplier and account.account_type != "Payable":
|
if self.supplier and account.account_type != "Payable":
|
||||||
frappe.throw(_("Credit To account must be a Payable account"))
|
frappe.throw(_("Credit To account must be a Payable account"))
|
||||||
|
|
||||||
|
self.party_account_currency = account.account_currency
|
||||||
|
|
||||||
def check_for_stopped_status(self):
|
def check_for_stopped_status(self):
|
||||||
check_list = []
|
check_list = []
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
@ -213,7 +216,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
'party_type': 'Supplier',
|
'party_type': 'Supplier',
|
||||||
'party': self.supplier,
|
'party': self.supplier,
|
||||||
'is_advance' : 'Yes',
|
'is_advance' : 'Yes',
|
||||||
'dr_or_cr' : 'debit',
|
'dr_or_cr' : 'debit_in_account_currency',
|
||||||
'unadjusted_amt' : flt(d.advance_amount),
|
'unadjusted_amt' : flt(d.advance_amount),
|
||||||
'allocated_amt' : flt(d.allocated_amount)
|
'allocated_amt' : flt(d.allocated_amount)
|
||||||
}
|
}
|
||||||
@ -257,26 +260,32 @@ class PurchaseInvoice(BuyingController):
|
|||||||
"party_type": "Supplier",
|
"party_type": "Supplier",
|
||||||
"party": self.supplier,
|
"party": self.supplier,
|
||||||
"against": self.against_expense_account,
|
"against": self.against_expense_account,
|
||||||
"credit": self.total_amount_to_pay,
|
"credit": self.base_grand_total,
|
||||||
"remarks": self.remarks,
|
"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": 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)
|
||||||
)
|
)
|
||||||
|
|
||||||
# tax table gl entries
|
# tax table gl entries
|
||||||
valuation_tax = {}
|
valuation_tax = {}
|
||||||
for tax in self.get("taxes"):
|
for tax in self.get("taxes"):
|
||||||
if tax.category in ("Total", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount):
|
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(
|
gl_entries.append(
|
||||||
self.get_gl_dict({
|
self.get_gl_dict({
|
||||||
"account": tax.account_head,
|
"account": tax.account_head,
|
||||||
"against": self.supplier,
|
"against": self.supplier,
|
||||||
"debit": tax.add_deduct_tax == "Add" and tax.base_tax_amount_after_discount_amount or 0,
|
dr_or_cr: tax.base_tax_amount_after_discount_amount,
|
||||||
"credit": tax.add_deduct_tax == "Deduct" and tax.base_tax_amount_after_discount_amount or 0,
|
dr_or_cr + "_in_account_currency": tax.base_tax_amount_after_discount_amount \
|
||||||
"remarks": self.remarks,
|
if account_currency==self.company_currency \
|
||||||
|
else tax.tax_amount_after_discount_amount,
|
||||||
"cost_center": tax.cost_center
|
"cost_center": tax.cost_center
|
||||||
})
|
}, account_currency)
|
||||||
)
|
)
|
||||||
|
|
||||||
# accumulate valuation tax
|
# accumulate valuation tax
|
||||||
@ -292,14 +301,16 @@ class PurchaseInvoice(BuyingController):
|
|||||||
stock_items = self.get_stock_items()
|
stock_items = self.get_stock_items()
|
||||||
for item in self.get("items"):
|
for item in self.get("items"):
|
||||||
if flt(item.base_net_amount):
|
if flt(item.base_net_amount):
|
||||||
|
account_currency = frappe.db.get_value("Account", item.expense_account, "account_currency")
|
||||||
gl_entries.append(
|
gl_entries.append(
|
||||||
self.get_gl_dict({
|
self.get_gl_dict({
|
||||||
"account": item.expense_account,
|
"account": item.expense_account,
|
||||||
"against": self.supplier,
|
"against": self.supplier,
|
||||||
"debit": item.base_net_amount,
|
"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
|
"cost_center": item.cost_center
|
||||||
})
|
}, account_currency)
|
||||||
)
|
)
|
||||||
|
|
||||||
if auto_accounting_for_stock and self.is_opening == "No" and \
|
if auto_accounting_for_stock and self.is_opening == "No" and \
|
||||||
@ -352,12 +363,28 @@ class PurchaseInvoice(BuyingController):
|
|||||||
# writeoff account includes petty difference in the invoice amount
|
# writeoff account includes petty difference in the invoice amount
|
||||||
# and the amount that is paid
|
# and the amount that is paid
|
||||||
if self.write_off_account and flt(self.write_off_amount):
|
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(
|
gl_entries.append(
|
||||||
self.get_gl_dict({
|
self.get_gl_dict({
|
||||||
"account": self.write_off_account,
|
"account": self.write_off_account,
|
||||||
"against": self.supplier,
|
"against": self.supplier,
|
||||||
"credit": flt(self.write_off_amount),
|
"credit": flt(self.base_write_off_amount),
|
||||||
"remarks": self.remarks,
|
"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
|
"cost_center": self.write_off_cost_center
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -10,6 +10,7 @@ from frappe.utils import cint
|
|||||||
import frappe.defaults
|
import frappe.defaults
|
||||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory, \
|
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory, \
|
||||||
test_records as pr_test_records
|
test_records as pr_test_records
|
||||||
|
from erpnext.controllers.accounts_controller import InvalidCurrency
|
||||||
|
|
||||||
test_dependencies = ["Item", "Cost Center"]
|
test_dependencies = ["Item", "Cost Center"]
|
||||||
test_ignore = ["Serial No"]
|
test_ignore = ["Serial No"]
|
||||||
@ -218,7 +219,8 @@ class TestPurchaseInvoice(unittest.TestCase):
|
|||||||
pi.load_from_db()
|
pi.load_from_db()
|
||||||
|
|
||||||
self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account`
|
self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account`
|
||||||
where reference_type='Purchase Invoice' and reference_name=%s and debit=300""", pi.name))
|
where reference_type='Purchase Invoice'
|
||||||
|
and reference_name=%s and debit_in_account_currency=300""", pi.name))
|
||||||
|
|
||||||
self.assertEqual(pi.outstanding_amount, 1212.30)
|
self.assertEqual(pi.outstanding_amount, 1212.30)
|
||||||
|
|
||||||
@ -277,6 +279,55 @@ class TestPurchaseInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
set_perpetual_inventory(0)
|
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):
|
def make_purchase_invoice(**args):
|
||||||
pi = frappe.new_doc("Purchase Invoice")
|
pi = frappe.new_doc("Purchase Invoice")
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
@ -141,6 +141,9 @@
|
|||||||
"supplier": "_Test Supplier",
|
"supplier": "_Test Supplier",
|
||||||
"supplier_name": "_Test Supplier"
|
"supplier_name": "_Test Supplier"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"bill_no": "NA",
|
"bill_no": "NA",
|
||||||
"buying_price_list": "_Test Price List",
|
"buying_price_list": "_Test Price List",
|
||||||
|
@ -117,7 +117,7 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "advance_amount",
|
"oldfieldname": "advance_amount",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "Company:company:default_currency",
|
"options": "party_account_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_width": "100px",
|
"print_width": "100px",
|
||||||
@ -143,7 +143,7 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "allocated_amount",
|
"oldfieldname": "allocated_amount",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "Company:company:default_currency",
|
"options": "party_account_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_width": "100px",
|
"print_width": "100px",
|
||||||
@ -164,7 +164,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2014-12-25 16:29:15.176476",
|
"modified": "2015-08-25 17:51:30.274069",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Invoice Advance",
|
"name": "Purchase Invoice Advance",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"description": "Standard tax template that can be applied to all Purchase Transactions. This template can contain list of tax heads and also other expense heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Consider Tax or Charge for: In this section you can specify if the tax / charge is only for valuation (not a part of total) or only for total (does not add value to the item) or for both.\n10. Add or Deduct: Whether you want to add or deduct the tax.",
|
"description": "Standard tax template that can be applied to all Purchase Transactions. This template can contain list of tax heads and also other expense heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Consider Tax or Charge for: In this section you can specify if the tax / charge is only for valuation (not a part of total) or only for total (does not add value to the item) or for both.\n10. Add or Deduct: Whether you want to add or deduct the tax.",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -21,7 +21,7 @@
|
|||||||
"in_filter": 1,
|
"in_filter": 1,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Title",
|
"label": "Title",
|
||||||
"no_copy": 0,
|
"no_copy": 1,
|
||||||
"oldfieldname": "title",
|
"oldfieldname": "title",
|
||||||
"oldfieldtype": "Data",
|
"oldfieldtype": "Data",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
@ -176,7 +176,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-05-06 08:52:01.499434",
|
"modified": "2015-09-11 12:19:53.741725",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Taxes and Charges Template",
|
"name": "Purchase Taxes and Charges Template",
|
||||||
|
@ -176,6 +176,26 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
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() {
|
allocated_amount: function() {
|
||||||
this.calculate_total_advance();
|
this.calculate_total_advance();
|
||||||
this.frm.refresh_fields();
|
this.frm.refresh_fields();
|
||||||
@ -183,10 +203,10 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
|||||||
|
|
||||||
write_off_outstanding_amount_automatically: function() {
|
write_off_outstanding_amount_automatically: function() {
|
||||||
if(cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
|
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 will make outstanding amount 0
|
||||||
this.frm.set_value("write_off_amount",
|
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);
|
this.frm.toggle_enable("write_off_amount", false);
|
||||||
|
|
||||||
@ -199,10 +219,12 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
|||||||
},
|
},
|
||||||
|
|
||||||
write_off_amount: function() {
|
write_off_amount: function() {
|
||||||
|
this.set_in_company_currency(this.frm.doc, ["write_off_amount"]);
|
||||||
this.write_off_outstanding_amount_automatically();
|
this.write_off_outstanding_amount_automatically();
|
||||||
},
|
},
|
||||||
|
|
||||||
paid_amount: function() {
|
paid_amount: function() {
|
||||||
|
this.set_in_company_currency(this.frm.doc, ["paid_amount"]);
|
||||||
this.write_off_outstanding_amount_automatically();
|
this.write_off_outstanding_amount_automatically();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Title",
|
"label": "Title",
|
||||||
"no_copy": 0,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -1145,7 +1145,7 @@
|
|||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Discount",
|
"label": "Additional Discount",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
@ -1448,7 +1448,7 @@
|
|||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"oldfieldname": "total_advance",
|
"oldfieldname": "total_advance",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "Company:company:default_currency",
|
"options": "party_account_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
@ -1472,7 +1472,7 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "outstanding_amount",
|
"oldfieldname": "outstanding_amount",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "Company:company:default_currency",
|
"options": "party_account_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
@ -1663,7 +1663,7 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "paid_amount",
|
"oldfieldname": "paid_amount",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "Company:company:default_currency",
|
"options": "currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
@ -1673,6 +1673,29 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"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,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -1710,7 +1733,7 @@
|
|||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Write Off Amount",
|
"label": "Write Off Amount",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Company:company:default_currency",
|
"options": "currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
@ -1720,6 +1743,29 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"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,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -2227,6 +2273,29 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"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,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@ -2882,7 +2951,7 @@
|
|||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-11 12:21:06.545927",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice",
|
"name": "Sales Invoice",
|
||||||
|
@ -271,7 +271,7 @@ class SalesInvoice(SellingController):
|
|||||||
'party_type': 'Customer',
|
'party_type': 'Customer',
|
||||||
'party': self.customer,
|
'party': self.customer,
|
||||||
'is_advance' : 'Yes',
|
'is_advance' : 'Yes',
|
||||||
'dr_or_cr' : 'credit',
|
'dr_or_cr' : 'credit_in_account_currency',
|
||||||
'unadjusted_amt' : flt(d.advance_amount),
|
'unadjusted_amt' : flt(d.advance_amount),
|
||||||
'allocated_amt' : flt(d.allocated_amount)
|
'allocated_amt' : flt(d.allocated_amount)
|
||||||
}
|
}
|
||||||
@ -282,7 +282,8 @@ class SalesInvoice(SellingController):
|
|||||||
reconcile_against_document(lst)
|
reconcile_against_document(lst)
|
||||||
|
|
||||||
def validate_debit_to_acc(self):
|
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":
|
if account.report_type != "Balance Sheet":
|
||||||
frappe.throw(_("Debit To account must be a Balance Sheet account"))
|
frappe.throw(_("Debit To account must be a Balance Sheet account"))
|
||||||
@ -290,6 +291,8 @@ class SalesInvoice(SellingController):
|
|||||||
if self.customer and account.account_type != "Receivable":
|
if self.customer and account.account_type != "Receivable":
|
||||||
frappe.throw(_("Debit To account must be a Receivable account"))
|
frappe.throw(_("Debit To account must be a Receivable account"))
|
||||||
|
|
||||||
|
self.party_account_currency = account.account_currency
|
||||||
|
|
||||||
def validate_fixed_asset_account(self):
|
def validate_fixed_asset_account(self):
|
||||||
"""Validate Fixed Asset and whether Income Account Entered Exists"""
|
"""Validate Fixed Asset and whether Income Account Entered Exists"""
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
@ -435,7 +438,7 @@ class SalesInvoice(SellingController):
|
|||||||
if flt(self.paid_amount) == 0:
|
if flt(self.paid_amount) == 0:
|
||||||
if self.cash_bank_account:
|
if self.cash_bank_account:
|
||||||
frappe.db.set(self, 'paid_amount',
|
frappe.db.set(self, 'paid_amount',
|
||||||
(flt(self.base_grand_total) - flt(self.write_off_amount)))
|
flt(flt(self.grand_total) - flt(self.write_off_amount), self.precision("paid_amount")))
|
||||||
else:
|
else:
|
||||||
# show message that the amount is not paid
|
# show message that the amount is not paid
|
||||||
frappe.db.set(self,'paid_amount',0)
|
frappe.db.set(self,'paid_amount',0)
|
||||||
@ -443,6 +446,9 @@ class SalesInvoice(SellingController):
|
|||||||
else:
|
else:
|
||||||
frappe.db.set(self,'paid_amount',0)
|
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):
|
def check_prev_docstatus(self):
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if d.sales_order and frappe.db.get_value("Sales Order", d.sales_order, "docstatus") != 1:
|
if d.sales_order and frappe.db.get_value("Sales Order", d.sales_order, "docstatus") != 1:
|
||||||
@ -498,7 +504,7 @@ class SalesInvoice(SellingController):
|
|||||||
return gl_entries
|
return gl_entries
|
||||||
|
|
||||||
def make_customer_gl_entry(self, gl_entries):
|
def make_customer_gl_entry(self, gl_entries):
|
||||||
if self.base_grand_total:
|
if self.grand_total:
|
||||||
gl_entries.append(
|
gl_entries.append(
|
||||||
self.get_gl_dict({
|
self.get_gl_dict({
|
||||||
"account": self.debit_to,
|
"account": self.debit_to,
|
||||||
@ -506,37 +512,42 @@ class SalesInvoice(SellingController):
|
|||||||
"party": self.customer,
|
"party": self.customer,
|
||||||
"against": self.against_income_account,
|
"against": self.against_income_account,
|
||||||
"debit": self.base_grand_total,
|
"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": 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)
|
||||||
)
|
)
|
||||||
|
|
||||||
def make_tax_gl_entries(self, gl_entries):
|
def make_tax_gl_entries(self, gl_entries):
|
||||||
for tax in self.get("taxes"):
|
for tax in self.get("taxes"):
|
||||||
if flt(tax.base_tax_amount_after_discount_amount):
|
if flt(tax.base_tax_amount_after_discount_amount):
|
||||||
|
account_currency = frappe.db.get_value("Account", tax.account_head, "account_currency")
|
||||||
gl_entries.append(
|
gl_entries.append(
|
||||||
self.get_gl_dict({
|
self.get_gl_dict({
|
||||||
"account": tax.account_head,
|
"account": tax.account_head,
|
||||||
"against": self.customer,
|
"against": self.customer,
|
||||||
"credit": flt(tax.base_tax_amount_after_discount_amount),
|
"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
|
"cost_center": tax.cost_center
|
||||||
})
|
}, account_currency)
|
||||||
)
|
)
|
||||||
|
|
||||||
def make_item_gl_entries(self, gl_entries):
|
def make_item_gl_entries(self, gl_entries):
|
||||||
# income account gl entries
|
# income account gl entries
|
||||||
for item in self.get("items"):
|
for item in self.get("items"):
|
||||||
if flt(item.base_net_amount):
|
if flt(item.base_net_amount):
|
||||||
|
account_currency = frappe.db.get_value("Account", item.income_account, "account_currency")
|
||||||
gl_entries.append(
|
gl_entries.append(
|
||||||
self.get_gl_dict({
|
self.get_gl_dict({
|
||||||
"account": item.income_account,
|
"account": item.income_account,
|
||||||
"against": self.customer,
|
"against": self.customer,
|
||||||
"credit": item.base_net_amount,
|
"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
|
"cost_center": item.cost_center
|
||||||
})
|
}, account_currency)
|
||||||
)
|
)
|
||||||
|
|
||||||
# expense account gl entries
|
# expense account gl entries
|
||||||
@ -546,6 +557,7 @@ class SalesInvoice(SellingController):
|
|||||||
|
|
||||||
def make_pos_gl_entries(self, gl_entries):
|
def make_pos_gl_entries(self, gl_entries):
|
||||||
if cint(self.is_pos) and self.cash_bank_account and self.paid_amount:
|
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
|
# POS, make payment entries
|
||||||
gl_entries.append(
|
gl_entries.append(
|
||||||
self.get_gl_dict({
|
self.get_gl_dict({
|
||||||
@ -553,44 +565,50 @@ class SalesInvoice(SellingController):
|
|||||||
"party_type": "Customer",
|
"party_type": "Customer",
|
||||||
"party": self.customer,
|
"party": self.customer,
|
||||||
"against": self.cash_bank_account,
|
"against": self.cash_bank_account,
|
||||||
"credit": self.paid_amount,
|
"credit": self.base_paid_amount,
|
||||||
"remarks": self.remarks,
|
"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": 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(
|
gl_entries.append(
|
||||||
self.get_gl_dict({
|
self.get_gl_dict({
|
||||||
"account": self.cash_bank_account,
|
"account": self.cash_bank_account,
|
||||||
"against": self.customer,
|
"against": self.customer,
|
||||||
"debit": self.paid_amount,
|
"debit": self.base_paid_amount,
|
||||||
"remarks": self.remarks,
|
"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):
|
def make_write_off_gl_entry(self, gl_entries):
|
||||||
# write off entries, applicable if only pos
|
# write off entries, applicable if only pos
|
||||||
if self.write_off_account and self.write_off_amount:
|
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(
|
gl_entries.append(
|
||||||
self.get_gl_dict({
|
self.get_gl_dict({
|
||||||
"account": self.debit_to,
|
"account": self.debit_to,
|
||||||
"party_type": "Customer",
|
"party_type": "Customer",
|
||||||
"party": self.customer,
|
"party": self.customer,
|
||||||
"against": self.write_off_account,
|
"against": self.write_off_account,
|
||||||
"credit": self.write_off_amount,
|
"credit": self.base_write_off_amount,
|
||||||
"remarks": self.remarks,
|
"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": 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(
|
gl_entries.append(
|
||||||
self.get_gl_dict({
|
self.get_gl_dict({
|
||||||
"account": self.write_off_account,
|
"account": self.write_off_account,
|
||||||
"against": self.customer,
|
"against": self.customer,
|
||||||
"debit": self.write_off_amount,
|
"debit": self.base_write_off_amount,
|
||||||
"remarks": self.remarks,
|
"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
|
"cost_center": self.write_off_cost_center
|
||||||
})
|
}, write_off_account_currency)
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_list_context(context=None):
|
def get_list_context(context=None):
|
||||||
|
@ -7,6 +7,8 @@ import unittest, copy
|
|||||||
from frappe.utils import nowdate, add_days, flt
|
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.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.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):
|
class TestSalesInvoice(unittest.TestCase):
|
||||||
def make(self):
|
def make(self):
|
||||||
@ -401,7 +403,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
jv.cancel()
|
jv.cancel()
|
||||||
self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 561.8)
|
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)
|
set_perpetual_inventory(0)
|
||||||
si = frappe.copy_doc(test_records[1])
|
si = frappe.copy_doc(test_records[1])
|
||||||
si.insert()
|
si.insert()
|
||||||
@ -433,7 +435,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertFalse(gle)
|
self.assertFalse(gle)
|
||||||
|
|
||||||
def test_pos_gl_entry_with_aii(self):
|
def test_pos_gl_entry_with_perpetual_inventory(self):
|
||||||
set_perpetual_inventory()
|
set_perpetual_inventory()
|
||||||
self.make_pos_profile()
|
self.make_pos_profile()
|
||||||
|
|
||||||
@ -442,8 +444,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
pos = copy.deepcopy(test_records[1])
|
pos = copy.deepcopy(test_records[1])
|
||||||
pos["is_pos"] = 1
|
pos["is_pos"] = 1
|
||||||
pos["update_stock"] = 1
|
pos["update_stock"] = 1
|
||||||
# pos["posting_time"] = "12:05"
|
pos["cash_bank_account"] = "_Test Bank - _TC"
|
||||||
pos["cash_bank_account"] = "_Test Account Bank Account - _TC"
|
|
||||||
pos["paid_amount"] = 600.0
|
pos["paid_amount"] = 600.0
|
||||||
|
|
||||||
si = frappe.copy_doc(pos)
|
si = frappe.copy_doc(pos)
|
||||||
@ -474,7 +475,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
[stock_in_hand, 0.0, abs(sle.stock_value_difference)],
|
[stock_in_hand, 0.0, abs(sle.stock_value_difference)],
|
||||||
[pos["items"][0]["expense_account"], abs(sle.stock_value_difference), 0.0],
|
[pos["items"][0]["expense_account"], abs(sle.stock_value_difference), 0.0],
|
||||||
[si.debit_to, 0.0, 600.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)):
|
for i, gle in enumerate(sorted(gl_entries, key=lambda gle: gle.account)):
|
||||||
@ -494,7 +495,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
def make_pos_profile(self):
|
def make_pos_profile(self):
|
||||||
pos_profile = frappe.get_doc({
|
pos_profile = frappe.get_doc({
|
||||||
"cash_bank_account": "_Test Account Bank Account - _TC",
|
"cash_bank_account": "_Test Bank - _TC",
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"cost_center": "_Test Cost Center - _TC",
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
"currency": "INR",
|
"currency": "INR",
|
||||||
@ -513,7 +514,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
if not frappe.db.exists("POS Profile", "_Test POS Profile"):
|
if not frappe.db.exists("POS Profile", "_Test POS Profile"):
|
||||||
pos_profile.insert()
|
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()
|
set_perpetual_inventory()
|
||||||
frappe.delete_doc("Account", "_Test Warehouse No Account - _TC")
|
frappe.delete_doc("Account", "_Test Warehouse No Account - _TC")
|
||||||
|
|
||||||
@ -567,7 +568,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
self.assertFalse(gle)
|
self.assertFalse(gle)
|
||||||
set_perpetual_inventory(0)
|
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()
|
set_perpetual_inventory()
|
||||||
|
|
||||||
si = frappe.get_doc(test_records[1])
|
si = frappe.get_doc(test_records[1])
|
||||||
@ -593,7 +594,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
set_perpetual_inventory(0)
|
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()
|
set_perpetual_inventory()
|
||||||
si = frappe.get_doc(test_records[1])
|
si = frappe.get_doc(test_records[1])
|
||||||
si.get("items")[0].item_code = "_Test Non Stock Item"
|
si.get("items")[0].item_code = "_Test Non Stock Item"
|
||||||
@ -660,7 +661,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
where reference_name=%s""", si.name))
|
where reference_name=%s""", si.name))
|
||||||
|
|
||||||
self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account`
|
self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account`
|
||||||
where reference_name=%s and credit=300""", si.name))
|
where reference_name=%s and credit_in_account_currency=300""", si.name))
|
||||||
|
|
||||||
self.assertEqual(si.outstanding_amount, 261.8)
|
self.assertEqual(si.outstanding_amount, 261.8)
|
||||||
|
|
||||||
@ -842,6 +843,79 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
self.assertEquals(si.base_grand_total, 859.44)
|
self.assertEquals(si.base_grand_total, 859.44)
|
||||||
self.assertEquals(si.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):
|
def create_sales_invoice(**args):
|
||||||
si = frappe.new_doc("Sales Invoice")
|
si = frappe.new_doc("Sales Invoice")
|
||||||
@ -856,14 +930,15 @@ def create_sales_invoice(**args):
|
|||||||
si.is_pos = args.is_pos
|
si.is_pos = args.is_pos
|
||||||
si.is_return = args.is_return
|
si.is_return = args.is_return
|
||||||
si.return_against = args.return_against
|
si.return_against = args.return_against
|
||||||
si.currency="INR"
|
si.currency=args.currency or "INR"
|
||||||
si.conversion_rate = 1
|
si.conversion_rate = args.conversion_rate or 1
|
||||||
|
|
||||||
si.append("items", {
|
si.append("items", {
|
||||||
"item_code": args.item or args.item_code or "_Test Item",
|
"item_code": args.item or args.item_code or "_Test Item",
|
||||||
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
||||||
"qty": args.qty or 1,
|
"qty": args.qty or 1,
|
||||||
"rate": args.rate or 100,
|
"rate": args.rate or 100,
|
||||||
|
"income_account": "Sales - _TC",
|
||||||
"expense_account": "Cost of Goods Sold - _TC",
|
"expense_account": "Cost of Goods Sold - _TC",
|
||||||
"cost_center": "_Test Cost Center - _TC",
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
"serial_no": args.serial_no
|
"serial_no": args.serial_no
|
||||||
|
@ -117,7 +117,7 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "advance_amount",
|
"oldfieldname": "advance_amount",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "Company:company:default_currency",
|
"options": "party_account_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_width": "120px",
|
"print_width": "120px",
|
||||||
@ -143,7 +143,7 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "allocated_amount",
|
"oldfieldname": "allocated_amount",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "Company:company:default_currency",
|
"options": "party_account_currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_width": "120px",
|
"print_width": "120px",
|
||||||
@ -164,7 +164,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2014-12-25 16:30:19.446500",
|
"modified": "2015-08-21 16:22:28.866049",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice Advance",
|
"name": "Sales Invoice Advance",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"description": "Standard tax template that can be applied to all Sales Transactions. This template can contain list of tax heads and also other expense / income heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Is this Tax included in Basic Rate?: If you check this, it means that this tax will not be shown below the item table, but will be included in the Basic Rate in your main item table. This is useful where you want give a flat price (inclusive of all taxes) price to customers.",
|
"description": "Standard tax template that can be applied to all Sales Transactions. This template can contain list of tax heads and also other expense / income heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Is this Tax included in Basic Rate?: If you check this, it means that this tax will not be shown below the item table, but will be included in the Basic Rate in your main item table. This is useful where you want give a flat price (inclusive of all taxes) price to customers.",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -21,7 +21,7 @@
|
|||||||
"in_filter": 1,
|
"in_filter": 1,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Title",
|
"label": "Title",
|
||||||
"no_copy": 0,
|
"no_copy": 1,
|
||||||
"oldfieldname": "title",
|
"oldfieldname": "title",
|
||||||
"oldfieldtype": "Data",
|
"oldfieldtype": "Data",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
@ -198,7 +198,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-11 12:19:46.488710",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Taxes and Charges Template",
|
"name": "Sales Taxes and Charges Template",
|
||||||
|
@ -31,10 +31,21 @@ def process_gl_map(gl_map, merge_entries=True):
|
|||||||
if flt(entry.debit) < 0:
|
if flt(entry.debit) < 0:
|
||||||
entry.credit = flt(entry.credit) - flt(entry.debit)
|
entry.credit = flt(entry.credit) - flt(entry.debit)
|
||||||
entry.debit = 0.0
|
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:
|
if flt(entry.credit) < 0:
|
||||||
entry.debit = flt(entry.debit) - flt(entry.credit)
|
entry.debit = flt(entry.debit) - flt(entry.credit)
|
||||||
entry.credit = 0.0
|
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
|
return gl_map
|
||||||
|
|
||||||
def merge_similar_entries(gl_map):
|
def merge_similar_entries(gl_map):
|
||||||
@ -45,7 +56,11 @@ def merge_similar_entries(gl_map):
|
|||||||
same_head = check_if_in_list(entry, merged_gl_map)
|
same_head = check_if_in_list(entry, merged_gl_map)
|
||||||
if same_head:
|
if same_head:
|
||||||
same_head.debit = flt(same_head.debit) + flt(entry.debit)
|
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 = 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:
|
else:
|
||||||
merged_gl_map.append(entry)
|
merged_gl_map.append(entry)
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ erpnext.AccountsChart = Class.extend({
|
|||||||
var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr";
|
var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr";
|
||||||
if (me.ctype == 'Account' && node.data && node.data.balance!==undefined) {
|
if (me.ctype == 'Account' && node.data && node.data.balance!==undefined) {
|
||||||
$('<span class="balance-area pull-right text-muted small">'
|
$('<span class="balance-area pull-right text-muted small">'
|
||||||
+ format_currency(Math.abs(node.data.balance), node.data.currency)
|
+ format_currency(Math.abs(node.data.balance), node.data.account_currency)
|
||||||
+ " " + dr_or_cr
|
+ " " + dr_or_cr
|
||||||
+ '</span>').insertBefore(node.$ul);
|
+ '</span>').insertBefore(node.$ul);
|
||||||
}
|
}
|
||||||
@ -214,7 +214,8 @@ erpnext.AccountsChart = Class.extend({
|
|||||||
'Income Account', 'Tax', 'Chargeable', 'Temporary'].join('\n'),
|
'Income Account', 'Tax', 'Chargeable', 'Temporary'].join('\n'),
|
||||||
description: __("Optional. This setting will be used to filter in various transactions.") },
|
description: __("Optional. This setting will be used to filter in various transactions.") },
|
||||||
{fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate')},
|
{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"}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -21,8 +21,7 @@ def get_children():
|
|||||||
|
|
||||||
# root
|
# root
|
||||||
if args['parent'] in ("Accounts", "Cost Centers"):
|
if args['parent'] in ("Accounts", "Cost Centers"):
|
||||||
select_cond = ", root_type, report_type" if args["parent"]=="Accounts" else ""
|
select_cond = ", root_type, report_type, account_currency" if ctype=="Account" else ""
|
||||||
|
|
||||||
acc = frappe.db.sql(""" select
|
acc = frappe.db.sql(""" select
|
||||||
name as value, is_group as expandable %s
|
name as value, is_group as expandable %s
|
||||||
from `tab%s`
|
from `tab%s`
|
||||||
@ -35,19 +34,17 @@ def get_children():
|
|||||||
sort_root_accounts(acc)
|
sort_root_accounts(acc)
|
||||||
else:
|
else:
|
||||||
# other
|
# other
|
||||||
|
select_cond = ", account_currency" if ctype=="Account" else ""
|
||||||
acc = frappe.db.sql("""select
|
acc = frappe.db.sql("""select
|
||||||
name as value, is_group as expandable
|
name as value, is_group as expandable %s
|
||||||
from `tab%s`
|
from `tab%s`
|
||||||
where ifnull(parent_%s,'') = %s
|
where ifnull(parent_%s,'') = %s
|
||||||
and docstatus<2
|
and docstatus<2
|
||||||
order by name""" % (ctype, ctype.lower().replace(' ','_'), '%s'),
|
order by name""" % (select_cond, ctype, ctype.lower().replace(' ','_'), '%s'),
|
||||||
args['parent'], as_dict=1)
|
args['parent'], as_dict=1)
|
||||||
|
|
||||||
if ctype == 'Account':
|
if ctype == 'Account':
|
||||||
currency = frappe.db.sql("select default_currency from `tabCompany` where name = %s", company)[0][0]
|
|
||||||
for each in acc:
|
for each in acc:
|
||||||
bal = get_balance_on(each.get("value"))
|
each["balance"] = flt(get_balance_on(each.get("value")))
|
||||||
each["currency"] = currency
|
|
||||||
each["balance"] = flt(bal)
|
|
||||||
|
|
||||||
return acc
|
return acc
|
||||||
|
@ -7,10 +7,13 @@ import frappe
|
|||||||
import datetime
|
import datetime
|
||||||
from frappe import _, msgprint, scrub
|
from frappe import _, msgprint, scrub
|
||||||
from frappe.defaults import get_user_permissions
|
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.address.address import get_address_display
|
||||||
from erpnext.utilities.doctype.contact.contact import get_contact_details
|
from erpnext.utilities.doctype.contact.contact import get_contact_details
|
||||||
|
|
||||||
|
class InvalidCurrency(frappe.ValidationError): pass
|
||||||
|
class InvalidAccountCurrency(frappe.ValidationError): pass
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_party_details(party=None, account=None, party_type="Customer", company=None,
|
def get_party_details(party=None, account=None, party_type="Customer", company=None,
|
||||||
posting_date=None, price_list=None, currency=None, doctype=None):
|
posting_date=None, price_list=None, currency=None, doctype=None):
|
||||||
@ -142,6 +145,60 @@ def set_account_and_due_date(party, account, party_type, company, posting_date,
|
|||||||
}
|
}
|
||||||
return out
|
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()
|
@frappe.whitelist()
|
||||||
def get_party_account(company, party, party_type):
|
def get_party_account(company, party, party_type):
|
||||||
"""Returns the account for the given `party`.
|
"""Returns the account for the given `party`.
|
||||||
|
@ -30,19 +30,40 @@ class ReceivablePayableReport(object):
|
|||||||
if args.get("party_type") == "Supplier":
|
if args.get("party_type") == "Supplier":
|
||||||
columns += [_("Bill No") + "::80", _("Bill Date") + ":Date:80"]
|
columns += [_("Bill No") + "::80", _("Bill Date") + ":Date:80"]
|
||||||
|
|
||||||
columns += [_("Invoiced Amount") + ":Currency:100", _("Paid Amount") + ":Currency:100",
|
for label in ("Invoiced Amount", "Paid Amount", "Outstanding Amount"):
|
||||||
_("Outstanding Amount") + ":Currency:100", _("Age") + ":Int:50",
|
columns.append({
|
||||||
"0-" + str(self.filters.range1) + ":Currency:100",
|
"label": label,
|
||||||
str(self.filters.range1) + "-" + str(self.filters.range2) + ":Currency:100",
|
"fieldtype": "Currency",
|
||||||
str(self.filters.range2) + "-" + str(self.filters.range3) + ":Currency:100",
|
"options": "currency",
|
||||||
str(self.filters.range3) + _("-Above") + ":Currency:100"
|
"width": 120
|
||||||
]
|
})
|
||||||
|
|
||||||
|
columns += [_("Age (Days)") + "::80"]
|
||||||
|
|
||||||
|
for label in ("0-{range1}".format(**self.filters),
|
||||||
|
"{range1}-{range2}".format(**self.filters),
|
||||||
|
"{range2}-{range3}".format(**self.filters),
|
||||||
|
"{range3}-{above}".format(range3=self.filters.range3, above=_("Above"))):
|
||||||
|
columns.append({
|
||||||
|
"label": label,
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": "currency",
|
||||||
|
"width": 120
|
||||||
|
})
|
||||||
|
|
||||||
if args.get("party_type") == "Customer":
|
if args.get("party_type") == "Customer":
|
||||||
columns += [_("Territory") + ":Link/Territory:80"]
|
columns += [_("Territory") + ":Link/Territory:80"]
|
||||||
if args.get("party_type") == "Supplier":
|
if args.get("party_type") == "Supplier":
|
||||||
columns += [_("Supplier Type") + ":Link/Supplier Type:80"]
|
columns += [_("Supplier Type") + ":Link/Supplier Type:80"]
|
||||||
columns += [_("Remarks") + "::200"]
|
columns += [
|
||||||
|
{
|
||||||
|
"fieldname": "currency",
|
||||||
|
"label": _("Currency"),
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"width": 100,
|
||||||
|
},
|
||||||
|
_("Remarks") + "::200"
|
||||||
|
]
|
||||||
|
|
||||||
return columns
|
return columns
|
||||||
|
|
||||||
@ -55,6 +76,8 @@ class ReceivablePayableReport(object):
|
|||||||
|
|
||||||
future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type"))
|
future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type"))
|
||||||
|
|
||||||
|
company_currency = frappe.db.get_value("Company", self.filters.get("company"), "default_currency")
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
for gle in self.get_entries_till(self.filters.report_date, args.get("party_type")):
|
for gle in self.get_entries_till(self.filters.report_date, args.get("party_type")):
|
||||||
if self.is_receivable_or_payable(gle, dr_or_cr, future_vouchers):
|
if self.is_receivable_or_payable(gle, dr_or_cr, future_vouchers):
|
||||||
@ -91,10 +114,16 @@ class ReceivablePayableReport(object):
|
|||||||
|
|
||||||
# customer territory / supplier type
|
# customer territory / supplier type
|
||||||
if args.get("party_type") == "Customer":
|
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":
|
if args.get("party_type") == "Supplier":
|
||||||
row += [self.get_supplier_type(gle.party), gle.remarks]
|
row += [self.get_supplier_type(gle.party)]
|
||||||
|
|
||||||
|
if self.filters.get(scrub(args.get("party_type"))):
|
||||||
|
row.append(gle.account_currency)
|
||||||
|
else:
|
||||||
|
row.append(company_currency)
|
||||||
|
|
||||||
|
row.append(gle.remarks)
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
@ -171,10 +200,17 @@ class ReceivablePayableReport(object):
|
|||||||
def get_gl_entries(self, party_type):
|
def get_gl_entries(self, party_type):
|
||||||
if not hasattr(self, "gl_entries"):
|
if not hasattr(self, "gl_entries"):
|
||||||
conditions, values = self.prepare_conditions(party_type)
|
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`
|
if self.filters.get(scrub(party_type)):
|
||||||
where docstatus < 2 and party_type=%s {0} order by posting_date, party"""
|
select_fields = "debit_in_account_currency as debit, credit_in_account_currency as credit"
|
||||||
.format(conditions), values, as_dict=True)
|
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
|
return self.gl_entries
|
||||||
|
|
||||||
|
@ -23,7 +23,8 @@ def execute(filters=None):
|
|||||||
total_debit += flt(d[2])
|
total_debit += flt(d[2])
|
||||||
total_credit += flt(d[3])
|
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
|
from `tabJournal Entry Account` jvd, `tabJournal Entry` jv
|
||||||
where jvd.parent = jv.name and jv.docstatus=1 and jvd.account=%s
|
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'
|
and jv.posting_date > %s and jv.clearance_date <= %s and ifnull(jv.is_opening, 'No') = 'No'
|
||||||
@ -38,7 +39,7 @@ def execute(filters=None):
|
|||||||
data += [
|
data += [
|
||||||
get_balance_row(_("System Balance"), balance_as_per_system),
|
get_balance_row(_("System Balance"), balance_as_per_system),
|
||||||
[""]*len(columns),
|
[""]*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),
|
get_balance_row(_("Amounts not reflected in system"), amounts_not_reflected_in_system),
|
||||||
[""]*len(columns),
|
[""]*len(columns),
|
||||||
get_balance_row(_("Expected balance as per bank"), bank_bal)
|
get_balance_row(_("Expected balance as per bank"), bank_bal)
|
||||||
@ -49,13 +50,14 @@ def execute(filters=None):
|
|||||||
def get_columns():
|
def get_columns():
|
||||||
return [_("Posting Date") + ":Date:100", _("Journal Entry") + ":Link/Journal Entry:220",
|
return [_("Posting Date") + ":Date:100", _("Journal Entry") + ":Link/Journal Entry:220",
|
||||||
_("Debit") + ":Currency:120", _("Credit") + ":Currency:120",
|
_("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):
|
def get_entries(filters):
|
||||||
entries = frappe.db.sql("""select
|
entries = frappe.db.sql("""select
|
||||||
jv.posting_date, jv.name, jvd.debit, jvd.credit,
|
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.against_account, jv.cheque_no, jv.cheque_date, jv.clearance_date, jvd.account_currency
|
||||||
from
|
from
|
||||||
`tabJournal Entry Account` jvd, `tabJournal Entry` jv
|
`tabJournal Entry Account` jvd, `tabJournal Entry` jv
|
||||||
where jvd.parent = jv.name and jv.docstatus=1
|
where jvd.parent = jv.name and jv.docstatus=1
|
||||||
@ -68,6 +70,6 @@ def get_entries(filters):
|
|||||||
|
|
||||||
def get_balance_row(label, amount):
|
def get_balance_row(label, amount):
|
||||||
if amount > 0:
|
if amount > 0:
|
||||||
return ["", '"' + label + '"', amount, 0, "", "", "", ""]
|
return ["", '"' + label + '"', amount, 0, "", "", "", "", ""]
|
||||||
else:
|
else:
|
||||||
return ["", '"' + label + '"', 0, abs(amount), "", "", "", ""]
|
return ["", '"' + label + '"', 0, abs(amount), "", "", "", "", ""]
|
||||||
|
@ -12,9 +12,12 @@ def execute(filters=None):
|
|||||||
account_details.setdefault(acc.name, acc)
|
account_details.setdefault(acc.name, acc)
|
||||||
|
|
||||||
validate_filters(filters, account_details)
|
validate_filters(filters, account_details)
|
||||||
|
|
||||||
validate_party(filters)
|
validate_party(filters)
|
||||||
|
|
||||||
columns = get_columns()
|
filters = set_account_currency(filters)
|
||||||
|
|
||||||
|
columns = get_columns(filters)
|
||||||
|
|
||||||
res = get_result(filters, account_details)
|
res = get_result(filters, account_details)
|
||||||
|
|
||||||
@ -44,35 +47,76 @@ def validate_party(filters):
|
|||||||
elif not frappe.db.exists(party_type, party):
|
elif not frappe.db.exists(party_type, party):
|
||||||
frappe.throw(_("Invalid {0}: {1}").format(party_type, party))
|
frappe.throw(_("Invalid {0}: {1}").format(party_type, party))
|
||||||
|
|
||||||
def get_columns():
|
def set_account_currency(filters):
|
||||||
return [_("Posting Date") + ":Date:90", _("Account") + ":Link/Account:200",
|
if not (filters.get("account") or filters.get("party")):
|
||||||
_("Debit") + ":Float:100", _("Credit") + ":Float:100",
|
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",
|
_("Voucher Type") + "::120", _("Voucher No") + ":Dynamic Link/Voucher Type:160",
|
||||||
_("Against Account") + "::120", _("Party Type") + "::80", _("Party") + "::150",
|
_("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):
|
def get_result(filters, account_details):
|
||||||
gl_entries = get_gl_entries(filters)
|
gl_entries = get_gl_entries(filters)
|
||||||
|
|
||||||
data = get_data_with_opening_closing(filters, account_details, gl_entries)
|
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
|
return result
|
||||||
|
|
||||||
def get_gl_entries(filters):
|
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" \
|
group_by_condition = "group by voucher_type, voucher_no, account, cost_center" \
|
||||||
if filters.get("group_by_voucher") else "group by name"
|
if filters.get("group_by_voucher") else "group by name"
|
||||||
|
|
||||||
gl_entries = frappe.db.sql("""select posting_date, account, party_type, party,
|
gl_entries = frappe.db.sql("""select posting_date, account, party_type, party,
|
||||||
sum(ifnull(debit, 0)) as debit, sum(ifnull(credit, 0)) as credit,
|
sum(ifnull(debit, 0)) as debit, sum(ifnull(credit, 0)) as credit,
|
||||||
voucher_type, voucher_no, cost_center, remarks, against, is_opening
|
voucher_type, voucher_no, cost_center, remarks, against, is_opening {select_fields}
|
||||||
from `tabGL Entry`
|
from `tabGL Entry`
|
||||||
where company=%(company)s {conditions}
|
where company=%(company)s {conditions}
|
||||||
{group_by_condition}
|
{group_by_condition}
|
||||||
order by posting_date, account"""\
|
order by posting_date, account"""\
|
||||||
.format(conditions=get_conditions(filters), group_by_condition=group_by_condition),
|
.format(select_fields=select_fields, conditions=get_conditions(filters),
|
||||||
filters, as_dict=1)
|
group_by_condition=group_by_condition), filters, as_dict=1)
|
||||||
|
|
||||||
return gl_entries
|
return gl_entries
|
||||||
|
|
||||||
@ -105,35 +149,51 @@ def get_data_with_opening_closing(filters, account_details, gl_entries):
|
|||||||
data = []
|
data = []
|
||||||
gle_map = initialize_gle_map(gl_entries)
|
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
|
# Opening for filtered account
|
||||||
if filters.get("account") or filters.get("party"):
|
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():
|
for acc, acc_dict in gle_map.items():
|
||||||
if acc_dict.entries:
|
if acc_dict.entries:
|
||||||
# Opening for individual ledger, if grouped by account
|
# Opening for individual ledger, if grouped by account
|
||||||
if filters.get("group_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
|
data += acc_dict.entries
|
||||||
|
|
||||||
# Totals and closing for individual ledger, if grouped by account
|
# Totals and closing for individual ledger, if grouped by account
|
||||||
if filters.get("group_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,
|
data += [{"account": "'" + _("Totals") + "'", "debit": acc_dict.total_debit,
|
||||||
"credit": acc_dict.total_credit},
|
"credit": acc_dict.total_credit},
|
||||||
get_balance_row(_("Closing (Opening + Totals)"),
|
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
|
# Total debit and credit between from and to date
|
||||||
if total_debit or total_credit:
|
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
|
# Closing for filtered account
|
||||||
if filters.get("account") or filters.get("party"):
|
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)"),
|
data.append(get_balance_row(_("Closing (Opening + Totals)"),
|
||||||
(opening + total_debit - total_credit)))
|
closing, closing_in_account_currency))
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@ -142,23 +202,38 @@ def initialize_gle_map(gl_entries):
|
|||||||
for gle in gl_entries:
|
for gle in gl_entries:
|
||||||
gle_map.setdefault(gle.account, frappe._dict({
|
gle_map.setdefault(gle.account, frappe._dict({
|
||||||
"opening": 0,
|
"opening": 0,
|
||||||
|
"opening_in_account_currency": 0,
|
||||||
"entries": [],
|
"entries": [],
|
||||||
"total_debit": 0,
|
"total_debit": 0,
|
||||||
|
"total_debit_in_account_currency": 0,
|
||||||
"total_credit": 0,
|
"total_credit": 0,
|
||||||
"closing": 0
|
"total_credit_in_account_currency": 0,
|
||||||
|
"closing": 0,
|
||||||
|
"closing_in_account_currency": 0
|
||||||
}))
|
}))
|
||||||
return gle_map
|
return gle_map
|
||||||
|
|
||||||
def get_accountwise_gle(filters, gl_entries, gle_map):
|
def get_accountwise_gle(filters, gl_entries, gle_map):
|
||||||
opening, total_debit, total_credit = 0, 0, 0
|
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)
|
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
|
||||||
for gle in gl_entries:
|
for gle in gl_entries:
|
||||||
amount = flt(gle.debit, 3) - flt(gle.credit, 3)
|
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")) \
|
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"):
|
and (gle.posting_date < from_date or cstr(gle.is_opening) == "Yes"):
|
||||||
|
|
||||||
gle_map[gle.account].opening += amount
|
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"):
|
if filters.get("account") or filters.get("party"):
|
||||||
opening += amount
|
opening += amount
|
||||||
|
if filters.get("show_in_account_currency"):
|
||||||
|
opening_in_account_currency += amount_in_account_currency
|
||||||
|
|
||||||
elif gle.posting_date <= to_date:
|
elif gle.posting_date <= to_date:
|
||||||
gle_map[gle.account].entries.append(gle)
|
gle_map[gle.account].entries.append(gle)
|
||||||
gle_map[gle.account].total_debit += flt(gle.debit, 3)
|
gle_map[gle.account].total_debit += flt(gle.debit, 3)
|
||||||
@ -167,21 +242,43 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
|
|||||||
total_debit += flt(gle.debit, 3)
|
total_debit += flt(gle.debit, 3)
|
||||||
total_credit += flt(gle.credit, 3)
|
total_credit += flt(gle.credit, 3)
|
||||||
|
|
||||||
return opening, total_debit, total_credit, gle_map
|
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)
|
||||||
|
|
||||||
def get_balance_row(label, balance):
|
total_debit_in_account_currency += flt(gle.debit_in_account_currency, 3)
|
||||||
return {
|
total_credit_in_account_currency += flt(gle.credit_in_account_currency, 3)
|
||||||
|
|
||||||
|
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, balance_in_account_currency=None):
|
||||||
|
balance_row = {
|
||||||
"account": "'" + label + "'",
|
"account": "'" + label + "'",
|
||||||
"debit": balance if balance > 0 else 0,
|
"debit": balance if balance > 0 else 0,
|
||||||
"credit": -1*balance if balance < 0 else 0,
|
"credit": -1*balance if balance < 0 else 0
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_result_as_list(data):
|
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, filters):
|
||||||
result = []
|
result = []
|
||||||
for d in data:
|
for d in data:
|
||||||
result.append([d.get("posting_date"), d.get("account"), d.get("debit"),
|
row = [d.get("posting_date"), d.get("account"), d.get("debit"), d.get("credit")]
|
||||||
d.get("credit"), d.get("voucher_type"), d.get("voucher_no"),
|
|
||||||
d.get("against"), d.get("party_type"), d.get("party"),
|
if filters.get("show_in_account_currency"):
|
||||||
d.get("cost_center"), d.get("remarks")])
|
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
|
return result
|
||||||
|
@ -50,7 +50,7 @@ def validate_fiscal_year(date, fiscal_year, label=_("Date"), doc=None):
|
|||||||
throw(_("{0} '{1}' not in Fiscal Year {2}").format(label, formatdate(date), fiscal_year))
|
throw(_("{0} '{1}' not in Fiscal Year {2}").format(label, formatdate(date), fiscal_year))
|
||||||
|
|
||||||
@frappe.whitelist()
|
@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"):
|
if not account and frappe.form_dict.get("account"):
|
||||||
account = frappe.form_dict.get("account")
|
account = frappe.form_dict.get("account")
|
||||||
if not date and frappe.form_dict.get("date"):
|
if not date and frappe.form_dict.get("date"):
|
||||||
@ -94,6 +94,11 @@ def get_balance_on(account=None, date=None, party_type=None, party=None):
|
|||||||
select name from `tabAccount` ac where ac.name = gle.account
|
select name from `tabAccount` ac where ac.name = gle.account
|
||||||
and ac.lft >= %s and ac.rgt <= %s
|
and ac.lft >= %s and ac.rgt <= %s
|
||||||
)""" % (acc.lft, acc.rgt))
|
)""" % (acc.lft, acc.rgt))
|
||||||
|
|
||||||
|
# If group and currency same as company,
|
||||||
|
# always return balance based on debit and credit in company currency
|
||||||
|
if acc.account_currency == frappe.db.get_value("Company", acc.company, "default_currency"):
|
||||||
|
in_account_currency = False
|
||||||
else:
|
else:
|
||||||
cond.append("""gle.account = "%s" """ % (account.replace('"', '\\"'), ))
|
cond.append("""gle.account = "%s" """ % (account.replace('"', '\\"'), ))
|
||||||
|
|
||||||
@ -102,10 +107,14 @@ def get_balance_on(account=None, date=None, party_type=None, party=None):
|
|||||||
(party_type.replace('"', '\\"'), party.replace('"', '\\"')))
|
(party_type.replace('"', '\\"'), party.replace('"', '\\"')))
|
||||||
|
|
||||||
if account or (party_type and party):
|
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("""
|
bal = frappe.db.sql("""
|
||||||
SELECT sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
|
SELECT {0}
|
||||||
FROM `tabGL Entry` gle
|
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
|
# if bal is None, return 0
|
||||||
return flt(bal)
|
return flt(bal)
|
||||||
@ -194,21 +203,26 @@ def update_against_doc(d, jv_obj):
|
|||||||
jv_detail.set("reference_name", d["against_voucher"])
|
jv_detail.set("reference_name", d["against_voucher"])
|
||||||
|
|
||||||
if d['allocated_amt'] < d['unadjusted_amt']:
|
if d['allocated_amt'] < d['unadjusted_amt']:
|
||||||
jvd = frappe.db.sql("""select cost_center, balance, against_account, is_advance
|
jvd = frappe.db.sql("""
|
||||||
from `tabJournal Entry Account` where name = %s""", d['voucher_detail_no'])
|
select cost_center, balance, against_account, is_advance, account_type, exchange_rate
|
||||||
|
from `tabJournal Entry Account` where name = %s
|
||||||
|
""", d['voucher_detail_no'], as_dict=True)
|
||||||
|
|
||||||
# new entry with balance amount
|
# new entry with balance amount
|
||||||
ch = jv_obj.append("accounts")
|
ch = jv_obj.append("accounts")
|
||||||
ch.account = d['account']
|
ch.account = d['account']
|
||||||
|
ch.account_type = jvd[0]['account_type']
|
||||||
|
ch.exchange_rate = jvd[0]['exchange_rate']
|
||||||
ch.party_type = d["party_type"]
|
ch.party_type = d["party_type"]
|
||||||
ch.party = d["party"]
|
ch.party = d["party"]
|
||||||
ch.cost_center = cstr(jvd[0][0])
|
ch.cost_center = cstr(jvd[0]["cost_center"])
|
||||||
ch.balance = flt(jvd[0][1])
|
ch.balance = flt(jvd[0]["balance"])
|
||||||
ch.set(d['dr_or_cr'], flt(d['unadjusted_amt']) - flt(d['allocated_amt']))
|
ch.set(d['dr_or_cr'], flt(d['unadjusted_amt']) - flt(d['allocated_amt']))
|
||||||
ch.set(d['dr_or_cr']== 'debit' and 'credit' or 'debit', 0)
|
ch.set(d['dr_or_cr']== 'debit' and 'credit' or 'debit', 0)
|
||||||
ch.against_account = cstr(jvd[0][2])
|
ch.against_account = cstr(jvd[0]["against_account"])
|
||||||
ch.reference_type = original_reference_type
|
ch.reference_type = original_reference_type
|
||||||
ch.reference_name = original_reference_name
|
ch.reference_name = original_reference_name
|
||||||
ch.is_advance = cstr(jvd[0][3])
|
ch.is_advance = cstr(jvd[0]["is_advance"])
|
||||||
ch.docstatus = 1
|
ch.docstatus = 1
|
||||||
|
|
||||||
# will work as update after submit
|
# will work as update after submit
|
||||||
@ -273,7 +287,7 @@ def get_stock_and_account_difference(account_list=None, posting_date=None):
|
|||||||
and name in (%s)""" % ', '.join(['%s']*len(account_list)), account_list))
|
and name in (%s)""" % ', '.join(['%s']*len(account_list)), account_list))
|
||||||
|
|
||||||
for account, warehouse in account_warehouse.items():
|
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)
|
stock_value = get_stock_value_on(warehouse, posting_date)
|
||||||
if abs(flt(stock_value) - flt(account_balance)) > 0.005:
|
if abs(flt(stock_value) - flt(account_balance)) > 0.005:
|
||||||
difference.setdefault(account, flt(stock_value) - flt(account_balance))
|
difference.setdefault(account, flt(stock_value) - flt(account_balance))
|
||||||
@ -378,12 +392,12 @@ def get_stock_rbnb_difference(posting_date, company):
|
|||||||
|
|
||||||
# Balance as per system
|
# Balance as per system
|
||||||
stock_rbnb_account = "Stock Received But Not Billed - " + frappe.db.get_value("Company", company, "abbr")
|
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
|
# Amount should be credited
|
||||||
return flt(stock_rbnb) + flt(sys_bal)
|
return flt(stock_rbnb) + flt(sys_bal)
|
||||||
|
|
||||||
def get_outstanding_invoices(amount_query, account, party_type, party):
|
def get_outstanding_invoices(amount_query, account, party_type, party, with_journal_entry=True):
|
||||||
all_outstanding_vouchers = []
|
all_outstanding_vouchers = []
|
||||||
outstanding_voucher_list = frappe.db.sql("""
|
outstanding_voucher_list = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
@ -411,6 +425,9 @@ def get_outstanding_invoices(amount_query, account, party_type, party):
|
|||||||
payment_amount = -1*payment_amount[0][0] if payment_amount else 0
|
payment_amount = -1*payment_amount[0][0] if payment_amount else 0
|
||||||
precision = frappe.get_precision("Sales Invoice", "outstanding_amount")
|
precision = frappe.get_precision("Sales Invoice", "outstanding_amount")
|
||||||
|
|
||||||
|
if not with_journal_entry and d.voucher_type=="Journal Entry":
|
||||||
|
continue
|
||||||
|
|
||||||
if d.invoice_amount > payment_amount:
|
if d.invoice_amount > payment_amount:
|
||||||
|
|
||||||
all_outstanding_vouchers.append({
|
all_outstanding_vouchers.append({
|
||||||
|
@ -157,20 +157,9 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
|||||||
},
|
},
|
||||||
add_deduct_tax: function(doc, cdt, cdn) {
|
add_deduct_tax: function(doc, cdt, cdn) {
|
||||||
this.calculate_taxes_and_totals();
|
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');
|
cur_frm.add_fetch('project_name', 'cost_center', 'cost_center');
|
||||||
|
|
||||||
erpnext.buying.get_default_bom = function(frm) {
|
erpnext.buying.get_default_bom = function(frm) {
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Title",
|
"label": "Title",
|
||||||
"no_copy": 0,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -2032,7 +2032,7 @@
|
|||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-11 12:19:55.502661",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order",
|
"name": "Purchase Order",
|
||||||
|
@ -166,7 +166,7 @@ class PurchaseOrder(BuyingController):
|
|||||||
self.update_ordered_qty()
|
self.update_ordered_qty()
|
||||||
|
|
||||||
msgprint(_("Status of {0} {1} is now {2}").format(self.doctype, self.name, status))
|
msgprint(_("Status of {0} {1} is now {2}").format(self.doctype, self.name, status))
|
||||||
self.notify_modified()
|
self.notify_update()
|
||||||
clear_doctype_notifications(self)
|
clear_doctype_notifications(self)
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
|
@ -39,16 +39,12 @@ cur_frm.cscript.make_dashboard = function(doc) {
|
|||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if (in_list(user_roles, "Accounts User") || in_list(user_roles, "Accounts Manager")) {
|
if (in_list(user_roles, "Accounts User") || in_list(user_roles, "Accounts Manager")) {
|
||||||
if(r.message["company_currency"].length == 1) {
|
|
||||||
cur_frm.dashboard.set_headline(
|
cur_frm.dashboard.set_headline(
|
||||||
__("Total Billing This Year: ") + "<b>"
|
__("Total Billing This Year: ") + "<b>"
|
||||||
+ format_currency(r.message.billing_this_year, r.message.company_currency[0])
|
+ format_currency(r.message.billing_this_year, cur_frm.doc.party_account_currency)
|
||||||
+ '</b> / <span class="text-muted">' + __("Total Unpaid") + ": <b>"
|
+ '</b> / <span class="text-muted">' + __("Total Unpaid") + ": <b>"
|
||||||
+ format_currency(r.message.total_unpaid, r.message.company_currency[0])
|
+ format_currency(r.message.total_unpaid, cur_frm.doc.party_account_currency)
|
||||||
+ '</b></span>');
|
+ '</b></span>');
|
||||||
} else {
|
|
||||||
cur_frm.dashboard.set_headline("");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
cur_frm.dashboard.set_badge_count(r.message);
|
cur_frm.dashboard.set_badge_count(r.message);
|
||||||
}
|
}
|
||||||
|
@ -178,7 +178,7 @@
|
|||||||
"ignore_user_permissions": 1,
|
"ignore_user_permissions": 1,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Default Currency",
|
"label": "Billing Currency",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Currency",
|
"options": "Currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
@ -389,8 +389,31 @@
|
|||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"fieldname": "party_account_currency",
|
||||||
"description": "Mention if non-standard receivable account applicable",
|
"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",
|
"fieldname": "accounts",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -511,7 +534,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-17 14:05:24.793609",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Supplier",
|
"name": "Supplier",
|
||||||
|
@ -8,6 +8,7 @@ from frappe import msgprint, _
|
|||||||
from frappe.model.naming import make_autoname
|
from frappe.model.naming import make_autoname
|
||||||
from erpnext.utilities.address_and_contact import load_address_and_contact
|
from erpnext.utilities.address_and_contact import load_address_and_contact
|
||||||
from erpnext.utilities.transaction_base import TransactionBase
|
from erpnext.utilities.transaction_base import TransactionBase
|
||||||
|
from erpnext.accounts.party import validate_accounting_currency, validate_party_account
|
||||||
|
|
||||||
class Supplier(TransactionBase):
|
class Supplier(TransactionBase):
|
||||||
def get_feed(self):
|
def get_feed(self):
|
||||||
@ -45,6 +46,9 @@ class Supplier(TransactionBase):
|
|||||||
if not self.naming_series:
|
if not self.naming_series:
|
||||||
msgprint(_("Series is mandatory"), raise_exception=1)
|
msgprint(_("Series is mandatory"), raise_exception=1)
|
||||||
|
|
||||||
|
validate_accounting_currency(self)
|
||||||
|
validate_party_account(self)
|
||||||
|
|
||||||
def get_contacts(self,nm):
|
def get_contacts(self,nm):
|
||||||
if nm:
|
if nm:
|
||||||
contact_details =frappe.db.convert_to_lists(frappe.db.sql("select name, CONCAT(IFNULL(first_name,''),' ',IFNULL(last_name,'')),contact_no,email_id from `tabContact` where supplier = %s", nm))
|
contact_details =frappe.db.convert_to_lists(frappe.db.sql("select name, CONCAT(IFNULL(first_name,''),' ',IFNULL(last_name,'')),contact_no,email_id from `tabContact` where supplier = %s", nm))
|
||||||
@ -89,9 +93,11 @@ def get_dashboard_info(supplier):
|
|||||||
out[doctype] = frappe.db.get_value(doctype,
|
out[doctype] = frappe.db.get_value(doctype,
|
||||||
{"supplier": supplier, "docstatus": ["!=", 2] }, "count(*)")
|
{"supplier": supplier, "docstatus": ["!=", 2] }, "count(*)")
|
||||||
|
|
||||||
billing_this_year = frappe.db.sql("""select sum(base_grand_total)
|
billing_this_year = frappe.db.sql("""
|
||||||
from `tabPurchase Invoice`
|
select sum(ifnull(credit_in_account_currency, 0)) - sum(ifnull(debit_in_account_currency, 0))
|
||||||
where supplier=%s and docstatus = 1 and fiscal_year = %s""",
|
from `tabGL Entry`
|
||||||
|
where voucher_type='Purchase Invoice' and party_type = 'Supplier'
|
||||||
|
and party=%s and fiscal_year = %s""",
|
||||||
(supplier, frappe.db.get_default("fiscal_year")))
|
(supplier, frappe.db.get_default("fiscal_year")))
|
||||||
|
|
||||||
total_unpaid = frappe.db.sql("""select sum(outstanding_amount)
|
total_unpaid = frappe.db.sql("""select sum(outstanding_amount)
|
||||||
|
@ -1,14 +1,22 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"company": "_Test Company",
|
|
||||||
"doctype": "Supplier",
|
"doctype": "Supplier",
|
||||||
"supplier_name": "_Test Supplier",
|
"supplier_name": "_Test Supplier",
|
||||||
"supplier_type": "_Test Supplier Type"
|
"supplier_type": "_Test Supplier Type"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"company": "_Test Company",
|
|
||||||
"doctype": "Supplier",
|
"doctype": "Supplier",
|
||||||
"supplier_name": "_Test Supplier 1",
|
"supplier_name": "_Test Supplier 1",
|
||||||
"supplier_type": "_Test Supplier Type"
|
"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"
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
]
|
]
|
@ -43,7 +43,7 @@
|
|||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Title",
|
"label": "Title",
|
||||||
"no_copy": 0,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -1554,7 +1554,7 @@
|
|||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-11 12:20:10.684388",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Supplier Quotation",
|
"name": "Supplier Quotation",
|
||||||
|
1
erpnext/change_log/v6/v6_2_0.md
Normal file
1
erpnext/change_log/v6/v6_2_0.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
- **[Multi-currency Accounting](https://manual.erpnext.com/contents/accounts/multi-currency-accounting)**: You can now have an Account in a different currency than your Company's currency
|
@ -14,8 +14,19 @@ from erpnext.controllers.sales_and_purchase_return import validate_return
|
|||||||
force_item_fields = ("item_group", "barcode", "brand", "stock_uom")
|
force_item_fields = ("item_group", "barcode", "brand", "stock_uom")
|
||||||
|
|
||||||
class CustomerFrozen(frappe.ValidationError): pass
|
class CustomerFrozen(frappe.ValidationError): pass
|
||||||
|
class InvalidCurrency(frappe.ValidationError): pass
|
||||||
|
|
||||||
class AccountsController(TransactionBase):
|
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):
|
def validate(self):
|
||||||
if self.get("_action") and self._action != "update_after_submit":
|
if self.get("_action") and self._action != "update_after_submit":
|
||||||
self.set_missing_values(for_validate=True)
|
self.set_missing_values(for_validate=True)
|
||||||
@ -39,6 +50,7 @@ class AccountsController(TransactionBase):
|
|||||||
self.validate_enabled_taxes_and_charges()
|
self.validate_enabled_taxes_and_charges()
|
||||||
|
|
||||||
self.validate_party()
|
self.validate_party()
|
||||||
|
self.validate_currency()
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
if self.meta.get_field("is_recurring"):
|
if self.meta.get_field("is_recurring"):
|
||||||
@ -95,8 +107,6 @@ class AccountsController(TransactionBase):
|
|||||||
|
|
||||||
def set_price_list_currency(self, buying_or_selling):
|
def set_price_list_currency(self, buying_or_selling):
|
||||||
if self.meta.get_field("currency"):
|
if self.meta.get_field("currency"):
|
||||||
company_currency = get_company_currency(self.company)
|
|
||||||
|
|
||||||
# price list part
|
# price list part
|
||||||
fieldname = "selling_price_list" if buying_or_selling.lower() == "selling" \
|
fieldname = "selling_price_list" if buying_or_selling.lower() == "selling" \
|
||||||
else "buying_price_list"
|
else "buying_price_list"
|
||||||
@ -104,22 +114,22 @@ class AccountsController(TransactionBase):
|
|||||||
self.price_list_currency = frappe.db.get_value("Price List",
|
self.price_list_currency = frappe.db.get_value("Price List",
|
||||||
self.get(fieldname), "currency")
|
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
|
self.plc_conversion_rate = 1.0
|
||||||
|
|
||||||
elif not self.plc_conversion_rate:
|
elif not self.plc_conversion_rate:
|
||||||
self.plc_conversion_rate = get_exchange_rate(
|
self.plc_conversion_rate = get_exchange_rate(
|
||||||
self.price_list_currency, company_currency)
|
self.price_list_currency, self.company_currency)
|
||||||
|
|
||||||
# currency
|
# currency
|
||||||
if not self.currency:
|
if not self.currency:
|
||||||
self.currency = self.price_list_currency
|
self.currency = self.price_list_currency
|
||||||
self.conversion_rate = self.plc_conversion_rate
|
self.conversion_rate = self.plc_conversion_rate
|
||||||
elif self.currency == company_currency:
|
elif self.currency == self.company_currency:
|
||||||
self.conversion_rate = 1.0
|
self.conversion_rate = 1.0
|
||||||
elif not self.conversion_rate:
|
elif not self.conversion_rate:
|
||||||
self.conversion_rate = get_exchange_rate(self.currency,
|
self.conversion_rate = get_exchange_rate(self.currency,
|
||||||
company_currency)
|
self.company_currency)
|
||||||
|
|
||||||
def set_missing_item_details(self):
|
def set_missing_item_details(self):
|
||||||
"""set missing item values"""
|
"""set missing item values"""
|
||||||
@ -187,7 +197,7 @@ class AccountsController(TransactionBase):
|
|||||||
if frappe.db.get_value(taxes_and_charges_doctype, self.taxes_and_charges, "disabled"):
|
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))
|
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"""
|
"""this method populates the common properties of a gl entry record"""
|
||||||
gl_dict = frappe._dict({
|
gl_dict = frappe._dict({
|
||||||
'company': self.company,
|
'company': self.company,
|
||||||
@ -198,11 +208,51 @@ class AccountsController(TransactionBase):
|
|||||||
'fiscal_year': self.fiscal_year,
|
'fiscal_year': self.fiscal_year,
|
||||||
'debit': 0,
|
'debit': 0,
|
||||||
'credit': 0,
|
'credit': 0,
|
||||||
|
'debit_in_account_currency': 0,
|
||||||
|
'credit_in_account_currency': 0,
|
||||||
'is_opening': self.get("is_opening") or "No",
|
'is_opening': self.get("is_opening") or "No",
|
||||||
'party_type': None,
|
'party_type': None,
|
||||||
'party': None
|
'party': None
|
||||||
})
|
})
|
||||||
gl_dict.update(args)
|
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") and self.doctype!="Journal Entry"
|
||||||
|
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
|
return gl_dict
|
||||||
|
|
||||||
def clear_unallocated_advances(self, childtype, parentfield):
|
def clear_unallocated_advances(self, childtype, parentfield):
|
||||||
@ -321,9 +371,9 @@ class AccountsController(TransactionBase):
|
|||||||
|
|
||||||
def set_total_advance_paid(self):
|
def set_total_advance_paid(self):
|
||||||
if self.doctype == "Sales Order":
|
if self.doctype == "Sales Order":
|
||||||
dr_or_cr = "credit"
|
dr_or_cr = "credit_in_account_currency"
|
||||||
else:
|
else:
|
||||||
dr_or_cr = "debit"
|
dr_or_cr = "debit_in_account_currency"
|
||||||
|
|
||||||
advance_paid = frappe.db.sql("""
|
advance_paid = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
@ -331,10 +381,9 @@ class AccountsController(TransactionBase):
|
|||||||
from
|
from
|
||||||
`tabJournal Entry Account`
|
`tabJournal Entry Account`
|
||||||
where
|
where
|
||||||
reference_type = %s and
|
reference_type = %s and reference_name = %s
|
||||||
reference_name = %s and
|
and docstatus = 1 and is_advance = "Yes"
|
||||||
docstatus = 1 and is_advance = "Yes" """.format(dr_or_cr=dr_or_cr),
|
""".format(dr_or_cr=dr_or_cr), (self.doctype, self.name))
|
||||||
(self.doctype, self.name))
|
|
||||||
|
|
||||||
if advance_paid:
|
if advance_paid:
|
||||||
advance_paid = flt(advance_paid[0][0], self.precision("advance_paid"))
|
advance_paid = flt(advance_paid[0][0], self.precision("advance_paid"))
|
||||||
@ -357,6 +406,13 @@ class AccountsController(TransactionBase):
|
|||||||
if frozen_accounts_modifier in frappe.get_roles():
|
if frozen_accounts_modifier in frappe.get_roles():
|
||||||
return
|
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
|
party_type = None
|
||||||
if self.meta.get_field("customer"):
|
if self.meta.get_field("customer"):
|
||||||
party_type = 'Customer'
|
party_type = 'Customer'
|
||||||
@ -364,10 +420,20 @@ class AccountsController(TransactionBase):
|
|||||||
elif self.meta.get_field("supplier"):
|
elif self.meta.get_field("supplier"):
|
||||||
party_type = 'Supplier'
|
party_type = 'Supplier'
|
||||||
|
|
||||||
if party_type:
|
party = self.get(party_type.lower()) if party_type else None
|
||||||
party = self.get(party_type.lower())
|
|
||||||
if frappe.db.get_value(party_type, party, "is_frozen"):
|
return party_type, party
|
||||||
frappe.throw("{0} {1} is frozen".format(party_type, party), CustomerFrozen)
|
|
||||||
|
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()
|
@frappe.whitelist()
|
||||||
def get_tax_rate(account_head):
|
def get_tax_rate(account_head):
|
||||||
|
@ -61,7 +61,7 @@ def validate_item_variant_attributes(item, args):
|
|||||||
frappe.throw(_("Value for Attribute {0} must be within the range of {1} to {2} in the increments of {3}")\
|
frappe.throw(_("Value for Attribute {0} must be within the range of {1} to {2} in the increments of {3}")\
|
||||||
.format(attribute, from_range, to_range, increment), InvalidItemAttributeValueError)
|
.format(attribute, from_range, to_range, increment), InvalidItemAttributeValueError)
|
||||||
|
|
||||||
elif value not in attribute_values[attribute]:
|
elif value not in attribute_values.get(attribute, []):
|
||||||
frappe.throw(_("Value {0} for Attribute {1} does not exist in the list of valid Item Attribute Values").format(
|
frappe.throw(_("Value {0} for Attribute {1} does not exist in the list of valid Item Attribute Values").format(
|
||||||
value, attribute))
|
value, attribute))
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ from frappe.utils import nowdate
|
|||||||
|
|
||||||
def get_filters_cond(doctype, filters, conditions):
|
def get_filters_cond(doctype, filters, conditions):
|
||||||
if filters:
|
if filters:
|
||||||
|
flt = filters
|
||||||
if isinstance(filters, dict):
|
if isinstance(filters, dict):
|
||||||
filters = filters.items()
|
filters = filters.items()
|
||||||
flt = []
|
flt = []
|
||||||
|
@ -4,7 +4,7 @@ import frappe.utils
|
|||||||
import frappe.defaults
|
import frappe.defaults
|
||||||
|
|
||||||
from frappe.utils import add_days, cint, cstr, date_diff, flt, getdate, nowdate, \
|
from frappe.utils import add_days, cint, cstr, date_diff, flt, getdate, nowdate, \
|
||||||
get_first_day, get_last_day, comma_and
|
get_first_day, get_last_day, comma_and, split_emails
|
||||||
from frappe.model.naming import make_autoname
|
from frappe.model.naming import make_autoname
|
||||||
|
|
||||||
from frappe import _, msgprint, throw
|
from frappe import _, msgprint, throw
|
||||||
@ -180,8 +180,7 @@ def convert_to_recurring(doc, posting_date):
|
|||||||
|
|
||||||
def validate_notification_email_id(doc):
|
def validate_notification_email_id(doc):
|
||||||
if doc.notification_email_address:
|
if doc.notification_email_address:
|
||||||
email_list = filter(None, [cstr(email).strip() for email in
|
email_list = split_emails(doc.notification_email_address.replace("\n", ""))
|
||||||
doc.notification_email_address.replace("\n", "").split(",")])
|
|
||||||
|
|
||||||
from frappe.utils import validate_email_add
|
from frappe.utils import validate_email_add
|
||||||
for email in email_list:
|
for email in email_list:
|
||||||
|
@ -222,7 +222,7 @@ class StatusUpdater(Document):
|
|||||||
where name='%(name)s'""" % args)
|
where name='%(name)s'""" % args)
|
||||||
|
|
||||||
if args.get("set_modified"):
|
if args.get("set_modified"):
|
||||||
frappe.get_doc(args["target_parent_dt"], name).notify_modified()
|
frappe.get_doc(args["target_parent_dt"], name).notify_update()
|
||||||
|
|
||||||
def update_billing_status_for_zero_amount_refdoc(self, ref_dt):
|
def update_billing_status_for_zero_amount_refdoc(self, ref_dt):
|
||||||
ref_fieldname = ref_dt.lower().replace(" ", "_")
|
ref_fieldname = ref_dt.lower().replace(" ", "_")
|
||||||
|
@ -48,20 +48,20 @@ class StockController(AccountsController):
|
|||||||
self.check_expense_account(detail)
|
self.check_expense_account(detail)
|
||||||
|
|
||||||
gl_list.append(self.get_gl_dict({
|
gl_list.append(self.get_gl_dict({
|
||||||
"account": warehouse_account[sle.warehouse],
|
"account": warehouse_account[sle.warehouse]["name"],
|
||||||
"against": detail.expense_account,
|
"against": detail.expense_account,
|
||||||
"cost_center": detail.cost_center,
|
"cost_center": detail.cost_center,
|
||||||
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
"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({
|
gl_list.append(self.get_gl_dict({
|
||||||
"account": detail.expense_account,
|
"account": detail.expense_account,
|
||||||
"against": warehouse_account[sle.warehouse],
|
"against": warehouse_account[sle.warehouse]["name"],
|
||||||
"cost_center": detail.cost_center,
|
"cost_center": detail.cost_center,
|
||||||
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
"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:
|
elif sle.warehouse not in warehouse_with_no_account:
|
||||||
warehouse_with_no_account.append(sle.warehouse)
|
warehouse_with_no_account.append(sle.warehouse)
|
||||||
@ -336,6 +336,9 @@ def get_voucherwise_gl_entries(future_stock_vouchers, posting_date):
|
|||||||
return gl_entries
|
return gl_entries
|
||||||
|
|
||||||
def get_warehouse_account():
|
def get_warehouse_account():
|
||||||
warehouse_account = dict(frappe.db.sql("""select warehouse, name from tabAccount
|
warehouse_account = frappe._dict()
|
||||||
where account_type = 'Warehouse' and ifnull(warehouse, '') != ''"""))
|
|
||||||
|
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
|
return warehouse_account
|
||||||
|
@ -394,17 +394,21 @@ class calculate_taxes_and_totals(object):
|
|||||||
# NOTE:
|
# NOTE:
|
||||||
# write_off_amount is only for POS Invoice
|
# write_off_amount is only for POS Invoice
|
||||||
# total_advance is only for non 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 self.doc.doctype == "Sales Invoice":
|
||||||
if not self.doc.is_return:
|
self.doc.round_floats_in(self.doc, ["paid_amount"])
|
||||||
self.doc.round_floats_in(self.doc, ["base_grand_total", "total_advance", "write_off_amount", "paid_amount"])
|
outstanding_amount = flt(total_amount_to_pay - self.doc.paid_amount, self.doc.precision("outstanding_amount"))
|
||||||
total_amount_to_pay = self.doc.base_grand_total - self.doc.write_off_amount
|
elif self.doc.doctype == "Purchase Invoice":
|
||||||
self.doc.outstanding_amount = flt(total_amount_to_pay - self.doc.total_advance - self.doc.paid_amount,
|
outstanding_amount = flt(total_amount_to_pay, self.doc.precision("outstanding_amount"))
|
||||||
self.doc.precision("outstanding_amount"))
|
|
||||||
|
if self.doc.party_account_currency == self.doc.currency:
|
||||||
|
self.doc.outstanding_amount = outstanding_amount
|
||||||
else:
|
else:
|
||||||
self.doc.round_floats_in(self.doc, ["total_advance", "write_off_amount"])
|
self.doc.outstanding_amount = flt(outstanding_amount * self.doc.conversion_rate,
|
||||||
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.precision("outstanding_amount"))
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Setup",
|
"document_type": "Document",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -808,7 +808,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-08-27 03:26:48.324207",
|
"modified": "2015-09-14 02:57:27.841011",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "Lead",
|
"name": "Lead",
|
||||||
|
@ -20,7 +20,7 @@ class Newsletter(Document):
|
|||||||
group by status""", (self.doctype, self.name))) or None
|
group by status""", (self.doctype, self.name))) or None
|
||||||
|
|
||||||
def test_send(self, doctype="Lead"):
|
def test_send(self, doctype="Lead"):
|
||||||
self.recipients = self.test_email_id.split(",")
|
self.recipients = frappe.utils.split_emails(self.test_email_id)
|
||||||
self.send_bulk()
|
self.send_bulk()
|
||||||
frappe.msgprint(_("Scheduled to send to {0}").format(self.test_email_id))
|
frappe.msgprint(_("Scheduled to send to {0}").format(self.test_email_id))
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -20,7 +20,7 @@
|
|||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Title",
|
"label": "Title",
|
||||||
"no_copy": 0,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -62,7 +62,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-07-15 07:18:30.094155",
|
"modified": "2015-09-11 12:20:05.237636",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "Newsletter List",
|
"name": "Newsletter List",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Transaction",
|
"document_type": "Document",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -84,7 +84,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-03-23 04:47:36.505462",
|
"modified": "2015-09-14 02:55:58.113810",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "Newsletter List Subscriber",
|
"name": "Newsletter List Subscriber",
|
||||||
|
@ -185,7 +185,7 @@
|
|||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Title",
|
"label": "Title",
|
||||||
"no_copy": 0,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -889,7 +889,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-11 12:19:38.052900",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "Opportunity",
|
"name": "Opportunity",
|
||||||
|
@ -6,6 +6,7 @@ import frappe, json
|
|||||||
from frappe.utils import cstr, cint
|
from frappe.utils import cstr, cint
|
||||||
from frappe import msgprint, _
|
from frappe import msgprint, _
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
|
from erpnext.setup.utils import get_exchange_rate
|
||||||
|
|
||||||
from erpnext.utilities.transaction_base import TransactionBase
|
from erpnext.utilities.transaction_base import TransactionBase
|
||||||
|
|
||||||
@ -179,7 +180,17 @@ def get_item_details(item_code):
|
|||||||
def make_quotation(source_name, target_doc=None):
|
def make_quotation(source_name, target_doc=None):
|
||||||
def set_missing_values(source, target):
|
def set_missing_values(source, target):
|
||||||
quotation = frappe.get_doc(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("set_missing_values")
|
||||||
quotation.run_method("calculate_taxes_and_totals")
|
quotation.run_method("calculate_taxes_and_totals")
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ blogs.
|
|||||||
"""
|
"""
|
||||||
app_icon = "icon-th"
|
app_icon = "icon-th"
|
||||||
app_color = "#e74c3c"
|
app_color = "#e74c3c"
|
||||||
app_version = "6.1.1"
|
app_version = "6.2.0"
|
||||||
github_link = "https://github.com/frappe/erpnext"
|
github_link = "https://github.com/frappe/erpnext"
|
||||||
|
|
||||||
error_report_email = "support@erpnext.com"
|
error_report_email = "support@erpnext.com"
|
||||||
@ -120,7 +120,7 @@ scheduler_events = {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
default_mail_footer = """<div style="padding: 15px; text-align: center;">
|
default_mail_footer = """<div style="text-align: center;">
|
||||||
<a href="https://erpnext.com?source=via_email_footer" target="_blank" style="color: #8d99a6;">
|
<a href="https://erpnext.com?source=via_email_footer" target="_blank" style="color: #8d99a6;">
|
||||||
Sent via ERPNext
|
Sent via ERPNext
|
||||||
</a>
|
</a>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -91,7 +91,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:53.800359",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Appraisal Template",
|
"name": "Appraisal Template",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -277,7 +277,7 @@
|
|||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:53.875571",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Attendance",
|
"name": "Attendance",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -42,7 +42,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:54.431393",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Branch",
|
"name": "Branch",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -66,7 +66,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:55.387298",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Deduction Type",
|
"name": "Deduction Type",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -65,7 +65,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:55.449257",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Department",
|
"name": "Department",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -42,7 +42,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:55.508901",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Designation",
|
"name": "Designation",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -66,7 +66,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:55.558890",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Earning Type",
|
"name": "Earning Type",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -1893,7 +1893,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:55.671692",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Employee",
|
"name": "Employee",
|
||||||
|
@ -158,8 +158,13 @@ def get_retirement_date(date_of_birth=None):
|
|||||||
import datetime
|
import datetime
|
||||||
ret = {}
|
ret = {}
|
||||||
if date_of_birth:
|
if date_of_birth:
|
||||||
|
try:
|
||||||
dt = getdate(date_of_birth) + datetime.timedelta(21915)
|
dt = getdate(date_of_birth) + datetime.timedelta(21915)
|
||||||
ret = {'date_of_retirement': dt.strftime('%Y-%m-%d')}
|
ret = {'date_of_retirement': dt.strftime('%Y-%m-%d')}
|
||||||
|
except ValueError:
|
||||||
|
# invalid date
|
||||||
|
ret = {}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -42,7 +42,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:56.145539",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Employment Type",
|
"name": "Employment Type",
|
||||||
|
@ -467,7 +467,7 @@
|
|||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Title",
|
"label": "Title",
|
||||||
"no_copy": 0,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@ -536,7 +536,7 @@
|
|||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-11 12:20:16.578324",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Expense Claim",
|
"name": "Expense Claim",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -89,7 +89,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-07-15 08:57:23.069980",
|
"modified": "2015-09-14 02:55:56.204289",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Expense Claim Type",
|
"name": "Expense Claim Type",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -177,7 +177,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-02-05 05:11:39.099428",
|
"modified": "2015-09-14 02:55:56.430032",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Holiday List",
|
"name": "Holiday List",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"description": "Applicant for a Job",
|
"description": "Applicant for a Job",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Transaction",
|
"document_type": "Document",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -191,7 +191,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:57.100488",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Job Applicant",
|
"name": "Job Applicant",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"description": "Description of a Job Opening",
|
"description": "Description of a Job Opening",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Transaction",
|
"document_type": "Document",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -85,7 +85,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:57.210679",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Job Opening",
|
"name": "Job Opening",
|
||||||
|
12
erpnext/hr/doctype/job_opening/test_job_opening.py
Normal file
12
erpnext/hr/doctype/job_opening/test_job_opening.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# See license.txt
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
# test_records = frappe.get_test_records('Job Opening')
|
||||||
|
|
||||||
|
class TestJobOpening(unittest.TestCase):
|
||||||
|
pass
|
@ -8,7 +8,7 @@
|
|||||||
"description": "Apply / Approve Leaves",
|
"description": "Apply / Approve Leaves",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Transaction",
|
"document_type": "Document",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -559,7 +559,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 3,
|
"max_attachments": 3,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:57.427750",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Leave Application",
|
"name": "Leave Application",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"description": "Block Holidays on important days.",
|
"description": "Block Holidays on important days.",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -195,7 +195,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:57.796873",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Leave Block List",
|
"name": "Leave Block List",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -174,7 +174,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:57.897034",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Leave Type",
|
"name": "Leave Type",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"default_print_format": "Offer Letter",
|
"default_print_format": "Offer Letter",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Transaction",
|
"document_type": "Document",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -310,7 +310,7 @@
|
|||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-07-29 05:51:39.841591",
|
"modified": "2015-09-14 02:55:58.358852",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Offer Letter",
|
"name": "Offer Letter",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -39,7 +39,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-03-10 18:19:23.032194",
|
"modified": "2015-09-14 02:55:58.508655",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Offer Term",
|
"name": "Offer Term",
|
||||||
|
@ -147,9 +147,7 @@ cur_frm.fields_dict['project_name'].get_query = function(doc, dt, dn) {
|
|||||||
cur_frm.fields_dict['items'].grid.get_field('item_code').get_query = function(doc) {
|
cur_frm.fields_dict['items'].grid.get_field('item_code').get_query = function(doc) {
|
||||||
return{
|
return{
|
||||||
query: "erpnext.controllers.queries.item_query",
|
query: "erpnext.controllers.queries.item_query",
|
||||||
filters: {
|
filters: [["Item", "name", "!=", doc.item]]
|
||||||
"name": "!" + cstr(doc.item)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -713,7 +713,7 @@
|
|||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:55:54.208705",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "BOM",
|
"name": "BOM",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -127,7 +127,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-02-22 10:24:26.834166",
|
"modified": "2015-09-14 02:55:58.575636",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Operation",
|
"name": "Operation",
|
||||||
|
@ -109,7 +109,7 @@ class ProductionOrder(Document):
|
|||||||
self.update_status(status)
|
self.update_status(status)
|
||||||
self.update_planned_qty()
|
self.update_planned_qty()
|
||||||
frappe.msgprint(_("Production Order status is {0}").format(status))
|
frappe.msgprint(_("Production Order status is {0}").format(status))
|
||||||
self.notify_modified()
|
self.notify_update()
|
||||||
|
|
||||||
|
|
||||||
def update_status(self, status=None):
|
def update_status(self, status=None):
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Master",
|
"document_type": "Setup",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -341,7 +341,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-14 02:56:01.492085",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Workstation",
|
"name": "Workstation",
|
||||||
|
@ -206,3 +206,4 @@ execute:frappe.db.set_value("Stock Settings", None, "automatically_set_serial_no
|
|||||||
execute:frappe.db.sql("""update `tabProject` set percent_complete=round(percent_complete, 2) where percent_complete is not null""")
|
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.fix_outstanding_amount
|
||||||
erpnext.patches.v6_0.fix_planned_qty
|
erpnext.patches.v6_0.fix_planned_qty
|
||||||
|
erpnext.patches.v6_0.multi_currency
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user