Merge branch 'develop' of https://github.com/frappe/erpnext into other_app_acc_dims
This commit is contained in:
commit
7a837170ea
@ -92,6 +92,7 @@
|
|||||||
"cur_page": true,
|
"cur_page": true,
|
||||||
"cur_list": true,
|
"cur_list": true,
|
||||||
"cur_tree": true,
|
"cur_tree": true,
|
||||||
|
"cur_pos": true,
|
||||||
"msg_dialog": true,
|
"msg_dialog": true,
|
||||||
"is_null": true,
|
"is_null": true,
|
||||||
"in_list": true,
|
"in_list": true,
|
||||||
@ -149,6 +150,7 @@
|
|||||||
"it": true,
|
"it": true,
|
||||||
"context": true,
|
"context": true,
|
||||||
"before": true,
|
"before": true,
|
||||||
"beforeEach": true
|
"beforeEach": true,
|
||||||
|
"onScan": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
.github/helper/documentation.py
vendored
4
.github/helper/documentation.py
vendored
@ -21,8 +21,8 @@ def docs_link_exists(body):
|
|||||||
if word.startswith('http') and uri_validator(word):
|
if word.startswith('http') and uri_validator(word):
|
||||||
parsed_url = urlparse(word)
|
parsed_url = urlparse(word)
|
||||||
if parsed_url.netloc == "github.com":
|
if parsed_url.netloc == "github.com":
|
||||||
_, org, repo, _type, ref = parsed_url.path.split('/')
|
parts = parsed_url.path.split('/')
|
||||||
if org == "frappe" and repo in docs_repos:
|
if len(parts) == 5 and parts[1] == "frappe" and parts[2] in docs_repos:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
10
.github/helper/translation.py
vendored
10
.github/helper/translation.py
vendored
@ -2,7 +2,7 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
errors_encounter = 0
|
errors_encounter = 0
|
||||||
pattern = re.compile(r"_\(([\"']{,3})(?P<message>((?!\1).)*)\1(\s*,\s*context\s*=\s*([\"'])(?P<py_context>((?!\5).)*)\5)*(\s*,\s*(.)*?\s*(,\s*([\"'])(?P<js_context>((?!\11).)*)\11)*)*\)")
|
pattern = re.compile(r"_\(([\"']{,3})(?P<message>((?!\1).)*)\1(\s*,\s*context\s*=\s*([\"'])(?P<py_context>((?!\5).)*)\5)*(\s*,(\s*?.*?\n*?)*(,\s*([\"'])(?P<js_context>((?!\11).)*)\11)*)*\)")
|
||||||
words_pattern = re.compile(r"_{1,2}\([\"'`]{1,3}.*?[a-zA-Z]")
|
words_pattern = re.compile(r"_{1,2}\([\"'`]{1,3}.*?[a-zA-Z]")
|
||||||
start_pattern = re.compile(r"_{1,2}\([f\"'`]{1,3}")
|
start_pattern = re.compile(r"_{1,2}\([f\"'`]{1,3}")
|
||||||
f_string_pattern = re.compile(r"_\(f[\"']")
|
f_string_pattern = re.compile(r"_\(f[\"']")
|
||||||
@ -28,7 +28,7 @@ for _file in files_to_scan:
|
|||||||
has_f_string = f_string_pattern.search(line)
|
has_f_string = f_string_pattern.search(line)
|
||||||
if has_f_string:
|
if has_f_string:
|
||||||
errors_encounter += 1
|
errors_encounter += 1
|
||||||
print(f'\nF-strings are not supported for translations at line number {line_number + 1}\n{line.strip()[:100]}')
|
print(f'\nF-strings are not supported for translations at line number {line_number}\n{line.strip()[:100]}')
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
@ -36,7 +36,7 @@ for _file in files_to_scan:
|
|||||||
match = pattern.search(line)
|
match = pattern.search(line)
|
||||||
error_found = False
|
error_found = False
|
||||||
|
|
||||||
if not match and line.endswith(',\n'):
|
if not match and line.endswith((',\n', '[\n')):
|
||||||
# concat remaining text to validate multiline pattern
|
# concat remaining text to validate multiline pattern
|
||||||
line = "".join(file_lines[line_number - 1:])
|
line = "".join(file_lines[line_number - 1:])
|
||||||
line = line[start_matches.start() + 1:]
|
line = line[start_matches.start() + 1:]
|
||||||
@ -44,11 +44,11 @@ for _file in files_to_scan:
|
|||||||
|
|
||||||
if not match:
|
if not match:
|
||||||
error_found = True
|
error_found = True
|
||||||
print(f'\nTranslation syntax error at line number {line_number + 1}\n{line.strip()[:100]}')
|
print(f'\nTranslation syntax error at line number {line_number}\n{line.strip()[:100]}')
|
||||||
|
|
||||||
if not error_found and not words_pattern.search(line):
|
if not error_found and not words_pattern.search(line):
|
||||||
error_found = True
|
error_found = True
|
||||||
print(f'\nTranslation is useless because it has no words at line number {line_number + 1}\n{line.strip()[:100]}')
|
print(f'\nTranslation is useless because it has no words at line number {line_number}\n{line.strip()[:100]}')
|
||||||
|
|
||||||
if error_found:
|
if error_found:
|
||||||
errors_encounter += 1
|
errors_encounter += 1
|
||||||
|
9
erpnext/.stylelintrc
Normal file
9
erpnext/.stylelintrc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": ["stylelint-config-recommended"],
|
||||||
|
"plugins": ["stylelint-scss"],
|
||||||
|
"rules": {
|
||||||
|
"at-rule-no-unknown": null,
|
||||||
|
"scss/at-rule-no-unknown": true,
|
||||||
|
"no-descending-specificity": null
|
||||||
|
}
|
||||||
|
}
|
@ -109,7 +109,7 @@ def get_region(company=None):
|
|||||||
'''
|
'''
|
||||||
if company or frappe.flags.company:
|
if company or frappe.flags.company:
|
||||||
return frappe.get_cached_value('Company',
|
return frappe.get_cached_value('Company',
|
||||||
company or frappe.flags.company, 'country')
|
company or frappe.flags.company, 'country')
|
||||||
elif frappe.flags.country:
|
elif frappe.flags.country:
|
||||||
return frappe.flags.country
|
return frappe.flags.country
|
||||||
else:
|
else:
|
||||||
@ -132,16 +132,10 @@ def allow_regional(fn):
|
|||||||
|
|
||||||
return caller
|
return caller
|
||||||
|
|
||||||
def get_last_membership():
|
def get_last_membership(member):
|
||||||
'''Returns last membership if exists'''
|
'''Returns last membership if exists'''
|
||||||
last_membership = frappe.get_all('Membership', 'name,to_date,membership_type',
|
last_membership = frappe.get_all('Membership', 'name,to_date,membership_type',
|
||||||
dict(member=frappe.session.user, paid=1), order_by='to_date desc', limit=1)
|
dict(member=member, paid=1), order_by='to_date desc', limit=1)
|
||||||
|
|
||||||
return last_membership and last_membership[0]
|
if last_membership:
|
||||||
|
return last_membership[0]
|
||||||
def is_member():
|
|
||||||
'''Returns true if the user is still a member'''
|
|
||||||
last_membership = get_last_membership()
|
|
||||||
if last_membership and getdate(last_membership.to_date) > getdate():
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
@ -1,161 +0,0 @@
|
|||||||
{
|
|
||||||
"cards": [
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Accounting Masters",
|
|
||||||
"links": "[\n {\n \"description\": \"Company (not Customer or Supplier) master.\",\n \"label\": \"Company\",\n \"name\": \"Company\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tree of financial accounts.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Chart of Accounts\",\n \"name\": \"Account\",\n \"onboard\": 1,\n \"route\": \"#Tree/Account\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounts Settings\",\n \"name\": \"Accounts Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Financial / accounting year.\",\n \"label\": \"Fiscal Year\",\n \"name\": \"Fiscal Year\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounting Dimension\",\n \"name\": \"Accounting Dimension\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Finance Book\",\n \"name\": \"Finance Book\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounting Period\",\n \"name\": \"Accounting Period\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Payment Terms based on conditions\",\n \"label\": \"Payment Term\",\n \"name\": \"Payment Term\",\n \"type\": \"doctype\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "General Ledger",
|
|
||||||
"links": "[\n {\n \"description\": \"Accounting journal entries.\",\n \"label\": \"Journal Entry\",\n \"name\": \"Journal Entry\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Make journal entries from a template.\",\n \"label\": \"Journal Entry Template\",\n \"name\": \"Journal Entry Template\",\n \"type\": \"doctype\"\n },\n \n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"General Ledger\",\n \"name\": \"General Ledger\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Customer Ledger Summary\",\n \"name\": \"Customer Ledger Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Supplier Ledger Summary\",\n \"name\": \"Supplier Ledger Summary\",\n \"type\": \"report\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Accounts Receivable",
|
|
||||||
"links": "[\n {\n \"description\": \"Bills raised to Customers.\",\n \"label\": \"Sales Invoice\",\n \"name\": \"Sales Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Customer database.\",\n \"label\": \"Customer\",\n \"name\": \"Customer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bank/Cash transactions against party or for internal transfer\",\n \"label\": \"Payment Entry\",\n \"name\": \"Payment Entry\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Payment Request\",\n \"label\": \"Payment Request\",\n \"name\": \"Payment Request\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Receivable\",\n \"name\": \"Accounts Receivable\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Receivable Summary\",\n \"name\": \"Accounts Receivable Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Register\",\n \"name\": \"Sales Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Item-wise Sales Register\",\n \"name\": \"Item-wise Sales Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Sales Order Analysis\",\n \"name\": \"Sales Order Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Delivered Items To Be Billed\",\n \"name\": \"Delivered Items To Be Billed\",\n \"type\": \"report\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Accounts Payable",
|
|
||||||
"links": "[\n {\n \"description\": \"Bills raised by Suppliers.\",\n \"label\": \"Purchase Invoice\",\n \"name\": \"Purchase Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Supplier database.\",\n \"label\": \"Supplier\",\n \"name\": \"Supplier\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bank/Cash transactions against party or for internal transfer\",\n \"label\": \"Payment Entry\",\n \"name\": \"Payment Entry\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Payable\",\n \"name\": \"Accounts Payable\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Payable Summary\",\n \"name\": \"Accounts Payable Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Register\",\n \"name\": \"Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Item-wise Purchase Register\",\n \"name\": \"Item-wise Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Order\"\n ],\n \"doctype\": \"Purchase Order\",\n \"is_query_report\": true,\n \"label\": \"Purchase Order Analysis\",\n \"name\": \"Purchase Order Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Received Items To Be Billed\",\n \"name\": \"Received Items To Be Billed\",\n \"type\": \"report\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Reports",
|
|
||||||
"links": "[\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Trial Balance for Party\",\n \"name\": \"Trial Balance for Party\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Journal Entry\"\n ],\n \"doctype\": \"Journal Entry\",\n \"is_query_report\": true,\n \"label\": \"Payment Period Based On Invoice Date\",\n \"name\": \"Payment Period Based On Invoice Date\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Partners Commission\",\n \"name\": \"Sales Partners Commission\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customer Credit Balance\",\n \"name\": \"Customer Credit Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Payment Summary\",\n \"name\": \"Sales Payment Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Address\"\n ],\n \"doctype\": \"Address\",\n \"is_query_report\": true,\n \"label\": \"Address And Contacts\",\n \"name\": \"Address And Contacts\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"DATEV Export\",\n \"name\": \"DATEV\",\n \"type\": \"report\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Financial Statements",
|
|
||||||
"links": "[\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Trial Balance\",\n \"name\": \"Trial Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Profit and Loss Statement\",\n \"name\": \"Profit and Loss Statement\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Balance Sheet\",\n \"name\": \"Balance Sheet\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Cash Flow\",\n \"name\": \"Cash Flow\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Consolidated Financial Statement\",\n \"name\": \"Consolidated Financial Statement\",\n \"type\": \"report\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Multi Currency",
|
|
||||||
"links": "[\n {\n \"description\": \"Enable / disable currencies.\",\n \"label\": \"Currency\",\n \"name\": \"Currency\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Currency exchange rate master.\",\n \"label\": \"Currency Exchange\",\n \"name\": \"Currency Exchange\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Exchange Rate Revaluation master.\",\n \"label\": \"Exchange Rate Revaluation\",\n \"name\": \"Exchange Rate Revaluation\",\n \"type\": \"doctype\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Settings",
|
|
||||||
"links": "[\n {\n \"description\": \"Setup Gateway accounts.\",\n \"label\": \"Payment Gateway Account\",\n \"name\": \"Payment Gateway Account\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Template of terms or contract.\",\n \"label\": \"Terms and Conditions Template\",\n \"name\": \"Terms and Conditions\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"e.g. Bank, Cash, Credit Card\",\n \"label\": \"Mode of Payment\",\n \"name\": \"Mode of Payment\",\n \"type\": \"doctype\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Bank Statement",
|
|
||||||
"links": "[\n {\n \"label\": \"Bank\",\n \"name\": \"Bank\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Account\",\n \"name\": \"Bank Account\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Clearance\",\n \"name\": \"Bank Clearance\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Reconciliation\",\n \"name\": \"bank-reconciliation\",\n \"type\": \"page\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Bank Reconciliation Statement\",\n \"name\": \"Bank Reconciliation Statement\",\n \"type\": \"report\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Subscription Management",
|
|
||||||
"links": "[\n {\n \"label\": \"Subscription Plan\",\n \"name\": \"Subscription Plan\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Subscription\",\n \"name\": \"Subscription\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Subscription Settings\",\n \"name\": \"Subscription Settings\",\n \"type\": \"doctype\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Goods and Services Tax (GST India)",
|
|
||||||
"links": "[\n {\n \"label\": \"GST Settings\",\n \"name\": \"GST Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"GST HSN Code\",\n \"name\": \"GST HSN Code\",\n \"type\": \"doctype\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GSTR-1\",\n \"name\": \"GSTR-1\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GSTR-2\",\n \"name\": \"GSTR-2\",\n \"type\": \"report\"\n },\n {\n \"label\": \"GSTR 3B Report\",\n \"name\": \"GSTR 3B Report\",\n \"type\": \"doctype\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Sales Register\",\n \"name\": \"GST Sales Register\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Purchase Register\",\n \"name\": \"GST Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Itemised Sales Register\",\n \"name\": \"GST Itemised Sales Register\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Itemised Purchase Register\",\n \"name\": \"GST Itemised Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"country\": \"India\",\n \"description\": \"C-Form records\",\n \"label\": \"C-Form\",\n \"name\": \"C-Form\",\n \"type\": \"doctype\"\n },\n {\n \"country\": \"India\",\n \"label\": \"Lower Deduction Certificate\",\n \"name\": \"Lower Deduction Certificate\",\n \"type\": \"doctype\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Share Management",
|
|
||||||
"links": "[\n {\n \"description\": \"List of available Shareholders with folio numbers\",\n \"label\": \"Shareholder\",\n \"name\": \"Shareholder\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"List of all share transactions\",\n \"label\": \"Share Transfer\",\n \"name\": \"Share Transfer\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Share Transfer\"\n ],\n \"doctype\": \"Share Transfer\",\n \"is_query_report\": true,\n \"label\": \"Share Ledger\",\n \"name\": \"Share Ledger\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Share Transfer\"\n ],\n \"doctype\": \"Share Transfer\",\n \"is_query_report\": true,\n \"label\": \"Share Balance\",\n \"name\": \"Share Balance\",\n \"type\": \"report\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Cost Center and Budgeting",
|
|
||||||
"links": "[\n {\n \"description\": \"Tree of financial Cost Centers.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Chart of Cost Centers\",\n \"name\": \"Cost Center\",\n \"route\": \"#Tree/Cost Center\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Define budget for a financial year.\",\n \"label\": \"Budget\",\n \"name\": \"Budget\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounting Dimension\",\n \"name\": \"Accounting Dimension\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Cost Center\"\n ],\n \"doctype\": \"Cost Center\",\n \"is_query_report\": true,\n \"label\": \"Budget Variance Report\",\n \"name\": \"Budget Variance Report\",\n \"type\": \"report\"\n },\n {\n \"description\": \"Seasonality for setting budgets, targets etc.\",\n \"label\": \"Monthly Distribution\",\n \"name\": \"Monthly Distribution\",\n \"type\": \"doctype\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Opening and Closing",
|
|
||||||
"links": "[\n {\n \"label\": \"Opening Invoice Creation Tool\",\n \"name\": \"Opening Invoice Creation Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Chart of Accounts Importer\",\n \"name\": \"Chart of Accounts Importer\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Close Balance Sheet and book Profit or Loss.\",\n \"label\": \"Period Closing Voucher\",\n \"name\": \"Period Closing Voucher\",\n \"type\": \"doctype\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Taxes",
|
|
||||||
"links": "[\n {\n \"description\": \"Tax template for selling transactions.\",\n \"label\": \"Sales Taxes and Charges Template\",\n \"name\": \"Sales Taxes and Charges Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax template for buying transactions.\",\n \"label\": \"Purchase Taxes and Charges Template\",\n \"name\": \"Purchase Taxes and Charges Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax template for item tax rates.\",\n \"label\": \"Item Tax Template\",\n \"name\": \"Item Tax Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax Category for overriding tax rates.\",\n \"label\": \"Tax Category\",\n \"name\": \"Tax Category\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax Rule for transactions.\",\n \"label\": \"Tax Rule\",\n \"name\": \"Tax Rule\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax Withholding rates to be applied on transactions.\",\n \"label\": \"Tax Withholding Category\",\n \"name\": \"Tax Withholding Category\",\n \"type\": \"doctype\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Profitability",
|
|
||||||
"links": "[\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Gross Profit\",\n \"name\": \"Gross Profit\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Profitability Analysis\",\n \"name\": \"Profitability Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Invoice Trends\",\n \"name\": \"Sales Invoice Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Invoice Trends\",\n \"name\": \"Purchase Invoice Trends\",\n \"type\": \"report\"\n }\n]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Value-Added Tax (VAT UAE)",
|
|
||||||
"links": "[\n {\n \"country\": \"United Arab Emirates\",\n \"label\": \"UAE VAT Settings\",\n \"name\": \"UAE VAT Settings\",\n \"type\": \"doctype\"\n },\n {\n \"country\": \"United Arab Emirates\",\n \"is_query_report\": true,\n \"label\": \"UAE VAT 201\",\n \"name\": \"UAE VAT 201\",\n \"type\": \"report\"\n }\n\n]"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"category": "Modules",
|
|
||||||
"charts": [
|
|
||||||
{
|
|
||||||
"chart_name": "Profit and Loss",
|
|
||||||
"label": "Profit and Loss"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"creation": "2020-03-02 15:41:59.515192",
|
|
||||||
"developer_mode_only": 0,
|
|
||||||
"disable_user_customization": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "Desk Page",
|
|
||||||
"extends_another_page": 0,
|
|
||||||
"hide_custom": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"is_standard": 1,
|
|
||||||
"label": "Accounting",
|
|
||||||
"modified": "2020-11-11 18:35:11.542909",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Accounts",
|
|
||||||
"name": "Accounting",
|
|
||||||
"onboarding": "Accounts",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"pin_to_bottom": 0,
|
|
||||||
"pin_to_top": 0,
|
|
||||||
"shortcuts": [
|
|
||||||
{
|
|
||||||
"label": "Chart Of Accounts",
|
|
||||||
"link_to": "Account",
|
|
||||||
"type": "DocType"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Sales Invoice",
|
|
||||||
"link_to": "Sales Invoice",
|
|
||||||
"type": "DocType"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Purchase Invoice",
|
|
||||||
"link_to": "Purchase Invoice",
|
|
||||||
"type": "DocType"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Journal Entry",
|
|
||||||
"link_to": "Journal Entry",
|
|
||||||
"type": "DocType"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Payment Entry",
|
|
||||||
"link_to": "Payment Entry",
|
|
||||||
"type": "DocType"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Accounts Receivable",
|
|
||||||
"link_to": "Accounts Receivable",
|
|
||||||
"type": "Report"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "General Ledger",
|
|
||||||
"link_to": "General Ledger",
|
|
||||||
"type": "Report"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Trial Balance",
|
|
||||||
"link_to": "Trial Balance",
|
|
||||||
"type": "Report"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Dashboard",
|
|
||||||
"link_to": "Accounts",
|
|
||||||
"type": "Dashboard"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -120,17 +120,17 @@ frappe.treeview_settings["Account"] = {
|
|||||||
} else {
|
} else {
|
||||||
treeview.new_node();
|
treeview.new_node();
|
||||||
}
|
}
|
||||||
}, "octicon octicon-plus");
|
}, "add");
|
||||||
},
|
},
|
||||||
onrender: function(node) {
|
onrender: function(node) {
|
||||||
if(frappe.boot.user.can_read.indexOf("GL Entry") !== -1){
|
if (frappe.boot.user.can_read.indexOf("GL Entry") !== -1) {
|
||||||
|
|
||||||
// show Dr if positive since balance is calculated as debit - credit else show Cr
|
// show Dr if positive since balance is calculated as debit - credit else show Cr
|
||||||
let balance = node.data.balance_in_account_currency || node.data.balance;
|
let balance = node.data.balance_in_account_currency || node.data.balance;
|
||||||
let dr_or_cr = balance > 0 ? "Dr": "Cr";
|
let dr_or_cr = balance > 0 ? "Dr": "Cr";
|
||||||
|
|
||||||
if (node.data && node.data.balance!==undefined) {
|
if (node.data && node.data.balance!==undefined) {
|
||||||
$('<span class="balance-area pull-right text-muted small">'
|
$('<span class="balance-area pull-right">'
|
||||||
+ (node.data.balance_in_account_currency ?
|
+ (node.data.balance_in_account_currency ?
|
||||||
(format_currency(Math.abs(node.data.balance_in_account_currency),
|
(format_currency(Math.abs(node.data.balance_in_account_currency),
|
||||||
node.data.account_currency) + " / ") : "")
|
node.data.account_currency) + " / ") : "")
|
||||||
|
@ -910,98 +910,8 @@
|
|||||||
},
|
},
|
||||||
"is_group": 1
|
"is_group": 1
|
||||||
},
|
},
|
||||||
"Passiva": {
|
"Passiva - Verbindlichkeiten": {
|
||||||
"root_type": "Liability",
|
"root_type": "Liability",
|
||||||
"A - Eigenkapital": {
|
|
||||||
"account_type": "Equity",
|
|
||||||
"is_group": 1,
|
|
||||||
"I - Gezeichnetes Kapital": {
|
|
||||||
"account_type": "Equity",
|
|
||||||
"is_group": 1,
|
|
||||||
"Gezeichnetes Kapital": {
|
|
||||||
"account_type": "Equity",
|
|
||||||
"account_number": "2900"
|
|
||||||
},
|
|
||||||
"Ausstehende Einlagen auf das gezeichnete Kapital": {
|
|
||||||
"account_number": "2910",
|
|
||||||
"is_group": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"II - Kapitalr\u00fccklage": {
|
|
||||||
"account_type": "Equity",
|
|
||||||
"is_group": 1,
|
|
||||||
"Kapitalr\u00fccklage": {
|
|
||||||
"account_number": "2920"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"III - Gewinnr\u00fccklagen": {
|
|
||||||
"account_type": "Equity",
|
|
||||||
"1 - gesetzliche R\u00fccklage": {
|
|
||||||
"account_type": "Equity",
|
|
||||||
"is_group": 1,
|
|
||||||
"Gesetzliche R\u00fccklage": {
|
|
||||||
"account_number": "2930"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"2 - R\u00fccklage f. Anteile an einem herrschenden oder mehrheitlich beteiligten Unternehmen": {
|
|
||||||
"account_type": "Equity",
|
|
||||||
"is_group": 1
|
|
||||||
},
|
|
||||||
"3 - satzungsm\u00e4\u00dfige R\u00fccklagen": {
|
|
||||||
"account_type": "Equity",
|
|
||||||
"is_group": 1,
|
|
||||||
"Satzungsm\u00e4\u00dfige R\u00fccklagen": {
|
|
||||||
"account_number": "2950"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"4 - andere Gewinnr\u00fccklagen": {
|
|
||||||
"account_type": "Equity",
|
|
||||||
"is_group": 1,
|
|
||||||
"Gewinnr\u00fccklagen aus den \u00dcbergangsvorschriften BilMoG": {
|
|
||||||
"is_group": 1,
|
|
||||||
"Gewinnr\u00fccklagen (BilMoG)": {
|
|
||||||
"account_number": "2963"
|
|
||||||
},
|
|
||||||
"Gewinnr\u00fccklagen aus Zuschreibung Sachanlageverm\u00f6gen (BilMoG)": {
|
|
||||||
"account_number": "2964"
|
|
||||||
},
|
|
||||||
"Gewinnr\u00fccklagen aus Zuschreibung Finanzanlageverm\u00f6gen (BilMoG)": {
|
|
||||||
"account_number": "2965"
|
|
||||||
},
|
|
||||||
"Gewinnr\u00fccklagen aus Aufl\u00f6sung der Sonderposten mit R\u00fccklageanteil (BilMoG)": {
|
|
||||||
"account_number": "2966"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Latente Steuern (Gewinnr\u00fccklage Haben) aus erfolgsneutralen Verrechnungen": {
|
|
||||||
"account_number": "2967"
|
|
||||||
},
|
|
||||||
"Latente Steuern (Gewinnr\u00fccklage Soll) aus erfolgsneutralen Verrechnungen": {
|
|
||||||
"account_number": "2968"
|
|
||||||
},
|
|
||||||
"Rechnungsabgrenzungsposten (Gewinnr\u00fccklage Soll) aus erfolgsneutralen Verrechnungen": {
|
|
||||||
"account_number": "2969"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"is_group": 1
|
|
||||||
},
|
|
||||||
"IV - Gewinnvortrag/Verlustvortrag": {
|
|
||||||
"account_type": "Equity",
|
|
||||||
"is_group": 1,
|
|
||||||
"Gewinnvortrag vor Verwendung": {
|
|
||||||
"account_number": "2970"
|
|
||||||
},
|
|
||||||
"Verlustvortrag vor Verwendung": {
|
|
||||||
"account_number": "2978"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"V - Jahres\u00fcberschu\u00df/Jahresfehlbetrag": {
|
|
||||||
"account_type": "Equity",
|
|
||||||
"is_group": 1
|
|
||||||
},
|
|
||||||
"Einlagen stiller Gesellschafter": {
|
|
||||||
"account_number": "9295"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"B - R\u00fcckstellungen": {
|
"B - R\u00fcckstellungen": {
|
||||||
"is_group": 1,
|
"is_group": 1,
|
||||||
"1 - R\u00fcckstellungen f. Pensionen und \u00e4hnliche Verplicht.": {
|
"1 - R\u00fcckstellungen f. Pensionen und \u00e4hnliche Verplicht.": {
|
||||||
@ -1618,6 +1528,143 @@
|
|||||||
},
|
},
|
||||||
"is_group": 1
|
"is_group": 1
|
||||||
},
|
},
|
||||||
|
"Passiva - Eigenkapital": {
|
||||||
|
"root_type": "Equity",
|
||||||
|
"A - Eigenkapital": {
|
||||||
|
"account_type": "Equity",
|
||||||
|
"is_group": 1,
|
||||||
|
"I - Gezeichnetes Kapital": {
|
||||||
|
"account_type": "Equity",
|
||||||
|
"is_group": 1,
|
||||||
|
"Gezeichnetes Kapital": {
|
||||||
|
"account_number": "2900",
|
||||||
|
"account_type": "Equity"
|
||||||
|
},
|
||||||
|
"Gesch\u00e4ftsguthaben der verbleibenden Mitglieder": {
|
||||||
|
"account_number": "2901"
|
||||||
|
},
|
||||||
|
"Gesch\u00e4ftsguthaben der ausscheidenden Mitglieder": {
|
||||||
|
"account_number": "2902"
|
||||||
|
},
|
||||||
|
"Gesch\u00e4ftsguthaben aus gek\u00fcndigten Gesch\u00e4ftsanteilen": {
|
||||||
|
"account_number": "2903"
|
||||||
|
},
|
||||||
|
"R\u00fcckst\u00e4ndige f\u00e4llige Einzahlungen auf Gesch\u00e4ftsanteile, vermerkt": {
|
||||||
|
"account_number": "2906"
|
||||||
|
},
|
||||||
|
"Gegenkonto R\u00fcckst\u00e4ndige f\u00e4llige Einzahlungen auf Gesch\u00e4ftsanteile, vermerkt": {
|
||||||
|
"account_number": "2907"
|
||||||
|
},
|
||||||
|
"Kapitalerh\u00f6hung aus Gesellschaftsmitteln": {
|
||||||
|
"account_number": "2908"
|
||||||
|
},
|
||||||
|
"Ausstehende Einlagen auf das gezeichnete Kapital, nicht eingefordert": {
|
||||||
|
"account_number": "2910"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"II - Kapitalr\u00fccklage": {
|
||||||
|
"account_type": "Equity",
|
||||||
|
"is_group": 1,
|
||||||
|
"Kapitalr\u00fccklage": {
|
||||||
|
"account_number": "2920"
|
||||||
|
},
|
||||||
|
"Kapitalr\u00fccklage durch Ausgabe von Anteilen \u00fcber Nennbetrag": {
|
||||||
|
"account_number": "2925"
|
||||||
|
},
|
||||||
|
"Kapitalr\u00fccklage durch Ausgabe von Schuldverschreibungen": {
|
||||||
|
"account_number": "2926"
|
||||||
|
},
|
||||||
|
"Kapitalr\u00fccklage durch Zuzahlungen gegen Gew\u00e4hrung eines Vorzugs": {
|
||||||
|
"account_number": "2927"
|
||||||
|
},
|
||||||
|
"Kapitalr\u00fccklage durch Zuzahlungen in das Eigenkapital": {
|
||||||
|
"account_number": "2928"
|
||||||
|
},
|
||||||
|
"Nachschusskapital (Gegenkonto 1299)": {
|
||||||
|
"account_number": "2929"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"III - Gewinnr\u00fccklagen": {
|
||||||
|
"account_type": "Equity",
|
||||||
|
"1 - gesetzliche R\u00fccklage": {
|
||||||
|
"account_type": "Equity",
|
||||||
|
"is_group": 1,
|
||||||
|
"Gesetzliche R\u00fccklage": {
|
||||||
|
"account_number": "2930"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"2 - R\u00fccklage f. Anteile an einem herrschenden oder mehrheitlich beteiligten Unternehmen": {
|
||||||
|
"account_type": "Equity",
|
||||||
|
"is_group": 1,
|
||||||
|
"R\u00fccklage f. Anteile an einem herrschenden oder mehrheitlich beteiligten Unternehmen": {
|
||||||
|
"account_number": "2935"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"3 - satzungsm\u00e4\u00dfige R\u00fccklagen": {
|
||||||
|
"account_type": "Equity",
|
||||||
|
"is_group": 1,
|
||||||
|
"Satzungsm\u00e4\u00dfige R\u00fccklagen": {
|
||||||
|
"account_number": "2950"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"4 - andere Gewinnr\u00fccklagen": {
|
||||||
|
"account_type": "Equity",
|
||||||
|
"is_group": 1,
|
||||||
|
"Andere Gewinnr\u00fccklagen": {
|
||||||
|
"account_number": "2960"
|
||||||
|
},
|
||||||
|
"Andere Gewinnr\u00fccklagen aus dem Erwerb eigener Anteile": {
|
||||||
|
"account_number": "2961"
|
||||||
|
},
|
||||||
|
"Eigenkapitalanteil von Wertaufholungen": {
|
||||||
|
"account_number": "2962"
|
||||||
|
},
|
||||||
|
"Gewinnr\u00fccklagen aus den \u00dcbergangsvorschriften BilMoG": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Gewinnr\u00fccklagen (BilMoG)": {
|
||||||
|
"account_number": "2963"
|
||||||
|
},
|
||||||
|
"Gewinnr\u00fccklagen aus Zuschreibung Sachanlageverm\u00f6gen (BilMoG)": {
|
||||||
|
"account_number": "2964"
|
||||||
|
},
|
||||||
|
"Gewinnr\u00fccklagen aus Zuschreibung Finanzanlageverm\u00f6gen (BilMoG)": {
|
||||||
|
"account_number": "2965"
|
||||||
|
},
|
||||||
|
"Gewinnr\u00fccklagen aus Aufl\u00f6sung der Sonderposten mit R\u00fccklageanteil (BilMoG)": {
|
||||||
|
"account_number": "2966"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Latente Steuern (Gewinnr\u00fccklage Haben) aus erfolgsneutralen Verrechnungen": {
|
||||||
|
"account_number": "2967"
|
||||||
|
},
|
||||||
|
"Latente Steuern (Gewinnr\u00fccklage Soll) aus erfolgsneutralen Verrechnungen": {
|
||||||
|
"account_number": "2968"
|
||||||
|
},
|
||||||
|
"Rechnungsabgrenzungsposten (Gewinnr\u00fccklage Soll) aus erfolgsneutralen Verrechnungen": {
|
||||||
|
"account_number": "2969"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"is_group": 1
|
||||||
|
},
|
||||||
|
"IV - Gewinnvortrag/Verlustvortrag": {
|
||||||
|
"account_type": "Equity",
|
||||||
|
"is_group": 1,
|
||||||
|
"Gewinnvortrag vor Verwendung": {
|
||||||
|
"account_number": "2970"
|
||||||
|
},
|
||||||
|
"Verlustvortrag vor Verwendung": {
|
||||||
|
"account_number": "2978"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"V - Jahres\u00fcberschu\u00df/Jahresfehlbetrag": {
|
||||||
|
"account_type": "Equity",
|
||||||
|
"is_group": 1
|
||||||
|
},
|
||||||
|
"Einlagen stiller Gesellschafter": {
|
||||||
|
"account_number": "9295"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"1 - Umsatzerl\u00f6se": {
|
"1 - Umsatzerl\u00f6se": {
|
||||||
"root_type": "Income",
|
"root_type": "Income",
|
||||||
"is_group": 1,
|
"is_group": 1,
|
||||||
|
@ -245,6 +245,9 @@ def get():
|
|||||||
"account_number": "2200"
|
"account_number": "2200"
|
||||||
},
|
},
|
||||||
_("Duties and Taxes"): {
|
_("Duties and Taxes"): {
|
||||||
|
_("TDS Payable"): {
|
||||||
|
"account_number": "2310"
|
||||||
|
},
|
||||||
"account_type": "Tax",
|
"account_type": "Tax",
|
||||||
"is_group": 1,
|
"is_group": 1,
|
||||||
"account_number": "2300"
|
"account_number": "2300"
|
||||||
|
@ -172,7 +172,7 @@ class TestAccount(unittest.TestCase):
|
|||||||
frappe.delete_doc("Account", doc)
|
frappe.delete_doc("Account", doc)
|
||||||
|
|
||||||
|
|
||||||
def _make_test_records(verbose):
|
def _make_test_records(verbose=None):
|
||||||
from frappe.test_runner import make_test_objects
|
from frappe.test_runner import make_test_objects
|
||||||
|
|
||||||
accounts = [
|
accounts = [
|
||||||
@ -254,7 +254,8 @@ def create_account(**kwargs):
|
|||||||
account_name = kwargs.get('account_name'),
|
account_name = kwargs.get('account_name'),
|
||||||
account_type = kwargs.get('account_type'),
|
account_type = kwargs.get('account_type'),
|
||||||
parent_account = kwargs.get('parent_account'),
|
parent_account = kwargs.get('parent_account'),
|
||||||
company = kwargs.get('company')
|
company = kwargs.get('company'),
|
||||||
|
account_currency = kwargs.get('account_currency')
|
||||||
))
|
))
|
||||||
|
|
||||||
account.save()
|
account.save()
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
|
|
||||||
frappe.ui.form.on('Accounting Dimension', {
|
frappe.ui.form.on('Accounting Dimension', {
|
||||||
|
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
frm.set_query('document_type', () => {
|
frm.set_query('document_type', () => {
|
||||||
let invalid_doctypes = frappe.model.core_doctypes_list;
|
let invalid_doctypes = frappe.model.core_doctypes_list;
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Reference Document Type",
|
"label": "Reference Document Type",
|
||||||
"options": "DocType",
|
"options": "DocType",
|
||||||
|
"read_only_depends_on": "eval:!doc.__islocal",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -48,7 +49,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-03-22 20:34:39.805728",
|
"modified": "2021-02-08 16:37:53.936656",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Accounting Dimension",
|
"name": "Accounting Dimension",
|
||||||
|
@ -29,15 +29,25 @@ class AccountingDimension(Document):
|
|||||||
if exists and self.is_new():
|
if exists and self.is_new():
|
||||||
frappe.throw("Document Type already used as a dimension")
|
frappe.throw("Document Type already used as a dimension")
|
||||||
|
|
||||||
|
if not self.is_new():
|
||||||
|
self.validate_document_type_change()
|
||||||
|
|
||||||
|
def validate_document_type_change(self):
|
||||||
|
doctype_before_save = frappe.db.get_value("Accounting Dimension", self.name, "document_type")
|
||||||
|
if doctype_before_save != self.document_type:
|
||||||
|
message = _("Cannot change Reference Document Type.")
|
||||||
|
message += _("Please create a new Accounting Dimension if required.")
|
||||||
|
frappe.throw(message)
|
||||||
|
|
||||||
def after_insert(self):
|
def after_insert(self):
|
||||||
if frappe.flags.in_test:
|
if frappe.flags.in_test:
|
||||||
make_dimension_in_accounting_doctypes(doc=self)
|
make_dimension_in_accounting_doctypes(doc=self)
|
||||||
else:
|
else:
|
||||||
frappe.enqueue(make_dimension_in_accounting_doctypes, doc=self)
|
frappe.enqueue(make_dimension_in_accounting_doctypes, doc=self, queue='long')
|
||||||
|
|
||||||
def on_trash(self):
|
def on_trash(self):
|
||||||
if frappe.flags.in_test:
|
if frappe.flags.in_test:
|
||||||
delete_accounting_dimension(doc=self)
|
delete_accounting_dimension(doc=self, queue='long')
|
||||||
else:
|
else:
|
||||||
frappe.enqueue(delete_accounting_dimension, doc=self)
|
frappe.enqueue(delete_accounting_dimension, doc=self)
|
||||||
|
|
||||||
@ -48,9 +58,13 @@ class AccountingDimension(Document):
|
|||||||
if not self.fieldname:
|
if not self.fieldname:
|
||||||
self.fieldname = scrub(self.label)
|
self.fieldname = scrub(self.label)
|
||||||
|
|
||||||
|
def on_update(self):
|
||||||
|
frappe.flags.accounting_dimensions = None
|
||||||
|
|
||||||
def make_dimension_in_accounting_doctypes(doc, doclist=None):
|
def make_dimension_in_accounting_doctypes(doc, doclist=None):
|
||||||
if not doclist:
|
if not doclist:
|
||||||
doclist = get_doctypes_with_dimensions()
|
doclist = get_doctypes_with_dimensions()
|
||||||
|
|
||||||
doc_count = len(get_accounting_dimensions())
|
doc_count = len(get_accounting_dimensions())
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
@ -72,6 +86,7 @@ def make_dimension_in_accounting_doctypes(doc, doclist=None):
|
|||||||
|
|
||||||
meta = frappe.get_meta(doctype, cached=False)
|
meta = frappe.get_meta(doctype, cached=False)
|
||||||
fieldnames = [d.fieldname for d in meta.get("fields")]
|
fieldnames = [d.fieldname for d in meta.get("fields")]
|
||||||
|
|
||||||
if df['fieldname'] not in fieldnames:
|
if df['fieldname'] not in fieldnames:
|
||||||
if doctype == "Budget":
|
if doctype == "Budget":
|
||||||
add_dimension_to_budget_doctype(df.copy(), doc)
|
add_dimension_to_budget_doctype(df.copy(), doc)
|
||||||
@ -168,12 +183,14 @@ def get_doctypes_with_dimensions():
|
|||||||
return frappe.get_hooks("accounting_dimension_doctypes")
|
return frappe.get_hooks("accounting_dimension_doctypes")
|
||||||
|
|
||||||
def get_accounting_dimensions(as_list=True):
|
def get_accounting_dimensions(as_list=True):
|
||||||
accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["label", "fieldname", "disabled", "document_type"])
|
if frappe.flags.accounting_dimensions is None:
|
||||||
|
frappe.flags.accounting_dimensions = frappe.get_all("Accounting Dimension",
|
||||||
|
fields=["label", "fieldname", "disabled", "document_type"])
|
||||||
|
|
||||||
if as_list:
|
if as_list:
|
||||||
return [d.fieldname for d in accounting_dimensions]
|
return [d.fieldname for d in frappe.flags.accounting_dimensions]
|
||||||
else:
|
else:
|
||||||
return accounting_dimensions
|
return frappe.flags.accounting_dimensions
|
||||||
|
|
||||||
def get_checks_for_pl_and_bs_accounts():
|
def get_checks_for_pl_and_bs_accounts():
|
||||||
dimensions = frappe.db.sql("""SELECT p.label, p.disabled, p.fieldname, c.default_dimension, c.company, c.mandatory_for_pl, c.mandatory_for_bs
|
dimensions = frappe.db.sql("""SELECT p.label, p.disabled, p.fieldname, c.default_dimension, c.company, c.mandatory_for_pl, c.mandatory_for_bs
|
||||||
@ -195,7 +212,7 @@ def get_dimension_with_children(doctype, dimension):
|
|||||||
return all_dimensions
|
return all_dimensions
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_dimension_filters():
|
def get_dimensions(with_cost_center_and_project=False):
|
||||||
dimension_filters = frappe.db.sql("""
|
dimension_filters = frappe.db.sql("""
|
||||||
SELECT label, fieldname, document_type
|
SELECT label, fieldname, document_type
|
||||||
FROM `tabAccounting Dimension`
|
FROM `tabAccounting Dimension`
|
||||||
@ -206,6 +223,18 @@ def get_dimension_filters():
|
|||||||
FROM `tabAccounting Dimension Detail` c, `tabAccounting Dimension` p
|
FROM `tabAccounting Dimension Detail` c, `tabAccounting Dimension` p
|
||||||
WHERE c.parent = p.name""", as_dict=1)
|
WHERE c.parent = p.name""", as_dict=1)
|
||||||
|
|
||||||
|
if with_cost_center_and_project:
|
||||||
|
dimension_filters.extend([
|
||||||
|
{
|
||||||
|
'fieldname': 'cost_center',
|
||||||
|
'document_type': 'Cost Center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'project',
|
||||||
|
'document_type': 'Project'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
default_dimensions_map = {}
|
default_dimensions_map = {}
|
||||||
for dimension in default_dimensions:
|
for dimension in default_dimensions:
|
||||||
default_dimensions_map.setdefault(dimension.company, {})
|
default_dimensions_map.setdefault(dimension.company, {})
|
||||||
|
@ -11,37 +11,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import d
|
|||||||
|
|
||||||
class TestAccountingDimension(unittest.TestCase):
|
class TestAccountingDimension(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
frappe.set_user("Administrator")
|
create_dimension()
|
||||||
|
|
||||||
if not frappe.db.exists("Accounting Dimension", {"document_type": "Department"}):
|
|
||||||
dimension = frappe.get_doc({
|
|
||||||
"doctype": "Accounting Dimension",
|
|
||||||
"document_type": "Department",
|
|
||||||
}).insert()
|
|
||||||
else:
|
|
||||||
dimension1 = frappe.get_doc("Accounting Dimension", "Department")
|
|
||||||
dimension1.disabled = 0
|
|
||||||
dimension1.save()
|
|
||||||
|
|
||||||
if not frappe.db.exists("Accounting Dimension", {"document_type": "Location"}):
|
|
||||||
dimension1 = frappe.get_doc({
|
|
||||||
"doctype": "Accounting Dimension",
|
|
||||||
"document_type": "Location",
|
|
||||||
})
|
|
||||||
|
|
||||||
dimension1.append("dimension_defaults", {
|
|
||||||
"company": "_Test Company",
|
|
||||||
"reference_document": "Location",
|
|
||||||
"default_dimension": "Block 1",
|
|
||||||
"mandatory_for_bs": 1
|
|
||||||
})
|
|
||||||
|
|
||||||
dimension1.insert()
|
|
||||||
dimension1.save()
|
|
||||||
else:
|
|
||||||
dimension1 = frappe.get_doc("Accounting Dimension", "Location")
|
|
||||||
dimension1.disabled = 0
|
|
||||||
dimension1.save()
|
|
||||||
|
|
||||||
def test_dimension_against_sales_invoice(self):
|
def test_dimension_against_sales_invoice(self):
|
||||||
si = create_sales_invoice(do_not_save=1)
|
si = create_sales_invoice(do_not_save=1)
|
||||||
@ -101,6 +71,38 @@ class TestAccountingDimension(unittest.TestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
disable_dimension()
|
disable_dimension()
|
||||||
|
|
||||||
|
def create_dimension():
|
||||||
|
frappe.set_user("Administrator")
|
||||||
|
|
||||||
|
if not frappe.db.exists("Accounting Dimension", {"document_type": "Department"}):
|
||||||
|
frappe.get_doc({
|
||||||
|
"doctype": "Accounting Dimension",
|
||||||
|
"document_type": "Department",
|
||||||
|
}).insert()
|
||||||
|
else:
|
||||||
|
dimension = frappe.get_doc("Accounting Dimension", "Department")
|
||||||
|
dimension.disabled = 0
|
||||||
|
dimension.save()
|
||||||
|
|
||||||
|
if not frappe.db.exists("Accounting Dimension", {"document_type": "Location"}):
|
||||||
|
dimension1 = frappe.get_doc({
|
||||||
|
"doctype": "Accounting Dimension",
|
||||||
|
"document_type": "Location",
|
||||||
|
})
|
||||||
|
|
||||||
|
dimension1.append("dimension_defaults", {
|
||||||
|
"company": "_Test Company",
|
||||||
|
"reference_document": "Location",
|
||||||
|
"default_dimension": "Block 1",
|
||||||
|
"mandatory_for_bs": 1
|
||||||
|
})
|
||||||
|
|
||||||
|
dimension1.insert()
|
||||||
|
dimension1.save()
|
||||||
|
else:
|
||||||
|
dimension1 = frappe.get_doc("Accounting Dimension", "Location")
|
||||||
|
dimension1.disabled = 0
|
||||||
|
dimension1.save()
|
||||||
|
|
||||||
def disable_dimension():
|
def disable_dimension():
|
||||||
dimension1 = frappe.get_doc("Accounting Dimension", "Department")
|
dimension1 = frappe.get_doc("Accounting Dimension", "Department")
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
frappe.ui.form.on('Accounting Dimension Filter', {
|
||||||
|
refresh: function(frm, cdt, cdn) {
|
||||||
|
if (frm.doc.accounting_dimension) {
|
||||||
|
frm.set_df_property('dimensions', 'label', frm.doc.accounting_dimension, cdn, 'dimension_value');
|
||||||
|
}
|
||||||
|
|
||||||
|
let help_content =
|
||||||
|
`<table class="table table-bordered" style="background-color: #f9f9f9;">
|
||||||
|
<tr><td>
|
||||||
|
<p>
|
||||||
|
<i class="fa fa-hand-right"></i>
|
||||||
|
{{__('Note: On checking Is Mandatory the accounting dimension will become mandatory against that specific account for all accounting transactions')}}
|
||||||
|
</p>
|
||||||
|
</td></tr>
|
||||||
|
</table>`;
|
||||||
|
|
||||||
|
frm.set_df_property('dimension_filter_help', 'options', help_content);
|
||||||
|
},
|
||||||
|
onload: function(frm) {
|
||||||
|
frm.set_query('applicable_on_account', 'accounts', function() {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
'company': frm.doc.company
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
frappe.db.get_list('Accounting Dimension',
|
||||||
|
{fields: ['document_type']}).then((res) => {
|
||||||
|
let options = ['Cost Center', 'Project'];
|
||||||
|
|
||||||
|
res.forEach((dimension) => {
|
||||||
|
options.push(dimension.document_type);
|
||||||
|
});
|
||||||
|
|
||||||
|
frm.set_df_property('accounting_dimension', 'options', options);
|
||||||
|
});
|
||||||
|
|
||||||
|
frm.trigger('setup_filters');
|
||||||
|
},
|
||||||
|
|
||||||
|
setup_filters: function(frm) {
|
||||||
|
let filters = {};
|
||||||
|
|
||||||
|
if (frm.doc.accounting_dimension) {
|
||||||
|
frappe.model.with_doctype(frm.doc.accounting_dimension, function() {
|
||||||
|
if (frappe.model.is_tree(frm.doc.accounting_dimension)) {
|
||||||
|
filters['is_group'] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frappe.meta.has_field(frm.doc.accounting_dimension, 'company')) {
|
||||||
|
filters['company'] = frm.doc.company;
|
||||||
|
}
|
||||||
|
|
||||||
|
frm.set_query('dimension_value', 'dimensions', function() {
|
||||||
|
return {
|
||||||
|
filters: filters
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
accounting_dimension: function(frm) {
|
||||||
|
frm.clear_table("dimensions");
|
||||||
|
let row = frm.add_child("dimensions");
|
||||||
|
row.accounting_dimension = frm.doc.accounting_dimension;
|
||||||
|
frm.refresh_field("dimensions");
|
||||||
|
frm.trigger('setup_filters');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
frappe.ui.form.on('Allowed Dimension', {
|
||||||
|
dimensions_add: function(frm, cdt, cdn) {
|
||||||
|
let row = locals[cdt][cdn];
|
||||||
|
row.accounting_dimension = frm.doc.accounting_dimension;
|
||||||
|
frm.refresh_field("dimensions");
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,158 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"autoname": "format:{accounting_dimension}-{#####}",
|
||||||
|
"creation": "2020-11-08 18:28:11.906146",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"accounting_dimension",
|
||||||
|
"disabled",
|
||||||
|
"column_break_2",
|
||||||
|
"company",
|
||||||
|
"allow_or_restrict",
|
||||||
|
"section_break_4",
|
||||||
|
"accounts",
|
||||||
|
"column_break_6",
|
||||||
|
"dimensions",
|
||||||
|
"section_break_10",
|
||||||
|
"dimension_filter_help"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "accounting_dimension",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Accounting Dimension",
|
||||||
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_2",
|
||||||
|
"fieldtype": "Column Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_4",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"hide_border": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_6",
|
||||||
|
"fieldtype": "Column Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "allow_or_restrict",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Allow Or Restrict Dimension",
|
||||||
|
"options": "Allow\nRestrict",
|
||||||
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "accounts",
|
||||||
|
"fieldtype": "Table",
|
||||||
|
"label": "Applicable On Account",
|
||||||
|
"options": "Applicable On Account",
|
||||||
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.accounting_dimension",
|
||||||
|
"fieldname": "dimensions",
|
||||||
|
"fieldtype": "Table",
|
||||||
|
"label": "Applicable Dimension",
|
||||||
|
"options": "Allowed Dimension",
|
||||||
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "disabled",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Disabled",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "company",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Company",
|
||||||
|
"options": "Company",
|
||||||
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "dimension_filter_help",
|
||||||
|
"fieldtype": "HTML",
|
||||||
|
"label": "Dimension Filter Help",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_10",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2021-02-03 12:04:58.678402",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Accounts",
|
||||||
|
"name": "Accounting Dimension Filter",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "System Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Accounts User",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Accounts Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"quick_entry": 1,
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"track_changes": 1
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright, (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe import _, scrub
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
class AccountingDimensionFilter(Document):
|
||||||
|
def validate(self):
|
||||||
|
self.validate_applicable_accounts()
|
||||||
|
|
||||||
|
def validate_applicable_accounts(self):
|
||||||
|
accounts = frappe.db.sql(
|
||||||
|
"""
|
||||||
|
SELECT a.applicable_on_account as account
|
||||||
|
FROM `tabApplicable On Account` a, `tabAccounting Dimension Filter` d
|
||||||
|
WHERE d.name = a.parent
|
||||||
|
and d.name != %s
|
||||||
|
and d.accounting_dimension = %s
|
||||||
|
""", (self.name, self.accounting_dimension), as_dict=1)
|
||||||
|
|
||||||
|
account_list = [d.account for d in accounts]
|
||||||
|
|
||||||
|
for account in self.get('accounts'):
|
||||||
|
if account.applicable_on_account in account_list:
|
||||||
|
frappe.throw(_("Row {0}: {1} account already applied for Accounting Dimension {2}").format(
|
||||||
|
account.idx, frappe.bold(account.applicable_on_account), frappe.bold(self.accounting_dimension)))
|
||||||
|
|
||||||
|
def get_dimension_filter_map():
|
||||||
|
filters = frappe.db.sql("""
|
||||||
|
SELECT
|
||||||
|
a.applicable_on_account, d.dimension_value, p.accounting_dimension,
|
||||||
|
p.allow_or_restrict, a.is_mandatory
|
||||||
|
FROM
|
||||||
|
`tabApplicable On Account` a, `tabAllowed Dimension` d,
|
||||||
|
`tabAccounting Dimension Filter` p
|
||||||
|
WHERE
|
||||||
|
p.name = a.parent
|
||||||
|
AND p.disabled = 0
|
||||||
|
AND p.name = d.parent
|
||||||
|
""", as_dict=1)
|
||||||
|
|
||||||
|
dimension_filter_map = {}
|
||||||
|
|
||||||
|
for f in filters:
|
||||||
|
f.fieldname = scrub(f.accounting_dimension)
|
||||||
|
|
||||||
|
build_map(dimension_filter_map, f.fieldname, f.applicable_on_account, f.dimension_value,
|
||||||
|
f.allow_or_restrict, f.is_mandatory)
|
||||||
|
|
||||||
|
return dimension_filter_map
|
||||||
|
|
||||||
|
def build_map(map_object, dimension, account, filter_value, allow_or_restrict, is_mandatory):
|
||||||
|
map_object.setdefault((dimension, account), {
|
||||||
|
'allowed_dimensions': [],
|
||||||
|
'is_mandatory': is_mandatory,
|
||||||
|
'allow_or_restrict': allow_or_restrict
|
||||||
|
})
|
||||||
|
map_object[(dimension, account)]['allowed_dimensions'].append(filter_value)
|
@ -0,0 +1,99 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# See license.txt
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
import unittest
|
||||||
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
|
from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import create_dimension, disable_dimension
|
||||||
|
from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError
|
||||||
|
|
||||||
|
class TestAccountingDimensionFilter(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
create_dimension()
|
||||||
|
create_accounting_dimension_filter()
|
||||||
|
self.invoice_list = []
|
||||||
|
|
||||||
|
def test_allowed_dimension_validation(self):
|
||||||
|
si = create_sales_invoice(do_not_save=1)
|
||||||
|
si.items[0].cost_center = 'Main - _TC'
|
||||||
|
si.department = 'Accounts - _TC'
|
||||||
|
si.location = 'Block 1'
|
||||||
|
si.save()
|
||||||
|
|
||||||
|
self.assertRaises(InvalidAccountDimensionError, si.submit)
|
||||||
|
self.invoice_list.append(si)
|
||||||
|
|
||||||
|
def test_mandatory_dimension_validation(self):
|
||||||
|
si = create_sales_invoice(do_not_save=1)
|
||||||
|
si.department = ''
|
||||||
|
si.location = 'Block 1'
|
||||||
|
|
||||||
|
# Test with no department for Sales Account
|
||||||
|
si.items[0].department = ''
|
||||||
|
si.items[0].cost_center = '_Test Cost Center 2 - _TC'
|
||||||
|
si.save()
|
||||||
|
|
||||||
|
self.assertRaises(MandatoryAccountDimensionError, si.submit)
|
||||||
|
self.invoice_list.append(si)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
disable_dimension_filter()
|
||||||
|
disable_dimension()
|
||||||
|
|
||||||
|
for si in self.invoice_list:
|
||||||
|
si.load_from_db()
|
||||||
|
if si.docstatus == 1:
|
||||||
|
si.cancel()
|
||||||
|
|
||||||
|
def create_accounting_dimension_filter():
|
||||||
|
if not frappe.db.get_value('Accounting Dimension Filter',
|
||||||
|
{'accounting_dimension': 'Cost Center'}):
|
||||||
|
frappe.get_doc({
|
||||||
|
'doctype': 'Accounting Dimension Filter',
|
||||||
|
'accounting_dimension': 'Cost Center',
|
||||||
|
'allow_or_restrict': 'Allow',
|
||||||
|
'company': '_Test Company',
|
||||||
|
'accounts': [{
|
||||||
|
'applicable_on_account': 'Sales - _TC',
|
||||||
|
}],
|
||||||
|
'dimensions': [{
|
||||||
|
'accounting_dimension': 'Cost Center',
|
||||||
|
'dimension_value': '_Test Cost Center 2 - _TC'
|
||||||
|
}]
|
||||||
|
}).insert()
|
||||||
|
else:
|
||||||
|
doc = frappe.get_doc('Accounting Dimension Filter', {'accounting_dimension': 'Cost Center'})
|
||||||
|
doc.disabled = 0
|
||||||
|
doc.save()
|
||||||
|
|
||||||
|
if not frappe.db.get_value('Accounting Dimension Filter',
|
||||||
|
{'accounting_dimension': 'Department'}):
|
||||||
|
frappe.get_doc({
|
||||||
|
'doctype': 'Accounting Dimension Filter',
|
||||||
|
'accounting_dimension': 'Department',
|
||||||
|
'allow_or_restrict': 'Allow',
|
||||||
|
'company': '_Test Company',
|
||||||
|
'accounts': [{
|
||||||
|
'applicable_on_account': 'Sales - _TC',
|
||||||
|
'is_mandatory': 1
|
||||||
|
}],
|
||||||
|
'dimensions': [{
|
||||||
|
'accounting_dimension': 'Department',
|
||||||
|
'dimension_value': 'Accounts - _TC'
|
||||||
|
}]
|
||||||
|
}).insert()
|
||||||
|
else:
|
||||||
|
doc = frappe.get_doc('Accounting Dimension Filter', {'accounting_dimension': 'Department'})
|
||||||
|
doc.disabled = 0
|
||||||
|
doc.save()
|
||||||
|
|
||||||
|
def disable_dimension_filter():
|
||||||
|
doc = frappe.get_doc('Accounting Dimension Filter', {'accounting_dimension': 'Cost Center'})
|
||||||
|
doc.disabled = 1
|
||||||
|
doc.save()
|
||||||
|
|
||||||
|
doc = frappe.get_doc('Accounting Dimension Filter', {'accounting_dimension': 'Department'})
|
||||||
|
doc.disabled = 1
|
||||||
|
doc.save()
|
@ -6,3 +6,46 @@ frappe.ui.form.on('Accounts Settings', {
|
|||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frappe.tour['Accounts Settings'] = [
|
||||||
|
{
|
||||||
|
fieldname: "acc_frozen_upto",
|
||||||
|
title: "Accounts Frozen Upto",
|
||||||
|
description: __("Freeze accounting transactions up to specified date, nobody can make/modify entry except the specified Role."),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: "frozen_accounts_modifier",
|
||||||
|
title: "Role Allowed to Set Frozen Accounts & Edit Frozen Entries",
|
||||||
|
description: __("Users with this Role are allowed to set frozen accounts and create/modify accounting entries against frozen accounts.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: "determine_address_tax_category_from",
|
||||||
|
title: "Determine Address Tax Category From",
|
||||||
|
description: __("Tax category can be set on Addresses. An address can be Shipping or Billing address. Set which addres to select when applying Tax Category.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: "over_billing_allowance",
|
||||||
|
title: "Over Billing Allowance Percentage",
|
||||||
|
description: __("The percentage by which you can overbill transactions. For example, if the order value is $100 for an Item and percentage here is set as 10% then you are allowed to bill for $110.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: "credit_controller",
|
||||||
|
title: "Credit Controller",
|
||||||
|
description: __("Select the role that is allowed to submit transactions that exceed credit limits set. The credit limit can be set in the Customer form.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: "make_payment_via_journal_entry",
|
||||||
|
title: "Make Payment via Journal Entry",
|
||||||
|
description: __("When checked, if user proceeds to make payment from an invoice, the system will open a Journal Entry instead of a Payment Entry.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: "unlink_payment_on_cancellation_of_invoice",
|
||||||
|
title: "Unlink Payment on Cancellation of Invoice",
|
||||||
|
description: __("If checked, system will unlink the payment against the respective invoice.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: "unlink_advance_payment_on_cancelation_of_order",
|
||||||
|
title: "Unlink Advance Payment on Cancellation of Order",
|
||||||
|
description: __("Similar to the previous option, this unlinks any advance payments made against Purchase/Sales Orders.")
|
||||||
|
}
|
||||||
|
];
|
@ -21,6 +21,7 @@
|
|||||||
"book_asset_depreciation_entry_automatically",
|
"book_asset_depreciation_entry_automatically",
|
||||||
"add_taxes_from_item_tax_template",
|
"add_taxes_from_item_tax_template",
|
||||||
"automatically_fetch_payment_terms",
|
"automatically_fetch_payment_terms",
|
||||||
|
"delete_linked_ledger_entries",
|
||||||
"deferred_accounting_settings_section",
|
"deferred_accounting_settings_section",
|
||||||
"automatically_process_deferred_accounting_entry",
|
"automatically_process_deferred_accounting_entry",
|
||||||
"book_deferred_entries_based_on",
|
"book_deferred_entries_based_on",
|
||||||
@ -219,6 +220,12 @@
|
|||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Book Deferred Entries Based On",
|
"label": "Book Deferred Entries Based On",
|
||||||
"options": "Days\nMonths"
|
"options": "Days\nMonths"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "delete_linked_ledger_entries",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Delete Accounting and Stock Ledger Entries on deletion of Transaction"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "icon-cog",
|
"icon": "icon-cog",
|
||||||
@ -226,7 +233,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-13 11:32:52.268826",
|
"modified": "2021-01-05 13:04:00.118892",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Accounts Settings",
|
"name": "Accounts Settings",
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"creation": "2020-11-08 18:22:36.001131",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"accounting_dimension",
|
||||||
|
"dimension_value"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "accounting_dimension",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Accounting Dimension",
|
||||||
|
"options": "DocType",
|
||||||
|
"read_only": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "dimension_value",
|
||||||
|
"fieldtype": "Dynamic Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"options": "accounting_dimension",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2020-11-23 09:56:19.744200",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Accounts",
|
||||||
|
"name": "Allowed Dimension",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [],
|
||||||
|
"quick_entry": 1,
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"track_changes": 1
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2017, sathishpy@gmail.com and contributors
|
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
# import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
class BankStatementTransactionInvoiceItem(Document):
|
class AllowedDimension(Document):
|
||||||
pass
|
pass
|
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"creation": "2020-11-08 18:20:00.944449",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"applicable_on_account",
|
||||||
|
"is_mandatory"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "applicable_on_account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Accounts",
|
||||||
|
"options": "Account",
|
||||||
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columns": 2,
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "is_mandatory",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Is Mandatory",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2020-11-22 19:55:13.324136",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Accounts",
|
||||||
|
"name": "Applicable On Account",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [],
|
||||||
|
"quick_entry": 1,
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"track_changes": 1
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2017, sathishpy@gmail.com and contributors
|
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
# import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
class BankStatementTransactionPaymentItem(Document):
|
class ApplicableOnAccount(Document):
|
||||||
pass
|
pass
|
@ -1,5 +1,6 @@
|
|||||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
|
frappe.provide('erpnext.integrations');
|
||||||
|
|
||||||
frappe.ui.form.on('Bank', {
|
frappe.ui.form.on('Bank', {
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
@ -20,7 +21,12 @@ frappe.ui.form.on('Bank', {
|
|||||||
frm.set_df_property('address_and_contact', 'hidden', 0);
|
frm.set_df_property('address_and_contact', 'hidden', 0);
|
||||||
frappe.contacts.render_address_and_contact(frm);
|
frappe.contacts.render_address_and_contact(frm);
|
||||||
}
|
}
|
||||||
},
|
if (frm.doc.plaid_access_token) {
|
||||||
|
frm.add_custom_button(__('Refresh Plaid Link'), () => {
|
||||||
|
new erpnext.integrations.refreshPlaidLink(frm.doc.plaid_access_token);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -41,3 +47,78 @@ let add_fields_to_mapping_table = function (frm) {
|
|||||||
|
|
||||||
frm.fields_dict.bank_transaction_mapping.grid.refresh();
|
frm.fields_dict.bank_transaction_mapping.grid.refresh();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
erpnext.integrations.refreshPlaidLink = class refreshPlaidLink {
|
||||||
|
constructor(access_token) {
|
||||||
|
this.access_token = access_token;
|
||||||
|
this.plaidUrl = 'https://cdn.plaid.com/link/v2/stable/link-initialize.js';
|
||||||
|
this.init_config();
|
||||||
|
}
|
||||||
|
|
||||||
|
async init_config() {
|
||||||
|
this.plaid_env = await frappe.db.get_single_value('Plaid Settings', 'plaid_env');
|
||||||
|
this.token = await this.get_link_token_for_update();
|
||||||
|
this.init_plaid();
|
||||||
|
}
|
||||||
|
|
||||||
|
async get_link_token_for_update() {
|
||||||
|
const token = frappe.xcall(
|
||||||
|
'erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.get_link_token_for_update',
|
||||||
|
{ access_token: this.access_token }
|
||||||
|
)
|
||||||
|
if (!token) {
|
||||||
|
frappe.throw(__('Cannot retrieve link token for update. Check Error Log for more information'));
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_plaid() {
|
||||||
|
const me = this;
|
||||||
|
me.loadScript(me.plaidUrl)
|
||||||
|
.then(() => {
|
||||||
|
me.onScriptLoaded(me);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
if (me.linkHandler) {
|
||||||
|
me.linkHandler.open();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
me.onScriptError(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadScript(src) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
if (document.querySelector("script[src='" + src + "']")) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const el = document.createElement('script');
|
||||||
|
el.type = 'text/javascript';
|
||||||
|
el.async = true;
|
||||||
|
el.src = src;
|
||||||
|
el.addEventListener('load', resolve);
|
||||||
|
el.addEventListener('error', reject);
|
||||||
|
el.addEventListener('abort', reject);
|
||||||
|
document.head.appendChild(el);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onScriptLoaded(me) {
|
||||||
|
me.linkHandler = Plaid.create({
|
||||||
|
env: me.plaid_env,
|
||||||
|
token: me.token,
|
||||||
|
onSuccess: me.plaid_success
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onScriptError(error) {
|
||||||
|
frappe.msgprint(__("There was an issue connecting to Plaid's authentication server. Check browser console for more information"));
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
plaid_success(token, response) {
|
||||||
|
frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -86,6 +86,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
|
"description": "Setting the account as a Company Account is necessary for Bank Reconciliation",
|
||||||
"fieldname": "is_company_account",
|
"fieldname": "is_company_account",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Is Company Account"
|
"label": "Is Company Account"
|
||||||
@ -207,7 +208,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-07-17 13:59:50.795412",
|
"modified": "2020-10-23 16:48:06.303658",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Bank Account",
|
"name": "Bank Account",
|
||||||
|
@ -0,0 +1,162 @@
|
|||||||
|
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
frappe.provide("erpnext.accounts.bank_reconciliation");
|
||||||
|
|
||||||
|
frappe.ui.form.on("Bank Reconciliation Tool", {
|
||||||
|
setup: function (frm) {
|
||||||
|
frm.set_query("bank_account", function () {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
company: ["in", frm.doc.company],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
refresh: function (frm) {
|
||||||
|
frappe.require("assets/js/bank-reconciliation-tool.min.js", () =>
|
||||||
|
frm.trigger("make_reconciliation_tool")
|
||||||
|
);
|
||||||
|
frm.upload_statement_button = frm.page.set_secondary_action(
|
||||||
|
__("Upload Bank Statement"),
|
||||||
|
() =>
|
||||||
|
frappe.call({
|
||||||
|
method:
|
||||||
|
"erpnext.accounts.doctype.bank_statement_import.bank_statement_import.upload_bank_statement",
|
||||||
|
args: {
|
||||||
|
dt: frm.doc.doctype,
|
||||||
|
dn: frm.doc.name,
|
||||||
|
company: frm.doc.company,
|
||||||
|
bank_account: frm.doc.bank_account,
|
||||||
|
},
|
||||||
|
callback: function (r) {
|
||||||
|
if (!r.exc) {
|
||||||
|
var doc = frappe.model.sync(r.message);
|
||||||
|
frappe.set_route(
|
||||||
|
"Form",
|
||||||
|
doc[0].doctype,
|
||||||
|
doc[0].name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
after_save: function (frm) {
|
||||||
|
frm.trigger("make_reconciliation_tool");
|
||||||
|
},
|
||||||
|
|
||||||
|
bank_account: function (frm) {
|
||||||
|
frappe.db.get_value(
|
||||||
|
"Bank Account",
|
||||||
|
frm.bank_account,
|
||||||
|
"account",
|
||||||
|
(r) => {
|
||||||
|
frappe.db.get_value(
|
||||||
|
"Account",
|
||||||
|
r.account,
|
||||||
|
"account_currency",
|
||||||
|
(r) => {
|
||||||
|
frm.currency = r.account_currency;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
frm.trigger("get_account_opening_balance");
|
||||||
|
},
|
||||||
|
|
||||||
|
bank_statement_from_date: function (frm) {
|
||||||
|
frm.trigger("get_account_opening_balance");
|
||||||
|
},
|
||||||
|
|
||||||
|
make_reconciliation_tool(frm) {
|
||||||
|
frm.get_field("reconciliation_tool_cards").$wrapper.empty();
|
||||||
|
if (frm.doc.bank_account && frm.doc.bank_statement_to_date) {
|
||||||
|
frm.trigger("get_cleared_balance").then(() => {
|
||||||
|
if (
|
||||||
|
frm.doc.bank_account &&
|
||||||
|
frm.doc.bank_statement_from_date &&
|
||||||
|
frm.doc.bank_statement_to_date &&
|
||||||
|
frm.doc.bank_statement_closing_balance
|
||||||
|
) {
|
||||||
|
frm.trigger("render_chart");
|
||||||
|
frm.trigger("render");
|
||||||
|
frappe.utils.scroll_to(
|
||||||
|
frm.get_field("reconciliation_tool_cards").$wrapper,
|
||||||
|
true,
|
||||||
|
30
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
get_account_opening_balance(frm) {
|
||||||
|
if (frm.doc.bank_account && frm.doc.bank_statement_from_date) {
|
||||||
|
frappe.call({
|
||||||
|
method:
|
||||||
|
"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
|
||||||
|
args: {
|
||||||
|
bank_account: frm.doc.bank_account,
|
||||||
|
till_date: frm.doc.bank_statement_from_date,
|
||||||
|
},
|
||||||
|
callback: (response) => {
|
||||||
|
frm.set_value("account_opening_balance", response.message);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
get_cleared_balance(frm) {
|
||||||
|
if (frm.doc.bank_account && frm.doc.bank_statement_to_date) {
|
||||||
|
return frappe.call({
|
||||||
|
method:
|
||||||
|
"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
|
||||||
|
args: {
|
||||||
|
bank_account: frm.doc.bank_account,
|
||||||
|
till_date: frm.doc.bank_statement_to_date,
|
||||||
|
},
|
||||||
|
callback: (response) => {
|
||||||
|
frm.cleared_balance = response.message;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
render_chart(frm) {
|
||||||
|
frm.cards_manager = new erpnext.accounts.bank_reconciliation.NumberCardManager(
|
||||||
|
{
|
||||||
|
$reconciliation_tool_cards: frm.get_field(
|
||||||
|
"reconciliation_tool_cards"
|
||||||
|
).$wrapper,
|
||||||
|
bank_statement_closing_balance:
|
||||||
|
frm.doc.bank_statement_closing_balance,
|
||||||
|
cleared_balance: frm.cleared_balance,
|
||||||
|
currency: frm.currency,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
render(frm) {
|
||||||
|
if (frm.doc.bank_account) {
|
||||||
|
frm.bank_reconciliation_data_table_manager = new erpnext.accounts.bank_reconciliation.DataTableManager(
|
||||||
|
{
|
||||||
|
company: frm.doc.company,
|
||||||
|
bank_account: frm.doc.bank_account,
|
||||||
|
$reconciliation_tool_dt: frm.get_field(
|
||||||
|
"reconciliation_tool_dt"
|
||||||
|
).$wrapper,
|
||||||
|
$no_bank_transactions: frm.get_field(
|
||||||
|
"no_bank_transactions"
|
||||||
|
).$wrapper,
|
||||||
|
bank_statement_from_date: frm.doc.bank_statement_from_date,
|
||||||
|
bank_statement_to_date: frm.doc.bank_statement_to_date,
|
||||||
|
bank_statement_closing_balance:
|
||||||
|
frm.doc.bank_statement_closing_balance,
|
||||||
|
cards_manager: frm.cards_manager,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
@ -0,0 +1,113 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"creation": "2020-12-02 10:13:02.148040",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"company",
|
||||||
|
"bank_account",
|
||||||
|
"column_break_1",
|
||||||
|
"bank_statement_from_date",
|
||||||
|
"bank_statement_to_date",
|
||||||
|
"column_break_2",
|
||||||
|
"account_opening_balance",
|
||||||
|
"bank_statement_closing_balance",
|
||||||
|
"section_break_1",
|
||||||
|
"reconciliation_tool_cards",
|
||||||
|
"reconciliation_tool_dt",
|
||||||
|
"no_bank_transactions"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "company",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Company",
|
||||||
|
"options": "Company"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "bank_account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Bank Account",
|
||||||
|
"options": "Bank Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_1",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval: doc.bank_account",
|
||||||
|
"fieldname": "bank_statement_from_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"label": "Bank Statement From Date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval: doc.bank_statement_from_date",
|
||||||
|
"fieldname": "bank_statement_to_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"label": "Bank Statement To Date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_2",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval: doc.bank_statement_from_date",
|
||||||
|
"fieldname": "account_opening_balance",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Account Opening Balance",
|
||||||
|
"options": "Currency",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval: doc.bank_statement_to_date",
|
||||||
|
"fieldname": "bank_statement_closing_balance",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Bank Statement Closing Balance",
|
||||||
|
"options": "Currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval: doc.bank_statement_closing_balance",
|
||||||
|
"fieldname": "section_break_1",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Reconcile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "reconciliation_tool_cards",
|
||||||
|
"fieldtype": "HTML"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "reconciliation_tool_dt",
|
||||||
|
"fieldtype": "HTML"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "no_bank_transactions",
|
||||||
|
"fieldtype": "HTML",
|
||||||
|
"options": "<div class=\"text-muted text-center\">No Matching Bank Transactions Found</div>"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hide_toolbar": 1,
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"issingle": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2021-02-02 01:35:53.043578",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Accounts",
|
||||||
|
"name": "Bank Reconciliation Tool",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"role": "System Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"quick_entry": 1,
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC"
|
||||||
|
}
|
@ -0,0 +1,452 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import json
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
from frappe import _
|
||||||
|
from frappe.utils import flt
|
||||||
|
|
||||||
|
from erpnext import get_company_currency
|
||||||
|
from erpnext.accounts.utils import get_balance_on
|
||||||
|
from erpnext.accounts.report.bank_reconciliation_statement.bank_reconciliation_statement import get_entries, get_amounts_not_reflected_in_system
|
||||||
|
from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_paid_amount
|
||||||
|
|
||||||
|
|
||||||
|
class BankReconciliationTool(Document):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_bank_transactions(bank_account, from_date = None, to_date = None):
|
||||||
|
# returns bank transactions for a bank account
|
||||||
|
filters = []
|
||||||
|
filters.append(['bank_account', '=', bank_account])
|
||||||
|
filters.append(['docstatus', '=', 1])
|
||||||
|
filters.append(['unallocated_amount', '>', 0])
|
||||||
|
if to_date:
|
||||||
|
filters.append(['date', '<=', to_date])
|
||||||
|
if from_date:
|
||||||
|
filters.append(['date', '>=', from_date])
|
||||||
|
transactions = frappe.get_all(
|
||||||
|
'Bank Transaction',
|
||||||
|
fields = ['date', 'deposit', 'withdrawal', 'currency',
|
||||||
|
'description', 'name', 'bank_account', 'company',
|
||||||
|
'unallocated_amount', 'reference_number', 'party_type', 'party'],
|
||||||
|
filters = filters
|
||||||
|
)
|
||||||
|
return transactions
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_account_balance(bank_account, till_date):
|
||||||
|
# returns account balance till the specified date
|
||||||
|
account = frappe.db.get_value('Bank Account', bank_account, 'account')
|
||||||
|
filters = frappe._dict({
|
||||||
|
"account": account,
|
||||||
|
"report_date": till_date,
|
||||||
|
"include_pos_transactions": 1
|
||||||
|
})
|
||||||
|
data = get_entries(filters)
|
||||||
|
|
||||||
|
balance_as_per_system = get_balance_on(filters["account"], filters["report_date"])
|
||||||
|
|
||||||
|
total_debit, total_credit = 0,0
|
||||||
|
for d in data:
|
||||||
|
total_debit += flt(d.debit)
|
||||||
|
total_credit += flt(d.credit)
|
||||||
|
|
||||||
|
amounts_not_reflected_in_system = get_amounts_not_reflected_in_system(filters)
|
||||||
|
|
||||||
|
bank_bal = flt(balance_as_per_system) - flt(total_debit) + flt(total_credit) \
|
||||||
|
+ amounts_not_reflected_in_system
|
||||||
|
|
||||||
|
return bank_bal
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def update_bank_transaction(bank_transaction_name, reference_number, party_type=None, party=None):
|
||||||
|
# updates bank transaction based on the new parameters provided by the user from Vouchers
|
||||||
|
bank_transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
|
||||||
|
bank_transaction.reference_number = reference_number
|
||||||
|
bank_transaction.party_type = party_type
|
||||||
|
bank_transaction.party = party
|
||||||
|
bank_transaction.save()
|
||||||
|
return frappe.db.get_all('Bank Transaction',
|
||||||
|
filters={
|
||||||
|
'name': bank_transaction_name
|
||||||
|
},
|
||||||
|
fields=['date', 'deposit', 'withdrawal', 'currency',
|
||||||
|
'description', 'name', 'bank_account', 'company',
|
||||||
|
'unallocated_amount', 'reference_number',
|
||||||
|
'party_type', 'party'],
|
||||||
|
)[0]
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def create_journal_entry_bts( bank_transaction_name, reference_number=None, reference_date=None, posting_date=None, entry_type=None,
|
||||||
|
second_account=None, mode_of_payment=None, party_type=None, party=None, allow_edit=None):
|
||||||
|
# Create a new journal entry based on the bank transaction
|
||||||
|
bank_transaction = frappe.db.get_values(
|
||||||
|
"Bank Transaction", bank_transaction_name,
|
||||||
|
fieldname=["name", "deposit", "withdrawal", "bank_account"] ,
|
||||||
|
as_dict=True
|
||||||
|
)[0]
|
||||||
|
company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account")
|
||||||
|
account_type = frappe.db.get_value("Account", second_account, "account_type")
|
||||||
|
if account_type in ["Receivable", "Payable"]:
|
||||||
|
if not (party_type and party):
|
||||||
|
frappe.throw(_("Party Type and Party is required for Receivable / Payable account {0}").format( second_account))
|
||||||
|
accounts = []
|
||||||
|
# Multi Currency?
|
||||||
|
accounts.append({
|
||||||
|
"account": second_account,
|
||||||
|
"credit_in_account_currency": bank_transaction.deposit
|
||||||
|
if bank_transaction.deposit > 0
|
||||||
|
else 0,
|
||||||
|
"debit_in_account_currency":bank_transaction.withdrawal
|
||||||
|
if bank_transaction.withdrawal > 0
|
||||||
|
else 0,
|
||||||
|
"party_type":party_type,
|
||||||
|
"party":party,
|
||||||
|
})
|
||||||
|
|
||||||
|
accounts.append({
|
||||||
|
"account": company_account,
|
||||||
|
"bank_account": bank_transaction.bank_account,
|
||||||
|
"credit_in_account_currency": bank_transaction.withdrawal
|
||||||
|
if bank_transaction.withdrawal > 0
|
||||||
|
else 0,
|
||||||
|
"debit_in_account_currency":bank_transaction.deposit
|
||||||
|
if bank_transaction.deposit > 0
|
||||||
|
else 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
company = frappe.get_value("Account", company_account, "company")
|
||||||
|
|
||||||
|
journal_entry_dict = {
|
||||||
|
"voucher_type" : entry_type,
|
||||||
|
"company" : company,
|
||||||
|
"posting_date" : posting_date,
|
||||||
|
"cheque_date" : reference_date,
|
||||||
|
"cheque_no" : reference_number,
|
||||||
|
"mode_of_payment" : mode_of_payment
|
||||||
|
}
|
||||||
|
journal_entry = frappe.new_doc('Journal Entry')
|
||||||
|
journal_entry.update(journal_entry_dict)
|
||||||
|
journal_entry.set("accounts", accounts)
|
||||||
|
|
||||||
|
|
||||||
|
if allow_edit:
|
||||||
|
return journal_entry
|
||||||
|
|
||||||
|
journal_entry.insert()
|
||||||
|
journal_entry.submit()
|
||||||
|
|
||||||
|
if bank_transaction.deposit > 0:
|
||||||
|
paid_amount = bank_transaction.deposit
|
||||||
|
else:
|
||||||
|
paid_amount = bank_transaction.withdrawal
|
||||||
|
|
||||||
|
vouchers = json.dumps([{
|
||||||
|
"payment_doctype":"Journal Entry",
|
||||||
|
"payment_name":journal_entry.name,
|
||||||
|
"amount":paid_amount}])
|
||||||
|
|
||||||
|
return reconcile_vouchers(bank_transaction.name, vouchers)
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def create_payment_entry_bts( bank_transaction_name, reference_number=None, reference_date=None, party_type=None, party=None, posting_date=None,
|
||||||
|
mode_of_payment=None, project=None, cost_center=None, allow_edit=None):
|
||||||
|
# Create a new payment entry based on the bank transaction
|
||||||
|
bank_transaction = frappe.db.get_values(
|
||||||
|
"Bank Transaction", bank_transaction_name,
|
||||||
|
fieldname=["name", "unallocated_amount", "deposit", "bank_account"] ,
|
||||||
|
as_dict=True
|
||||||
|
)[0]
|
||||||
|
paid_amount = bank_transaction.unallocated_amount
|
||||||
|
payment_type = "Receive" if bank_transaction.deposit > 0 else "Pay"
|
||||||
|
|
||||||
|
company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account")
|
||||||
|
company = frappe.get_value("Account", company_account, "company")
|
||||||
|
payment_entry_dict = {
|
||||||
|
"company" : company,
|
||||||
|
"payment_type" : payment_type,
|
||||||
|
"reference_no" : reference_number,
|
||||||
|
"reference_date" : reference_date,
|
||||||
|
"party_type" : party_type,
|
||||||
|
"party" : party,
|
||||||
|
"posting_date" : posting_date,
|
||||||
|
"paid_amount": paid_amount,
|
||||||
|
"received_amount": paid_amount
|
||||||
|
}
|
||||||
|
payment_entry = frappe.new_doc("Payment Entry")
|
||||||
|
|
||||||
|
|
||||||
|
payment_entry.update(payment_entry_dict)
|
||||||
|
|
||||||
|
if mode_of_payment:
|
||||||
|
payment_entry.mode_of_payment = mode_of_payment
|
||||||
|
if project:
|
||||||
|
payment_entry.project = project
|
||||||
|
if cost_center:
|
||||||
|
payment_entry.cost_center = cost_center
|
||||||
|
if payment_type == "Receive":
|
||||||
|
payment_entry.paid_to = company_account
|
||||||
|
else:
|
||||||
|
payment_entry.paid_from = company_account
|
||||||
|
|
||||||
|
payment_entry.validate()
|
||||||
|
|
||||||
|
if allow_edit:
|
||||||
|
return payment_entry
|
||||||
|
|
||||||
|
payment_entry.insert()
|
||||||
|
|
||||||
|
payment_entry.submit()
|
||||||
|
vouchers = json.dumps([{
|
||||||
|
"payment_doctype":"Payment Entry",
|
||||||
|
"payment_name":payment_entry.name,
|
||||||
|
"amount":paid_amount}])
|
||||||
|
return reconcile_vouchers(bank_transaction.name, vouchers)
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def reconcile_vouchers(bank_transaction_name, vouchers):
|
||||||
|
# updated clear date of all the vouchers based on the bank transaction
|
||||||
|
vouchers = json.loads(vouchers)
|
||||||
|
transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
|
||||||
|
if transaction.unallocated_amount == 0:
|
||||||
|
frappe.throw(_("This bank transaction is already fully reconciled"))
|
||||||
|
total_amount = 0
|
||||||
|
for voucher in vouchers:
|
||||||
|
voucher['payment_entry'] = frappe.get_doc(voucher['payment_doctype'], voucher['payment_name'])
|
||||||
|
total_amount += get_paid_amount(frappe._dict({
|
||||||
|
'payment_document': voucher['payment_doctype'],
|
||||||
|
'payment_entry': voucher['payment_name'],
|
||||||
|
}), transaction.currency)
|
||||||
|
|
||||||
|
if total_amount > transaction.unallocated_amount:
|
||||||
|
frappe.throw(_("The Sum Total of Amounts of All Selected Vouchers Should be Less than the Unallocated Amount of the Bank Transaction"))
|
||||||
|
account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
|
||||||
|
|
||||||
|
for voucher in vouchers:
|
||||||
|
gl_entry = frappe.db.get_value("GL Entry", dict(account=account, voucher_type=voucher['payment_doctype'], voucher_no=voucher['payment_name']), ['credit', 'debit'], as_dict=1)
|
||||||
|
gl_amount, transaction_amount = (gl_entry.credit, transaction.deposit) if gl_entry.credit > 0 else (gl_entry.debit, transaction.withdrawal)
|
||||||
|
allocated_amount = gl_amount if gl_amount >= transaction_amount else transaction_amount
|
||||||
|
|
||||||
|
transaction.append("payment_entries", {
|
||||||
|
"payment_document": voucher['payment_entry'].doctype,
|
||||||
|
"payment_entry": voucher['payment_entry'].name,
|
||||||
|
"allocated_amount": allocated_amount
|
||||||
|
})
|
||||||
|
|
||||||
|
transaction.save()
|
||||||
|
transaction.update_allocations()
|
||||||
|
return frappe.get_doc("Bank Transaction", bank_transaction_name)
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_linked_payments(bank_transaction_name, document_types = None):
|
||||||
|
# get all matching payments for a bank transaction
|
||||||
|
transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
|
||||||
|
bank_account = frappe.db.get_values(
|
||||||
|
"Bank Account",
|
||||||
|
transaction.bank_account,
|
||||||
|
["account", "company"],
|
||||||
|
as_dict=True)[0]
|
||||||
|
(account, company) = (bank_account.account, bank_account.company)
|
||||||
|
matching = check_matching(account, company, transaction, document_types)
|
||||||
|
return matching
|
||||||
|
|
||||||
|
def check_matching(bank_account, company, transaction, document_types):
|
||||||
|
# combine all types of vocuhers
|
||||||
|
subquery = get_queries(bank_account, company, transaction, document_types)
|
||||||
|
filters = {
|
||||||
|
"amount": transaction.unallocated_amount,
|
||||||
|
"payment_type" : "Receive" if transaction.deposit > 0 else "Pay",
|
||||||
|
"reference_no": transaction.reference_number,
|
||||||
|
"party_type": transaction.party_type,
|
||||||
|
"party": transaction.party,
|
||||||
|
"bank_account": bank_account
|
||||||
|
}
|
||||||
|
|
||||||
|
matching_vouchers = []
|
||||||
|
for query in subquery:
|
||||||
|
matching_vouchers.extend(
|
||||||
|
frappe.db.sql(query, filters,)
|
||||||
|
)
|
||||||
|
|
||||||
|
return sorted(matching_vouchers, key = lambda x: x[0], reverse=True) if matching_vouchers else []
|
||||||
|
|
||||||
|
def get_queries(bank_account, company, transaction, document_types):
|
||||||
|
# get queries to get matching vouchers
|
||||||
|
amount_condition = "=" if "exact_match" in document_types else "<="
|
||||||
|
account_from_to = "paid_to" if transaction.deposit > 0 else "paid_from"
|
||||||
|
queries = []
|
||||||
|
|
||||||
|
if "payment_entry" in document_types:
|
||||||
|
pe_amount_matching = get_pe_matching_query(amount_condition, account_from_to, transaction)
|
||||||
|
queries.extend([pe_amount_matching])
|
||||||
|
|
||||||
|
if "journal_entry" in document_types:
|
||||||
|
je_amount_matching = get_je_matching_query(amount_condition, transaction)
|
||||||
|
queries.extend([je_amount_matching])
|
||||||
|
|
||||||
|
if transaction.deposit > 0 and "sales_invoice" in document_types:
|
||||||
|
si_amount_matching = get_si_matching_query(amount_condition)
|
||||||
|
queries.extend([si_amount_matching])
|
||||||
|
|
||||||
|
if transaction.withdrawal > 0:
|
||||||
|
if "purchase_invoice" in document_types:
|
||||||
|
pi_amount_matching = get_pi_matching_query(amount_condition)
|
||||||
|
queries.extend([pi_amount_matching])
|
||||||
|
|
||||||
|
if "expense_claim" in document_types:
|
||||||
|
ec_amount_matching = get_ec_matching_query(bank_account, company, amount_condition)
|
||||||
|
queries.extend([ec_amount_matching])
|
||||||
|
|
||||||
|
return queries
|
||||||
|
|
||||||
|
def get_pe_matching_query(amount_condition, account_from_to, transaction):
|
||||||
|
# get matching payment entries query
|
||||||
|
if transaction.deposit > 0:
|
||||||
|
currency_field = "paid_to_account_currency as currency"
|
||||||
|
else:
|
||||||
|
currency_field = "paid_from_account_currency as currency"
|
||||||
|
return f"""
|
||||||
|
SELECT
|
||||||
|
(CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END
|
||||||
|
+ CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0 END
|
||||||
|
+ 1 ) AS rank,
|
||||||
|
'Payment Entry' as doctype,
|
||||||
|
name,
|
||||||
|
paid_amount,
|
||||||
|
reference_no,
|
||||||
|
reference_date,
|
||||||
|
party,
|
||||||
|
party_type,
|
||||||
|
posting_date,
|
||||||
|
{currency_field}
|
||||||
|
FROM
|
||||||
|
`tabPayment Entry`
|
||||||
|
WHERE
|
||||||
|
paid_amount {amount_condition} %(amount)s
|
||||||
|
AND docstatus = 1
|
||||||
|
AND payment_type IN (%(payment_type)s, 'Internal Transfer')
|
||||||
|
AND ifnull(clearance_date, '') = ""
|
||||||
|
AND {account_from_to} = %(bank_account)s
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def get_je_matching_query(amount_condition, transaction):
|
||||||
|
# get matching journal entry query
|
||||||
|
cr_or_dr = "credit" if transaction.withdrawal > 0 else "debit"
|
||||||
|
return f"""
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
(CASE WHEN je.cheque_no=%(reference_no)s THEN 1 ELSE 0 END
|
||||||
|
+ 1) AS rank ,
|
||||||
|
'Journal Entry' as doctype,
|
||||||
|
je.name,
|
||||||
|
jea.{cr_or_dr}_in_account_currency as paid_amount,
|
||||||
|
je.cheque_no as reference_no,
|
||||||
|
je.cheque_date as reference_date,
|
||||||
|
je.pay_to_recd_from as party,
|
||||||
|
jea.party_type,
|
||||||
|
je.posting_date,
|
||||||
|
jea.account_currency as currency
|
||||||
|
FROM
|
||||||
|
`tabJournal Entry Account` as jea
|
||||||
|
JOIN
|
||||||
|
`tabJournal Entry` as je
|
||||||
|
ON
|
||||||
|
jea.parent = je.name
|
||||||
|
WHERE
|
||||||
|
(je.clearance_date is null or je.clearance_date='0000-00-00')
|
||||||
|
AND jea.account = %(bank_account)s
|
||||||
|
AND jea.{cr_or_dr}_in_account_currency {amount_condition} %(amount)s
|
||||||
|
AND je.docstatus = 1
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def get_si_matching_query(amount_condition):
|
||||||
|
# get matchin sales invoice query
|
||||||
|
return f"""
|
||||||
|
SELECT
|
||||||
|
( CASE WHEN si.customer = %(party)s THEN 1 ELSE 0 END
|
||||||
|
+ 1 ) AS rank,
|
||||||
|
'Sales Invoice' as doctype,
|
||||||
|
si.name,
|
||||||
|
sip.amount as paid_amount,
|
||||||
|
'' as reference_no,
|
||||||
|
'' as reference_date,
|
||||||
|
si.customer as party,
|
||||||
|
'Customer' as party_type,
|
||||||
|
si.posting_date,
|
||||||
|
si.currency
|
||||||
|
|
||||||
|
FROM
|
||||||
|
`tabSales Invoice Payment` as sip
|
||||||
|
JOIN
|
||||||
|
`tabSales Invoice` as si
|
||||||
|
ON
|
||||||
|
sip.parent = si.name
|
||||||
|
WHERE (sip.clearance_date is null or sip.clearance_date='0000-00-00')
|
||||||
|
AND sip.account = %(bank_account)s
|
||||||
|
AND sip.amount {amount_condition} %(amount)s
|
||||||
|
AND si.docstatus = 1
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_pi_matching_query(amount_condition):
|
||||||
|
# get matching purchase invoice query
|
||||||
|
return f"""
|
||||||
|
SELECT
|
||||||
|
( CASE WHEN supplier = %(party)s THEN 1 ELSE 0 END
|
||||||
|
+ 1 ) AS rank,
|
||||||
|
'Purchase Invoice' as doctype,
|
||||||
|
name,
|
||||||
|
paid_amount,
|
||||||
|
'' as reference_no,
|
||||||
|
'' as reference_date,
|
||||||
|
supplier as party,
|
||||||
|
'Supplier' as party_type,
|
||||||
|
posting_date,
|
||||||
|
currency
|
||||||
|
FROM
|
||||||
|
`tabPurchase Invoice`
|
||||||
|
WHERE
|
||||||
|
paid_amount {amount_condition} %(amount)s
|
||||||
|
AND docstatus = 1
|
||||||
|
AND is_paid = 1
|
||||||
|
AND ifnull(clearance_date, '') = ""
|
||||||
|
AND cash_bank_account = %(bank_account)s
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_ec_matching_query(bank_account, company, amount_condition):
|
||||||
|
# get matching Expense Claim query
|
||||||
|
mode_of_payments = [x["parent"] for x in frappe.db.get_list("Mode of Payment Account",
|
||||||
|
filters={"default_account": bank_account}, fields=["parent"])]
|
||||||
|
mode_of_payments = '(\'' + '\', \''.join(mode_of_payments) + '\' )'
|
||||||
|
company_currency = get_company_currency(company)
|
||||||
|
return f"""
|
||||||
|
SELECT
|
||||||
|
( CASE WHEN employee = %(party)s THEN 1 ELSE 0 END
|
||||||
|
+ 1 ) AS rank,
|
||||||
|
'Expense Claim' as doctype,
|
||||||
|
name,
|
||||||
|
total_sanctioned_amount as paid_amount,
|
||||||
|
'' as reference_no,
|
||||||
|
'' as reference_date,
|
||||||
|
employee as party,
|
||||||
|
'Employee' as party_type,
|
||||||
|
posting_date,
|
||||||
|
'{company_currency}' as currency
|
||||||
|
FROM
|
||||||
|
`tabExpense Claim`
|
||||||
|
WHERE
|
||||||
|
total_sanctioned_amount {amount_condition} %(amount)s
|
||||||
|
AND docstatus = 1
|
||||||
|
AND is_paid = 1
|
||||||
|
AND ifnull(clearance_date, '') = ""
|
||||||
|
AND mode_of_payment in {mode_of_payments}
|
||||||
|
"""
|
@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# See license.txt
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class TestBankReconciliationTool(unittest.TestCase):
|
||||||
|
pass
|
3
erpnext/accounts/doctype/bank_statement_import/bank_statement_import.css
vendored
Normal file
3
erpnext/accounts/doctype/bank_statement_import/bank_statement_import.css
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.warnings .warning {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
@ -0,0 +1,574 @@
|
|||||||
|
// Copyright (c) 2019, Frappe Technologies and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
frappe.ui.form.on("Bank Statement Import", {
|
||||||
|
setup(frm) {
|
||||||
|
frappe.realtime.on("data_import_refresh", ({ data_import }) => {
|
||||||
|
frm.import_in_progress = false;
|
||||||
|
if (data_import !== frm.doc.name) return;
|
||||||
|
frappe.model.clear_doc("Bank Statement Import", frm.doc.name);
|
||||||
|
frappe.model
|
||||||
|
.with_doc("Bank Statement Import", frm.doc.name)
|
||||||
|
.then(() => {
|
||||||
|
frm.refresh();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
frappe.realtime.on("data_import_progress", (data) => {
|
||||||
|
frm.import_in_progress = true;
|
||||||
|
if (data.data_import !== frm.doc.name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let percent = Math.floor((data.current * 100) / data.total);
|
||||||
|
let seconds = Math.floor(data.eta);
|
||||||
|
let minutes = Math.floor(data.eta / 60);
|
||||||
|
let eta_message =
|
||||||
|
// prettier-ignore
|
||||||
|
seconds < 60
|
||||||
|
? __('About {0} seconds remaining', [seconds])
|
||||||
|
: minutes === 1
|
||||||
|
? __('About {0} minute remaining', [minutes])
|
||||||
|
: __('About {0} minutes remaining', [minutes]);
|
||||||
|
|
||||||
|
let message;
|
||||||
|
if (data.success) {
|
||||||
|
let message_args = [data.current, data.total, eta_message];
|
||||||
|
message =
|
||||||
|
frm.doc.import_type === "Insert New Records"
|
||||||
|
? __("Importing {0} of {1}, {2}", message_args)
|
||||||
|
: __("Updating {0} of {1}, {2}", message_args);
|
||||||
|
}
|
||||||
|
if (data.skipping) {
|
||||||
|
message = __(
|
||||||
|
"Skipping {0} of {1}, {2}",
|
||||||
|
[
|
||||||
|
data.current,
|
||||||
|
data.total,
|
||||||
|
eta_message,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
frm.dashboard.show_progress(
|
||||||
|
__("Import Progress"),
|
||||||
|
percent,
|
||||||
|
message
|
||||||
|
);
|
||||||
|
frm.page.set_indicator(__("In Progress"), "orange");
|
||||||
|
|
||||||
|
// hide progress when complete
|
||||||
|
if (data.current === data.total) {
|
||||||
|
setTimeout(() => {
|
||||||
|
frm.dashboard.hide();
|
||||||
|
frm.refresh();
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
frm.set_query("reference_doctype", () => {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
name: ["in", frappe.boot.user.can_import],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
frm.get_field("import_file").df.options = {
|
||||||
|
restrictions: {
|
||||||
|
allowed_file_types: [".csv", ".xls", ".xlsx"],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
frm.has_import_file = () => {
|
||||||
|
return frm.doc.import_file || frm.doc.google_sheets_url;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
refresh(frm) {
|
||||||
|
frm.page.hide_icon_group();
|
||||||
|
frm.trigger("update_indicators");
|
||||||
|
frm.trigger("import_file");
|
||||||
|
frm.trigger("show_import_log");
|
||||||
|
frm.trigger("show_import_warnings");
|
||||||
|
frm.trigger("toggle_submit_after_import");
|
||||||
|
frm.trigger("show_import_status");
|
||||||
|
frm.trigger("show_report_error_button");
|
||||||
|
|
||||||
|
if (frm.doc.status === "Partial Success") {
|
||||||
|
frm.add_custom_button(__("Export Errored Rows"), () =>
|
||||||
|
frm.trigger("export_errored_rows")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frm.doc.status.includes("Success")) {
|
||||||
|
frm.add_custom_button(
|
||||||
|
__("Go to {0} List", [frm.doc.reference_doctype]),
|
||||||
|
() => frappe.set_route("List", frm.doc.reference_doctype)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onload_post_render(frm) {
|
||||||
|
frm.trigger("update_primary_action");
|
||||||
|
},
|
||||||
|
|
||||||
|
update_primary_action(frm) {
|
||||||
|
if (frm.is_dirty()) {
|
||||||
|
frm.enable_save();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
frm.disable_save();
|
||||||
|
if (frm.doc.status !== "Success") {
|
||||||
|
if (!frm.is_new() && frm.has_import_file()) {
|
||||||
|
let label =
|
||||||
|
frm.doc.status === "Pending"
|
||||||
|
? __("Start Import")
|
||||||
|
: __("Retry");
|
||||||
|
frm.page.set_primary_action(label, () =>
|
||||||
|
frm.events.start_import(frm)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
frm.page.set_primary_action(__("Save"), () => frm.save());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
update_indicators(frm) {
|
||||||
|
const indicator = frappe.get_indicator(frm.doc);
|
||||||
|
if (indicator) {
|
||||||
|
frm.page.set_indicator(indicator[0], indicator[1]);
|
||||||
|
} else {
|
||||||
|
frm.page.clear_indicator();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
show_import_status(frm) {
|
||||||
|
let import_log = JSON.parse(frm.doc.import_log || "[]");
|
||||||
|
let successful_records = import_log.filter((log) => log.success);
|
||||||
|
let failed_records = import_log.filter((log) => !log.success);
|
||||||
|
if (successful_records.length === 0) return;
|
||||||
|
|
||||||
|
let message;
|
||||||
|
if (failed_records.length === 0) {
|
||||||
|
let message_args = [successful_records.length];
|
||||||
|
if (frm.doc.import_type === "Insert New Records") {
|
||||||
|
message =
|
||||||
|
successful_records.length > 1
|
||||||
|
? __("Successfully imported {0} records.", message_args)
|
||||||
|
: __("Successfully imported {0} record.", message_args);
|
||||||
|
} else {
|
||||||
|
message =
|
||||||
|
successful_records.length > 1
|
||||||
|
? __("Successfully updated {0} records.", message_args)
|
||||||
|
: __("Successfully updated {0} record.", message_args);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let message_args = [successful_records.length, import_log.length];
|
||||||
|
if (frm.doc.import_type === "Insert New Records") {
|
||||||
|
message =
|
||||||
|
successful_records.length > 1
|
||||||
|
? __(
|
||||||
|
"Successfully imported {0} records out of {1}. Click on Export Errored Rows, fix the errors and import again.",
|
||||||
|
message_args
|
||||||
|
)
|
||||||
|
: __(
|
||||||
|
"Successfully imported {0} record out of {1}. Click on Export Errored Rows, fix the errors and import again.",
|
||||||
|
message_args
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
message =
|
||||||
|
successful_records.length > 1
|
||||||
|
? __(
|
||||||
|
"Successfully updated {0} records out of {1}. Click on Export Errored Rows, fix the errors and import again.",
|
||||||
|
message_args
|
||||||
|
)
|
||||||
|
: __(
|
||||||
|
"Successfully updated {0} record out of {1}. Click on Export Errored Rows, fix the errors and import again.",
|
||||||
|
message_args
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frm.dashboard.set_headline(message);
|
||||||
|
},
|
||||||
|
|
||||||
|
show_report_error_button(frm) {
|
||||||
|
if (frm.doc.status === "Error") {
|
||||||
|
frappe.db
|
||||||
|
.get_list("Error Log", {
|
||||||
|
filters: { method: frm.doc.name },
|
||||||
|
fields: ["method", "error"],
|
||||||
|
order_by: "creation desc",
|
||||||
|
limit: 1,
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
if (result.length > 0) {
|
||||||
|
frm.add_custom_button("Report Error", () => {
|
||||||
|
let fake_xhr = {
|
||||||
|
responseText: JSON.stringify({
|
||||||
|
exc: result[0].error,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
frappe.request.report_error(fake_xhr, {});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
start_import(frm) {
|
||||||
|
frm.call({
|
||||||
|
method: "form_start_import",
|
||||||
|
args: { data_import: frm.doc.name },
|
||||||
|
btn: frm.page.btn_primary,
|
||||||
|
}).then((r) => {
|
||||||
|
if (r.message === true) {
|
||||||
|
frm.disable_save();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
download_template() {
|
||||||
|
let method =
|
||||||
|
"/api/method/frappe.core.doctype.data_import.data_import.download_template";
|
||||||
|
|
||||||
|
open_url_post(method, {
|
||||||
|
doctype: "Bank Transaction",
|
||||||
|
export_records: "5_records",
|
||||||
|
export_fields: {
|
||||||
|
"Bank Transaction": [
|
||||||
|
"date",
|
||||||
|
"deposit",
|
||||||
|
"withdrawal",
|
||||||
|
"description",
|
||||||
|
"reference_number",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
reference_doctype(frm) {
|
||||||
|
frm.trigger("toggle_submit_after_import");
|
||||||
|
},
|
||||||
|
|
||||||
|
toggle_submit_after_import(frm) {
|
||||||
|
frm.toggle_display("submit_after_import", false);
|
||||||
|
let doctype = frm.doc.reference_doctype;
|
||||||
|
if (doctype) {
|
||||||
|
frappe.model.with_doctype(doctype, () => {
|
||||||
|
let meta = frappe.get_meta(doctype);
|
||||||
|
frm.toggle_display("submit_after_import", meta.is_submittable);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
google_sheets_url(frm) {
|
||||||
|
if (!frm.is_dirty()) {
|
||||||
|
frm.trigger("import_file");
|
||||||
|
} else {
|
||||||
|
frm.trigger("update_primary_action");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
refresh_google_sheet(frm) {
|
||||||
|
frm.trigger("import_file");
|
||||||
|
},
|
||||||
|
|
||||||
|
import_file(frm) {
|
||||||
|
frm.toggle_display("section_import_preview", frm.has_import_file());
|
||||||
|
if (!frm.has_import_file()) {
|
||||||
|
frm.get_field("import_preview").$wrapper.empty();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
frm.trigger("update_primary_action");
|
||||||
|
}
|
||||||
|
|
||||||
|
// load import preview
|
||||||
|
frm.get_field("import_preview").$wrapper.empty();
|
||||||
|
$('<span class="text-muted">')
|
||||||
|
.html(__("Loading import file..."))
|
||||||
|
.appendTo(frm.get_field("import_preview").$wrapper);
|
||||||
|
|
||||||
|
frm.call({
|
||||||
|
method: "get_preview_from_template",
|
||||||
|
args: {
|
||||||
|
data_import: frm.doc.name,
|
||||||
|
import_file: frm.doc.import_file,
|
||||||
|
google_sheets_url: frm.doc.google_sheets_url,
|
||||||
|
},
|
||||||
|
error_handlers: {
|
||||||
|
TimestampMismatchError() {
|
||||||
|
// ignore this error
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).then((r) => {
|
||||||
|
let preview_data = r.message;
|
||||||
|
frm.events.show_import_preview(frm, preview_data);
|
||||||
|
frm.events.show_import_warnings(frm, preview_data);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// method: 'frappe.core.doctype.data_import.data_import.get_preview_from_template',
|
||||||
|
|
||||||
|
show_import_preview(frm, preview_data) {
|
||||||
|
let import_log = JSON.parse(frm.doc.import_log || "[]");
|
||||||
|
|
||||||
|
if (
|
||||||
|
frm.import_preview &&
|
||||||
|
frm.import_preview.doctype === frm.doc.reference_doctype
|
||||||
|
) {
|
||||||
|
frm.import_preview.preview_data = preview_data;
|
||||||
|
frm.import_preview.import_log = import_log;
|
||||||
|
frm.import_preview.refresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
frappe.require("/assets/js/data_import_tools.min.js", () => {
|
||||||
|
frm.import_preview = new frappe.data_import.ImportPreview({
|
||||||
|
wrapper: frm.get_field("import_preview").$wrapper,
|
||||||
|
doctype: frm.doc.reference_doctype,
|
||||||
|
preview_data,
|
||||||
|
import_log,
|
||||||
|
frm,
|
||||||
|
events: {
|
||||||
|
remap_column(changed_map) {
|
||||||
|
let template_options = JSON.parse(
|
||||||
|
frm.doc.template_options || "{}"
|
||||||
|
);
|
||||||
|
template_options.column_to_field_map =
|
||||||
|
template_options.column_to_field_map || {};
|
||||||
|
Object.assign(
|
||||||
|
template_options.column_to_field_map,
|
||||||
|
changed_map
|
||||||
|
);
|
||||||
|
frm.set_value(
|
||||||
|
"template_options",
|
||||||
|
JSON.stringify(template_options)
|
||||||
|
);
|
||||||
|
frm.save().then(() => frm.trigger("import_file"));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
export_errored_rows(frm) {
|
||||||
|
open_url_post(
|
||||||
|
"/api/method/frappe.core.doctype.data_import.data_import.download_errored_template",
|
||||||
|
{
|
||||||
|
data_import_name: frm.doc.name,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
show_import_warnings(frm, preview_data) {
|
||||||
|
let columns = preview_data.columns;
|
||||||
|
let warnings = JSON.parse(frm.doc.template_warnings || "[]");
|
||||||
|
warnings = warnings.concat(preview_data.warnings || []);
|
||||||
|
|
||||||
|
frm.toggle_display("import_warnings_section", warnings.length > 0);
|
||||||
|
if (warnings.length === 0) {
|
||||||
|
frm.get_field("import_warnings").$wrapper.html("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// group warnings by row
|
||||||
|
let warnings_by_row = {};
|
||||||
|
let other_warnings = [];
|
||||||
|
for (let warning of warnings) {
|
||||||
|
if (warning.row) {
|
||||||
|
warnings_by_row[warning.row] =
|
||||||
|
warnings_by_row[warning.row] || [];
|
||||||
|
warnings_by_row[warning.row].push(warning);
|
||||||
|
} else {
|
||||||
|
other_warnings.push(warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let html = "";
|
||||||
|
html += Object.keys(warnings_by_row)
|
||||||
|
.map((row_number) => {
|
||||||
|
let message = warnings_by_row[row_number]
|
||||||
|
.map((w) => {
|
||||||
|
if (w.field) {
|
||||||
|
let label =
|
||||||
|
w.field.label +
|
||||||
|
(w.field.parent !== frm.doc.reference_doctype
|
||||||
|
? ` (${w.field.parent})`
|
||||||
|
: "");
|
||||||
|
return `<li>${label}: ${w.message}</li>`;
|
||||||
|
}
|
||||||
|
return `<li>${w.message}</li>`;
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
return `
|
||||||
|
<div class="warning" data-row="${row_number}">
|
||||||
|
<h5 class="text-uppercase">${__("Row {0}", [row_number])}</h5>
|
||||||
|
<div class="body"><ul>${message}</ul></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
html += other_warnings
|
||||||
|
.map((warning) => {
|
||||||
|
let header = "";
|
||||||
|
if (warning.col) {
|
||||||
|
let column_number = `<span class="text-uppercase">${__(
|
||||||
|
"Column {0}",
|
||||||
|
[warning.col]
|
||||||
|
)}</span>`;
|
||||||
|
let column_header = columns[warning.col].header_title;
|
||||||
|
header = `${column_number} (${column_header})`;
|
||||||
|
}
|
||||||
|
return `
|
||||||
|
<div class="warning" data-col="${warning.col}">
|
||||||
|
<h5>${header}</h5>
|
||||||
|
<div class="body">${warning.message}</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
frm.get_field("import_warnings").$wrapper.html(`
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-10 warnings">${html}</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
},
|
||||||
|
|
||||||
|
show_failed_logs(frm) {
|
||||||
|
frm.trigger("show_import_log");
|
||||||
|
},
|
||||||
|
|
||||||
|
show_import_log(frm) {
|
||||||
|
let import_log = JSON.parse(frm.doc.import_log || "[]");
|
||||||
|
let logs = import_log;
|
||||||
|
frm.toggle_display("import_log", false);
|
||||||
|
frm.toggle_display("import_log_section", logs.length > 0);
|
||||||
|
|
||||||
|
if (logs.length === 0) {
|
||||||
|
frm.get_field("import_log_preview").$wrapper.empty();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rows = logs
|
||||||
|
.map((log) => {
|
||||||
|
let html = "";
|
||||||
|
if (log.success) {
|
||||||
|
if (frm.doc.import_type === "Insert New Records") {
|
||||||
|
html = __(
|
||||||
|
"Successfully imported {0}", [
|
||||||
|
`<span class="underline">${frappe.utils.get_form_link(
|
||||||
|
frm.doc.reference_doctype,
|
||||||
|
log.docname,
|
||||||
|
true
|
||||||
|
)}<span>`,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
html = __(
|
||||||
|
"Successfully updated {0}", [
|
||||||
|
`<span class="underline">${frappe.utils.get_form_link(
|
||||||
|
frm.doc.reference_doctype,
|
||||||
|
log.docname,
|
||||||
|
true
|
||||||
|
)}<span>`,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let messages = log.messages
|
||||||
|
.map(JSON.parse)
|
||||||
|
.map((m) => {
|
||||||
|
let title = m.title
|
||||||
|
? `<strong>${m.title}</strong>`
|
||||||
|
: "";
|
||||||
|
let message = m.message
|
||||||
|
? `<div>${m.message}</div>`
|
||||||
|
: "";
|
||||||
|
return title + message;
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
let id = frappe.dom.get_unique_id();
|
||||||
|
html = `${messages}
|
||||||
|
<button class="btn btn-default btn-xs" type="button" data-toggle="collapse" data-target="#${id}" aria-expanded="false" aria-controls="${id}" style="margin-top: 15px;">
|
||||||
|
${__("Show Traceback")}
|
||||||
|
</button>
|
||||||
|
<div class="collapse" id="${id}" style="margin-top: 15px;">
|
||||||
|
<div class="well">
|
||||||
|
<pre>${log.exception}</pre>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
let indicator_color = log.success ? "green" : "red";
|
||||||
|
let title = log.success ? __("Success") : __("Failure");
|
||||||
|
|
||||||
|
if (frm.doc.show_failed_logs && log.success) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<tr>
|
||||||
|
<td>${log.row_indexes.join(", ")}</td>
|
||||||
|
<td>
|
||||||
|
<div class="indicator ${indicator_color}">${title}</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
${html}
|
||||||
|
</td>
|
||||||
|
</tr>`;
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
if (!rows && frm.doc.show_failed_logs) {
|
||||||
|
rows = `<tr><td class="text-center text-muted" colspan=3>
|
||||||
|
${__("No failed logs")}
|
||||||
|
</td></tr>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
frm.get_field("import_log_preview").$wrapper.html(`
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<tr class="text-muted">
|
||||||
|
<th width="10%">${__("Row Number")}</th>
|
||||||
|
<th width="10%">${__("Status")}</th>
|
||||||
|
<th width="80%">${__("Message")}</th>
|
||||||
|
</tr>
|
||||||
|
${rows}
|
||||||
|
</table>
|
||||||
|
`);
|
||||||
|
},
|
||||||
|
|
||||||
|
show_missing_link_values(frm, missing_link_values) {
|
||||||
|
let can_be_created_automatically = missing_link_values.every(
|
||||||
|
(d) => d.has_one_mandatory_field
|
||||||
|
);
|
||||||
|
|
||||||
|
let html = missing_link_values
|
||||||
|
.map((d) => {
|
||||||
|
let doctype = d.doctype;
|
||||||
|
let values = d.missing_values;
|
||||||
|
return `
|
||||||
|
<h5>${doctype}</h5>
|
||||||
|
<ul>${values.map((v) => `<li>${v}</li>`).join("")}</ul>
|
||||||
|
`;
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
if (can_be_created_automatically) {
|
||||||
|
// prettier-ignore
|
||||||
|
let message = __('There are some linked records which needs to be created before we can import your file. Do you want to create the following missing records automatically?');
|
||||||
|
frappe.confirm(message + html, () => {
|
||||||
|
frm.call("create_missing_link_values", {
|
||||||
|
missing_link_values,
|
||||||
|
}).then((r) => {
|
||||||
|
let records = r.message;
|
||||||
|
frappe.msgprint(__(
|
||||||
|
"Created {0} records successfully.", [
|
||||||
|
records.length,
|
||||||
|
]
|
||||||
|
));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
frappe.msgprint(
|
||||||
|
// prettier-ignore
|
||||||
|
__('The following records needs to be created before we can import your file.') + html
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
@ -0,0 +1,227 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"autoname": "format:Bank Statement Import on {creation}",
|
||||||
|
"beta": 1,
|
||||||
|
"creation": "2019-08-04 14:16:08.318714",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"company",
|
||||||
|
"bank_account",
|
||||||
|
"bank",
|
||||||
|
"column_break_4",
|
||||||
|
"google_sheets_url",
|
||||||
|
"refresh_google_sheet",
|
||||||
|
"html_5",
|
||||||
|
"import_file",
|
||||||
|
"download_template",
|
||||||
|
"status",
|
||||||
|
"template_options",
|
||||||
|
"import_warnings_section",
|
||||||
|
"template_warnings",
|
||||||
|
"import_warnings",
|
||||||
|
"section_import_preview",
|
||||||
|
"import_preview",
|
||||||
|
"import_log_section",
|
||||||
|
"import_log",
|
||||||
|
"show_failed_logs",
|
||||||
|
"import_log_preview",
|
||||||
|
"reference_doctype",
|
||||||
|
"import_type",
|
||||||
|
"submit_after_import",
|
||||||
|
"mute_emails"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "company",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Company",
|
||||||
|
"options": "Company",
|
||||||
|
"reqd": 1,
|
||||||
|
"set_only_once": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "bank_account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Bank Account",
|
||||||
|
"options": "Bank Account",
|
||||||
|
"reqd": 1,
|
||||||
|
"set_only_once": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.bank_account",
|
||||||
|
"fetch_from": "bank_account.bank",
|
||||||
|
"fieldname": "bank",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Bank",
|
||||||
|
"options": "Bank",
|
||||||
|
"read_only": 1,
|
||||||
|
"set_only_once": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"fieldname": "download_template",
|
||||||
|
"fieldtype": "Button",
|
||||||
|
"label": "Download Template"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"fieldname": "import_file",
|
||||||
|
"fieldtype": "Attach",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Import File"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "import_preview",
|
||||||
|
"fieldtype": "HTML",
|
||||||
|
"label": "Import Preview"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_import_preview",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Preview"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "template_options",
|
||||||
|
"fieldtype": "Code",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Template Options",
|
||||||
|
"options": "JSON",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "import_log",
|
||||||
|
"fieldtype": "Code",
|
||||||
|
"label": "Import Log",
|
||||||
|
"options": "JSON"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "import_log_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Import Log"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "import_log_preview",
|
||||||
|
"fieldtype": "HTML",
|
||||||
|
"label": "Import Log Preview"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "Pending",
|
||||||
|
"fieldname": "status",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Status",
|
||||||
|
"options": "Pending\nSuccess\nPartial Success\nError",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "template_warnings",
|
||||||
|
"fieldtype": "Code",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Template Warnings",
|
||||||
|
"options": "JSON"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "import_warnings_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Import File Errors and Warnings"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "import_warnings",
|
||||||
|
"fieldtype": "HTML",
|
||||||
|
"label": "Import Warnings"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "show_failed_logs",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Show Failed Logs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:!doc.__islocal && !doc.import_file",
|
||||||
|
"fieldname": "html_5",
|
||||||
|
"fieldtype": "HTML",
|
||||||
|
"options": "<h5 class=\"text-muted uppercase\">Or</h5>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:!doc.__islocal && !doc.import_file\n",
|
||||||
|
"description": "Must be a publicly accessible Google Sheets URL",
|
||||||
|
"fieldname": "google_sheets_url",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Import from Google Sheets"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.google_sheets_url && !doc.__unsaved",
|
||||||
|
"fieldname": "refresh_google_sheet",
|
||||||
|
"fieldtype": "Button",
|
||||||
|
"label": "Refresh Google Sheet"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "Bank Transaction",
|
||||||
|
"fieldname": "reference_doctype",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 1,
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Document Type",
|
||||||
|
"options": "DocType",
|
||||||
|
"reqd": 1,
|
||||||
|
"set_only_once": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "Insert New Records",
|
||||||
|
"fieldname": "import_type",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"hidden": 1,
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Import Type",
|
||||||
|
"options": "\nInsert New Records\nUpdate Existing Records",
|
||||||
|
"reqd": 1,
|
||||||
|
"set_only_once": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "1",
|
||||||
|
"fieldname": "submit_after_import",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Submit After Import",
|
||||||
|
"set_only_once": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "1",
|
||||||
|
"fieldname": "mute_emails",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Don't Send Emails",
|
||||||
|
"set_only_once": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_4",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hide_toolbar": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2021-02-10 19:29:59.027325",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Accounts",
|
||||||
|
"name": "Bank Statement Import",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "System Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"track_changes": 1
|
||||||
|
}
|
@ -0,0 +1,205 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2019, Frappe Technologies and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import csv
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
|
import openpyxl
|
||||||
|
from openpyxl.styles import Font
|
||||||
|
from openpyxl.utils import get_column_letter
|
||||||
|
from six import string_types
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from frappe.core.doctype.data_import.importer import Importer, ImportFile
|
||||||
|
from frappe.utils.background_jobs import enqueue
|
||||||
|
from frappe.utils.xlsxutils import handle_html, ILLEGAL_CHARACTERS_RE
|
||||||
|
from frappe import _
|
||||||
|
|
||||||
|
from frappe.core.doctype.data_import.data_import import DataImport
|
||||||
|
|
||||||
|
class BankStatementImport(DataImport):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(BankStatementImport, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
doc_before_save = self.get_doc_before_save()
|
||||||
|
if (
|
||||||
|
not (self.import_file or self.google_sheets_url)
|
||||||
|
or (doc_before_save and doc_before_save.import_file != self.import_file)
|
||||||
|
or (doc_before_save and doc_before_save.google_sheets_url != self.google_sheets_url)
|
||||||
|
):
|
||||||
|
|
||||||
|
template_options_dict = {}
|
||||||
|
column_to_field_map = {}
|
||||||
|
bank = frappe.get_doc("Bank", self.bank)
|
||||||
|
for i in bank.bank_transaction_mapping:
|
||||||
|
column_to_field_map[i.file_field] = i.bank_transaction_field
|
||||||
|
template_options_dict["column_to_field_map"] = column_to_field_map
|
||||||
|
self.template_options = json.dumps(template_options_dict)
|
||||||
|
|
||||||
|
self.template_warnings = ""
|
||||||
|
|
||||||
|
self.validate_import_file()
|
||||||
|
self.validate_google_sheets_url()
|
||||||
|
|
||||||
|
def start_import(self):
|
||||||
|
|
||||||
|
from frappe.core.page.background_jobs.background_jobs import get_info
|
||||||
|
from frappe.utils.scheduler import is_scheduler_inactive
|
||||||
|
|
||||||
|
if is_scheduler_inactive() and not frappe.flags.in_test:
|
||||||
|
frappe.throw(
|
||||||
|
_("Scheduler is inactive. Cannot import data."), title=_("Scheduler Inactive")
|
||||||
|
)
|
||||||
|
|
||||||
|
enqueued_jobs = [d.get("job_name") for d in get_info()]
|
||||||
|
|
||||||
|
if self.name not in enqueued_jobs:
|
||||||
|
enqueue(
|
||||||
|
start_import,
|
||||||
|
queue="default",
|
||||||
|
timeout=6000,
|
||||||
|
event="data_import",
|
||||||
|
job_name=self.name,
|
||||||
|
data_import=self.name,
|
||||||
|
bank_account=self.bank_account,
|
||||||
|
import_file_path=self.import_file,
|
||||||
|
bank=self.bank,
|
||||||
|
template_options=self.template_options,
|
||||||
|
now=frappe.conf.developer_mode or frappe.flags.in_test,
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_preview_from_template(data_import, import_file=None, google_sheets_url=None):
|
||||||
|
return frappe.get_doc("Bank Statement Import", data_import).get_preview_from_template(
|
||||||
|
import_file, google_sheets_url
|
||||||
|
)
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def form_start_import(data_import):
|
||||||
|
return frappe.get_doc("Bank Statement Import", data_import).start_import()
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def download_errored_template(data_import_name):
|
||||||
|
data_import = frappe.get_doc("Bank Statement Import", data_import_name)
|
||||||
|
data_import.export_errored_rows()
|
||||||
|
|
||||||
|
def start_import(data_import, bank_account, import_file_path, bank, template_options):
|
||||||
|
"""This method runs in background job"""
|
||||||
|
|
||||||
|
update_mapping_db(bank, template_options)
|
||||||
|
|
||||||
|
data_import = frappe.get_doc("Bank Statement Import", data_import)
|
||||||
|
|
||||||
|
import_file = ImportFile("Bank Transaction", file = import_file_path, import_type="Insert New Records")
|
||||||
|
data = import_file.raw_data
|
||||||
|
|
||||||
|
add_bank_account(data, bank_account)
|
||||||
|
write_files(import_file, data)
|
||||||
|
|
||||||
|
try:
|
||||||
|
i = Importer(data_import.reference_doctype, data_import=data_import)
|
||||||
|
i.import_data()
|
||||||
|
except Exception:
|
||||||
|
frappe.db.rollback()
|
||||||
|
data_import.db_set("status", "Error")
|
||||||
|
frappe.log_error(title=data_import.name)
|
||||||
|
finally:
|
||||||
|
frappe.flags.in_import = False
|
||||||
|
|
||||||
|
frappe.publish_realtime("data_import_refresh", {"data_import": data_import.name})
|
||||||
|
|
||||||
|
def update_mapping_db(bank, template_options):
|
||||||
|
bank = frappe.get_doc("Bank", bank)
|
||||||
|
for d in bank.bank_transaction_mapping:
|
||||||
|
d.delete()
|
||||||
|
|
||||||
|
for d in json.loads(template_options)["column_to_field_map"].items():
|
||||||
|
bank.append("bank_transaction_mapping", {"bank_transaction_field": d[1] ,"file_field": d[0]} )
|
||||||
|
|
||||||
|
bank.save()
|
||||||
|
|
||||||
|
def add_bank_account(data, bank_account):
|
||||||
|
bank_account_loc = None
|
||||||
|
if "Bank Account" not in data[0]:
|
||||||
|
data[0].append("Bank Account")
|
||||||
|
else:
|
||||||
|
for loc, header in enumerate(data[0]):
|
||||||
|
if header == "Bank Account":
|
||||||
|
bank_account_loc = loc
|
||||||
|
|
||||||
|
for row in data[1:]:
|
||||||
|
if bank_account_loc:
|
||||||
|
row[bank_account_loc] = bank_account
|
||||||
|
else:
|
||||||
|
row.append(bank_account)
|
||||||
|
|
||||||
|
def write_files(import_file, data):
|
||||||
|
full_file_path = import_file.file_doc.get_full_path()
|
||||||
|
parts = import_file.file_doc.get_extension()
|
||||||
|
extension = parts[1]
|
||||||
|
extension = extension.lstrip(".")
|
||||||
|
|
||||||
|
if extension == "csv":
|
||||||
|
with open(full_file_path, 'w', newline='') as file:
|
||||||
|
writer = csv.writer(file)
|
||||||
|
writer.writerows(data)
|
||||||
|
elif extension == "xlsx" or "xls":
|
||||||
|
write_xlsx(data, "trans", file_path = full_file_path)
|
||||||
|
|
||||||
|
def write_xlsx(data, sheet_name, wb=None, column_widths=None, file_path=None):
|
||||||
|
# from xlsx utils with changes
|
||||||
|
column_widths = column_widths or []
|
||||||
|
if wb is None:
|
||||||
|
wb = openpyxl.Workbook(write_only=True)
|
||||||
|
|
||||||
|
ws = wb.create_sheet(sheet_name, 0)
|
||||||
|
|
||||||
|
for i, column_width in enumerate(column_widths):
|
||||||
|
if column_width:
|
||||||
|
ws.column_dimensions[get_column_letter(i + 1)].width = column_width
|
||||||
|
|
||||||
|
row1 = ws.row_dimensions[1]
|
||||||
|
row1.font = Font(name='Calibri', bold=True)
|
||||||
|
|
||||||
|
for row in data:
|
||||||
|
clean_row = []
|
||||||
|
for item in row:
|
||||||
|
if isinstance(item, string_types) and (sheet_name not in ['Data Import Template', 'Data Export']):
|
||||||
|
value = handle_html(item)
|
||||||
|
else:
|
||||||
|
value = item
|
||||||
|
|
||||||
|
if isinstance(item, string_types) and next(ILLEGAL_CHARACTERS_RE.finditer(value), None):
|
||||||
|
# Remove illegal characters from the string
|
||||||
|
value = re.sub(ILLEGAL_CHARACTERS_RE, '', value)
|
||||||
|
|
||||||
|
clean_row.append(value)
|
||||||
|
|
||||||
|
ws.append(clean_row)
|
||||||
|
|
||||||
|
wb.save(file_path)
|
||||||
|
return True
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def upload_bank_statement(**args):
|
||||||
|
args = frappe._dict(args)
|
||||||
|
bsi = frappe.new_doc("Bank Statement Import")
|
||||||
|
|
||||||
|
if args.company:
|
||||||
|
bsi.update({
|
||||||
|
"company": args.company,
|
||||||
|
})
|
||||||
|
|
||||||
|
if args.bank_account:
|
||||||
|
bsi.update({
|
||||||
|
"bank_account": args.bank_account
|
||||||
|
})
|
||||||
|
|
||||||
|
return bsi
|
@ -0,0 +1,36 @@
|
|||||||
|
let imports_in_progress = [];
|
||||||
|
|
||||||
|
frappe.listview_settings['Bank Statement Import'] = {
|
||||||
|
onload(listview) {
|
||||||
|
frappe.realtime.on('data_import_progress', data => {
|
||||||
|
if (!imports_in_progress.includes(data.data_import)) {
|
||||||
|
imports_in_progress.push(data.data_import);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
frappe.realtime.on('data_import_refresh', data => {
|
||||||
|
imports_in_progress = imports_in_progress.filter(
|
||||||
|
d => d !== data.data_import
|
||||||
|
);
|
||||||
|
listview.refresh();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
get_indicator: function(doc) {
|
||||||
|
var colors = {
|
||||||
|
'Pending': 'orange',
|
||||||
|
'Not Started': 'orange',
|
||||||
|
'Partial Success': 'orange',
|
||||||
|
'Success': 'green',
|
||||||
|
'In Progress': 'orange',
|
||||||
|
'Error': 'red'
|
||||||
|
};
|
||||||
|
let status = doc.status;
|
||||||
|
if (imports_in_progress.includes(doc.name)) {
|
||||||
|
status = 'In Progress';
|
||||||
|
}
|
||||||
|
if (status == 'Pending') {
|
||||||
|
status = 'Not Started';
|
||||||
|
}
|
||||||
|
return [__(status), colors[status], 'status,=,' + doc.status];
|
||||||
|
},
|
||||||
|
hide_name_column: true
|
||||||
|
};
|
@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2020, Frappe Technologies and Contributors
|
||||||
|
# See license.txt
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class TestBankStatementImport(unittest.TestCase):
|
||||||
|
pass
|
@ -1,8 +0,0 @@
|
|||||||
// Copyright (c) 2017, sathishpy@gmail.com and contributors
|
|
||||||
// For license information, please see license.txt
|
|
||||||
|
|
||||||
frappe.ui.form.on('Bank Statement Settings', {
|
|
||||||
refresh: function(frm) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,272 +0,0 @@
|
|||||||
{
|
|
||||||
"allow_copy": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 1,
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2017-11-13 13:38:10.863592",
|
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
|
||||||
"engine": "InnoDB",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "bank",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Bank Account",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Bank",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "'%d/%m/%Y'",
|
|
||||||
"fieldname": "date_format",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Date Format",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "statement_header_mapping",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Statement Header Mapping",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "header_items",
|
|
||||||
"fieldtype": "Table",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Statement Headers",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Bank Statement Settings Item",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "transaction_data_mapping",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Transaction Data Mapping",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "mapped_items",
|
|
||||||
"fieldtype": "Table",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Mapped Items",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Bank Statement Transaction Settings Item",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-04-07 18:57:04.048423",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Accounts",
|
|
||||||
"name": "Bank Statement Settings",
|
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [
|
|
||||||
{
|
|
||||||
"amend": 0,
|
|
||||||
"apply_user_permissions": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
|
||||||
"delete": 1,
|
|
||||||
"email": 1,
|
|
||||||
"export": 1,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "System Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"amend": 0,
|
|
||||||
"apply_user_permissions": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
|
||||||
"delete": 1,
|
|
||||||
"email": 1,
|
|
||||||
"export": 1,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "Accounts Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"quick_entry": 1,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
|
||||||
"sort_order": "DESC",
|
|
||||||
"track_changes": 1,
|
|
||||||
"track_seen": 0
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (c) 2017, sathishpy@gmail.com and contributors
|
|
||||||
# For license information, please see license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
from frappe.model.document import Document
|
|
||||||
|
|
||||||
class BankStatementSettings(Document):
|
|
||||||
def autoname(self):
|
|
||||||
self.name = self.bank + "-Statement-Settings"
|
|
@ -1,23 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
// rename this file from _test_[name] to test_[name] to activate
|
|
||||||
// and remove above this line
|
|
||||||
|
|
||||||
QUnit.test("test: Bank Statement Settings", function (assert) {
|
|
||||||
let done = assert.async();
|
|
||||||
|
|
||||||
// number of asserts
|
|
||||||
assert.expect(1);
|
|
||||||
|
|
||||||
frappe.run_serially([
|
|
||||||
// insert a new Bank Statement Settings
|
|
||||||
() => frappe.tests.make('Bank Statement Settings', [
|
|
||||||
// values to be set
|
|
||||||
{key: 'value'}
|
|
||||||
]),
|
|
||||||
() => {
|
|
||||||
assert.equal(cur_frm.doc.key, 'value');
|
|
||||||
},
|
|
||||||
() => done()
|
|
||||||
]);
|
|
||||||
|
|
||||||
});
|
|
@ -1,10 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (c) 2017, sathishpy@gmail.com and Contributors
|
|
||||||
# See license.txt
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import frappe
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
class TestBankStatementSettings(unittest.TestCase):
|
|
||||||
pass
|
|
@ -1,101 +0,0 @@
|
|||||||
{
|
|
||||||
"allow_copy": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2018-01-08 00:16:42.762980",
|
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
|
||||||
"engine": "InnoDB",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "mapped_header",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Mapped Header",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "stmt_header",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Bank Header",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 1,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-01-08 00:19:14.841134",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Accounts",
|
|
||||||
"name": "Bank Statement Settings Item",
|
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [],
|
|
||||||
"quick_entry": 1,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
|
||||||
"sort_order": "DESC",
|
|
||||||
"track_changes": 1,
|
|
||||||
"track_seen": 0
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
// Copyright (c) 2017, sathishpy@gmail.com and contributors
|
|
||||||
// For license information, please see license.txt
|
|
||||||
|
|
||||||
frappe.ui.form.on('Bank Statement Transaction Entry', {
|
|
||||||
setup: function(frm) {
|
|
||||||
frm.events.account_filters(frm)
|
|
||||||
frm.events.invoice_filter(frm)
|
|
||||||
},
|
|
||||||
refresh: function(frm) {
|
|
||||||
frm.set_df_property("bank_account", "read_only", frm.doc.__islocal ? 0 : 1);
|
|
||||||
frm.set_df_property("from_date", "read_only", frm.doc.__islocal ? 0 : 1);
|
|
||||||
frm.set_df_property("to_date", "read_only", frm.doc.__islocal ? 0 : 1);
|
|
||||||
},
|
|
||||||
invoke_doc_function(frm, method) {
|
|
||||||
frappe.call({
|
|
||||||
doc: frm.doc,
|
|
||||||
method: method,
|
|
||||||
callback: function(r) {
|
|
||||||
if(!r.exe) {
|
|
||||||
frm.refresh_fields();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
account_filters: function(frm) {
|
|
||||||
frm.fields_dict['bank_account'].get_query = function(doc, dt, dn) {
|
|
||||||
return {
|
|
||||||
filters:[
|
|
||||||
["Account", "account_type", "in", ["Bank"]]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
frm.fields_dict['receivable_account'].get_query = function(doc, dt, dn) {
|
|
||||||
return {
|
|
||||||
filters: {"account_type": "Receivable"}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
frm.fields_dict['payable_account'].get_query = function(doc, dt, dn) {
|
|
||||||
return {
|
|
||||||
filters: {"account_type": "Payable"}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
invoice_filter: function(frm) {
|
|
||||||
frm.set_query("invoice", "payment_invoice_items", function(doc, cdt, cdn) {
|
|
||||||
let row = locals[cdt][cdn]
|
|
||||||
if (row.party_type == "Customer") {
|
|
||||||
return {
|
|
||||||
filters:[[row.invoice_type, "customer", "in", [row.party]],
|
|
||||||
[row.invoice_type, "status", "!=", "Cancelled" ],
|
|
||||||
[row.invoice_type, "posting_date", "<", row.transaction_date ],
|
|
||||||
[row.invoice_type, "outstanding_amount", ">", 0 ]]
|
|
||||||
}
|
|
||||||
} else if (row.party_type == "Supplier") {
|
|
||||||
return {
|
|
||||||
filters:[[row.invoice_type, "supplier", "in", [row.party]],
|
|
||||||
[row.invoice_type, "status", "!=", "Cancelled" ],
|
|
||||||
[row.invoice_type, "posting_date", "<", row.transaction_date ],
|
|
||||||
[row.invoice_type, "outstanding_amount", ">", 0 ]]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
match_invoices: function(frm) {
|
|
||||||
frm.events.invoke_doc_function(frm, "populate_matching_invoices");
|
|
||||||
},
|
|
||||||
create_payments: function(frm) {
|
|
||||||
frm.events.invoke_doc_function(frm, "create_payment_entries");
|
|
||||||
},
|
|
||||||
submit_payments: function(frm) {
|
|
||||||
frm.events.invoke_doc_function(frm, "submit_payment_entries");
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
frappe.ui.form.on('Bank Statement Transaction Invoice Item', {
|
|
||||||
party_type: function(frm, cdt, cdn) {
|
|
||||||
let row = locals[cdt][cdn];
|
|
||||||
if (row.party_type == "Customer") {
|
|
||||||
row.invoice_type = "Sales Invoice";
|
|
||||||
} else if (row.party_type == "Supplier") {
|
|
||||||
row.invoice_type = "Purchase Invoice";
|
|
||||||
} else if (row.party_type == "Account") {
|
|
||||||
row.invoice_type = "Journal Entry";
|
|
||||||
}
|
|
||||||
refresh_field("invoice_type", row.name, "payment_invoice_items");
|
|
||||||
|
|
||||||
},
|
|
||||||
invoice_type: function(frm, cdt, cdn) {
|
|
||||||
let row = locals[cdt][cdn];
|
|
||||||
if (row.invoice_type == "Purchase Invoice") {
|
|
||||||
row.party_type = "Supplier";
|
|
||||||
} else if (row.invoice_type == "Sales Invoice") {
|
|
||||||
row.party_type = "Customer";
|
|
||||||
}
|
|
||||||
refresh_field("party_type", row.name, "payment_invoice_items");
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,792 +0,0 @@
|
|||||||
{
|
|
||||||
"allow_copy": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 1,
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2017-11-07 13:48:13.123185",
|
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
|
||||||
"engine": "InnoDB",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "bank_account",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Bank Account",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Account",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "from_date",
|
|
||||||
"fieldtype": "Date",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "From Date",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "to_date",
|
|
||||||
"fieldtype": "Date",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "To Date",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "bank_settings",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Bank Statement Settings",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Bank Statement Settings",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_3",
|
|
||||||
"fieldtype": "Column Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "bank",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Bank",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Bank",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "receivable_account",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Receivable Account",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Account",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "payable_account",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Payable Account",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Account",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "bank_statement",
|
|
||||||
"fieldtype": "Attach",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Bank Statement",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "",
|
|
||||||
"fieldname": "section_break_6",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Bank Transaction Entries",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "new_transaction_items",
|
|
||||||
"fieldtype": "Table",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "New Transactions",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Bank Statement Transaction Payment Item",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "eval:doc.new_transaction_items && doc.new_transaction_items.length",
|
|
||||||
"fieldname": "section_break_9",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "",
|
|
||||||
"fieldname": "match_invoices",
|
|
||||||
"fieldtype": "Button",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Match Transaction to Invoices",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_14",
|
|
||||||
"fieldtype": "Column Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "create_payments",
|
|
||||||
"fieldtype": "Button",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Create New Payment/Journal Entry",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_16",
|
|
||||||
"fieldtype": "Column Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "submit_payments",
|
|
||||||
"fieldtype": "Button",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Submit/Reconcile Payments",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "eval:doc.new_transaction_items && doc.new_transaction_items.length",
|
|
||||||
"fieldname": "section_break_18",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Matching Invoices",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "payment_invoice_items",
|
|
||||||
"fieldtype": "Table",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Payment Invoice Items",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Bank Statement Transaction Invoice Item",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "reconciled_transactions",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Reconciled Transactions",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "reconciled_transaction_items",
|
|
||||||
"fieldtype": "Table",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Reconciled Transactions",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Bank Statement Transaction Payment Item",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "amended_from",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Amended From",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
|
||||||
"options": "Bank Statement Transaction Entry",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 1,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 1,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-09-14 18:04:44.170455",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Accounts",
|
|
||||||
"name": "Bank Statement Transaction Entry",
|
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [
|
|
||||||
{
|
|
||||||
"amend": 1,
|
|
||||||
"cancel": 1,
|
|
||||||
"create": 1,
|
|
||||||
"delete": 1,
|
|
||||||
"email": 1,
|
|
||||||
"export": 1,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "System Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 1,
|
|
||||||
"write": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"amend": 1,
|
|
||||||
"cancel": 1,
|
|
||||||
"create": 1,
|
|
||||||
"delete": 1,
|
|
||||||
"email": 1,
|
|
||||||
"export": 1,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "Accounts Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 1,
|
|
||||||
"write": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"quick_entry": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
|
||||||
"sort_order": "DESC",
|
|
||||||
"track_changes": 1,
|
|
||||||
"track_seen": 0
|
|
||||||
}
|
|
@ -1,443 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (c) 2017, sathishpy@gmail.com and contributors
|
|
||||||
# For license information, please see license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
from frappe import _
|
|
||||||
from frappe.model.document import Document
|
|
||||||
from erpnext.accounts.utils import get_outstanding_invoices
|
|
||||||
from frappe.utils import nowdate
|
|
||||||
from datetime import datetime
|
|
||||||
import csv, os, re, io
|
|
||||||
import difflib
|
|
||||||
import copy
|
|
||||||
|
|
||||||
class BankStatementTransactionEntry(Document):
|
|
||||||
def autoname(self):
|
|
||||||
self.name = self.bank_account + "-" + self.from_date + "-" + self.to_date
|
|
||||||
if self.bank:
|
|
||||||
mapper_name = self.bank + "-Statement-Settings"
|
|
||||||
if not frappe.db.exists("Bank Statement Settings", mapper_name):
|
|
||||||
self.create_settings(self.bank)
|
|
||||||
self.bank_settings = mapper_name
|
|
||||||
|
|
||||||
def create_settings(self, bank):
|
|
||||||
mapper = frappe.new_doc("Bank Statement Settings")
|
|
||||||
mapper.bank = bank
|
|
||||||
mapper.date_format = "%Y-%m-%d"
|
|
||||||
mapper.bank_account = self.bank_account
|
|
||||||
for header in ["Date", "Particulars", "Withdrawals", "Deposits", "Balance"]:
|
|
||||||
header_item = mapper.append("header_items", {})
|
|
||||||
header_item.mapped_header = header_item.stmt_header = header
|
|
||||||
mapper.save()
|
|
||||||
|
|
||||||
def on_update(self):
|
|
||||||
if (not self.bank_statement):
|
|
||||||
self.reconciled_transaction_items = self.new_transaction_items = []
|
|
||||||
return
|
|
||||||
|
|
||||||
if len(self.new_transaction_items + self.reconciled_transaction_items) == 0:
|
|
||||||
self.populate_payment_entries()
|
|
||||||
else:
|
|
||||||
self.match_invoice_to_payment()
|
|
||||||
|
|
||||||
def validate(self):
|
|
||||||
if not self.new_transaction_items:
|
|
||||||
self.populate_payment_entries()
|
|
||||||
|
|
||||||
def get_statement_headers(self):
|
|
||||||
if not self.bank_settings:
|
|
||||||
frappe.throw(_("Bank Data mapper doesn't exist"))
|
|
||||||
mapper_doc = frappe.get_doc("Bank Statement Settings", self.bank_settings)
|
|
||||||
headers = {entry.mapped_header:entry.stmt_header for entry in mapper_doc.header_items}
|
|
||||||
return headers
|
|
||||||
|
|
||||||
def populate_payment_entries(self):
|
|
||||||
if self.bank_statement is None: return
|
|
||||||
file_url = self.bank_statement
|
|
||||||
if (len(self.new_transaction_items + self.reconciled_transaction_items) > 0):
|
|
||||||
frappe.throw(_("Transactions already retreived from the statement"))
|
|
||||||
|
|
||||||
date_format = frappe.get_value("Bank Statement Settings", self.bank_settings, "date_format")
|
|
||||||
if (date_format is None):
|
|
||||||
date_format = '%Y-%m-%d'
|
|
||||||
if self.bank_settings:
|
|
||||||
mapped_items = frappe.get_doc("Bank Statement Settings", self.bank_settings).mapped_items
|
|
||||||
statement_headers = self.get_statement_headers()
|
|
||||||
transactions = get_transaction_entries(file_url, statement_headers)
|
|
||||||
for entry in transactions:
|
|
||||||
date = entry[statement_headers["Date"]].strip()
|
|
||||||
#print("Processing entry DESC:{0}-W:{1}-D:{2}-DT:{3}".format(entry["Particulars"], entry["Withdrawals"], entry["Deposits"], entry["Date"]))
|
|
||||||
if (not date): continue
|
|
||||||
transaction_date = datetime.strptime(date, date_format).date()
|
|
||||||
if (self.from_date and transaction_date < datetime.strptime(self.from_date, '%Y-%m-%d').date()): continue
|
|
||||||
if (self.to_date and transaction_date > datetime.strptime(self.to_date, '%Y-%m-%d').date()): continue
|
|
||||||
bank_entry = self.append('new_transaction_items', {})
|
|
||||||
bank_entry.transaction_date = transaction_date
|
|
||||||
bank_entry.description = entry[statement_headers["Particulars"]]
|
|
||||||
|
|
||||||
mapped_item = next((entry for entry in mapped_items if entry.mapping_type == "Transaction" and frappe.safe_decode(entry.bank_data.lower()) in frappe.safe_decode(bank_entry.description.lower())), None)
|
|
||||||
if (mapped_item is not None):
|
|
||||||
bank_entry.party_type = mapped_item.mapped_data_type
|
|
||||||
bank_entry.party = mapped_item.mapped_data
|
|
||||||
else:
|
|
||||||
bank_entry.party_type = "Supplier" if not entry[statement_headers["Deposits"]].strip() else "Customer"
|
|
||||||
party_list = frappe.get_all(bank_entry.party_type, fields=["name"])
|
|
||||||
parties = [party.name for party in party_list]
|
|
||||||
matches = difflib.get_close_matches(frappe.safe_decode(bank_entry.description.lower()), parties, 1, 0.4)
|
|
||||||
if len(matches) > 0: bank_entry.party = matches[0]
|
|
||||||
bank_entry.amount = -float(entry[statement_headers["Withdrawals"]]) if not entry[statement_headers["Deposits"]].strip() else float(entry[statement_headers["Deposits"]])
|
|
||||||
self.map_unknown_transactions()
|
|
||||||
self.map_transactions_on_journal_entry()
|
|
||||||
|
|
||||||
def map_transactions_on_journal_entry(self):
|
|
||||||
for entry in self.new_transaction_items:
|
|
||||||
vouchers = frappe.db.sql("""select name, posting_date from `tabJournal Entry`
|
|
||||||
where posting_date='{0}' and total_credit={1} and cheque_no='{2}' and docstatus != 2
|
|
||||||
""".format(entry.transaction_date, abs(entry.amount), frappe.safe_decode(entry.description)), as_dict=True)
|
|
||||||
if (len(vouchers) == 1):
|
|
||||||
entry.reference_name = vouchers[0].name
|
|
||||||
|
|
||||||
def populate_matching_invoices(self):
|
|
||||||
self.payment_invoice_items = []
|
|
||||||
self.map_unknown_transactions()
|
|
||||||
added_invoices = []
|
|
||||||
for entry in self.new_transaction_items:
|
|
||||||
if (not entry.party or entry.party_type == "Account"): continue
|
|
||||||
account = self.receivable_account if entry.party_type == "Customer" else self.payable_account
|
|
||||||
invoices = get_outstanding_invoices(entry.party_type, entry.party, account)
|
|
||||||
transaction_date = datetime.strptime(entry.transaction_date, "%Y-%m-%d").date()
|
|
||||||
outstanding_invoices = [invoice for invoice in invoices if invoice.posting_date <= transaction_date]
|
|
||||||
amount = abs(entry.amount)
|
|
||||||
matching_invoices = [invoice for invoice in outstanding_invoices if invoice.outstanding_amount == amount]
|
|
||||||
sorted(outstanding_invoices, key=lambda k: k['posting_date'])
|
|
||||||
for e in (matching_invoices + outstanding_invoices):
|
|
||||||
added = next((inv for inv in added_invoices if inv == e.get('voucher_no')), None)
|
|
||||||
if (added is not None): continue
|
|
||||||
ent = self.append('payment_invoice_items', {})
|
|
||||||
ent.transaction_date = entry.transaction_date
|
|
||||||
ent.payment_description = frappe.safe_decode(entry.description)
|
|
||||||
ent.party_type = entry.party_type
|
|
||||||
ent.party = entry.party
|
|
||||||
ent.invoice = e.get('voucher_no')
|
|
||||||
added_invoices += [ent.invoice]
|
|
||||||
ent.invoice_type = "Sales Invoice" if entry.party_type == "Customer" else "Purchase Invoice"
|
|
||||||
ent.invoice_date = e.get('posting_date')
|
|
||||||
ent.outstanding_amount = e.get('outstanding_amount')
|
|
||||||
ent.allocated_amount = min(float(e.get('outstanding_amount')), amount)
|
|
||||||
amount -= float(e.get('outstanding_amount'))
|
|
||||||
if (amount <= 5): break
|
|
||||||
self.match_invoice_to_payment()
|
|
||||||
self.populate_matching_vouchers()
|
|
||||||
self.map_transactions_on_journal_entry()
|
|
||||||
|
|
||||||
def match_invoice_to_payment(self):
|
|
||||||
added_payments = []
|
|
||||||
for entry in self.new_transaction_items:
|
|
||||||
if (not entry.party or entry.party_type == "Account"): continue
|
|
||||||
entry.account = self.receivable_account if entry.party_type == "Customer" else self.payable_account
|
|
||||||
amount = abs(entry.amount)
|
|
||||||
payment, matching_invoices = None, []
|
|
||||||
for inv_entry in self.payment_invoice_items:
|
|
||||||
if (inv_entry.payment_description != frappe.safe_decode(entry.description) or inv_entry.transaction_date != entry.transaction_date): continue
|
|
||||||
if (inv_entry.party != entry.party): continue
|
|
||||||
matching_invoices += [inv_entry.invoice_type + "|" + inv_entry.invoice]
|
|
||||||
payment = get_payments_matching_invoice(inv_entry.invoice, entry.amount, entry.transaction_date)
|
|
||||||
doc = frappe.get_doc(inv_entry.invoice_type, inv_entry.invoice)
|
|
||||||
inv_entry.invoice_date = doc.posting_date
|
|
||||||
inv_entry.outstanding_amount = doc.outstanding_amount
|
|
||||||
inv_entry.allocated_amount = min(float(doc.outstanding_amount), amount)
|
|
||||||
amount -= inv_entry.allocated_amount
|
|
||||||
if (amount < 0): break
|
|
||||||
|
|
||||||
amount = abs(entry.amount)
|
|
||||||
if (payment is None):
|
|
||||||
order_doctype = "Sales Order" if entry.party_type=="Customer" else "Purchase Order"
|
|
||||||
from erpnext.controllers.accounts_controller import get_advance_payment_entries
|
|
||||||
payment_entries = get_advance_payment_entries(entry.party_type, entry.party, entry.account, order_doctype, against_all_orders=True)
|
|
||||||
payment_entries += self.get_matching_payments(entry.party, amount, entry.transaction_date)
|
|
||||||
payment = next((payment for payment in payment_entries if payment.amount == amount and payment not in added_payments), None)
|
|
||||||
if (payment is None):
|
|
||||||
print("Failed to find payments for {0}:{1}".format(entry.party, amount))
|
|
||||||
continue
|
|
||||||
added_payments += [payment]
|
|
||||||
entry.reference_type = payment.reference_type
|
|
||||||
entry.reference_name = payment.reference_name
|
|
||||||
entry.mode_of_payment = "Wire Transfer"
|
|
||||||
entry.outstanding_amount = min(amount, 0)
|
|
||||||
if (entry.payment_reference is None):
|
|
||||||
entry.payment_reference = frappe.safe_decode(entry.description)
|
|
||||||
entry.invoices = ",".join(matching_invoices)
|
|
||||||
#print("Matching payment is {0}:{1}".format(entry.reference_type, entry.reference_name))
|
|
||||||
|
|
||||||
def get_matching_payments(self, party, amount, pay_date):
|
|
||||||
query = """select 'Payment Entry' as reference_type, name as reference_name, paid_amount as amount
|
|
||||||
from `tabPayment Entry` where party='{0}' and paid_amount={1} and posting_date='{2}' and docstatus != 2
|
|
||||||
""".format(party, amount, pay_date)
|
|
||||||
matching_payments = frappe.db.sql(query, as_dict=True)
|
|
||||||
return matching_payments
|
|
||||||
|
|
||||||
def map_unknown_transactions(self):
|
|
||||||
for entry in self.new_transaction_items:
|
|
||||||
if (entry.party): continue
|
|
||||||
inv_type = "Sales Invoice" if (entry.amount > 0) else "Purchase Invoice"
|
|
||||||
party_type = "customer" if (entry.amount > 0) else "supplier"
|
|
||||||
|
|
||||||
query = """select posting_date, name, {0}, outstanding_amount
|
|
||||||
from `tab{1}` where ROUND(outstanding_amount)={2} and posting_date < '{3}'
|
|
||||||
""".format(party_type, inv_type, round(abs(entry.amount)), entry.transaction_date)
|
|
||||||
invoices = frappe.db.sql(query, as_dict = True)
|
|
||||||
if(len(invoices) > 0):
|
|
||||||
entry.party = invoices[0].get(party_type)
|
|
||||||
|
|
||||||
def populate_matching_vouchers(self):
|
|
||||||
for entry in self.new_transaction_items:
|
|
||||||
if (not entry.party or entry.reference_name): continue
|
|
||||||
print("Finding matching voucher for {0}".format(frappe.safe_decode(entry.description)))
|
|
||||||
amount = abs(entry.amount)
|
|
||||||
invoices = []
|
|
||||||
vouchers = get_matching_journal_entries(self.from_date, self.to_date, entry.party, self.bank_account, amount)
|
|
||||||
if len(vouchers) == 0: continue
|
|
||||||
for voucher in vouchers:
|
|
||||||
added = next((entry.invoice for entry in self.payment_invoice_items if entry.invoice == voucher.voucher_no), None)
|
|
||||||
if (added):
|
|
||||||
print("Found voucher {0}".format(added))
|
|
||||||
continue
|
|
||||||
print("Adding voucher {0} {1} {2}".format(voucher.voucher_no, voucher.posting_date, voucher.debit))
|
|
||||||
ent = self.append('payment_invoice_items', {})
|
|
||||||
ent.invoice_date = voucher.posting_date
|
|
||||||
ent.invoice_type = "Journal Entry"
|
|
||||||
ent.invoice = voucher.voucher_no
|
|
||||||
ent.payment_description = frappe.safe_decode(entry.description)
|
|
||||||
ent.allocated_amount = max(voucher.debit, voucher.credit)
|
|
||||||
|
|
||||||
invoices += [ent.invoice_type + "|" + ent.invoice]
|
|
||||||
entry.reference_type = "Journal Entry"
|
|
||||||
entry.mode_of_payment = "Wire Transfer"
|
|
||||||
entry.reference_name = ent.invoice
|
|
||||||
#entry.account = entry.party
|
|
||||||
entry.invoices = ",".join(invoices)
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
def create_payment_entries(self):
|
|
||||||
for payment_entry in self.new_transaction_items:
|
|
||||||
if (not payment_entry.party): continue
|
|
||||||
if (payment_entry.reference_name): continue
|
|
||||||
print("Creating payment entry for {0}".format(frappe.safe_decode(payment_entry.description)))
|
|
||||||
if (payment_entry.party_type == "Account"):
|
|
||||||
payment = self.create_journal_entry(payment_entry)
|
|
||||||
invoices = [payment.doctype + "|" + payment.name]
|
|
||||||
payment_entry.invoices = ",".join(invoices)
|
|
||||||
else:
|
|
||||||
payment = self.create_payment_entry(payment_entry)
|
|
||||||
invoices = [entry.reference_doctype + "|" + entry.reference_name for entry in payment.references if entry is not None]
|
|
||||||
payment_entry.invoices = ",".join(invoices)
|
|
||||||
payment_entry.mode_of_payment = payment.mode_of_payment
|
|
||||||
payment_entry.account = self.receivable_account if payment_entry.party_type == "Customer" else self.payable_account
|
|
||||||
payment_entry.reference_name = payment.name
|
|
||||||
payment_entry.reference_type = payment.doctype
|
|
||||||
frappe.msgprint(_("Successfully created payment entries"))
|
|
||||||
|
|
||||||
def create_payment_entry(self, pe):
|
|
||||||
payment = frappe.new_doc("Payment Entry")
|
|
||||||
payment.posting_date = pe.transaction_date
|
|
||||||
payment.payment_type = "Receive" if pe.party_type == "Customer" else "Pay"
|
|
||||||
payment.mode_of_payment = "Wire Transfer"
|
|
||||||
payment.party_type = pe.party_type
|
|
||||||
payment.party = pe.party
|
|
||||||
payment.paid_to = self.bank_account if pe.party_type == "Customer" else self.payable_account
|
|
||||||
payment.paid_from = self.receivable_account if pe.party_type == "Customer" else self.bank_account
|
|
||||||
payment.paid_amount = payment.received_amount = abs(pe.amount)
|
|
||||||
payment.reference_no = pe.description
|
|
||||||
payment.reference_date = pe.transaction_date
|
|
||||||
payment.save()
|
|
||||||
for inv_entry in self.payment_invoice_items:
|
|
||||||
if (pe.description != inv_entry.payment_description or pe.transaction_date != inv_entry.transaction_date): continue
|
|
||||||
if (pe.party != inv_entry.party): continue
|
|
||||||
reference = payment.append("references", {})
|
|
||||||
reference.reference_doctype = inv_entry.invoice_type
|
|
||||||
reference.reference_name = inv_entry.invoice
|
|
||||||
reference.allocated_amount = inv_entry.allocated_amount
|
|
||||||
print ("Adding invoice {0} {1}".format(reference.reference_name, reference.allocated_amount))
|
|
||||||
payment.setup_party_account_field()
|
|
||||||
payment.set_missing_values()
|
|
||||||
#payment.set_exchange_rate()
|
|
||||||
#payment.set_amounts()
|
|
||||||
#print("Created payment entry {0}".format(payment.as_dict()))
|
|
||||||
payment.save()
|
|
||||||
return payment
|
|
||||||
|
|
||||||
def create_journal_entry(self, pe):
|
|
||||||
je = frappe.new_doc("Journal Entry")
|
|
||||||
je.is_opening = "No"
|
|
||||||
je.voucher_type = "Bank Entry"
|
|
||||||
je.cheque_no = pe.description
|
|
||||||
je.cheque_date = pe.transaction_date
|
|
||||||
je.remark = pe.description
|
|
||||||
je.posting_date = pe.transaction_date
|
|
||||||
if (pe.amount < 0):
|
|
||||||
je.append("accounts", {"account": pe.party, "debit_in_account_currency": abs(pe.amount)})
|
|
||||||
je.append("accounts", {"account": self.bank_account, "credit_in_account_currency": abs(pe.amount)})
|
|
||||||
else:
|
|
||||||
je.append("accounts", {"account": pe.party, "credit_in_account_currency": pe.amount})
|
|
||||||
je.append("accounts", {"account": self.bank_account, "debit_in_account_currency": pe.amount})
|
|
||||||
je.save()
|
|
||||||
return je
|
|
||||||
|
|
||||||
def update_payment_entry(self, payment):
|
|
||||||
lst = []
|
|
||||||
invoices = payment.invoices.strip().split(',')
|
|
||||||
if (len(invoices) == 0): return
|
|
||||||
amount = float(abs(payment.amount))
|
|
||||||
for invoice_entry in invoices:
|
|
||||||
if (not invoice_entry.strip()): continue
|
|
||||||
invs = invoice_entry.split('|')
|
|
||||||
invoice_type, invoice = invs[0], invs[1]
|
|
||||||
outstanding_amount = frappe.get_value(invoice_type, invoice, 'outstanding_amount')
|
|
||||||
|
|
||||||
lst.append(frappe._dict({
|
|
||||||
'voucher_type': payment.reference_type,
|
|
||||||
'voucher_no' : payment.reference_name,
|
|
||||||
'against_voucher_type' : invoice_type,
|
|
||||||
'against_voucher' : invoice,
|
|
||||||
'account' : payment.account,
|
|
||||||
'party_type': payment.party_type,
|
|
||||||
'party': frappe.get_value("Payment Entry", payment.reference_name, "party"),
|
|
||||||
'unadjusted_amount' : float(amount),
|
|
||||||
'allocated_amount' : min(outstanding_amount, amount)
|
|
||||||
}))
|
|
||||||
amount -= outstanding_amount
|
|
||||||
if lst:
|
|
||||||
from erpnext.accounts.utils import reconcile_against_document
|
|
||||||
try:
|
|
||||||
reconcile_against_document(lst)
|
|
||||||
except:
|
|
||||||
frappe.throw(_("Exception occurred while reconciling {0}").format(payment.reference_name))
|
|
||||||
|
|
||||||
def submit_payment_entries(self):
|
|
||||||
for payment in self.new_transaction_items:
|
|
||||||
if payment.reference_name is None: continue
|
|
||||||
doc = frappe.get_doc(payment.reference_type, payment.reference_name)
|
|
||||||
if doc.docstatus == 1:
|
|
||||||
if (payment.reference_type == "Journal Entry"): continue
|
|
||||||
if doc.unallocated_amount == 0: continue
|
|
||||||
print("Reconciling payment {0}".format(payment.reference_name))
|
|
||||||
self.update_payment_entry(payment)
|
|
||||||
else:
|
|
||||||
print("Submitting payment {0}".format(payment.reference_name))
|
|
||||||
if (payment.reference_type == "Payment Entry"):
|
|
||||||
if (payment.payment_reference):
|
|
||||||
doc.reference_no = payment.payment_reference
|
|
||||||
doc.mode_of_payment = payment.mode_of_payment
|
|
||||||
doc.save()
|
|
||||||
doc.submit()
|
|
||||||
self.move_reconciled_entries()
|
|
||||||
self.populate_matching_invoices()
|
|
||||||
|
|
||||||
def move_reconciled_entries(self):
|
|
||||||
idx = 0
|
|
||||||
while idx < len(self.new_transaction_items):
|
|
||||||
entry = self.new_transaction_items[idx]
|
|
||||||
try:
|
|
||||||
print("Checking transaction {0}: {2} in {1} entries".format(idx, len(self.new_transaction_items), frappe.safe_decode(entry.description)))
|
|
||||||
except UnicodeEncodeError:
|
|
||||||
pass
|
|
||||||
idx += 1
|
|
||||||
if entry.reference_name is None: continue
|
|
||||||
doc = frappe.get_doc(entry.reference_type, entry.reference_name)
|
|
||||||
if doc.docstatus == 1 and (entry.reference_type == "Journal Entry" or doc.unallocated_amount == 0):
|
|
||||||
self.remove(entry)
|
|
||||||
rc_entry = self.append('reconciled_transaction_items', {})
|
|
||||||
dentry = entry.as_dict()
|
|
||||||
dentry.pop('idx', None)
|
|
||||||
rc_entry.update(dentry)
|
|
||||||
idx -= 1
|
|
||||||
|
|
||||||
|
|
||||||
def get_matching_journal_entries(from_date, to_date, account, against, amount):
|
|
||||||
query = """select voucher_no, posting_date, account, against, debit_in_account_currency as debit, credit_in_account_currency as credit
|
|
||||||
from `tabGL Entry`
|
|
||||||
where posting_date between '{0}' and '{1}' and account = '{2}' and against = '{3}' and debit = '{4}'
|
|
||||||
""".format(from_date, to_date, account, against, amount)
|
|
||||||
jv_entries = frappe.db.sql(query, as_dict=True)
|
|
||||||
#print("voucher query:{0}\n Returned {1} entries".format(query, len(jv_entries)))
|
|
||||||
return jv_entries
|
|
||||||
|
|
||||||
def get_payments_matching_invoice(invoice, amount, pay_date):
|
|
||||||
query = """select pe.name as reference_name, per.reference_doctype as reference_type, per.outstanding_amount, per.allocated_amount
|
|
||||||
from `tabPayment Entry Reference` as per JOIN `tabPayment Entry` as pe on pe.name = per.parent
|
|
||||||
where per.reference_name='{0}' and (posting_date='{1}' or reference_date='{1}') and pe.docstatus != 2
|
|
||||||
""".format(invoice, pay_date)
|
|
||||||
payments = frappe.db.sql(query, as_dict=True)
|
|
||||||
if (len(payments) == 0): return
|
|
||||||
payment = next((payment for payment in payments if payment.allocated_amount == amount), payments[0])
|
|
||||||
#Hack: Update the reference type which is set to invoice type
|
|
||||||
payment.reference_type = "Payment Entry"
|
|
||||||
return payment
|
|
||||||
|
|
||||||
def is_headers_present(headers, row):
|
|
||||||
for header in headers:
|
|
||||||
if header not in row:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def get_header_index(headers, row):
|
|
||||||
header_index = {}
|
|
||||||
for header in headers:
|
|
||||||
if header in row:
|
|
||||||
header_index[header] = row.index(header)
|
|
||||||
return header_index
|
|
||||||
|
|
||||||
def get_transaction_info(headers, header_index, row):
|
|
||||||
transaction = {}
|
|
||||||
for header in headers:
|
|
||||||
transaction[header] = row[header_index[header]]
|
|
||||||
if (transaction[header] == None):
|
|
||||||
transaction[header] = ""
|
|
||||||
return transaction
|
|
||||||
|
|
||||||
def get_transaction_entries(file_url, headers):
|
|
||||||
header_index = {}
|
|
||||||
rows, transactions = [], []
|
|
||||||
|
|
||||||
if (file_url.lower().endswith("xlsx")):
|
|
||||||
from frappe.utils.xlsxutils import read_xlsx_file_from_attached_file
|
|
||||||
rows = read_xlsx_file_from_attached_file(file_url=file_url)
|
|
||||||
elif (file_url.lower().endswith("csv")):
|
|
||||||
from frappe.utils.csvutils import read_csv_content
|
|
||||||
_file = frappe.get_doc("File", {"file_url": file_url})
|
|
||||||
filepath = _file.get_full_path()
|
|
||||||
with open(filepath,'rb') as csvfile:
|
|
||||||
rows = read_csv_content(csvfile.read())
|
|
||||||
elif (file_url.lower().endswith("xls")):
|
|
||||||
filename = file_url.split("/")[-1]
|
|
||||||
rows = get_rows_from_xls_file(filename)
|
|
||||||
else:
|
|
||||||
frappe.throw(_("Only .csv and .xlsx files are supported currently"))
|
|
||||||
|
|
||||||
stmt_headers = headers.values()
|
|
||||||
for row in rows:
|
|
||||||
if len(row) == 0 or row[0] == None or not row[0]: continue
|
|
||||||
#print("Processing row {0}".format(row))
|
|
||||||
if header_index:
|
|
||||||
transaction = get_transaction_info(stmt_headers, header_index, row)
|
|
||||||
transactions.append(transaction)
|
|
||||||
elif is_headers_present(stmt_headers, row):
|
|
||||||
header_index = get_header_index(stmt_headers, row)
|
|
||||||
return transactions
|
|
||||||
|
|
||||||
def get_rows_from_xls_file(filename):
|
|
||||||
_file = frappe.get_doc("File", {"file_name": filename})
|
|
||||||
filepath = _file.get_full_path()
|
|
||||||
import xlrd
|
|
||||||
book = xlrd.open_workbook(filepath)
|
|
||||||
sheets = book.sheets()
|
|
||||||
rows = []
|
|
||||||
for row in range(1, sheets[0].nrows):
|
|
||||||
row_values = []
|
|
||||||
for col in range(1, sheets[0].ncols):
|
|
||||||
row_values.append(sheets[0].cell_value(row, col))
|
|
||||||
rows.append(row_values)
|
|
||||||
return rows
|
|
@ -1,23 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
// rename this file from _test_[name] to test_[name] to activate
|
|
||||||
// and remove above this line
|
|
||||||
|
|
||||||
QUnit.test("test: Bank Statement Transaction Entry", function (assert) {
|
|
||||||
let done = assert.async();
|
|
||||||
|
|
||||||
// number of asserts
|
|
||||||
assert.expect(1);
|
|
||||||
|
|
||||||
frappe.run_serially([
|
|
||||||
// insert a new Bank Statement Transaction Entry
|
|
||||||
() => frappe.tests.make('Bank Statement Transaction Entry', [
|
|
||||||
// values to be set
|
|
||||||
{key: 'value'}
|
|
||||||
]),
|
|
||||||
() => {
|
|
||||||
assert.equal(cur_frm.doc.key, 'value');
|
|
||||||
},
|
|
||||||
() => done()
|
|
||||||
]);
|
|
||||||
|
|
||||||
});
|
|
@ -1,10 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (c) 2017, sathishpy@gmail.com and Contributors
|
|
||||||
# See license.txt
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import frappe
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
class TestBankStatementTransactionEntry(unittest.TestCase):
|
|
||||||
pass
|
|
@ -1,365 +0,0 @@
|
|||||||
{
|
|
||||||
"allow_copy": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2017-11-07 13:58:53.827058",
|
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
|
||||||
"engine": "InnoDB",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "transaction_date",
|
|
||||||
"fieldtype": "Date",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Transaction Date",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 4,
|
|
||||||
"fieldname": "payment_description",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Payment Description",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "party_type",
|
|
||||||
"fieldtype": "Select",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Party Type",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Customer\nSupplier\nAccount",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "party",
|
|
||||||
"fieldtype": "Dynamic Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Party",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "party_type",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_4",
|
|
||||||
"fieldtype": "Column Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 2,
|
|
||||||
"fieldname": "invoice_date",
|
|
||||||
"fieldtype": "Date",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Invoice Date",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "invoice_type",
|
|
||||||
"fieldtype": "Select",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Invoice Type",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Sales Invoice\nPurchase Invoice\nJournal Entry",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 2,
|
|
||||||
"fieldname": "invoice",
|
|
||||||
"fieldtype": "Dynamic Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "invoice",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "invoice_type",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 1,
|
|
||||||
"fieldname": "outstanding_amount",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Outstanding Amount",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 1,
|
|
||||||
"fieldname": "allocated_amount",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Allocated Amount",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 1,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-09-14 19:03:30.949831",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Accounts",
|
|
||||||
"name": "Bank Statement Transaction Invoice Item",
|
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [],
|
|
||||||
"quick_entry": 1,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
|
||||||
"sort_order": "DESC",
|
|
||||||
"track_changes": 1,
|
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
|
@ -1,494 +0,0 @@
|
|||||||
{
|
|
||||||
"allow_copy": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2017-11-07 14:03:05.651413",
|
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
|
||||||
"engine": "InnoDB",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 1,
|
|
||||||
"fieldname": "transaction_date",
|
|
||||||
"fieldtype": "Date",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Transaction Date",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 4,
|
|
||||||
"fieldname": "description",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Description",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 1,
|
|
||||||
"fieldname": "amount",
|
|
||||||
"fieldtype": "Currency",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Amount",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_3",
|
|
||||||
"fieldtype": "Column Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 1,
|
|
||||||
"fieldname": "party_type",
|
|
||||||
"fieldtype": "Select",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Party Type",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Customer\nSupplier\nAccount",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 2,
|
|
||||||
"fieldname": "party",
|
|
||||||
"fieldtype": "Dynamic Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Party",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "party_type",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_6",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "reference_type",
|
|
||||||
"fieldtype": "Select",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Reference Type",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Payment Entry\nJournal Entry",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "account",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Account",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Account",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "mode_of_payment",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Mode of Payment",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Mode of Payment",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "outstanding_amount",
|
|
||||||
"fieldtype": "Currency",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "outstanding_amount",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_10",
|
|
||||||
"fieldtype": "Column Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 2,
|
|
||||||
"fieldname": "reference_name",
|
|
||||||
"fieldtype": "Dynamic Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Reference Name",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "reference_type",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "payment_reference",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Payment Reference",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "invoices",
|
|
||||||
"fieldtype": "Text",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Invoices",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 1,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2017-11-15 19:18:52.876221",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Accounts",
|
|
||||||
"name": "Bank Statement Transaction Payment Item",
|
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [],
|
|
||||||
"quick_entry": 1,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
|
||||||
"sort_order": "DESC",
|
|
||||||
"track_changes": 1,
|
|
||||||
"track_seen": 0
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
// Copyright (c) 2017, sathishpy@gmail.com and contributors
|
|
||||||
// For license information, please see license.txt
|
|
||||||
|
|
||||||
frappe.ui.form.on('Bank Statement Settings', {
|
|
||||||
refresh: function(frm) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,266 +0,0 @@
|
|||||||
{
|
|
||||||
"allow_copy": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 1,
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2017-11-13 13:38:10.863592",
|
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
|
||||||
"engine": "InnoDB",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "bank_account",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Bank Account",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Account",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "'%d/%m/%Y'",
|
|
||||||
"fieldname": "date_format",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Date Format",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "statement_header_mapping",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Statement Header Mapping",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "header_items",
|
|
||||||
"fieldtype": "Table",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Statement Headers",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Bank Statement Settings Item",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "transaction_data_mapping",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Transaction Data Mapping",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "mapped_items",
|
|
||||||
"fieldtype": "Table",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Mapped Items",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Bank Statement Transaction Settings Item",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-01-12 10:34:32.840487",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Accounts",
|
|
||||||
"name": "Bank Statement Settings",
|
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [
|
|
||||||
{
|
|
||||||
"amend": 0,
|
|
||||||
"apply_user_permissions": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
|
||||||
"delete": 1,
|
|
||||||
"email": 1,
|
|
||||||
"export": 1,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "System Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"amend": 0,
|
|
||||||
"apply_user_permissions": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
|
||||||
"delete": 1,
|
|
||||||
"email": 1,
|
|
||||||
"export": 1,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "Accounts Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"quick_entry": 1,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
|
||||||
"sort_order": "DESC",
|
|
||||||
"track_changes": 1,
|
|
||||||
"track_seen": 0
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (c) 2017, sathishpy@gmail.com and contributors
|
|
||||||
# For license information, please see license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
from frappe.model.document import Document
|
|
||||||
|
|
||||||
class BankStatementSettings(Document):
|
|
||||||
def autoname(self):
|
|
||||||
self.name = self.bank_account + "-Mappings"
|
|
@ -1,23 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
// rename this file from _test_[name] to test_[name] to activate
|
|
||||||
// and remove above this line
|
|
||||||
|
|
||||||
QUnit.test("test: Bank Statement Settings", function (assert) {
|
|
||||||
let done = assert.async();
|
|
||||||
|
|
||||||
// number of asserts
|
|
||||||
assert.expect(1);
|
|
||||||
|
|
||||||
frappe.run_serially([
|
|
||||||
// insert a new Bank Statement Settings
|
|
||||||
() => frappe.tests.make('Bank Statement Settings', [
|
|
||||||
// values to be set
|
|
||||||
{key: 'value'}
|
|
||||||
]),
|
|
||||||
() => {
|
|
||||||
assert.equal(cur_frm.doc.key, 'value');
|
|
||||||
},
|
|
||||||
() => done()
|
|
||||||
]);
|
|
||||||
|
|
||||||
});
|
|
@ -1,10 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (c) 2017, sathishpy@gmail.com and Contributors
|
|
||||||
# See license.txt
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import frappe
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
class TestBankStatementSettings(unittest.TestCase):
|
|
||||||
pass
|
|
@ -1,166 +0,0 @@
|
|||||||
{
|
|
||||||
"allow_copy": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2017-11-13 13:42:00.335432",
|
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
|
||||||
"engine": "InnoDB",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "Transaction",
|
|
||||||
"fieldname": "mapping_type",
|
|
||||||
"fieldtype": "Select",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Mapping Type",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Transaction",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "bank_data",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Bank Data",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "Account",
|
|
||||||
"fieldname": "mapped_data_type",
|
|
||||||
"fieldtype": "Select",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Mapped Data Type",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Account\nCustomer\nSupplier\nAccount",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "mapped_data",
|
|
||||||
"fieldtype": "Dynamic Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Mapped Data",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "mapped_data_type",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 1,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-01-08 00:13:49.973501",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Accounts",
|
|
||||||
"name": "Bank Statement Transaction Settings Item",
|
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [],
|
|
||||||
"quick_entry": 1,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
|
||||||
"sort_order": "DESC",
|
|
||||||
"track_changes": 1,
|
|
||||||
"track_seen": 0
|
|
||||||
}
|
|
@ -1,32 +1,70 @@
|
|||||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
|
|
||||||
frappe.ui.form.on('Bank Transaction', {
|
frappe.ui.form.on("Bank Transaction", {
|
||||||
onload(frm) {
|
onload(frm) {
|
||||||
frm.set_query('payment_document', 'payment_entries', function() {
|
frm.set_query("payment_document", "payment_entries", function () {
|
||||||
return {
|
return {
|
||||||
"filters": {
|
filters: {
|
||||||
"name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice", "Expense Claim"]]
|
name: [
|
||||||
}
|
"in",
|
||||||
|
[
|
||||||
|
"Payment Entry",
|
||||||
|
"Journal Entry",
|
||||||
|
"Sales Invoice",
|
||||||
|
"Purchase Invoice",
|
||||||
|
"Expense Claim",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
bank_account: function (frm) {
|
||||||
|
set_bank_statement_filter(frm);
|
||||||
|
},
|
||||||
|
|
||||||
|
setup: function (frm) {
|
||||||
|
frm.set_query("party_type", function () {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
name: ["in", Object.keys(frappe.boot.party_account_types)],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
frappe.ui.form.on('Bank Transaction Payments', {
|
frappe.ui.form.on("Bank Transaction Payments", {
|
||||||
payment_entries_remove: function(frm, cdt, cdn) {
|
payment_entries_remove: function (frm, cdt, cdn) {
|
||||||
update_clearance_date(frm, cdt, cdn);
|
update_clearance_date(frm, cdt, cdn);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const update_clearance_date = (frm, cdt, cdn) => {
|
const update_clearance_date = (frm, cdt, cdn) => {
|
||||||
if (frm.doc.docstatus === 1) {
|
if (frm.doc.docstatus === 1) {
|
||||||
frappe.xcall('erpnext.accounts.doctype.bank_transaction.bank_transaction.unclear_reference_payment',
|
frappe
|
||||||
{doctype: cdt, docname: cdn})
|
.xcall(
|
||||||
.then(e => {
|
"erpnext.accounts.doctype.bank_transaction.bank_transaction.unclear_reference_payment",
|
||||||
|
{ doctype: cdt, docname: cdn }
|
||||||
|
)
|
||||||
|
.then((e) => {
|
||||||
if (e == "success") {
|
if (e == "success") {
|
||||||
frappe.show_alert({message:__("Document {0} successfully uncleared", [e]), indicator:'green'});
|
frappe.show_alert({
|
||||||
|
message: __("Document {0} successfully uncleared", [e]),
|
||||||
|
indicator: "green",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function set_bank_statement_filter(frm) {
|
||||||
|
frm.set_query("bank_statement", function () {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
bank_account: frm.doc.bank_account,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -1,833 +1,245 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_events_in_timeline": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 0,
|
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"beta": 0,
|
|
||||||
"creation": "2018-10-22 18:19:02.784533",
|
"creation": "2018-10-22 18:19:02.784533",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"naming_series",
|
||||||
|
"date",
|
||||||
|
"column_break_2",
|
||||||
|
"status",
|
||||||
|
"bank_account",
|
||||||
|
"company",
|
||||||
|
"section_break_4",
|
||||||
|
"deposit",
|
||||||
|
"withdrawal",
|
||||||
|
"column_break_7",
|
||||||
|
"currency",
|
||||||
|
"section_break_10",
|
||||||
|
"description",
|
||||||
|
"section_break_14",
|
||||||
|
"reference_number",
|
||||||
|
"transaction_id",
|
||||||
|
"payment_entries",
|
||||||
|
"section_break_18",
|
||||||
|
"allocated_amount",
|
||||||
|
"amended_from",
|
||||||
|
"column_break_17",
|
||||||
|
"unallocated_amount",
|
||||||
|
"party_section",
|
||||||
|
"party_type",
|
||||||
|
"party"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "ACC-BTN-.YYYY.-",
|
"default": "ACC-BTN-.YYYY.-",
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "naming_series",
|
"fieldname": "naming_series",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Series",
|
"label": "Series",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "ACC-BTN-.YYYY.-",
|
"options": "ACC-BTN-.YYYY.-",
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"set_only_once": 1
|
||||||
"set_only_once": 1,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "date",
|
"fieldname": "date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"hidden": 0,
|
"label": "Date"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Date",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "column_break_2",
|
"fieldname": "column_break_2",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "Pending",
|
"default": "Pending",
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "status",
|
"fieldname": "status",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Status",
|
"label": "Status",
|
||||||
"length": 0,
|
"options": "\nPending\nSettled\nUnreconciled\nReconciled"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "\nPending\nSettled\nUnreconciled\nReconciled",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "bank_account",
|
"fieldname": "bank_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Bank Account",
|
"label": "Bank Account",
|
||||||
"length": 0,
|
"options": "Bank Account"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Bank Account",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "",
|
|
||||||
"fetch_from": "bank_account.company",
|
"fetch_from": "bank_account.company",
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Company",
|
"label": "Company",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Company",
|
"options": "Company",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "section_break_4",
|
"fieldname": "section_break_4",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "debit",
|
|
||||||
"fieldtype": "Currency",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Debit",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "credit",
|
|
||||||
"fieldtype": "Currency",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Credit",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "column_break_7",
|
"fieldname": "column_break_7",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Currency",
|
"label": "Currency",
|
||||||
"length": 0,
|
"options": "Currency"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Currency",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "section_break_10",
|
"fieldname": "section_break_10",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "description",
|
"fieldname": "description",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"label": "Description"
|
||||||
"label": "Description",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "section_break_14",
|
"fieldname": "section_break_14",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_on_submit": 1,
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "reference_number",
|
"fieldname": "reference_number",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"label": "Reference Number"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Reference Number",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "transaction_id",
|
"fieldname": "transaction_id",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Transaction ID",
|
"label": "Transaction ID",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 1
|
"unique": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "payment_entries",
|
"fieldname": "payment_entries",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Payment Entries",
|
"label": "Payment Entries",
|
||||||
"length": 0,
|
"options": "Bank Transaction Payments"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Bank Transaction Payments",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "section_break_18",
|
"fieldname": "section_break_18",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "allocated_amount",
|
"fieldname": "allocated_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
"label": "Allocated Amount"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Allocated Amount",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "amended_from",
|
"fieldname": "amended_from",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Amended From",
|
"label": "Amended From",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Bank Transaction",
|
"options": "Bank Transaction",
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"read_only": 1
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "column_break_17",
|
"fieldname": "column_break_17",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "",
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "unallocated_amount",
|
"fieldname": "unallocated_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
"label": "Unallocated Amount"
|
||||||
"ignore_user_permissions": 0,
|
},
|
||||||
"ignore_xss_filter": 0,
|
{
|
||||||
"in_filter": 0,
|
"fieldname": "party_section",
|
||||||
"in_global_search": 0,
|
"fieldtype": "Section Break",
|
||||||
"in_list_view": 0,
|
"label": "Payment From / To"
|
||||||
"in_standard_filter": 0,
|
},
|
||||||
"label": "Unallocated Amount",
|
{
|
||||||
"length": 0,
|
"allow_on_submit": 1,
|
||||||
"no_copy": 0,
|
"fieldname": "party_type",
|
||||||
"permlevel": 0,
|
"fieldtype": "Link",
|
||||||
"precision": "",
|
"label": "Party Type",
|
||||||
"print_hide": 0,
|
"options": "DocType"
|
||||||
"print_hide_if_no_value": 0,
|
},
|
||||||
"read_only": 0,
|
{
|
||||||
"remember_last_selected_value": 0,
|
"allow_on_submit": 1,
|
||||||
"report_hide": 0,
|
"fieldname": "party",
|
||||||
"reqd": 0,
|
"fieldtype": "Dynamic Link",
|
||||||
"search_index": 0,
|
"label": "Party",
|
||||||
"set_only_once": 0,
|
"options": "party_type"
|
||||||
"translatable": 0,
|
},
|
||||||
"unique": 0
|
{
|
||||||
|
"fieldname": "deposit",
|
||||||
|
"oldfieldname": "debit",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Deposit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "withdrawal",
|
||||||
|
"oldfieldname": "credit",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Withdrawal"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"links": [],
|
||||||
"istable": 0,
|
"modified": "2020-12-30 19:40:54.221070",
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2019-05-11 05:27:55.244721",
|
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Bank Transaction",
|
"name": "Bank Transaction",
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 1,
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "System Manager",
|
"role": "System Manager",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 1,
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Accounts Manager",
|
"role": "Accounts Manager",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Accounts User",
|
"role": "Accounts User",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "date",
|
"sort_field": "date",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"title_field": "bank_account",
|
"title_field": "bank_account",
|
||||||
"track_changes": 0,
|
"track_changes": 1
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
@ -11,7 +11,7 @@ from frappe import _
|
|||||||
|
|
||||||
class BankTransaction(StatusUpdater):
|
class BankTransaction(StatusUpdater):
|
||||||
def after_insert(self):
|
def after_insert(self):
|
||||||
self.unallocated_amount = abs(flt(self.credit) - flt(self.debit))
|
self.unallocated_amount = abs(flt(self.withdrawal) - flt(self.deposit))
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
self.clear_linked_payment_entries()
|
self.clear_linked_payment_entries()
|
||||||
@ -30,13 +30,13 @@ class BankTransaction(StatusUpdater):
|
|||||||
|
|
||||||
if allocated_amount:
|
if allocated_amount:
|
||||||
frappe.db.set_value(self.doctype, self.name, "allocated_amount", flt(allocated_amount))
|
frappe.db.set_value(self.doctype, self.name, "allocated_amount", flt(allocated_amount))
|
||||||
frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.credit) - flt(self.debit)) - flt(allocated_amount))
|
frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.withdrawal) - flt(self.deposit)) - flt(allocated_amount))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
frappe.db.set_value(self.doctype, self.name, "allocated_amount", 0)
|
frappe.db.set_value(self.doctype, self.name, "allocated_amount", 0)
|
||||||
frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.credit) - flt(self.debit)))
|
frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.withdrawal) - flt(self.deposit)))
|
||||||
|
|
||||||
amount = self.debit or self.credit
|
amount = self.deposit or self.withdrawal
|
||||||
if amount == self.allocated_amount:
|
if amount == self.allocated_amount:
|
||||||
frappe.db.set_value(self.doctype, self.name, "status", "Reconciled")
|
frappe.db.set_value(self.doctype, self.name, "status", "Reconciled")
|
||||||
|
|
||||||
@ -44,18 +44,11 @@ class BankTransaction(StatusUpdater):
|
|||||||
|
|
||||||
def clear_linked_payment_entries(self):
|
def clear_linked_payment_entries(self):
|
||||||
for payment_entry in self.payment_entries:
|
for payment_entry in self.payment_entries:
|
||||||
allocated_amount = get_total_allocated_amount(payment_entry)
|
if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]:
|
||||||
paid_amount = get_paid_amount(payment_entry, self.currency)
|
self.clear_simple_entry(payment_entry)
|
||||||
|
|
||||||
if paid_amount and allocated_amount:
|
elif payment_entry.payment_document == "Sales Invoice":
|
||||||
if flt(allocated_amount[0]["allocated_amount"]) > flt(paid_amount):
|
self.clear_sales_invoice(payment_entry)
|
||||||
frappe.throw(_("The total allocated amount ({0}) is greated than the paid amount ({1}).").format(flt(allocated_amount[0]["allocated_amount"]), flt(paid_amount)))
|
|
||||||
else:
|
|
||||||
if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]:
|
|
||||||
self.clear_simple_entry(payment_entry)
|
|
||||||
|
|
||||||
elif payment_entry.payment_document == "Sales Invoice":
|
|
||||||
self.clear_sales_invoice(payment_entry)
|
|
||||||
|
|
||||||
def clear_simple_entry(self, payment_entry):
|
def clear_simple_entry(self, payment_entry):
|
||||||
frappe.db.set_value(payment_entry.payment_document, payment_entry.payment_entry, "clearance_date", self.date)
|
frappe.db.set_value(payment_entry.payment_document, payment_entry.payment_entry, "clearance_date", self.date)
|
||||||
@ -112,3 +105,4 @@ def unclear_reference_payment(doctype, docname):
|
|||||||
frappe.db.set_value(doc.payment_document, doc.payment_entry, "clearance_date", None)
|
frappe.db.set_value(doc.payment_document, doc.payment_entry, "clearance_date", None)
|
||||||
|
|
||||||
return doc.payment_entry
|
return doc.payment_entry
|
||||||
|
|
||||||
|
@ -5,17 +5,20 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
import unittest
|
import unittest
|
||||||
|
import json
|
||||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||||
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
|
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
|
||||||
from erpnext.accounts.page.bank_reconciliation.bank_reconciliation import reconcile, get_linked_payments
|
from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import reconcile_vouchers, get_linked_payments
|
||||||
|
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
|
||||||
|
|
||||||
test_dependencies = ["Item", "Cost Center"]
|
test_dependencies = ["Item", "Cost Center"]
|
||||||
|
|
||||||
class TestBankTransaction(unittest.TestCase):
|
class TestBankTransaction(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
make_pos_profile()
|
||||||
add_transactions()
|
add_transactions()
|
||||||
add_payments()
|
add_vouchers()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
for bt in frappe.get_all("Bank Transaction"):
|
for bt in frappe.get_all("Bank Transaction"):
|
||||||
@ -27,20 +30,27 @@ class TestBankTransaction(unittest.TestCase):
|
|||||||
frappe.db.sql("""delete from `tabPayment Entry Reference`""")
|
frappe.db.sql("""delete from `tabPayment Entry Reference`""")
|
||||||
frappe.db.sql("""delete from `tabPayment Entry`""")
|
frappe.db.sql("""delete from `tabPayment Entry`""")
|
||||||
|
|
||||||
|
# Delete POS Profile
|
||||||
|
frappe.db.sql("delete from `tabPOS Profile`")
|
||||||
|
|
||||||
frappe.flags.test_bank_transactions_created = False
|
frappe.flags.test_bank_transactions_created = False
|
||||||
frappe.flags.test_payments_created = False
|
frappe.flags.test_payments_created = False
|
||||||
|
|
||||||
# This test checks if ERPNext is able to provide a linked payment for a bank transaction based on the amount of the bank transaction.
|
# This test checks if ERPNext is able to provide a linked payment for a bank transaction based on the amount of the bank transaction.
|
||||||
def test_linked_payments(self):
|
def test_linked_payments(self):
|
||||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic"))
|
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic"))
|
||||||
linked_payments = get_linked_payments(bank_transaction.name)
|
linked_payments = get_linked_payments(bank_transaction.name, ['payment_entry', 'exact_match'])
|
||||||
self.assertTrue(linked_payments[0].party == "Conrad Electronic")
|
self.assertTrue(linked_payments[0][6] == "Conrad Electronic")
|
||||||
|
|
||||||
# This test validates a simple reconciliation leading to the clearance of the bank transaction and the payment
|
# This test validates a simple reconciliation leading to the clearance of the bank transaction and the payment
|
||||||
def test_reconcile(self):
|
def test_reconcile(self):
|
||||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
|
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
|
||||||
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
|
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
|
||||||
reconcile(bank_transaction.name, "Payment Entry", payment.name)
|
vouchers = json.dumps([{
|
||||||
|
"payment_doctype":"Payment Entry",
|
||||||
|
"payment_name":payment.name,
|
||||||
|
"amount":bank_transaction.unallocated_amount}])
|
||||||
|
reconcile_vouchers(bank_transaction.name, vouchers)
|
||||||
|
|
||||||
unallocated_amount = frappe.db.get_value("Bank Transaction", bank_transaction.name, "unallocated_amount")
|
unallocated_amount = frappe.db.get_value("Bank Transaction", bank_transaction.name, "unallocated_amount")
|
||||||
self.assertTrue(unallocated_amount == 0)
|
self.assertTrue(unallocated_amount == 0)
|
||||||
@ -48,45 +58,40 @@ class TestBankTransaction(unittest.TestCase):
|
|||||||
clearance_date = frappe.db.get_value("Payment Entry", payment.name, "clearance_date")
|
clearance_date = frappe.db.get_value("Payment Entry", payment.name, "clearance_date")
|
||||||
self.assertTrue(clearance_date is not None)
|
self.assertTrue(clearance_date is not None)
|
||||||
|
|
||||||
# Check if ERPNext can correctly fetch a linked payment based on the party
|
|
||||||
def test_linked_payments_based_on_party(self):
|
|
||||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000003025 OPSKATTUZWXXX AT776000000098709849 Herr G"))
|
|
||||||
linked_payments = get_linked_payments(bank_transaction.name)
|
|
||||||
self.assertTrue(len(linked_payments)==1)
|
|
||||||
|
|
||||||
# Check if ERPNext can correctly filter a linked payments based on the debit/credit amount
|
# Check if ERPNext can correctly filter a linked payments based on the debit/credit amount
|
||||||
def test_debit_credit_output(self):
|
def test_debit_credit_output(self):
|
||||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07"))
|
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07"))
|
||||||
linked_payments = get_linked_payments(bank_transaction.name)
|
linked_payments = get_linked_payments(bank_transaction.name, ['payment_entry', 'exact_match'])
|
||||||
self.assertTrue(linked_payments[0].payment_type == "Pay")
|
print(linked_payments)
|
||||||
|
self.assertTrue(linked_payments[0][3])
|
||||||
|
|
||||||
# Check error if already reconciled
|
# Check error if already reconciled
|
||||||
def test_already_reconciled(self):
|
def test_already_reconciled(self):
|
||||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
|
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
|
||||||
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
|
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
|
||||||
reconcile(bank_transaction.name, "Payment Entry", payment.name)
|
vouchers = json.dumps([{
|
||||||
|
"payment_doctype":"Payment Entry",
|
||||||
|
"payment_name":payment.name,
|
||||||
|
"amount":bank_transaction.unallocated_amount}])
|
||||||
|
reconcile_vouchers(bank_transaction.name, vouchers)
|
||||||
|
|
||||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
|
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
|
||||||
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
|
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
|
||||||
self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name)
|
vouchers = json.dumps([{
|
||||||
|
"payment_doctype":"Payment Entry",
|
||||||
# Raise an error if creditor transaction vs creditor payment
|
"payment_name":payment.name,
|
||||||
def test_invalid_creditor_reconcilation(self):
|
"amount":bank_transaction.unallocated_amount}])
|
||||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio"))
|
self.assertRaises(frappe.ValidationError, reconcile_vouchers, bank_transaction_name=bank_transaction.name, vouchers=vouchers)
|
||||||
payment = frappe.get_doc("Payment Entry", dict(party="Conrad Electronic", paid_amount=690))
|
|
||||||
self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name)
|
|
||||||
|
|
||||||
# Raise an error if debitor transaction vs debitor payment
|
|
||||||
def test_invalid_debitor_reconcilation(self):
|
|
||||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07"))
|
|
||||||
payment = frappe.get_doc("Payment Entry", dict(party="Fayva", paid_amount=109080))
|
|
||||||
self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name)
|
|
||||||
|
|
||||||
# Raise an error if debitor transaction vs debitor payment
|
# Raise an error if debitor transaction vs debitor payment
|
||||||
def test_clear_sales_invoice(self):
|
def test_clear_sales_invoice(self):
|
||||||
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio"))
|
bank_transaction = frappe.get_doc("Bank Transaction", dict(description="I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio"))
|
||||||
payment = frappe.get_doc("Sales Invoice", dict(customer="Fayva", status=["=", "Paid"]))
|
payment = frappe.get_doc("Sales Invoice", dict(customer="Fayva", status=["=", "Paid"]))
|
||||||
reconcile(bank_transaction.name, "Sales Invoice", payment.name)
|
vouchers = json.dumps([{
|
||||||
|
"payment_doctype":"Sales Invoice",
|
||||||
|
"payment_name":payment.name,
|
||||||
|
"amount":bank_transaction.unallocated_amount}])
|
||||||
|
reconcile_vouchers(bank_transaction.name, vouchers=vouchers)
|
||||||
|
|
||||||
self.assertEqual(frappe.db.get_value("Bank Transaction", bank_transaction.name, "unallocated_amount"), 0)
|
self.assertEqual(frappe.db.get_value("Bank Transaction", bank_transaction.name, "unallocated_amount"), 0)
|
||||||
self.assertTrue(frappe.db.get_value("Sales Invoice Payment", dict(parent=payment.name), "clearance_date") is not None)
|
self.assertTrue(frappe.db.get_value("Sales Invoice Payment", dict(parent=payment.name), "clearance_date") is not None)
|
||||||
@ -121,7 +126,7 @@ def add_transactions():
|
|||||||
"doctype": "Bank Transaction",
|
"doctype": "Bank Transaction",
|
||||||
"description":"1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G",
|
"description":"1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G",
|
||||||
"date": "2018-10-23",
|
"date": "2018-10-23",
|
||||||
"debit": 1200,
|
"deposit": 1200,
|
||||||
"currency": "INR",
|
"currency": "INR",
|
||||||
"bank_account": "Checking Account - Citi Bank"
|
"bank_account": "Checking Account - Citi Bank"
|
||||||
}).insert()
|
}).insert()
|
||||||
@ -131,7 +136,7 @@ def add_transactions():
|
|||||||
"doctype": "Bank Transaction",
|
"doctype": "Bank Transaction",
|
||||||
"description":"1512567 BG/000003025 OPSKATTUZWXXX AT776000000098709849 Herr G",
|
"description":"1512567 BG/000003025 OPSKATTUZWXXX AT776000000098709849 Herr G",
|
||||||
"date": "2018-10-23",
|
"date": "2018-10-23",
|
||||||
"debit": 1700,
|
"deposit": 1700,
|
||||||
"currency": "INR",
|
"currency": "INR",
|
||||||
"bank_account": "Checking Account - Citi Bank"
|
"bank_account": "Checking Account - Citi Bank"
|
||||||
}).insert()
|
}).insert()
|
||||||
@ -141,7 +146,7 @@ def add_transactions():
|
|||||||
"doctype": "Bank Transaction",
|
"doctype": "Bank Transaction",
|
||||||
"description":"Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic",
|
"description":"Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic",
|
||||||
"date": "2018-10-26",
|
"date": "2018-10-26",
|
||||||
"debit": 690,
|
"withdrawal": 690,
|
||||||
"currency": "INR",
|
"currency": "INR",
|
||||||
"bank_account": "Checking Account - Citi Bank"
|
"bank_account": "Checking Account - Citi Bank"
|
||||||
}).insert()
|
}).insert()
|
||||||
@ -151,7 +156,7 @@ def add_transactions():
|
|||||||
"doctype": "Bank Transaction",
|
"doctype": "Bank Transaction",
|
||||||
"description":"Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07",
|
"description":"Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07",
|
||||||
"date": "2018-10-27",
|
"date": "2018-10-27",
|
||||||
"debit": 3900,
|
"deposit": 3900,
|
||||||
"currency": "INR",
|
"currency": "INR",
|
||||||
"bank_account": "Checking Account - Citi Bank"
|
"bank_account": "Checking Account - Citi Bank"
|
||||||
}).insert()
|
}).insert()
|
||||||
@ -161,7 +166,7 @@ def add_transactions():
|
|||||||
"doctype": "Bank Transaction",
|
"doctype": "Bank Transaction",
|
||||||
"description":"I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio",
|
"description":"I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio",
|
||||||
"date": "2018-10-27",
|
"date": "2018-10-27",
|
||||||
"credit": 109080,
|
"withdrawal": 109080,
|
||||||
"currency": "INR",
|
"currency": "INR",
|
||||||
"bank_account": "Checking Account - Citi Bank"
|
"bank_account": "Checking Account - Citi Bank"
|
||||||
}).insert()
|
}).insert()
|
||||||
@ -169,7 +174,7 @@ def add_transactions():
|
|||||||
|
|
||||||
frappe.flags.test_bank_transactions_created = True
|
frappe.flags.test_bank_transactions_created = True
|
||||||
|
|
||||||
def add_payments():
|
def add_vouchers():
|
||||||
if frappe.flags.test_payments_created:
|
if frappe.flags.test_payments_created:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -187,6 +192,7 @@ def add_payments():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
pi = make_purchase_invoice(supplier="Conrad Electronic", qty=1, rate=690)
|
pi = make_purchase_invoice(supplier="Conrad Electronic", qty=1, rate=690)
|
||||||
|
|
||||||
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
|
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
|
||||||
pe.reference_no = "Conrad Oct 18"
|
pe.reference_no = "Conrad Oct 18"
|
||||||
pe.reference_date = "2018-10-24"
|
pe.reference_date = "2018-10-24"
|
||||||
@ -237,10 +243,15 @@ def add_payments():
|
|||||||
except frappe.DuplicateEntryError:
|
except frappe.DuplicateEntryError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
pi = make_purchase_invoice(supplier="Poore Simon's", qty=1, rate=3900)
|
pi = make_purchase_invoice(supplier="Poore Simon's", qty=1, rate=3900, is_paid=1, do_not_save =1)
|
||||||
|
pi.cash_bank_account = "_Test Bank - _TC"
|
||||||
|
pi.insert()
|
||||||
|
pi.submit()
|
||||||
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
|
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
|
||||||
pe.reference_no = "Poore Simon's Oct 18"
|
pe.reference_no = "Poore Simon's Oct 18"
|
||||||
pe.reference_date = "2018-10-28"
|
pe.reference_date = "2018-10-28"
|
||||||
|
pe.paid_amount = 690
|
||||||
|
pe.received_amount = 690
|
||||||
pe.insert()
|
pe.insert()
|
||||||
pe.submit()
|
pe.submit()
|
||||||
|
|
||||||
|
@ -1,24 +1,9 @@
|
|||||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
|
frappe.provide("erpnext.accounts.dimensions");
|
||||||
|
|
||||||
frappe.ui.form.on('Budget', {
|
frappe.ui.form.on('Budget', {
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
frm.set_query("cost_center", function() {
|
|
||||||
return {
|
|
||||||
filters: {
|
|
||||||
company: frm.doc.company
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
frm.set_query("project", function() {
|
|
||||||
return {
|
|
||||||
filters: {
|
|
||||||
company: frm.doc.company
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
frm.set_query("account", "accounts", function() {
|
frm.set_query("account", "accounts", function() {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
@ -26,16 +11,18 @@ frappe.ui.form.on('Budget', {
|
|||||||
report_type: "Profit and Loss",
|
report_type: "Profit and Loss",
|
||||||
is_group: 0
|
is_group: 0
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
|
|
||||||
frm.set_query("monthly_distribution", function() {
|
frm.set_query("monthly_distribution", function() {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
fiscal_year: frm.doc.fiscal_year
|
fiscal_year: frm.doc.fiscal_year
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
|
|
||||||
|
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
|
@ -122,8 +122,10 @@ class TestBudget(unittest.TestCase):
|
|||||||
|
|
||||||
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||||
|
|
||||||
|
project = frappe.get_value("Project", {"project_name": "_Test Project"})
|
||||||
|
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", project="_Test Project", posting_date=nowdate())
|
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", project=project, posting_date=nowdate())
|
||||||
|
|
||||||
self.assertRaises(BudgetError, jv.submit)
|
self.assertRaises(BudgetError, jv.submit)
|
||||||
|
|
||||||
@ -147,8 +149,11 @@ class TestBudget(unittest.TestCase):
|
|||||||
|
|
||||||
budget = make_budget(budget_against="Project")
|
budget = make_budget(budget_against="Project")
|
||||||
|
|
||||||
|
project = frappe.get_value("Project", {"project_name": "_Test Project"})
|
||||||
|
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", 250000, "_Test Cost Center - _TC", project="_Test Project", posting_date=nowdate())
|
"_Test Bank - _TC", 250000, "_Test Cost Center - _TC",
|
||||||
|
project=project, posting_date=nowdate())
|
||||||
|
|
||||||
self.assertRaises(BudgetError, jv.submit)
|
self.assertRaises(BudgetError, jv.submit)
|
||||||
|
|
||||||
@ -159,10 +164,10 @@ class TestBudget(unittest.TestCase):
|
|||||||
|
|
||||||
budget = make_budget(budget_against="Cost Center")
|
budget = make_budget(budget_against="Cost Center")
|
||||||
month = now_datetime().month
|
month = now_datetime().month
|
||||||
if month > 10:
|
if month > 9:
|
||||||
month = 10
|
month = 9
|
||||||
|
|
||||||
for i in range(month):
|
for i in range(month+1):
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
|
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
|
||||||
|
|
||||||
@ -181,12 +186,14 @@ class TestBudget(unittest.TestCase):
|
|||||||
|
|
||||||
budget = make_budget(budget_against="Project")
|
budget = make_budget(budget_against="Project")
|
||||||
month = now_datetime().month
|
month = now_datetime().month
|
||||||
if month > 10:
|
if month > 9:
|
||||||
month = 10
|
month = 9
|
||||||
|
|
||||||
for i in range(month):
|
project = frappe.get_value("Project", {"project_name": "_Test Project"})
|
||||||
|
for i in range(month + 1):
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True, project="_Test Project")
|
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True,
|
||||||
|
project=project)
|
||||||
|
|
||||||
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}))
|
||||||
@ -289,7 +296,7 @@ def make_budget(**args):
|
|||||||
budget = frappe.new_doc("Budget")
|
budget = frappe.new_doc("Budget")
|
||||||
|
|
||||||
if budget_against == "Project":
|
if budget_against == "Project":
|
||||||
budget.project = "_Test Project"
|
budget.project = frappe.get_value("Project", {"project_name": "_Test Project"})
|
||||||
else:
|
else:
|
||||||
budget.cost_center =cost_center or "_Test Cost Center - _TC"
|
budget.cost_center =cost_center or "_Test Cost Center - _TC"
|
||||||
|
|
||||||
|
@ -28,22 +28,22 @@ def test_create_test_data():
|
|||||||
"item_group": "_Test Item Group",
|
"item_group": "_Test Item Group",
|
||||||
"item_name": "_Test Tesla Car",
|
"item_name": "_Test Tesla Car",
|
||||||
"apply_warehouse_wise_reorder_level": 0,
|
"apply_warehouse_wise_reorder_level": 0,
|
||||||
"warehouse":"Stores - TCP1",
|
"warehouse":"Stores - _TC",
|
||||||
"gst_hsn_code": "999800",
|
"gst_hsn_code": "999800",
|
||||||
"valuation_rate": 5000,
|
"valuation_rate": 5000,
|
||||||
"standard_rate":5000,
|
"standard_rate":5000,
|
||||||
"item_defaults": [{
|
"item_defaults": [{
|
||||||
"company": "_Test Company with perpetual inventory",
|
"company": "_Test Company",
|
||||||
"default_warehouse": "Stores - TCP1",
|
"default_warehouse": "Stores - _TC",
|
||||||
"default_price_list":"_Test Price List",
|
"default_price_list":"_Test Price List",
|
||||||
"expense_account": "Cost of Goods Sold - TCP1",
|
"expense_account": "Cost of Goods Sold - _TC",
|
||||||
"buying_cost_center": "Main - TCP1",
|
"buying_cost_center": "Main - _TC",
|
||||||
"selling_cost_center": "Main - TCP1",
|
"selling_cost_center": "Main - _TC",
|
||||||
"income_account": "Sales - TCP1"
|
"income_account": "Sales - _TC"
|
||||||
}],
|
}],
|
||||||
"show_in_website": 1,
|
"show_in_website": 1,
|
||||||
"route":"-test-tesla-car",
|
"route":"-test-tesla-car",
|
||||||
"website_warehouse": "Stores - TCP1"
|
"website_warehouse": "Stores - _TC"
|
||||||
})
|
})
|
||||||
item.insert()
|
item.insert()
|
||||||
# create test item price
|
# create test item price
|
||||||
@ -65,12 +65,12 @@ def test_create_test_data():
|
|||||||
"items": [{
|
"items": [{
|
||||||
"item_code": "_Test Tesla Car"
|
"item_code": "_Test Tesla Car"
|
||||||
}],
|
}],
|
||||||
"warehouse":"Stores - TCP1",
|
"warehouse":"Stores - _TC",
|
||||||
"coupon_code_based":1,
|
"coupon_code_based":1,
|
||||||
"selling": 1,
|
"selling": 1,
|
||||||
"rate_or_discount": "Discount Percentage",
|
"rate_or_discount": "Discount Percentage",
|
||||||
"discount_percentage": 30,
|
"discount_percentage": 30,
|
||||||
"company": "_Test Company with perpetual inventory",
|
"company": "_Test Company",
|
||||||
"currency":"INR",
|
"currency":"INR",
|
||||||
"for_price_list":"_Test Price List"
|
"for_price_list":"_Test Price List"
|
||||||
})
|
})
|
||||||
@ -85,7 +85,7 @@ def test_create_test_data():
|
|||||||
})
|
})
|
||||||
sales_partner.insert()
|
sales_partner.insert()
|
||||||
# create test item coupon code
|
# create test item coupon code
|
||||||
if not frappe.db.exists("Coupon Code","SAVE30"):
|
if not frappe.db.exists("Coupon Code", "SAVE30"):
|
||||||
coupon_code = frappe.get_doc({
|
coupon_code = frappe.get_doc({
|
||||||
"doctype": "Coupon Code",
|
"doctype": "Coupon Code",
|
||||||
"coupon_name":"SAVE30",
|
"coupon_name":"SAVE30",
|
||||||
@ -104,33 +104,25 @@ class TestCouponCode(unittest.TestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
frappe.set_user("Administrator")
|
frappe.set_user("Administrator")
|
||||||
|
|
||||||
def test_1_check_coupon_code_used_before_so(self):
|
def test_sales_order_with_coupon_code(self):
|
||||||
coupon_code = frappe.get_doc("Coupon Code", frappe.db.get_value("Coupon Code", {"coupon_name":"SAVE30"}))
|
frappe.db.set_value("Coupon Code", "SAVE30", "used", 0)
|
||||||
# reset used coupon code count
|
|
||||||
coupon_code.used=0
|
|
||||||
coupon_code.save()
|
|
||||||
# check no coupon code is used before sales order is made
|
|
||||||
self.assertEqual(coupon_code.get("used"),0)
|
|
||||||
|
|
||||||
def test_2_sales_order_with_coupon_code(self):
|
so = make_sales_order(company='_Test Company', warehouse='Stores - _TC',
|
||||||
so = make_sales_order(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1',
|
customer="_Test Customer", selling_price_list="_Test Price List",
|
||||||
customer="_Test Customer", selling_price_list="_Test Price List", item_code="_Test Tesla Car", rate=5000,qty=1,
|
item_code="_Test Tesla Car", rate=5000, qty=1,
|
||||||
do_not_submit=True)
|
do_not_submit=True)
|
||||||
|
|
||||||
so = frappe.get_doc('Sales Order', so.name)
|
|
||||||
# check item price before coupon code is applied
|
|
||||||
self.assertEqual(so.items[0].rate, 5000)
|
self.assertEqual(so.items[0].rate, 5000)
|
||||||
|
|
||||||
so.coupon_code='SAVE30'
|
so.coupon_code='SAVE30'
|
||||||
so.sales_partner='_Test Coupon Partner'
|
so.sales_partner='_Test Coupon Partner'
|
||||||
so.save()
|
so.save()
|
||||||
|
|
||||||
# check item price after coupon code is applied
|
# check item price after coupon code is applied
|
||||||
self.assertEqual(so.items[0].rate, 3500)
|
self.assertEqual(so.items[0].rate, 3500)
|
||||||
|
|
||||||
so.submit()
|
so.submit()
|
||||||
|
self.assertEqual(frappe.db.get_value("Coupon Code", "SAVE30", "used"), 1)
|
||||||
def test_3_check_coupon_code_used_after_so(self):
|
|
||||||
doc = frappe.get_doc("Coupon Code", frappe.db.get_value("Coupon Code", {"coupon_name":"SAVE30"}))
|
|
||||||
# check no coupon code is used before sales order is made
|
|
||||||
self.assertEqual(doc.get("used"),1)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,8 +11,10 @@ from frappe.model.meta import get_field_precision
|
|||||||
from erpnext.accounts.party import validate_party_gle_currency, validate_party_frozen_disabled
|
from erpnext.accounts.party import validate_party_gle_currency, validate_party_frozen_disabled
|
||||||
from erpnext.accounts.utils import get_account_currency
|
from erpnext.accounts.utils import get_account_currency
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
from erpnext.exceptions import InvalidAccountCurrency
|
from erpnext.exceptions import InvalidAccountCurrency, InvalidAccountDimensionError, MandatoryAccountDimensionError
|
||||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_checks_for_pl_and_bs_accounts
|
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_checks_for_pl_and_bs_accounts
|
||||||
|
from erpnext.accounts.doctype.accounting_dimension_filter.accounting_dimension_filter import get_dimension_filter_map
|
||||||
|
from six import iteritems
|
||||||
|
|
||||||
exclude_from_linked_with = True
|
exclude_from_linked_with = True
|
||||||
class GLEntry(Document):
|
class GLEntry(Document):
|
||||||
@ -25,27 +27,30 @@ class GLEntry(Document):
|
|||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.flags.ignore_submit_comment = True
|
self.flags.ignore_submit_comment = True
|
||||||
self.check_mandatory()
|
|
||||||
self.validate_and_set_fiscal_year()
|
self.validate_and_set_fiscal_year()
|
||||||
self.pl_must_have_cost_center()
|
self.pl_must_have_cost_center()
|
||||||
self.validate_cost_center()
|
|
||||||
|
|
||||||
self.check_pl_account()
|
if not self.flags.from_repost:
|
||||||
self.validate_party()
|
self.check_mandatory()
|
||||||
self.validate_currency()
|
self.validate_cost_center()
|
||||||
|
self.check_pl_account()
|
||||||
|
self.validate_party()
|
||||||
|
self.validate_currency()
|
||||||
|
|
||||||
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'):
|
def on_update(self):
|
||||||
self.validate_account_details(adv_adj)
|
adv_adj = self.flags.adv_adj
|
||||||
self.validate_dimensions_for_pl_and_bs()
|
if not self.flags.from_repost:
|
||||||
|
self.validate_account_details(adv_adj)
|
||||||
|
self.validate_dimensions_for_pl_and_bs()
|
||||||
|
self.validate_allowed_dimensions()
|
||||||
|
validate_balance_type(self.account, adv_adj)
|
||||||
|
validate_frozen_account(self.account, adv_adj)
|
||||||
|
|
||||||
validate_frozen_account(self.account, adv_adj)
|
# Update outstanding amt on against voucher
|
||||||
validate_balance_type(self.account, adv_adj)
|
if (self.against_voucher_type in ['Journal Entry', 'Sales Invoice', 'Purchase Invoice', 'Fees']
|
||||||
|
and self.against_voucher and self.flags.update_outstanding == 'Yes'):
|
||||||
# Update outstanding amt on against voucher
|
update_outstanding_amt(self.account, self.party_type, self.party, self.against_voucher_type,
|
||||||
if self.against_voucher_type in ['Journal Entry', 'Sales Invoice', 'Purchase Invoice', 'Fees'] \
|
self.against_voucher)
|
||||||
and self.against_voucher and update_outstanding == 'Yes':
|
|
||||||
update_outstanding_amt(self.account, self.party_type, self.party, self.against_voucher_type,
|
|
||||||
self.against_voucher)
|
|
||||||
|
|
||||||
def check_mandatory(self):
|
def check_mandatory(self):
|
||||||
mandatory = ['account','voucher_type','voucher_no','company']
|
mandatory = ['account','voucher_type','voucher_no','company']
|
||||||
@ -53,7 +58,7 @@ class GLEntry(Document):
|
|||||||
if not self.get(k):
|
if not self.get(k):
|
||||||
frappe.throw(_("{0} is required").format(_(self.meta.get_label(k))))
|
frappe.throw(_("{0} is required").format(_(self.meta.get_label(k))))
|
||||||
|
|
||||||
account_type = frappe.db.get_value("Account", self.account, "account_type")
|
account_type = frappe.get_cached_value("Account", self.account, "account_type")
|
||||||
if not (self.party_type and self.party):
|
if not (self.party_type and self.party):
|
||||||
if account_type == "Receivable":
|
if account_type == "Receivable":
|
||||||
frappe.throw(_("{0} {1}: Customer is required against Receivable account {2}")
|
frappe.throw(_("{0} {1}: Customer is required against Receivable account {2}")
|
||||||
@ -68,17 +73,15 @@ class GLEntry(Document):
|
|||||||
.format(self.voucher_type, self.voucher_no, self.account))
|
.format(self.voucher_type, self.voucher_no, self.account))
|
||||||
|
|
||||||
def pl_must_have_cost_center(self):
|
def pl_must_have_cost_center(self):
|
||||||
if frappe.db.get_value("Account", self.account, "report_type") == "Profit and Loss":
|
if frappe.get_cached_value("Account", self.account, "report_type") == "Profit and Loss":
|
||||||
if not self.cost_center and self.voucher_type != 'Period Closing Voucher':
|
if not self.cost_center and self.voucher_type != 'Period Closing Voucher':
|
||||||
frappe.throw(_("{0} {1}: Cost Center is required for 'Profit and Loss' account {2}. Please set up a default Cost Center for the Company.")
|
frappe.throw(_("{0} {1}: Cost Center is required for 'Profit and Loss' account {2}. Please set up a default Cost Center for the Company.")
|
||||||
.format(self.voucher_type, self.voucher_no, self.account))
|
.format(self.voucher_type, self.voucher_no, self.account))
|
||||||
|
|
||||||
def validate_dimensions_for_pl_and_bs(self):
|
def validate_dimensions_for_pl_and_bs(self):
|
||||||
|
|
||||||
account_type = frappe.db.get_value("Account", self.account, "report_type")
|
account_type = frappe.db.get_value("Account", self.account, "report_type")
|
||||||
|
|
||||||
for dimension in get_checks_for_pl_and_bs_accounts():
|
for dimension in get_checks_for_pl_and_bs_accounts():
|
||||||
|
|
||||||
if account_type == "Profit and Loss" \
|
if account_type == "Profit and Loss" \
|
||||||
and self.company == dimension.company and dimension.mandatory_for_pl and not dimension.disabled:
|
and self.company == dimension.company and dimension.mandatory_for_pl and not dimension.disabled:
|
||||||
if not self.get(dimension.fieldname):
|
if not self.get(dimension.fieldname):
|
||||||
@ -91,6 +94,25 @@ class GLEntry(Document):
|
|||||||
frappe.throw(_("Accounting Dimension <b>{0}</b> is required for 'Balance Sheet' account {1}.")
|
frappe.throw(_("Accounting Dimension <b>{0}</b> is required for 'Balance Sheet' account {1}.")
|
||||||
.format(dimension.label, self.account))
|
.format(dimension.label, self.account))
|
||||||
|
|
||||||
|
def validate_allowed_dimensions(self):
|
||||||
|
dimension_filter_map = get_dimension_filter_map()
|
||||||
|
for key, value in iteritems(dimension_filter_map):
|
||||||
|
dimension = key[0]
|
||||||
|
account = key[1]
|
||||||
|
|
||||||
|
if self.account == account:
|
||||||
|
if value['is_mandatory'] and not self.get(dimension):
|
||||||
|
frappe.throw(_("{0} is mandatory for account {1}").format(
|
||||||
|
frappe.bold(frappe.unscrub(dimension)), frappe.bold(self.account)), MandatoryAccountDimensionError)
|
||||||
|
|
||||||
|
if value['allow_or_restrict'] == 'Allow':
|
||||||
|
if self.get(dimension) and self.get(dimension) not in value['allowed_dimensions']:
|
||||||
|
frappe.throw(_("Invalid value {0} for {1} against account {2}").format(
|
||||||
|
frappe.bold(self.get(dimension)), frappe.bold(frappe.unscrub(dimension)), frappe.bold(self.account)), InvalidAccountDimensionError)
|
||||||
|
else:
|
||||||
|
if self.get(dimension) and self.get(dimension) in value['allowed_dimensions']:
|
||||||
|
frappe.throw(_("Invalid value {0} for {1} against account {2}").format(
|
||||||
|
frappe.bold(self.get(dimension)), frappe.bold(frappe.unscrub(dimension)), frappe.bold(self.account)), InvalidAccountDimensionError)
|
||||||
|
|
||||||
def check_pl_account(self):
|
def check_pl_account(self):
|
||||||
if self.is_opening=='Yes' and \
|
if self.is_opening=='Yes' and \
|
||||||
@ -106,8 +128,8 @@ class GLEntry(Document):
|
|||||||
from tabAccount where name=%s""", self.account, as_dict=1)[0]
|
from tabAccount where name=%s""", self.account, as_dict=1)[0]
|
||||||
|
|
||||||
if ret.is_group==1:
|
if ret.is_group==1:
|
||||||
frappe.throw(_('''{0} {1}: Account {2} is a Group Account and group accounts cannot be used in
|
frappe.throw(_('''{0} {1}: Account {2} is a Group Account and group accounts cannot be used in transactions''')
|
||||||
transactions''').format(self.voucher_type, self.voucher_no, self.account))
|
.format(self.voucher_type, self.voucher_no, self.account))
|
||||||
|
|
||||||
if ret.docstatus==2:
|
if ret.docstatus==2:
|
||||||
frappe.throw(_("{0} {1}: Account {2} is inactive")
|
frappe.throw(_("{0} {1}: Account {2} is inactive")
|
||||||
@ -118,26 +140,18 @@ class GLEntry(Document):
|
|||||||
.format(self.voucher_type, self.voucher_no, self.account, self.company))
|
.format(self.voucher_type, self.voucher_no, self.account, self.company))
|
||||||
|
|
||||||
def validate_cost_center(self):
|
def validate_cost_center(self):
|
||||||
if not hasattr(self, "cost_center_company"):
|
if not self.cost_center: return
|
||||||
self.cost_center_company = {}
|
|
||||||
|
|
||||||
def _get_cost_center_company():
|
is_group, company = frappe.get_cached_value('Cost Center',
|
||||||
if not self.cost_center_company.get(self.cost_center):
|
self.cost_center, ['is_group', 'company'])
|
||||||
self.cost_center_company[self.cost_center] = frappe.db.get_value(
|
|
||||||
"Cost Center", self.cost_center, "company")
|
|
||||||
|
|
||||||
return self.cost_center_company[self.cost_center]
|
if company != self.company:
|
||||||
|
|
||||||
def _check_is_group():
|
|
||||||
return cint(frappe.get_cached_value('Cost Center', self.cost_center, 'is_group'))
|
|
||||||
|
|
||||||
if self.cost_center and _get_cost_center_company() != self.company:
|
|
||||||
frappe.throw(_("{0} {1}: Cost Center {2} does not belong to Company {3}")
|
frappe.throw(_("{0} {1}: Cost Center {2} does not belong to Company {3}")
|
||||||
.format(self.voucher_type, self.voucher_no, self.cost_center, self.company))
|
.format(self.voucher_type, self.voucher_no, self.cost_center, self.company))
|
||||||
|
|
||||||
if self.cost_center and _check_is_group():
|
if (self.voucher_type != 'Period Closing Voucher' and is_group):
|
||||||
frappe.throw(_("""{0} {1}: Cost Center {2} is a group cost center and group cost centers cannot
|
frappe.throw(_("""{0} {1}: Cost Center {2} is a group cost center and group cost centers cannot be used in transactions""").format(
|
||||||
be used in transactions""").format(self.voucher_type, self.voucher_no, frappe.bold(self.cost_center)))
|
self.voucher_type, self.voucher_no, frappe.bold(self.cost_center)))
|
||||||
|
|
||||||
def validate_party(self):
|
def validate_party(self):
|
||||||
validate_party_frozen_disabled(self.party_type, self.party)
|
validate_party_frozen_disabled(self.party_type, self.party)
|
||||||
@ -147,7 +161,7 @@ class GLEntry(Document):
|
|||||||
account_currency = get_account_currency(self.account)
|
account_currency = get_account_currency(self.account)
|
||||||
|
|
||||||
if not self.account_currency:
|
if not self.account_currency:
|
||||||
self.account_currency = company_currency
|
self.account_currency = account_currency or company_currency
|
||||||
|
|
||||||
if account_currency != self.account_currency:
|
if account_currency != self.account_currency:
|
||||||
frappe.throw(_("{0} {1}: Accounting Entry for {2} can only be made in currency: {3}")
|
frappe.throw(_("{0} {1}: Accounting Entry for {2} can only be made in currency: {3}")
|
||||||
@ -161,7 +175,6 @@ class GLEntry(Document):
|
|||||||
if not self.fiscal_year:
|
if not self.fiscal_year:
|
||||||
self.fiscal_year = get_fiscal_year(self.posting_date, company=self.company)[0]
|
self.fiscal_year = get_fiscal_year(self.posting_date, company=self.company)[0]
|
||||||
|
|
||||||
|
|
||||||
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")
|
||||||
@ -227,7 +240,7 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
|
|||||||
|
|
||||||
|
|
||||||
def validate_frozen_account(account, adv_adj=None):
|
def validate_frozen_account(account, adv_adj=None):
|
||||||
frozen_account = frappe.db.get_value("Account", account, "freeze_account")
|
frozen_account = frappe.get_cached_value("Account", account, "freeze_account")
|
||||||
if frozen_account == 'Yes' and not adv_adj:
|
if frozen_account == 'Yes' and not adv_adj:
|
||||||
frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,
|
frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,
|
||||||
'frozen_accounts_modifier')
|
'frozen_accounts_modifier')
|
||||||
|
@ -20,7 +20,8 @@ def get_data():
|
|||||||
'items': ['Purchase Invoice', 'Purchase Order', 'Purchase Receipt']
|
'items': ['Purchase Invoice', 'Purchase Order', 'Purchase Receipt']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'items': ['Item']
|
'label': _('Stock'),
|
||||||
|
'items': ['Item Groups', 'Item']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -120,6 +120,8 @@ frappe.ui.form.on("Journal Entry", {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
|
||||||
},
|
},
|
||||||
|
|
||||||
voucher_type: function(frm){
|
voucher_type: function(frm){
|
||||||
@ -197,6 +199,7 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
|||||||
this.load_defaults();
|
this.load_defaults();
|
||||||
this.setup_queries();
|
this.setup_queries();
|
||||||
this.setup_balance_formatter();
|
this.setup_balance_formatter();
|
||||||
|
erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
|
||||||
},
|
},
|
||||||
|
|
||||||
onload_post_render: function() {
|
onload_post_render: function() {
|
||||||
@ -222,15 +225,6 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
|||||||
return erpnext.journal_entry.account_query(me.frm);
|
return erpnext.journal_entry.account_query(me.frm);
|
||||||
});
|
});
|
||||||
|
|
||||||
me.frm.set_query("cost_center", "accounts", function(doc, cdt, cdn) {
|
|
||||||
return {
|
|
||||||
filters: {
|
|
||||||
company: me.frm.doc.company,
|
|
||||||
is_group: 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
me.frm.set_query("party_type", "accounts", function(doc, cdt, cdn) {
|
me.frm.set_query("party_type", "accounts", function(doc, cdt, cdn) {
|
||||||
const row = locals[cdt][cdn];
|
const row = locals[cdt][cdn];
|
||||||
|
|
||||||
@ -406,6 +400,8 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cur_frm.cscript.update_totals(doc);
|
cur_frm.cscript.update_totals(doc);
|
||||||
|
|
||||||
|
erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, 'accounts');
|
||||||
},
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -6,14 +6,18 @@ import frappe, erpnext, json
|
|||||||
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate, nowdate, cint, get_link_to_form
|
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate, nowdate, cint, get_link_to_form
|
||||||
from frappe import msgprint, _, scrub
|
from frappe import msgprint, _, scrub
|
||||||
from erpnext.controllers.accounts_controller import AccountsController
|
from erpnext.controllers.accounts_controller import AccountsController
|
||||||
from erpnext.accounts.utils import get_balance_on, get_account_currency
|
from erpnext.accounts.utils import get_balance_on, get_stock_accounts, get_stock_and_account_balance, \
|
||||||
|
get_account_currency, check_if_stock_and_account_balance_synced
|
||||||
from erpnext.accounts.party import get_party_account
|
from erpnext.accounts.party import get_party_account
|
||||||
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
||||||
from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import get_party_account_based_on_invoice_discounting
|
from erpnext.accounts.doctype.invoice_discounting.invoice_discounting \
|
||||||
|
import get_party_account_based_on_invoice_discounting
|
||||||
from erpnext.accounts.deferred_revenue import get_deferred_booking_accounts
|
from erpnext.accounts.deferred_revenue import get_deferred_booking_accounts
|
||||||
|
|
||||||
from six import string_types, iteritems
|
from six import string_types, iteritems
|
||||||
|
|
||||||
|
class StockAccountInvalidTransaction(frappe.ValidationError): pass
|
||||||
|
|
||||||
class JournalEntry(AccountsController):
|
class JournalEntry(AccountsController):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(JournalEntry, self).__init__(*args, **kwargs)
|
super(JournalEntry, self).__init__(*args, **kwargs)
|
||||||
@ -46,6 +50,7 @@ class JournalEntry(AccountsController):
|
|||||||
self.validate_empty_accounts_table()
|
self.validate_empty_accounts_table()
|
||||||
self.set_account_and_party_balance()
|
self.set_account_and_party_balance()
|
||||||
self.validate_inter_company_accounts()
|
self.validate_inter_company_accounts()
|
||||||
|
self.validate_stock_accounts()
|
||||||
if not self.title:
|
if not self.title:
|
||||||
self.title = self.get_title()
|
self.title = self.get_title()
|
||||||
|
|
||||||
@ -57,6 +62,8 @@ class JournalEntry(AccountsController):
|
|||||||
self.update_expense_claim()
|
self.update_expense_claim()
|
||||||
self.update_inter_company_jv()
|
self.update_inter_company_jv()
|
||||||
self.update_invoice_discounting()
|
self.update_invoice_discounting()
|
||||||
|
check_if_stock_and_account_balance_synced(self.posting_date,
|
||||||
|
self.company, self.doctype, self.name)
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
|
from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
|
||||||
@ -96,6 +103,16 @@ class JournalEntry(AccountsController):
|
|||||||
if self.total_credit != doc.total_debit or self.total_debit != doc.total_credit:
|
if self.total_credit != doc.total_debit or self.total_debit != doc.total_credit:
|
||||||
frappe.throw(_("Total Credit/ Debit Amount should be same as linked Journal Entry"))
|
frappe.throw(_("Total Credit/ Debit Amount should be same as linked Journal Entry"))
|
||||||
|
|
||||||
|
def validate_stock_accounts(self):
|
||||||
|
stock_accounts = get_stock_accounts(self.company, self.doctype, self.name)
|
||||||
|
for account in stock_accounts:
|
||||||
|
account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(account,
|
||||||
|
self.posting_date, self.company)
|
||||||
|
|
||||||
|
if account_bal == stock_bal:
|
||||||
|
frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
|
||||||
|
.format(account), StockAccountInvalidTransaction)
|
||||||
|
|
||||||
def update_inter_company_jv(self):
|
def update_inter_company_jv(self):
|
||||||
if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
|
if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
|
||||||
frappe.db.set_value("Journal Entry", self.inter_company_journal_entry_reference,\
|
frappe.db.set_value("Journal Entry", self.inter_company_journal_entry_reference,\
|
||||||
@ -212,11 +229,11 @@ class JournalEntry(AccountsController):
|
|||||||
if d.reference_type=="Journal Entry":
|
if d.reference_type=="Journal Entry":
|
||||||
account_root_type = frappe.db.get_value("Account", d.account, "root_type")
|
account_root_type = frappe.db.get_value("Account", d.account, "root_type")
|
||||||
if account_root_type == "Asset" and flt(d.debit) > 0:
|
if account_root_type == "Asset" and flt(d.debit) > 0:
|
||||||
frappe.throw(_("For {0}, only credit accounts can be linked against another debit entry")
|
frappe.throw(_("Row #{0}: For {1}, you can select reference document only if account gets credited")
|
||||||
.format(d.account))
|
.format(d.idx, d.account))
|
||||||
elif account_root_type == "Liability" and flt(d.credit) > 0:
|
elif account_root_type == "Liability" and flt(d.credit) > 0:
|
||||||
frappe.throw(_("For {0}, only debit accounts can be linked against another credit entry")
|
frappe.throw(_("Row #{0}: For {1}, you can select reference document only if account gets debited")
|
||||||
.format(d.account))
|
.format(d.idx, d.account))
|
||||||
|
|
||||||
if d.reference_name == self.name:
|
if d.reference_name == self.name:
|
||||||
frappe.throw(_("You can not enter current voucher in 'Against Journal Entry' column"))
|
frappe.throw(_("You can not enter current voucher in 'Against Journal Entry' column"))
|
||||||
|
@ -6,7 +6,7 @@ import unittest, frappe
|
|||||||
from frappe.utils import flt, nowdate
|
from frappe.utils import flt, nowdate
|
||||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||||
from erpnext.exceptions import InvalidAccountCurrency
|
from erpnext.exceptions import InvalidAccountCurrency
|
||||||
from erpnext.accounts.general_ledger import StockAccountInvalidTransaction
|
from erpnext.accounts.doctype.journal_entry.journal_entry import StockAccountInvalidTransaction
|
||||||
|
|
||||||
class TestJournalEntry(unittest.TestCase):
|
class TestJournalEntry(unittest.TestCase):
|
||||||
def test_journal_entry_with_against_jv(self):
|
def test_journal_entry_with_against_jv(self):
|
||||||
@ -75,54 +75,46 @@ class TestJournalEntry(unittest.TestCase):
|
|||||||
|
|
||||||
elif test_voucher.doctype in ["Sales Order", "Purchase Order"]:
|
elif test_voucher.doctype in ["Sales Order", "Purchase Order"]:
|
||||||
# if test_voucher is a Sales Order/Purchase Order, test error on cancellation of test_voucher
|
# if test_voucher is a Sales Order/Purchase Order, test error on cancellation of test_voucher
|
||||||
|
frappe.db.set_value("Accounts Settings", "Accounts Settings",
|
||||||
|
"unlink_advance_payment_on_cancelation_of_order", 0)
|
||||||
submitted_voucher = frappe.get_doc(test_voucher.doctype, test_voucher.name)
|
submitted_voucher = frappe.get_doc(test_voucher.doctype, test_voucher.name)
|
||||||
self.assertRaises(frappe.LinkExistsError, submitted_voucher.cancel)
|
self.assertRaises(frappe.LinkExistsError, submitted_voucher.cancel)
|
||||||
|
|
||||||
def test_jv_against_stock_account(self):
|
def test_jv_against_stock_account(self):
|
||||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
|
company = "_Test Company with perpetual inventory"
|
||||||
set_perpetual_inventory()
|
stock_account = get_inventory_account(company)
|
||||||
|
|
||||||
jv = frappe.copy_doc({
|
from erpnext.accounts.utils import get_stock_and_account_balance
|
||||||
"cheque_date": nowdate(),
|
account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(stock_account, nowdate(), company)
|
||||||
"cheque_no": "33",
|
diff = flt(account_bal) - flt(stock_bal)
|
||||||
"company": "_Test Company with perpetual inventory",
|
|
||||||
"doctype": "Journal Entry",
|
|
||||||
"accounts": [
|
|
||||||
{
|
|
||||||
"account": "Debtors - TCP1",
|
|
||||||
"party_type": "Customer",
|
|
||||||
"party": "_Test Customer",
|
|
||||||
"credit_in_account_currency": 400.0,
|
|
||||||
"debit_in_account_currency": 0.0,
|
|
||||||
"doctype": "Journal Entry Account",
|
|
||||||
"parentfield": "accounts",
|
|
||||||
"cost_center": "Main - TCP1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"account": "_Test Bank - TCP1",
|
|
||||||
"credit_in_account_currency": 0.0,
|
|
||||||
"debit_in_account_currency": 400.0,
|
|
||||||
"doctype": "Journal Entry Account",
|
|
||||||
"parentfield": "accounts",
|
|
||||||
"cost_center": "Main - TCP1"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"naming_series": "_T-Journal Entry-",
|
|
||||||
"posting_date": nowdate(),
|
|
||||||
"user_remark": "test",
|
|
||||||
"voucher_type": "Bank Entry"
|
|
||||||
})
|
|
||||||
|
|
||||||
jv.get("accounts")[0].update({
|
if not diff:
|
||||||
"account": get_inventory_account('_Test Company with perpetual inventory'),
|
diff = 100
|
||||||
"company": "_Test Company with perpetual inventory",
|
|
||||||
"party_type": None,
|
jv = frappe.new_doc("Journal Entry")
|
||||||
"party": None
|
jv.company = company
|
||||||
|
jv.posting_date = nowdate()
|
||||||
|
jv.append("accounts", {
|
||||||
|
"account": stock_account,
|
||||||
|
"cost_center": "Main - TCP1",
|
||||||
|
"debit_in_account_currency": 0 if diff > 0 else abs(diff),
|
||||||
|
"credit_in_account_currency": diff if diff > 0 else 0
|
||||||
})
|
})
|
||||||
|
|
||||||
self.assertRaises(StockAccountInvalidTransaction, jv.submit)
|
jv.append("accounts", {
|
||||||
jv.cancel()
|
"account": "Stock Adjustment - TCP1",
|
||||||
set_perpetual_inventory(0)
|
"cost_center": "Main - TCP1",
|
||||||
|
"debit_in_account_currency": diff if diff > 0 else 0,
|
||||||
|
"credit_in_account_currency": 0 if diff > 0 else abs(diff)
|
||||||
|
})
|
||||||
|
jv.insert()
|
||||||
|
|
||||||
|
if account_bal == stock_bal:
|
||||||
|
self.assertRaises(StockAccountInvalidTransaction, jv.submit)
|
||||||
|
frappe.db.rollback()
|
||||||
|
else:
|
||||||
|
jv.submit()
|
||||||
|
jv.cancel()
|
||||||
|
|
||||||
def test_multi_currency(self):
|
def test_multi_currency(self):
|
||||||
jv = make_journal_entry("_Test Bank USD - _TC",
|
jv = make_journal_entry("_Test Bank USD - _TC",
|
||||||
@ -307,15 +299,20 @@ class TestJournalEntry(unittest.TestCase):
|
|||||||
|
|
||||||
def test_jv_with_project(self):
|
def test_jv_with_project(self):
|
||||||
from erpnext.projects.doctype.project.test_project import make_project
|
from erpnext.projects.doctype.project.test_project import make_project
|
||||||
project = make_project({
|
|
||||||
'project_name': 'Journal Entry Project',
|
if not frappe.db.exists("Project", {"project_name": "Journal Entry Project"}):
|
||||||
'project_template_name': 'Test Project Template',
|
project = make_project({
|
||||||
'start_date': '2020-01-01'
|
'project_name': 'Journal Entry Project',
|
||||||
})
|
'project_template_name': 'Test Project Template',
|
||||||
|
'start_date': '2020-01-01'
|
||||||
|
})
|
||||||
|
project_name = project.name
|
||||||
|
else:
|
||||||
|
project_name = frappe.get_value("Project", {"project_name": "_Test Project"})
|
||||||
|
|
||||||
jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, save=False)
|
jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, save=False)
|
||||||
for d in jv.accounts:
|
for d in jv.accounts:
|
||||||
d.project = project.project_name
|
d.project = project_name
|
||||||
jv.voucher_type = "Bank Entry"
|
jv.voucher_type = "Bank Entry"
|
||||||
jv.multi_currency = 0
|
jv.multi_currency = 0
|
||||||
jv.cheque_no = "112233"
|
jv.cheque_no = "112233"
|
||||||
@ -325,10 +322,10 @@ class TestJournalEntry(unittest.TestCase):
|
|||||||
|
|
||||||
expected_values = {
|
expected_values = {
|
||||||
"_Test Cash - _TC": {
|
"_Test Cash - _TC": {
|
||||||
"project": project.project_name
|
"project": project_name
|
||||||
},
|
},
|
||||||
"_Test Bank - _TC": {
|
"_Test Bank - _TC": {
|
||||||
"project": project.project_name
|
"project": project_name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
frappe.provide("erpnext.accounts.dimensions");
|
||||||
|
|
||||||
frappe.ui.form.on('Loyalty Program', {
|
frappe.ui.form.on('Loyalty Program', {
|
||||||
setup: function(frm) {
|
setup: function(frm) {
|
||||||
var help_content =
|
var help_content =
|
||||||
@ -46,20 +48,17 @@ frappe.ui.form.on('Loyalty Program', {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
frm.set_query("cost_center", function() {
|
|
||||||
return {
|
|
||||||
filters: {
|
|
||||||
company: frm.doc.company
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
frm.set_value("company", frappe.defaults.get_user_default("Company"));
|
frm.set_value("company", frappe.defaults.get_user_default("Company"));
|
||||||
|
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
if (frm.doc.loyalty_program_type === "Single Tier Program" && frm.doc.collection_rules.length > 1) {
|
if (frm.doc.loyalty_program_type === "Single Tier Program" && frm.doc.collection_rules.length > 1) {
|
||||||
frappe.throw(__("Please select the Multiple Tier Program type for more than one collection rules."));
|
frappe.throw(__("Please select the Multiple Tier Program type for more than one collection rules."));
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
company: function(frm) {
|
||||||
|
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -8,12 +8,10 @@ import unittest
|
|||||||
from frappe.utils import today, cint, flt, getdate
|
from frappe.utils import today, cint, flt, getdate
|
||||||
from erpnext.accounts.doctype.loyalty_program.loyalty_program import get_loyalty_program_details_with_points
|
from erpnext.accounts.doctype.loyalty_program.loyalty_program import get_loyalty_program_details_with_points
|
||||||
from erpnext.accounts.party import get_dashboard_info
|
from erpnext.accounts.party import get_dashboard_info
|
||||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
|
|
||||||
|
|
||||||
class TestLoyaltyProgram(unittest.TestCase):
|
class TestLoyaltyProgram(unittest.TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(self):
|
def setUpClass(self):
|
||||||
set_perpetual_inventory(0)
|
|
||||||
# create relevant item, customer, loyalty program, etc
|
# create relevant item, customer, loyalty program, etc
|
||||||
create_records()
|
create_records()
|
||||||
|
|
||||||
|
@ -36,6 +36,8 @@ frappe.ui.form.on('Opening Invoice Creation Tool', {
|
|||||||
frm.dashboard.show_progress(data.title, (data.count / data.total) * 100, data.message);
|
frm.dashboard.show_progress(data.title, (data.count / data.total) * 100, data.message);
|
||||||
frm.page.set_indicator(__('In Progress'), 'orange');
|
frm.page.set_indicator(__('In Progress'), 'orange');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
@ -100,6 +102,7 @@ frappe.ui.form.on('Opening Invoice Creation Tool', {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
|
||||||
},
|
},
|
||||||
|
|
||||||
invoice_type: function(frm) {
|
invoice_type: function(frm) {
|
||||||
@ -118,7 +121,8 @@ frappe.ui.form.on('Opening Invoice Creation Tool', {
|
|||||||
frappe.render_template('opening_invoice_creation_tool_dashboard', {
|
frappe.render_template('opening_invoice_creation_tool_dashboard', {
|
||||||
data: opening_invoices_summary,
|
data: opening_invoices_summary,
|
||||||
max_count: max_count
|
max_count: max_count
|
||||||
})
|
}),
|
||||||
|
__("Opening Invoices Summary")
|
||||||
);
|
);
|
||||||
|
|
||||||
section.on('click', '.invoice-link', function() {
|
section.on('click', '.invoice-link', function() {
|
||||||
|
@ -155,7 +155,8 @@ class OpeningInvoiceCreationTool(Document):
|
|||||||
"posting_date": row.posting_date,
|
"posting_date": row.posting_date,
|
||||||
frappe.scrub(row.party_type): row.party,
|
frappe.scrub(row.party_type): row.party,
|
||||||
"is_pos": 0,
|
"is_pos": 0,
|
||||||
"doctype": "Sales Invoice" if self.invoice_type == "Sales" else "Purchase Invoice"
|
"doctype": "Sales Invoice" if self.invoice_type == "Sales" else "Purchase Invoice",
|
||||||
|
"update_stock": 0
|
||||||
})
|
})
|
||||||
|
|
||||||
accounting_dimension = get_accounting_dimensions()
|
accounting_dimension = get_accounting_dimensions()
|
||||||
@ -209,7 +210,7 @@ def start_import(invoices):
|
|||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
if errors:
|
if errors:
|
||||||
frappe.msgprint(_("You had {} errors while creating opening invoices. Check {} for more details")
|
frappe.msgprint(_("You had {} errors while creating opening invoices. Check {} for more details")
|
||||||
.format(errors, "<a href='#List/Error Log' class='variant-click'>Error Log</a>"), indicator="red", title=_("Error Occured"))
|
.format(errors, "<a href='/app/List/Error Log' class='variant-click'>Error Log</a>"), indicator="red", title=_("Error Occured"))
|
||||||
return names
|
return names
|
||||||
|
|
||||||
def publish(index, total, doctype):
|
def publish(index, total, doctype):
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
<h5 style="margin-top: 0px;">{{ __("Opening Invoices Summary") }}</h5>
|
|
||||||
{% $.each(data, (company, summary) => { %}
|
{% $.each(data, (company, summary) => { %}
|
||||||
<h6 style="margin: 15px 0px -10px 0px;"><a class="company-link"> {{ company }}</a></h6>
|
<h6 style="margin: 15px 0px -10px 0px;"><a class="company-link"> {{ company }}</a></h6>
|
||||||
|
|
||||||
|
@ -7,17 +7,24 @@ import frappe
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
test_dependencies = ["Customer", "Supplier"]
|
test_dependencies = ["Customer", "Supplier"]
|
||||||
|
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
|
||||||
from erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool import get_temporary_opening_account
|
from erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool import get_temporary_opening_account
|
||||||
|
|
||||||
class TestOpeningInvoiceCreationTool(unittest.TestCase):
|
class TestOpeningInvoiceCreationTool(unittest.TestCase):
|
||||||
def make_invoices(self, invoice_type="Sales"):
|
def setUp(self):
|
||||||
|
if not frappe.db.exists("Company", "_Test Opening Invoice Company"):
|
||||||
|
make_company()
|
||||||
|
|
||||||
|
def make_invoices(self, invoice_type="Sales", company=None, party_1=None, party_2=None):
|
||||||
doc = frappe.get_single("Opening Invoice Creation Tool")
|
doc = frappe.get_single("Opening Invoice Creation Tool")
|
||||||
args = get_opening_invoice_creation_dict(invoice_type=invoice_type)
|
args = get_opening_invoice_creation_dict(invoice_type=invoice_type, company=company,
|
||||||
|
party_1=party_1, party_2=party_2)
|
||||||
doc.update(args)
|
doc.update(args)
|
||||||
return doc.make_invoices()
|
return doc.make_invoices()
|
||||||
|
|
||||||
def test_opening_sales_invoice_creation(self):
|
def test_opening_sales_invoice_creation(self):
|
||||||
invoices = self.make_invoices()
|
property_setter = make_property_setter("Sales Invoice", "update_stock", "default", 1, "Check")
|
||||||
|
invoices = self.make_invoices(company="_Test Opening Invoice Company")
|
||||||
|
|
||||||
self.assertEqual(len(invoices), 2)
|
self.assertEqual(len(invoices), 2)
|
||||||
expected_value = {
|
expected_value = {
|
||||||
@ -27,6 +34,13 @@ class TestOpeningInvoiceCreationTool(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
self.check_expected_values(invoices, expected_value)
|
self.check_expected_values(invoices, expected_value)
|
||||||
|
|
||||||
|
si = frappe.get_doc("Sales Invoice", invoices[0])
|
||||||
|
|
||||||
|
# Check if update stock is not enabled
|
||||||
|
self.assertEqual(si.update_stock, 0)
|
||||||
|
|
||||||
|
property_setter.delete()
|
||||||
|
|
||||||
def check_expected_values(self, invoices, expected_value, invoice_type="Sales"):
|
def check_expected_values(self, invoices, expected_value, invoice_type="Sales"):
|
||||||
doctype = "Sales Invoice" if invoice_type == "Sales" else "Purchase Invoice"
|
doctype = "Sales Invoice" if invoice_type == "Sales" else "Purchase Invoice"
|
||||||
|
|
||||||
@ -36,7 +50,7 @@ class TestOpeningInvoiceCreationTool(unittest.TestCase):
|
|||||||
self.assertEqual(si.get(field, ""), expected_value[invoice_idx][field_idx])
|
self.assertEqual(si.get(field, ""), expected_value[invoice_idx][field_idx])
|
||||||
|
|
||||||
def test_opening_purchase_invoice_creation(self):
|
def test_opening_purchase_invoice_creation(self):
|
||||||
invoices = self.make_invoices(invoice_type="Purchase")
|
invoices = self.make_invoices(invoice_type="Purchase", company="_Test Opening Invoice Company")
|
||||||
|
|
||||||
self.assertEqual(len(invoices), 2)
|
self.assertEqual(len(invoices), 2)
|
||||||
expected_value = {
|
expected_value = {
|
||||||
@ -46,6 +60,32 @@ class TestOpeningInvoiceCreationTool(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
self.check_expected_values(invoices, expected_value, "Purchase")
|
self.check_expected_values(invoices, expected_value, "Purchase")
|
||||||
|
|
||||||
|
def test_opening_sales_invoice_creation_with_missing_debit_account(self):
|
||||||
|
company = "_Test Opening Invoice Company"
|
||||||
|
party_1, party_2 = make_customer("Customer A"), make_customer("Customer B")
|
||||||
|
|
||||||
|
old_default_receivable_account = frappe.db.get_value("Company", company, "default_receivable_account")
|
||||||
|
frappe.db.set_value("Company", company, "default_receivable_account", "")
|
||||||
|
|
||||||
|
if not frappe.db.exists("Cost Center", "_Test Opening Invoice Company - _TOIC"):
|
||||||
|
cc = frappe.get_doc({"doctype": "Cost Center", "cost_center_name": "_Test Opening Invoice Company",
|
||||||
|
"is_group": 1, "company": "_Test Opening Invoice Company"})
|
||||||
|
cc.insert(ignore_mandatory=True)
|
||||||
|
cc2 = frappe.get_doc({"doctype": "Cost Center", "cost_center_name": "Main", "is_group": 0,
|
||||||
|
"company": "_Test Opening Invoice Company", "parent_cost_center": cc.name})
|
||||||
|
cc2.insert()
|
||||||
|
|
||||||
|
frappe.db.set_value("Company", company, "cost_center", "Main - _TOIC")
|
||||||
|
|
||||||
|
self.make_invoices(company="_Test Opening Invoice Company", party_1=party_1, party_2=party_2)
|
||||||
|
|
||||||
|
# Check if missing debit account error raised
|
||||||
|
error_log = frappe.db.exists("Error Log", {"error": ["like", "%erpnext.controllers.accounts_controller.AccountMissingError%"]})
|
||||||
|
self.assertTrue(error_log)
|
||||||
|
|
||||||
|
# teardown
|
||||||
|
frappe.db.set_value("Company", company, "default_receivable_account", old_default_receivable_account)
|
||||||
|
|
||||||
def get_opening_invoice_creation_dict(**args):
|
def get_opening_invoice_creation_dict(**args):
|
||||||
party = "Customer" if args.get("invoice_type", "Sales") == "Sales" else "Supplier"
|
party = "Customer" if args.get("invoice_type", "Sales") == "Sales" else "Supplier"
|
||||||
company = args.get("company", "_Test Company")
|
company = args.get("company", "_Test Company")
|
||||||
@ -57,7 +97,7 @@ def get_opening_invoice_creation_dict(**args):
|
|||||||
{
|
{
|
||||||
"qty": 1.0,
|
"qty": 1.0,
|
||||||
"outstanding_amount": 300,
|
"outstanding_amount": 300,
|
||||||
"party": "_Test {0}".format(party),
|
"party": args.get("party_1") or "_Test {0}".format(party),
|
||||||
"item_name": "Opening Item",
|
"item_name": "Opening Item",
|
||||||
"due_date": "2016-09-10",
|
"due_date": "2016-09-10",
|
||||||
"posting_date": "2016-09-05",
|
"posting_date": "2016-09-05",
|
||||||
@ -66,7 +106,7 @@ def get_opening_invoice_creation_dict(**args):
|
|||||||
{
|
{
|
||||||
"qty": 2.0,
|
"qty": 2.0,
|
||||||
"outstanding_amount": 250,
|
"outstanding_amount": 250,
|
||||||
"party": "_Test {0} 1".format(party),
|
"party": args.get("party_2") or "_Test {0} 1".format(party),
|
||||||
"item_name": "Opening Item",
|
"item_name": "Opening Item",
|
||||||
"due_date": "2016-09-10",
|
"due_date": "2016-09-10",
|
||||||
"posting_date": "2016-09-05",
|
"posting_date": "2016-09-05",
|
||||||
@ -77,3 +117,30 @@ def get_opening_invoice_creation_dict(**args):
|
|||||||
|
|
||||||
invoice_dict.update(args)
|
invoice_dict.update(args)
|
||||||
return invoice_dict
|
return invoice_dict
|
||||||
|
|
||||||
|
def make_company():
|
||||||
|
if frappe.db.exists("Company", "_Test Opening Invoice Company"):
|
||||||
|
return frappe.get_doc("Company", "_Test Opening Invoice Company")
|
||||||
|
|
||||||
|
company = frappe.new_doc("Company")
|
||||||
|
company.company_name = "_Test Opening Invoice Company"
|
||||||
|
company.abbr = "_TOIC"
|
||||||
|
company.default_currency = "INR"
|
||||||
|
company.country = "India"
|
||||||
|
company.insert()
|
||||||
|
return company
|
||||||
|
|
||||||
|
def make_customer(customer=None):
|
||||||
|
customer_name = customer or "Opening Customer"
|
||||||
|
customer = frappe.get_doc({
|
||||||
|
"doctype": "Customer",
|
||||||
|
"customer_name": customer_name,
|
||||||
|
"customer_group": "All Customer Groups",
|
||||||
|
"customer_type": "Company",
|
||||||
|
"territory": "All Territories"
|
||||||
|
})
|
||||||
|
if not frappe.db.exists("Customer", customer_name):
|
||||||
|
customer.insert(ignore_permissions=True)
|
||||||
|
return customer.name
|
||||||
|
else:
|
||||||
|
return frappe.db.exists("Customer", customer_name)
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
{% include "erpnext/public/js/controllers/accounts.js" %}
|
{% include "erpnext/public/js/controllers/accounts.js" %}
|
||||||
|
frappe.provide("erpnext.accounts.dimensions");
|
||||||
|
|
||||||
frappe.ui.form.on('Payment Entry', {
|
frappe.ui.form.on('Payment Entry', {
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
@ -8,6 +9,8 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null);
|
if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null);
|
||||||
if (!frm.doc.paid_to) frm.set_value("paid_to_account_currency", null);
|
if (!frm.doc.paid_to) frm.set_value("paid_to_account_currency", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
|
||||||
},
|
},
|
||||||
|
|
||||||
setup: function(frm) {
|
setup: function(frm) {
|
||||||
@ -88,15 +91,6 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
frm.set_query("cost_center", "deductions", function() {
|
|
||||||
return {
|
|
||||||
filters: {
|
|
||||||
"is_group": 0,
|
|
||||||
"company": frm.doc.company
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
frm.set_query("reference_doctype", "references", function() {
|
frm.set_query("reference_doctype", "references", function() {
|
||||||
if (frm.doc.party_type=="Customer") {
|
if (frm.doc.party_type=="Customer") {
|
||||||
var doctypes = ["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"];
|
var doctypes = ["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"];
|
||||||
@ -167,6 +161,7 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
company: function(frm) {
|
company: function(frm) {
|
||||||
frm.events.hide_unhide_fields(frm);
|
frm.events.hide_unhide_fields(frm);
|
||||||
frm.events.set_dynamic_labels(frm);
|
frm.events.set_dynamic_labels(frm);
|
||||||
|
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
|
||||||
},
|
},
|
||||||
|
|
||||||
contact_person: function(frm) {
|
contact_person: function(frm) {
|
||||||
@ -401,6 +396,8 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
|
|
||||||
set_account_currency_and_balance: function(frm, account, currency_field,
|
set_account_currency_and_balance: function(frm, account, currency_field,
|
||||||
balance_field, callback_function) {
|
balance_field, callback_function) {
|
||||||
|
|
||||||
|
var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
|
||||||
if (frm.doc.posting_date && account) {
|
if (frm.doc.posting_date && account) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_account_details",
|
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_account_details",
|
||||||
@ -427,6 +424,14 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
|
|
||||||
if(!frm.doc.paid_amount && frm.doc.received_amount)
|
if(!frm.doc.paid_amount && frm.doc.received_amount)
|
||||||
frm.events.received_amount(frm);
|
frm.events.received_amount(frm);
|
||||||
|
|
||||||
|
if (frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency
|
||||||
|
&& frm.doc.paid_amount != frm.doc.received_amount) {
|
||||||
|
if (company_currency != frm.doc.paid_from_account_currency &&
|
||||||
|
frm.doc.payment_type == "Pay") {
|
||||||
|
frm.doc.paid_amount = frm.doc.received_amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
|
@ -88,19 +88,19 @@ class PaymentReconciliation(Document):
|
|||||||
voucher_type = ('Sales Invoice'
|
voucher_type = ('Sales Invoice'
|
||||||
if self.party_type == 'Customer' else "Purchase Invoice")
|
if self.party_type == 'Customer' else "Purchase Invoice")
|
||||||
|
|
||||||
return frappe.db.sql(""" SELECT `tab{doc}`.name as reference_name, %(voucher_type)s as reference_type,
|
return frappe.db.sql(""" SELECT doc.name as reference_name, %(voucher_type)s as reference_type,
|
||||||
(sum(`tabGL Entry`.{dr_or_cr}) - sum(`tabGL Entry`.{reconciled_dr_or_cr})) as amount,
|
(sum(gl.{dr_or_cr}) - sum(gl.{reconciled_dr_or_cr})) as amount,
|
||||||
account_currency as currency
|
account_currency as currency
|
||||||
FROM `tab{doc}`, `tabGL Entry`
|
FROM `tab{doc}` doc, `tabGL Entry` gl
|
||||||
WHERE
|
WHERE
|
||||||
(`tab{doc}`.name = `tabGL Entry`.against_voucher or `tab{doc}`.name = `tabGL Entry`.voucher_no)
|
(doc.name = gl.against_voucher or doc.name = gl.voucher_no)
|
||||||
and `tab{doc}`.{party_type_field} = %(party)s
|
and doc.{party_type_field} = %(party)s
|
||||||
and `tab{doc}`.is_return = 1 and `tab{doc}`.return_against IS NULL
|
and doc.is_return = 1 and ifnull(doc.return_against, "") = ""
|
||||||
and `tabGL Entry`.against_voucher_type = %(voucher_type)s
|
and gl.against_voucher_type = %(voucher_type)s
|
||||||
and `tab{doc}`.docstatus = 1 and `tabGL Entry`.party = %(party)s
|
and doc.docstatus = 1 and gl.party = %(party)s
|
||||||
and `tabGL Entry`.party_type = %(party_type)s and `tabGL Entry`.account = %(account)s
|
and gl.party_type = %(party_type)s and gl.account = %(account)s
|
||||||
and `tabGL Entry`.is_cancelled = 0
|
and gl.is_cancelled = 0
|
||||||
GROUP BY `tab{doc}`.name
|
GROUP BY doc.name
|
||||||
Having
|
Having
|
||||||
amount > 0
|
amount > 0
|
||||||
""".format(
|
""".format(
|
||||||
@ -113,7 +113,7 @@ class PaymentReconciliation(Document):
|
|||||||
'party_type': self.party_type,
|
'party_type': self.party_type,
|
||||||
'voucher_type': voucher_type,
|
'voucher_type': voucher_type,
|
||||||
'account': self.receivable_payable_account
|
'account': self.receivable_payable_account
|
||||||
}, as_dict=1)
|
}, as_dict=1, debug=1)
|
||||||
|
|
||||||
def add_payment_entries(self, entries):
|
def add_payment_entries(self, entries):
|
||||||
self.set('payments', [])
|
self.set('payments', [])
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
import json
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
@ -82,18 +83,37 @@ class PaymentRequest(Document):
|
|||||||
self.make_communication_entry()
|
self.make_communication_entry()
|
||||||
|
|
||||||
elif self.payment_channel == "Phone":
|
elif self.payment_channel == "Phone":
|
||||||
controller = get_payment_gateway_controller(self.payment_gateway)
|
self.request_phone_payment()
|
||||||
payment_record = dict(
|
|
||||||
reference_doctype="Payment Request",
|
def request_phone_payment(self):
|
||||||
reference_docname=self.name,
|
controller = get_payment_gateway_controller(self.payment_gateway)
|
||||||
payment_reference=self.reference_name,
|
request_amount = self.get_request_amount()
|
||||||
grand_total=self.grand_total,
|
|
||||||
sender=self.email_to,
|
payment_record = dict(
|
||||||
currency=self.currency,
|
reference_doctype="Payment Request",
|
||||||
payment_gateway=self.payment_gateway
|
reference_docname=self.name,
|
||||||
)
|
payment_reference=self.reference_name,
|
||||||
controller.validate_transaction_currency(self.currency)
|
request_amount=request_amount,
|
||||||
controller.request_for_payment(**payment_record)
|
sender=self.email_to,
|
||||||
|
currency=self.currency,
|
||||||
|
payment_gateway=self.payment_gateway
|
||||||
|
)
|
||||||
|
|
||||||
|
controller.validate_transaction_currency(self.currency)
|
||||||
|
controller.request_for_payment(**payment_record)
|
||||||
|
|
||||||
|
def get_request_amount(self):
|
||||||
|
data_of_completed_requests = frappe.get_all("Integration Request", filters={
|
||||||
|
'reference_doctype': self.doctype,
|
||||||
|
'reference_docname': self.name,
|
||||||
|
'status': 'Completed'
|
||||||
|
}, pluck="data")
|
||||||
|
|
||||||
|
if not data_of_completed_requests:
|
||||||
|
return self.grand_total
|
||||||
|
|
||||||
|
request_amounts = sum([json.loads(d).get('request_amount') for d in data_of_completed_requests])
|
||||||
|
return request_amounts
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
self.check_if_payment_entry_exists()
|
self.check_if_payment_entry_exists()
|
||||||
@ -351,8 +371,8 @@ def make_payment_request(**args):
|
|||||||
if args.order_type == "Shopping Cart" or args.mute_email:
|
if args.order_type == "Shopping Cart" or args.mute_email:
|
||||||
pr.flags.mute_email = True
|
pr.flags.mute_email = True
|
||||||
|
|
||||||
|
pr.insert(ignore_permissions=True)
|
||||||
if args.submit_doc:
|
if args.submit_doc:
|
||||||
pr.insert(ignore_permissions=True)
|
|
||||||
pr.submit()
|
pr.submit()
|
||||||
|
|
||||||
if args.order_type == "Shopping Cart":
|
if args.order_type == "Shopping Cart":
|
||||||
@ -412,8 +432,8 @@ def get_existing_payment_request_amount(ref_dt, ref_dn):
|
|||||||
|
|
||||||
def get_gateway_details(args):
|
def get_gateway_details(args):
|
||||||
"""return gateway and payment account of default payment gateway"""
|
"""return gateway and payment account of default payment gateway"""
|
||||||
if args.get("payment_gateway"):
|
if args.get("payment_gateway_account"):
|
||||||
return get_payment_gateway_account(args.get("payment_gateway"))
|
return get_payment_gateway_account(args.get("payment_gateway_account"))
|
||||||
|
|
||||||
if args.order_type == "Shopping Cart":
|
if args.order_type == "Shopping Cart":
|
||||||
payment_gateway_account = frappe.get_doc("Shopping Cart Settings").payment_gateway_account
|
payment_gateway_account = frappe.get_doc("Shopping Cart Settings").payment_gateway_account
|
||||||
|
@ -2,7 +2,7 @@ frappe.listview_settings['Payment Request'] = {
|
|||||||
add_fields: ["status"],
|
add_fields: ["status"],
|
||||||
get_indicator: function(doc) {
|
get_indicator: function(doc) {
|
||||||
if(doc.status == "Draft") {
|
if(doc.status == "Draft") {
|
||||||
return [__("Draft"), "darkgrey", "status,=,Draft"];
|
return [__("Draft"), "gray", "status,=,Draft"];
|
||||||
}
|
}
|
||||||
if(doc.status == "Requested") {
|
if(doc.status == "Requested") {
|
||||||
return [__("Requested"), "green", "status,=,Requested"];
|
return [__("Requested"), "green", "status,=,Requested"];
|
||||||
|
@ -45,7 +45,8 @@ class TestPaymentRequest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_payment_request_linkings(self):
|
def test_payment_request_linkings(self):
|
||||||
so_inr = make_sales_order(currency="INR")
|
so_inr = make_sales_order(currency="INR")
|
||||||
pr = make_payment_request(dt="Sales Order", dn=so_inr.name, recipient_id="saurabh@erpnext.com")
|
pr = make_payment_request(dt="Sales Order", dn=so_inr.name, recipient_id="saurabh@erpnext.com",
|
||||||
|
payment_gateway_account="_Test Gateway - INR")
|
||||||
|
|
||||||
self.assertEqual(pr.reference_doctype, "Sales Order")
|
self.assertEqual(pr.reference_doctype, "Sales Order")
|
||||||
self.assertEqual(pr.reference_name, so_inr.name)
|
self.assertEqual(pr.reference_name, so_inr.name)
|
||||||
@ -54,7 +55,8 @@ class TestPaymentRequest(unittest.TestCase):
|
|||||||
conversion_rate = get_exchange_rate("USD", "INR")
|
conversion_rate = get_exchange_rate("USD", "INR")
|
||||||
|
|
||||||
si_usd = create_sales_invoice(currency="USD", conversion_rate=conversion_rate)
|
si_usd = create_sales_invoice(currency="USD", conversion_rate=conversion_rate)
|
||||||
pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com")
|
pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com",
|
||||||
|
payment_gateway_account="_Test Gateway - USD")
|
||||||
|
|
||||||
self.assertEqual(pr.reference_doctype, "Sales Invoice")
|
self.assertEqual(pr.reference_doctype, "Sales Invoice")
|
||||||
self.assertEqual(pr.reference_name, si_usd.name)
|
self.assertEqual(pr.reference_name, si_usd.name)
|
||||||
@ -68,7 +70,7 @@ class TestPaymentRequest(unittest.TestCase):
|
|||||||
|
|
||||||
so_inr = make_sales_order(currency="INR")
|
so_inr = make_sales_order(currency="INR")
|
||||||
pr = make_payment_request(dt="Sales Order", dn=so_inr.name, recipient_id="saurabh@erpnext.com",
|
pr = make_payment_request(dt="Sales Order", dn=so_inr.name, recipient_id="saurabh@erpnext.com",
|
||||||
mute_email=1, submit_doc=1, return_doc=1)
|
mute_email=1, payment_gateway_account="_Test Gateway - INR", submit_doc=1, return_doc=1)
|
||||||
pe = pr.set_as_paid()
|
pe = pr.set_as_paid()
|
||||||
|
|
||||||
so_inr = frappe.get_doc("Sales Order", so_inr.name)
|
so_inr = frappe.get_doc("Sales Order", so_inr.name)
|
||||||
@ -79,7 +81,7 @@ class TestPaymentRequest(unittest.TestCase):
|
|||||||
currency="USD", conversion_rate=50)
|
currency="USD", conversion_rate=50)
|
||||||
|
|
||||||
pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com",
|
pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com",
|
||||||
mute_email=1, payment_gateway="_Test Gateway - USD", submit_doc=1, return_doc=1)
|
mute_email=1, payment_gateway_account="_Test Gateway - USD", submit_doc=1, return_doc=1)
|
||||||
|
|
||||||
pe = pr.set_as_paid()
|
pe = pr.set_as_paid()
|
||||||
|
|
||||||
@ -106,7 +108,7 @@ class TestPaymentRequest(unittest.TestCase):
|
|||||||
currency="USD", conversion_rate=50)
|
currency="USD", conversion_rate=50)
|
||||||
|
|
||||||
pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com",
|
pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com",
|
||||||
mute_email=1, payment_gateway="_Test Gateway - USD", submit_doc=1, return_doc=1)
|
mute_email=1, payment_gateway_account="_Test Gateway - USD", submit_doc=1, return_doc=1)
|
||||||
|
|
||||||
pe = pr.create_payment_entry()
|
pe = pr.create_payment_entry()
|
||||||
pr.load_from_db()
|
pr.load_from_db()
|
||||||
|
@ -8,7 +8,7 @@ from frappe import _
|
|||||||
from erpnext.accounts.utils import get_account_currency
|
from erpnext.accounts.utils import get_account_currency
|
||||||
from erpnext.controllers.accounts_controller import AccountsController
|
from erpnext.controllers.accounts_controller import AccountsController
|
||||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (get_accounting_dimensions,
|
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (get_accounting_dimensions,
|
||||||
get_dimension_filters)
|
get_dimensions)
|
||||||
|
|
||||||
class PeriodClosingVoucher(AccountsController):
|
class PeriodClosingVoucher(AccountsController):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@ -58,7 +58,7 @@ class PeriodClosingVoucher(AccountsController):
|
|||||||
for dimension in accounting_dimensions:
|
for dimension in accounting_dimensions:
|
||||||
dimension_fields.append('t1.{0}'.format(dimension))
|
dimension_fields.append('t1.{0}'.format(dimension))
|
||||||
|
|
||||||
dimension_filters, default_dimensions = get_dimension_filters()
|
dimension_filters, default_dimensions = get_dimensions()
|
||||||
|
|
||||||
pl_accounts = self.get_pl_balances(dimension_fields)
|
pl_accounts = self.get_pl_balances(dimension_fields)
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
frappe.ui.form.on('POS Closing Entry', {
|
frappe.ui.form.on('POS Closing Entry', {
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
|
frm.ignore_doctypes_on_cancel_all = ['POS Invoice Merge Log'];
|
||||||
frm.set_query("pos_profile", function(doc) {
|
frm.set_query("pos_profile", function(doc) {
|
||||||
return {
|
return {
|
||||||
filters: { 'user': doc.user }
|
filters: { 'user': doc.user }
|
||||||
@ -20,7 +21,7 @@ frappe.ui.form.on('POS Closing Entry', {
|
|||||||
return { filters: { 'status': 'Open', 'docstatus': 1 } };
|
return { filters: { 'status': 'Open', 'docstatus': 1 } };
|
||||||
});
|
});
|
||||||
|
|
||||||
if (frm.doc.docstatus === 0) frm.set_value("period_end_date", frappe.datetime.now_datetime());
|
if (frm.doc.docstatus === 0 && !frm.doc.amended_from) frm.set_value("period_end_date", frappe.datetime.now_datetime());
|
||||||
if (frm.doc.docstatus === 1) set_html_data(frm);
|
if (frm.doc.docstatus === 1) set_html_data(frm);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -6,11 +6,13 @@
|
|||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
|
"period_details_section",
|
||||||
"period_start_date",
|
"period_start_date",
|
||||||
"period_end_date",
|
"period_end_date",
|
||||||
"column_break_3",
|
"column_break_3",
|
||||||
"posting_date",
|
"posting_date",
|
||||||
"pos_opening_entry",
|
"pos_opening_entry",
|
||||||
|
"status",
|
||||||
"section_break_5",
|
"section_break_5",
|
||||||
"company",
|
"company",
|
||||||
"column_break_7",
|
"column_break_7",
|
||||||
@ -64,7 +66,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "section_break_5",
|
"fieldname": "section_break_5",
|
||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break",
|
||||||
|
"label": "User Details"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
@ -120,7 +123,7 @@
|
|||||||
"collapsible_depends_on": "eval:doc.docstatus==0",
|
"collapsible_depends_on": "eval:doc.docstatus==0",
|
||||||
"fieldname": "section_break_13",
|
"fieldname": "section_break_13",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Details"
|
"label": "Totals"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
@ -184,11 +187,32 @@
|
|||||||
"label": "POS Opening Entry",
|
"label": "POS Opening Entry",
|
||||||
"options": "POS Opening Entry",
|
"options": "POS Opening Entry",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 1,
|
||||||
|
"default": "Draft",
|
||||||
|
"fieldname": "status",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Status",
|
||||||
|
"options": "Draft\nSubmitted\nQueued\nCancelled",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "period_details_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Period Details"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [
|
||||||
"modified": "2020-05-29 15:03:22.226113",
|
{
|
||||||
|
"link_doctype": "POS Invoice Merge Log",
|
||||||
|
"link_fieldname": "pos_closing_entry"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"modified": "2021-02-01 13:47:20.722104",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "POS Closing Entry",
|
"name": "POS Closing Entry",
|
||||||
|
@ -6,13 +6,12 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
import json
|
import json
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.utils import get_datetime, flt
|
||||||
from frappe.utils import getdate, get_datetime, flt
|
from erpnext.controllers.status_updater import StatusUpdater
|
||||||
from collections import defaultdict
|
|
||||||
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data
|
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data
|
||||||
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import merge_pos_invoices
|
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import consolidate_pos_invoices, unconsolidate_pos_invoices
|
||||||
|
|
||||||
class POSClosingEntry(Document):
|
class POSClosingEntry(StatusUpdater):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
if frappe.db.get_value("POS Opening Entry", self.pos_opening_entry, "status") != "Open":
|
if frappe.db.get_value("POS Opening Entry", self.pos_opening_entry, "status") != "Open":
|
||||||
frappe.throw(_("Selected POS Opening Entry should be open."), title=_("Invalid Opening Entry"))
|
frappe.throw(_("Selected POS Opening Entry should be open."), title=_("Invalid Opening Entry"))
|
||||||
@ -21,11 +20,16 @@ class POSClosingEntry(Document):
|
|||||||
self.validate_pos_invoices()
|
self.validate_pos_invoices()
|
||||||
|
|
||||||
def validate_pos_closing(self):
|
def validate_pos_closing(self):
|
||||||
user = frappe.get_all("POS Closing Entry",
|
user = frappe.db.sql("""
|
||||||
filters = { "user": self.user, "docstatus": 1, "pos_profile": self.pos_profile },
|
SELECT name FROM `tabPOS Closing Entry`
|
||||||
or_filters = {
|
WHERE
|
||||||
"period_start_date": ("between", [self.period_start_date, self.period_end_date]),
|
user = %(user)s AND docstatus = 1 AND pos_profile = %(profile)s AND
|
||||||
"period_end_date": ("between", [self.period_start_date, self.period_end_date])
|
(period_start_date between %(start)s and %(end)s OR period_end_date between %(start)s and %(end)s)
|
||||||
|
""", {
|
||||||
|
'user': self.user,
|
||||||
|
'profile': self.pos_profile,
|
||||||
|
'start': self.period_start_date,
|
||||||
|
'end': self.period_end_date
|
||||||
})
|
})
|
||||||
|
|
||||||
if user:
|
if user:
|
||||||
@ -57,21 +61,30 @@ class POSClosingEntry(Document):
|
|||||||
if not invalid_rows:
|
if not invalid_rows:
|
||||||
return
|
return
|
||||||
|
|
||||||
error_list = [_("Row #{}: {}").format(row.get('idx'), row.get('msg')) for row in invalid_rows]
|
error_list = []
|
||||||
frappe.throw(error_list, title=_("Invalid POS Invoices"), as_list=True)
|
for row in invalid_rows:
|
||||||
|
for msg in row.get('msg'):
|
||||||
|
error_list.append(_("Row #{}: {}").format(row.get('idx'), msg))
|
||||||
|
|
||||||
def on_submit(self):
|
frappe.throw(error_list, title=_("Invalid POS Invoices"), as_list=True)
|
||||||
merge_pos_invoices(self.pos_transactions)
|
|
||||||
opening_entry = frappe.get_doc("POS Opening Entry", self.pos_opening_entry)
|
|
||||||
opening_entry.pos_closing_entry = self.name
|
|
||||||
opening_entry.set_status()
|
|
||||||
opening_entry.save()
|
|
||||||
|
|
||||||
def get_payment_reconciliation_details(self):
|
def get_payment_reconciliation_details(self):
|
||||||
currency = frappe.get_cached_value('Company', self.company, "default_currency")
|
currency = frappe.get_cached_value('Company', self.company, "default_currency")
|
||||||
return frappe.render_template("erpnext/accounts/doctype/pos_closing_entry/closing_voucher_details.html",
|
return frappe.render_template("erpnext/accounts/doctype/pos_closing_entry/closing_voucher_details.html",
|
||||||
{"data": self, "currency": currency})
|
{"data": self, "currency": currency})
|
||||||
|
|
||||||
|
def on_submit(self):
|
||||||
|
consolidate_pos_invoices(closing_entry=self)
|
||||||
|
|
||||||
|
def on_cancel(self):
|
||||||
|
unconsolidate_pos_invoices(closing_entry=self)
|
||||||
|
|
||||||
|
def update_opening_entry(self, for_cancel=False):
|
||||||
|
opening_entry = frappe.get_doc("POS Opening Entry", self.pos_opening_entry)
|
||||||
|
opening_entry.pos_closing_entry = self.name if not for_cancel else None
|
||||||
|
opening_entry.set_status()
|
||||||
|
opening_entry.save()
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@frappe.validate_and_sanitize_search_inputs
|
@frappe.validate_and_sanitize_search_inputs
|
||||||
def get_cashiers(doctype, txt, searchfield, start, page_len, filters):
|
def get_cashiers(doctype, txt, searchfield, start, page_len, filters):
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
// render
|
||||||
|
frappe.listview_settings['POS Closing Entry'] = {
|
||||||
|
get_indicator: function(doc) {
|
||||||
|
var status_color = {
|
||||||
|
"Draft": "red",
|
||||||
|
"Submitted": "blue",
|
||||||
|
"Queued": "orange",
|
||||||
|
"Cancelled": "red"
|
||||||
|
|
||||||
|
};
|
||||||
|
return [__(doc.status), status_color[doc.status], "status,=,"+doc.status];
|
||||||
|
}
|
||||||
|
};
|
@ -13,7 +13,6 @@ from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profi
|
|||||||
class TestPOSClosingEntry(unittest.TestCase):
|
class TestPOSClosingEntry(unittest.TestCase):
|
||||||
def test_pos_closing_entry(self):
|
def test_pos_closing_entry(self):
|
||||||
test_user, pos_profile = init_user_and_profile()
|
test_user, pos_profile = init_user_and_profile()
|
||||||
|
|
||||||
opening_entry = create_opening_entry(pos_profile, test_user.name)
|
opening_entry = create_opening_entry(pos_profile, test_user.name)
|
||||||
|
|
||||||
pos_inv1 = create_pos_invoice(rate=3500, do_not_submit=1)
|
pos_inv1 = create_pos_invoice(rate=3500, do_not_submit=1)
|
||||||
@ -45,6 +44,49 @@ class TestPOSClosingEntry(unittest.TestCase):
|
|||||||
frappe.set_user("Administrator")
|
frappe.set_user("Administrator")
|
||||||
frappe.db.sql("delete from `tabPOS Profile`")
|
frappe.db.sql("delete from `tabPOS Profile`")
|
||||||
|
|
||||||
|
def test_cancelling_of_pos_closing_entry(self):
|
||||||
|
test_user, pos_profile = init_user_and_profile()
|
||||||
|
opening_entry = create_opening_entry(pos_profile, test_user.name)
|
||||||
|
|
||||||
|
pos_inv1 = create_pos_invoice(rate=3500, do_not_submit=1)
|
||||||
|
pos_inv1.append('payments', {
|
||||||
|
'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 3500
|
||||||
|
})
|
||||||
|
pos_inv1.submit()
|
||||||
|
|
||||||
|
pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
|
||||||
|
pos_inv2.append('payments', {
|
||||||
|
'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 3200
|
||||||
|
})
|
||||||
|
pos_inv2.submit()
|
||||||
|
|
||||||
|
pcv_doc = make_closing_entry_from_opening(opening_entry)
|
||||||
|
payment = pcv_doc.payment_reconciliation[0]
|
||||||
|
|
||||||
|
self.assertEqual(payment.mode_of_payment, 'Cash')
|
||||||
|
|
||||||
|
for d in pcv_doc.payment_reconciliation:
|
||||||
|
if d.mode_of_payment == 'Cash':
|
||||||
|
d.closing_amount = 6700
|
||||||
|
|
||||||
|
pcv_doc.submit()
|
||||||
|
|
||||||
|
pos_inv1.load_from_db()
|
||||||
|
self.assertRaises(frappe.ValidationError, pos_inv1.cancel)
|
||||||
|
|
||||||
|
si_doc = frappe.get_doc("Sales Invoice", pos_inv1.consolidated_invoice)
|
||||||
|
self.assertRaises(frappe.ValidationError, si_doc.cancel)
|
||||||
|
|
||||||
|
pcv_doc.load_from_db()
|
||||||
|
pcv_doc.cancel()
|
||||||
|
si_doc.load_from_db()
|
||||||
|
pos_inv1.load_from_db()
|
||||||
|
self.assertEqual(si_doc.docstatus, 2)
|
||||||
|
self.assertEqual(pos_inv1.status, 'Paid')
|
||||||
|
|
||||||
|
frappe.set_user("Administrator")
|
||||||
|
frappe.db.sql("delete from `tabPOS Profile`")
|
||||||
|
|
||||||
def init_user_and_profile(**args):
|
def init_user_and_profile(**args):
|
||||||
user = 'test@example.com'
|
user = 'test@example.com'
|
||||||
test_user = frappe.get_doc('User', user)
|
test_user = frappe.get_doc('User', user)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
|
|
||||||
{% include 'erpnext/selling/sales_common.js' %};
|
{% include 'erpnext/selling/sales_common.js' %};
|
||||||
|
frappe.provide("erpnext.accounts");
|
||||||
|
|
||||||
erpnext.selling.POSInvoiceController = erpnext.selling.SellingController.extend({
|
erpnext.selling.POSInvoiceController = erpnext.selling.SellingController.extend({
|
||||||
setup(doc) {
|
setup(doc) {
|
||||||
@ -9,12 +10,19 @@ erpnext.selling.POSInvoiceController = erpnext.selling.SellingController.extend(
|
|||||||
this._super(doc);
|
this._super(doc);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
company: function() {
|
||||||
|
erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
|
||||||
|
},
|
||||||
|
|
||||||
onload(doc) {
|
onload(doc) {
|
||||||
this._super();
|
this._super();
|
||||||
|
this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice Merge Log'];
|
||||||
if(doc.__islocal && doc.is_pos && frappe.get_route_str() !== 'point-of-sale') {
|
if(doc.__islocal && doc.is_pos && frappe.get_route_str() !== 'point-of-sale') {
|
||||||
this.frm.script_manager.trigger("is_pos");
|
this.frm.script_manager.trigger("is_pos");
|
||||||
this.frm.refresh_fields();
|
this.frm.refresh_fields();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh(doc) {
|
refresh(doc) {
|
||||||
@ -187,18 +195,43 @@ frappe.ui.form.on('POS Invoice', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
request_for_payment: function (frm) {
|
request_for_payment: function (frm) {
|
||||||
|
if (!frm.doc.contact_mobile) {
|
||||||
|
frappe.throw(__('Please enter mobile number first.'));
|
||||||
|
}
|
||||||
|
frm.dirty();
|
||||||
frm.save().then(() => {
|
frm.save().then(() => {
|
||||||
frappe.dom.freeze();
|
frappe.dom.freeze(__('Waiting for payment...'));
|
||||||
frappe.call({
|
frappe
|
||||||
method: 'create_payment_request',
|
.call({
|
||||||
doc: frm.doc,
|
method: 'create_payment_request',
|
||||||
})
|
doc: frm.doc
|
||||||
|
})
|
||||||
.fail(() => {
|
.fail(() => {
|
||||||
frappe.dom.unfreeze();
|
frappe.dom.unfreeze();
|
||||||
frappe.msgprint('Payment request failed');
|
frappe.msgprint(__('Payment request failed'));
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(({ message }) => {
|
||||||
frappe.msgprint('Payment request sent successfully');
|
const payment_request_name = message.name;
|
||||||
|
setTimeout(() => {
|
||||||
|
frappe.db.get_value('Payment Request', payment_request_name, ['status', 'grand_total']).then(({ message }) => {
|
||||||
|
if (message.status != 'Paid') {
|
||||||
|
frappe.dom.unfreeze();
|
||||||
|
frappe.msgprint({
|
||||||
|
message: __('Payment Request took too long to respond. Please try requesting for payment again.'),
|
||||||
|
title: __('Request Timeout')
|
||||||
|
});
|
||||||
|
} else if (frappe.dom.freeze_count != 0) {
|
||||||
|
frappe.dom.unfreeze();
|
||||||
|
cur_frm.reload_doc();
|
||||||
|
cur_pos.payment.events.submit_invoice();
|
||||||
|
|
||||||
|
frappe.show_alert({
|
||||||
|
message: __("Payment of {0} received successfully.", [format_currency(message.grand_total, frm.doc.currency, 0)]),
|
||||||
|
indicator: 'green'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 60000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,11 @@
|
|||||||
"customer",
|
"customer",
|
||||||
"customer_name",
|
"customer_name",
|
||||||
"tax_id",
|
"tax_id",
|
||||||
"is_pos",
|
|
||||||
"pos_profile",
|
"pos_profile",
|
||||||
"offline_pos_name",
|
|
||||||
"is_return",
|
|
||||||
"consolidated_invoice",
|
"consolidated_invoice",
|
||||||
|
"is_pos",
|
||||||
|
"is_return",
|
||||||
|
"update_billed_amount_in_sales_order",
|
||||||
"column_break1",
|
"column_break1",
|
||||||
"company",
|
"company",
|
||||||
"posting_date",
|
"posting_date",
|
||||||
@ -25,10 +25,7 @@
|
|||||||
"set_posting_time",
|
"set_posting_time",
|
||||||
"due_date",
|
"due_date",
|
||||||
"amended_from",
|
"amended_from",
|
||||||
"returns",
|
|
||||||
"return_against",
|
"return_against",
|
||||||
"column_break_21",
|
|
||||||
"update_billed_amount_in_sales_order",
|
|
||||||
"accounting_dimensions_section",
|
"accounting_dimensions_section",
|
||||||
"project",
|
"project",
|
||||||
"dimension_col_break",
|
"dimension_col_break",
|
||||||
@ -183,8 +180,7 @@
|
|||||||
"column_break_140",
|
"column_break_140",
|
||||||
"auto_repeat",
|
"auto_repeat",
|
||||||
"update_auto_repeat_reference",
|
"update_auto_repeat_reference",
|
||||||
"against_income_account",
|
"against_income_account"
|
||||||
"pos_total_qty"
|
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -265,14 +261,6 @@
|
|||||||
"options": "POS Profile",
|
"options": "POS Profile",
|
||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "offline_pos_name",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 1,
|
|
||||||
"label": "Offline POS Name",
|
|
||||||
"print_hide": 1,
|
|
||||||
"read_only": 1
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
"default": "0",
|
"default": "0",
|
||||||
@ -348,26 +336,16 @@
|
|||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"depends_on": "return_against",
|
|
||||||
"fieldname": "returns",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"label": "Returns"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"depends_on": "return_against",
|
"depends_on": "return_against",
|
||||||
"fieldname": "return_against",
|
"fieldname": "return_against",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Return Against POS Invoice",
|
"label": "Return Against",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "POS Invoice",
|
"options": "POS Invoice",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "column_break_21",
|
|
||||||
"fieldtype": "Column Break"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"depends_on": "eval: doc.is_return && doc.return_against",
|
"depends_on": "eval: doc.is_return && doc.return_against",
|
||||||
@ -587,19 +565,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "sec_warehouse",
|
"fieldname": "sec_warehouse",
|
||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Warehouse"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "update_stock",
|
"depends_on": "update_stock",
|
||||||
"fieldname": "set_warehouse",
|
"fieldname": "set_warehouse",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Set Source Warehouse",
|
"label": "Source Warehouse",
|
||||||
"options": "Warehouse",
|
"options": "Warehouse",
|
||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "items_section",
|
"fieldname": "items_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Items",
|
||||||
"oldfieldtype": "Section Break",
|
"oldfieldtype": "Section Break",
|
||||||
"options": "fa fa-shopping-cart"
|
"options": "fa fa-shopping-cart"
|
||||||
},
|
},
|
||||||
@ -1501,7 +1481,7 @@
|
|||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
"fieldname": "sales_team",
|
"fieldname": "sales_team",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Sales Team1",
|
"label": "Sales Team",
|
||||||
"oldfieldname": "sales_team",
|
"oldfieldname": "sales_team",
|
||||||
"oldfieldtype": "Table",
|
"oldfieldtype": "Table",
|
||||||
"options": "Sales Team",
|
"options": "Sales Team",
|
||||||
@ -1560,15 +1540,6 @@
|
|||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"report_hide": 1
|
"report_hide": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "pos_total_qty",
|
|
||||||
"fieldtype": "Float",
|
|
||||||
"hidden": 1,
|
|
||||||
"label": "Total Qty",
|
|
||||||
"print_hide": 1,
|
|
||||||
"print_hide_if_no_value": 1,
|
|
||||||
"read_only": 1
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
"fieldname": "consolidated_invoice",
|
"fieldname": "consolidated_invoice",
|
||||||
@ -1581,7 +1552,7 @@
|
|||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-30 13:56:51.056083",
|
"modified": "2021-02-01 15:03:33.800707",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "POS Invoice",
|
"name": "POS Invoice",
|
||||||
@ -1626,7 +1597,6 @@
|
|||||||
"role": "All"
|
"role": "All"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
|
||||||
"search_fields": "posting_date, due_date, customer, base_grand_total, outstanding_amount",
|
"search_fields": "posting_date, due_date, customer, base_grand_total, outstanding_amount",
|
||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
|
@ -6,10 +6,9 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.controllers.selling_controller import SellingController
|
|
||||||
from frappe.utils import cint, flt, add_months, today, date_diff, getdate, add_days, cstr, nowdate
|
|
||||||
from erpnext.accounts.utils import get_account_currency
|
from erpnext.accounts.utils import get_account_currency
|
||||||
from erpnext.accounts.party import get_party_account, get_due_date
|
from erpnext.accounts.party import get_party_account, get_due_date
|
||||||
|
from frappe.utils import cint, flt, getdate, nowdate, get_link_to_form
|
||||||
from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
|
from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
|
||||||
from erpnext.accounts.doctype.loyalty_program.loyalty_program import validate_loyalty_points
|
from erpnext.accounts.doctype.loyalty_program.loyalty_program import validate_loyalty_points
|
||||||
from erpnext.stock.doctype.serial_no.serial_no import get_pos_reserved_serial_nos, get_serial_nos
|
from erpnext.stock.doctype.serial_no.serial_no import get_pos_reserved_serial_nos, get_serial_nos
|
||||||
@ -59,6 +58,22 @@ class POSInvoice(SalesInvoice):
|
|||||||
self.check_phone_payments()
|
self.check_phone_payments()
|
||||||
self.set_status(update=True)
|
self.set_status(update=True)
|
||||||
|
|
||||||
|
def before_cancel(self):
|
||||||
|
if self.consolidated_invoice and frappe.db.get_value('Sales Invoice', self.consolidated_invoice, 'docstatus') == 1:
|
||||||
|
pos_closing_entry = frappe.get_all(
|
||||||
|
"POS Invoice Reference",
|
||||||
|
ignore_permissions=True,
|
||||||
|
filters={ 'pos_invoice': self.name },
|
||||||
|
pluck="parent",
|
||||||
|
limit=1
|
||||||
|
)
|
||||||
|
frappe.throw(
|
||||||
|
_('You need to cancel POS Closing Entry {} to be able to cancel this document.').format(
|
||||||
|
get_link_to_form("POS Closing Entry", pos_closing_entry[0])
|
||||||
|
),
|
||||||
|
title=_('Not Allowed')
|
||||||
|
)
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
# run on cancel method of selling controller
|
# run on cancel method of selling controller
|
||||||
super(SalesInvoice, self).on_cancel()
|
super(SalesInvoice, self).on_cancel()
|
||||||
@ -78,7 +93,7 @@ class POSInvoice(SalesInvoice):
|
|||||||
mode_of_payment=pay.mode_of_payment, status="Paid"),
|
mode_of_payment=pay.mode_of_payment, status="Paid"),
|
||||||
fieldname="grand_total")
|
fieldname="grand_total")
|
||||||
|
|
||||||
if pay.amount != paid_amt:
|
if paid_amt and pay.amount != paid_amt:
|
||||||
return frappe.throw(_("Payment related to {0} is not completed").format(pay.mode_of_payment))
|
return frappe.throw(_("Payment related to {0} is not completed").format(pay.mode_of_payment))
|
||||||
|
|
||||||
def validate_stock_availablility(self):
|
def validate_stock_availablility(self):
|
||||||
@ -164,10 +179,18 @@ class POSInvoice(SalesInvoice):
|
|||||||
if d.get("serial_no"):
|
if d.get("serial_no"):
|
||||||
serial_nos = get_serial_nos(d.serial_no)
|
serial_nos = get_serial_nos(d.serial_no)
|
||||||
for sr in serial_nos:
|
for sr in serial_nos:
|
||||||
serial_no_exists = frappe.db.exists("POS Invoice Item", {
|
serial_no_exists = frappe.db.sql("""
|
||||||
"parent": self.return_against,
|
SELECT name
|
||||||
"serial_no": ["like", d.get("serial_no")]
|
FROM `tabPOS Invoice Item`
|
||||||
})
|
WHERE
|
||||||
|
parent = %s
|
||||||
|
and (serial_no = %s
|
||||||
|
or serial_no like %s
|
||||||
|
or serial_no like %s
|
||||||
|
or serial_no like %s
|
||||||
|
)
|
||||||
|
""", (self.return_against, sr, sr+'\n%', '%\n'+sr, '%\n'+sr+'\n%'))
|
||||||
|
|
||||||
if not serial_no_exists:
|
if not serial_no_exists:
|
||||||
bold_return_against = frappe.bold(self.return_against)
|
bold_return_against = frappe.bold(self.return_against)
|
||||||
bold_serial_no = frappe.bold(sr)
|
bold_serial_no = frappe.bold(sr)
|
||||||
@ -267,6 +290,8 @@ class POSInvoice(SalesInvoice):
|
|||||||
from erpnext.stock.get_item_details import get_pos_profile_item_details, get_pos_profile
|
from erpnext.stock.get_item_details import get_pos_profile_item_details, get_pos_profile
|
||||||
if not self.pos_profile:
|
if not self.pos_profile:
|
||||||
pos_profile = get_pos_profile(self.company) or {}
|
pos_profile = get_pos_profile(self.company) or {}
|
||||||
|
if not pos_profile:
|
||||||
|
frappe.throw(_("No POS Profile found. Please create a New POS Profile first"))
|
||||||
self.pos_profile = pos_profile.get('name')
|
self.pos_profile = pos_profile.get('name')
|
||||||
|
|
||||||
profile = {}
|
profile = {}
|
||||||
@ -295,9 +320,14 @@ class POSInvoice(SalesInvoice):
|
|||||||
self.set(fieldname, profile.get(fieldname))
|
self.set(fieldname, profile.get(fieldname))
|
||||||
|
|
||||||
if self.customer:
|
if self.customer:
|
||||||
customer_price_list, customer_group = frappe.db.get_value("Customer", self.customer, ['default_price_list', 'customer_group'])
|
customer_price_list, customer_group, customer_currency = frappe.db.get_value(
|
||||||
|
"Customer", self.customer, ['default_price_list', 'customer_group', 'default_currency']
|
||||||
|
)
|
||||||
customer_group_price_list = frappe.db.get_value("Customer Group", customer_group, 'default_price_list')
|
customer_group_price_list = frappe.db.get_value("Customer Group", customer_group, 'default_price_list')
|
||||||
selling_price_list = customer_price_list or customer_group_price_list or profile.get('selling_price_list')
|
selling_price_list = customer_price_list or customer_group_price_list or profile.get('selling_price_list')
|
||||||
|
if customer_currency != profile.get('currency'):
|
||||||
|
self.set('currency', customer_currency)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
selling_price_list = profile.get('selling_price_list')
|
selling_price_list = profile.get('selling_price_list')
|
||||||
|
|
||||||
@ -362,22 +392,48 @@ class POSInvoice(SalesInvoice):
|
|||||||
if not self.contact_mobile:
|
if not self.contact_mobile:
|
||||||
frappe.throw(_("Please enter the phone number first"))
|
frappe.throw(_("Please enter the phone number first"))
|
||||||
|
|
||||||
payment_gateway = frappe.db.get_value("Payment Gateway Account", {
|
pay_req = self.get_existing_payment_request(pay)
|
||||||
"payment_account": pay.account,
|
if not pay_req:
|
||||||
})
|
pay_req = self.get_new_payment_request(pay)
|
||||||
record = {
|
pay_req.submit()
|
||||||
"payment_gateway": payment_gateway,
|
else:
|
||||||
"dt": "POS Invoice",
|
pay_req.request_phone_payment()
|
||||||
"dn": self.name,
|
|
||||||
"payment_request_type": "Inward",
|
|
||||||
"party_type": "Customer",
|
|
||||||
"party": self.customer,
|
|
||||||
"mode_of_payment": pay.mode_of_payment,
|
|
||||||
"recipient_id": self.contact_mobile,
|
|
||||||
"submit_doc": True
|
|
||||||
}
|
|
||||||
|
|
||||||
return make_payment_request(**record)
|
return pay_req
|
||||||
|
|
||||||
|
def get_new_payment_request(self, mop):
|
||||||
|
payment_gateway_account = frappe.db.get_value("Payment Gateway Account", {
|
||||||
|
"payment_account": mop.account,
|
||||||
|
}, ["name"])
|
||||||
|
|
||||||
|
args = {
|
||||||
|
"dt": "POS Invoice",
|
||||||
|
"dn": self.name,
|
||||||
|
"recipient_id": self.contact_mobile,
|
||||||
|
"mode_of_payment": mop.mode_of_payment,
|
||||||
|
"payment_gateway_account": payment_gateway_account,
|
||||||
|
"payment_request_type": "Inward",
|
||||||
|
"party_type": "Customer",
|
||||||
|
"party": self.customer,
|
||||||
|
"return_doc": True
|
||||||
|
}
|
||||||
|
return make_payment_request(**args)
|
||||||
|
|
||||||
|
def get_existing_payment_request(self, pay):
|
||||||
|
payment_gateway_account = frappe.db.get_value("Payment Gateway Account", {
|
||||||
|
"payment_account": pay.account,
|
||||||
|
}, ["name"])
|
||||||
|
|
||||||
|
args = {
|
||||||
|
'doctype': 'Payment Request',
|
||||||
|
'reference_doctype': 'POS Invoice',
|
||||||
|
'reference_name': self.name,
|
||||||
|
'payment_gateway_account': payment_gateway_account,
|
||||||
|
'email_to': self.contact_mobile
|
||||||
|
}
|
||||||
|
pr = frappe.db.exists(args)
|
||||||
|
if pr:
|
||||||
|
return frappe.get_doc('Payment Request', pr[0][0])
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_stock_availability(item_code, warehouse):
|
def get_stock_availability(item_code, warehouse):
|
||||||
|
@ -198,6 +198,65 @@ class TestPOSInvoice(unittest.TestCase):
|
|||||||
self.assertEqual(pos_return.get('payments')[0].amount, -500)
|
self.assertEqual(pos_return.get('payments')[0].amount, -500)
|
||||||
self.assertEqual(pos_return.get('payments')[1].amount, -500)
|
self.assertEqual(pos_return.get('payments')[1].amount, -500)
|
||||||
|
|
||||||
|
def test_pos_return_for_serialized_item(self):
|
||||||
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
|
||||||
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
|
|
||||||
|
se = make_serialized_item(company='_Test Company',
|
||||||
|
target_warehouse="Stores - _TC", cost_center='Main - _TC', expense_account='Cost of Goods Sold - _TC')
|
||||||
|
|
||||||
|
serial_nos = get_serial_nos(se.get("items")[0].serial_no)
|
||||||
|
|
||||||
|
pos = create_pos_invoice(company='_Test Company', debit_to='Debtors - _TC',
|
||||||
|
account_for_change_amount='Cash - _TC', warehouse='Stores - _TC', income_account='Sales - _TC',
|
||||||
|
expense_account='Cost of Goods Sold - _TC', cost_center='Main - _TC',
|
||||||
|
item=se.get("items")[0].item_code, rate=1000, do_not_save=1)
|
||||||
|
|
||||||
|
pos.get("items")[0].serial_no = serial_nos[0]
|
||||||
|
pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 1000, 'default': 1})
|
||||||
|
|
||||||
|
pos.insert()
|
||||||
|
pos.submit()
|
||||||
|
|
||||||
|
pos_return = make_sales_return(pos.name)
|
||||||
|
|
||||||
|
pos_return.insert()
|
||||||
|
pos_return.submit()
|
||||||
|
self.assertEqual(pos_return.get('items')[0].serial_no, serial_nos[0])
|
||||||
|
|
||||||
|
def test_partial_pos_returns(self):
|
||||||
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
|
||||||
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
|
|
||||||
|
se = make_serialized_item(company='_Test Company',
|
||||||
|
target_warehouse="Stores - _TC", cost_center='Main - _TC', expense_account='Cost of Goods Sold - _TC')
|
||||||
|
|
||||||
|
serial_nos = get_serial_nos(se.get("items")[0].serial_no)
|
||||||
|
|
||||||
|
pos = create_pos_invoice(company='_Test Company', debit_to='Debtors - _TC',
|
||||||
|
account_for_change_amount='Cash - _TC', warehouse='Stores - _TC', income_account='Sales - _TC',
|
||||||
|
expense_account='Cost of Goods Sold - _TC', cost_center='Main - _TC',
|
||||||
|
item=se.get("items")[0].item_code, qty=2, rate=1000, do_not_save=1)
|
||||||
|
|
||||||
|
pos.get("items")[0].serial_no = serial_nos[0] + "\n" + serial_nos[1]
|
||||||
|
pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 1000, 'default': 1})
|
||||||
|
|
||||||
|
pos.insert()
|
||||||
|
pos.submit()
|
||||||
|
|
||||||
|
pos_return1 = make_sales_return(pos.name)
|
||||||
|
|
||||||
|
# partial return 1
|
||||||
|
pos_return1.get('items')[0].qty = -1
|
||||||
|
pos_return1.get('items')[0].serial_no = serial_nos[0]
|
||||||
|
pos_return1.insert()
|
||||||
|
pos_return1.submit()
|
||||||
|
|
||||||
|
# partial return 2
|
||||||
|
pos_return2 = make_sales_return(pos.name)
|
||||||
|
self.assertEqual(pos_return2.get('items')[0].qty, -1)
|
||||||
|
self.assertEqual(pos_return2.get('items')[0].serial_no, serial_nos[1])
|
||||||
|
|
||||||
def test_pos_change_amount(self):
|
def test_pos_change_amount(self):
|
||||||
pos = create_pos_invoice(company= "_Test Company", debit_to="Debtors - _TC",
|
pos = create_pos_invoice(company= "_Test Company", debit_to="Debtors - _TC",
|
||||||
income_account = "Sales - _TC", expense_account = "Cost of Goods Sold - _TC", rate=105,
|
income_account = "Sales - _TC", expense_account = "Cost of Goods Sold - _TC", rate=105,
|
||||||
@ -290,7 +349,7 @@ class TestPOSInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
def test_merging_into_sales_invoice_with_discount(self):
|
def test_merging_into_sales_invoice_with_discount(self):
|
||||||
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
|
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
|
||||||
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import merge_pos_invoices
|
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import consolidate_pos_invoices
|
||||||
|
|
||||||
frappe.db.sql("delete from `tabPOS Invoice`")
|
frappe.db.sql("delete from `tabPOS Invoice`")
|
||||||
test_user, pos_profile = init_user_and_profile()
|
test_user, pos_profile = init_user_and_profile()
|
||||||
@ -306,7 +365,7 @@ class TestPOSInvoice(unittest.TestCase):
|
|||||||
})
|
})
|
||||||
pos_inv2.submit()
|
pos_inv2.submit()
|
||||||
|
|
||||||
merge_pos_invoices()
|
consolidate_pos_invoices()
|
||||||
|
|
||||||
pos_inv.load_from_db()
|
pos_inv.load_from_db()
|
||||||
rounded_total = frappe.db.get_value("Sales Invoice", pos_inv.consolidated_invoice, "rounded_total")
|
rounded_total = frappe.db.get_value("Sales Invoice", pos_inv.consolidated_invoice, "rounded_total")
|
||||||
@ -315,7 +374,7 @@ class TestPOSInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
def test_merging_into_sales_invoice_with_discount_and_inclusive_tax(self):
|
def test_merging_into_sales_invoice_with_discount_and_inclusive_tax(self):
|
||||||
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
|
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
|
||||||
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import merge_pos_invoices
|
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import consolidate_pos_invoices
|
||||||
|
|
||||||
frappe.db.sql("delete from `tabPOS Invoice`")
|
frappe.db.sql("delete from `tabPOS Invoice`")
|
||||||
test_user, pos_profile = init_user_and_profile()
|
test_user, pos_profile = init_user_and_profile()
|
||||||
@ -348,7 +407,7 @@ class TestPOSInvoice(unittest.TestCase):
|
|||||||
})
|
})
|
||||||
pos_inv2.submit()
|
pos_inv2.submit()
|
||||||
|
|
||||||
merge_pos_invoices()
|
consolidate_pos_invoices()
|
||||||
|
|
||||||
pos_inv.load_from_db()
|
pos_inv.load_from_db()
|
||||||
rounded_total = frappe.db.get_value("Sales Invoice", pos_inv.consolidated_invoice, "rounded_total")
|
rounded_total = frappe.db.get_value("Sales Invoice", pos_inv.consolidated_invoice, "rounded_total")
|
||||||
@ -357,7 +416,7 @@ class TestPOSInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
def test_merging_with_validate_selling_price(self):
|
def test_merging_with_validate_selling_price(self):
|
||||||
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
|
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
|
||||||
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import merge_pos_invoices
|
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import consolidate_pos_invoices
|
||||||
|
|
||||||
if not frappe.db.get_single_value("Selling Settings", "validate_selling_price"):
|
if not frappe.db.get_single_value("Selling Settings", "validate_selling_price"):
|
||||||
frappe.db.set_value("Selling Settings", "Selling Settings", "validate_selling_price", 1)
|
frappe.db.set_value("Selling Settings", "Selling Settings", "validate_selling_price", 1)
|
||||||
@ -393,7 +452,7 @@ class TestPOSInvoice(unittest.TestCase):
|
|||||||
})
|
})
|
||||||
pos_inv2.submit()
|
pos_inv2.submit()
|
||||||
|
|
||||||
merge_pos_invoices()
|
consolidate_pos_invoices()
|
||||||
|
|
||||||
pos_inv2.load_from_db()
|
pos_inv2.load_from_db()
|
||||||
rounded_total = frappe.db.get_value("Sales Invoice", pos_inv2.consolidated_invoice, "rounded_total")
|
rounded_total = frappe.db.get_value("Sales Invoice", pos_inv2.consolidated_invoice, "rounded_total")
|
||||||
|
@ -87,6 +87,7 @@
|
|||||||
"edit_references",
|
"edit_references",
|
||||||
"sales_order",
|
"sales_order",
|
||||||
"so_detail",
|
"so_detail",
|
||||||
|
"pos_invoice_item",
|
||||||
"column_break_74",
|
"column_break_74",
|
||||||
"delivery_note",
|
"delivery_note",
|
||||||
"dn_detail",
|
"dn_detail",
|
||||||
@ -790,11 +791,20 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Project",
|
"label": "Project",
|
||||||
"options": "Project"
|
"options": "Project"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "pos_invoice_item",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"ignore_user_permissions": 1,
|
||||||
|
"label": "POS Invoice Item",
|
||||||
|
"no_copy": 1,
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-07-22 13:40:34.418346",
|
"modified": "2021-01-04 17:34:49.924531",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "POS Invoice Item",
|
"name": "POS Invoice Item",
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
"field_order": [
|
"field_order": [
|
||||||
"posting_date",
|
"posting_date",
|
||||||
"customer",
|
"customer",
|
||||||
|
"column_break_3",
|
||||||
|
"pos_closing_entry",
|
||||||
"section_break_3",
|
"section_break_3",
|
||||||
"pos_invoices",
|
"pos_invoices",
|
||||||
"references_section",
|
"references_section",
|
||||||
@ -76,11 +78,22 @@
|
|||||||
"label": "Consolidated Credit Note",
|
"label": "Consolidated Credit Note",
|
||||||
"options": "Sales Invoice",
|
"options": "Sales Invoice",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_3",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "pos_closing_entry",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "POS Closing Entry",
|
||||||
|
"options": "POS Closing Entry"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-05-29 15:08:41.317100",
|
"modified": "2020-12-01 11:53:57.267579",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "POS Invoice Merge Log",
|
"name": "POS Invoice Merge Log",
|
||||||
|
@ -5,10 +5,13 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import cint, flt, add_months, today, date_diff, getdate, add_days, cstr, nowdate
|
|
||||||
from frappe.model.document import Document
|
|
||||||
from frappe.model.mapper import map_doc
|
|
||||||
from frappe.model import default_fields
|
from frappe.model import default_fields
|
||||||
|
from frappe.model.document import Document
|
||||||
|
from frappe.utils import flt, getdate, nowdate
|
||||||
|
from frappe.utils.background_jobs import enqueue
|
||||||
|
from frappe.model.mapper import map_doc, map_child_doc
|
||||||
|
from frappe.utils.scheduler import is_scheduler_inactive
|
||||||
|
from frappe.core.page.background_jobs.background_jobs import get_info
|
||||||
|
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
@ -61,7 +64,13 @@ class POSInvoiceMergeLog(Document):
|
|||||||
|
|
||||||
self.save() # save consolidated_sales_invoice & consolidated_credit_note ref in merge log
|
self.save() # save consolidated_sales_invoice & consolidated_credit_note ref in merge log
|
||||||
|
|
||||||
self.update_pos_invoices(sales_invoice, credit_note)
|
self.update_pos_invoices(pos_invoice_docs, sales_invoice, credit_note)
|
||||||
|
|
||||||
|
def on_cancel(self):
|
||||||
|
pos_invoice_docs = [frappe.get_doc("POS Invoice", d.pos_invoice) for d in self.pos_invoices]
|
||||||
|
|
||||||
|
self.update_pos_invoices(pos_invoice_docs)
|
||||||
|
self.cancel_linked_invoices()
|
||||||
|
|
||||||
def process_merging_into_sales_invoice(self, data):
|
def process_merging_into_sales_invoice(self, data):
|
||||||
sales_invoice = self.get_new_sales_invoice()
|
sales_invoice = self.get_new_sales_invoice()
|
||||||
@ -83,7 +92,7 @@ class POSInvoiceMergeLog(Document):
|
|||||||
|
|
||||||
credit_note.is_consolidated = 1
|
credit_note.is_consolidated = 1
|
||||||
# TODO: return could be against multiple sales invoice which could also have been consolidated?
|
# TODO: return could be against multiple sales invoice which could also have been consolidated?
|
||||||
credit_note.return_against = self.consolidated_invoice
|
# credit_note.return_against = self.consolidated_invoice
|
||||||
credit_note.save()
|
credit_note.save()
|
||||||
credit_note.submit()
|
credit_note.submit()
|
||||||
self.consolidated_credit_note = credit_note.name
|
self.consolidated_credit_note = credit_note.name
|
||||||
@ -109,9 +118,12 @@ class POSInvoiceMergeLog(Document):
|
|||||||
i.uom == item.uom and i.net_rate == item.net_rate):
|
i.uom == item.uom and i.net_rate == item.net_rate):
|
||||||
found = True
|
found = True
|
||||||
i.qty = i.qty + item.qty
|
i.qty = i.qty + item.qty
|
||||||
|
|
||||||
if not found:
|
if not found:
|
||||||
item.rate = item.net_rate
|
item.rate = item.net_rate
|
||||||
items.append(item)
|
item.price_list_rate = 0
|
||||||
|
si_item = map_child_doc(item, invoice, {"doctype": "Sales Invoice Item"})
|
||||||
|
items.append(si_item)
|
||||||
|
|
||||||
for tax in doc.get('taxes'):
|
for tax in doc.get('taxes'):
|
||||||
found = False
|
found = False
|
||||||
@ -147,6 +159,8 @@ class POSInvoiceMergeLog(Document):
|
|||||||
invoice.set('taxes', taxes)
|
invoice.set('taxes', taxes)
|
||||||
invoice.additional_discount_percentage = 0
|
invoice.additional_discount_percentage = 0
|
||||||
invoice.discount_amount = 0.0
|
invoice.discount_amount = 0.0
|
||||||
|
invoice.taxes_and_charges = None
|
||||||
|
invoice.ignore_pricing_rule = 1
|
||||||
|
|
||||||
return invoice
|
return invoice
|
||||||
|
|
||||||
@ -159,17 +173,21 @@ class POSInvoiceMergeLog(Document):
|
|||||||
|
|
||||||
return sales_invoice
|
return sales_invoice
|
||||||
|
|
||||||
def update_pos_invoices(self, sales_invoice, credit_note):
|
def update_pos_invoices(self, invoice_docs, sales_invoice='', credit_note=''):
|
||||||
for d in self.pos_invoices:
|
for doc in invoice_docs:
|
||||||
doc = frappe.get_doc('POS Invoice', d.pos_invoice)
|
doc.load_from_db()
|
||||||
if not doc.is_return:
|
doc.update({ 'consolidated_invoice': None if self.docstatus==2 else (credit_note if doc.is_return else sales_invoice) })
|
||||||
doc.update({'consolidated_invoice': sales_invoice})
|
|
||||||
else:
|
|
||||||
doc.update({'consolidated_invoice': credit_note})
|
|
||||||
doc.set_status(update=True)
|
doc.set_status(update=True)
|
||||||
doc.save()
|
doc.save()
|
||||||
|
|
||||||
def get_all_invoices():
|
def cancel_linked_invoices(self):
|
||||||
|
for si_name in [self.consolidated_invoice, self.consolidated_credit_note]:
|
||||||
|
if not si_name: continue
|
||||||
|
si = frappe.get_doc('Sales Invoice', si_name)
|
||||||
|
si.flags.ignore_validate = True
|
||||||
|
si.cancel()
|
||||||
|
|
||||||
|
def get_all_unconsolidated_invoices():
|
||||||
filters = {
|
filters = {
|
||||||
'consolidated_invoice': [ 'in', [ '', None ]],
|
'consolidated_invoice': [ 'in', [ '', None ]],
|
||||||
'status': ['not in', ['Consolidated']],
|
'status': ['not in', ['Consolidated']],
|
||||||
@ -180,7 +198,7 @@ def get_all_invoices():
|
|||||||
|
|
||||||
return pos_invoices
|
return pos_invoices
|
||||||
|
|
||||||
def get_invoices_customer_map(pos_invoices):
|
def get_invoice_customer_map(pos_invoices):
|
||||||
# pos_invoice_customer_map = { 'Customer 1': [{}, {}, {}], 'Custoemr 2' : [{}] }
|
# pos_invoice_customer_map = { 'Customer 1': [{}, {}, {}], 'Custoemr 2' : [{}] }
|
||||||
pos_invoice_customer_map = {}
|
pos_invoice_customer_map = {}
|
||||||
for invoice in pos_invoices:
|
for invoice in pos_invoices:
|
||||||
@ -190,20 +208,82 @@ def get_invoices_customer_map(pos_invoices):
|
|||||||
|
|
||||||
return pos_invoice_customer_map
|
return pos_invoice_customer_map
|
||||||
|
|
||||||
def merge_pos_invoices(pos_invoices=[]):
|
def consolidate_pos_invoices(pos_invoices=[], closing_entry={}):
|
||||||
if not pos_invoices:
|
invoices = pos_invoices or closing_entry.get('pos_transactions') or get_all_unconsolidated_invoices()
|
||||||
pos_invoices = get_all_invoices()
|
invoice_by_customer = get_invoice_customer_map(invoices)
|
||||||
|
|
||||||
pos_invoice_map = get_invoices_customer_map(pos_invoices)
|
if len(invoices) >= 5 and closing_entry:
|
||||||
create_merge_logs(pos_invoice_map)
|
closing_entry.set_status(update=True, status='Queued')
|
||||||
|
enqueue_job(create_merge_logs, invoice_by_customer, closing_entry)
|
||||||
|
else:
|
||||||
|
create_merge_logs(invoice_by_customer, closing_entry)
|
||||||
|
|
||||||
def create_merge_logs(pos_invoice_customer_map):
|
def unconsolidate_pos_invoices(closing_entry):
|
||||||
for customer, invoices in iteritems(pos_invoice_customer_map):
|
merge_logs = frappe.get_all(
|
||||||
|
'POS Invoice Merge Log',
|
||||||
|
filters={ 'pos_closing_entry': closing_entry.name },
|
||||||
|
pluck='name'
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(merge_logs) >= 5:
|
||||||
|
closing_entry.set_status(update=True, status='Queued')
|
||||||
|
enqueue_job(cancel_merge_logs, merge_logs, closing_entry)
|
||||||
|
else:
|
||||||
|
cancel_merge_logs(merge_logs, closing_entry)
|
||||||
|
|
||||||
|
def create_merge_logs(invoice_by_customer, closing_entry={}):
|
||||||
|
for customer, invoices in iteritems(invoice_by_customer):
|
||||||
merge_log = frappe.new_doc('POS Invoice Merge Log')
|
merge_log = frappe.new_doc('POS Invoice Merge Log')
|
||||||
merge_log.posting_date = getdate(nowdate())
|
merge_log.posting_date = getdate(nowdate())
|
||||||
merge_log.customer = customer
|
merge_log.customer = customer
|
||||||
|
merge_log.pos_closing_entry = closing_entry.get('name', None)
|
||||||
|
|
||||||
merge_log.set('pos_invoices', invoices)
|
merge_log.set('pos_invoices', invoices)
|
||||||
merge_log.save(ignore_permissions=True)
|
merge_log.save(ignore_permissions=True)
|
||||||
merge_log.submit()
|
merge_log.submit()
|
||||||
|
|
||||||
|
if closing_entry:
|
||||||
|
closing_entry.set_status(update=True, status='Submitted')
|
||||||
|
closing_entry.update_opening_entry()
|
||||||
|
|
||||||
|
def cancel_merge_logs(merge_logs, closing_entry={}):
|
||||||
|
for log in merge_logs:
|
||||||
|
merge_log = frappe.get_doc('POS Invoice Merge Log', log)
|
||||||
|
merge_log.flags.ignore_permissions = True
|
||||||
|
merge_log.cancel()
|
||||||
|
|
||||||
|
if closing_entry:
|
||||||
|
closing_entry.set_status(update=True, status='Cancelled')
|
||||||
|
closing_entry.update_opening_entry(for_cancel=True)
|
||||||
|
|
||||||
|
def enqueue_job(job, invoice_by_customer, closing_entry):
|
||||||
|
check_scheduler_status()
|
||||||
|
|
||||||
|
job_name = closing_entry.get("name")
|
||||||
|
if not job_already_enqueued(job_name):
|
||||||
|
enqueue(
|
||||||
|
job,
|
||||||
|
queue="long",
|
||||||
|
timeout=10000,
|
||||||
|
event="processing_merge_logs",
|
||||||
|
job_name=job_name,
|
||||||
|
closing_entry=closing_entry,
|
||||||
|
invoice_by_customer=invoice_by_customer,
|
||||||
|
now=frappe.conf.developer_mode or frappe.flags.in_test
|
||||||
|
)
|
||||||
|
|
||||||
|
if job == create_merge_logs:
|
||||||
|
msg = _('POS Invoices will be consolidated in a background process')
|
||||||
|
else:
|
||||||
|
msg = _('POS Invoices will be unconsolidated in a background process')
|
||||||
|
|
||||||
|
frappe.msgprint(msg, alert=1)
|
||||||
|
|
||||||
|
def check_scheduler_status():
|
||||||
|
if is_scheduler_inactive() and not frappe.flags.in_test:
|
||||||
|
frappe.throw(_("Scheduler is inactive. Cannot enqueue job."), title=_("Scheduler Inactive"))
|
||||||
|
|
||||||
|
def job_already_enqueued(job_name):
|
||||||
|
enqueued_jobs = [d.get("job_name") for d in get_info()]
|
||||||
|
if job_name in enqueued_jobs:
|
||||||
|
return True
|
@ -7,7 +7,7 @@ import frappe
|
|||||||
import unittest
|
import unittest
|
||||||
from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice
|
from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice
|
||||||
from erpnext.accounts.doctype.pos_invoice.pos_invoice import make_sales_return
|
from erpnext.accounts.doctype.pos_invoice.pos_invoice import make_sales_return
|
||||||
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import merge_pos_invoices
|
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import consolidate_pos_invoices
|
||||||
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
|
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
|
||||||
|
|
||||||
class TestPOSInvoiceMergeLog(unittest.TestCase):
|
class TestPOSInvoiceMergeLog(unittest.TestCase):
|
||||||
@ -34,7 +34,7 @@ class TestPOSInvoiceMergeLog(unittest.TestCase):
|
|||||||
})
|
})
|
||||||
pos_inv3.submit()
|
pos_inv3.submit()
|
||||||
|
|
||||||
merge_pos_invoices()
|
consolidate_pos_invoices()
|
||||||
|
|
||||||
pos_inv.load_from_db()
|
pos_inv.load_from_db()
|
||||||
self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv.consolidated_invoice))
|
self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv.consolidated_invoice))
|
||||||
@ -79,7 +79,7 @@ class TestPOSInvoiceMergeLog(unittest.TestCase):
|
|||||||
pos_inv_cn.paid_amount = -300
|
pos_inv_cn.paid_amount = -300
|
||||||
pos_inv_cn.submit()
|
pos_inv_cn.submit()
|
||||||
|
|
||||||
merge_pos_invoices()
|
consolidate_pos_invoices()
|
||||||
|
|
||||||
pos_inv.load_from_db()
|
pos_inv.load_from_db()
|
||||||
self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv.consolidated_invoice))
|
self.assertTrue(frappe.db.exists("Sales Invoice", pos_inv.consolidated_invoice))
|
||||||
|
@ -6,7 +6,6 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import cint, get_link_to_form
|
from frappe.utils import cint, get_link_to_form
|
||||||
from frappe.model.document import Document
|
|
||||||
from erpnext.controllers.status_updater import StatusUpdater
|
from erpnext.controllers.status_updater import StatusUpdater
|
||||||
|
|
||||||
class POSOpeningEntry(StatusUpdater):
|
class POSOpeningEntry(StatusUpdater):
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
frappe.listview_settings['POS Opening Entry'] = {
|
frappe.listview_settings['POS Opening Entry'] = {
|
||||||
get_indicator: function(doc) {
|
get_indicator: function(doc) {
|
||||||
var status_color = {
|
var status_color = {
|
||||||
"Draft": "grey",
|
"Draft": "red",
|
||||||
"Open": "orange",
|
"Open": "orange",
|
||||||
"Closed": "green",
|
"Closed": "green",
|
||||||
"Cancelled": "red"
|
"Cancelled": "red"
|
||||||
|
@ -57,6 +57,8 @@ frappe.ui.form.on('POS Profile', {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
@ -67,6 +69,7 @@ frappe.ui.form.on('POS Profile', {
|
|||||||
|
|
||||||
company: function(frm) {
|
company: function(frm) {
|
||||||
frm.trigger("toggle_display_account_head");
|
frm.trigger("toggle_display_account_head");
|
||||||
|
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
|
||||||
},
|
},
|
||||||
|
|
||||||
toggle_display_account_head: function(frm) {
|
toggle_display_account_head: function(frm) {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user