diff --git a/.travis.yml b/.travis.yml
index 213445b806e..77d427e5a50 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,5 @@
-dist: trusty
-
language: python
+dist: trusty
git:
depth: 1
@@ -14,21 +13,10 @@ addons:
jobs:
include:
- - name: "Python 2.7 Server Side Test"
- python: 2.7
- script: bench --site test_site run-tests --app erpnext --coverage
-
- name: "Python 3.6 Server Side Test"
python: 3.6
script: bench --site test_site run-tests --app erpnext --coverage
- - name: "Python 2.7 Patch Test"
- python: 2.7
- before_script:
- - wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
- - bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz
- script: bench --site test_site migrate
-
- name: "Python 3.6 Patch Test"
python: 3.6
before_script:
@@ -40,8 +28,7 @@ install:
- cd ~
- nvm install 10
- - git clone https://github.com/frappe/bench --depth 1
- - pip install -e ./bench
+ - pip install frappe-bench
- git clone https://github.com/frappe/frappe --branch $TRAVIS_BRANCH --depth 1
- bench init --skip-assets --frappe-path ~/frappe --python $(which python) frappe-bench
diff --git a/erpnext/accounts/accounts b/erpnext/accounts/accounts
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
index 5decccb4869..39bf4b053a7 100644
--- a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
+++ b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
@@ -14,7 +14,7 @@ from frappe.utils.nestedset import get_descendants_of
@frappe.whitelist()
@cache_source
def get(chart_name = None, chart = None, no_cache = None, filters = None, from_date = None,
- to_date = None, timespan = None, time_interval = None):
+ to_date = None, timespan = None, time_interval = None, heatmap_year = None):
if chart_name:
chart = frappe.get_doc('Dashboard Chart', chart_name)
else:
diff --git a/erpnext/accounts/dashboard_fixtures.py b/erpnext/accounts/dashboard_fixtures.py
index cdd166134f9..214e467b5c0 100644
--- a/erpnext/accounts/dashboard_fixtures.py
+++ b/erpnext/accounts/dashboard_fixtures.py
@@ -1,127 +1,264 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
-from erpnext import get_default_company
import frappe
import json
+from frappe.utils import nowdate, add_months, get_date_str
+from frappe import _
+from erpnext.accounts.utils import get_fiscal_year, get_account_name
+def get_company_for_dashboards():
+ company = frappe.defaults.get_defaults().company
+ if company:
+ return company
+ else:
+ company_list = frappe.get_list("Company")
+ if company_list:
+ return company_list[0].name
+ return None
def get_data():
- data = frappe._dict({
- "dashboards": [],
- "charts": []
+ return frappe._dict({
+ "dashboards": get_dashboards(),
+ "charts": get_charts(),
+ "number_cards": get_number_cards()
})
- company = get_company_for_dashboards()
- if company:
- company_doc = frappe.get_doc("Company", company)
- data.dashboards = get_dashboards()
- data.charts = get_charts(company_doc)
- return data
def get_dashboards():
return [{
- "name": "Accounts",
- "dashboard_name": "Accounts",
+ "name": "Accounts Dashboard",
+ "dashboard_name": "Accounts Dashboard",
+ "doctype": "Dashboard",
"charts": [
- { "chart": "Outgoing Bills (Sales Invoice)" },
- { "chart": "Incoming Bills (Purchase Invoice)" },
- { "chart": "Bank Balance" },
- { "chart": "Income" },
- { "chart": "Expenses" }
+ { "chart": "Profit and Loss" , "width": "Full"},
+ { "chart": "Incoming Bills (Purchase Invoice)", "width": "Half"},
+ { "chart": "Outgoing Bills (Sales Invoice)", "width": "Half"},
+ { "chart": "Accounts Receivable Ageing", "width": "Half"},
+ { "chart": "Accounts Payable Ageing", "width": "Half"},
+ { "chart": "Budget Variance", "width": "Full"},
+ { "chart": "Bank Balance", "width": "Full"}
+ ],
+ "cards": [
+ {"card": "Total Outgoing Bills"},
+ {"card": "Total Incoming Bills"},
+ {"card": "Total Incoming Payment"},
+ {"card": "Total Outgoing Payment"}
]
}]
-def get_charts(company):
- income_account = company.default_income_account or get_account("Income Account", company.name)
- expense_account = company.default_expense_account or get_account("Expense Account", company.name)
- bank_account = company.default_bank_account or get_account("Bank", company.name)
+def get_charts():
+ company = frappe.get_doc("Company", get_company_for_dashboards())
+ bank_account = company.default_bank_account or get_account_name("Bank", company=company.name)
+ fiscal_year = get_fiscal_year(date=nowdate())
+ default_cost_center = company.cost_center
return [
{
- "doctype": "Dashboard Chart",
- "time_interval": "Quarterly",
- "name": "Income",
- "chart_name": "Income",
- "timespan": "Last Year",
- "color": None,
- "filters_json": json.dumps({"company": company.name, "account": income_account}),
- "source": "Account Balance Timeline",
- "chart_type": "Custom",
- "timeseries": 1,
+ "doctype": "Dashboard Charts",
+ "name": "Profit and Loss",
"owner": "Administrator",
- "type": "Line"
- },
- {
- "doctype": "Dashboard Chart",
- "time_interval": "Quarterly",
- "name": "Expenses",
- "chart_name": "Expenses",
- "timespan": "Last Year",
- "color": None,
- "filters_json": json.dumps({"company": company.name, "account": expense_account}),
- "source": "Account Balance Timeline",
- "chart_type": "Custom",
- "timeseries": 1,
- "owner": "Administrator",
- "type": "Line"
- },
- {
- "doctype": "Dashboard Chart",
- "time_interval": "Quarterly",
- "name": "Bank Balance",
- "chart_name": "Bank Balance",
- "timespan": "Last Year",
- "color": "#ffb868",
- "filters_json": json.dumps({"company": company.name, "account": bank_account}),
- "source": "Account Balance Timeline",
- "chart_type": "Custom",
- "timeseries": 1,
- "owner": "Administrator",
- "type": "Line"
+ "report_name": "Profit and Loss Statement",
+ "filters_json": json.dumps({
+ "company": company.name,
+ "filter_based_on": "Date Range",
+ "period_start_date": get_date_str(fiscal_year[1]),
+ "period_end_date": get_date_str(fiscal_year[2]),
+ "periodicity": "Monthly",
+ "include_default_book_entries": 1
+ }),
+ "type": "Bar",
+ 'timeseries': 0,
+ "chart_type": "Report",
+ "chart_name": _("Profit and Loss"),
+ "is_custom": 1,
+ "is_public": 1
},
{
"doctype": "Dashboard Chart",
"time_interval": "Monthly",
"name": "Incoming Bills (Purchase Invoice)",
- "chart_name": "Incoming Bills (Purchase Invoice)",
+ "chart_name": _("Incoming Bills (Purchase Invoice)"),
"timespan": "Last Year",
"color": "#a83333",
- "value_based_on": "base_grand_total",
- "filters_json": json.dumps({}),
+ "value_based_on": "base_net_total",
+ "filters_json": json.dumps({"docstatus": 1}),
"chart_type": "Sum",
"timeseries": 1,
"based_on": "posting_date",
"owner": "Administrator",
"document_type": "Purchase Invoice",
- "type": "Bar"
+ "type": "Bar",
+ "width": "Half",
+ "is_public": 1
},
{
"doctype": "Dashboard Chart",
- "time_interval": "Monthly",
"name": "Outgoing Bills (Sales Invoice)",
- "chart_name": "Outgoing Bills (Sales Invoice)",
+ "time_interval": "Monthly",
+ "chart_name": _("Outgoing Bills (Sales Invoice)"),
"timespan": "Last Year",
"color": "#7b933d",
- "value_based_on": "base_grand_total",
- "filters_json": json.dumps({}),
+ "value_based_on": "base_net_total",
+ "filters_json": json.dumps({"docstatus": 1}),
"chart_type": "Sum",
"timeseries": 1,
"based_on": "posting_date",
"owner": "Administrator",
"document_type": "Sales Invoice",
- "type": "Bar"
- }
+ "type": "Bar",
+ "width": "Half",
+ "is_public": 1
+ },
+ {
+ "doctype": "Dashboard Charts",
+ "name": "Accounts Receivable Ageing",
+ "owner": "Administrator",
+ "report_name": "Accounts Receivable",
+ "filters_json": json.dumps({
+ "company": company.name,
+ "report_date": nowdate(),
+ "ageing_based_on": "Due Date",
+ "range1": 30,
+ "range2": 60,
+ "range3": 90,
+ "range4": 120
+ }),
+ "type": "Donut",
+ 'timeseries': 0,
+ "chart_type": "Report",
+ "chart_name": _("Accounts Receivable Ageing"),
+ "is_custom": 1,
+ "is_public": 1
+ },
+ {
+ "doctype": "Dashboard Charts",
+ "name": "Accounts Payable Ageing",
+ "owner": "Administrator",
+ "report_name": "Accounts Payable",
+ "filters_json": json.dumps({
+ "company": company.name,
+ "report_date": nowdate(),
+ "ageing_based_on": "Due Date",
+ "range1": 30,
+ "range2": 60,
+ "range3": 90,
+ "range4": 120
+ }),
+ "type": "Donut",
+ 'timeseries': 0,
+ "chart_type": "Report",
+ "chart_name": _("Accounts Payable Ageing"),
+ "is_custom": 1,
+ "is_public": 1
+ },
+ {
+ "doctype": "Dashboard Charts",
+ "name": "Budget Variance",
+ "owner": "Administrator",
+ "report_name": "Budget Variance Report",
+ "filters_json": json.dumps({
+ "company": company.name,
+ "from_fiscal_year": fiscal_year[0],
+ "to_fiscal_year": fiscal_year[0],
+ "period": "Monthly",
+ "budget_against": "Cost Center"
+ }),
+ "type": "Bar",
+ "timeseries": 0,
+ "chart_type": "Report",
+ "chart_name": _("Budget Variance"),
+ "is_custom": 1,
+ "is_public": 1
+ },
+ {
+ "doctype": "Dashboard Charts",
+ "name": "Bank Balance",
+ "time_interval": "Quarterly",
+ "chart_name": "Bank Balance",
+ "timespan": "Last Year",
+ "filters_json": json.dumps({
+ "company": company.name,
+ "account": bank_account
+ }),
+ "source": "Account Balance Timeline",
+ "chart_type": "Custom",
+ "timeseries": 1,
+ "owner": "Administrator",
+ "type": "Line",
+ "width": "Half",
+ "is_public": 1
+ },
]
-def get_account(account_type, company):
- accounts = frappe.get_list("Account", filters={"account_type": account_type, "company": company})
- if accounts:
- return accounts[0].name
-
-def get_company_for_dashboards():
- company = get_default_company()
- if not company:
- company_list = frappe.get_list("Company")
- if company_list:
- company = company_list[0].name
- return company
+def get_number_cards():
+ fiscal_year = get_fiscal_year(date=nowdate())
+ year_start_date = get_date_str(fiscal_year[1])
+ year_end_date = get_date_str(fiscal_year[2])
+ return [
+ {
+ "doctype": "Number Card",
+ "document_type": "Payment Entry",
+ "name": "Total Incoming Payment",
+ "filters_json": json.dumps([
+ ['Payment Entry', 'docstatus', '=', 1],
+ ['Payment Entry', 'posting_date', 'between', [year_start_date, year_end_date]],
+ ['Payment Entry', 'payment_type', '=', 'Receive']
+ ]),
+ "label": _("Total Incoming Payment"),
+ "function": "Sum",
+ "aggregate_function_based_on": "base_received_amount",
+ "is_public": 1,
+ "is_custom": 1,
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Monthly"
+ },
+ {
+ "doctype": "Number Card",
+ "document_type": "Payment Entry",
+ "name": "Total Outgoing Payment",
+ "filters_json": json.dumps([
+ ['Payment Entry', 'docstatus', '=', 1],
+ ['Payment Entry', 'posting_date', 'between', [year_start_date, year_end_date]],
+ ['Payment Entry', 'payment_type', '=', 'Pay']
+ ]),
+ "label": _("Total Outgoing Payment"),
+ "function": "Sum",
+ "aggregate_function_based_on": "base_paid_amount",
+ "is_public": 1,
+ "is_custom": 1,
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Monthly"
+ },
+ {
+ "doctype": "Number Card",
+ "document_type": "Sales Invoice",
+ "name": "Total Outgoing Bills",
+ "filters_json": json.dumps([
+ ['Sales Invoice', 'docstatus', '=', 1],
+ ['Sales Invoice', 'posting_date', 'between', [year_start_date, year_end_date]]
+ ]),
+ "label": _("Total Outgoing Bills"),
+ "function": "Sum",
+ "aggregate_function_based_on": "base_net_total",
+ "is_public": 1,
+ "is_custom": 1,
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Monthly"
+ },
+ {
+ "doctype": "Number Card",
+ "document_type": "Purchase Invoice",
+ "name": "Total Incoming Bills",
+ "filters_json": json.dumps([
+ ['Purchase Invoice', 'docstatus', '=', 1],
+ ['Purchase Invoice', 'posting_date', 'between', [year_start_date, year_end_date]]
+ ]),
+ "label": _("Total Incoming Bills"),
+ "function": "Sum",
+ "aggregate_function_based_on": "base_net_total",
+ "is_public": 1,
+ "is_custom": 1,
+ "show_percentage_stats": 1,
+ "stats_time_interval": "Monthly"
+ }
+ ]
diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py
index b0210e5fd4b..b57e6783ceb 100644
--- a/erpnext/accounts/deferred_revenue.py
+++ b/erpnext/accounts/deferred_revenue.py
@@ -185,7 +185,7 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
total_days, total_booking_days, account_currency)
make_gl_entries(doc, credit_account, debit_account, against,
- amount, base_amount, end_date, project, account_currency, item.cost_center, item.name, deferred_process)
+ amount, base_amount, end_date, project, account_currency, item.cost_center, item, deferred_process)
# Returned in case of any errors because it tries to submit the same record again and again in case of errors
if frappe.flags.deferred_accounting_error:
@@ -222,7 +222,7 @@ def process_deferred_accounting(posting_date=today()):
doc.submit()
def make_gl_entries(doc, credit_account, debit_account, against,
- amount, base_amount, posting_date, project, account_currency, cost_center, voucher_detail_no, deferred_process=None):
+ amount, base_amount, posting_date, project, account_currency, cost_center, item, deferred_process=None):
# GL Entry for crediting the amount in the deferred expense
from erpnext.accounts.general_ledger import make_gl_entries
@@ -236,12 +236,12 @@ def make_gl_entries(doc, credit_account, debit_account, against,
"credit": base_amount,
"credit_in_account_currency": amount,
"cost_center": cost_center,
- "voucher_detail_no": voucher_detail_no,
+ "voucher_detail_no": item.name,
'posting_date': posting_date,
'project': project,
'against_voucher_type': 'Process Deferred Accounting',
'against_voucher': deferred_process
- }, account_currency)
+ }, account_currency, item=item)
)
# GL Entry to debit the amount from the expense
gl_entries.append(
@@ -251,12 +251,12 @@ def make_gl_entries(doc, credit_account, debit_account, against,
"debit": base_amount,
"debit_in_account_currency": amount,
"cost_center": cost_center,
- "voucher_detail_no": voucher_detail_no,
+ "voucher_detail_no": item.name,
'posting_date': posting_date,
'project': project,
'against_voucher_type': 'Process Deferred Accounting',
'against_voucher': deferred_process
- }, account_currency)
+ }, account_currency, item=item)
)
if gl_entries:
diff --git a/erpnext/accounts/desk_page/accounting/accounting.json b/erpnext/accounts/desk_page/accounting/accounting.json
index 0d6aca65b16..a783b1d0dbb 100644
--- a/erpnext/accounts/desk_page/accounting/accounting.json
+++ b/erpnext/accounts/desk_page/accounting/accounting.json
@@ -45,11 +45,6 @@
"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 Statement Transaction Entry\",\n \"name\": \"Bank Statement Transaction Entry\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Statement Settings\",\n \"name\": \"Bank Statement Settings\",\n \"type\": \"doctype\"\n }\n]"
},
- {
- "hidden": 0,
- "links": "[\n {\n \"description\": \"Match non-linked Invoices and Payments.\",\n \"label\": \"Match Payments with Invoices\",\n \"name\": \"Payment Reconciliation\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Update bank payment dates with journals.\",\n \"label\": \"Update Bank Clearance Dates\",\n \"name\": \"Bank Clearance\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Invoice Discounting\",\n \"name\": \"Invoice Discounting\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Journal Entry\"\n ],\n \"doctype\": \"Journal Entry\",\n \"is_query_report\": true,\n \"label\": \"Bank Reconciliation Statement\",\n \"name\": \"Bank Reconciliation Statement\",\n \"type\": \"report\"\n },\n {\n \"icon\": \"fa fa-bar-chart\",\n \"label\": \"Bank Reconciliation\",\n \"name\": \"bank-reconciliation\",\n \"type\": \"page\"\n },\n {\n \"dependencies\": [\n \"Journal Entry\"\n ],\n \"doctype\": \"Journal Entry\",\n \"is_query_report\": true,\n \"label\": \"Bank Clearance Summary\",\n \"name\": \"Bank Clearance Summary\",\n \"type\": \"report\"\n },\n {\n \"label\": \"Bank Guarantee\",\n \"name\": \"Bank Guarantee\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Setup cheque dimensions for printing\",\n \"label\": \"Cheque Print Template\",\n \"name\": \"Cheque Print Template\",\n \"type\": \"doctype\"\n }\n]",
- "title": "Banking and Payments"
- },
{
"hidden": 0,
"label": "Subscription Management",
@@ -89,8 +84,8 @@
"category": "Modules",
"charts": [
{
- "chart_name": "Bank Balance",
- "label": "Bank Balance"
+ "chart_name": "Profit and Loss",
+ "label": "Profit and Loss"
}
],
"creation": "2020-03-02 15:41:59.515192",
@@ -99,23 +94,38 @@
"docstatus": 0,
"doctype": "Desk Page",
"extends_another_page": 0,
- "icon": "",
"idx": 0,
"is_standard": 1,
"label": "Accounting",
- "modified": "2020-04-29 12:17:34.844397",
+ "modified": "2020-05-18 17:27:26.882340",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting",
+ "onboarding": "Accounts",
"owner": "Administrator",
"pin_to_bottom": 0,
"pin_to_top": 0,
"shortcuts": [
{
- "label": "Account",
+ "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": "Accounts Dashboard",
+ "link_to": "Accounts Dashboard",
+ "type": "Dashboard"
+ },
{
"label": "Journal Entry",
"link_to": "Journal Entry",
@@ -136,11 +146,6 @@
"link_to": "General Ledger",
"type": "Report"
},
- {
- "label": "Profit and Loss Statement",
- "link_to": "Profit and Loss Statement",
- "type": "Report"
- },
{
"label": "Trial Balance",
"link_to": "Trial Balance",
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
index 7a85bfb26b6..894ec5bdec5 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -162,9 +162,9 @@ def toggle_disabling(doc):
def get_doctypes_with_dimensions():
doclist = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset",
- "Expense Claim", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note", "Sales Invoice Item", "Purchase Invoice Item",
- "Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item", "Purchase Receipt Item",
- "Stock Entry Detail", "Payment Entry Deduction", "Sales Taxes and Charges", "Purchase Taxes and Charges", "Shipping Rule",
+ "Expense Claim", "Expense Claim Detail", "Expense Taxes and Charges", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note",
+ "Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item",
+ "Purchase Receipt Item", "Stock Entry Detail", "Payment Entry Deduction", "Sales Taxes and Charges", "Purchase Taxes and Charges", "Shipping Rule",
"Landed Cost Item", "Asset Value Adjustment", "Loyalty Program", "Fee Schedule", "Fee Structure", "Stock Reconciliation",
"Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item", "Subscription",
"Subscription Plan"]
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index efab5801e8b..291aff3f5ad 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -112,8 +112,8 @@ class GLEntry(Document):
from tabAccount where name=%s""", self.account, as_dict=1)[0]
if ret.is_group==1:
- frappe.throw(_("{0} {1}: Account {2} cannot be a Group")
- .format(self.voucher_type, self.voucher_no, self.account))
+ frappe.throw(_('''{0} {1}: Account {2} is a Group Account and group accounts cannot be used in
+ transactions''').format(self.voucher_type, self.voucher_no, self.account))
if ret.docstatus==2:
frappe.throw(_("{0} {1}: Account {2} is inactive")
diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py
index 39fc203d53f..594b4d4a223 100644
--- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py
+++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py
@@ -8,6 +8,7 @@ from frappe import _
from frappe.utils import flt, getdate, nowdate, add_days
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.accounts.general_ledger import make_gl_entries
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
class InvoiceDiscounting(AccountsController):
def validate(self):
@@ -81,10 +82,15 @@ class InvoiceDiscounting(AccountsController):
def make_gl_entries(self):
company_currency = frappe.get_cached_value('Company', self.company, "default_currency")
+
gl_entries = []
+ invoice_fields = ["debit_to", "party_account_currency", "conversion_rate", "cost_center"]
+ accounting_dimensions = get_accounting_dimensions()
+
+ invoice_fields.extend(accounting_dimensions)
+
for d in self.invoices:
- inv = frappe.db.get_value("Sales Invoice", d.sales_invoice,
- ["debit_to", "party_account_currency", "conversion_rate", "cost_center"], as_dict=1)
+ inv = frappe.db.get_value("Sales Invoice", d.sales_invoice, invoice_fields, as_dict=1)
if d.outstanding_amount:
outstanding_in_company_currency = flt(d.outstanding_amount * inv.conversion_rate,
@@ -102,7 +108,7 @@ class InvoiceDiscounting(AccountsController):
"cost_center": inv.cost_center,
"against_voucher": d.sales_invoice,
"against_voucher_type": "Sales Invoice"
- }, inv.party_account_currency))
+ }, inv.party_account_currency, item=inv))
gl_entries.append(self.get_gl_dict({
"account": self.accounts_receivable_credit,
@@ -115,7 +121,7 @@ class InvoiceDiscounting(AccountsController):
"cost_center": inv.cost_center,
"against_voucher": d.sales_invoice,
"against_voucher_type": "Sales Invoice"
- }, ar_credit_account_currency))
+ }, ar_credit_account_currency, item=inv))
make_gl_entries(gl_entries, cancel=(self.docstatus == 2), update_outstanding='No')
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 83c670eace4..d2245d6a6d6 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -86,7 +86,7 @@ class PaymentEntry(AccountsController):
self.update_payment_schedule(cancel=1)
self.set_payment_req_status()
self.set_status()
-
+
def set_payment_req_status(self):
from erpnext.accounts.doctype.payment_request.payment_request import update_payment_req_status
update_payment_req_status(self, None)
@@ -280,7 +280,7 @@ class PaymentEntry(AccountsController):
outstanding_amount, is_return = frappe.get_cached_value(d.reference_doctype, d.reference_name, ["outstanding_amount", "is_return"])
if outstanding_amount <= 0 and not is_return:
no_oustanding_refs.setdefault(d.reference_doctype, []).append(d)
-
+
for k, v in no_oustanding_refs.items():
frappe.msgprint(_("{} - {} now have {} as they had no outstanding amount left before submitting the Payment Entry.
\
If this is undesirable please cancel the corresponding Payment Entry.")
@@ -451,8 +451,6 @@ class PaymentEntry(AccountsController):
frappe.throw(_("Reference No and Reference Date is mandatory for Bank transaction"))
def set_remarks(self):
- if self.remarks: return
-
if self.payment_type=="Internal Transfer":
remarks = [_("Amount {0} {1} transferred from {2} to {3}")
.format(self.paid_from_account_currency, self.paid_amount, self.paid_from, self.paid_to)]
@@ -506,7 +504,7 @@ class PaymentEntry(AccountsController):
"against": against_account,
"account_currency": self.party_account_currency,
"cost_center": self.cost_center
- })
+ }, item=self)
dr_or_cr = "credit" if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit"
@@ -550,7 +548,7 @@ class PaymentEntry(AccountsController):
"credit_in_account_currency": self.paid_amount,
"credit": self.base_paid_amount,
"cost_center": self.cost_center
- })
+ }, item=self)
)
if self.payment_type in ("Receive", "Internal Transfer"):
gl_entries.append(
@@ -561,7 +559,7 @@ class PaymentEntry(AccountsController):
"debit_in_account_currency": self.received_amount,
"debit": self.base_received_amount,
"cost_center": self.cost_center
- })
+ }, item=self)
)
def add_deductions_gl_entries(self, gl_entries):
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index 19f571fb306..4d9053a55b3 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -99,7 +99,7 @@ class PricingRule(Document):
self.same_item = 1
def validate_max_discount(self):
- if self.rate_or_discount == "Discount Percentage" and self.items:
+ if self.rate_or_discount == "Discount Percentage" and self.get("items"):
for d in self.items:
max_discount = frappe.get_cached_value("Item", d.item_code, "max_discount")
if max_discount and flt(self.discount_percentage) > flt(max_discount):
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index b358f56671f..cb05481df5a 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -4,13 +4,19 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, copy, json
-from frappe import throw, _
+
+import copy
+import json
+
from six import string_types
-from frappe.utils import flt, cint, get_datetime, get_link_to_form, today
+
+import frappe
from erpnext.setup.doctype.item_group.item_group import get_child_item_groups
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
from erpnext.stock.get_item_details import get_conversion_factor
+from frappe import _, throw
+from frappe.utils import cint, flt, get_datetime, get_link_to_form, getdate, today
+
class MultiplePricingRuleConflict(frappe.ValidationError): pass
@@ -502,18 +508,16 @@ def get_pricing_rule_items(pr_doc):
return list(set(apply_on_data))
def validate_coupon_code(coupon_name):
- from frappe.utils import today,getdate
- coupon=frappe.get_doc("Coupon Code",coupon_name)
+ coupon = frappe.get_doc("Coupon Code", coupon_name)
+
if coupon.valid_from:
- if coupon.valid_from > getdate(today()) :
- frappe.throw(_("Sorry,coupon code validity has not started"))
+ if coupon.valid_from > getdate(today()):
+ frappe.throw(_("Sorry, this coupon code's validity has not started"))
elif coupon.valid_upto:
- if coupon.valid_upto < getdate(today()) :
- frappe.throw(_("Sorry,coupon code validity has expired"))
- elif coupon.used>=coupon.maximum_use:
- frappe.throw(_("Sorry,coupon code are exhausted"))
- else:
- return
+ if coupon.valid_upto < getdate(today()):
+ frappe.throw(_("Sorry, this coupon code's validity has expired"))
+ elif coupon.used >= coupon.maximum_use:
+ frappe.throw(_("Sorry, this coupon code is no longer valid"))
def update_coupon_code_count(coupon_name,transaction_type):
coupon=frappe.get_doc("Coupon Code",coupon_name)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 3aa24df16d3..aa1d5b526c8 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -460,7 +460,7 @@ class PurchaseInvoice(BuyingController):
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
- }, self.party_account_currency)
+ }, self.party_account_currency, item=self)
)
def make_item_gl_entries(self, gl_entries):
@@ -841,7 +841,7 @@ class PurchaseInvoice(BuyingController):
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
- }, self.party_account_currency)
+ }, self.party_account_currency, item=self)
)
gl_entries.append(
@@ -852,7 +852,7 @@ class PurchaseInvoice(BuyingController):
"credit_in_account_currency": self.base_paid_amount \
if bank_account_currency==self.company_currency else self.paid_amount,
"cost_center": self.cost_center
- }, bank_account_currency)
+ }, bank_account_currency, item=self)
)
def make_write_off_gl_entry(self, gl_entries):
@@ -873,7 +873,7 @@ class PurchaseInvoice(BuyingController):
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
- }, self.party_account_currency)
+ }, self.party_account_currency, item=self)
)
gl_entries.append(
self.get_gl_dict({
@@ -883,7 +883,7 @@ class PurchaseInvoice(BuyingController):
"credit_in_account_currency": self.base_write_off_amount \
if write_off_account_currency==self.company_currency else self.write_off_amount,
"cost_center": self.cost_center or self.write_off_cost_center
- })
+ }, item=self)
)
def make_gle_for_rounding_adjustment(self, gl_entries):
@@ -902,8 +902,7 @@ class PurchaseInvoice(BuyingController):
"debit_in_account_currency": self.rounding_adjustment,
"debit": self.base_rounding_adjustment,
"cost_center": self.cost_center or round_off_cost_center,
- }
- ))
+ }, item=self))
def on_cancel(self):
super(PurchaseInvoice, self).on_cancel()
@@ -1021,6 +1020,40 @@ class PurchaseInvoice(BuyingController):
# calculate totals again after applying TDS
self.calculate_taxes_and_totals()
+
+ def set_status(self, update=False, status=None, update_modified=True):
+ if self.is_new():
+ if self.get('amended_from'):
+ self.status = 'Draft'
+ return
+
+ precision = self.precision("outstanding_amount")
+ outstanding_amount = flt(self.outstanding_amount, precision)
+ due_date = getdate(self.due_date)
+ nowdate = getdate()
+
+ if not status:
+ if self.docstatus == 2:
+ status = "Cancelled"
+ elif self.docstatus == 1:
+ if outstanding_amount > 0 and due_date < nowdate:
+ self.status = "Overdue"
+ elif outstanding_amount > 0 and due_date >= nowdate:
+ self.status = "Unpaid"
+ #Check if outstanding amount is 0 due to debit note issued against invoice
+ elif outstanding_amount <= 0 and self.is_return == 0 and frappe.db.get_value('Purchase Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}):
+ self.status = "Debit Note Issued"
+ elif self.is_return == 1:
+ self.status = "Return"
+ elif outstanding_amount<=0:
+ self.status = "Paid"
+ else:
+ self.status = "Submitted"
+ else:
+ self.status = "Draft"
+
+ if update:
+ self.db_set('status', self.status, update_modified = update_modified)
def get_list_context(context=None):
from erpnext.controllers.website_list_for_contact import get_list_context
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index e41ad428469..61700050614 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -86,6 +86,8 @@ class TestPurchaseInvoice(unittest.TestCase):
pe.submit()
pi_doc = frappe.get_doc('Purchase Invoice', pi_doc.name)
+ pi_doc.load_from_db()
+ self.assertTrue(pi_doc.status, "Paid")
self.assertRaises(frappe.LinkExistsError, pi_doc.cancel)
unlink_payment_on_cancel_of_invoice()
@@ -203,7 +205,9 @@ class TestPurchaseInvoice(unittest.TestCase):
pi.insert()
pi.submit()
+ pi.load_from_db()
+ self.assertTrue(pi.status, "Unpaid")
self.check_gle_for_pi(pi.name)
def check_gle_for_pi(self, pi):
@@ -234,6 +238,9 @@ class TestPurchaseInvoice(unittest.TestCase):
pi = frappe.copy_doc(test_records[0])
pi.insert()
+ pi.load_from_db()
+
+ self.assertTrue(pi.status, "Draft")
pi.naming_series = 'TEST-'
self.assertRaises(frappe.CannotChangeConstantError, pi.save)
@@ -248,6 +255,8 @@ class TestPurchaseInvoice(unittest.TestCase):
pi.get("taxes").pop(1)
pi.insert()
pi.submit()
+ pi.load_from_db()
+ self.assertTrue(pi.status, "Unpaid")
gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
@@ -599,6 +608,11 @@ class TestPurchaseInvoice(unittest.TestCase):
# return entry
pi1 = make_purchase_invoice(is_return=1, return_against=pi.name, qty=-2, rate=50, update_stock=1)
+ pi.load_from_db()
+ self.assertTrue(pi.status, "Debit Note Issued")
+ pi1.load_from_db()
+ self.assertTrue(pi1.status, "Return")
+
actual_qty_2 = get_qty_after_transaction()
self.assertEqual(actual_qty_1 - 2, actual_qty_2)
@@ -771,6 +785,8 @@ class TestPurchaseInvoice(unittest.TestCase):
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import get_outstanding_amount
pi = make_purchase_invoice(item_code = "_Test Item", qty = (5 * -1), rate=500, is_return = 1)
+ pi.load_from_db()
+ self.assertTrue(pi.status, "Return")
outstanding_amount = get_outstanding_amount(pi.doctype,
pi.name, "Creditors - _TC", pi.supplier, "Supplier")
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index f248276e5bb..df0c3d2299b 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -924,7 +924,7 @@ var get_healthcare_services_to_invoice = function(frm) {
if(patient && patient!=selected_patient){
selected_patient = patient;
var method = "erpnext.healthcare.utils.get_healthcare_services_to_invoice";
- var args = {patient: patient};
+ var args = {patient: patient, company: frm.doc.company};
var columns = (["service", "reference_name", "reference_type"]);
get_healthcare_items(frm, true, $results, $placeholder, method, args, columns);
}
@@ -1068,7 +1068,11 @@ var get_drugs_to_invoice = function(frm) {
description:'Quantity will be calculated only for items which has "Nos" as UoM. You may change as required for each invoice item.',
get_query: function(doc) {
return {
- filters: { patient: dialog.get_value("patient"), docstatus: 1 }
+ filters: {
+ patient: dialog.get_value("patient"),
+ company: frm.doc.company,
+ docstatus: 1
+ }
};
}
},
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 3b0fade0e53..05b85dabd4f 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -791,7 +791,7 @@ class SalesInvoice(SellingController):
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
- }, self.party_account_currency)
+ }, self.party_account_currency, item=self)
)
def make_tax_gl_entries(self, gl_entries):
@@ -808,7 +808,7 @@ class SalesInvoice(SellingController):
tax.precision("base_tax_amount_after_discount_amount")) if account_currency==self.company_currency else
flt(tax.tax_amount_after_discount_amount, tax.precision("tax_amount_after_discount_amount"))),
"cost_center": tax.cost_center
- }, account_currency)
+ }, account_currency, item=tax)
)
def make_item_gl_entries(self, gl_entries):
@@ -828,7 +828,7 @@ class SalesInvoice(SellingController):
for gle in fixed_asset_gl_entries:
gle["against"] = self.customer
- gl_entries.append(self.get_gl_dict(gle))
+ gl_entries.append(self.get_gl_dict(gle, item=item))
asset.db_set("disposal_date", self.posting_date)
asset.set_status("Sold" if self.docstatus==1 else None)
@@ -866,7 +866,7 @@ class SalesInvoice(SellingController):
"against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
- })
+ }, item=self)
)
gl_entries.append(
self.get_gl_dict({
@@ -875,7 +875,7 @@ class SalesInvoice(SellingController):
"against": self.customer,
"debit": self.loyalty_amount,
"remark": "Loyalty Points redeemed by the customer"
- })
+ }, item=self)
)
def make_pos_gl_entries(self, gl_entries):
@@ -896,7 +896,7 @@ class SalesInvoice(SellingController):
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
- }, self.party_account_currency)
+ }, self.party_account_currency, item=self)
)
payment_mode_account_currency = get_account_currency(payment_mode.account)
@@ -909,7 +909,7 @@ class SalesInvoice(SellingController):
if payment_mode_account_currency==self.company_currency \
else payment_mode.amount,
"cost_center": self.cost_center
- }, payment_mode_account_currency)
+ }, payment_mode_account_currency, item=self)
)
def make_gle_for_change_amount(self, gl_entries):
@@ -927,7 +927,7 @@ class SalesInvoice(SellingController):
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
- }, self.party_account_currency)
+ }, self.party_account_currency, item=self)
)
gl_entries.append(
@@ -936,7 +936,7 @@ class SalesInvoice(SellingController):
"against": self.customer,
"credit": self.base_change_amount,
"cost_center": self.cost_center
- })
+ }, item=self)
)
else:
frappe.throw(_("Select change amount account"), title="Mandatory Field")
@@ -960,7 +960,7 @@ class SalesInvoice(SellingController):
"against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
- }, self.party_account_currency)
+ }, self.party_account_currency, item=self)
)
gl_entries.append(
self.get_gl_dict({
@@ -971,7 +971,7 @@ class SalesInvoice(SellingController):
self.precision("base_write_off_amount")) if write_off_account_currency==self.company_currency
else flt(self.write_off_amount, self.precision("write_off_amount"))),
"cost_center": self.cost_center or self.write_off_cost_center or default_cost_center
- }, write_off_account_currency)
+ }, write_off_account_currency, item=self)
)
def make_gle_for_rounding_adjustment(self, gl_entries):
@@ -988,8 +988,7 @@ class SalesInvoice(SellingController):
"credit": flt(self.base_rounding_adjustment,
self.precision("base_rounding_adjustment")),
"cost_center": self.cost_center or round_off_cost_center,
- }
- ))
+ }, item=self))
def update_billing_status_in_dn(self, update_modified=True):
updated_delivery_notes = []
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index dd6b4fdc603..4d43919f62e 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -58,7 +58,7 @@ def get_tax_withholding_details(tax_withholding_category, fiscal_year, company):
"rate": tax_rate_detail.tax_withholding_rate,
"threshold": tax_rate_detail.single_threshold,
"cumulative_threshold": tax_rate_detail.cumulative_threshold,
- "description": tax_withholding.category_name
+ "description": tax_withholding.category_name if tax_withholding.category_name else tax_withholding_category
})
def get_tax_withholding_rates(tax_withholding, fiscal_year):
diff --git a/erpnext/accounts/module_onboarding/accounts/accounts.json b/erpnext/accounts/module_onboarding/accounts/accounts.json
new file mode 100644
index 00000000000..12da4400284
--- /dev/null
+++ b/erpnext/accounts/module_onboarding/accounts/accounts.json
@@ -0,0 +1,51 @@
+{
+ "allow_roles": [
+ {
+ "role": "Accounts Manager"
+ },
+ {
+ "role": "Accounts User"
+ }
+ ],
+ "creation": "2020-05-13 19:03:32.564049",
+ "docstatus": 0,
+ "doctype": "Module Onboarding",
+ "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/accounts",
+ "idx": 0,
+ "is_complete": 0,
+ "modified": "2020-05-14 22:11:06.475938",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Accounts",
+ "owner": "Administrator",
+ "steps": [
+ {
+ "step": "Chart Of Accounts"
+ },
+ {
+ "step": "Setup Taxes"
+ },
+ {
+ "step": "Create a Product"
+ },
+ {
+ "step": "Create a Supplier"
+ },
+ {
+ "step": "Create Your First Purchase Invoice"
+ },
+ {
+ "step": "Create a Customer"
+ },
+ {
+ "step": "Create Your First Sales Invoice"
+ },
+ {
+ "step": "Configure Account Settings"
+ }
+ ],
+ "subtitle": "Accounts, invoices and taxation.",
+ "success_message": "The Accounts module is now set up!",
+ "title": "Let's Setup Your Accounts and Taxes.",
+ "user_can_dismiss": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/onboarding_step/chart_of_accounts/chart_of_accounts.json b/erpnext/accounts/onboarding_step/chart_of_accounts/chart_of_accounts.json
new file mode 100644
index 00000000000..cbd022bfdbe
--- /dev/null
+++ b/erpnext/accounts/onboarding_step/chart_of_accounts/chart_of_accounts.json
@@ -0,0 +1,20 @@
+{
+ "action": "Go to Page",
+ "creation": "2020-05-13 19:58:20.928127",
+ "docstatus": 0,
+ "doctype": "Onboarding Step",
+ "idx": 0,
+ "is_complete": 0,
+ "is_mandatory": 0,
+ "is_single": 0,
+ "is_skipped": 0,
+ "modified": "2020-05-14 17:40:28.410447",
+ "modified_by": "Administrator",
+ "name": "Chart Of Accounts",
+ "owner": "Administrator",
+ "path": "Tree/Account",
+ "reference_document": "Account",
+ "show_full_form": 0,
+ "title": "Review Chart Of Accounts",
+ "validate_action": 0
+}
\ No newline at end of file
diff --git a/erpnext/accounts/onboarding_step/configure_account_settings/configure_account_settings.json b/erpnext/accounts/onboarding_step/configure_account_settings/configure_account_settings.json
new file mode 100644
index 00000000000..c8be357de0a
--- /dev/null
+++ b/erpnext/accounts/onboarding_step/configure_account_settings/configure_account_settings.json
@@ -0,0 +1,19 @@
+{
+ "action": "Create Entry",
+ "creation": "2020-05-14 17:53:00.876946",
+ "docstatus": 0,
+ "doctype": "Onboarding Step",
+ "idx": 0,
+ "is_complete": 0,
+ "is_mandatory": 0,
+ "is_single": 1,
+ "is_skipped": 0,
+ "modified": "2020-05-14 18:06:25.212923",
+ "modified_by": "Administrator",
+ "name": "Configure Account Settings",
+ "owner": "Administrator",
+ "reference_document": "Accounts Settings",
+ "show_full_form": 1,
+ "title": "Configure Account Settings",
+ "validate_action": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/onboarding_step/create_a_customer/create_a_customer.json b/erpnext/accounts/onboarding_step/create_a_customer/create_a_customer.json
new file mode 100644
index 00000000000..bb396d268ae
--- /dev/null
+++ b/erpnext/accounts/onboarding_step/create_a_customer/create_a_customer.json
@@ -0,0 +1,19 @@
+{
+ "action": "Create Entry",
+ "creation": "2020-05-14 17:46:41.831517",
+ "docstatus": 0,
+ "doctype": "Onboarding Step",
+ "idx": 0,
+ "is_complete": 0,
+ "is_mandatory": 0,
+ "is_single": 0,
+ "is_skipped": 0,
+ "modified": "2020-05-14 17:46:41.831517",
+ "modified_by": "Administrator",
+ "name": "Create a Customer",
+ "owner": "Administrator",
+ "reference_document": "Customer",
+ "show_full_form": 0,
+ "title": "Create a Customer",
+ "validate_action": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/onboarding_step/create_a_product/create_a_product.json b/erpnext/accounts/onboarding_step/create_a_product/create_a_product.json
new file mode 100644
index 00000000000..450bee1f40b
--- /dev/null
+++ b/erpnext/accounts/onboarding_step/create_a_product/create_a_product.json
@@ -0,0 +1,19 @@
+{
+ "action": "Create Entry",
+ "creation": "2020-05-14 17:45:28.554605",
+ "docstatus": 0,
+ "doctype": "Onboarding Step",
+ "idx": 0,
+ "is_complete": 0,
+ "is_mandatory": 0,
+ "is_single": 0,
+ "is_skipped": 0,
+ "modified": "2020-05-14 17:45:28.554605",
+ "modified_by": "Administrator",
+ "name": "Create a Product",
+ "owner": "Administrator",
+ "reference_document": "Item",
+ "show_full_form": 0,
+ "title": "Create a Product",
+ "validate_action": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/onboarding_step/create_a_supplier/create_a_supplier.json b/erpnext/accounts/onboarding_step/create_a_supplier/create_a_supplier.json
new file mode 100644
index 00000000000..7a64224bd43
--- /dev/null
+++ b/erpnext/accounts/onboarding_step/create_a_supplier/create_a_supplier.json
@@ -0,0 +1,19 @@
+{
+ "action": "Create Entry",
+ "creation": "2020-05-14 22:09:10.043554",
+ "docstatus": 0,
+ "doctype": "Onboarding Step",
+ "idx": 0,
+ "is_complete": 0,
+ "is_mandatory": 0,
+ "is_single": 0,
+ "is_skipped": 0,
+ "modified": "2020-05-14 22:09:10.043554",
+ "modified_by": "Administrator",
+ "name": "Create a Supplier",
+ "owner": "Administrator",
+ "reference_document": "Supplier",
+ "show_full_form": 0,
+ "title": "Create a Supplier",
+ "validate_action": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/onboarding_step/create_your_first_purchase_invoice/create_your_first_purchase_invoice.json b/erpnext/accounts/onboarding_step/create_your_first_purchase_invoice/create_your_first_purchase_invoice.json
new file mode 100644
index 00000000000..3a2b8d39253
--- /dev/null
+++ b/erpnext/accounts/onboarding_step/create_your_first_purchase_invoice/create_your_first_purchase_invoice.json
@@ -0,0 +1,19 @@
+{
+ "action": "Create Entry",
+ "creation": "2020-05-14 22:10:07.049704",
+ "docstatus": 0,
+ "doctype": "Onboarding Step",
+ "idx": 0,
+ "is_complete": 0,
+ "is_mandatory": 0,
+ "is_single": 0,
+ "is_skipped": 0,
+ "modified": "2020-05-14 22:10:07.049704",
+ "modified_by": "Administrator",
+ "name": "Create Your First Purchase Invoice",
+ "owner": "Administrator",
+ "reference_document": "Purchase Invoice",
+ "show_full_form": 1,
+ "title": "Create Your First Purchase Invoice ",
+ "validate_action": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/onboarding_step/create_your_first_sales_invoice/create_your_first_sales_invoice.json b/erpnext/accounts/onboarding_step/create_your_first_sales_invoice/create_your_first_sales_invoice.json
new file mode 100644
index 00000000000..473de5079f5
--- /dev/null
+++ b/erpnext/accounts/onboarding_step/create_your_first_sales_invoice/create_your_first_sales_invoice.json
@@ -0,0 +1,19 @@
+{
+ "action": "Create Entry",
+ "creation": "2020-05-14 17:48:21.019019",
+ "docstatus": 0,
+ "doctype": "Onboarding Step",
+ "idx": 0,
+ "is_complete": 0,
+ "is_mandatory": 0,
+ "is_single": 0,
+ "is_skipped": 0,
+ "modified": "2020-05-14 17:48:21.019019",
+ "modified_by": "Administrator",
+ "name": "Create Your First Sales Invoice",
+ "owner": "Administrator",
+ "reference_document": "Sales Invoice",
+ "show_full_form": 1,
+ "title": "Create Your First Sales Invoice ",
+ "validate_action": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/onboarding_step/setup_taxes/setup_taxes.json b/erpnext/accounts/onboarding_step/setup_taxes/setup_taxes.json
new file mode 100644
index 00000000000..8e0006762d1
--- /dev/null
+++ b/erpnext/accounts/onboarding_step/setup_taxes/setup_taxes.json
@@ -0,0 +1,19 @@
+{
+ "action": "Create Entry",
+ "creation": "2020-05-13 19:29:43.844463",
+ "docstatus": 0,
+ "doctype": "Onboarding Step",
+ "idx": 0,
+ "is_complete": 0,
+ "is_mandatory": 0,
+ "is_single": 0,
+ "is_skipped": 0,
+ "modified": "2020-05-14 17:40:16.014413",
+ "modified_by": "Administrator",
+ "name": "Setup Taxes",
+ "owner": "Administrator",
+ "reference_document": "Sales Taxes and Charges Template",
+ "show_full_form": 1,
+ "title": "Lets create a Tax Template for Sales ",
+ "validate_action": 0
+}
\ No newline at end of file
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index e9c286fcf0d..a0a1b9783ac 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -546,7 +546,7 @@ class ReceivablePayableReport(object):
self.filters.range1, self.filters.range2, self.filters.range3, self.filters.range4 = 30, 60, 90, 120
for i, days in enumerate([self.filters.range1, self.filters.range2, self.filters.range3, self.filters.range4]):
- if row.age <= days:
+ if cint(row.age) <= cint(days):
index = i
break
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
index 49c1d0f2ccd..05dc2826611 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
@@ -56,14 +56,26 @@ def execute(filters=None):
row += totals
data.append(row)
- return columns, data
+ chart = get_chart_data(filters, columns, data)
+ return columns, data, None, chart
def get_columns(filters):
columns = [
- _(filters.get("budget_against"))
- + ":Link/%s:150" % (filters.get("budget_against")),
- _("Account") + ":Link/Account:150"
+ {
+ 'label': _(filters.get("budget_against")),
+ 'fieldtype': 'Link',
+ 'fieldname': 'budget_against',
+ 'options': filters.get('budget_against'),
+ 'width': 150
+ },
+ {
+ 'label': _('Account'),
+ 'fieldname': 'Account',
+ 'fieldtype': 'Link',
+ 'options': 'Account',
+ 'width': 150
+ }
]
group_months = False if filters["period"] == "Monthly" else True
@@ -79,7 +91,12 @@ def get_columns(filters):
_("Variance ") + " " + str(year[0])
]
for label in labels:
- columns.append(label + ":Float:150")
+ columns.append({
+ 'label': label,
+ 'fieldtype': 'Float',
+ 'fieldname': frappe.scrub(label),
+ 'width': 150
+ })
else:
for label in [
_("Budget") + " (%s)" + " " + str(year[0]),
@@ -95,14 +112,23 @@ def get_columns(filters):
else:
label = label % formatdate(from_date, format_string="MMM")
- columns.append(label + ":Float:150")
+ columns.append({
+ 'label': label,
+ 'fieldtype': 'Float',
+ 'fieldname': frappe.scrub(label),
+ 'width': 150
+ })
if filters["period"] != "Yearly":
- return columns + [
- _("Total Budget") + ":Float:150",
- _("Total Actual") + ":Float:150",
- _("Total Variance") + ":Float:150"
- ]
+ for label in [_("Total Budget"), _("Total Actual"), _("Total Variance")]:
+ columns.append({
+ 'label': label,
+ 'fieldtype': 'Float',
+ 'fieldname': frappe.scrub(label),
+ 'width': 150
+ })
+
+ return columns
else:
return columns
@@ -173,7 +199,7 @@ def get_dimension_target_details(filters):
filters.budget_against,
filters.company,
]
- + filters.get("budget_against_filter")
+ + (filters.get("budget_against_filter") or [])
), as_dict=True)
@@ -305,3 +331,49 @@ def get_fiscal_years(filters):
})
return fiscal_year
+
+def get_chart_data(filters, columns, data):
+
+ if not data:
+ return None
+
+ labels = []
+
+ fiscal_year = get_fiscal_years(filters)
+ group_months = False if filters["period"] == "Monthly" else True
+
+ for year in fiscal_year:
+ for from_date, to_date in get_period_date_ranges(filters["period"], year[0]):
+ if filters['period'] == 'Yearly':
+ labels.append(year[0])
+ else:
+ if group_months:
+ label = formatdate(from_date, format_string="MMM") + "-" \
+ + formatdate(to_date, format_string="MMM")
+ labels.append(label)
+ else:
+ label = formatdate(from_date, format_string="MMM")
+ labels.append(label)
+
+ no_of_columns = len(labels)
+
+ budget_values, actual_values = [0] * no_of_columns, [0] * no_of_columns
+ for d in data:
+ values = d[2:]
+ index = 0
+
+ for i in range(no_of_columns):
+ budget_values[i] += values[index]
+ actual_values[i] += values[index+1]
+ index += 3
+
+ return {
+ 'data': {
+ 'labels': labels,
+ 'datasets': [
+ {'name': 'Budget', 'chartType': 'bar', 'values': budget_values},
+ {'name': 'Actual Expense', 'chartType': 'bar', 'values': actual_values}
+ ]
+ }
+ }
+
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 1188beaa0f8..2aecd6b717d 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -53,7 +53,7 @@ frappe.query_reports["General Ledger"] = {
"label": __("Voucher No"),
"fieldtype": "Data",
on_change: function() {
- frappe.query_report.set_filter_value('group_by', "");
+ frappe.query_report.set_filter_value('group_by', "Group by Voucher (Consolidated)");
}
},
{
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.js b/erpnext/accounts/report/trial_balance/trial_balance.js
index 622bab6946f..07752e1e626 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.js
+++ b/erpnext/accounts/report/trial_balance/trial_balance.js
@@ -46,7 +46,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"default": frappe.defaults.get_user_default("year_end_date"),
},
{
- "fieldname":"cost_center",
+ "fieldname": "cost_center",
"label": __("Cost Center"),
"fieldtype": "Link",
"options": "Cost Center",
@@ -61,7 +61,13 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
}
},
{
- "fieldname":"finance_book",
+ "fieldname": "project",
+ "label": __("Project"),
+ "fieldtype": "Link",
+ "options": "Project"
+ },
+ {
+ "fieldname": "finance_book",
"label": __("Finance Book"),
"fieldtype": "Link",
"options": "Finance Book",
@@ -97,7 +103,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
}
erpnext.dimension_filters.forEach((dimension) => {
- frappe.query_reports["Trial Balance"].filters.splice(5, 0 ,{
+ frappe.query_reports["Trial Balance"].filters.splice(6, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py
index d78324157a9..8bd4399e608 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.py
+++ b/erpnext/accounts/report/trial_balance/trial_balance.py
@@ -69,6 +69,10 @@ def get_data(filters):
gl_entries_by_account = {}
opening_balances = get_opening_balances(filters)
+
+ #add filter inside list so that the query in financial_statements.py doesn't break
+ filters.project = [filters.project]
+
set_gl_entries_by_account(filters.company, filters.from_date,
filters.to_date, min_lft, max_rgt, filters, gl_entries_by_account, ignore_closing_entries=not flt(filters.with_period_closing_entry))
@@ -102,6 +106,9 @@ def get_rootwise_opening_balances(filters, report_type):
additional_conditions += """ and cost_center in (select name from `tabCost Center`
where lft >= %s and rgt <= %s)""" % (lft, rgt)
+ if filters.project:
+ additional_conditions += " and project = %(project)s"
+
if filters.finance_book:
fb_conditions = " AND finance_book = %(finance_book)s"
if filters.include_default_book_entries:
@@ -116,6 +123,7 @@ def get_rootwise_opening_balances(filters, report_type):
"from_date": filters.from_date,
"report_type": report_type,
"year_start_date": filters.year_start_date,
+ "project": filters.project,
"finance_book": filters.finance_book,
"company_fb": frappe.db.get_value("Company", filters.company, 'default_finance_book')
}
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index a3200d56443..505ba4c6b64 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -125,7 +125,7 @@ class Asset(AccountsController):
if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(self.purchase_date):
frappe.throw(_("Available-for-use Date should be after purchase date"))
-
+
def validate_gross_and_purchase_amount(self):
if self.gross_purchase_amount and self.gross_purchase_amount != self.purchase_receipt_amount:
frappe.throw(_("Gross Purchase Amount should be {} to purchase amount of one single Asset. {}\
@@ -455,7 +455,7 @@ class Asset(AccountsController):
for d in self.get('finance_books'):
if d.finance_book == self.default_finance_book:
return cint(d.idx) - 1
-
+
def validate_make_gl_entry(self):
purchase_document = self.get_purchase_document()
asset_bought_with_invoice = purchase_document == self.purchase_invoice
@@ -487,14 +487,14 @@ class Asset(AccountsController):
purchase_document = self.purchase_invoice if asset_bought_with_invoice else self.purchase_receipt
return purchase_document
-
+
def get_asset_accounts(self):
fixed_asset_account = get_asset_category_account('fixed_asset_account', asset=self.name,
asset_category = self.asset_category, company = self.company)
cwip_account = get_asset_account("capital_work_in_progress_account",
self.name, self.asset_category, self.company)
-
+
return fixed_asset_account, cwip_account
def make_gl_entries(self):
@@ -513,7 +513,7 @@ class Asset(AccountsController):
"credit": self.purchase_receipt_amount,
"credit_in_account_currency": self.purchase_receipt_amount,
"cost_center": self.cost_center
- }))
+ }, item=self))
gl_entries.append(self.get_gl_dict({
"account": fixed_asset_account,
@@ -523,7 +523,7 @@ class Asset(AccountsController):
"debit": self.purchase_receipt_amount,
"debit_in_account_currency": self.purchase_receipt_amount,
"cost_center": self.cost_center
- }))
+ }, item=self))
if gl_entries:
from erpnext.accounts.general_ledger import make_gl_entries
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
index 16061c61ba0..1b8b40459f6 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
@@ -18,6 +18,10 @@ erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.ext
refresh: function() {
var me = this;
this._super();
+
+ if (this.frm.doc.__islocal && !this.frm.doc.valid_till) {
+ this.frm.set_value('valid_till', frappe.datetime.add_months(this.frm.doc.transaction_date, 1));
+ }
if (this.frm.doc.docstatus === 1) {
cur_frm.add_custom_button(__("Purchase Order"), this.make_purchase_order,
__('Create'));
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
index 82fc6285bcf..3bc441af6d1 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
@@ -13,9 +13,10 @@
"supplier",
"supplier_name",
"column_break1",
- "transaction_date",
- "amended_from",
"company",
+ "transaction_date",
+ "valid_till",
+ "amended_from",
"address_section",
"supplier_address",
"contact_person",
@@ -791,13 +792,18 @@
"options": "Opportunity",
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fieldname": "valid_till",
+ "fieldtype": "Date",
+ "label": "Valid Till"
}
],
"icon": "fa fa-shopping-cart",
"idx": 29,
"is_submittable": 1,
"links": [],
- "modified": "2019-12-30 19:17:28.208693",
+ "modified": "2020-04-15 11:44:52.958022",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation",
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
index 5b4356a7471..baf245735a4 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import flt, nowdate, add_days
+from frappe.utils import flt, nowdate, add_days, getdate
from frappe.model.mapper import get_mapped_doc
from erpnext.controllers.buying_controller import BuyingController
@@ -28,6 +28,7 @@ class SupplierQuotation(BuyingController):
validate_for_items(self)
self.validate_with_previous_doc()
self.validate_uom_is_integer("uom", "qty")
+ self.validate_valid_till()
def on_submit(self):
frappe.db.set(self, "status", "Submitted")
@@ -52,6 +53,11 @@ class SupplierQuotation(BuyingController):
"is_child_table": True
}
})
+
+ def validate_valid_till(self):
+ if self.valid_till and getdate(self.valid_till) < getdate(self.transaction_date):
+ frappe.throw(_("Valid till Date cannot be before Transaction Date"))
+
def update_rfq_supplier_status(self, include_me):
rfq_list = set([])
for item in self.items:
@@ -158,3 +164,11 @@ def make_quotation(source_name, target_doc=None):
}, target_doc)
return doclist
+
+def set_expired_status():
+ frappe.db.sql("""
+ UPDATE
+ `tabSupplier Quotation` SET `status` = 'Expired'
+ WHERE
+ `status` not in ('Cancelled', 'Stopped') AND `valid_till` < %s
+ """, (nowdate()))
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js b/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js
index 95554397bb7..9f4fecea86b 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js
@@ -5,6 +5,8 @@ frappe.listview_settings['Supplier Quotation'] = {
return [__("Ordered"), "green", "status,=,Ordered"];
} else if(doc.status==="Rejected") {
return [__("Lost"), "darkgrey", "status,=,Lost"];
+ } else if(doc.status==="Expired") {
+ return [__("Expired"), "darkgrey", "status,=,Expired"];
}
}
};
diff --git a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js
index 3d05612c9ed..a76ffeec2ec 100644
--- a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js
+++ b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js
@@ -5,20 +5,18 @@ frappe.query_reports["Quoted Item Comparison"] = {
filters: [
{
fieldtype: "Link",
- label: __("Supplier Quotation"),
- options: "Supplier Quotation",
- fieldname: "supplier_quotation",
- default: "",
- get_query: () => {
- return { filters: { "docstatus": ["<", 2] } }
- }
+ label: __("Company"),
+ options: "Company",
+ fieldname: "company",
+ default: frappe.defaults.get_user_default("Company"),
+ "reqd": 1
},
{
reqd: 1,
default: "",
options: "Item",
label: __("Item"),
- fieldname: "item",
+ fieldname: "item_code",
fieldtype: "Link",
get_query: () => {
let quote = frappe.query_report.get_filter_value('supplier_quotation');
@@ -37,8 +35,37 @@ frappe.query_reports["Quoted Item Comparison"] = {
}
}
}
+ },
+ {
+ fieldname: "supplier",
+ label: __("Supplier"),
+ fieldtype: "MultiSelectList",
+ get_data: function(txt) {
+ return frappe.db.get_link_options('Supplier', txt);
+ }
+ },
+ {
+ fieldtype: "Link",
+ label: __("Supplier Quotation"),
+ options: "Supplier Quotation",
+ fieldname: "supplier_quotation",
+ default: "",
+ get_query: () => {
+ return { filters: { "docstatus": ["<", 2] } }
+ }
+ },
+ {
+ fieldtype: "Link",
+ label: __("Request for Quotation"),
+ options: "Request for Quotation",
+ fieldname: "request_for_quotation",
+ default: "",
+ get_query: () => {
+ return { filters: { "docstatus": ["<", 2] } }
+ }
}
],
+
onload: (report) => {
// Create a button for setting the default supplier
report.page.add_inner_button(__("Select Default Supplier"), () => {
@@ -102,6 +129,4 @@ frappe.query_reports["Quoted Item Comparison"] = {
});
dialog.show();
}
-}
-
-
+}
\ No newline at end of file
diff --git a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py
index 5aff6bacaea..a33867a525e 100644
--- a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py
+++ b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py
@@ -2,103 +2,180 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from erpnext.setup.utils import get_exchange_rate
-from frappe.utils import flt, cint
import frappe
+from frappe.utils import flt, cint
+from frappe import _
+from collections import defaultdict
+from erpnext.setup.utils import get_exchange_rate
def execute(filters=None):
- qty_list = get_quantity_list(filters.item)
- data = get_quote_list(filters.item, qty_list)
- columns = get_columns(qty_list)
- return columns, data
-
-def get_quote_list(item, qty_list):
- out = []
- if not item:
+ if not filters:
+ return [], []
+
+ conditions = get_conditions(filters)
+ supplier_quotation_data = get_data(filters, conditions)
+ columns = get_columns()
+
+ data, chart_data = prepare_data(supplier_quotation_data)
+
+ return columns, data, None, chart_data
+
+def get_conditions(filters):
+ conditions = ""
+ if filters.get("supplier_quotation"):
+ conditions += " AND sqi.parent = %(supplier_quotation)s"
+
+ if filters.get("request_for_quotation"):
+ conditions += " AND sqi.request_for_quotation = %(request_for_quotation)s"
+
+ if filters.get("supplier"):
+ conditions += " AND sq.supplier in %(supplier)s"
+ return conditions
+
+def get_data(filters, conditions):
+ if not filters.get("item_code"):
return []
- suppliers = []
- price_data = []
- company_currency = frappe.db.get_default("currency")
- float_precision = cint(frappe.db.get_default("float_precision")) or 2
- # Get the list of suppliers
- for root in frappe.db.sql("""select parent, qty, rate from `tabSupplier Quotation Item`
- where item_code=%s and docstatus < 2""", item, as_dict=1):
- for splr in frappe.db.sql("""select supplier from `tabSupplier Quotation`
- where name =%s and docstatus < 2""", root.parent, as_dict=1):
- ip = frappe._dict({
- "supplier": splr.supplier,
- "qty": root.qty,
- "parent": root.parent,
- "rate": root.rate
- })
- price_data.append(ip)
- suppliers.append(splr.supplier)
+ supplier_quotation_data = frappe.db.sql("""SELECT
+ sqi.parent, sqi.qty, sqi.rate, sqi.uom, sqi.request_for_quotation,
+ sq.supplier
+ FROM
+ `tabSupplier Quotation Item` sqi,
+ `tabSupplier Quotation` sq
+ WHERE
+ sqi.item_code = %(item_code)s
+ AND sqi.parent = sq.name
+ AND sqi.docstatus < 2
+ AND sq.company = %(company)s
+ AND sq.status != 'Expired'
+ {0}""".format(conditions), filters, as_dict=1)
+
+ return supplier_quotation_data
+
+def prepare_data(supplier_quotation_data):
+ out, suppliers, qty_list = [], [], []
+ supplier_wise_map = defaultdict(list)
+ supplier_qty_price_map = {}
+
+ company_currency = frappe.db.get_default("currency")
+ float_precision = cint(frappe.db.get_default("float_precision")) or 2
+
+ for data in supplier_quotation_data:
+ supplier = data.get("supplier")
+ supplier_currency = frappe.db.get_value("Supplier", data.get("supplier"), "default_currency")
- #Add a row for each supplier
- for root in set(suppliers):
- supplier_currency = frappe.db.get_value("Supplier", root, "default_currency")
if supplier_currency:
exchange_rate = get_exchange_rate(supplier_currency, company_currency)
else:
exchange_rate = 1
- row = frappe._dict({
- "supplier_name": root
- })
- for col in qty_list:
- # Get the quantity for this row
- for item_price in price_data:
- if str(item_price.qty) == col.key and item_price.supplier == root:
- row[col.key] = flt(item_price.rate * exchange_rate, float_precision)
- row[col.key + "QUOTE"] = item_price.parent
- break
- else:
- row[col.key] = ""
- row[col.key + "QUOTE"] = ""
- out.append(row)
-
- return out
-
-def get_quantity_list(item):
- out = []
-
- if item:
- qty_list = frappe.db.sql("""select distinct qty from `tabSupplier Quotation Item`
- where ifnull(item_code,'')=%s and docstatus < 2 order by qty""", item, as_dict=1)
+ row = {
+ "quotation": data.get("parent"),
+ "qty": data.get("qty"),
+ "price": flt(data.get("rate") * exchange_rate, float_precision),
+ "uom": data.get("uom"),
+ "request_for_quotation": data.get("request_for_quotation"),
+ }
- for qt in qty_list:
- col = frappe._dict({
- "key": str(qt.qty),
- "label": "Qty: " + str(int(qt.qty))
- })
- out.append(col)
+ # map for report view of form {'supplier1':[{},{},...]}
+ supplier_wise_map[supplier].append(row)
- return out
-
-def get_columns(qty_list):
+ # map for chart preparation of the form {'supplier1': {'qty': 'price'}}
+ if not supplier in supplier_qty_price_map:
+ supplier_qty_price_map[supplier] = {}
+ supplier_qty_price_map[supplier][row["qty"]] = row["price"]
+
+ suppliers.append(supplier)
+ qty_list.append(data.get("qty"))
+
+ suppliers = list(set(suppliers))
+ qty_list = list(set(qty_list))
+
+ # final data format for report view
+ for supplier in suppliers:
+ supplier_wise_map[supplier][0].update({"supplier_name": supplier})
+ for entry in supplier_wise_map[supplier]:
+ out.append(entry)
+
+ chart_data = prepare_chart_data(suppliers, qty_list, supplier_qty_price_map)
+
+ return out, chart_data
+
+def prepare_chart_data(suppliers, qty_list, supplier_qty_price_map):
+ data_points_map = {}
+ qty_list.sort()
+
+ # create qty wise values map of the form {'qty1':[value1, value2]}
+ for supplier in suppliers:
+ entry = supplier_qty_price_map[supplier]
+ for qty in qty_list:
+ if not qty in data_points_map:
+ data_points_map[qty] = []
+ if qty in entry:
+ data_points_map[qty].append(entry[qty])
+ else:
+ data_points_map[qty].append(None)
+
+ dataset = []
+ for qty in qty_list:
+ datapoints = {
+ "name": _("Price for Qty ") + str(qty),
+ "values": data_points_map[qty]
+ }
+ dataset.append(datapoints)
+
+ chart_data = {
+ "data": {
+ "labels": suppliers,
+ "datasets": dataset
+ },
+ "type": "bar"
+ }
+
+ return chart_data
+
+def get_columns():
columns = [{
"fieldname": "supplier_name",
- "label": "Supplier",
+ "label": _("Supplier"),
"fieldtype": "Link",
"options": "Supplier",
"width": 200
- }]
-
- for qty in qty_list:
- columns.append({
- "fieldname": qty.key,
- "label": qty.label,
- "fieldtype": "Currency",
- "options": "currency",
- "width": 80
- })
- columns.append({
- "fieldname": qty.key + "QUOTE",
- "label": "Quotation",
- "fieldtype": "Link",
- "options": "Supplier Quotation",
- "width": 90
- })
+ },
+ {
+ "fieldname": "quotation",
+ "label": _("Supplier Quotation"),
+ "fieldtype": "Link",
+ "options": "Supplier Quotation",
+ "width": 200
+ },
+ {
+ "fieldname": "qty",
+ "label": _("Quantity"),
+ "fieldtype": "Float",
+ "width": 80
+ },
+ {
+ "fieldname": "price",
+ "label": _("Price"),
+ "fieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "width": 110
+ },
+ {
+ "fieldname": "uom",
+ "label": _("UOM"),
+ "fieldtype": "Link",
+ "options": "UOM",
+ "width": 90
+ },
+ {
+ "fieldname": "request_for_quotation",
+ "label": _("Request for Quotation"),
+ "fieldtype": "Link",
+ "options": "Request for Quotation",
+ "width": 200
+ }
+ ]
return columns
\ No newline at end of file
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 5febfd6bf28..5fbc460a973 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -8,11 +8,14 @@ from frappe.desk.reportview import get_match_cond, get_filters_cond
from frappe.utils import nowdate, getdate
from collections import defaultdict
from erpnext.stock.get_item_details import _get_item_tax_template
+from frappe.utils import unique
# searches for active employees
def employee_query(doctype, txt, searchfield, start, page_len, filters):
conditions = []
- return frappe.db.sql("""select name, employee_name from `tabEmployee`
+ fields = get_fields("Employee", ["name", "employee_name"])
+
+ return frappe.db.sql("""select {fields} from `tabEmployee`
where status = 'Active'
and docstatus < 2
and ({key} like %(txt)s
@@ -24,6 +27,7 @@ def employee_query(doctype, txt, searchfield, start, page_len, filters):
idx desc,
name, employee_name
limit %(start)s, %(page_len)s""".format(**{
+ 'fields': ", ".join(fields),
'key': searchfield,
'fcond': get_filters_cond(doctype, filters, conditions),
'mcond': get_match_cond(doctype)
@@ -34,9 +38,12 @@ def employee_query(doctype, txt, searchfield, start, page_len, filters):
'page_len': page_len
})
- # searches for leads which are not converted
+
+# searches for leads which are not converted
def lead_query(doctype, txt, searchfield, start, page_len, filters):
- return frappe.db.sql("""select name, lead_name, company_name from `tabLead`
+ fields = get_fields("Lead", ["name", "lead_name", "company_name"])
+
+ return frappe.db.sql("""select {fields} from `tabLead`
where docstatus < 2
and ifnull(status, '') != 'Converted'
and ({key} like %(txt)s
@@ -50,6 +57,7 @@ def lead_query(doctype, txt, searchfield, start, page_len, filters):
idx desc,
name, lead_name
limit %(start)s, %(page_len)s""".format(**{
+ 'fields': ", ".join(fields),
'key': searchfield,
'mcond':get_match_cond(doctype)
}), {
@@ -59,6 +67,7 @@ def lead_query(doctype, txt, searchfield, start, page_len, filters):
'page_len': page_len
})
+
# searches for customer
def customer_query(doctype, txt, searchfield, start, page_len, filters):
conditions = []
@@ -69,13 +78,9 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters):
else:
fields = ["name", "customer_name", "customer_group", "territory"]
- meta = frappe.get_meta("Customer")
- searchfields = meta.get_search_fields()
- searchfields = searchfields + [f for f in [searchfield or "name", "customer_name"] \
- if not f in searchfields]
- fields = fields + [f for f in searchfields if not f in fields]
+ fields = get_fields("Customer", fields)
- fields = ", ".join(fields)
+ searchfields = frappe.get_meta("Customer").get_search_fields()
searchfields = " or ".join([field + " like %(txt)s" for field in searchfields])
return frappe.db.sql("""select {fields} from `tabCustomer`
@@ -88,7 +93,7 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters):
idx desc,
name, customer_name
limit %(start)s, %(page_len)s""".format(**{
- "fields": fields,
+ "fields": ", ".join(fields),
"scond": searchfields,
"mcond": get_match_cond(doctype),
"fcond": get_filters_cond(doctype, filters, conditions).replace('%', '%%'),
@@ -99,6 +104,7 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters):
'page_len': page_len
})
+
# searches for supplier
def supplier_query(doctype, txt, searchfield, start, page_len, filters):
supp_master_name = frappe.defaults.get_user_default("supp_master_name")
@@ -106,7 +112,8 @@ def supplier_query(doctype, txt, searchfield, start, page_len, filters):
fields = ["name", "supplier_group"]
else:
fields = ["name", "supplier_name", "supplier_group"]
- fields = ", ".join(fields)
+
+ fields = get_fields("Supplier", fields)
return frappe.db.sql("""select {field} from `tabSupplier`
where docstatus < 2
@@ -119,7 +126,7 @@ def supplier_query(doctype, txt, searchfield, start, page_len, filters):
idx desc,
name, supplier_name
limit %(start)s, %(page_len)s """.format(**{
- 'field': fields,
+ 'field': ', '.join(fields),
'key': searchfield,
'mcond':get_match_cond(doctype)
}), {
@@ -129,6 +136,7 @@ def supplier_query(doctype, txt, searchfield, start, page_len, filters):
'page_len': page_len
})
+
def tax_account_query(doctype, txt, searchfield, start, page_len, filters):
company_currency = erpnext.get_company_currency(filters.get('company'))
@@ -153,6 +161,7 @@ def tax_account_query(doctype, txt, searchfield, start, page_len, filters):
return tax_accounts
+
def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False):
conditions = []
@@ -221,10 +230,12 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
"page_len": page_len
}, as_dict=as_dict)
+
def bom(doctype, txt, searchfield, start, page_len, filters):
conditions = []
+ fields = get_fields("BOM", ["name", "item"])
- return frappe.db.sql("""select tabBOM.name, tabBOM.item
+ return frappe.db.sql("""select {fields}
from tabBOM
where tabBOM.docstatus=1
and tabBOM.is_active=1
@@ -234,6 +245,7 @@ def bom(doctype, txt, searchfield, start, page_len, filters):
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
idx desc, name
limit %(start)s, %(page_len)s """.format(
+ fields=", ".join(fields),
fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'),
mcond=get_match_cond(doctype).replace('%', '%%'),
key=searchfield),
@@ -244,13 +256,16 @@ def bom(doctype, txt, searchfield, start, page_len, filters):
'page_len': page_len or 20
})
+
def get_project_name(doctype, txt, searchfield, start, page_len, filters):
cond = ''
if filters.get('customer'):
cond = """(`tabProject`.customer = %s or
ifnull(`tabProject`.customer,"")="") and""" %(frappe.db.escape(filters.get("customer")))
- return frappe.db.sql("""select `tabProject`.name from `tabProject`
+ fields = get_fields("Project", ["name"])
+
+ return frappe.db.sql("""select {fields} from `tabProject`
where `tabProject`.status not in ("Completed", "Cancelled")
and {cond} `tabProject`.name like %(txt)s {match_cond}
order by
@@ -258,6 +273,7 @@ def get_project_name(doctype, txt, searchfield, start, page_len, filters):
idx desc,
`tabProject`.name asc
limit {start}, {page_len}""".format(
+ fields=", ".join(['`tabProject`.{0}'.format(f) for f in fields]),
cond=cond,
match_cond=get_match_cond(doctype),
start=start,
@@ -268,8 +284,10 @@ def get_project_name(doctype, txt, searchfield, start, page_len, filters):
def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len, filters, as_dict):
+ fields = get_fields("Delivery Note", ["name", "customer", "posting_date"])
+
return frappe.db.sql("""
- select `tabDelivery Note`.name, `tabDelivery Note`.customer, `tabDelivery Note`.posting_date
+ select %(fields)s
from `tabDelivery Note`
where `tabDelivery Note`.`%(key)s` like %(txt)s and
`tabDelivery Note`.docstatus = 1
@@ -284,6 +302,7 @@ def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len,
)
%(mcond)s order by `tabDelivery Note`.`%(key)s` asc limit %(start)s, %(page_len)s
""" % {
+ "fields": ", ".join(["`tabDelivery Note`.{0}".format(f) for f in fields]),
"key": searchfield,
"fcond": get_filters_cond(doctype, filters, []),
"mcond": get_match_cond(doctype),
@@ -349,6 +368,7 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
order by expiry_date, name desc
limit %(start)s, %(page_len)s""".format(cond, match_conditions=get_match_cond(doctype)), args)
+
def get_account_list(doctype, txt, searchfield, start, page_len, filters):
filter_list = []
@@ -371,6 +391,7 @@ def get_account_list(doctype, txt, searchfield, start, page_len, filters):
fields = ["name", "parent_account"],
limit_start=start, limit_page_length=page_len, as_list=True)
+
def get_blanket_orders(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select distinct bo.name, bo.blanket_order_type, bo.to_date
from `tabBlanket Order` bo, `tabBlanket Order Item` boi
@@ -385,6 +406,7 @@ def get_blanket_orders(doctype, txt, searchfield, start, page_len, filters):
company = frappe.db.escape(filters.get("company"))
))
+
@frappe.whitelist()
def get_income_account(doctype, txt, searchfield, start, page_len, filters):
from erpnext.controllers.queries import get_match_cond
@@ -490,6 +512,7 @@ def get_batch_numbers(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql(query, filters)
+
@frappe.whitelist()
def item_manufacturer_query(doctype, txt, searchfield, start, page_len, filters):
item_filters = [
@@ -507,6 +530,7 @@ def item_manufacturer_query(doctype, txt, searchfield, start, page_len, filters)
)
return item_manufacturers
+
@frappe.whitelist()
def get_purchase_receipts(doctype, txt, searchfield, start, page_len, filters):
query = """
@@ -520,6 +544,7 @@ def get_purchase_receipts(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql(query, filters)
+
@frappe.whitelist()
def get_purchase_invoices(doctype, txt, searchfield, start, page_len, filters):
query = """
@@ -533,6 +558,7 @@ def get_purchase_invoices(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql(query, filters)
+
@frappe.whitelist()
def get_tax_template(doctype, txt, searchfield, start, page_len, filters):
@@ -556,3 +582,13 @@ def get_tax_template(doctype, txt, searchfield, start, page_len, filters):
taxes = _get_item_tax_template(args, taxes, for_validate=True)
return [(d,) for d in set(taxes)]
+
+
+def get_fields(doctype, fields=[]):
+ meta = frappe.get_meta(doctype)
+ fields.extend(meta.get_search_fields())
+
+ if meta.title_field and not meta.title_field.strip() in fields:
+ fields.insert(1, meta.title_field.strip())
+
+ return unique(fields)
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index de76e45cd11..b465a106f0e 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -69,17 +69,6 @@ status_map = {
["Cancelled", "eval:self.docstatus==2"],
["Closed", "eval:self.status=='Closed'"],
],
- "Purchase Invoice": [
- ["Draft", None],
- ["Submitted", "eval:self.docstatus==1"],
- ["Paid", "eval:self.outstanding_amount==0 and self.docstatus==1"],
- ["Return", "eval:self.is_return==1 and self.docstatus==1"],
- ["Debit Note Issued",
- "eval:self.outstanding_amount <= 0 and self.docstatus==1 and self.is_return==0 and get_value('Purchase Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1})"],
- ["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"],
- ["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"],
- ["Cancelled", "eval:self.docstatus==2"],
- ],
"Material Request": [
["Draft", None],
["Stopped", "eval:self.status == 'Stopped'"],
diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json
index 20ab51d44bc..6fef0c46437 100644
--- a/erpnext/crm/doctype/lead/lead.json
+++ b/erpnext/crm/doctype/lead/lead.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_events_in_timeline": 1,
"allow_import": 1,
"autoname": "naming_series:",
@@ -447,7 +448,7 @@
"idx": 5,
"image_field": "image",
"links": [],
- "modified": "2020-04-08 22:26:11.687110",
+ "modified": "2020-05-11 20:27:45.868960",
"modified_by": "Administrator",
"module": "CRM",
"name": "Lead",
@@ -504,15 +505,6 @@
"read": 1,
"report": 1,
"role": "Sales User"
- },
- {
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Guest",
- "share": 1
}
],
"search_fields": "lead_name,lead_owner,status",
diff --git a/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py b/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py
index bdde9eed379..377e061fdf4 100644
--- a/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py
+++ b/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py
@@ -15,7 +15,7 @@ class LinkedInSettings(Document):
params = urlencode({
"response_type":"code",
"client_id": self.consumer_key,
- "redirect_uri": get_site_url(frappe.local.site) + "/api/method/erpnext.crm.doctype.linkedin_settings.linkedin_settings.callback?",
+ "redirect_uri": "{0}/api/method/erpnext.crm.doctype.linkedin_settings.linkedin_settings.callback?".format(frappe.utils.get_url()),
"scope": "r_emailaddress w_organization_social r_basicprofile r_liteprofile r_organization_social rw_organization_admin w_member_social"
})
@@ -30,7 +30,7 @@ class LinkedInSettings(Document):
"code": code,
"client_id": self.consumer_key,
"client_secret": self.get_password(fieldname="consumer_secret"),
- "redirect_uri": get_site_url(frappe.local.site) + "/api/method/erpnext.crm.doctype.linkedin_settings.linkedin_settings.callback?",
+ "redirect_uri": "{0}/api/method/erpnext.crm.doctype.linkedin_settings.linkedin_settings.callback?".format(frappe.utils.get_url()),
}
headers = {
"Content-Type": "application/x-www-form-urlencoded"
diff --git a/erpnext/crm/doctype/twitter_settings/twitter_settings.json b/erpnext/crm/doctype/twitter_settings/twitter_settings.json
index f92e7f04955..36776e5c202 100644
--- a/erpnext/crm/doctype/twitter_settings/twitter_settings.json
+++ b/erpnext/crm/doctype/twitter_settings/twitter_settings.json
@@ -11,8 +11,8 @@
"consumer_key",
"column_break_5",
"consumer_secret",
- "oauth_token",
- "oauth_secret",
+ "access_token",
+ "access_token_secret",
"session_status"
],
"fields": [
@@ -41,20 +41,6 @@
"label": "API Secret Key",
"reqd": 1
},
- {
- "fieldname": "oauth_token",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "OAuth Token",
- "read_only": 1
- },
- {
- "fieldname": "oauth_secret",
- "fieldtype": "Password",
- "hidden": 1,
- "label": "OAuth Token Secret",
- "read_only": 1
- },
{
"fieldname": "column_break_5",
"fieldtype": "Column Break"
@@ -72,12 +58,26 @@
"label": "Session Status",
"options": "Expired\nActive",
"read_only": 1
+ },
+ {
+ "fieldname": "access_token",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Access Token",
+ "read_only": 1
+ },
+ {
+ "fieldname": "access_token_secret",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Access Token Secret",
+ "read_only": 1
}
],
"image_field": "profile_pic",
"issingle": 1,
"links": [],
- "modified": "2020-04-21 22:06:43.726798",
+ "modified": "2020-05-13 17:50:47.934776",
"modified_by": "Administrator",
"module": "CRM",
"name": "Twitter Settings",
diff --git a/erpnext/crm/doctype/twitter_settings/twitter_settings.py b/erpnext/crm/doctype/twitter_settings/twitter_settings.py
index 7616b4c027e..976a23dfc7d 100644
--- a/erpnext/crm/doctype/twitter_settings/twitter_settings.py
+++ b/erpnext/crm/doctype/twitter_settings/twitter_settings.py
@@ -31,13 +31,13 @@ class TwitterSettings(Document):
try:
auth.get_access_token(oauth_verifier)
- api = self.get_api()
+ api = self.get_api(auth.access_token, auth.access_token_secret)
user = api.me()
profile_pic = (user._json["profile_image_url"]).replace("_normal","")
frappe.db.set_value(self.doctype, self.name, {
- "oauth_token" : auth.access_token,
- "oauth_secret" : auth.access_token_secret,
+ "access_token" : auth.access_token,
+ "access_token_secret" : auth.access_token_secret,
"account_name" : user._json["screen_name"],
"profile_pic" : profile_pic,
"session_status" : "Active"
@@ -49,11 +49,11 @@ class TwitterSettings(Document):
frappe.msgprint(_("Error! Failed to get access token."))
frappe.throw(_('Invalid Consumer Key or Consumer Secret Key'))
- def get_api(self):
+ def get_api(self, access_token, access_token_secret):
# authentication of consumer key and secret
auth = tweepy.OAuthHandler(self.consumer_key, self.get_password(fieldname="consumer_secret"))
# authentication of access token and secret
- auth.set_access_token(self.oauth_token, self.get_password(fieldname="oauth_secret"))
+ auth.set_access_token(access_token, access_token_secret)
return tweepy.API(auth)
@@ -67,13 +67,13 @@ class TwitterSettings(Document):
def upload_image(self, media):
media = get_file_path(media)
- api = self.get_api()
+ api = self.get_api(self.access_token, self.access_token_secret)
media = api.media_upload(media)
return media.media_id
def send_tweet(self, text, media_id=None):
- api = self.get_api()
+ api = self.get_api(self.access_token, self.access_token_secret)
try:
if media_id:
response = api.update_status(status = text, media_ids = [media_id])
diff --git a/erpnext/education/doctype/fees/fees.py b/erpnext/education/doctype/fees/fees.py
index f0d60faed6f..25d67d2d5f6 100644
--- a/erpnext/education/doctype/fees/fees.py
+++ b/erpnext/education/doctype/fees/fees.py
@@ -98,14 +98,16 @@ class Fees(AccountsController):
"debit_in_account_currency": self.grand_total,
"against_voucher": self.name,
"against_voucher_type": self.doctype
- })
+ }, item=self)
+
fee_gl_entry = self.get_gl_dict({
"account": self.income_account,
"against": self.student,
"credit": self.grand_total,
"credit_in_account_currency": self.grand_total,
"cost_center": self.cost_center
- })
+ }, item=self)
+
from erpnext.accounts.general_ledger import make_gl_entries
make_gl_entries([student_gl_entries, fee_gl_entry], cancel=(self.docstatus == 2),
update_outstanding="Yes", merge_entries=False)
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
index b4a5bd11a04..a7062239c32 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
@@ -209,7 +209,7 @@ def new_bank_transaction(transaction):
result.append(new_transaction.name)
except Exception:
- frappe.throw(frappe.get_traceback())
+ frappe.throw(title=_('Bank transaction creation error'))
return result
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js
index 87c22ccf6f3..eb7d4bdebad 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js
@@ -43,7 +43,8 @@ frappe.ui.form.on('Clinical Procedure', {
return {
filters: {
'is_group': false,
- 'allow_appointments': true
+ 'allow_appointments': true,
+ 'company': frm.doc.company
}
};
});
@@ -158,11 +159,13 @@ frappe.ui.form.on('Clinical Procedure', {
age = __('{0} as on {1}', [age, data.message.age_as_on]);
}
}
+ frm.set_value('patient_name', data.message.patient_name);
frm.set_value('patient_age', age);
frm.set_value('patient_sex', data.message.sex);
}
});
} else {
+ frm.set_value('patient_name', '');
frm.set_value('patient_age', '');
frm.set_value('patient_sex', '');
}
@@ -177,15 +180,35 @@ frappe.ui.form.on('Clinical Procedure', {
name: frm.doc.appointment
},
callback: function(data) {
- frm.set_value('patient', data.message.patient);
- frm.set_value('procedure_template', data.message.procedure_template);
- frm.set_value('medical_department', data.message.department);
- frm.set_value('start_date', data.message.appointment_date);
- frm.set_value('start_time', data.message.appointment_time);
- frm.set_value('notes', data.message.notes);
- frm.set_value('service_unit', data.message.service_unit);
+ let values = {
+ 'patient':data.message.patient,
+ 'procedure_template': data.message.procedure_template,
+ 'medical_department': data.message.department,
+ 'practitioner': data.message.practitioner,
+ 'start_date': data.message.appointment_date,
+ 'start_time': data.message.appointment_time,
+ 'notes': data.message.notes,
+ 'service_unit': data.message.service_unit,
+ 'company': data.message.company
+ };
+ frm.set_value(values);
}
});
+ } else {
+ let values = {
+ 'patient': '',
+ 'patient_name': '',
+ 'patient_sex': '',
+ 'patient_age': '',
+ 'medical_department': '',
+ 'procedure_template': '',
+ 'start_date': '',
+ 'start_time': '',
+ 'notes': '',
+ 'service_unit': '',
+ 'inpatient_record': ''
+ };
+ frm.set_value(values);
}
},
@@ -234,9 +257,11 @@ frappe.ui.form.on('Clinical Procedure', {
name: frm.doc.practitioner
},
callback: function (data) {
- frappe.model.set_value(frm.doctype,frm.docname, 'medical_department',data.message.department);
+ frappe.model.set_value(frm.doctype,frm.docname, 'practitioner_name', data.message.practitioner_name);
}
});
+ } else {
+ frappe.model.set_value(frm.doctype,frm.docname, 'practitioner_name', '');
}
},
@@ -284,14 +309,6 @@ frappe.ui.form.on('Clinical Procedure', {
});
-cur_frm.set_query('procedure_template', function(doc) {
- return {
- filters: {
- 'medical_department': doc.medical_department
- }
- };
-});
-
frappe.ui.form.on('Clinical Procedure Item', {
qty: function(frm, cdt, cdn) {
let d = locals[cdt][cdn];
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json
index 3c936bbf277..eaf8d80ba8c 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json
@@ -7,28 +7,32 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "inpatient_record",
"naming_series",
- "procedure_template",
+ "title",
"appointment",
+ "procedure_template",
+ "column_break_30",
+ "company",
+ "invoiced",
+ "section_break_6",
"patient",
+ "patient_name",
"patient_sex",
"patient_age",
- "prescription",
- "medical_department",
- "practitioner",
+ "inpatient_record",
+ "notes",
"column_break_7",
"status",
+ "practitioner",
+ "practitioner_name",
+ "medical_department",
"service_unit",
- "warehouse",
"start_date",
"start_time",
"sample",
- "invoiced",
- "notes",
- "company",
"consumables_section",
"consume_stock",
+ "warehouse",
"items",
"section_break_24",
"invoice_separately_as_consumables",
@@ -36,6 +40,9 @@
"consumable_total_amount",
"column_break_27",
"consumption_details",
+ "sb_refs",
+ "column_break_34",
+ "prescription",
"amended_from"
],
"fields": [
@@ -56,15 +63,15 @@
{
"fieldname": "appointment",
"fieldtype": "Link",
- "in_list_view": 1,
+ "in_standard_filter": 1,
"label": "Appointment",
- "options": "Patient Appointment"
+ "options": "Patient Appointment",
+ "set_only_once": 1
},
{
- "fetch_from": "inpatient_record.patient",
"fieldname": "patient",
"fieldtype": "Link",
- "in_list_view": 1,
+ "in_standard_filter": 1,
"label": "Patient",
"options": "Patient",
"reqd": 1
@@ -88,17 +95,20 @@
"fieldtype": "Link",
"hidden": 1,
"label": "Procedure Prescription",
- "options": "Procedure Prescription"
+ "options": "Procedure Prescription",
+ "read_only": 1
},
{
"fieldname": "medical_department",
"fieldtype": "Link",
+ "in_standard_filter": 1,
"label": "Medical Department",
"options": "Medical Department"
},
{
"fieldname": "practitioner",
"fieldtype": "Link",
+ "in_standard_filter": 1,
"label": "Healthcare Practitioner",
"options": "Healthcare Practitioner"
},
@@ -208,6 +218,7 @@
"read_only": 1
},
{
+ "depends_on": "eval:!doc.__islocal",
"fieldname": "status",
"fieldtype": "Select",
"in_list_view": 1,
@@ -226,6 +237,8 @@
"read_only": 1
},
{
+ "collapsible": 1,
+ "collapsible_depends_on": "consume_stock",
"fieldname": "consumables_section",
"fieldtype": "Section Break",
"label": "Consumables"
@@ -237,11 +250,51 @@
{
"fieldname": "section_break_24",
"fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_30",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "sb_refs",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "patient_name",
+ "fieldtype": "Data",
+ "label": "Patient Name",
+ "read_only": 1
+ },
+ {
+ "fieldname": "practitioner_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Practitioner Name",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_34",
+ "fieldtype": "Column Break"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Title",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-03-02 11:44:27.970651",
+ "modified": "2020-04-27 21:36:23.796924",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Clinical Procedure",
@@ -257,11 +310,27 @@
"report": 1,
"role": "Nursing User",
"share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Physician",
+ "share": 1,
+ "submit": 1,
"write": 1
}
],
"restrict_to_domain": "Healthcare",
"sort_field": "modified",
"sort_order": "DESC",
+ "title_field": "title",
"track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
index b7d7a62a950..e55a1433a51 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
@@ -16,6 +16,7 @@ from frappe.model.mapper import get_mapped_doc
class ClinicalProcedure(Document):
def validate(self):
self.set_status()
+ self.set_title()
if self.consume_stock:
self.set_actual_qty()
@@ -37,7 +38,7 @@ class ClinicalProcedure(Document):
template = frappe.get_doc('Clinical Procedure Template', self.procedure_template)
if template.sample:
patient = frappe.get_doc('Patient', self.patient)
- sample_collection = create_sample_doc(template, patient, None)
+ sample_collection = create_sample_doc(template, patient, None, self.company)
frappe.db.set_value('Clinical Procedure', self.name, 'sample', sample_collection.name)
self.reload()
@@ -50,6 +51,9 @@ class ClinicalProcedure(Document):
elif self.docstatus == 2:
self.status = 'Cancelled'
+ def set_title(self):
+ self.title = _('{0} - {1}').format(self.patient_name or self.patient, self.procedure_template)[:100]
+
def complete_procedure(self):
if self.consume_stock and self.items:
stock_entry = make_stock_entry(self)
diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json
index fd5b6e12f66..cb747f95ef8 100644
--- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json
+++ b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json
@@ -1,6 +1,5 @@
{
"actions": [],
- "allow_copy": 1,
"allow_import": 1,
"allow_rename": 1,
"autoname": "naming_series:",
@@ -51,17 +50,20 @@
"fieldname": "first_name",
"fieldtype": "Data",
"label": "First Name",
+ "no_copy": 1,
"reqd": 1
},
{
"fieldname": "middle_name",
"fieldtype": "Data",
- "label": "Middle Name (Optional)"
+ "label": "Middle Name (Optional)",
+ "no_copy": 1
},
{
"fieldname": "last_name",
"fieldtype": "Data",
- "label": "Last Name"
+ "label": "Last Name",
+ "no_copy": 1
},
{
"fieldname": "image",
@@ -226,6 +228,7 @@
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Full Name",
+ "no_copy": 1,
"read_only": 1,
"search_index": 1
},
@@ -233,6 +236,7 @@
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Series",
+ "no_copy": 1,
"options": "HLC-PRAC-.YYYY.-",
"report_hide": 1,
"set_only_once": 1
diff --git a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json
index de086201795..2f0115c36a7 100644
--- a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json
+++ b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json
@@ -240,7 +240,7 @@
"label": "Patient Registration"
},
{
- "default": "Hello {{doc.patient}}, Thank you for registering with {{doc.company}}. Your ID is {{doc.id}} . Please note this ID for future reference. \nThank You, Get well soon!",
+ "default": "Hello {{doc.patient}}, Thank you for registering with {{doc.company}}. Your ID is {{doc.name}} . Please note this ID for future reference. \nThank You!",
"depends_on": "send_registration_msg",
"fieldname": "registration_msg",
"fieldtype": "Small Text",
@@ -254,7 +254,7 @@
"label": "Appointment Confirmation"
},
{
- "default": "Hello {{doc.patient}}, You have scheduled an appointment with {{doc.practitioner}} by {{doc.start_dt}} at {{doc.company}}.\nThank you, Good day!",
+ "default": "Hello {{doc.patient}}, You have scheduled an appointment with {{doc.practitioner}} on {{doc.appointment_datetime}} at {{doc.company}}.\nThank you, Good day!",
"depends_on": "send_appointment_confirmation",
"fieldname": "appointment_confirmation_msg",
"fieldtype": "Small Text",
@@ -276,7 +276,7 @@
"label": "Appointment Reminder"
},
{
- "default": "Hello {{doc.patient}}, You have an appointment with {{doc.practitioner}} by {{doc.appointment_time}} at {{doc.company}}.\nThank you, Good day!\n",
+ "default": "Hello {{doc.patient}}, You have an appointment with {{doc.practitioner}} by {{doc.appointment_datetime}} at {{doc.company}}.\nThank you, Good day!\n",
"depends_on": "send_appointment_reminder",
"fieldname": "appointment_reminder_msg",
"fieldtype": "Small Text",
diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json
index 92c11fbb4da..c1b516d5363 100644
--- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json
+++ b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json
@@ -1,980 +1,255 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2018-07-11 17:48:51.404139",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "autoname": "naming_series:",
+ "creation": "2018-07-11 17:48:51.404139",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "section_break_1",
+ "naming_series",
+ "patient",
+ "patient_name",
+ "gender",
+ "blood_group",
+ "dob",
+ "mobile",
+ "email",
+ "phone",
+ "column_break_8",
+ "company",
+ "status",
+ "scheduled_date",
+ "admitted_datetime",
+ "expected_discharge",
+ "discharge_date",
+ "references",
+ "cb_admission",
+ "admission_practitioner",
+ "admission_encounter",
+ "cb_discharge",
+ "discharge_practitioner",
+ "discharge_encounter",
+ "sb_inpatient_occupancy",
+ "inpatient_occupancies",
+ "btn_transfer",
+ "sb_discharge_note",
+ "discharge_note"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_1",
- "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
- },
+ "fieldname": "section_break_1",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "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",
- "length": 0,
- "no_copy": 0,
- "options": "HLC-INP-.YYYY.-",
- "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
- },
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "label": "Series",
+ "options": "HLC-INP-.YYYY.-"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "patient",
- "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": "Patient",
- "length": 0,
- "no_copy": 0,
- "options": "Patient",
- "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
- },
+ "fieldname": "patient",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Patient",
+ "options": "Patient",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "patient.patient_name",
- "fieldname": "patient_name",
- "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": "Patient Name",
- "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
- },
+ "fetch_from": "patient.patient_name",
+ "fieldname": "patient_name",
+ "fieldtype": "Data",
+ "label": "Patient Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "patient.sex",
- "fieldname": "gender",
- "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": "Gender",
- "length": 0,
- "no_copy": 0,
- "options": "Gender",
- "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
- },
+ "fetch_from": "patient.sex",
+ "fieldname": "gender",
+ "fieldtype": "Link",
+ "label": "Gender",
+ "options": "Gender",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "patient.blood_group",
- "fieldname": "blood_group",
- "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": "Blood Group",
- "length": 0,
- "no_copy": 0,
- "options": "\nA Positive\nA Negative\nAB Positive\nAB Negative\nB Positive\nB Negative\nO Positive\nO Negative",
- "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
- },
+ "fetch_from": "patient.blood_group",
+ "fieldname": "blood_group",
+ "fieldtype": "Select",
+ "label": "Blood Group",
+ "options": "\nA Positive\nA Negative\nAB Positive\nAB Negative\nB Positive\nB Negative\nO Positive\nO Negative",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "dob",
- "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": "Date of birth",
- "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
- },
+ "fetch_from": "patient.dob",
+ "fieldname": "dob",
+ "fieldtype": "Date",
+ "label": "Date of birth",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "patient.mobile",
- "fieldname": "mobile",
- "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": "Mobile",
- "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
- },
+ "fetch_from": "patient.mobile",
+ "fieldname": "mobile",
+ "fieldtype": "Data",
+ "label": "Mobile",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "patient.email",
- "fieldname": "email",
- "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": "Email",
- "length": 0,
- "no_copy": 0,
- "options": "Email",
- "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
- },
+ "fetch_from": "patient.email",
+ "fieldname": "email",
+ "fieldtype": "Data",
+ "label": "Email",
+ "options": "Email",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "patient.phone",
- "fieldname": "phone",
- "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": "Phone",
- "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
- },
+ "fetch_from": "patient.phone",
+ "fieldname": "phone",
+ "fieldtype": "Data",
+ "label": "Phone",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_8",
- "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
- },
+ "fieldname": "column_break_8",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "status",
- "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": "Status",
- "length": 0,
- "no_copy": 0,
- "options": "Admission Scheduled\nAdmitted\nDischarge Scheduled\nDischarged",
- "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
- },
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Status",
+ "options": "Admission Scheduled\nAdmitted\nDischarge Scheduled\nDischarged",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "fieldname": "scheduled_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": "Admission Schedule 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
- },
+ "default": "Today",
+ "fieldname": "scheduled_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Admission Schedule Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "fieldname": "admitted_datetime",
- "fieldtype": "Datetime",
- "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": "Admitted Datetime",
- "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
- },
+ "default": "Today",
+ "fieldname": "admitted_datetime",
+ "fieldtype": "Datetime",
+ "in_list_view": 1,
+ "label": "Admitted Datetime"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "expected_discharge",
- "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": "Expected Discharge",
- "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
- },
+ "fieldname": "expected_discharge",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Expected Discharge"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "discharge_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": "Discharge 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
- },
+ "fieldname": "discharge_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Discharge Date"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "references",
- "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": "References",
- "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
- },
+ "collapsible": 1,
+ "fieldname": "references",
+ "fieldtype": "Section Break",
+ "label": "References"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "cb_admission",
- "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,
- "label": "Admission",
- "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
- },
+ "fieldname": "cb_admission",
+ "fieldtype": "Column Break",
+ "label": "Admission"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "admission_practitioner",
- "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": "Healthcare Practitioner",
- "length": 0,
- "no_copy": 0,
- "options": "Healthcare Practitioner",
- "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
- },
+ "fieldname": "admission_practitioner",
+ "fieldtype": "Link",
+ "label": "Healthcare Practitioner",
+ "options": "Healthcare Practitioner",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "admission_encounter",
- "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": "Patient Encounter",
- "length": 0,
- "no_copy": 0,
- "options": "Patient Encounter",
- "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
- },
+ "fieldname": "admission_encounter",
+ "fieldtype": "Link",
+ "label": "Patient Encounter",
+ "options": "Patient Encounter",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "cb_discharge",
- "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,
- "label": "Discharge",
- "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
- },
+ "fieldname": "cb_discharge",
+ "fieldtype": "Column Break",
+ "label": "Discharge"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "discharge_practitioner",
- "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": "Healthcare Practitioner",
- "length": 0,
- "no_copy": 0,
- "options": "Healthcare Practitioner",
- "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
- },
+ "fieldname": "discharge_practitioner",
+ "fieldtype": "Link",
+ "label": "Healthcare Practitioner",
+ "options": "Healthcare Practitioner",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "discharge_encounter",
- "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": "Patient Encounter",
- "length": 0,
- "no_copy": 0,
- "options": "Patient Encounter",
- "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
- },
+ "fieldname": "discharge_encounter",
+ "fieldtype": "Link",
+ "label": "Patient Encounter",
+ "options": "Patient Encounter",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sb_inpatient_occupancy",
- "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": "Inpatient Occupancy",
- "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
- },
+ "fieldname": "sb_inpatient_occupancy",
+ "fieldtype": "Section Break",
+ "label": "Inpatient Occupancy"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "inpatient_occupancies",
- "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,
- "length": 0,
- "no_copy": 0,
- "options": "Inpatient Occupancy",
- "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
- },
+ "fieldname": "inpatient_occupancies",
+ "fieldtype": "Table",
+ "options": "Inpatient Occupancy",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "btn_transfer",
- "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": "Transfer",
- "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
- },
+ "fieldname": "btn_transfer",
+ "fieldtype": "Button",
+ "label": "Transfer"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.status != \"Admission Scheduled\"",
- "fieldname": "sb_discharge_note",
- "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": "Discharge Note",
- "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
- },
+ "depends_on": "eval:doc.status != \"Admission Scheduled\"",
+ "fieldname": "sb_discharge_note",
+ "fieldtype": "Section Break",
+ "label": "Discharge Note"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "discharge_note",
- "fieldtype": "Text Editor",
- "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": "",
- "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
+ "fieldname": "discharge_note",
+ "fieldtype": "Text Editor"
+ },
+ {
+ "fetch_from": "admission_encounter.company",
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Company",
+ "options": "Company"
}
- ],
- "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-08-21 14:44:43.168245",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Inpatient Record",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "links": [],
+ "modified": "2020-04-07 13:13:39.351977",
+ "modified_by": "Administrator",
+ "module": "Healthcare",
+ "name": "Inpatient Record",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 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": "Healthcare Administrator",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Healthcare Administrator",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "restrict_to_domain": "Healthcare",
- "search_fields": "patient",
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "patient",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
-}
+ ],
+ "restrict_to_domain": "Healthcare",
+ "search_fields": "patient",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "patient",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py b/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py
index e15324c55bf..4c2d3f692a2 100644
--- a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py
+++ b/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py
@@ -8,7 +8,6 @@ import unittest
from frappe.utils import now_datetime, today
from frappe.utils.make_random import get_random
from erpnext.healthcare.doctype.inpatient_record.inpatient_record import admit_patient, discharge_patient, schedule_discharge
-from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_patient
class TestInpatientRecord(unittest.TestCase):
def test_admit_and_discharge(self):
@@ -112,3 +111,13 @@ def get_service_unit_type():
service_unit_type.save(ignore_permissions = True)
return service_unit_type.name
return service_unit_type
+
+def create_patient():
+ patient = frappe.db.exists('Patient', '_Test IPD Patient')
+ if not patient:
+ patient = frappe.new_doc('Patient')
+ patient.first_name = '_Test IPD Patient'
+ patient.sex = 'Female'
+ patient.save(ignore_permissions=True)
+ patient = patient.name
+ return patient
diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.js b/erpnext/healthcare/doctype/lab_test/lab_test.js
index 5b3f4c705ad..bf1ecc87e4c 100644
--- a/erpnext/healthcare/doctype/lab_test/lab_test.js
+++ b/erpnext/healthcare/doctype/lab_test/lab_test.js
@@ -137,13 +137,13 @@ var get_lab_test_prescribed = function(frm){
});
}
else{
- frappe.msgprint(__("Please select Patient to get Lab Tests"));
+ frappe.msgprint(__("Please select a Patient to get Lab Tests"));
}
};
var show_lab_tests = function(frm, result){
var d = new frappe.ui.Dialog({
- title: __("Lab Test Prescriptions"),
+ title: __("Lab Tests"),
fields: [
{
fieldtype: "HTML", fieldname: "lab_test"
@@ -161,7 +161,7 @@ var show_lab_tests = function(frm, result){