Merge branch 'develop' into rename-bank-reco

This commit is contained in:
Saqib 2020-04-20 12:21:22 +05:30 committed by GitHub
commit b61d2411b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
286 changed files with 9947 additions and 17977 deletions

19
CODEOWNERS Normal file
View File

@ -0,0 +1,19 @@
# Each line is a file pattern followed by one or more owners.
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence,
* @nabinhait
manufacturing/ @rohitwaghchaure
accounts/ @deepeshgarg007 @nextchamp-saqib
loan_management/ @deepeshgarg007
pos* @nextchamp-saqib
assets/ @nextchamp-saqib
stock/ @marination @rohitwaghchaure
buying/ @marination @rohitwaghchaure
hr/ @Anurag810
projects/ @hrwX
support/ @hrwX
healthcare/ @ruchamahabal
erpnext_integrations/ @Mangesh-Khairnar
requirements.txt @gavindsouza

View File

@ -1,83 +1,96 @@
{ {
"cards": [ "cards": [
{ {
"links": "[\n {\n \"description\": \"Company (not Customer or Supplier) master.\",\n \"label\": \"Company\",\n \"name\": \"Company\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tree of financial accounts.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Chart of Accounts\",\n \"name\": \"Account\",\n \"onboard\": 1,\n \"route\": \"#Tree/Account\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounts Settings\",\n \"name\": \"Accounts Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Financial / accounting year.\",\n \"label\": \"Fiscal Year\",\n \"name\": \"Fiscal Year\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounting Dimension\",\n \"name\": \"Accounting Dimension\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Finance Book\",\n \"name\": \"Finance Book\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounting Period\",\n \"name\": \"Accounting Period\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Payment Terms based on conditions\",\n \"label\": \"Payment Term\",\n \"name\": \"Payment Term\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Accounting Masters" "label": "Accounting Masters",
"links": "[\n {\n \"description\": \"Company (not Customer or Supplier) master.\",\n \"label\": \"Company\",\n \"name\": \"Company\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tree of financial accounts.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Chart of Accounts\",\n \"name\": \"Account\",\n \"onboard\": 1,\n \"route\": \"#Tree/Account\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounts Settings\",\n \"name\": \"Accounts Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Financial / accounting year.\",\n \"label\": \"Fiscal Year\",\n \"name\": \"Fiscal Year\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounting Dimension\",\n \"name\": \"Accounting Dimension\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Finance Book\",\n \"name\": \"Finance Book\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounting Period\",\n \"name\": \"Accounting Period\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Payment Terms based on conditions\",\n \"label\": \"Payment Term\",\n \"name\": \"Payment Term\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"description\": \"Accounting journal entries.\",\n \"label\": \"Journal Entry\",\n \"name\": \"Journal Entry\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"General Ledger\",\n \"name\": \"General Ledger\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Customer Ledger Summary\",\n \"name\": \"Customer Ledger Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Supplier Ledger Summary\",\n \"name\": \"Supplier Ledger Summary\",\n \"type\": \"report\"\n }\n]", "hidden": 0,
"title": "General Ledger" "label": "General Ledger",
"links": "[\n {\n \"description\": \"Accounting journal entries.\",\n \"label\": \"Journal Entry\",\n \"name\": \"Journal Entry\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"General Ledger\",\n \"name\": \"General Ledger\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Customer Ledger Summary\",\n \"name\": \"Customer Ledger Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Supplier Ledger Summary\",\n \"name\": \"Supplier Ledger Summary\",\n \"type\": \"report\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"description\": \"Bills raised to Customers.\",\n \"label\": \"Sales Invoice\",\n \"name\": \"Sales Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Customer database.\",\n \"label\": \"Customer\",\n \"name\": \"Customer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bank/Cash transactions against party or for internal transfer\",\n \"label\": \"Payment Entry\",\n \"name\": \"Payment Entry\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Payment Request\",\n \"label\": \"Payment Request\",\n \"name\": \"Payment Request\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Receivable\",\n \"name\": \"Accounts Receivable\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Receivable Summary\",\n \"name\": \"Accounts Receivable Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Register\",\n \"name\": \"Sales Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Item-wise Sales Register\",\n \"name\": \"Item-wise Sales Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Ordered Items To Be Billed\",\n \"name\": \"Ordered Items To Be Billed\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Delivered Items To Be Billed\",\n \"name\": \"Delivered Items To Be Billed\",\n \"type\": \"report\"\n }\n]", "hidden": 0,
"title": "Accounts Receivable" "label": "Accounts Receivable",
"links": "[\n {\n \"description\": \"Bills raised to Customers.\",\n \"label\": \"Sales Invoice\",\n \"name\": \"Sales Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Customer database.\",\n \"label\": \"Customer\",\n \"name\": \"Customer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bank/Cash transactions against party or for internal transfer\",\n \"label\": \"Payment Entry\",\n \"name\": \"Payment Entry\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Payment Request\",\n \"label\": \"Payment Request\",\n \"name\": \"Payment Request\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Receivable\",\n \"name\": \"Accounts Receivable\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Receivable Summary\",\n \"name\": \"Accounts Receivable Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Register\",\n \"name\": \"Sales Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Item-wise Sales Register\",\n \"name\": \"Item-wise Sales Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Ordered Items To Be Billed\",\n \"name\": \"Ordered Items To Be Billed\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Delivered Items To Be Billed\",\n \"name\": \"Delivered Items To Be Billed\",\n \"type\": \"report\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"description\": \"Bills raised by Suppliers.\",\n \"label\": \"Purchase Invoice\",\n \"name\": \"Purchase Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Supplier database.\",\n \"label\": \"Supplier\",\n \"name\": \"Supplier\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bank/Cash transactions against party or for internal transfer\",\n \"label\": \"Payment Entry\",\n \"name\": \"Payment Entry\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Payable\",\n \"name\": \"Accounts Payable\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Payable Summary\",\n \"name\": \"Accounts Payable Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Register\",\n \"name\": \"Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Item-wise Purchase Register\",\n \"name\": \"Item-wise Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Order Items To Be Billed\",\n \"name\": \"Purchase Order Items To Be Billed\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Received Items To Be Billed\",\n \"name\": \"Received Items To Be Billed\",\n \"type\": \"report\"\n }\n]", "hidden": 0,
"title": "Accounts Payable" "label": "Accounts Payable",
"links": "[\n {\n \"description\": \"Bills raised by Suppliers.\",\n \"label\": \"Purchase Invoice\",\n \"name\": \"Purchase Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Supplier database.\",\n \"label\": \"Supplier\",\n \"name\": \"Supplier\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bank/Cash transactions against party or for internal transfer\",\n \"label\": \"Payment Entry\",\n \"name\": \"Payment Entry\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Payable\",\n \"name\": \"Accounts Payable\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Payable Summary\",\n \"name\": \"Accounts Payable Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Register\",\n \"name\": \"Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Item-wise Purchase Register\",\n \"name\": \"Item-wise Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Order Items To Be Billed\",\n \"name\": \"Purchase Order Items To Be Billed\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Received Items To Be Billed\",\n \"name\": \"Received Items To Be Billed\",\n \"type\": \"report\"\n }\n]"
}, },
{ {
"icon": "fa fa-table", "hidden": 0,
"links": "[\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Trial Balance for Party\",\n \"name\": \"Trial Balance for Party\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Journal Entry\"\n ],\n \"doctype\": \"Journal Entry\",\n \"is_query_report\": true,\n \"label\": \"Payment Period Based On Invoice Date\",\n \"name\": \"Payment Period Based On Invoice Date\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Partners Commission\",\n \"name\": \"Sales Partners Commission\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customer Credit Balance\",\n \"name\": \"Customer Credit Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Payment Summary\",\n \"name\": \"Sales Payment Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Address\"\n ],\n \"doctype\": \"Address\",\n \"is_query_report\": true,\n \"label\": \"Address And Contacts\",\n \"name\": \"Address And Contacts\",\n \"type\": \"report\"\n }\n]", "label": "Reports",
"title": "Reports" "links": "[\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Trial Balance for Party\",\n \"name\": \"Trial Balance for Party\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Journal Entry\"\n ],\n \"doctype\": \"Journal Entry\",\n \"is_query_report\": true,\n \"label\": \"Payment Period Based On Invoice Date\",\n \"name\": \"Payment Period Based On Invoice Date\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Partners Commission\",\n \"name\": \"Sales Partners Commission\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customer Credit Balance\",\n \"name\": \"Customer Credit Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Payment Summary\",\n \"name\": \"Sales Payment Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Address\"\n ],\n \"doctype\": \"Address\",\n \"is_query_report\": true,\n \"label\": \"Address And Contacts\",\n \"name\": \"Address And Contacts\",\n \"type\": \"report\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Trial Balance\",\n \"name\": \"Trial Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Profit and Loss Statement\",\n \"name\": \"Profit and Loss Statement\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Balance Sheet\",\n \"name\": \"Balance Sheet\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Cash Flow\",\n \"name\": \"Cash Flow\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Consolidated Financial Statement\",\n \"name\": \"Consolidated Financial Statement\",\n \"type\": \"report\"\n }\n]", "hidden": 0,
"title": "Financial Statements" "label": "Financial Statements",
"links": "[\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Trial Balance\",\n \"name\": \"Trial Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Profit and Loss Statement\",\n \"name\": \"Profit and Loss Statement\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Balance Sheet\",\n \"name\": \"Balance Sheet\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Cash Flow\",\n \"name\": \"Cash Flow\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Consolidated Financial Statement\",\n \"name\": \"Consolidated Financial Statement\",\n \"type\": \"report\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"description\": \"Enable / disable currencies.\",\n \"label\": \"Currency\",\n \"name\": \"Currency\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Currency exchange rate master.\",\n \"label\": \"Currency Exchange\",\n \"name\": \"Currency Exchange\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Exchange Rate Revaluation master.\",\n \"label\": \"Exchange Rate Revaluation\",\n \"name\": \"Exchange Rate Revaluation\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Multi Currency" "label": "Multi Currency",
"links": "[\n {\n \"description\": \"Enable / disable currencies.\",\n \"label\": \"Currency\",\n \"name\": \"Currency\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Currency exchange rate master.\",\n \"label\": \"Currency Exchange\",\n \"name\": \"Currency Exchange\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Exchange Rate Revaluation master.\",\n \"label\": \"Exchange Rate Revaluation\",\n \"name\": \"Exchange Rate Revaluation\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"icon": "fa fa-cog", "hidden": 0,
"links": "[\n {\n \"description\": \"Setup Gateway accounts.\",\n \"label\": \"Payment Gateway Account\",\n \"name\": \"Payment Gateway Account\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Template of terms or contract.\",\n \"label\": \"Terms and Conditions Template\",\n \"name\": \"Terms and Conditions\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"e.g. Bank, Cash, Credit Card\",\n \"label\": \"Mode of Payment\",\n \"name\": \"Mode of Payment\",\n \"type\": \"doctype\"\n }\n]", "label": "Settings",
"title": "Settings" "links": "[\n {\n \"description\": \"Setup Gateway accounts.\",\n \"label\": \"Payment Gateway Account\",\n \"name\": \"Payment Gateway Account\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Template of terms or contract.\",\n \"label\": \"Terms and Conditions Template\",\n \"name\": \"Terms and Conditions\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"e.g. Bank, Cash, Credit Card\",\n \"label\": \"Mode of Payment\",\n \"name\": \"Mode of Payment\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"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,
"title": "Bank Statement" "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]", "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" "title": "Banking and Payments"
}, },
{ {
"links": "[\n {\n \"label\": \"Subscription Plan\",\n \"name\": \"Subscription Plan\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Subscription\",\n \"name\": \"Subscription\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Subscription Settings\",\n \"name\": \"Subscription Settings\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Subscription Management" "label": "Subscription Management",
"links": "[\n {\n \"label\": \"Subscription Plan\",\n \"name\": \"Subscription Plan\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Subscription\",\n \"name\": \"Subscription\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Subscription Settings\",\n \"name\": \"Subscription Settings\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"label\": \"GST Settings\",\n \"name\": \"GST Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"GST HSN Code\",\n \"name\": \"GST HSN Code\",\n \"type\": \"doctype\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GSTR-1\",\n \"name\": \"GSTR-1\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GSTR-2\",\n \"name\": \"GSTR-2\",\n \"type\": \"report\"\n },\n {\n \"label\": \"GSTR 3B Report\",\n \"name\": \"GSTR 3B Report\",\n \"type\": \"doctype\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Sales Register\",\n \"name\": \"GST Sales Register\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Purchase Register\",\n \"name\": \"GST Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Itemised Sales Register\",\n \"name\": \"GST Itemised Sales Register\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Itemised Purchase Register\",\n \"name\": \"GST Itemised Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"country\": \"India\",\n \"description\": \"C-Form records\",\n \"label\": \"C-Form\",\n \"name\": \"C-Form\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Goods and Services Tax (GST India)" "label": "Goods and Services Tax (GST India)",
"links": "[\n {\n \"label\": \"GST Settings\",\n \"name\": \"GST Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"GST HSN Code\",\n \"name\": \"GST HSN Code\",\n \"type\": \"doctype\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GSTR-1\",\n \"name\": \"GSTR-1\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GSTR-2\",\n \"name\": \"GSTR-2\",\n \"type\": \"report\"\n },\n {\n \"label\": \"GSTR 3B Report\",\n \"name\": \"GSTR 3B Report\",\n \"type\": \"doctype\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Sales Register\",\n \"name\": \"GST Sales Register\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Purchase Register\",\n \"name\": \"GST Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Itemised Sales Register\",\n \"name\": \"GST Itemised Sales Register\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"GST Itemised Purchase Register\",\n \"name\": \"GST Itemised Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"country\": \"India\",\n \"description\": \"C-Form records\",\n \"label\": \"C-Form\",\n \"name\": \"C-Form\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"icon": "fa fa-microchip ", "hidden": 0,
"links": "[\n {\n \"description\": \"List of available Shareholders with folio numbers\",\n \"label\": \"Shareholder\",\n \"name\": \"Shareholder\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"List of all share transactions\",\n \"label\": \"Share Transfer\",\n \"name\": \"Share Transfer\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Share Transfer\"\n ],\n \"doctype\": \"Share Transfer\",\n \"is_query_report\": true,\n \"label\": \"Share Ledger\",\n \"name\": \"Share Ledger\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Share Transfer\"\n ],\n \"doctype\": \"Share Transfer\",\n \"is_query_report\": true,\n \"label\": \"Share Balance\",\n \"name\": \"Share Balance\",\n \"type\": \"report\"\n }\n]", "label": "Share Management",
"title": "Share Management" "links": "[\n {\n \"description\": \"List of available Shareholders with folio numbers\",\n \"label\": \"Shareholder\",\n \"name\": \"Shareholder\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"List of all share transactions\",\n \"label\": \"Share Transfer\",\n \"name\": \"Share Transfer\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Share Transfer\"\n ],\n \"doctype\": \"Share Transfer\",\n \"is_query_report\": true,\n \"label\": \"Share Ledger\",\n \"name\": \"Share Ledger\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Share Transfer\"\n ],\n \"doctype\": \"Share Transfer\",\n \"is_query_report\": true,\n \"label\": \"Share Balance\",\n \"name\": \"Share Balance\",\n \"type\": \"report\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"description\": \"Tree of financial Cost Centers.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Chart of Cost Centers\",\n \"name\": \"Cost Center\",\n \"route\": \"#Tree/Cost Center\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Define budget for a financial year.\",\n \"label\": \"Budget\",\n \"name\": \"Budget\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounting Dimension\",\n \"name\": \"Accounting Dimension\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Cost Center\"\n ],\n \"doctype\": \"Cost Center\",\n \"is_query_report\": true,\n \"label\": \"Budget Variance Report\",\n \"name\": \"Budget Variance Report\",\n \"type\": \"report\"\n },\n {\n \"description\": \"Seasonality for setting budgets, targets etc.\",\n \"label\": \"Monthly Distribution\",\n \"name\": \"Monthly Distribution\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Cost Center and Budgeting" "label": "Cost Center and Budgeting",
"links": "[\n {\n \"description\": \"Tree of financial Cost Centers.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Chart of Cost Centers\",\n \"name\": \"Cost Center\",\n \"route\": \"#Tree/Cost Center\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Define budget for a financial year.\",\n \"label\": \"Budget\",\n \"name\": \"Budget\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Accounting Dimension\",\n \"name\": \"Accounting Dimension\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Cost Center\"\n ],\n \"doctype\": \"Cost Center\",\n \"is_query_report\": true,\n \"label\": \"Budget Variance Report\",\n \"name\": \"Budget Variance Report\",\n \"type\": \"report\"\n },\n {\n \"description\": \"Seasonality for setting budgets, targets etc.\",\n \"label\": \"Monthly Distribution\",\n \"name\": \"Monthly Distribution\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"label\": \"Opening Invoice Creation Tool\",\n \"name\": \"Opening Invoice Creation Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Chart of Accounts Importer\",\n \"name\": \"Chart of Accounts Importer\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Close Balance Sheet and book Profit or Loss.\",\n \"label\": \"Period Closing Voucher\",\n \"name\": \"Period Closing Voucher\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Opening and Closing" "label": "Opening and Closing",
"links": "[\n {\n \"label\": \"Opening Invoice Creation Tool\",\n \"name\": \"Opening Invoice Creation Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Chart of Accounts Importer\",\n \"name\": \"Chart of Accounts Importer\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Close Balance Sheet and book Profit or Loss.\",\n \"label\": \"Period Closing Voucher\",\n \"name\": \"Period Closing Voucher\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"description\": \"Tax template for selling transactions.\",\n \"label\": \"Sales Taxes and Charges Template\",\n \"name\": \"Sales Taxes and Charges Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax template for buying transactions.\",\n \"label\": \"Purchase Taxes and Charges Template\",\n \"name\": \"Purchase Taxes and Charges Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax template for item tax rates.\",\n \"label\": \"Item Tax Template\",\n \"name\": \"Item Tax Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax Category for overriding tax rates.\",\n \"label\": \"Tax Category\",\n \"name\": \"Tax Category\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax Rule for transactions.\",\n \"label\": \"Tax Rule\",\n \"name\": \"Tax Rule\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax Withholding rates to be applied on transactions.\",\n \"label\": \"Tax Withholding Category\",\n \"name\": \"Tax Withholding Category\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Taxes" "label": "Taxes",
"links": "[\n {\n \"description\": \"Tax template for selling transactions.\",\n \"label\": \"Sales Taxes and Charges Template\",\n \"name\": \"Sales Taxes and Charges Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax template for buying transactions.\",\n \"label\": \"Purchase Taxes and Charges Template\",\n \"name\": \"Purchase Taxes and Charges Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax template for item tax rates.\",\n \"label\": \"Item Tax Template\",\n \"name\": \"Item Tax Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax Category for overriding tax rates.\",\n \"label\": \"Tax Category\",\n \"name\": \"Tax Category\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax Rule for transactions.\",\n \"label\": \"Tax Rule\",\n \"name\": \"Tax Rule\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax Withholding rates to be applied on transactions.\",\n \"label\": \"Tax Withholding Category\",\n \"name\": \"Tax Withholding Category\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Gross Profit\",\n \"name\": \"Gross Profit\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Profitability Analysis\",\n \"name\": \"Profitability Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Invoice Trends\",\n \"name\": \"Sales Invoice Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Invoice Trends\",\n \"name\": \"Purchase Invoice Trends\",\n \"type\": \"report\"\n }\n]", "hidden": 0,
"title": "Profitability" "label": "Profitability",
"links": "[\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Gross Profit\",\n \"name\": \"Gross Profit\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Profitability Analysis\",\n \"name\": \"Profitability Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Invoice Trends\",\n \"name\": \"Sales Invoice Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Invoice Trends\",\n \"name\": \"Purchase Invoice Trends\",\n \"type\": \"report\"\n }\n]"
} }
], ],
"category": "Modules", "category": "Modules",
"charts": [ "charts": [
{ {
"chart_name": "Bank Balance", "chart_name": "Bank Balance",
"label": "Bank Balance", "label": "Bank Balance"
"size": "Full"
} }
], ],
"creation": "2020-03-02 15:41:59.515192", "creation": "2020-03-02 15:41:59.515192",
@ -90,7 +103,7 @@
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "Accounting", "label": "Accounting",
"modified": "2020-03-12 16:30:35.580450", "modified": "2020-04-01 11:28:50.925719",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Accounting", "name": "Accounting",
@ -99,37 +112,37 @@
"pin_to_top": 0, "pin_to_top": 0,
"shortcuts": [ "shortcuts": [
{ {
"is_query_report": 0, "label": "Account",
"link_to": "Account", "link_to": "Account",
"type": "DocType" "type": "DocType"
}, },
{ {
"is_query_report": 0, "label": "Journal Entry",
"link_to": "Journal Entry", "link_to": "Journal Entry",
"type": "DocType" "type": "DocType"
}, },
{ {
"is_query_report": 0, "label": "Payment Entry",
"link_to": "Payment Entry", "link_to": "Payment Entry",
"type": "DocType" "type": "DocType"
}, },
{ {
"is_query_report": 1, "label": "Accounts Receivable",
"link_to": "Accounts Receivable", "link_to": "Accounts Receivable",
"type": "Report" "type": "Report"
}, },
{ {
"is_query_report": 0, "label": "General Ledger",
"link_to": "General Ledger", "link_to": "General Ledger",
"type": "Report" "type": "Report"
}, },
{ {
"is_query_report": 0, "label": "Profit and Loss Statement",
"link_to": "Profit and Loss Statement", "link_to": "Profit and Loss Statement",
"type": "Report" "type": "Report"
}, },
{ {
"is_query_report": 0, "label": "Trial Balance",
"link_to": "Trial Balance", "link_to": "Trial Balance",
"type": "Report" "type": "Report"
} }

View File

@ -89,7 +89,7 @@ class Account(NestedSet):
throw(_("Root cannot be edited."), RootNotEditable) throw(_("Root cannot be edited."), RootNotEditable)
if not self.parent_account and not self.is_group: if not self.parent_account and not self.is_group:
frappe.throw(_("Root Account must be a group")) frappe.throw(_("The root account {0} must be a group").format(frappe.bold(self.name)))
def validate_root_company_and_sync_account_to_children(self): def validate_root_company_and_sync_account_to_children(self):
# ignore validation while creating new compnay or while syncing to child companies # ignore validation while creating new compnay or while syncing to child companies

View File

@ -1,7 +1,7 @@
frappe.provide("frappe.treeview_settings") frappe.provide("frappe.treeview_settings")
frappe.treeview_settings["Account"] = { frappe.treeview_settings["Account"] = {
breadcrumbs: "Accounts", breadcrumb: "Accounts",
title: __("Chart Of Accounts"), title: __("Chart Of Accounts"),
get_tree_root: false, get_tree_root: false,
filters: [ filters: [

View File

@ -69,6 +69,7 @@ class TestAccount(unittest.TestCase):
acc.account_name = "Accumulated Depreciation" acc.account_name = "Accumulated Depreciation"
acc.parent_account = "Fixed Assets - _TC" acc.parent_account = "Fixed Assets - _TC"
acc.company = "_Test Company" acc.company = "_Test Company"
acc.account_type = "Accumulated Depreciation"
acc.insert() acc.insert()
doc = frappe.get_doc("Account", "Securities and Deposits - _TC") doc = frappe.get_doc("Account", "Securities and Deposits - _TC")
@ -149,7 +150,7 @@ def _make_test_records(verbose):
# fixed asset depreciation # fixed asset depreciation
["_Test Fixed Asset", "Current Assets", 0, "Fixed Asset", None], ["_Test Fixed Asset", "Current Assets", 0, "Fixed Asset", None],
["_Test Accumulated Depreciations", "Current Assets", 0, None, None], ["_Test Accumulated Depreciations", "Current Assets", 0, "Accumulated Depreciation", None],
["_Test Depreciations", "Expenses", 0, None, None], ["_Test Depreciations", "Expenses", 0, None, None],
["_Test Gain/Loss on Asset Disposal", "Expenses", 0, None, None], ["_Test Gain/Loss on Asset Disposal", "Expenses", 0, None, None],

View File

@ -193,7 +193,7 @@ def get_dimension_with_children(doctype, dimension):
all_dimensions = [] all_dimensions = []
lft, rgt = frappe.db.get_value(doctype, dimension, ["lft", "rgt"]) lft, rgt = frappe.db.get_value(doctype, dimension, ["lft", "rgt"])
children = frappe.get_all(doctype, filters={"lft": [">=", lft], "rgt": ["<=", rgt]}) children = frappe.get_all(doctype, filters={"lft": [">=", lft], "rgt": ["<=", rgt]}, order_by="lft")
all_dimensions += [c.name for c in children] all_dimensions += [c.name for c in children]
return all_dimensions return all_dimensions

View File

@ -152,10 +152,9 @@ def build_forest(data):
return [parent_account] return [parent_account]
elif account_name == child: elif account_name == child:
parent_account_list = return_parent(data, parent_account) parent_account_list = return_parent(data, parent_account)
if not parent_account_list: if not parent_account_list and parent_account:
frappe.throw(_("The parent account {0} does not exists in the uploaded template").format( frappe.throw(_("The parent account {0} does not exists in the uploaded template").format(
frappe.bold(parent_account))) frappe.bold(parent_account)))
return [child] + parent_account_list return [child] + parent_account_list
charts_map, paths = {}, [] charts_map, paths = {}, []
@ -164,7 +163,7 @@ def build_forest(data):
error_messages = [] error_messages = []
for i in data: for i in data:
account_name, _, account_number, is_group, account_type, root_type = i account_name, dummy, account_number, is_group, account_type, root_type = i
if not account_name: if not account_name:
error_messages.append("Row {0}: Please enter Account Name".format(line_no)) error_messages.append("Row {0}: Please enter Account Name".format(line_no))

View File

@ -1,5 +1,5 @@
frappe.treeview_settings["Cost Center"] = { frappe.treeview_settings["Cost Center"] = {
breadcrumbs: "Accounts", breadcrumb: "Accounts",
get_tree_root: false, get_tree_root: false,
filters: [{ filters: [{
fieldname: "company", fieldname: "company",

View File

@ -156,8 +156,11 @@ frappe.ui.form.on('Payment Entry', {
frm.toggle_display("base_paid_amount", frm.doc.paid_from_account_currency != company_currency); frm.toggle_display("base_paid_amount", frm.doc.paid_from_account_currency != company_currency);
frm.toggle_display("base_received_amount", (frm.doc.paid_to_account_currency != company_currency && frm.toggle_display("base_received_amount", (
frm.doc.paid_from_account_currency != frm.doc.paid_to_account_currency)); frm.doc.paid_to_account_currency != company_currency
&& frm.doc.paid_from_account_currency != frm.doc.paid_to_account_currency
&& frm.doc.base_paid_amount != frm.doc.base_received_amount
));
frm.toggle_display("received_amount", (frm.doc.payment_type=="Internal Transfer" || frm.toggle_display("received_amount", (frm.doc.payment_type=="Internal Transfer" ||
frm.doc.paid_from_account_currency != frm.doc.paid_to_account_currency)) frm.doc.paid_from_account_currency != frm.doc.paid_to_account_currency))
@ -501,6 +504,7 @@ frappe.ui.form.on('Payment Entry', {
paid_amount: function(frm) { paid_amount: function(frm) {
frm.set_value("base_paid_amount", flt(frm.doc.paid_amount) * flt(frm.doc.source_exchange_rate)); frm.set_value("base_paid_amount", flt(frm.doc.paid_amount) * flt(frm.doc.source_exchange_rate));
frm.trigger("reset_received_amount"); frm.trigger("reset_received_amount");
frm.events.hide_unhide_fields(frm);
}, },
received_amount: function(frm) { received_amount: function(frm) {
@ -524,6 +528,7 @@ frappe.ui.form.on('Payment Entry', {
frm.events.set_unallocated_amount(frm); frm.events.set_unallocated_amount(frm);
frm.set_paid_amount_based_on_received_amount = false; frm.set_paid_amount_based_on_received_amount = false;
frm.events.hide_unhide_fields(frm);
}, },
reset_received_amount: function(frm) { reset_received_amount: function(frm) {

View File

@ -81,8 +81,13 @@ class PaymentEntry(AccountsController):
self.update_advance_paid() self.update_advance_paid()
self.update_expense_claim() self.update_expense_claim()
self.delink_advance_entry_references() self.delink_advance_entry_references()
self.set_payment_req_status()
self.set_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)
def update_outstanding_amounts(self): def update_outstanding_amounts(self):
self.set_missing_ref_details(force=True) self.set_missing_ref_details(force=True)

View File

@ -15,11 +15,11 @@ frappe.ui.form.on('Payment Order', {
if (frm.doc.docstatus == 0) { if (frm.doc.docstatus == 0) {
frm.add_custom_button(__('Payment Request'), function() { frm.add_custom_button(__('Payment Request'), function() {
frm.trigger("get_from_payment_request"); frm.trigger("get_from_payment_request");
}, __("Get from")); }, __("Get Payments from"));
frm.add_custom_button(__('Payment Entry'), function() { frm.add_custom_button(__('Payment Entry'), function() {
frm.trigger("get_from_payment_entry"); frm.trigger("get_from_payment_entry");
}, __("Get from")); }, __("Get Payments from"));
frm.trigger('remove_button'); frm.trigger('remove_button');
} }

View File

@ -59,7 +59,6 @@
"fieldtype": "Section Break" "fieldtype": "Section Break"
}, },
{ {
"allow_bulk_edit": 1,
"fieldname": "references", "fieldname": "references",
"fieldtype": "Table", "fieldtype": "Table",
"label": "Payment Order Reference", "label": "Payment Order Reference",
@ -108,7 +107,7 @@
} }
], ],
"is_submittable": 1, "is_submittable": 1,
"modified": "2019-05-14 17:12:24.912666", "modified": "2020-04-06 18:00:56.022642",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Payment Order", "name": "Payment Order",

File diff suppressed because it is too large Load Diff

View File

@ -66,6 +66,8 @@ class PaymentRequest(Document):
if self.payment_request_type == 'Outward': if self.payment_request_type == 'Outward':
self.db_set('status', 'Initiated') self.db_set('status', 'Initiated')
return return
elif self.payment_request_type == 'Inward':
self.db_set('status', 'Requested')
send_mail = self.payment_gateway_validation() send_mail = self.payment_gateway_validation()
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name) ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
@ -88,6 +90,7 @@ class PaymentRequest(Document):
if (hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart"): if (hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart"):
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
si = make_sales_invoice(self.reference_name, ignore_permissions=True) si = make_sales_invoice(self.reference_name, ignore_permissions=True)
si.allocate_advances_automatically = True
si = si.insert(ignore_permissions=True) si = si.insert(ignore_permissions=True)
si.submit() si.submit()
@ -415,16 +418,30 @@ def make_payment_entry(docname):
doc = frappe.get_doc("Payment Request", docname) doc = frappe.get_doc("Payment Request", docname)
return doc.create_payment_entry(submit=False).as_dict() return doc.create_payment_entry(submit=False).as_dict()
def make_status_as_paid(doc, method): def update_payment_req_status(doc, method):
from erpnext.accounts.doctype.payment_entry.payment_entry import get_reference_details
for ref in doc.references: for ref in doc.references:
payment_request_name = frappe.db.get_value("Payment Request", payment_request_name = frappe.db.get_value("Payment Request",
{"reference_doctype": ref.reference_doctype, "reference_name": ref.reference_name, {"reference_doctype": ref.reference_doctype, "reference_name": ref.reference_name,
"docstatus": 1}) "docstatus": 1})
if payment_request_name: if payment_request_name:
doc = frappe.get_doc("Payment Request", payment_request_name) ref_details = get_reference_details(ref.reference_doctype, ref.reference_name, doc.party_account_currency)
if doc.status != "Paid": pay_req_doc = frappe.get_doc('Payment Request', payment_request_name)
doc.db_set('status', 'Paid') status = pay_req_doc.status
if status != "Paid" and not ref_details.outstanding_amount:
status = 'Paid'
elif status != "Partially Paid" and ref_details.outstanding_amount != ref_details.total_amount:
status = 'Partially Paid'
elif ref_details.outstanding_amount == ref_details.total_amount:
if pay_req_doc.payment_request_type == 'Outward':
status = 'Initiated'
elif pay_req_doc.payment_request_type == 'Inward':
status = 'Requested'
pay_req_doc.db_set('status', status)
frappe.db.commit() frappe.db.commit()
def get_dummy_message(doc): def get_dummy_message(doc):

View File

@ -4,14 +4,20 @@ frappe.listview_settings['Payment Request'] = {
if(doc.status == "Draft") { if(doc.status == "Draft") {
return [__("Draft"), "darkgrey", "status,=,Draft"]; return [__("Draft"), "darkgrey", "status,=,Draft"];
} }
if(doc.status == "Requested") {
return [__("Requested"), "green", "status,=,Requested"];
}
else if(doc.status == "Initiated") { else if(doc.status == "Initiated") {
return [__("Initiated"), "green", "status,=,Initiated"]; return [__("Initiated"), "green", "status,=,Initiated"];
} }
else if(doc.status == "Partially Paid") {
return [__("Partially Paid"), "orange", "status,=,Partially Paid"];
}
else if(doc.status == "Paid") { else if(doc.status == "Paid") {
return [__("Paid"), "blue", "status,=,Paid"]; return [__("Paid"), "blue", "status,=,Paid"];
} }
else if(doc.status == "Cancelled") { else if(doc.status == "Cancelled") {
return [__("Cancelled"), "orange", "status,=,Cancelled"]; return [__("Cancelled"), "red", "status,=,Cancelled"];
} }
} }
} }

View File

@ -101,6 +101,23 @@ class TestPaymentRequest(unittest.TestCase):
self.assertEqual(expected_gle[gle.account][2], gle.credit) self.assertEqual(expected_gle[gle.account][2], gle.credit)
self.assertEqual(expected_gle[gle.account][3], gle.against_voucher) self.assertEqual(expected_gle[gle.account][3], gle.against_voucher)
def test_status(self):
si_usd = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
currency="USD", conversion_rate=50)
pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com",
mute_email=1, payment_gateway="_Test Gateway - USD", submit_doc=1, return_doc=1)
pe = pr.create_payment_entry()
pr.load_from_db()
self.assertEqual(pr.status, 'Paid')
pe.cancel()
pr.load_from_db()
self.assertEqual(pr.status, 'Requested')
def test_multiple_payment_entries_against_sales_order(self): def test_multiple_payment_entries_against_sales_order(self):
# Make Sales Order, grand_total = 1000 # Make Sales Order, grand_total = 1000
so = make_sales_order() so = make_sales_order()

View File

@ -178,7 +178,8 @@ def filter_pricing_rules(args, pricing_rules, doc=None):
if pricing_rules[0].mixed_conditions and doc: if pricing_rules[0].mixed_conditions and doc:
stock_qty, amount, items = get_qty_and_rate_for_mixed_conditions(doc, pr_doc, args) stock_qty, amount, items = get_qty_and_rate_for_mixed_conditions(doc, pr_doc, args)
pricing_rules[0].apply_rule_on_other_items = items for pricing_rule_args in pricing_rules:
pricing_rule_args.apply_rule_on_other_items = items
elif pricing_rules[0].is_cumulative: elif pricing_rules[0].is_cumulative:
items = [args.get(frappe.scrub(pr_doc.get('apply_on')))] items = [args.get(frappe.scrub(pr_doc.get('apply_on')))]
@ -329,9 +330,9 @@ def get_qty_and_rate_for_mixed_conditions(doc, pr_doc, args):
if pr_doc.mixed_conditions: if pr_doc.mixed_conditions:
amt = args.get('qty') * args.get("price_list_rate") amt = args.get('qty') * args.get("price_list_rate")
if args.get("item_code") != row.get("item_code"): if args.get("item_code") != row.get("item_code"):
amt = row.get('qty') * row.get("price_list_rate") amt = row.get('qty') * (row.get("price_list_rate") or args.get("rate"))
sum_qty += row.get("stock_qty") or args.get("stock_qty") sum_qty += row.get("stock_qty") or args.get("stock_qty") or args.get("qty")
sum_amt += amt sum_amt += amt
if pr_doc.is_cumulative: if pr_doc.is_cumulative:

View File

@ -174,7 +174,8 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
read_only: 0, read_only: 0,
fieldtype:'Date', fieldtype:'Date',
label: __('Release Date'), label: __('Release Date'),
default: me.frm.doc.release_date default: me.frm.doc.release_date,
reqd: 1
}, },
{ {
fieldname: 'hold_comment', fieldname: 'hold_comment',

View File

@ -73,9 +73,9 @@
"base_total", "base_total",
"base_net_total", "base_net_total",
"column_break_28", "column_break_28",
"total_net_weight",
"total", "total",
"net_total", "net_total",
"total_net_weight",
"taxes_section", "taxes_section",
"tax_category", "tax_category",
"column_break_49", "column_break_49",
@ -1298,7 +1298,7 @@
"idx": 204, "idx": 204,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2019-12-30 19:13:49.610538", "modified": "2020-04-17 13:05:25.199832",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Invoice", "name": "Purchase Invoice",

View File

@ -754,8 +754,7 @@
{ {
"fieldname": "manufacturer_part_no", "fieldname": "manufacturer_part_no",
"fieldtype": "Data", "fieldtype": "Data",
"label": "Manufacturer Part Number", "label": "Manufacturer Part Number"
"read_only": 1
}, },
{ {
"depends_on": "is_fixed_asset", "depends_on": "is_fixed_asset",
@ -777,7 +776,7 @@
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2020-04-01 14:20:17.297284", "modified": "2020-04-07 18:34:35.104178",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Invoice Item", "name": "Purchase Invoice Item",

View File

@ -794,7 +794,7 @@ frappe.ui.form.on('Sales Invoice', {
}, },
refresh: function(frm) { refresh: function(frm) {
if (frappe.boot.active_domains.includes("Healthcare")){ if (frappe.boot.active_domains.includes("Healthcare")) {
frm.set_df_property("patient", "hidden", 0); frm.set_df_property("patient", "hidden", 0);
frm.set_df_property("patient_name", "hidden", 0); frm.set_df_property("patient_name", "hidden", 0);
frm.set_df_property("ref_practitioner", "hidden", 0); frm.set_df_property("ref_practitioner", "hidden", 0);
@ -807,7 +807,7 @@ frappe.ui.form.on('Sales Invoice', {
},"Get items from"); },"Get items from");
} }
} }
else{ else {
frm.set_df_property("patient", "hidden", 1); frm.set_df_property("patient", "hidden", 1);
frm.set_df_property("patient_name", "hidden", 1); frm.set_df_property("patient_name", "hidden", 1);
frm.set_df_property("ref_practitioner", "hidden", 1); frm.set_df_property("ref_practitioner", "hidden", 1);

View File

@ -1,4 +1,5 @@
{ {
"actions": [],
"allow_import": 1, "allow_import": 1,
"autoname": "naming_series:", "autoname": "naming_series:",
"creation": "2013-05-24 19:29:05", "creation": "2013-05-24 19:29:05",
@ -74,9 +75,9 @@
"base_total", "base_total",
"base_net_total", "base_net_total",
"column_break_32", "column_break_32",
"total_net_weight",
"total", "total",
"net_total", "net_total",
"total_net_weight",
"taxes_section", "taxes_section",
"taxes_and_charges", "taxes_and_charges",
"column_break_38", "column_break_38",
@ -1577,7 +1578,8 @@
"icon": "fa fa-file-text", "icon": "fa fa-file-text",
"idx": 181, "idx": 181,
"is_submittable": 1, "is_submittable": 1,
"modified": "2020-02-10 04:57:11.221180", "links": [],
"modified": "2020-04-17 12:38:41.435728",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Sales Invoice", "name": "Sales Invoice",

View File

@ -440,11 +440,12 @@ class SalesInvoice(SellingController):
if pos.get("company_address"): if pos.get("company_address"):
self.company_address = pos.get("company_address") self.company_address = pos.get("company_address")
if self.customer:
customer_price_list, customer_group = frappe.get_value("Customer", self.customer, ['default_price_list', 'customer_group']) customer_price_list, customer_group = frappe.get_value("Customer", self.customer, ['default_price_list', 'customer_group'])
customer_group_price_list = frappe.get_value("Customer Group", customer_group, 'default_price_list') customer_group_price_list = frappe.get_value("Customer Group", customer_group, 'default_price_list')
selling_price_list = customer_price_list or customer_group_price_list or pos.get('selling_price_list') selling_price_list = customer_price_list or customer_group_price_list or pos.get('selling_price_list')
else:
selling_price_list = pos.get('selling_price_list')
if selling_price_list: if selling_price_list:
self.set('selling_price_list', selling_price_list) self.set('selling_price_list', selling_price_list)

View File

@ -1948,7 +1948,7 @@ def create_sales_invoice(**args):
"gst_hsn_code": "999800", "gst_hsn_code": "999800",
"warehouse": args.warehouse or "_Test Warehouse - _TC", "warehouse": args.warehouse or "_Test Warehouse - _TC",
"qty": args.qty or 1, "qty": args.qty or 1,
"rate": args.rate or 100, "rate": args.rate if args.get("rate") is not None else 100,
"income_account": args.income_account or "Sales - _TC", "income_account": args.income_account or "Sales - _TC",
"expense_account": args.expense_account or "Cost of Goods Sold - _TC", "expense_account": args.expense_account or "Cost of Goods Sold - _TC",
"cost_center": args.cost_center or "_Test Cost Center - _TC", "cost_center": args.cost_center or "_Test Cost Center - _TC",

View File

@ -82,7 +82,7 @@ class ShippingRule(Document):
if not shipping_country: if not shipping_country:
frappe.throw(_('Shipping Address does not have country, which is required for this Shipping Rule')) frappe.throw(_('Shipping Address does not have country, which is required for this Shipping Rule'))
if shipping_country not in [d.country for d in self.countries]: if shipping_country not in [d.country for d in self.countries]:
frappe.throw(_('Shipping rule not applicable for country {0}').format(shipping_country)) frappe.throw(_('Shipping rule not applicable for country {0} in Shipping Address').format(shipping_country))
def add_shipping_rule_to_tax_table(self, doc, shipping_amount): def add_shipping_rule_to_tax_table(self, doc, shipping_amount):
shipping_charge = { shipping_charge = {

View File

@ -163,7 +163,8 @@ def set_price_list(party_details, party, party_type, given_price_list, pos=None)
# price list # price list
price_list = get_permitted_documents('Price List') price_list = get_permitted_documents('Price List')
if price_list: # if there is only one permitted document based on user permissions, set it
if price_list and len(price_list) == 1:
price_list = price_list[0] price_list = price_list[0]
elif pos and party_type == 'Customer': elif pos and party_type == 'Customer':
customer_price_list = frappe.get_value('Customer', party.name, 'default_price_list') customer_price_list = frappe.get_value('Customer', party.name, 'default_price_list')

View File

@ -9,6 +9,7 @@ from erpnext.accounts.report.financial_statements import (get_period_list, get_c
def execute(filters=None): def execute(filters=None):
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
filters.period_start_date, filters.period_end_date, filters.filter_based_on,
filters.periodicity, company=filters.company) filters.periodicity, company=filters.company)
currency = filters.presentation_currency or frappe.get_cached_value('Company', filters.company, "default_currency") currency = filters.presentation_currency or frappe.get_cached_value('Company', filters.company, "default_currency")

View File

@ -9,7 +9,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
// filter. It won't be used in cash flow for now so we pop it. Please take // filter. It won't be used in cash flow for now so we pop it. Please take
// of this if you are working here. // of this if you are working here.
frappe.query_reports["Cash Flow"]["filters"].splice(5, 1); frappe.query_reports["Cash Flow"]["filters"].splice(8, 1);
frappe.query_reports["Cash Flow"]["filters"].push( frappe.query_reports["Cash Flow"]["filters"].push(
{ {

View File

@ -17,7 +17,8 @@ def execute(filters=None):
return execute_custom(filters=filters) return execute_custom(filters=filters)
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
filters.periodicity, filters.accumulated_values, filters.company) filters.period_start_date, filters.period_end_date, filters.filter_based_on,
filters.periodicity, company=filters.company)
cash_flow_accounts = get_cash_flow_accounts() cash_flow_accounts = get_cash_flow_accounts()

View File

@ -12,6 +12,39 @@ frappe.query_reports["Consolidated Financial Statement"] = {
"default": frappe.defaults.get_user_default("Company"), "default": frappe.defaults.get_user_default("Company"),
"reqd": 1 "reqd": 1
}, },
{
"fieldname":"filter_based_on",
"label": __("Filter Based On"),
"fieldtype": "Select",
"options": ["Fiscal Year", "Date Range"],
"default": ["Fiscal Year"],
"reqd": 1,
on_change: function() {
let filter_based_on = frappe.query_report.get_filter_value('filter_based_on');
frappe.query_report.toggle_filter_display('from_fiscal_year', filter_based_on === 'Date Range');
frappe.query_report.toggle_filter_display('to_fiscal_year', filter_based_on === 'Date Range');
frappe.query_report.toggle_filter_display('period_start_date', filter_based_on === 'Fiscal Year');
frappe.query_report.toggle_filter_display('period_end_date', filter_based_on === 'Fiscal Year');
frappe.query_report.refresh();
}
},
{
"fieldname":"period_start_date",
"label": __("Start Date"),
"fieldtype": "Date",
"default": frappe.datetime.nowdate(),
"hidden": 1,
"reqd": 1
},
{
"fieldname":"period_end_date",
"label": __("End Date"),
"fieldtype": "Date",
"default": frappe.datetime.add_months(frappe.datetime.nowdate(), 12),
"hidden": 1,
"reqd": 1
},
{ {
"fieldname":"from_fiscal_year", "fieldname":"from_fiscal_year",
"label": __("Start Year"), "label": __("Start Year"),

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe, erpnext import frappe, erpnext
from frappe import _ from frappe import _
from frappe.utils import flt, cint from frappe.utils import flt, cint, getdate
from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency
from erpnext.accounts.report.financial_statements import get_fiscal_year_data, sort_accounts from erpnext.accounts.report.financial_statements import get_fiscal_year_data, sort_accounts
from erpnext.accounts.report.balance_sheet.balance_sheet import (get_provisional_profit_loss, from erpnext.accounts.report.balance_sheet.balance_sheet import (get_provisional_profit_loss,
@ -208,17 +208,24 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i
company_currency = get_company_currency(filters) company_currency = get_company_currency(filters)
if filters.filter_based_on == 'Fiscal Year':
start_date = fiscal_year.year_start_date
end_date = fiscal_year.year_end_date
else:
start_date = filters.period_start_date
end_date = filters.period_end_date
gl_entries_by_account = {} gl_entries_by_account = {}
for root in frappe.db.sql("""select lft, rgt from tabAccount for root in frappe.db.sql("""select lft, rgt from tabAccount
where root_type=%s and ifnull(parent_account, '') = ''""", root_type, as_dict=1): where root_type=%s and ifnull(parent_account, '') = ''""", root_type, as_dict=1):
set_gl_entries_by_account(fiscal_year.year_start_date, set_gl_entries_by_account(start_date,
fiscal_year.year_end_date, root.lft, root.rgt, filters, end_date, root.lft, root.rgt, filters,
gl_entries_by_account, accounts_by_name, ignore_closing_entries=False) gl_entries_by_account, accounts_by_name, ignore_closing_entries=False)
calculate_values(accounts_by_name, gl_entries_by_account, companies, fiscal_year, filters) calculate_values(accounts_by_name, gl_entries_by_account, companies, start_date, filters)
accumulate_values_into_parents(accounts, accounts_by_name, companies) accumulate_values_into_parents(accounts, accounts_by_name, companies)
out = prepare_data(accounts, fiscal_year, balance_must_be, companies, company_currency) out = prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency)
if out: if out:
add_total_row(out, root_type, balance_must_be, companies, company_currency) add_total_row(out, root_type, balance_must_be, companies, company_currency)
@ -229,7 +236,7 @@ def get_company_currency(filters=None):
return (filters.get('presentation_currency') return (filters.get('presentation_currency')
or frappe.get_cached_value('Company', filters.company, "default_currency")) or frappe.get_cached_value('Company', filters.company, "default_currency"))
def calculate_values(accounts_by_name, gl_entries_by_account, companies, fiscal_year, filters): def calculate_values(accounts_by_name, gl_entries_by_account, companies, start_date, filters):
for entries in gl_entries_by_account.values(): for entries in gl_entries_by_account.values():
for entry in entries: for entry in entries:
key = entry.account_number or entry.account_name key = entry.account_number or entry.account_name
@ -241,7 +248,7 @@ def calculate_values(accounts_by_name, gl_entries_by_account, companies, fiscal_
and entry.company in companies.get(company)): and entry.company in companies.get(company)):
d[company] = d.get(company, 0.0) + flt(entry.debit) - flt(entry.credit) d[company] = d.get(company, 0.0) + flt(entry.debit) - flt(entry.credit)
if entry.posting_date < fiscal_year.year_start_date: if entry.posting_date < getdate(start_date):
d["opening_balance"] = d.get("opening_balance", 0.0) + flt(entry.debit) - flt(entry.credit) d["opening_balance"] = d.get("opening_balance", 0.0) + flt(entry.debit) - flt(entry.credit)
def accumulate_values_into_parents(accounts, accounts_by_name, companies): def accumulate_values_into_parents(accounts, accounts_by_name, companies):
@ -295,10 +302,8 @@ def get_accounts(root_type, filters):
`tabAccount` where company = %s and root_type = %s `tabAccount` where company = %s and root_type = %s
""" , (filters.get('company'), root_type), as_dict=1) """ , (filters.get('company'), root_type), as_dict=1)
def prepare_data(accounts, fiscal_year, balance_must_be, companies, company_currency): def prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency):
data = [] data = []
year_start_date = fiscal_year.year_start_date
year_end_date = fiscal_year.year_end_date
for d in accounts: for d in accounts:
# add to output # add to output
@ -309,8 +314,8 @@ def prepare_data(accounts, fiscal_year, balance_must_be, companies, company_curr
"account": _(d.account_name), "account": _(d.account_name),
"parent_account": _(d.parent_account), "parent_account": _(d.parent_account),
"indent": flt(d.indent), "indent": flt(d.indent),
"year_start_date": year_start_date, "year_start_date": start_date,
"year_end_date": year_end_date, "year_end_date": end_date,
"currency": company_currency, "currency": company_currency,
"opening_balance": d.get("opening_balance", 0.0) * (1 if balance_must_be == "Debit" else -1) "opening_balance": d.get("opening_balance", 0.0) * (1 if balance_must_be == "Debit" else -1)
}) })

View File

@ -18,17 +18,20 @@ from frappe.utils import (flt, getdate, get_first_day, add_months, add_days, for
from six import itervalues from six import itervalues
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children
def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, accumulated_values=False, def get_period_list(from_fiscal_year, to_fiscal_year, period_start_date, period_end_date, filter_based_on, periodicity, accumulated_values=False,
company=None, reset_period_on_fy_change=True): company=None, reset_period_on_fy_change=True):
"""Get a list of dict {"from_date": from_date, "to_date": to_date, "key": key, "label": label} """Get a list of dict {"from_date": from_date, "to_date": to_date, "key": key, "label": label}
Periodicity can be (Yearly, Quarterly, Monthly)""" Periodicity can be (Yearly, Quarterly, Monthly)"""
if filter_based_on == 'Fiscal Year':
fiscal_year = get_fiscal_year_data(from_fiscal_year, to_fiscal_year) fiscal_year = get_fiscal_year_data(from_fiscal_year, to_fiscal_year)
validate_fiscal_year(fiscal_year, from_fiscal_year, to_fiscal_year) validate_fiscal_year(fiscal_year, from_fiscal_year, to_fiscal_year)
# start with first day, so as to avoid year to_dates like 2-April if ever they occur]
year_start_date = getdate(fiscal_year.year_start_date) year_start_date = getdate(fiscal_year.year_start_date)
year_end_date = getdate(fiscal_year.year_end_date) year_end_date = getdate(fiscal_year.year_end_date)
else:
validate_dates(period_start_date, period_end_date)
year_start_date = getdate(period_start_date)
year_end_date = getdate(period_end_date)
months_to_add = { months_to_add = {
"Yearly": 12, "Yearly": 12,
@ -42,6 +45,9 @@ def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, accumulated_v
start_date = year_start_date start_date = year_start_date
months = get_months(year_start_date, year_end_date) months = get_months(year_start_date, year_end_date)
if (months // months_to_add) != (months / months_to_add):
months += months_to_add
for i in range(months // months_to_add): for i in range(months // months_to_add):
period = frappe._dict({ period = frappe._dict({
"from_date": start_date "from_date": start_date
@ -103,9 +109,18 @@ def get_fiscal_year_data(from_fiscal_year, to_fiscal_year):
def validate_fiscal_year(fiscal_year, from_fiscal_year, to_fiscal_year): def validate_fiscal_year(fiscal_year, from_fiscal_year, to_fiscal_year):
if not fiscal_year.get('year_start_date') and not fiscal_year.get('year_end_date'): if not fiscal_year.get('year_start_date') or not fiscal_year.get('year_end_date'):
frappe.throw(_("Start Year and End Year are mandatory"))
if getdate(fiscal_year.get('year_end_date')) < getdate(fiscal_year.get('year_start_date')):
frappe.throw(_("End Year cannot be before Start Year")) frappe.throw(_("End Year cannot be before Start Year"))
def validate_dates(from_date, to_date):
if not from_date or not to_date:
frappe.throw("From Date and To Date are mandatory")
if to_date < from_date:
frappe.throw("To Date cannot be less than From Date")
def get_months(start_date, end_date): def get_months(start_date, end_date):
diff = (12 * end_date.year + end_date.month) - (12 * start_date.year + start_date.month) diff = (12 * end_date.year + end_date.month) - (12 * start_date.year + start_date.month)
@ -420,6 +435,8 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type, filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
filters.get(dimension.fieldname)) filters.get(dimension.fieldname))
additional_conditions.append("{0} in %({0})s".format(dimension.fieldname)) additional_conditions.append("{0} in %({0})s".format(dimension.fieldname))
else:
additional_conditions.append("{0} in (%({0})s)".format(dimension.fieldname))
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else "" return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""

View File

@ -2,7 +2,7 @@
<h4 class="text-center"> <h4 class="text-center">
{% if (filters.party_name) { %} {% if (filters.party_name) { %}
{%= filters.party_name %} {%= filters.party_name %}
{% } else if (filters.party) { %} {% } else if (filters.party && filters.party.length) { %}
{%= filters.party %} {%= filters.party %}
{% } else if (filters.account) { %} {% } else if (filters.account) { %}
{%= filters.account %} {%= filters.account %}

View File

@ -203,6 +203,8 @@ def get_conditions(filters):
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type, filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
filters.get(dimension.fieldname)) filters.get(dimension.fieldname))
conditions.append("{0} in %({0})s".format(dimension.fieldname)) conditions.append("{0} in %({0})s".format(dimension.fieldname))
else:
conditions.append("{0} in (%({0})s)".format(dimension.fieldname))
return "and {}".format(" and ".join(conditions)) if conditions else "" return "and {}".format(" and ".join(conditions)) if conditions else ""
@ -363,6 +365,7 @@ def get_columns(filters):
columns = [ columns = [
{ {
"label": _("GL Entry"),
"fieldname": "gl_entry", "fieldname": "gl_entry",
"fieldtype": "Link", "fieldtype": "Link",
"options": "GL Entry", "options": "GL Entry",

View File

@ -9,7 +9,8 @@ from erpnext.accounts.report.financial_statements import (get_period_list, get_c
def execute(filters=None): def execute(filters=None):
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
filters.periodicity, filters.accumulated_values, filters.company) filters.period_start_date, filters.period_end_date, filters.filter_based_on, filters.periodicity,
company=filters.company)
income = get_data(filters.company, "Income", "Credit", period_list, filters = filters, income = get_data(filters.company, "Income", "Credit", period_list, filters = filters,
accumulated_values=filters.accumulated_values, accumulated_values=filters.accumulated_values,

View File

@ -34,6 +34,33 @@ frappe.query_reports["Purchase Register"] = {
"label": __("Mode of Payment"), "label": __("Mode of Payment"),
"fieldtype": "Link", "fieldtype": "Link",
"options": "Mode of Payment" "options": "Mode of Payment"
},
{
"fieldname":"cost_center",
"label": __("Cost Center"),
"fieldtype": "Link",
"options": "Cost Center"
},
{
"fieldname":"warehouse",
"label": __("Warehouse"),
"fieldtype": "Link",
"options": "Warehouse"
},
{
"fieldname":"item_group",
"label": __("Item Group"),
"fieldtype": "Link",
"options": "Item Group"
} }
] ]
} }
erpnext.dimension_filters.forEach((dimension) => {
frappe.query_reports["Purchase Register"].filters.splice(7, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
"options": dimension["document_type"]
});
});

View File

@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe.utils import flt from frappe.utils import flt
from frappe import msgprint, _ from frappe import msgprint, _
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children
def execute(filters=None): def execute(filters=None):
return _execute(filters) return _execute(filters)
@ -134,6 +135,38 @@ def get_conditions(filters):
if filters.get("mode_of_payment"): conditions += " and ifnull(mode_of_payment, '') = %(mode_of_payment)s" if filters.get("mode_of_payment"): conditions += " and ifnull(mode_of_payment, '') = %(mode_of_payment)s"
if filters.get("cost_center"):
conditions += """ and exists(select name from `tabPurchase Invoice Item`
where parent=`tabPurchase Invoice`.name
and ifnull(`tabPurchase Invoice Item`.cost_center, '') = %(cost_center)s)"""
if filters.get("warehouse"):
conditions += """ and exists(select name from `tabPurchase Invoice Item`
where parent=`tabPurchase Invoice`.name
and ifnull(`tabPurchase Invoice Item`.warehouse, '') = %(warehouse)s)"""
if filters.get("item_group"):
conditions += """ and exists(select name from `tabPurchase Invoice Item`
where parent=`tabPurchase Invoice`.name
and ifnull(`tabPurchase Invoice Item`.item_group, '') = %(item_group)s)"""
accounting_dimensions = get_accounting_dimensions(as_list=False)
if accounting_dimensions:
common_condition = """
and exists(select name from `tabPurchase Invoice Item`
where parent=`tabPurchase Invoice`.name
"""
for dimension in accounting_dimensions:
if filters.get(dimension.fieldname):
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
filters.get(dimension.fieldname))
conditions += common_condition + "and ifnull(`tabPurchase Invoice Item`.{0}, '') in %({0})s)".format(dimension.fieldname)
else:
conditions += common_condition + "and ifnull(`tabPurchase Invoice Item`.{0}, '') in (%({0})s))".format(dimension.fieldname)
return conditions return conditions
def get_invoices(filters, additional_query_columns): def get_invoices(filters, additional_query_columns):

View File

@ -344,16 +344,19 @@ def get_conditions(filters):
accounting_dimensions = get_accounting_dimensions(as_list=False) accounting_dimensions = get_accounting_dimensions(as_list=False)
if accounting_dimensions: if accounting_dimensions:
common_condition = """
and exists(select name from `tabSales Invoice Item`
where parent=`tabSales Invoice`.name
"""
for dimension in accounting_dimensions: for dimension in accounting_dimensions:
if filters.get(dimension.fieldname): if filters.get(dimension.fieldname):
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'): if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type, filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
filters.get(dimension.fieldname)) filters.get(dimension.fieldname))
conditions += """ and exists(select name from `tabSales Invoice Item` conditions += common_condition + "and ifnull(`tabSales Invoice Item`.{0}, '') in %({0})s)".format(dimension.fieldname)
where parent=`tabSales Invoice`.name else:
and ifnull(`tabSales Invoice Item`.{0}, '') in %({0})s)""".format(dimension.fieldname) conditions += common_condition + "and ifnull(`tabSales Invoice Item`.{0}, '') in (%({0})s))".format(dimension.fieldname)
return conditions return conditions

View File

@ -127,6 +127,8 @@ def get_rootwise_opening_balances(filters, report_type):
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type, filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
filters.get(dimension.fieldname)) filters.get(dimension.fieldname))
additional_conditions += "and {0} in %({0})s".format(dimension.fieldname) additional_conditions += "and {0} in %({0})s".format(dimension.fieldname)
else:
additional_conditions += "and {0} in (%({0})s)".format(dimension.fieldname)
query_filters.update({ query_filters.update({
dimension.fieldname: filters.get(dimension.fieldname) dimension.fieldname: filters.get(dimension.fieldname)

View File

@ -1,16 +1,19 @@
{ {
"cards": [ "cards": [
{ {
"links": "[\n {\n \"label\": \"Crop\",\n \"name\": \"Crop\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Crop Cycle\",\n \"name\": \"Crop Cycle\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Location\",\n \"name\": \"Location\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Crops & Lands" "label": "Crops & Lands",
"links": "[\n {\n \"label\": \"Crop\",\n \"name\": \"Crop\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Crop Cycle\",\n \"name\": \"Crop Cycle\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Location\",\n \"name\": \"Location\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"label\": \"Plant Analysis\",\n \"name\": \"Plant Analysis\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Soil Analysis\",\n \"name\": \"Soil Analysis\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Water Analysis\",\n \"name\": \"Water Analysis\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Soil Texture\",\n \"name\": \"Soil Texture\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Weather\",\n \"name\": \"Weather\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Agriculture Analysis Criteria\",\n \"name\": \"Agriculture Analysis Criteria\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Analytics" "label": "Analytics",
"links": "[\n {\n \"label\": \"Plant Analysis\",\n \"name\": \"Plant Analysis\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Soil Analysis\",\n \"name\": \"Soil Analysis\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Water Analysis\",\n \"name\": \"Water Analysis\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Soil Texture\",\n \"name\": \"Soil Texture\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Weather\",\n \"name\": \"Weather\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Agriculture Analysis Criteria\",\n \"name\": \"Agriculture Analysis Criteria\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"label\": \"Disease\",\n \"name\": \"Disease\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fertilizer\",\n \"name\": \"Fertilizer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Diseases & Fertilizers" "label": "Diseases & Fertilizers",
"links": "[\n {\n \"label\": \"Disease\",\n \"name\": \"Disease\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fertilizer\",\n \"name\": \"Fertilizer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
} }
], ],
"category": "Domains", "category": "Domains",
@ -24,7 +27,7 @@
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "Agriculture", "label": "Agriculture",
"modified": "2020-03-12 16:30:37.565413", "modified": "2020-04-01 11:28:51.032822",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Agriculture", "module": "Agriculture",
"name": "Agriculture", "name": "Agriculture",

View File

@ -1,17 +1,19 @@
{ {
"cards": [ "cards": [
{ {
"links": "[\n {\n \"label\": \"Asset\",\n \"name\": \"Asset\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Location\",\n \"name\": \"Location\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Asset Category\",\n \"name\": \"Asset Category\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Transfer an asset from one warehouse to another\",\n \"label\": \"Asset Movement\",\n \"name\": \"Asset Movement\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Assets" "label": "Assets",
"links": "[\n {\n \"label\": \"Asset\",\n \"name\": \"Asset\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Location\",\n \"name\": \"Location\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Asset Category\",\n \"name\": \"Asset Category\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Transfer an asset from one warehouse to another\",\n \"label\": \"Asset Movement\",\n \"name\": \"Asset Movement\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"label\": \"Asset Maintenance Team\",\n \"name\": \"Asset Maintenance Team\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Asset Maintenance Team\"\n ],\n \"label\": \"Asset Maintenance\",\n \"name\": \"Asset Maintenance\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Asset Maintenance\"\n ],\n \"label\": \"Asset Maintenance Log\",\n \"name\": \"Asset Maintenance Log\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Asset\"\n ],\n \"label\": \"Asset Value Adjustment\",\n \"name\": \"Asset Value Adjustment\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Asset\"\n ],\n \"label\": \"Asset Repair\",\n \"name\": \"Asset Repair\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Maintenance" "label": "Maintenance",
"links": "[\n {\n \"label\": \"Asset Maintenance Team\",\n \"name\": \"Asset Maintenance Team\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Asset Maintenance Team\"\n ],\n \"label\": \"Asset Maintenance\",\n \"name\": \"Asset Maintenance\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Asset Maintenance\"\n ],\n \"label\": \"Asset Maintenance Log\",\n \"name\": \"Asset Maintenance Log\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Asset\"\n ],\n \"label\": \"Asset Value Adjustment\",\n \"name\": \"Asset Value Adjustment\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Asset\"\n ],\n \"label\": \"Asset Repair\",\n \"name\": \"Asset Repair\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"icon": "fa fa-table", "hidden": 0,
"links": "[\n {\n \"dependencies\": [\n \"Asset\"\n ],\n \"doctype\": \"Asset\",\n \"is_query_report\": true,\n \"label\": \"Asset Depreciation Ledger\",\n \"name\": \"Asset Depreciation Ledger\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Asset\"\n ],\n \"doctype\": \"Asset\",\n \"is_query_report\": true,\n \"label\": \"Asset Depreciations and Balances\",\n \"name\": \"Asset Depreciations and Balances\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Asset Maintenance\"\n ],\n \"doctype\": \"Asset Maintenance\",\n \"label\": \"Asset Maintenance\",\n \"name\": \"Asset Maintenance\",\n \"type\": \"report\"\n }\n]", "label": "Reports",
"title": "Reports" "links": "[\n {\n \"dependencies\": [\n \"Asset\"\n ],\n \"doctype\": \"Asset\",\n \"is_query_report\": true,\n \"label\": \"Asset Depreciation Ledger\",\n \"name\": \"Asset Depreciation Ledger\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Asset\"\n ],\n \"doctype\": \"Asset\",\n \"is_query_report\": true,\n \"label\": \"Asset Depreciations and Balances\",\n \"name\": \"Asset Depreciations and Balances\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Asset Maintenance\"\n ],\n \"doctype\": \"Asset Maintenance\",\n \"label\": \"Asset Maintenance\",\n \"name\": \"Asset Maintenance\",\n \"type\": \"report\"\n }\n]"
} }
], ],
"category": "Modules", "category": "Modules",
@ -26,7 +28,7 @@
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "Assets", "label": "Assets",
"modified": "2020-03-12 16:30:38.651019", "modified": "2020-04-01 11:28:51.072198",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Assets", "module": "Assets",
"name": "Assets", "name": "Assets",
@ -35,17 +37,17 @@
"pin_to_top": 0, "pin_to_top": 0,
"shortcuts": [ "shortcuts": [
{ {
"is_query_report": 0, "label": "Asset",
"link_to": "Asset", "link_to": "Asset",
"type": "DocType" "type": "DocType"
}, },
{ {
"is_query_report": 0, "label": "Asset Movement",
"link_to": "Asset Movement", "link_to": "Asset Movement",
"type": "DocType" "type": "DocType"
}, },
{ {
"is_query_report": 0, "label": "Fixed Asset Register",
"link_to": "Fixed Asset Register", "link_to": "Fixed Asset Register",
"type": "Report" "type": "Report"
} }

View File

@ -11,6 +11,7 @@ from frappe.model.document import Document
class AssetCategory(Document): class AssetCategory(Document):
def validate(self): def validate(self):
self.validate_finance_books() self.validate_finance_books()
self.validate_accounts()
def validate_finance_books(self): def validate_finance_books(self):
for d in self.finance_books: for d in self.finance_books:
@ -18,6 +19,27 @@ class AssetCategory(Document):
if cint(d.get(frappe.scrub(field)))<1: if cint(d.get(frappe.scrub(field)))<1:
frappe.throw(_("Row {0}: {1} must be greater than 0").format(d.idx, field), frappe.MandatoryError) frappe.throw(_("Row {0}: {1} must be greater than 0").format(d.idx, field), frappe.MandatoryError)
def validate_accounts(self):
account_type_map = {
'fixed_asset_account': { 'account_type': 'Fixed Asset' },
'accumulated_depreciation_account': { 'account_type': 'Accumulated Depreciation' },
'depreciation_expense_account': { 'root_type': 'Expense' },
'capital_work_in_progress_account': { 'account_type': 'Capital Work in Progress' }
}
for d in self.accounts:
for fieldname in account_type_map.keys():
if d.get(fieldname):
selected_account = d.get(fieldname)
key_to_match = next(iter(account_type_map.get(fieldname))) # acount_type or root_type
selected_key_type = frappe.db.get_value('Account', selected_account, key_to_match)
expected_key_type = account_type_map[fieldname][key_to_match]
if selected_key_type != expected_key_type:
frappe.throw(_("Row #{}: {} of {} should be {}. Please modify the account or select a different account.")
.format(d.idx, frappe.unscrub(key_to_match), frappe.bold(selected_account), frappe.bold(expected_key_type)),
title=_("Invalid Account"))
@frappe.whitelist() @frappe.whitelist()
def get_asset_category_account(fieldname, item=None, asset=None, account=None, asset_category = None, company = None): def get_asset_category_account(fieldname, item=None, asset=None, account=None, asset_category = None, company = None):
if item and frappe.db.get_value("Item", item, "is_fixed_asset"): if item and frappe.db.get_value("Item", item, "is_fixed_asset"):

View File

@ -1,44 +1,46 @@
{ {
"cards": [ "cards": [
{ {
"links": "[\n {\n \"description\": \"Supplier database.\",\n \"label\": \"Supplier\",\n \"name\": \"Supplier\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Supplier Group master.\",\n \"label\": \"Supplier Group\",\n \"name\": \"Supplier Group\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"All Contacts.\",\n \"label\": \"Contact\",\n \"name\": \"Contact\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"All Addresses.\",\n \"label\": \"Address\",\n \"name\": \"Address\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Supplier" "label": "Supplier",
"links": "[\n {\n \"description\": \"Supplier database.\",\n \"label\": \"Supplier\",\n \"name\": \"Supplier\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Supplier Group master.\",\n \"label\": \"Supplier Group\",\n \"name\": \"Supplier Group\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"All Contacts.\",\n \"label\": \"Contact\",\n \"name\": \"Contact\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"All Addresses.\",\n \"label\": \"Address\",\n \"name\": \"Address\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"icon": "fa fa-star", "hidden": 0,
"links": "[\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"description\": \"Purchase Orders given to Suppliers.\",\n \"label\": \"Purchase Order\",\n \"name\": \"Purchase Order\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"label\": \"Purchase Invoice\",\n \"name\": \"Purchase Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"description\": \"Request for purchase.\",\n \"label\": \"Material Request\",\n \"name\": \"Material Request\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"description\": \"Request for quotation.\",\n \"label\": \"Request for Quotation\",\n \"name\": \"Request for Quotation\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"description\": \"Quotations received from Suppliers.\",\n \"label\": \"Supplier Quotation\",\n \"name\": \"Supplier Quotation\",\n \"type\": \"doctype\"\n }\n]", "label": "Purchasing",
"title": "Purchasing" "links": "[\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"description\": \"Purchase Orders given to Suppliers.\",\n \"label\": \"Purchase Order\",\n \"name\": \"Purchase Order\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"label\": \"Purchase Invoice\",\n \"name\": \"Purchase Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"description\": \"Request for purchase.\",\n \"label\": \"Material Request\",\n \"name\": \"Material Request\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"description\": \"Request for quotation.\",\n \"label\": \"Request for Quotation\",\n \"name\": \"Request for Quotation\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"description\": \"Quotations received from Suppliers.\",\n \"label\": \"Supplier Quotation\",\n \"name\": \"Supplier Quotation\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"description\": \"All Products or Services.\",\n \"label\": \"Item\",\n \"name\": \"Item\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Multiple Item prices.\",\n \"label\": \"Item Price\",\n \"name\": \"Item Price\",\n \"onboard\": 1,\n \"route\": \"#Report/Item Price\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Price List master.\",\n \"label\": \"Price List\",\n \"name\": \"Price List\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bundle items at time of sale.\",\n \"label\": \"Product Bundle\",\n \"name\": \"Product Bundle\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tree of Item Groups.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Item Group\",\n \"link\": \"Tree/Item Group\",\n \"name\": \"Item Group\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Rules for applying different promotional schemes.\",\n \"label\": \"Promotional Scheme\",\n \"name\": \"Promotional Scheme\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Rules for applying pricing and discount.\",\n \"label\": \"Pricing Rule\",\n \"name\": \"Pricing Rule\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Items and Pricing" "label": "Items and Pricing",
"links": "[\n {\n \"description\": \"All Products or Services.\",\n \"label\": \"Item\",\n \"name\": \"Item\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Multiple Item prices.\",\n \"label\": \"Item Price\",\n \"name\": \"Item Price\",\n \"onboard\": 1,\n \"route\": \"#Report/Item Price\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Price List master.\",\n \"label\": \"Price List\",\n \"name\": \"Price List\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bundle items at time of sale.\",\n \"label\": \"Product Bundle\",\n \"name\": \"Product Bundle\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tree of Item Groups.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Item Group\",\n \"link\": \"Tree/Item Group\",\n \"name\": \"Item Group\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Rules for applying different promotional schemes.\",\n \"label\": \"Promotional Scheme\",\n \"name\": \"Promotional Scheme\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Rules for applying pricing and discount.\",\n \"label\": \"Pricing Rule\",\n \"name\": \"Pricing Rule\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"icon": "fa fa-cog", "hidden": 0,
"links": "[\n {\n \"description\": \"Default settings for buying transactions.\",\n \"label\": \"Buying Settings\",\n \"name\": \"Buying Settings\",\n \"settings\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax template for buying transactions.\",\n \"label\": \"Purchase Taxes and Charges Template\",\n \"name\": \"Purchase Taxes and Charges Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Template of terms or contract.\",\n \"label\": \"Terms and Conditions Template\",\n \"name\": \"Terms and Conditions\",\n \"type\": \"doctype\"\n }\n]", "label": "Settings",
"title": "Settings" "links": "[\n {\n \"description\": \"Default settings for buying transactions.\",\n \"label\": \"Buying Settings\",\n \"name\": \"Buying Settings\",\n \"settings\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax template for buying transactions.\",\n \"label\": \"Purchase Taxes and Charges Template\",\n \"name\": \"Purchase Taxes and Charges Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Template of terms or contract.\",\n \"label\": \"Terms and Conditions Template\",\n \"name\": \"Terms and Conditions\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"description\": \"All Supplier scorecards.\",\n \"label\": \"Supplier Scorecard\",\n \"name\": \"Supplier Scorecard\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Templates of supplier scorecard variables.\",\n \"label\": \"Supplier Scorecard Variable\",\n \"name\": \"Supplier Scorecard Variable\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Templates of supplier scorecard criteria.\",\n \"label\": \"Supplier Scorecard Criteria\",\n \"name\": \"Supplier Scorecard Criteria\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Templates of supplier standings.\",\n \"label\": \"Supplier Scorecard Standing\",\n \"name\": \"Supplier Scorecard Standing\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Supplier Scorecard" "label": "Supplier Scorecard",
"links": "[\n {\n \"description\": \"All Supplier scorecards.\",\n \"label\": \"Supplier Scorecard\",\n \"name\": \"Supplier Scorecard\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Templates of supplier scorecard variables.\",\n \"label\": \"Supplier Scorecard Variable\",\n \"name\": \"Supplier Scorecard Variable\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Templates of supplier scorecard criteria.\",\n \"label\": \"Supplier Scorecard Criteria\",\n \"name\": \"Supplier Scorecard Criteria\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Templates of supplier standings.\",\n \"label\": \"Supplier Scorecard Standing\",\n \"name\": \"Supplier Scorecard Standing\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"icon": "fa fa-table", "hidden": 0,
"links": "[\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Analytics\",\n \"name\": \"Purchase Analytics\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Supplier-Wise Sales Analytics\",\n \"name\": \"Supplier-Wise Sales Analytics\",\n \"onboard\": 1,\n \"reference_doctype\": \"Stock Ledger Entry\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Order Trends\",\n \"name\": \"Purchase Order Trends\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Procurement Tracker\",\n \"name\": \"Procurement Tracker\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Requested Items To Be Ordered\",\n \"name\": \"Requested Items To Be Ordered\",\n \"onboard\": 1,\n \"reference_doctype\": \"Material Request\",\n \"type\": \"report\"\n }\n]", "label": "Key Reports",
"title": "Key Reports" "links": "[\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Analytics\",\n \"name\": \"Purchase Analytics\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Supplier-Wise Sales Analytics\",\n \"name\": \"Supplier-Wise Sales Analytics\",\n \"onboard\": 1,\n \"reference_doctype\": \"Stock Ledger Entry\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Order Trends\",\n \"name\": \"Purchase Order Trends\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Procurement Tracker\",\n \"name\": \"Procurement Tracker\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Requested Items To Be Ordered\",\n \"name\": \"Requested Items To Be Ordered\",\n \"onboard\": 1,\n \"reference_doctype\": \"Material Request\",\n \"type\": \"report\"\n }\n]"
}, },
{ {
"icon": "fa fa-list", "hidden": 0,
"links": "[\n {\n \"is_query_report\": true,\n \"label\": \"Items To Be Requested\",\n \"name\": \"Items To Be Requested\",\n \"onboard\": 1,\n \"reference_doctype\": \"Item\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Item-wise Purchase History\",\n \"name\": \"Item-wise Purchase History\",\n \"onboard\": 1,\n \"reference_doctype\": \"Item\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Material Requests for which Supplier Quotations are not created\",\n \"name\": \"Material Requests for which Supplier Quotations are not created\",\n \"reference_doctype\": \"Material Request\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Supplier Addresses And Contacts\",\n \"name\": \"Address And Contacts\",\n \"reference_doctype\": \"Address\",\n \"route_options\": {\n \"party_type\": \"Supplier\"\n },\n \"type\": \"report\"\n }\n]", "label": "Other Reports",
"title": "Other Reports" "links": "[\n {\n \"is_query_report\": true,\n \"label\": \"Items To Be Requested\",\n \"name\": \"Items To Be Requested\",\n \"onboard\": 1,\n \"reference_doctype\": \"Item\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Item-wise Purchase History\",\n \"name\": \"Item-wise Purchase History\",\n \"onboard\": 1,\n \"reference_doctype\": \"Item\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Material Requests for which Supplier Quotations are not created\",\n \"name\": \"Material Requests for which Supplier Quotations are not created\",\n \"reference_doctype\": \"Material Request\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Supplier Addresses And Contacts\",\n \"name\": \"Address And Contacts\",\n \"reference_doctype\": \"Address\",\n \"route_options\": {\n \"party_type\": \"Supplier\"\n },\n \"type\": \"report\"\n }\n]"
} }
], ],
"category": "Modules", "category": "Modules",
"charts": [ "charts": [
{ {
"chart_name": "Expenses", "chart_name": "Expenses",
"label": "Expenses", "label": "Expenses"
"size": "Full"
} }
], ],
"creation": "2020-01-28 11:50:26.195467", "creation": "2020-01-28 11:50:26.195467",
@ -51,7 +53,7 @@
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "Buying", "label": "Buying",
"modified": "2020-03-12 16:30:40.779078", "modified": "2020-04-01 11:28:51.192097",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Buying", "name": "Buying",
@ -61,30 +63,30 @@
"shortcuts": [ "shortcuts": [
{ {
"format": "{} Unpaid", "format": "{} Unpaid",
"is_query_report": 0, "label": "Purchase Invoice",
"link_to": "Purchase Invoice", "link_to": "Purchase Invoice",
"stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\": \"Unpaid\"\n}", "stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\": \"Unpaid\"\n}",
"type": "DocType" "type": "DocType"
}, },
{ {
"format": "{} to receive", "format": "{} to receive",
"is_query_report": 0, "label": "Purchase Order",
"link_to": "Purchase Order", "link_to": "Purchase Order",
"stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\": \"To Receive\"\n}", "stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\": \"To Receive\"\n}",
"type": "DocType" "type": "DocType"
}, },
{ {
"is_query_report": 0, "label": "Supplier Quotation",
"link_to": "Supplier Quotation", "link_to": "Supplier Quotation",
"type": "DocType" "type": "DocType"
}, },
{ {
"is_query_report": 0, "label": "Accounts Payable",
"link_to": "Accounts Payable", "link_to": "Accounts Payable",
"type": "Report" "type": "Report"
}, },
{ {
"is_query_report": 0, "label": "Purchase Register",
"link_to": "Purchase Register", "link_to": "Purchase Register",
"type": "Report" "type": "Report"
} }

View File

@ -1,4 +1,5 @@
{ {
"actions": [],
"allow_import": 1, "allow_import": 1,
"autoname": "naming_series:", "autoname": "naming_series:",
"creation": "2013-05-21 16:16:39", "creation": "2013-05-21 16:16:39",
@ -63,9 +64,9 @@
"base_total", "base_total",
"base_net_total", "base_net_total",
"column_break_26", "column_break_26",
"total_net_weight",
"total", "total",
"net_total", "net_total",
"total_net_weight",
"taxes_section", "taxes_section",
"tax_category", "tax_category",
"column_break_50", "column_break_50",
@ -170,8 +171,8 @@
"search_index": 1 "search_index": 1
}, },
{ {
"description": "Fetch items based on Default Supplier.",
"depends_on": "eval:doc.supplier && doc.docstatus===0 && (!(doc.items && doc.items.length) || (doc.items.length==1 && !doc.items[0].item_code))", "depends_on": "eval:doc.supplier && doc.docstatus===0 && (!(doc.items && doc.items.length) || (doc.items.length==1 && !doc.items[0].item_code))",
"description": "Fetch items based on Default Supplier.",
"fieldname": "get_items_from_open_material_requests", "fieldname": "get_items_from_open_material_requests",
"fieldtype": "Button", "fieldtype": "Button",
"label": "Get Items from Open Material Requests" "label": "Get Items from Open Material Requests"
@ -1054,7 +1055,8 @@
"icon": "fa fa-file-text", "icon": "fa fa-file-text",
"idx": 105, "idx": 105,
"is_submittable": 1, "is_submittable": 1,
"modified": "2020-01-14 18:54:39.694448", "links": [],
"modified": "2020-04-17 13:04:28.185197",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Order", "name": "Purchase Order",

View File

@ -702,8 +702,7 @@
{ {
"fieldname": "manufacturer_part_no", "fieldname": "manufacturer_part_no",
"fieldtype": "Data", "fieldtype": "Data",
"label": "Manufacturer Part Number", "label": "Manufacturer Part Number"
"read_only": 1
}, },
{ {
"default": "0", "default": "0",
@ -723,7 +722,7 @@
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2019-12-06 13:17:12.142799", "modified": "2020-04-07 18:35:17.558928",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Order Item", "name": "Purchase Order Item",

View File

@ -1,4 +1,5 @@
{ {
"actions": [],
"autoname": "hash", "autoname": "hash",
"creation": "2013-05-22 12:43:10", "creation": "2013-05-22 12:43:10",
"doctype": "DocType", "doctype": "DocType",
@ -522,8 +523,7 @@
{ {
"fieldname": "manufacturer_part_no", "fieldname": "manufacturer_part_no",
"fieldtype": "Data", "fieldtype": "Data",
"label": "Manufacturer Part Number", "label": "Manufacturer Part Number"
"read_only": 1
}, },
{ {
"fieldname": "column_break_15", "fieldname": "column_break_15",
@ -532,7 +532,8 @@
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"modified": "2019-06-02 05:32:46.019237", "links": [],
"modified": "2020-04-07 18:35:51.175947",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Supplier Quotation Item", "name": "Supplier Quotation Item",

View File

@ -2,131 +2,68 @@ from __future__ import unicode_literals
from frappe import _ from frappe import _
def get_data(): def get_data():
return [ return [
{
"label": _("Consultation"),
"icon": "icon-star",
"items": [
{
"type": "doctype",
"name": "Patient Appointment",
"label": _("Patient Appointment"),
},
{
"type": "doctype",
"name": "Patient Encounter",
"label": _("Patient Encounter"),
},
{
"type": "doctype",
"name": "Vital Signs",
"label": _("Vital Signs"),
"description": _("Record Patient Vitals"),
},
{
"type": "page",
"name": "patient_history",
"label": _("Patient History"),
},
{
"type": "page",
"name": "appointment-analytic",
"label": _("Appointment Analytics"),
},
{
"type": "doctype",
"name": "Clinical Procedure",
"label": _("Clinical Procedure"),
},
{
"type": "doctype",
"name": "Inpatient Record",
"label": _("Inpatient Record"),
}
]
},
{
"label": _("Laboratory"),
"icon": "icon-list",
"items": [
{
"type": "doctype",
"name": "Lab Test",
"label": _("Lab Test"),
},
{
"type": "doctype",
"name": "Sample Collection",
"label": _("Sample Collection"),
},
{
"type": "report",
"name": "Lab Test Report",
"is_query_report": True,
"label": _("Lab Test Report"),
}
]
},
{ {
"label": _("Masters"), "label": _("Masters"),
"icon": "icon-list",
"items": [ "items": [
{ {
"type": "doctype", "type": "doctype",
"name": "Patient", "name": "Patient",
"label": _("Patient"), "label": _("Patient"),
"onboard": 1, "onboard": 1
}, },
{ {
"type": "doctype", "type": "doctype",
"name": "Healthcare Practitioner", "name": "Healthcare Practitioner",
"label": _("Healthcare Practitioner"), "label": _("Healthcare Practitioner"),
"onboard": 1, "onboard": 1
}, },
{ {
"type": "doctype", "type": "doctype",
"name": "Practitioner Schedule", "name": "Practitioner Schedule",
"label": _("Practitioner Schedule"), "label": _("Practitioner Schedule"),
}, "onboard": 1
{
"type": "doctype",
"name": "Medical Code Standard",
"label": _("Medical Code Standard"),
},
{
"type": "doctype",
"name": "Medical Code",
"label": _("Medical Code"),
"onboard": 1,
},
{
"type": "doctype",
"name": "Healthcare Service Unit",
"label": _("Healthcare Service Unit")
}
]
},
{
"label": _("Settings"),
"icon": "icon-cog",
"items": [
{
"type": "doctype",
"name": "Healthcare Settings",
"label": _("Healthcare Settings"),
"onboard": 1,
}, },
{ {
"type": "doctype", "type": "doctype",
"name": "Medical Department", "name": "Medical Department",
"label": _("Medical Department"), "label": _("Medical Department"),
}, },
{
"type": "doctype",
"name": "Healthcare Service Unit Type",
"label": _("Healthcare Service Unit Type")
},
{
"type": "doctype",
"name": "Healthcare Service Unit",
"label": _("Healthcare Service Unit")
},
{
"type": "doctype",
"name": "Medical Code Standard",
"label": _("Medical Code Standard")
},
{
"type": "doctype",
"name": "Medical Code",
"label": _("Medical Code")
}
]
},
{
"label": _("Consultation Setup"),
"items": [
{ {
"type": "doctype", "type": "doctype",
"name": "Appointment Type", "name": "Appointment Type",
"label": _("Appointment Type"), "label": _("Appointment Type"),
}, },
{
"type": "doctype",
"name": "Clinical Procedure Template",
"label": _("Clinical Procedure Template")
},
{ {
"type": "doctype", "type": "doctype",
"name": "Prescription Dosage", "name": "Prescription Dosage",
@ -137,6 +74,36 @@ def get_data():
"name": "Prescription Duration", "name": "Prescription Duration",
"label": _("Prescription Duration") "label": _("Prescription Duration")
}, },
{
"type": "doctype",
"name": "Antibiotic",
"label": _("Antibiotic")
}
]
},
{
"label": _("Consultation"),
"items": [
{
"type": "doctype",
"name": "Patient Appointment",
"label": _("Patient Appointment")
},
{
"type": "doctype",
"name": "Clinical Procedure",
"label": _("Clinical Procedure")
},
{
"type": "doctype",
"name": "Patient Encounter",
"label": _("Patient Encounter")
},
{
"type": "doctype",
"name": "Vital Signs",
"label": _("Vital Signs")
},
{ {
"type": "doctype", "type": "doctype",
"name": "Complaint", "name": "Complaint",
@ -147,40 +114,104 @@ def get_data():
"name": "Diagnosis", "name": "Diagnosis",
"label": _("Diagnosis") "label": _("Diagnosis")
}, },
{
"type": "doctype",
"name": "Fee Validity",
"label": _("Fee Validity")
}
]
},
{
"label": _("Settings"),
"items": [
{
"type": "doctype",
"name": "Healthcare Settings",
"label": _("Healthcare Settings"),
"onboard": 1
}
]
},
{
"label": _("Laboratory Setup"),
"items": [
{
"type": "doctype",
"name": "Lab Test Template",
"label": _("Lab Test Template")
},
{ {
"type": "doctype", "type": "doctype",
"name": "Lab Test Sample", "name": "Lab Test Sample",
"label": _("Lab Test Sample"), "label": _("Lab Test Sample")
}, },
{ {
"type": "doctype", "type": "doctype",
"name": "Lab Test UOM", "name": "Lab Test UOM",
"label": _("Lab Test UOM") "label": _("Lab Test UOM")
}, },
{
"type": "doctype",
"name": "Antibiotic",
"label": _("Antibiotic")
},
{ {
"type": "doctype", "type": "doctype",
"name": "Sensitivity", "name": "Sensitivity",
"label": _("Sensitivity") "label": _("Sensitivity")
}
]
},
{
"label": _("Laboratory"),
"items": [
{
"type": "doctype",
"name": "Lab Test",
"label": _("Lab Test")
}, },
{ {
"type": "doctype", "type": "doctype",
"name": "Lab Test Template", "name": "Sample Collection",
"label": _("Lab Test Template") "label": _("Sample Collection")
}, },
{ {
"type": "doctype", "type": "doctype",
"name": "Clinical Procedure Template", "name": "Dosage Form",
"label": _("Clinical Procedure Template"), "label": _("Dosage Form")
}
]
},
{
"label": _("Records and History"),
"items": [
{
"type": "page",
"name": "patient_history",
"label": _("Patient History"),
}, },
{ {
"type": "doctype", "type": "doctype",
"name": "Healthcare Service Unit Type", "name": "Patient Medical Record",
"label": _("Healthcare Service Unit Type") "label": _("Patient Medical Record")
},
{
"type": "doctype",
"name": "Inpatient Record",
"label": _("Inpatient Record")
}
]
},
{
"label": _("Reports"),
"items": [
{
"type": "report",
"is_query_report": True,
"name": "Patient Appointment Analytics",
"doctype": "Patient Appointment"
},
{
"type": "report",
"is_query_report": True,
"name": "Lab Test Report",
"doctype": "Lab Test",
"label": _("Lab Test Report")
} }
] ]
} }

View File

@ -439,7 +439,7 @@ class AccountsController(TransactionBase):
if account_currency not in valid_currency: if account_currency not in valid_currency:
frappe.throw(_("Account {0} is invalid. Account Currency must be {1}") frappe.throw(_("Account {0} is invalid. Account Currency must be {1}")
.format(account, _(" or ").join(valid_currency))) .format(account, (' ' + _("or") + ' ').join(valid_currency)))
def clear_unallocated_advances(self, childtype, parentfield): def clear_unallocated_advances(self, childtype, parentfield):
self.set(parentfield, self.get(parentfield, {"allocated_amount": ["not in", [0, None, ""]]})) self.set(parentfield, self.get(parentfield, {"allocated_amount": ["not in", [0, None, ""]]}))
@ -834,7 +834,7 @@ class AccountsController(TransactionBase):
for d in self.get("payment_schedule"): for d in self.get("payment_schedule"):
if self.doctype == "Sales Order" and getdate(d.due_date) < getdate(self.transaction_date): if self.doctype == "Sales Order" and getdate(d.due_date) < getdate(self.transaction_date):
frappe.throw(_("Row {0}: Due Date cannot be before posting date").format(d.idx)) frappe.throw(_("Row {0}: Due Date in the Payment Terms table cannot be before Posting Date").format(d.idx))
elif d.due_date in dates: elif d.due_date in dates:
li.append(_("{0} in row {1}").format(d.due_date, d.idx)) li.append(_("{0} in row {1}").format(d.due_date, d.idx))
dates.append(d.due_date) dates.append(d.due_date)
@ -1123,36 +1123,39 @@ def get_supplier_block_status(party_name):
} }
return info return info
def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, item_code): def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, trans_item):
""" """
Returns a Sales Order Item child item containing the default values Returns a Sales Order Item child item containing the default values
""" """
p_doc = frappe.get_doc(parent_doctype, parent_doctype_name) p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
child_item = frappe.new_doc('Sales Order Item', p_doc, child_docname) child_item = frappe.new_doc('Sales Order Item', p_doc, child_docname)
item = frappe.get_doc("Item", item_code) item = frappe.get_doc("Item", trans_item.get('item_code'))
child_item.item_code = item.item_code child_item.item_code = item.item_code
child_item.item_name = item.item_name child_item.item_name = item.item_name
child_item.description = item.description child_item.description = item.description
child_item.reqd_by_date = p_doc.delivery_date child_item.delivery_date = trans_item.get('delivery_date') or p_doc.delivery_date
child_item.uom = item.stock_uom child_item.uom = item.stock_uom
child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0 child_item.conversion_factor = get_conversion_factor(item.item_code, item.stock_uom).get("conversion_factor") or 1.0
child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True) child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
if not child_item.warehouse:
frappe.throw(_("Cannot find {} for item {}. Please set the same in Item Master or Stock Settings.")
.format(frappe.bold("default warehouse"), frappe.bold(item.item_code)))
return child_item return child_item
def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, item_code): def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, trans_item):
""" """
Returns a Purchase Order Item child item containing the default values Returns a Purchase Order Item child item containing the default values
""" """
p_doc = frappe.get_doc(parent_doctype, parent_doctype_name) p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
child_item = frappe.new_doc('Purchase Order Item', p_doc, child_docname) child_item = frappe.new_doc('Purchase Order Item', p_doc, child_docname)
item = frappe.get_doc("Item", item_code) item = frappe.get_doc("Item", trans_item.get('item_code'))
child_item.item_code = item.item_code child_item.item_code = item.item_code
child_item.item_name = item.item_name child_item.item_name = item.item_name
child_item.description = item.description child_item.description = item.description
child_item.schedule_date = p_doc.schedule_date child_item.schedule_date = trans_item.get('schedule_date') or p_doc.schedule_date
child_item.uom = item.stock_uom child_item.uom = item.stock_uom
child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0 child_item.conversion_factor = get_conversion_factor(item.item_code, item.stock_uom).get("conversion_factor") or 1.0
child_item.base_rate = 1 # Initiallize value will update in parent validation child_item.base_rate = 1 # Initiallize value will update in parent validation
child_item.base_amount = 1 # Initiallize value will update in parent validation child_item.base_amount = 1 # Initiallize value will update in parent validation
return child_item return child_item
@ -1196,9 +1199,9 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
if not d.get("docname"): if not d.get("docname"):
new_child_flag = True new_child_flag = True
if parent_doctype == "Sales Order": if parent_doctype == "Sales Order":
child_item = set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, d.get("item_code")) child_item = set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, d)
if parent_doctype == "Purchase Order": if parent_doctype == "Purchase Order":
child_item = set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, d.get("item_code")) child_item = set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, d)
else: else:
child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname")) child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname"))
if flt(child_item.get("rate")) == flt(d.get("rate")) and flt(child_item.get("qty")) == flt(d.get("qty")): if flt(child_item.get("rate")) == flt(d.get("rate")) and flt(child_item.get("qty")) == flt(d.get("qty")):
@ -1243,6 +1246,7 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
child_item.flags.ignore_validate_update_after_submit = True child_item.flags.ignore_validate_update_after_submit = True
if new_child_flag: if new_child_flag:
parent.load_from_db()
child_item.idx = len(parent.items) + 1 child_item.idx = len(parent.items) + 1
child_item.insert() child_item.insert()
else: else:

View File

@ -45,6 +45,7 @@ class BuyingController(StockController):
self.validate_warehouse() self.validate_warehouse()
self.validate_from_warehouse() self.validate_from_warehouse()
self.set_supplier_address() self.set_supplier_address()
self.validate_asset_return()
if self.doctype=="Purchase Invoice": if self.doctype=="Purchase Invoice":
self.validate_purchase_receipt_if_update_stock() self.validate_purchase_receipt_if_update_stock()
@ -101,6 +102,19 @@ class BuyingController(StockController):
d.category = 'Total' d.category = 'Total'
msgprint(_('Tax Category has been changed to "Total" because all the Items are non-stock items')) msgprint(_('Tax Category has been changed to "Total" because all the Items are non-stock items'))
def validate_asset_return(self):
if self.doctype not in ['Purchase Receipt', 'Purchase Invoice'] or not self.is_return:
return
purchase_doc_field = 'purchase_receipt' if self.doctype == 'Purchase Receipt' else 'purchase_invoice'
not_cancelled_asset = [d.name for d in frappe.db.get_all("Asset", {
purchase_doc_field: self.return_against,
"docstatus": 1
})]
if self.is_return and len(not_cancelled_asset):
frappe.throw(_("{} has submitted assets linked to it. You need to cancel the assets to create purchase return.".format(self.return_against)),
title=_("Not Allowed"))
def get_asset_items(self): def get_asset_items(self):
if self.doctype not in ['Purchase Order', 'Purchase Invoice', 'Purchase Receipt']: if self.doctype not in ['Purchase Order', 'Purchase Invoice', 'Purchase Receipt']:
return [] return []

View File

@ -21,6 +21,7 @@ class StockController(AccountsController):
super(StockController, self).validate() super(StockController, self).validate()
self.validate_inspection() self.validate_inspection()
self.validate_serialized_batch() self.validate_serialized_batch()
self.validate_customer_provided_item()
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False): def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
if self.docstatus == 2: if self.docstatus == 2:
@ -377,6 +378,12 @@ class StockController(AccountsController):
for blanket_order in blanket_orders: for blanket_order in blanket_orders:
frappe.get_doc("Blanket Order", blanket_order).update_ordered_qty() frappe.get_doc("Blanket Order", blanket_order).update_ordered_qty()
def validate_customer_provided_item(self):
for d in self.get('items'):
# Customer Provided parts will have zero valuation rate
if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
d.allow_zero_valuation_rate = 1
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None, def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
warehouse_account=None, company=None): warehouse_account=None, company=None):
def _delete_gl_entries(voucher_type, voucher_no): def _delete_gl_entries(voucher_type, voucher_no):

View File

@ -667,8 +667,7 @@ def get_itemised_tax_breakup_html(doc):
itemised_tax=itemised_tax, itemised_tax=itemised_tax,
itemised_taxable_amount=itemised_taxable_amount, itemised_taxable_amount=itemised_taxable_amount,
tax_accounts=tax_accounts, tax_accounts=tax_accounts,
conversion_rate=doc.conversion_rate, doc=doc
currency=doc.currency
) )
) )

View File

@ -1,24 +1,24 @@
{ {
"cards": [ "cards": [
{ {
"icon": "fa fa-star", "hidden": 0,
"links": "[\n {\n \"description\": \"Database of potential customers.\",\n \"label\": \"Lead\",\n \"name\": \"Lead\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Potential opportunities for selling.\",\n \"label\": \"Opportunity\",\n \"name\": \"Opportunity\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Customer database.\",\n \"label\": \"Customer\",\n \"name\": \"Customer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"All Contacts.\",\n \"label\": \"Contact\",\n \"name\": \"Contact\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Record of all communications of type email, phone, chat, visit, etc.\",\n \"label\": \"Communication\",\n \"name\": \"Communication\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Track Leads by Lead Source.\",\n \"label\": \"Lead Source\",\n \"name\": \"Lead Source\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Helps you keep tracks of Contracts based on Supplier, Customer and Employee\",\n \"label\": \"Contract\",\n \"name\": \"Contract\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Helps you manage appointments with your leads\",\n \"label\": \"Appointment\",\n \"name\": \"Appointment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Newsletter\",\n \"name\": \"Newsletter\",\n \"type\": \"doctype\"\n }\n]", "label": "Sales Pipeline",
"title": "Sales Pipeline" "links": "[\n {\n \"description\": \"Database of potential customers.\",\n \"label\": \"Lead\",\n \"name\": \"Lead\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Potential opportunities for selling.\",\n \"label\": \"Opportunity\",\n \"name\": \"Opportunity\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Customer database.\",\n \"label\": \"Customer\",\n \"name\": \"Customer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"All Contacts.\",\n \"label\": \"Contact\",\n \"name\": \"Contact\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Record of all communications of type email, phone, chat, visit, etc.\",\n \"label\": \"Communication\",\n \"name\": \"Communication\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Track Leads by Lead Source.\",\n \"label\": \"Lead Source\",\n \"name\": \"Lead Source\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Helps you keep tracks of Contracts based on Supplier, Customer and Employee\",\n \"label\": \"Contract\",\n \"name\": \"Contract\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Helps you manage appointments with your leads\",\n \"label\": \"Appointment\",\n \"name\": \"Appointment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Newsletter\",\n \"name\": \"Newsletter\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"icon": "fa fa-list", "hidden": 0,
"links": "[\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Lead Details\",\n \"name\": \"Lead Details\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"icon\": \"fa fa-bar-chart\",\n \"label\": \"Sales Funnel\",\n \"name\": \"sales-funnel\",\n \"onboard\": 1,\n \"type\": \"page\"\n },\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Prospects Engaged But Not Converted\",\n \"name\": \"Prospects Engaged But Not Converted\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Opportunity\"\n ],\n \"doctype\": \"Opportunity\",\n \"is_query_report\": true,\n \"label\": \"Minutes to First Response for Opportunity\",\n \"name\": \"Minutes to First Response for Opportunity\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Inactive Customers\",\n \"name\": \"Inactive Customers\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Campaign Efficiency\",\n \"name\": \"Campaign Efficiency\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Lead Owner Efficiency\",\n \"name\": \"Lead Owner Efficiency\",\n \"type\": \"report\"\n }\n]", "label": "Reports",
"title": "Reports" "links": "[\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Lead Details\",\n \"name\": \"Lead Details\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"icon\": \"fa fa-bar-chart\",\n \"label\": \"Sales Funnel\",\n \"name\": \"sales-funnel\",\n \"onboard\": 1,\n \"type\": \"page\"\n },\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Prospects Engaged But Not Converted\",\n \"name\": \"Prospects Engaged But Not Converted\",\n \"onboard\": 1,\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Opportunity\"\n ],\n \"doctype\": \"Opportunity\",\n \"is_query_report\": true,\n \"label\": \"Minutes to First Response for Opportunity\",\n \"name\": \"Minutes to First Response for Opportunity\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Inactive Customers\",\n \"name\": \"Inactive Customers\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Campaign Efficiency\",\n \"name\": \"Campaign Efficiency\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Lead Owner Efficiency\",\n \"name\": \"Lead Owner Efficiency\",\n \"type\": \"report\"\n }\n]"
}, },
{ {
"icon": "fa fa-cog", "hidden": 0,
"links": "[\n {\n \"description\": \"Manage Customer Group Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Customer Group\",\n \"link\": \"Tree/Customer Group\",\n \"name\": \"Customer Group\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Territory Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Territory\",\n \"link\": \"Tree/Territory\",\n \"name\": \"Territory\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Sales Person Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Sales Person\",\n \"link\": \"Tree/Sales Person\",\n \"name\": \"Sales Person\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Sales campaigns.\",\n \"label\": \"Campaign\",\n \"name\": \"Campaign\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Sends Mails to lead or contact based on a Campaign schedule\",\n \"label\": \"Email Campaign\",\n \"name\": \"Email Campaign\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Send mass SMS to your contacts\",\n \"label\": \"SMS Center\",\n \"name\": \"SMS Center\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Logs for maintaining sms delivery status\",\n \"label\": \"SMS Log\",\n \"name\": \"SMS Log\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Setup SMS gateway settings\",\n \"label\": \"SMS Settings\",\n \"name\": \"SMS Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Email Group\",\n \"name\": \"Email Group\",\n \"type\": \"doctype\"\n }\n]", "label": "Settings",
"title": "Settings" "links": "[\n {\n \"description\": \"Manage Customer Group Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Customer Group\",\n \"link\": \"Tree/Customer Group\",\n \"name\": \"Customer Group\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Territory Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Territory\",\n \"link\": \"Tree/Territory\",\n \"name\": \"Territory\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Sales Person Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Sales Person\",\n \"link\": \"Tree/Sales Person\",\n \"name\": \"Sales Person\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Sales campaigns.\",\n \"label\": \"Campaign\",\n \"name\": \"Campaign\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Sends Mails to lead or contact based on a Campaign schedule\",\n \"label\": \"Email Campaign\",\n \"name\": \"Email Campaign\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Send mass SMS to your contacts\",\n \"label\": \"SMS Center\",\n \"name\": \"SMS Center\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Logs for maintaining sms delivery status\",\n \"label\": \"SMS Log\",\n \"name\": \"SMS Log\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Setup SMS gateway settings\",\n \"label\": \"SMS Settings\",\n \"name\": \"SMS Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Email Group\",\n \"name\": \"Email Group\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"icon": "fa fa-star", "hidden": 0,
"links": "[\n {\n \"description\": \"Plan for maintenance visits.\",\n \"label\": \"Maintenance Schedule\",\n \"name\": \"Maintenance Schedule\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Visit report for maintenance call.\",\n \"label\": \"Maintenance Visit\",\n \"name\": \"Maintenance Visit\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Warranty Claim against Serial No.\",\n \"label\": \"Warranty Claim\",\n \"name\": \"Warranty Claim\",\n \"type\": \"doctype\"\n }\n]", "label": "Maintenance",
"title": "Maintenance" "links": "[\n {\n \"description\": \"Plan for maintenance visits.\",\n \"label\": \"Maintenance Schedule\",\n \"name\": \"Maintenance Schedule\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Visit report for maintenance call.\",\n \"label\": \"Maintenance Visit\",\n \"name\": \"Maintenance Visit\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Warranty Claim against Serial No.\",\n \"label\": \"Warranty Claim\",\n \"name\": \"Warranty Claim\",\n \"type\": \"doctype\"\n }\n]"
} }
], ],
"category": "Modules", "category": "Modules",
@ -33,7 +33,7 @@
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "CRM", "label": "CRM",
"modified": "2020-03-12 16:30:41.142037", "modified": "2020-04-01 11:28:51.219999",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "CRM", "module": "CRM",
"name": "CRM", "name": "CRM",
@ -43,25 +43,25 @@
"shortcuts": [ "shortcuts": [
{ {
"format": "Open", "format": "Open",
"is_query_report": 0, "label": "Lead",
"link_to": "Lead", "link_to": "Lead",
"stats_filter": "{\"status\":\"Open\"}", "stats_filter": "{\"status\":\"Open\"}",
"type": "DocType" "type": "DocType"
}, },
{ {
"format": "{} Assigned", "format": "{} Assigned",
"is_query_report": 0, "label": "Opportunity",
"link_to": "Opportunity", "link_to": "Opportunity",
"stats_filter": "{\"_assign\": [\"like\", '%' + frappe.session.user + '%']}", "stats_filter": "{\"_assign\": [\"like\", '%' + frappe.session.user + '%']}",
"type": "DocType" "type": "DocType"
}, },
{ {
"is_query_report": 0, "label": "Customer",
"link_to": "Customer", "link_to": "Customer",
"type": "DocType" "type": "DocType"
}, },
{ {
"is_query_report": 0, "label": "Sales Analytics",
"link_to": "Sales Analytics", "link_to": "Sales Analytics",
"type": "Report" "type": "Report"
} }

View File

@ -1,12 +1,10 @@
{ {
"actions": [],
"allow_events_in_timeline": 1, "allow_events_in_timeline": 1,
"allow_import": 1, "allow_import": 1,
"autoname": "naming_series:", "autoname": "naming_series:",
"creation": "2013-04-10 11:45:37", "creation": "2013-04-10 11:45:37",
"doctype": "DocType", "doctype": "DocType",
"document_type": "Document", "document_type": "Document",
"email_append_to": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [ "field_order": [
"organization_lead", "organization_lead",
@ -34,6 +32,7 @@
"notes", "notes",
"address_info", "address_info",
"address_html", "address_html",
"address_type",
"address_title", "address_title",
"address_line1", "address_line1",
"address_line2", "address_line2",
@ -285,8 +284,7 @@
"depends_on": "eval: doc.__islocal", "depends_on": "eval: doc.__islocal",
"fieldname": "pincode", "fieldname": "pincode",
"fieldtype": "Data", "fieldtype": "Data",
"label": "Postal Code", "label": "Postal Code"
"options": "Country"
}, },
{ {
"fieldname": "column_break2", "fieldname": "column_break2",
@ -304,7 +302,8 @@
"fieldtype": "Data", "fieldtype": "Data",
"label": "Phone", "label": "Phone",
"oldfieldname": "contact_no", "oldfieldname": "contact_no",
"oldfieldtype": "Data" "oldfieldtype": "Data",
"options": "Phone"
}, },
{ {
"depends_on": "eval: doc.__islocal", "depends_on": "eval: doc.__islocal",
@ -312,7 +311,8 @@
"fieldtype": "Data", "fieldtype": "Data",
"label": "Mobile No.", "label": "Mobile No.",
"oldfieldname": "mobile_no", "oldfieldname": "mobile_no",
"oldfieldtype": "Data" "oldfieldtype": "Data",
"options": "Phone"
}, },
{ {
"depends_on": "eval: doc.__islocal", "depends_on": "eval: doc.__islocal",
@ -433,13 +433,21 @@
"fieldname": "contact_section", "fieldname": "contact_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Contact" "label": "Contact"
},
{
"default": "Billing",
"depends_on": "eval: doc.__islocal",
"fieldname": "address_type",
"fieldtype": "Select",
"label": "Address Type",
"options": "Billing\nShipping\nOffice\nPersonal\nPlant\nPostal\nShop\nSubsidiary\nWarehouse\nCurrent\nPermanent\nOther"
} }
], ],
"icon": "fa fa-user", "icon": "fa fa-user",
"idx": 5, "idx": 5,
"image_field": "image", "image_field": "image",
"links": [], "links": [],
"modified": "2020-01-13 16:16:48.885228", "modified": "2020-04-08 22:26:11.687110",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "CRM", "module": "CRM",
"name": "Lead", "name": "Lead",
@ -508,7 +516,6 @@
} }
], ],
"search_fields": "lead_name,lead_owner,status", "search_fields": "lead_name,lead_owner,status",
"sender_field": "email_id",
"show_name_in_global_search": 1, "show_name_in_global_search": 1,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",

View File

@ -126,7 +126,7 @@ class Lead(SellingController):
self.title = self.lead_name self.title = self.lead_name
def create_address(self): def create_address(self):
address_fields = ["address_title", "address_line1", "address_line2", address_fields = ["address_type", "address_title", "address_line1", "address_line2",
"city", "county", "state", "country", "pincode"] "city", "county", "state", "country", "pincode"]
info_fields = ["email_id", "phone", "fax"] info_fields = ["email_id", "phone", "fax"]
@ -209,7 +209,7 @@ class Lead(SellingController):
self.contact_doc.save() self.contact_doc.save()
def flush_address_and_contact_fields(self): def flush_address_and_contact_fields(self):
fields = ['address_line1', 'address_line2', 'address_title', fields = ['address_type', 'address_line1', 'address_line2', 'address_title',
'city', 'county', 'country', 'fax', 'pincode', 'state'] 'city', 'county', 'country', 'fax', 'pincode', 'state']
for field in fields: for field in fields:

View File

@ -423,7 +423,7 @@
"icon": "fa fa-info-sign", "icon": "fa fa-info-sign",
"idx": 195, "idx": 195,
"links": [], "links": [],
"modified": "2020-03-20 12:28:45.228994", "modified": "2020-04-07 09:05:39.391109",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "CRM", "module": "CRM",
"name": "Opportunity", "name": "Opportunity",

View File

@ -336,3 +336,27 @@ def make_opportunity_from_communication(communication, ignore_communication_link
link_communication_to_document(doc, "Opportunity", opportunity.name, ignore_communication_links) link_communication_to_document(doc, "Opportunity", opportunity.name, ignore_communication_links)
return opportunity.name return opportunity.name
@frappe.whitelist()
def get_events(start, end, filters=None):
"""Returns events for Gantt / Calendar view rendering.
:param start: Start date-time.
:param end: End date-time.
:param filters: Filters (JSON).
"""
from frappe.desk.calendar import get_event_conditions
conditions = get_event_conditions("Opportunity", filters)
data = frappe.db.sql("""
select
distinct `tabOpportunity`.name, `tabOpportunity`.customer_name, `tabOpportunity`.opportunity_amount,
`tabOpportunity`.title, `tabOpportunity`.contact_date
from
`tabOpportunity`
where
(`tabOpportunity`.contact_date between %(start)s and %(end)s)
{conditions}
""".format(conditions=conditions), {
"start": start,
"end": end
}, as_dict=True, update={"allDay": 0})
return data

View File

@ -0,0 +1,19 @@
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.views.calendar["Opportunity"] = {
field_map: {
"start": "contact_date",
"end": "contact_date",
"id": "name",
"title": "customer_name",
"allDay": "allDay"
},
options: {
header: {
left: 'prev,next today',
center: 'title',
right: 'month'
}
},
get_events_method: 'erpnext.crm.doctype.opportunity.opportunity.get_events'
}

View File

@ -1,56 +1,69 @@
{ {
"cards": [ "cards": [
{ {
"links": "[\n {\n \"label\": \"Student Attendance Tool\",\n \"name\": \"Student Attendance Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Result Tool\",\n \"name\": \"Assessment Result Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Group Creation Tool\",\n \"name\": \"Student Group Creation Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Program Enrollment Tool\",\n \"name\": \"Program Enrollment Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course Scheduling Tool\",\n \"name\": \"Course Scheduling Tool\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Tools" "label": "Tools",
"links": "[\n {\n \"label\": \"Student Attendance Tool\",\n \"name\": \"Student Attendance Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Result Tool\",\n \"name\": \"Assessment Result Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Group Creation Tool\",\n \"name\": \"Student Group Creation Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Program Enrollment Tool\",\n \"name\": \"Program Enrollment Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course Scheduling Tool\",\n \"name\": \"Course Scheduling Tool\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"dependencies\": [\n \"Program Enrollment\"\n ],\n \"doctype\": \"Program Enrollment\",\n \"is_query_report\": true,\n \"label\": \"Student and Guardian Contact Details\",\n \"name\": \"Student and Guardian Contact Details\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Student Monthly Attendance Sheet\",\n \"name\": \"Student Monthly Attendance Sheet\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Fees\"\n ],\n \"doctype\": \"Fees\",\n \"is_query_report\": true,\n \"label\": \"Student Fee Collection\",\n \"name\": \"Student Fee Collection\",\n \"type\": \"report\"\n }\n]", "hidden": 0,
"title": "Other Reports" "label": "Other Reports",
"links": "[\n {\n \"dependencies\": [\n \"Program Enrollment\"\n ],\n \"doctype\": \"Program Enrollment\",\n \"is_query_report\": true,\n \"label\": \"Student and Guardian Contact Details\",\n \"name\": \"Student and Guardian Contact Details\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Student Monthly Attendance Sheet\",\n \"name\": \"Student Monthly Attendance Sheet\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Fees\"\n ],\n \"doctype\": \"Fees\",\n \"is_query_report\": true,\n \"label\": \"Student Fee Collection\",\n \"name\": \"Student Fee Collection\",\n \"type\": \"report\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"label\": \"Student Category\",\n \"name\": \"Student Category\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Batch Name\",\n \"name\": \"Student Batch Name\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Grading Scale\",\n \"name\": \"Grading Scale\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Academic Term\",\n \"name\": \"Academic Term\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Academic Year\",\n \"name\": \"Academic Year\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Education Settings\",\n \"name\": \"Education Settings\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Settings" "label": "Settings",
"links": "[\n {\n \"label\": \"Student Category\",\n \"name\": \"Student Category\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Batch Name\",\n \"name\": \"Student Batch Name\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Grading Scale\",\n \"name\": \"Grading Scale\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Academic Term\",\n \"name\": \"Academic Term\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Academic Year\",\n \"name\": \"Academic Year\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Education Settings\",\n \"name\": \"Education Settings\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"label\": \"Article\",\n \"name\": \"Article\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Video\",\n \"name\": \"Video\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Quiz\",\n \"name\": \"Quiz\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Content Masters" "label": "Content Masters",
"links": "[\n {\n \"label\": \"Article\",\n \"name\": \"Article\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Video\",\n \"name\": \"Video\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Quiz\",\n \"name\": \"Quiz\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"label\": \"Student Attendance\",\n \"name\": \"Student Attendance\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Leave Application\",\n \"name\": \"Student Leave Application\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Absent Student Report\",\n \"name\": \"Absent Student Report\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Student Batch-Wise Attendance\",\n \"name\": \"Student Batch-Wise Attendance\",\n \"type\": \"report\"\n }\n]", "hidden": 0,
"title": "Attendance" "label": "Attendance",
"links": "[\n {\n \"label\": \"Student Attendance\",\n \"name\": \"Student Attendance\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Leave Application\",\n \"name\": \"Student Leave Application\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Absent Student Report\",\n \"name\": \"Absent Student Report\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Student Batch-Wise Attendance\",\n \"name\": \"Student Batch-Wise Attendance\",\n \"type\": \"report\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"label\": \"Student Applicant\",\n \"name\": \"Student Applicant\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Admission\",\n \"name\": \"Student Admission\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Program Enrollment\",\n \"name\": \"Program Enrollment\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Admission" "label": "Admission",
"links": "[\n {\n \"label\": \"Student Applicant\",\n \"name\": \"Student Applicant\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Admission\",\n \"name\": \"Student Admission\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Program Enrollment\",\n \"name\": \"Program Enrollment\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"label\": \"Assessment Plan\",\n \"name\": \"Assessment Plan\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Group\",\n \"link\": \"Tree/Assessment Group\",\n \"name\": \"Assessment Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Result\",\n \"name\": \"Assessment Result\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Criteria\",\n \"name\": \"Assessment Criteria\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Assessment" "label": "Assessment",
"links": "[\n {\n \"label\": \"Assessment Plan\",\n \"name\": \"Assessment Plan\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Group\",\n \"link\": \"Tree/Assessment Group\",\n \"name\": \"Assessment Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Result\",\n \"name\": \"Assessment Result\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Criteria\",\n \"name\": \"Assessment Criteria\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"label\": \"Student\",\n \"name\": \"Student\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Guardian\",\n \"name\": \"Guardian\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Log\",\n \"name\": \"Student Log\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Group\",\n \"name\": \"Student Group\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Student" "label": "Student",
"links": "[\n {\n \"label\": \"Student\",\n \"name\": \"Student\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Guardian\",\n \"name\": \"Guardian\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Log\",\n \"name\": \"Student Log\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Group\",\n \"name\": \"Student Group\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"label\": \"Program\",\n \"name\": \"Program\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course\",\n \"name\": \"Course\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Topic\",\n \"name\": \"Topic\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Instructor\",\n \"name\": \"Instructor\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Room\",\n \"name\": \"Room\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Masters" "label": "Masters",
"links": "[\n {\n \"label\": \"Program\",\n \"name\": \"Program\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course\",\n \"name\": \"Course\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Topic\",\n \"name\": \"Topic\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Instructor\",\n \"name\": \"Instructor\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Room\",\n \"name\": \"Room\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"label\": \"Course Enrollment\",\n \"name\": \"Course Enrollment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course Activity\",\n \"name\": \"Course Activity\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Quiz Activity\",\n \"name\": \"Quiz Activity\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "LMS Activity" "label": "LMS Activity",
"links": "[\n {\n \"label\": \"Course Enrollment\",\n \"name\": \"Course Enrollment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course Activity\",\n \"name\": \"Course Activity\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Quiz Activity\",\n \"name\": \"Quiz Activity\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"label\": \"Course Schedule\",\n \"name\": \"Course Schedule\",\n \"route\": \"#List/Course Schedule/Calendar\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course Scheduling Tool\",\n \"name\": \"Course Scheduling Tool\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Schedule" "label": "Schedule",
"links": "[\n {\n \"label\": \"Course Schedule\",\n \"name\": \"Course Schedule\",\n \"route\": \"#List/Course Schedule/Calendar\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course Scheduling Tool\",\n \"name\": \"Course Scheduling Tool\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"label\": \"Fees\",\n \"name\": \"Fees\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fee Schedule\",\n \"name\": \"Fee Schedule\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fee Structure\",\n \"name\": \"Fee Structure\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fee Category\",\n \"name\": \"Fee Category\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Fees" "label": "Fees",
"links": "[\n {\n \"label\": \"Fees\",\n \"name\": \"Fees\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fee Schedule\",\n \"name\": \"Fee Schedule\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fee Structure\",\n \"name\": \"Fee Structure\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fee Category\",\n \"name\": \"Fee Category\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"links": "[\n {\n \"dependencies\": [\n \"Assessment Result\"\n ],\n \"doctype\": \"Assessment Result\",\n \"is_query_report\": true,\n \"label\": \"Course wise Assessment Report\",\n \"name\": \"Course wise Assessment Report\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Assessment Result\"\n ],\n \"doctype\": \"Assessment Result\",\n \"is_query_report\": true,\n \"label\": \"Final Assessment Grades\",\n \"name\": \"Final Assessment Grades\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Assessment Plan\"\n ],\n \"doctype\": \"Assessment Plan\",\n \"is_query_report\": true,\n \"label\": \"Assessment Plan Status\",\n \"name\": \"Assessment Plan Status\",\n \"type\": \"report\"\n },\n {\n \"label\": \"Student Report Generation Tool\",\n \"name\": \"Student Report Generation Tool\",\n \"type\": \"doctype\"\n }\n]", "hidden": 0,
"title": "Assessment Reports" "label": "Assessment Reports",
"links": "[\n {\n \"dependencies\": [\n \"Assessment Result\"\n ],\n \"doctype\": \"Assessment Result\",\n \"is_query_report\": true,\n \"label\": \"Course wise Assessment Report\",\n \"name\": \"Course wise Assessment Report\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Assessment Result\"\n ],\n \"doctype\": \"Assessment Result\",\n \"is_query_report\": true,\n \"label\": \"Final Assessment Grades\",\n \"name\": \"Final Assessment Grades\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Assessment Plan\"\n ],\n \"doctype\": \"Assessment Plan\",\n \"is_query_report\": true,\n \"label\": \"Assessment Plan Status\",\n \"name\": \"Assessment Plan Status\",\n \"type\": \"report\"\n },\n {\n \"label\": \"Student Report Generation Tool\",\n \"name\": \"Student Report Generation Tool\",\n \"type\": \"doctype\"\n }\n]"
} }
], ],
"category": "Domains", "category": "Domains",
@ -64,7 +77,7 @@
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "Education", "label": "Education",
"modified": "2020-03-12 16:30:37.217514", "modified": "2020-04-01 11:28:51.011309",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Education", "module": "Education",
"name": "Education", "name": "Education",

View File

@ -46,7 +46,7 @@ def execute(filters=None):
def get_columns(): def get_columns():
columns = [ columns = [
_(" Group Roll No") + "::60", _("Group Roll No") + "::60",
_("Student ID") + ":Link/Student:90", _("Student ID") + ":Link/Student:90",
_("Student Name") + "::150", _("Student Name") + "::150",
_("Student Mobile No.") + "::110", _("Student Mobile No.") + "::110",

View File

@ -121,7 +121,7 @@ def call_mws_method(mws_method, *args, **kwargs):
time.sleep(delay) time.sleep(delay)
continue continue
mws_settings.enable_synch = 0 mws_settings.enable_sync = 0
mws_settings.save() mws_settings.save()
frappe.throw(_("Sync has been temporarily disabled because maximum retries have been exceeded")) frappe.throw(_("Sync has been temporarily disabled because maximum retries have been exceeded"))

View File

@ -39,16 +39,19 @@ __all__ = [
# for a list of the end points and marketplace IDs # for a list of the end points and marketplace IDs
MARKETPLACES = { MARKETPLACES = {
"CA" : "https://mws.amazonservices.ca", #A2EUQ1WTGCTBG2 "CA": "https://mws.amazonservices.ca", #A2EUQ1WTGCTBG2
"US" : "https://mws.amazonservices.com", #ATVPDKIKX0DER", "US": "https://mws.amazonservices.com", #ATVPDKIKX0DER",
"DE" : "https://mws-eu.amazonservices.com", #A1PA6795UKMFR9 "DE": "https://mws-eu.amazonservices.com", #A1PA6795UKMFR9
"ES" : "https://mws-eu.amazonservices.com", #A1RKKUPIHCS9HS "ES": "https://mws-eu.amazonservices.com", #A1RKKUPIHCS9HS
"FR" : "https://mws-eu.amazonservices.com", #A13V1IB3VIYZZH "FR": "https://mws-eu.amazonservices.com", #A13V1IB3VIYZZH
"IN" : "https://mws.amazonservices.in", #A21TJRUUN4KGV "IN": "https://mws.amazonservices.in", #A21TJRUUN4KGV
"IT" : "https://mws-eu.amazonservices.com", #APJ6JRA9NG5V4 "IT": "https://mws-eu.amazonservices.com", #APJ6JRA9NG5V4
"UK" : "https://mws-eu.amazonservices.com", #A1F83G8C2ARO7P "UK": "https://mws-eu.amazonservices.com", #A1F83G8C2ARO7P
"JP" : "https://mws.amazonservices.jp", #A1VC38T7YXB528 "JP": "https://mws.amazonservices.jp", #A1VC38T7YXB528
"CN" : "https://mws.amazonservices.com.cn", #AAHKV2X7AFYLW "CN": "https://mws.amazonservices.com.cn", #AAHKV2X7AFYLW
"AE": " https://mws.amazonservices.ae", #A2VIGQ35RCS4UG
"MX": "https://mws.amazonservices.com.mx", #A1AM78C64UM0Y8
"BR": "https://mws.amazonservices.com", #A2Q3Y263D00KWC
} }

View File

@ -7,14 +7,15 @@ import frappe
from frappe.model.document import Document from frappe.model.document import Document
import dateutil import dateutil
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_methods import get_orders
class AmazonMWSSettings(Document): class AmazonMWSSettings(Document):
def validate(self): def validate(self):
if self.enable_amazon == 1: if self.enable_amazon == 1:
self.enable_synch = 1 self.enable_sync = 1
setup_custom_fields() setup_custom_fields()
else: else:
self.enable_synch = 0 self.enable_sync = 0
def get_products_details(self): def get_products_details(self):
if self.enable_amazon == 1: if self.enable_amazon == 1:
@ -27,7 +28,7 @@ class AmazonMWSSettings(Document):
def schedule_get_order_details(): def schedule_get_order_details():
mws_settings = frappe.get_doc("Amazon MWS Settings") mws_settings = frappe.get_doc("Amazon MWS Settings")
if mws_settings.enable_synch and mws_settings.enable_amazon: if mws_settings.enable_sync and mws_settings.enable_amazon:
after_date = dateutil.parser.parse(mws_settings.after_date).strftime("%Y-%m-%d") after_date = dateutil.parser.parse(mws_settings.after_date).strftime("%Y-%m-%d")
get_orders(after_date = after_date) get_orders(after_date = after_date)

View File

@ -2,15 +2,40 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Tally Migration', { frappe.ui.form.on('Tally Migration', {
onload: function(frm) { onload: function (frm) {
let reload_status = true;
frappe.realtime.on("tally_migration_progress_update", function (data) { frappe.realtime.on("tally_migration_progress_update", function (data) {
if (reload_status) {
frappe.model.with_doc(frm.doc.doctype, frm.doc.name, () => {
frm.refresh_header();
});
reload_status = false;
}
frm.dashboard.show_progress(data.title, (data.count / data.total) * 100, data.message); frm.dashboard.show_progress(data.title, (data.count / data.total) * 100, data.message);
if (data.count == data.total) { let error_occurred = data.count === -1;
window.setTimeout(title => frm.dashboard.hide_progress(title), 1500, data.title); if (data.count == data.total || error_occurred) {
window.setTimeout((title) => {
frm.dashboard.hide_progress(title);
frm.reload_doc();
if (error_occurred) {
frappe.msgprint({
message: __("An error has occurred during {0}. Check {1} for more details",
[
repl("<a href='#Form/Tally Migration/%(tally_document)s' class='variant-click'>%(tally_document)s</a>", {
tally_document: frm.docname
}),
"<a href='#List/Error Log' class='variant-click'>Error Log</a>"
]
),
title: __("Tally Migration Error"),
indicator: "red"
});
}
}, 2000, data.title);
} }
}); });
}, },
refresh: function(frm) { refresh: function (frm) {
if (frm.doc.master_data && !frm.doc.is_master_data_imported) { if (frm.doc.master_data && !frm.doc.is_master_data_imported) {
if (frm.doc.is_master_data_processed) { if (frm.doc.is_master_data_processed) {
if (frm.doc.status != "Importing Master Data") { if (frm.doc.status != "Importing Master Data") {
@ -34,17 +59,17 @@ frappe.ui.form.on('Tally Migration', {
} }
} }
}, },
add_button: function(frm, label, method) { add_button: function (frm, label, method) {
frm.add_custom_button( frm.add_custom_button(
label, label,
() => frm.call({ () => {
frm.call({
doc: frm.doc, doc: frm.doc,
method: method, method: method,
freeze: true, freeze: true
callback: () => { });
frm.remove_custom_button(label); frm.reload_doc();
} }
})
); );
} }
}); });

View File

@ -1,4 +1,5 @@
{ {
"actions": [],
"beta": 1, "beta": 1,
"creation": "2019-02-01 14:27:09.485238", "creation": "2019-02-01 14:27:09.485238",
"doctype": "DocType", "doctype": "DocType",
@ -14,6 +15,7 @@
"tally_debtors_account", "tally_debtors_account",
"company_section", "company_section",
"tally_company", "tally_company",
"default_uom",
"column_break_8", "column_break_8",
"erpnext_company", "erpnext_company",
"processed_files_section", "processed_files_section",
@ -43,6 +45,7 @@
"label": "Status" "label": "Status"
}, },
{ {
"description": "Data exported from Tally that consists of the Chart of Accounts, Customers, Suppliers, Addresses, Items and UOMs",
"fieldname": "master_data", "fieldname": "master_data",
"fieldtype": "Attach", "fieldtype": "Attach",
"in_list_view": 1, "in_list_view": 1,
@ -50,6 +53,7 @@
}, },
{ {
"default": "Sundry Creditors", "default": "Sundry Creditors",
"description": "Creditors Account set in Tally",
"fieldname": "tally_creditors_account", "fieldname": "tally_creditors_account",
"fieldtype": "Data", "fieldtype": "Data",
"label": "Tally Creditors Account", "label": "Tally Creditors Account",
@ -61,6 +65,7 @@
}, },
{ {
"default": "Sundry Debtors", "default": "Sundry Debtors",
"description": "Debtors Account set in Tally",
"fieldname": "tally_debtors_account", "fieldname": "tally_debtors_account",
"fieldtype": "Data", "fieldtype": "Data",
"label": "Tally Debtors Account", "label": "Tally Debtors Account",
@ -72,6 +77,7 @@
"fieldtype": "Section Break" "fieldtype": "Section Break"
}, },
{ {
"description": "Company Name as per Imported Tally Data",
"fieldname": "tally_company", "fieldname": "tally_company",
"fieldtype": "Data", "fieldtype": "Data",
"label": "Tally Company", "label": "Tally Company",
@ -82,9 +88,11 @@
"fieldtype": "Column Break" "fieldtype": "Column Break"
}, },
{ {
"description": "Your Company set in ERPNext",
"fieldname": "erpnext_company", "fieldname": "erpnext_company",
"fieldtype": "Data", "fieldtype": "Data",
"label": "ERPNext Company" "label": "ERPNext Company",
"read_only_depends_on": "eval:doc.is_master_data_processed == 1"
}, },
{ {
"fieldname": "processed_files_section", "fieldname": "processed_files_section",
@ -155,24 +163,28 @@
"options": "Cost Center" "options": "Cost Center"
}, },
{ {
"default": "0",
"fieldname": "is_master_data_processed", "fieldname": "is_master_data_processed",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Is Master Data Processed", "label": "Is Master Data Processed",
"read_only": 1 "read_only": 1
}, },
{ {
"default": "0",
"fieldname": "is_day_book_data_processed", "fieldname": "is_day_book_data_processed",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Is Day Book Data Processed", "label": "Is Day Book Data Processed",
"read_only": 1 "read_only": 1
}, },
{ {
"default": "0",
"fieldname": "is_day_book_data_imported", "fieldname": "is_day_book_data_imported",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Is Day Book Data Imported", "label": "Is Day Book Data Imported",
"read_only": 1 "read_only": 1
}, },
{ {
"default": "0",
"fieldname": "is_master_data_imported", "fieldname": "is_master_data_imported",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Is Master Data Imported", "label": "Is Master Data Imported",
@ -188,13 +200,23 @@
"fieldtype": "Column Break" "fieldtype": "Column Break"
}, },
{ {
"description": "Day Book Data exported from Tally that consists of all historic transactions",
"fieldname": "day_book_data", "fieldname": "day_book_data",
"fieldtype": "Attach", "fieldtype": "Attach",
"in_list_view": 1, "in_list_view": 1,
"label": "Day Book Data" "label": "Day Book Data"
},
{
"default": "Unit",
"description": "UOM in case unspecified in imported data",
"fieldname": "default_uom",
"fieldtype": "Link",
"label": "Default UOM",
"options": "UOM"
} }
], ],
"modified": "2019-04-29 05:46:54.394967", "links": [],
"modified": "2020-04-16 13:03:28.894919",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "ERPNext Integrations", "module": "ERPNext Integrations",
"name": "Tally Migration", "name": "Tally Migration",

View File

@ -4,20 +4,23 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from decimal import Decimal
import json import json
import re import re
import traceback import traceback
import zipfile import zipfile
from decimal import Decimal
from bs4 import BeautifulSoup as bs
import frappe import frappe
from erpnext import encode_company_abbr
from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts
from frappe import _ from frappe import _
from frappe.custom.doctype.custom_field.custom_field import create_custom_field from frappe.custom.doctype.custom_field.custom_field import create_custom_field
from frappe.model.document import Document from frappe.model.document import Document
from frappe.model.naming import getseries, revert_series_if_last from frappe.model.naming import getseries, revert_series_if_last
from frappe.utils.data import format_datetime from frappe.utils.data import format_datetime
from bs4 import BeautifulSoup as bs
from erpnext import encode_company_abbr
from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts
PRIMARY_ACCOUNT = "Primary" PRIMARY_ACCOUNT = "Primary"
VOUCHER_CHUNK_SIZE = 500 VOUCHER_CHUNK_SIZE = 500
@ -39,8 +42,10 @@ class TallyMigration(Document):
return string return string
master_file = frappe.get_doc("File", {"file_url": data_file}) master_file = frappe.get_doc("File", {"file_url": data_file})
master_file_path = master_file.get_full_path()
with zipfile.ZipFile(master_file.get_full_path()) as zf: if zipfile.is_zipfile(master_file_path):
with zipfile.ZipFile(master_file_path) as zf:
encoded_content = zf.read(zf.namelist()[0]) encoded_content = zf.read(zf.namelist()[0])
try: try:
content = encoded_content.decode("utf-8-sig") content = encoded_content.decode("utf-8-sig")
@ -58,13 +63,14 @@ class TallyMigration(Document):
"file_name": key + ".json", "file_name": key + ".json",
"attached_to_doctype": self.doctype, "attached_to_doctype": self.doctype,
"attached_to_name": self.name, "attached_to_name": self.name,
"content": json.dumps(value) "content": json.dumps(value),
"is_private": True
}).insert() }).insert()
setattr(self, key, f.file_url) setattr(self, key, f.file_url)
def _process_master_data(self): def _process_master_data(self):
def get_company_name(collection): def get_company_name(collection):
return collection.find_all("REMOTECMPINFO.LIST")[0].REMOTECMPNAME.string return collection.find_all("REMOTECMPINFO.LIST")[0].REMOTECMPNAME.string.strip()
def get_coa_customers_suppliers(collection): def get_coa_customers_suppliers(collection):
root_type_map = { root_type_map = {
@ -97,17 +103,17 @@ class TallyMigration(Document):
# If Ledger doesn't have PARENT field then don't create Account # If Ledger doesn't have PARENT field then don't create Account
# For example "Profit & Loss A/c" # For example "Profit & Loss A/c"
if account.PARENT: if account.PARENT:
yield account.PARENT.string, account["NAME"], 0 yield account.PARENT.string.strip(), account["NAME"], 0
def get_parent(account): def get_parent(account):
if account.PARENT: if account.PARENT:
return account.PARENT.string return account.PARENT.string.strip()
return { return {
("Yes", "No"): "Application of Funds (Assets)", ("Yes", "No"): "Application of Funds (Assets)",
("Yes", "Yes"): "Expenses", ("Yes", "Yes"): "Expenses",
("No", "Yes"): "Income", ("No", "Yes"): "Income",
("No", "No"): "Source of Funds (Liabilities)", ("No", "No"): "Source of Funds (Liabilities)",
}[(account.ISDEEMEDPOSITIVE.string, account.ISREVENUE.string)] }[(account.ISDEEMEDPOSITIVE.string.strip(), account.ISREVENUE.string.strip())]
def get_children_and_parent_dict(accounts): def get_children_and_parent_dict(accounts):
children, parents = {}, {} children, parents = {}, {}
@ -145,38 +151,38 @@ class TallyMigration(Document):
parties, addresses = [], [] parties, addresses = [], []
for account in collection.find_all("LEDGER"): for account in collection.find_all("LEDGER"):
party_type = None party_type = None
if account.NAME.string in customers: if account.NAME.string.strip() in customers:
party_type = "Customer" party_type = "Customer"
parties.append({ parties.append({
"doctype": party_type, "doctype": party_type,
"customer_name": account.NAME.string, "customer_name": account.NAME.string.strip(),
"tax_id": account.INCOMETAXNUMBER.string if account.INCOMETAXNUMBER else None, "tax_id": account.INCOMETAXNUMBER.string.strip() if account.INCOMETAXNUMBER else None,
"customer_group": "All Customer Groups", "customer_group": "All Customer Groups",
"territory": "All Territories", "territory": "All Territories",
"customer_type": "Individual", "customer_type": "Individual",
}) })
elif account.NAME.string in suppliers: elif account.NAME.string.strip() in suppliers:
party_type = "Supplier" party_type = "Supplier"
parties.append({ parties.append({
"doctype": party_type, "doctype": party_type,
"supplier_name": account.NAME.string, "supplier_name": account.NAME.string.strip(),
"pan": account.INCOMETAXNUMBER.string if account.INCOMETAXNUMBER else None, "pan": account.INCOMETAXNUMBER.string.strip() if account.INCOMETAXNUMBER else None,
"supplier_group": "All Supplier Groups", "supplier_group": "All Supplier Groups",
"supplier_type": "Individual", "supplier_type": "Individual",
}) })
if party_type: if party_type:
address = "\n".join([a.string for a in account.find_all("ADDRESS")]) address = "\n".join([a.string.strip() for a in account.find_all("ADDRESS")])
addresses.append({ addresses.append({
"doctype": "Address", "doctype": "Address",
"address_line1": address[:140].strip(), "address_line1": address[:140].strip(),
"address_line2": address[140:].strip(), "address_line2": address[140:].strip(),
"country": account.COUNTRYNAME.string if account.COUNTRYNAME else None, "country": account.COUNTRYNAME.string.strip() if account.COUNTRYNAME else None,
"state": account.LEDSTATENAME.string if account.LEDSTATENAME else None, "state": account.LEDSTATENAME.string.strip() if account.LEDSTATENAME else None,
"gst_state": account.LEDSTATENAME.string if account.LEDSTATENAME else None, "gst_state": account.LEDSTATENAME.string.strip() if account.LEDSTATENAME else None,
"pin_code": account.PINCODE.string if account.PINCODE else None, "pin_code": account.PINCODE.string.strip() if account.PINCODE else None,
"mobile": account.LEDGERPHONE.string if account.LEDGERPHONE else None, "mobile": account.LEDGERPHONE.string.strip() if account.LEDGERPHONE else None,
"phone": account.LEDGERPHONE.string if account.LEDGERPHONE else None, "phone": account.LEDGERPHONE.string.strip() if account.LEDGERPHONE else None,
"gstin": account.PARTYGSTIN.string if account.PARTYGSTIN else None, "gstin": account.PARTYGSTIN.string.strip() if account.PARTYGSTIN else None,
"links": [{"link_doctype": party_type, "link_name": account["NAME"]}], "links": [{"link_doctype": party_type, "link_name": account["NAME"]}],
}) })
return parties, addresses return parties, addresses
@ -184,41 +190,50 @@ class TallyMigration(Document):
def get_stock_items_uoms(collection): def get_stock_items_uoms(collection):
uoms = [] uoms = []
for uom in collection.find_all("UNIT"): for uom in collection.find_all("UNIT"):
uoms.append({"doctype": "UOM", "uom_name": uom.NAME.string}) uoms.append({"doctype": "UOM", "uom_name": uom.NAME.string.strip()})
items = [] items = []
for item in collection.find_all("STOCKITEM"): for item in collection.find_all("STOCKITEM"):
stock_uom = item.BASEUNITS.string.strip() if item.BASEUNITS else self.default_uom
items.append({ items.append({
"doctype": "Item", "doctype": "Item",
"item_code" : item.NAME.string, "item_code" : item.NAME.string.strip(),
"stock_uom": item.BASEUNITS.string, "stock_uom": stock_uom.strip(),
"is_stock_item": 0, "is_stock_item": 0,
"item_group": "All Item Groups", "item_group": "All Item Groups",
"item_defaults": [{"company": self.erpnext_company}] "item_defaults": [{"company": self.erpnext_company}]
}) })
return items, uoms return items, uoms
try:
self.publish("Process Master Data", _("Reading Uploaded File"), 1, 5) self.publish("Process Master Data", _("Reading Uploaded File"), 1, 5)
collection = self.get_collection(self.master_data) collection = self.get_collection(self.master_data)
company = get_company_name(collection) company = get_company_name(collection)
self.tally_company = company self.tally_company = company
self.erpnext_company = company self.erpnext_company = company
self.publish("Process Master Data", _("Processing Chart of Accounts and Parties"), 2, 5) self.publish("Process Master Data", _("Processing Chart of Accounts and Parties"), 2, 5)
chart_of_accounts, customers, suppliers = get_coa_customers_suppliers(collection) chart_of_accounts, customers, suppliers = get_coa_customers_suppliers(collection)
self.publish("Process Master Data", _("Processing Party Addresses"), 3, 5) self.publish("Process Master Data", _("Processing Party Addresses"), 3, 5)
parties, addresses = get_parties_addresses(collection, customers, suppliers) parties, addresses = get_parties_addresses(collection, customers, suppliers)
self.publish("Process Master Data", _("Processing Items and UOMs"), 4, 5) self.publish("Process Master Data", _("Processing Items and UOMs"), 4, 5)
items, uoms = get_stock_items_uoms(collection) items, uoms = get_stock_items_uoms(collection)
data = {"chart_of_accounts": chart_of_accounts, "parties": parties, "addresses": addresses, "items": items, "uoms": uoms} data = {"chart_of_accounts": chart_of_accounts, "parties": parties, "addresses": addresses, "items": items, "uoms": uoms}
self.publish("Process Master Data", _("Done"), 5, 5)
self.publish("Process Master Data", _("Done"), 5, 5)
self.dump_processed_data(data) self.dump_processed_data(data)
self.is_master_data_processed = 1 self.is_master_data_processed = 1
self.status = ""
self.save() except:
self.publish("Process Master Data", _("Process Failed"), -1, 5)
self.log()
finally:
self.set_status()
def publish(self, title, message, count, total): def publish(self, title, message, count, total):
frappe.publish_realtime("tally_migration_progress_update", {"title": title, "message": message, "count": count, "total": total}) frappe.publish_realtime("tally_migration_progress_update", {"title": title, "message": message, "count": count, "total": total})
@ -256,7 +271,6 @@ class TallyMigration(Document):
except: except:
self.log(address) self.log(address)
def create_items_uoms(items_file_url, uoms_file_url): def create_items_uoms(items_file_url, uoms_file_url):
uoms_file = frappe.get_doc("File", {"file_url": uoms_file_url}) uoms_file = frappe.get_doc("File", {"file_url": uoms_file_url})
for uom in json.loads(uoms_file.get_content()): for uom in json.loads(uoms_file.get_content()):
@ -273,25 +287,35 @@ class TallyMigration(Document):
except: except:
self.log(item) self.log(item)
try:
self.publish("Import Master Data", _("Creating Company and Importing Chart of Accounts"), 1, 4) self.publish("Import Master Data", _("Creating Company and Importing Chart of Accounts"), 1, 4)
create_company_and_coa(self.chart_of_accounts) create_company_and_coa(self.chart_of_accounts)
self.publish("Import Master Data", _("Importing Parties and Addresses"), 2, 4) self.publish("Import Master Data", _("Importing Parties and Addresses"), 2, 4)
create_parties_and_addresses(self.parties, self.addresses) create_parties_and_addresses(self.parties, self.addresses)
self.publish("Import Master Data", _("Importing Items and UOMs"), 3, 4) self.publish("Import Master Data", _("Importing Items and UOMs"), 3, 4)
create_items_uoms(self.items, self.uoms) create_items_uoms(self.items, self.uoms)
self.publish("Import Master Data", _("Done"), 4, 4) self.publish("Import Master Data", _("Done"), 4, 4)
self.status = ""
self.is_master_data_imported = 1 self.is_master_data_imported = 1
self.save()
except:
self.publish("Import Master Data", _("Process Failed"), -1, 5)
self.log()
finally:
self.set_status()
def _process_day_book_data(self): def _process_day_book_data(self):
def get_vouchers(collection): def get_vouchers(collection):
vouchers = [] vouchers = []
for voucher in collection.find_all("VOUCHER"): for voucher in collection.find_all("VOUCHER"):
if voucher.ISCANCELLED.string == "Yes": if voucher.ISCANCELLED.string.strip() == "Yes":
continue continue
inventory_entries = voucher.find_all("INVENTORYENTRIES.LIST") + voucher.find_all("ALLINVENTORYENTRIES.LIST") + voucher.find_all("INVENTORYENTRIESIN.LIST") + voucher.find_all("INVENTORYENTRIESOUT.LIST") inventory_entries = voucher.find_all("INVENTORYENTRIES.LIST") + voucher.find_all("ALLINVENTORYENTRIES.LIST") + voucher.find_all("INVENTORYENTRIESIN.LIST") + voucher.find_all("INVENTORYENTRIESOUT.LIST")
if voucher.VOUCHERTYPENAME.string not in ["Journal", "Receipt", "Payment", "Contra"] and inventory_entries: if voucher.VOUCHERTYPENAME.string.strip() not in ["Journal", "Receipt", "Payment", "Contra"] and inventory_entries:
function = voucher_to_invoice function = voucher_to_invoice
else: else:
function = voucher_to_journal_entry function = voucher_to_journal_entry
@ -307,15 +331,15 @@ class TallyMigration(Document):
accounts = [] accounts = []
ledger_entries = voucher.find_all("ALLLEDGERENTRIES.LIST") + voucher.find_all("LEDGERENTRIES.LIST") ledger_entries = voucher.find_all("ALLLEDGERENTRIES.LIST") + voucher.find_all("LEDGERENTRIES.LIST")
for entry in ledger_entries: for entry in ledger_entries:
account = {"account": encode_company_abbr(entry.LEDGERNAME.string, self.erpnext_company), "cost_center": self.default_cost_center} account = {"account": encode_company_abbr(entry.LEDGERNAME.string.strip(), self.erpnext_company), "cost_center": self.default_cost_center}
if entry.ISPARTYLEDGER.string == "Yes": if entry.ISPARTYLEDGER.string.strip() == "Yes":
party_details = get_party(entry.LEDGERNAME.string) party_details = get_party(entry.LEDGERNAME.string.strip())
if party_details: if party_details:
party_type, party_account = party_details party_type, party_account = party_details
account["party_type"] = party_type account["party_type"] = party_type
account["account"] = party_account account["account"] = party_account
account["party"] = entry.LEDGERNAME.string account["party"] = entry.LEDGERNAME.string.strip()
amount = Decimal(entry.AMOUNT.string) amount = Decimal(entry.AMOUNT.string.strip())
if amount > 0: if amount > 0:
account["credit_in_account_currency"] = str(abs(amount)) account["credit_in_account_currency"] = str(abs(amount))
else: else:
@ -324,21 +348,21 @@ class TallyMigration(Document):
journal_entry = { journal_entry = {
"doctype": "Journal Entry", "doctype": "Journal Entry",
"tally_guid": voucher.GUID.string, "tally_guid": voucher.GUID.string.strip(),
"posting_date": voucher.DATE.string, "posting_date": voucher.DATE.string.strip(),
"company": self.erpnext_company, "company": self.erpnext_company,
"accounts": accounts, "accounts": accounts,
} }
return journal_entry return journal_entry
def voucher_to_invoice(voucher): def voucher_to_invoice(voucher):
if voucher.VOUCHERTYPENAME.string in ["Sales", "Credit Note"]: if voucher.VOUCHERTYPENAME.string.strip() in ["Sales", "Credit Note"]:
doctype = "Sales Invoice" doctype = "Sales Invoice"
party_field = "customer" party_field = "customer"
account_field = "debit_to" account_field = "debit_to"
account_name = encode_company_abbr(self.tally_debtors_account, self.erpnext_company) account_name = encode_company_abbr(self.tally_debtors_account, self.erpnext_company)
price_list_field = "selling_price_list" price_list_field = "selling_price_list"
elif voucher.VOUCHERTYPENAME.string in ["Purchase", "Debit Note"]: elif voucher.VOUCHERTYPENAME.string.strip() in ["Purchase", "Debit Note"]:
doctype = "Purchase Invoice" doctype = "Purchase Invoice"
party_field = "supplier" party_field = "supplier"
account_field = "credit_to" account_field = "credit_to"
@ -351,10 +375,10 @@ class TallyMigration(Document):
invoice = { invoice = {
"doctype": doctype, "doctype": doctype,
party_field: voucher.PARTYNAME.string, party_field: voucher.PARTYNAME.string.strip(),
"tally_guid": voucher.GUID.string, "tally_guid": voucher.GUID.string.strip(),
"posting_date": voucher.DATE.string, "posting_date": voucher.DATE.string.strip(),
"due_date": voucher.DATE.string, "due_date": voucher.DATE.string.strip(),
"items": get_voucher_items(voucher, doctype), "items": get_voucher_items(voucher, doctype),
"taxes": get_voucher_taxes(voucher), "taxes": get_voucher_taxes(voucher),
account_field: account_name, account_field: account_name,
@ -375,15 +399,15 @@ class TallyMigration(Document):
for entry in inventory_entries: for entry in inventory_entries:
qty, uom = entry.ACTUALQTY.string.strip().split() qty, uom = entry.ACTUALQTY.string.strip().split()
items.append({ items.append({
"item_code": entry.STOCKITEMNAME.string, "item_code": entry.STOCKITEMNAME.string.strip(),
"description": entry.STOCKITEMNAME.string, "description": entry.STOCKITEMNAME.string.strip(),
"qty": qty.strip(), "qty": qty.strip(),
"uom": uom.strip(), "uom": uom.strip(),
"conversion_factor": 1, "conversion_factor": 1,
"price_list_rate": entry.RATE.string.split("/")[0], "price_list_rate": entry.RATE.string.strip().split("/")[0],
"cost_center": self.default_cost_center, "cost_center": self.default_cost_center,
"warehouse": self.default_warehouse, "warehouse": self.default_warehouse,
account_field: encode_company_abbr(entry.find_all("ACCOUNTINGALLOCATIONS.LIST")[0].LEDGERNAME.string, self.erpnext_company), account_field: encode_company_abbr(entry.find_all("ACCOUNTINGALLOCATIONS.LIST")[0].LEDGERNAME.string.strip(), self.erpnext_company),
}) })
return items return items
@ -391,13 +415,13 @@ class TallyMigration(Document):
ledger_entries = voucher.find_all("ALLLEDGERENTRIES.LIST") + voucher.find_all("LEDGERENTRIES.LIST") ledger_entries = voucher.find_all("ALLLEDGERENTRIES.LIST") + voucher.find_all("LEDGERENTRIES.LIST")
taxes = [] taxes = []
for entry in ledger_entries: for entry in ledger_entries:
if entry.ISPARTYLEDGER.string == "No": if entry.ISPARTYLEDGER.string.strip() == "No":
tax_account = encode_company_abbr(entry.LEDGERNAME.string, self.erpnext_company) tax_account = encode_company_abbr(entry.LEDGERNAME.string.strip(), self.erpnext_company)
taxes.append({ taxes.append({
"charge_type": "Actual", "charge_type": "Actual",
"account_head": tax_account, "account_head": tax_account,
"description": tax_account, "description": tax_account,
"tax_amount": entry.AMOUNT.string, "tax_amount": entry.AMOUNT.string.strip(),
"cost_center": self.default_cost_center, "cost_center": self.default_cost_center,
}) })
return taxes return taxes
@ -408,15 +432,24 @@ class TallyMigration(Document):
elif frappe.db.exists({"doctype": "Customer", "customer_name": party}): elif frappe.db.exists({"doctype": "Customer", "customer_name": party}):
return "Customer", encode_company_abbr(self.tally_debtors_account, self.erpnext_company) return "Customer", encode_company_abbr(self.tally_debtors_account, self.erpnext_company)
try:
self.publish("Process Day Book Data", _("Reading Uploaded File"), 1, 3) self.publish("Process Day Book Data", _("Reading Uploaded File"), 1, 3)
collection = self.get_collection(self.day_book_data) collection = self.get_collection(self.day_book_data)
self.publish("Process Day Book Data", _("Processing Vouchers"), 2, 3) self.publish("Process Day Book Data", _("Processing Vouchers"), 2, 3)
vouchers = get_vouchers(collection) vouchers = get_vouchers(collection)
self.publish("Process Day Book Data", _("Done"), 3, 3) self.publish("Process Day Book Data", _("Done"), 3, 3)
self.dump_processed_data({"vouchers": vouchers}) self.dump_processed_data({"vouchers": vouchers})
self.status = ""
self.is_day_book_data_processed = 1 self.is_day_book_data_processed = 1
self.save()
except:
self.publish("Process Day Book Data", _("Process Failed"), -1, 5)
self.log()
finally:
self.set_status()
def _import_day_book_data(self): def _import_day_book_data(self):
def create_fiscal_years(vouchers): def create_fiscal_years(vouchers):
@ -454,6 +487,7 @@ class TallyMigration(Document):
"currency": "INR" "currency": "INR"
}).insert() }).insert()
try:
frappe.db.set_value("Account", encode_company_abbr(self.tally_creditors_account, self.erpnext_company), "account_type", "Payable") frappe.db.set_value("Account", encode_company_abbr(self.tally_creditors_account, self.erpnext_company), "account_type", "Payable")
frappe.db.set_value("Account", encode_company_abbr(self.tally_debtors_account, self.erpnext_company), "account_type", "Receivable") frappe.db.set_value("Account", encode_company_abbr(self.tally_debtors_account, self.erpnext_company), "account_type", "Receivable")
frappe.db.set_value("Company", self.erpnext_company, "round_off_account", self.round_off_account) frappe.db.set_value("Company", self.erpnext_company, "round_off_account", self.round_off_account)
@ -467,11 +501,18 @@ class TallyMigration(Document):
total = len(vouchers) total = len(vouchers)
is_last = False is_last = False
for index in range(0, total, VOUCHER_CHUNK_SIZE): for index in range(0, total, VOUCHER_CHUNK_SIZE):
if index + VOUCHER_CHUNK_SIZE >= total: if index + VOUCHER_CHUNK_SIZE >= total:
is_last = True is_last = True
frappe.enqueue_doc(self.doctype, self.name, "_import_vouchers", queue="long", timeout=3600, start=index+1, total=total, is_last=is_last) frappe.enqueue_doc(self.doctype, self.name, "_import_vouchers", queue="long", timeout=3600, start=index+1, total=total, is_last=is_last)
except:
self.log()
finally:
self.set_status()
def _import_vouchers(self, start, total, is_last=False): def _import_vouchers(self, start, total, is_last=False):
frappe.flags.in_migrate = True frappe.flags.in_migrate = True
vouchers_file = frappe.get_doc("File", {"file_url": self.vouchers}) vouchers_file = frappe.get_doc("File", {"file_url": self.vouchers})
@ -494,25 +535,26 @@ class TallyMigration(Document):
frappe.flags.in_migrate = False frappe.flags.in_migrate = False
def process_master_data(self): def process_master_data(self):
self.status = "Processing Master Data" self.set_status("Processing Master Data")
self.save()
frappe.enqueue_doc(self.doctype, self.name, "_process_master_data", queue="long", timeout=3600) frappe.enqueue_doc(self.doctype, self.name, "_process_master_data", queue="long", timeout=3600)
def import_master_data(self): def import_master_data(self):
self.status = "Importing Master Data" self.set_status("Importing Master Data")
self.save()
frappe.enqueue_doc(self.doctype, self.name, "_import_master_data", queue="long", timeout=3600) frappe.enqueue_doc(self.doctype, self.name, "_import_master_data", queue="long", timeout=3600)
def process_day_book_data(self): def process_day_book_data(self):
self.status = "Processing Day Book Data" self.set_status("Processing Day Book Data")
self.save()
frappe.enqueue_doc(self.doctype, self.name, "_process_day_book_data", queue="long", timeout=3600) frappe.enqueue_doc(self.doctype, self.name, "_process_day_book_data", queue="long", timeout=3600)
def import_day_book_data(self): def import_day_book_data(self):
self.status = "Importing Day Book Data" self.set_status("Importing Day Book Data")
self.save()
frappe.enqueue_doc(self.doctype, self.name, "_import_day_book_data", queue="long", timeout=3600) frappe.enqueue_doc(self.doctype, self.name, "_import_day_book_data", queue="long", timeout=3600)
def log(self, data=None): def log(self, data=None):
message = "\n".join(["Data", json.dumps(data, default=str, indent=4), "Exception", traceback.format_exc()]) data = data or self.status
message = "\n".join(["Data:", json.dumps(data, default=str, indent=4), "--" * 50, "\nException:", traceback.format_exc()])
return frappe.log_error(title="Tally Migration Error", message=message) return frappe.log_error(title="Tally Migration Error", message=message)
def set_status(self, status=""):
self.status = status
self.save()

View File

@ -1,28 +1,49 @@
{ {
"cards": [ "cards": [
{ {
"icon": "icon-cog", "icon": "",
"links": "[\n {\n \"label\": \"Healthcare Settings\",\n \"name\": \"Healthcare Settings\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Medical Department\",\n \"name\": \"Medical Department\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Appointment Type\",\n \"name\": \"Appointment Type\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Prescription Dosage\",\n \"name\": \"Prescription Dosage\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Prescription Duration\",\n \"name\": \"Prescription Duration\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Complaint\",\n \"name\": \"Complaint\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Diagnosis\",\n \"name\": \"Diagnosis\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Lab Test Sample\",\n \"name\": \"Lab Test Sample\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Lab Test UOM\",\n \"name\": \"Lab Test UOM\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Antibiotic\",\n \"name\": \"Antibiotic\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Sensitivity\",\n \"name\": \"Sensitivity\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Lab Test Template\",\n \"name\": \"Lab Test Template\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Clinical Procedure Template\",\n \"name\": \"Clinical Procedure Template\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Healthcare Service Unit Type\",\n \"name\": \"Healthcare Service Unit Type\",\n \"type\": \"doctype\"\n }\n]", "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient\",\n\t\t\"label\": \"Patient\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Practitioner\",\n\t\t\"label\":\"Healthcare Practitioner\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Practitioner Schedule\",\n\t\t\"label\": \"Practitioner Schedule\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Medical Department\",\n\t\t\"label\": \"Medical Department\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Service Unit Type\",\n\t\t\"label\": \"Healthcare Service Unit Type\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Service Unit\",\n\t\t\"label\": \"Healthcare Service Unit\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Medical Code Standard\",\n\t\t\"label\": \"Medical Code Standard\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Medical Code\",\n\t\t\"label\": \"Medical Code\"\n\t}\n]",
"title": "Settings"
},
{
"icon": "icon-list",
"links": "[\n {\n \"label\": \"Lab Test\",\n \"name\": \"Lab Test\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Sample Collection\",\n \"name\": \"Sample Collection\",\n \"type\": \"doctype\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Lab Test Report\",\n \"name\": \"Lab Test Report\",\n \"type\": \"report\"\n }\n]",
"title": "Laboratory"
},
{
"icon": "icon-list",
"links": "[\n {\n \"label\": \"Patient\",\n \"name\": \"Patient\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Healthcare Practitioner\",\n \"name\": \"Healthcare Practitioner\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Practitioner Schedule\",\n \"name\": \"Practitioner Schedule\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Medical Code Standard\",\n \"name\": \"Medical Code Standard\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Medical Code\",\n \"name\": \"Medical Code\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Healthcare Service Unit\",\n \"name\": \"Healthcare Service Unit\",\n \"type\": \"doctype\"\n }\n]",
"title": "Masters" "title": "Masters"
}, },
{
"icon": "",
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Appointment Type\",\n\t\t\"label\": \"Appointment Type\"\n },\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Clinical Procedure Template\",\n\t\t\"label\": \"Clinical Procedure Template\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Prescription Dosage\",\n\t\t\"label\": \"Prescription Dosage\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Prescription Duration\",\n\t\t\"label\": \"Prescription Duration\"\n\t},\n\t{\n\t \"type\": \"doctype\",\n\t\t\"name\": \"Antibiotic\",\n\t\t\"label\": \"Antibiotic\"\n\t}\n]",
"title": "Consultation Setup"
},
{ {
"icon": "icon-star", "icon": "icon-star",
"links": "[\n {\n \"label\": \"Patient Appointment\",\n \"name\": \"Patient Appointment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Patient Encounter\",\n \"name\": \"Patient Encounter\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Record Patient Vitals\",\n \"label\": \"Vital Signs\",\n \"name\": \"Vital Signs\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Patient History\",\n \"name\": \"patient_history\",\n \"type\": \"page\"\n },\n {\n \"label\": \"Appointment Analytics\",\n \"name\": \"appointment-analytic\",\n \"type\": \"page\"\n },\n {\n \"label\": \"Clinical Procedure\",\n \"name\": \"Clinical Procedure\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Inpatient Record\",\n \"name\": \"Inpatient Record\",\n \"type\": \"doctype\"\n }\n]", "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Appointment\",\n\t\t\"label\": \"Patient Appointment\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Clinical Procedure\",\n\t\t\"label\": \"Clinical Procedure\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Encounter\",\n\t\t\"label\": \"Patient Encounter\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Vital Signs\",\n\t\t\"label\": \"Vital Signs\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Complaint\",\n\t\t\"label\": \"Complaint\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Diagnosis\",\n\t\t\"label\": \"Diagnosis\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Fee Validity\",\n\t\t\"label\": \"Fee Validity\"\n\t}\n]",
"title": "Consultation" "title": "Consultation"
},
{
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Settings\",\n\t\t\"label\": \"Healthcare Settings\",\n\t\t\"onboard\": 1\n\t}\n]",
"title": "Settings"
},
{
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test Template\",\n\t\t\"label\": \"Lab Test Template\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test Sample\",\n\t\t\"label\": \"Lab Test Sample\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test UOM\",\n\t\t\"label\": \"Lab Test UOM\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Sensitivity\",\n\t\t\"label\": \"Sensitivity\"\n\t}\n]",
"title": "Laboratory Setup"
},
{
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test\",\n\t\t\"label\": \"Lab Test\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Sample Collection\",\n\t\t\"label\": \"Sample Collection\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Dosage Form\",\n\t\t\"label\": \"Dosage Form\"\n\t}\n]",
"title": "Laboratory"
},
{
"links": "[\n\t{\n\t\t\"type\": \"page\",\n\t\t\"name\": \"patient_history\",\n\t\t\"label\": \"Patient History\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Medical Record\",\n\t\t\"label\": \"Patient Medical Record\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Record\",\n\t\t\"label\": \"Inpatient Record\"\n\t}\n]",
"title": "Records and History"
},
{
"links": "[\n\t{\n\t\t\"type\": \"report\",\n\t\t\"is_query_report\": true,\n\t\t\"name\": \"Patient Appointment Analytics\",\n\t\t\"doctype\": \"Patient Appointment\"\n\t},\n\t{\n\t\t\"type\": \"report\",\n\t\t\"is_query_report\": true,\n\t\t\"name\": \"Lab Test Report\",\n\t\t\"doctype\": \"Lab Test\",\n\t\t\"label\": \"Lab Test Report\"\n\t}\n]",
"title": "Reports"
} }
], ],
"category": "Domains", "category": "Domains",
"charts": [], "charts": [
{
"chart_name": "Patient Appointments",
"label": "Patient Appointments"
}
],
"charts_label": "",
"creation": "2020-03-02 17:23:17.919682", "creation": "2020-03-02 17:23:17.919682",
"developer_mode_only": 0, "developer_mode_only": 0,
"disable_user_customization": 0, "disable_user_customization": 0,
@ -32,7 +53,7 @@
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "Healthcare", "label": "Healthcare",
"modified": "2020-03-12 16:30:36.952979", "modified": "2020-03-26 16:10:44.629795",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Healthcare", "module": "Healthcare",
"name": "Healthcare", "name": "Healthcare",
@ -40,5 +61,37 @@
"pin_to_bottom": 0, "pin_to_bottom": 0,
"pin_to_top": 0, "pin_to_top": 0,
"restrict_to_domain": "Healthcare", "restrict_to_domain": "Healthcare",
"shortcuts": [] "shortcuts": [
{
"format": "{} Open",
"is_query_report": 0,
"link_to": "Patient Appointment",
"stats_filter": "{\n \"status\": \"Open\"\n}",
"type": "DocType"
},
{
"format": "{} Active",
"is_query_report": 0,
"link_to": "Patient",
"stats_filter": "{\n \"status\": \"Active\"\n}",
"type": "DocType"
},
{
"format": "{} Vacant",
"is_query_report": 0,
"link_to": "Healthcare Service Unit",
"stats_filter": "{\n \"occupancy_status\": \"Vacant\",\n \"is_group\": 0\n}",
"type": "DocType"
},
{
"is_query_report": 0,
"link_to": "Healthcare Practitioner",
"type": "DocType"
},
{
"is_query_report": 0,
"link_to": "patient_history",
"type": "Page"
}
]
} }

View File

@ -1,213 +1,94 @@
{ {
"allow_copy": 0, "actions": [],
"allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 1, "allow_rename": 1,
"autoname": "field:appointment_type", "autoname": "field:appointment_type",
"beta": 1, "beta": 1,
"creation": "2016-07-22 11:52:34.953019", "creation": "2016-07-22 11:52:34.953019",
"custom": 0,
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "Setup", "document_type": "Setup",
"editable_grid": 0, "engine": "InnoDB",
"field_order": [
"appointment_type",
"ip",
"default_duration",
"color"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 1, "allow_in_quick_entry": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "appointment_type", "fieldname": "appointment_type",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 1, "ignore_xss_filter": 1,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Type", "label": "Type",
"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, "reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 1, "translatable": 1,
"unique": 1 "unique": 1
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0, "default": "0",
"columns": 0,
"fieldname": "ip", "fieldname": "ip",
"fieldtype": "Check", "fieldtype": "Check",
"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": "Is Inpatient", "label": "Is Inpatient",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0, "report_hide": 1
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 1, "allow_in_quick_entry": 1,
"allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0,
"columns": 0,
"description": "In Minutes",
"fieldname": "default_duration", "fieldname": "default_duration",
"fieldtype": "Int", "fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "label": "Default Duration (In Minutes)"
"label": "Default Duration",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 1, "allow_in_quick_entry": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "color", "fieldname": "color",
"fieldtype": "Color", "fieldtype": "Color",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Color", "label": "Color",
"length": 0,
"no_copy": 1, "no_copy": 1,
"permlevel": 0, "report_hide": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
} }
], ],
"has_web_view": 0, "links": [],
"hide_heading": 0, "modified": "2020-02-03 21:06:05.833050",
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-08-08 12:57:54.544216",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Healthcare", "module": "Healthcare",
"name": "Appointment Type", "name": "Appointment Type",
"name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 0,
"cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Healthcare Administrator", "role": "Healthcare Administrator",
"set_user_permissions": 0,
"share": 1, "share": 1,
"submit": 0,
"write": 1 "write": 1
}, },
{ {
"amend": 0,
"cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Physician", "role": "Physician",
"set_user_permissions": 0,
"share": 1, "share": 1,
"submit": 0,
"write": 1 "write": 1
} }
], ],
"quick_entry": 1, "quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"restrict_to_domain": "Healthcare", "restrict_to_domain": "Healthcare",
"search_fields": "appointment_type", "search_fields": "appointment_type",
"show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC"
"title_field": "",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
} }

View File

@ -0,0 +1,13 @@
from __future__ import unicode_literals
from frappe import _
def get_data():
return {
'fieldname': 'appointment_type',
'transactions': [
{
'label': _('Patient Appointments'),
'items': ['Patient Appointment']
},
]
}

View File

@ -4,244 +4,285 @@
frappe.ui.form.on('Clinical Procedure', { frappe.ui.form.on('Clinical Procedure', {
setup: function(frm) { setup: function(frm) {
frm.set_query('batch_no', 'items', function(doc, cdt, cdn) { frm.set_query('batch_no', 'items', function(doc, cdt, cdn) {
var item = locals[cdt][cdn]; let item = locals[cdt][cdn];
if(!item.item_code) { if (!item.item_code) {
frappe.throw(__("Please enter Item Code to get Batch Number")); frappe.throw(__('Please enter Item Code to get Batch Number'));
} else { } else {
let filters = {'item_code': item.item_code};
if (frm.doc.status == 'In Progress') { if (frm.doc.status == 'In Progress') {
var filters = { filters['posting_date'] = frm.doc.start_date || frappe.datetime.nowdate();
'item_code': item.item_code, if (frm.doc.warehouse) filters['warehouse'] = frm.doc.warehouse;
'posting_date': frm.doc.start_date || frappe.datetime.nowdate()
};
if(frm.doc.warehouse) filters["warehouse"] = frm.doc.warehouse;
} else {
filters = {
'item_code': item.item_code
};
} }
return { return {
query : "erpnext.controllers.queries.get_batch_no", query : 'erpnext.controllers.queries.get_batch_no',
filters: filters filters: filters
}; };
} }
}); });
}, },
refresh: function(frm) { refresh: function(frm) {
frm.set_query("patient", function () { frm.set_query('patient', function () {
return { return {
filters: {"disabled": 0} filters: {'status': ['!=', 'Disabled']}
}; };
}); });
frm.set_query("appointment", function () {
frm.set_query('appointment', function () {
return { return {
filters: { filters: {
"procedure_template": ["not in", null], 'procedure_template': ['not in', null],
"status": ['in', 'Open, Scheduled'] 'status': ['in', 'Open, Scheduled']
} }
}; };
}); });
frm.set_query("service_unit", function(){
frm.set_query('service_unit', function() {
return { return {
filters: { filters: {
"is_group": false, 'is_group': false,
"allow_appointments": true 'allow_appointments': true
} }
}; };
}); });
frm.set_query("practitioner", function() {
frm.set_query('practitioner', function() {
return { return {
filters: { filters: {
'department': frm.doc.medical_department 'department': frm.doc.medical_department
} }
}; };
}); });
if(frm.doc.consume_stock){
if (frm.doc.consume_stock) {
frm.set_indicator_formatter('item_code', frm.set_indicator_formatter('item_code',
function(doc) { return (doc.qty<=doc.actual_qty) ? "green" : "orange" ; }); function(doc) { return (doc.qty<=doc.actual_qty) ? 'green' : 'orange' ; });
} }
if (!frm.doc.__islocal && frm.doc.status == 'In Progress'){ if (frm.doc.docstatus == 1) {
if (frm.doc.status == 'In Progress') {
if(frm.doc.consume_stock){ let btn_label = '';
var btn_label = 'Complete and Consume'; let msg = '';
var msg = 'Complete '+frm.doc.name+' and Consume Stock?'; if (frm.doc.consume_stock) {
}else{ btn_label = __('Complete and Consume');
msg = __('Complete {0} and Consume Stock?', [frm.doc.name]);
} else {
btn_label = 'Complete'; btn_label = 'Complete';
msg = 'Complete '+frm.doc.name+'?'; msg = __('Complete {0}?', [frm.doc.name]);
} }
frm.add_custom_button(__(btn_label), function () { frm.add_custom_button(__(btn_label), function () {
frappe.confirm( frappe.confirm(
__(msg), msg,
function(){ function() {
frappe.call({ frappe.call({
method: 'complete_procedure',
doc: frm.doc, doc: frm.doc,
method: "complete",
callback: function(r) { callback: function(r) {
if(!r.exc){ if (r.message) {
cur_frm.reload_doc(); frappe.show_alert({
message: __('Stock Entry {0} created',
['<a class="bold" href="#Form/Stock Entry/'+ r.message + '">' + r.message + '</a>']),
indicator: 'green'
});
frm.reload_doc();
} }
} }
}); });
} }
); );
}); }).addClass("btn-primary");
}else if (frm.doc.status == 'Draft') {
frm.add_custom_button(__("Start"), function () { } else if (frm.doc.status == 'Pending') {
frm.add_custom_button(__('Start'), function() {
frappe.call({ frappe.call({
doc: frm.doc, doc: frm.doc,
method: "start", method: 'start_procedure',
callback: function(r) { callback: function(r) {
if(!r.exc){ if (!r.exc) {
if(frm.doc.status == 'Draft'){ if (r.message == 'insufficient stock') {
let msg = __('Stock quantity to start the Procedure is not available in the Warehouse {0}. Do you want to record a Stock Entry?',
[frm.doc.warehouse.bold()]);
frappe.confirm( frappe.confirm(
__("Stock quantity to start procedure is not available in the warehouse. Do you want to record a Stock Transfer"), msg,
function(){ function() {
frappe.call({ frappe.call({
doc: frm.doc, doc: frm.doc,
method: "make_material_transfer", method: 'make_material_receipt',
callback: function(r) { callback: function(r) {
if(!r.exc){ if (!r.exc) {
cur_frm.reload_doc(); cur_frm.reload_doc();
var doclist = frappe.model.sync(r.message); let doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name); frappe.set_route('Form', doclist[0].doctype, doclist[0].name);
} }
} }
}); });
} }
); );
}else{ } else {
cur_frm.reload_doc(); cur_frm.reload_doc();
} }
} }
} }
}); });
}); }).addClass("btn-primary");
} }
if (frm.doc.__islocal){
frm.set_df_property("consumables", "hidden", 1);
}else{
frm.set_df_property("consumables", "hidden", 0);
} }
}, },
onload: function(frm){
if(frm.doc.status == 'Completed'){ onload: function(frm) {
frm.set_df_property("items", "read_only", 1); if (frm.is_new()) {
} frm.add_fetch('procedure_template', 'medical_department', 'medical_department');
if(frm.is_new()) { frm.set_value('start_time', null);
frm.add_fetch("procedure_template", "medical_department", "medical_department");
frm.set_value("start_time", null);
} }
}, },
patient: function(frm) { patient: function(frm) {
if(frm.doc.patient){ if (frm.doc.patient) {
frappe.call({ frappe.call({
"method": "erpnext.healthcare.doctype.patient.patient.get_patient_detail", 'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail',
args: { args: {
patient: frm.doc.patient patient: frm.doc.patient
}, },
callback: function (data) { callback: function (data) {
let age = ""; let age = '';
if(data.message.dob){ if (data.message.dob) {
age = calculate_age(data.message.dob); age = calculate_age(data.message.dob);
}else if (data.message.age){ } else if (data.message.age) {
age = data.message.age; age = data.message.age;
if(data.message.age_as_on){ if (data.message.age_as_on) {
age = age+" as on "+data.message.age_as_on; age = __('{0} as on {1}', [age, data.message.age_as_on]);
} }
} }
frm.set_value("patient_age", age); frm.set_value('patient_age', age);
frm.set_value("patient_sex", data.message.sex); frm.set_value('patient_sex', data.message.sex);
} }
}); });
}else{ } else {
frm.set_value("patient_age", ""); frm.set_value('patient_age', '');
frm.set_value("patient_sex", ""); frm.set_value('patient_sex', '');
} }
}, },
appointment: function(frm) { appointment: function(frm) {
if(frm.doc.appointment){ if (frm.doc.appointment) {
frappe.call({ frappe.call({
"method": "frappe.client.get", 'method': 'frappe.client.get',
args: { args: {
doctype: "Patient Appointment", doctype: 'Patient Appointment',
name: frm.doc.appointment name: frm.doc.appointment
}, },
callback: function (data) { callback: function(data) {
frm.set_value("patient", data.message.patient); frm.set_value('patient', data.message.patient);
frm.set_value("procedure_template", data.message.procedure_template); frm.set_value('procedure_template', data.message.procedure_template);
frm.set_value("medical_department", data.message.department); frm.set_value('medical_department', data.message.department);
frm.set_value("start_date", data.message.appointment_date); frm.set_value('start_date', data.message.appointment_date);
frm.set_value("start_time", data.message.appointment_time); frm.set_value('start_time', data.message.appointment_time);
frm.set_value("notes", data.message.notes); frm.set_value('notes', data.message.notes);
frm.set_value("service_unit", data.message.service_unit); frm.set_value('service_unit', data.message.service_unit);
} }
}); });
} }
}, },
procedure_template: function(frm) { procedure_template: function(frm) {
if(frm.doc.procedure_template){ if (frm.doc.procedure_template) {
frappe.call({ frappe.call({
"method": "frappe.client.get", 'method': 'frappe.client.get',
args: { args: {
doctype: "Clinical Procedure Template", doctype: 'Clinical Procedure Template',
name: frm.doc.procedure_template name: frm.doc.procedure_template
}, },
callback: function (data) { callback: function (data) {
frm.set_value("medical_department", data.message.medical_department); frm.set_value('medical_department', data.message.medical_department);
frm.set_value("consume_stock", data.message.consume_stock); frm.set_value('consume_stock', data.message.consume_stock);
if(!frm.doc.warehouse){ frm.events.set_warehouse(frm);
frappe.call({ frm.events.set_procedure_consumables(frm);
method: "frappe.client.get_value",
args: {
doctype: "Stock Settings",
fieldname: "default_warehouse"
},
callback: function (data) {
frm.set_value("warehouse", data.message.default_warehouse);
} }
}); });
} }
}
});
}else{
frm.set_value("consume_stock", 0);
}
}, },
service_unit: function(frm) { service_unit: function(frm) {
if(frm.doc.service_unit){ if (frm.doc.service_unit) {
frappe.call({ frappe.call({
method: "frappe.client.get_value", method: 'frappe.client.get_value',
args:{ args:{
fieldname: "warehouse", fieldname: 'warehouse',
doctype: "Healthcare Service Unit", doctype: 'Healthcare Service Unit',
filters:{name: frm.doc.service_unit}, filters:{name: frm.doc.service_unit},
}, },
callback: function(data) { callback: function(data) {
if(data.message){ if (data.message) {
frm.set_value("warehouse", data.message.warehouse); frm.set_value('warehouse', data.message.warehouse);
} }
} }
}); });
} }
}, },
practitioner: function(frm) { practitioner: function(frm) {
if(frm.doc.practitioner){ if (frm.doc.practitioner) {
frappe.call({ frappe.call({
"method": "frappe.client.get", 'method': 'frappe.client.get',
args: { args: {
doctype: "Healthcare Practitioner", doctype: 'Healthcare Practitioner',
name: frm.doc.practitioner name: frm.doc.practitioner
}, },
callback: function (data) { callback: function (data) {
frappe.model.set_value(frm.doctype,frm.docname, "medical_department",data.message.department); frappe.model.set_value(frm.doctype,frm.docname, 'medical_department',data.message.department);
} }
}); });
} }
},
set_warehouse: function(frm) {
if (!frm.doc.warehouse) {
frappe.call({
method: 'frappe.client.get_value',
args: {
doctype: 'Stock Settings',
fieldname: 'default_warehouse'
},
callback: function (data) {
frm.set_value('warehouse', data.message.default_warehouse);
} }
});
}
},
set_procedure_consumables: function(frm) {
frappe.call({
method: 'erpnext.healthcare.doctype.clinical_procedure.clinical_procedure.get_procedure_consumables',
args: {
procedure_template: frm.doc.procedure_template
},
callback: function(data) {
if (data.message) {
frm.doc.items = [];
$.each(data.message, function(i, v) {
let item = frm.add_child('items');
item.item_code = v.item_code;
item.item_name = v.item_name;
item.uom = v.uom;
item.stock_uom = v.stock_uom;
item.qty = flt(v.qty);
item.transfer_qty = v.transfer_qty;
item.conversion_factor = v.conversion_factor;
item.invoice_separately_as_consumables = v.invoice_separately_as_consumables;
item.batch_no = v.batch_no;
});
refresh_field('items');
}
}
});
}
}); });
cur_frm.set_query("procedure_template", function(doc) { cur_frm.set_query('procedure_template', function(doc) {
return { return {
filters: { filters: {
'medical_department': doc.medical_department 'medical_department': doc.medical_department
@ -249,57 +290,51 @@ cur_frm.set_query("procedure_template", function(doc) {
}; };
}); });
cur_frm.set_query("appointment", function() {
return {
filters: {
status:['in',["Open"]]
}
};
});
frappe.ui.form.on('Clinical Procedure Item', { frappe.ui.form.on('Clinical Procedure Item', {
qty: function(frm, cdt, cdn){ qty: function(frm, cdt, cdn) {
var d = locals[cdt][cdn]; let d = locals[cdt][cdn];
frappe.model.set_value(cdt, cdn, "transfer_qty", d.qty*d.conversion_factor); frappe.model.set_value(cdt, cdn, 'transfer_qty', d.qty*d.conversion_factor);
}, },
uom: function(doc, cdt, cdn){
var d = locals[cdt][cdn]; uom: function(doc, cdt, cdn) {
if(d.uom && d.item_code){ let d = locals[cdt][cdn];
if (d.uom && d.item_code) {
return frappe.call({ return frappe.call({
method: "erpnext.stock.doctype.stock_entry.stock_entry.get_uom_details", method: 'erpnext.stock.doctype.stock_entry.stock_entry.get_uom_details',
args: { args: {
item_code: d.item_code, item_code: d.item_code,
uom: d.uom, uom: d.uom,
qty: d.qty qty: d.qty
}, },
callback: function(r) { callback: function(r) {
if(r.message) { if (r.message) {
frappe.model.set_value(cdt, cdn, r.message); frappe.model.set_value(cdt, cdn, r.message);
} }
} }
}); });
} }
}, },
item_code: function(frm, cdt, cdn) { item_code: function(frm, cdt, cdn) {
var d = locals[cdt][cdn]; let d = locals[cdt][cdn];
let args = null; let args = null;
if(d.item_code) { if (d.item_code) {
args = { args = {
'doctype' : "Clinical Procedure", 'doctype' : 'Clinical Procedure',
'item_code' : d.item_code, 'item_code' : d.item_code,
'company' : frm.doc.company, 'company' : frm.doc.company,
'warehouse': frm.doc.warehouse 'warehouse': frm.doc.warehouse
}; };
return frappe.call({ return frappe.call({
method: "erpnext.stock.get_item_details.get_item_details", method: 'erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.get_item_details',
args: {args: args}, args: {args: args},
callback: function(r) { callback: function(r) {
if(r.message) { if (r.message) {
frappe.model.set_value(cdt, cdn, "item_name", r.message.item_name); let d = locals[cdt][cdn];
frappe.model.set_value(cdt, cdn, "stock_uom", r.message.stock_uom); $.each(r.message, function(k, v) {
frappe.model.set_value(cdt, cdn, "conversion_factor", r.message.conversion_factor); d[k] = v;
frappe.model.set_value(cdt, cdn, "actual_qty", r.message.actual_qty); });
refresh_field("items"); refresh_field('items');
} }
} }
}); });
@ -307,16 +342,16 @@ frappe.ui.form.on('Clinical Procedure Item', {
} }
}); });
var calculate_age = function(birth) { let calculate_age = function(birth) {
var ageMS = Date.parse(Date()) - Date.parse(birth); let ageMS = Date.parse(Date()) - Date.parse(birth);
var age = new Date(); let age = new Date();
age.setTime(ageMS); age.setTime(ageMS);
var years = age.getFullYear() - 1970; let years = age.getFullYear() - 1970;
return years + " Year(s) " + age.getMonth() + " Month(s) " + age.getDate() + " Day(s)"; return years + ' Year(s) ' + age.getMonth() + ' Month(s) ' + age.getDate() + ' Day(s)';
}; };
// List Stock items // List Stock items
cur_frm.set_query("item_code", "items", function() { cur_frm.set_query('item_code', 'items', function() {
return { return {
filters: { filters: {
is_stock_item:1 is_stock_item:1

View File

@ -6,88 +6,101 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe import _ from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
from frappe.utils import cint, flt, nowdate, nowtime, cstr from frappe.utils import flt, nowdate, nowtime, cstr
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_account from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_account
from erpnext.healthcare.doctype.lab_test.lab_test import create_sample_doc from erpnext.healthcare.doctype.lab_test.lab_test import create_sample_doc
from erpnext.stock.stock_ledger import get_previous_sle from erpnext.stock.stock_ledger import get_previous_sle
from erpnext.stock.get_item_details import get_item_details from erpnext.stock.get_item_details import get_item_details
from frappe.model.mapper import get_mapped_doc
class ClinicalProcedure(Document): class ClinicalProcedure(Document):
def validate(self): def validate(self):
if self.consume_stock and not self.status == 'Draft': self.set_status()
if not self.warehouse: if self.consume_stock:
frappe.throw(_("Set warehouse for Procedure {0} ").format(self.name))
self.set_actual_qty() self.set_actual_qty()
if self.items: if self.items:
self.invoice_separately_as_consumables = False self.invoice_separately_as_consumables = False
for item in self.items: for item in self.items:
if item.invoice_separately_as_consumables == 1: if item.invoice_separately_as_consumables:
self.invoice_separately_as_consumables = True self.invoice_separately_as_consumables = True
def before_insert(self): def before_insert(self):
if self.consume_stock: if self.consume_stock:
set_stock_items(self, self.procedure_template, "Clinical Procedure Template") self.set_actual_qty()
self.set_actual_qty();
def after_insert(self): def after_insert(self):
if self.prescription: if self.prescription:
frappe.db.set_value("Procedure Prescription", self.prescription, "procedure_created", 1) frappe.db.set_value('Procedure Prescription', self.prescription, 'procedure_created', 1)
if self.appointment: if self.appointment:
frappe.db.set_value("Patient Appointment", self.appointment, "status", "Closed") frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Closed')
template = frappe.get_doc("Clinical Procedure Template", self.procedure_template) template = frappe.get_doc('Clinical Procedure Template', self.procedure_template)
if template.sample: if template.sample:
patient = frappe.get_doc("Patient", self.patient) patient = frappe.get_doc('Patient', self.patient)
sample_collection = create_sample_doc(template, patient, None) sample_collection = create_sample_doc(template, patient, None)
frappe.db.set_value("Clinical Procedure", self.name, "sample", sample_collection.name) frappe.db.set_value('Clinical Procedure', self.name, 'sample', sample_collection.name)
self.reload() self.reload()
def complete(self): def set_status(self):
if self.docstatus == 0:
self.status = 'Draft'
elif self.docstatus == 1:
if self.status not in ['In Progress', 'Completed']:
self.status = 'Pending'
elif self.docstatus == 2:
self.status = 'Cancelled'
def complete_procedure(self):
if self.consume_stock and self.items: if self.consume_stock and self.items:
create_stock_entry(self) stock_entry = make_stock_entry(self)
frappe.db.set_value("Clinical Procedure", self.name, "status", 'Completed')
if self.items: if self.items:
consumable_total_amount = 0 consumable_total_amount = 0
consumption_details = False consumption_details = False
customer = frappe.db.get_value('Patient', self.patient, 'customer')
if customer:
for item in self.items: for item in self.items:
if item.invoice_separately_as_consumables: if item.invoice_separately_as_consumables:
price_list, price_list_currency = frappe.db.get_values("Price List", {"selling": 1}, ['name', 'currency'])[0] price_list, price_list_currency = frappe.db.get_values('Price List', {'selling': 1}, ['name', 'currency'])[0]
args = { args = {
'doctype': "Sales Invoice", 'doctype': 'Sales Invoice',
'item_code': item.item_code, 'item_code': item.item_code,
'company': self.company, 'company': self.company,
'warehouse': self.warehouse, 'warehouse': self.warehouse,
'customer': frappe.db.get_value("Patient", self.patient, "customer"), 'customer': customer,
'selling_price_list': price_list, 'selling_price_list': price_list,
'price_list_currency': price_list_currency, 'price_list_currency': price_list_currency,
'plc_conversion_rate': 1.0, 'plc_conversion_rate': 1.0,
'conversion_rate': 1.0 'conversion_rate': 1.0
} }
item_details = get_item_details(args) item_details = get_item_details(args)
item_price = item_details.price_list_rate * item.transfer_qty item_price = item_details.price_list_rate * item.qty
item_consumption_details = item_details.item_name+"\t"+str(item.qty)+" "+item.uom+"\t"+str(item_price) item_consumption_details = item_details.item_name + ' ' + str(item.qty) + ' ' + item.uom + ' ' + str(item_price)
consumable_total_amount += item_price consumable_total_amount += item_price
if not consumption_details: if not consumption_details:
consumption_details = "Clinical Procedure ("+self.name+"):\n\t"+item_consumption_details consumption_details = _('Clinical Procedure ({0}):').format(self.name)
else: consumption_details += '\n\t' + item_consumption_details
consumption_details += "\n\t"+item_consumption_details
if consumable_total_amount > 0: if consumable_total_amount > 0:
frappe.db.set_value("Clinical Procedure", self.name, "consumable_total_amount", consumable_total_amount) frappe.db.set_value('Clinical Procedure', self.name, 'consumable_total_amount', consumable_total_amount)
frappe.db.set_value("Clinical Procedure", self.name, "consumption_details", consumption_details) frappe.db.set_value('Clinical Procedure', self.name, 'consumption_details', consumption_details)
else:
frappe.throw(_('Please set Customer in Patient {0}').format(frappe.bold(self.patient)), title=_('Customer Not Found'))
frappe.db.set_value('Clinical Procedure', self.name, 'status', 'Completed')
if self.consume_stock and self.items:
return stock_entry
def start(self): def start_procedure(self):
allow_start = self.set_actual_qty() allow_start = self.set_actual_qty()
if allow_start: if allow_start:
self.status = 'In Progress' self.db_set('status', 'In Progress')
insert_clinical_procedure_to_medical_record(self) insert_clinical_procedure_to_medical_record(self)
else: return 'success'
self.status = 'Draft' return 'insufficient stock'
self.save()
def set_actual_qty(self): def set_actual_qty(self):
allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock")) allow_negative_stock = frappe.db.get_single_value('Stock Settings', 'allow_negative_stock')
allow_start = True allow_start = True
for d in self.get('items'): for d in self.get('items'):
@ -95,15 +108,16 @@ class ClinicalProcedure(Document):
# validate qty # validate qty
if not allow_negative_stock and d.actual_qty < d.qty: if not allow_negative_stock and d.actual_qty < d.qty:
allow_start = False allow_start = False
break
return allow_start return allow_start
def make_material_transfer(self): def make_material_receipt(self, submit=False):
stock_entry = frappe.new_doc("Stock Entry") stock_entry = frappe.new_doc('Stock Entry')
stock_entry.purpose = "Material Transfer" stock_entry.stock_entry_type = 'Material Receipt'
stock_entry.to_warehouse = self.warehouse stock_entry.to_warehouse = self.warehouse
expense_account = get_account(None, "expense_account", "Healthcare Settings", self.company) expense_account = get_account(None, 'expense_account', 'Healthcare Settings', self.company)
for item in self.items: for item in self.items:
if item.qty > item.actual_qty: if item.qty > item.actual_qty:
se_child = stock_entry.append('items') se_child = stock_entry.append('items')
@ -111,7 +125,7 @@ class ClinicalProcedure(Document):
se_child.item_name = item.item_name se_child.item_name = item.item_name
se_child.uom = item.uom se_child.uom = item.uom
se_child.stock_uom = item.stock_uom se_child.stock_uom = item.stock_uom
se_child.qty = flt(item.qty-item.actual_qty) se_child.qty = flt(item.qty - item.actual_qty)
se_child.t_warehouse = self.warehouse se_child.t_warehouse = self.warehouse
# in stock uom # in stock uom
se_child.transfer_qty = flt(item.transfer_qty) se_child.transfer_qty = flt(item.transfer_qty)
@ -119,104 +133,130 @@ class ClinicalProcedure(Document):
cost_center = frappe.get_cached_value('Company', self.company, 'cost_center') cost_center = frappe.get_cached_value('Company', self.company, 'cost_center')
se_child.cost_center = cost_center se_child.cost_center = cost_center
se_child.expense_account = expense_account se_child.expense_account = expense_account
if submit:
stock_entry.submit()
return stock_entry
return stock_entry.as_dict() return stock_entry.as_dict()
@frappe.whitelist()
def get_stock_qty(item_code, warehouse): def get_stock_qty(item_code, warehouse):
return get_previous_sle({ return get_previous_sle({
"item_code": item_code, 'item_code': item_code,
"warehouse": warehouse, 'warehouse': warehouse,
"posting_date": nowdate(), 'posting_date': nowdate(),
"posting_time": nowtime() 'posting_time': nowtime()
}).get("qty_after_transaction") or 0 }).get('qty_after_transaction') or 0
@frappe.whitelist()
def get_procedure_consumables(procedure_template):
return get_items('Clinical Procedure Item', procedure_template, 'Clinical Procedure Template')
@frappe.whitelist() @frappe.whitelist()
def set_stock_items(doc, stock_detail_parent, parenttype): def set_stock_items(doc, stock_detail_parent, parenttype):
item_dict = get_item_dict("Clinical Procedure Item", stock_detail_parent, parenttype) items = get_items('Clinical Procedure Item', stock_detail_parent, parenttype)
for d in item_dict: for item in items:
se_child = doc.append('items') se_child = doc.append('items')
se_child.item_code = d["item_code"] se_child.item_code = item.item_code
se_child.item_name = d["item_name"] se_child.item_name = item.item_name
se_child.uom = d["uom"] se_child.uom = item.uom
se_child.stock_uom = d["stock_uom"] se_child.stock_uom = item.stock_uom
se_child.qty = flt(d["qty"]) se_child.qty = flt(item.qty)
# in stock uom # in stock uom
se_child.transfer_qty = flt(d["transfer_qty"]) se_child.transfer_qty = flt(item.transfer_qty)
se_child.conversion_factor = flt(d["conversion_factor"]) se_child.conversion_factor = flt(item.conversion_factor)
if d["batch_no"]: if item.batch_no:
se_child.batch_no = d["batch_no"] se_child.batch_no = item.batch_no
if parenttype == "Clinical Procedure Template": if parenttype == 'Clinical Procedure Template':
se_child.invoice_separately_as_consumables = d["invoice_separately_as_consumables"] se_child.invoice_separately_as_consumables = item.invoice_separately_as_consumables
return doc return doc
def get_item_dict(table, parent, parenttype):
query = """select * from `tab{table}` where parent = '{parent}' and parenttype = '{parenttype}' """
return frappe.db.sql(query.format(table=table, parent=parent, parenttype=parenttype), as_dict=True) def get_items(table, parent, parenttype):
items = frappe.db.get_all(table, filters={
'parent': parent,
'parenttype': parenttype
}, fields=['*'])
def create_stock_entry(doc): return items
stock_entry = frappe.new_doc("Stock Entry")
stock_entry = set_stock_items(stock_entry, doc.name, "Clinical Procedure")
stock_entry.purpose = "Material Issue" @frappe.whitelist()
def make_stock_entry(doc):
stock_entry = frappe.new_doc('Stock Entry')
stock_entry = set_stock_items(stock_entry, doc.name, 'Clinical Procedure')
stock_entry.stock_entry_type = 'Material Issue'
stock_entry.from_warehouse = doc.warehouse stock_entry.from_warehouse = doc.warehouse
stock_entry.company = doc.company stock_entry.company = doc.company
expense_account = get_account(None, "expense_account", "Healthcare Settings", doc.company) expense_account = get_account(None, 'expense_account', 'Healthcare Settings', doc.company)
for item_line in stock_entry.items: for item_line in stock_entry.items:
cost_center = frappe.get_cached_value('Company', doc.company, 'cost_center') cost_center = frappe.get_cached_value('Company', doc.company, 'cost_center')
#item_line.s_warehouse = warehouse #deaful source warehouse set, stock entry to copy to lines
item_line.cost_center = cost_center item_line.cost_center = cost_center
#if not expense_account:
# expense_account = frappe.db.get_value("Item", item_line.item_code, "expense_account")
item_line.expense_account = expense_account item_line.expense_account = expense_account
stock_entry.insert(ignore_permissions = True) stock_entry.save(ignore_permissions=True)
stock_entry.submit() stock_entry.submit()
return stock_entry.name
@frappe.whitelist() @frappe.whitelist()
def create_procedure(appointment): def make_procedure(source_name, target_doc=None):
appointment = frappe.get_doc("Patient Appointment",appointment) def set_missing_values(source, target):
procedure = frappe.new_doc("Clinical Procedure") consume_stock = frappe.db.get_value('Clinical Procedure Template', source.procedure_template, 'consume_stock')
procedure.appointment = appointment.name if consume_stock:
procedure.patient = appointment.patient target.consume_stock = 1
procedure.patient_age = appointment.patient_age warehouse = None
procedure.patient_sex = appointment.patient_sex if source.service_unit:
procedure.procedure_template = appointment.procedure_template warehouse = frappe.db.get_value('Healthcare Service Unit', source.service_unit, 'warehouse')
procedure.prescription = appointment.procedure_prescription
procedure.practitioner = appointment.practitioner
procedure.invoiced = appointment.invoiced
procedure.medical_department = appointment.department
procedure.start_date = appointment.appointment_date
procedure.start_time = appointment.appointment_time
procedure.notes = appointment.notes
procedure.service_unit = appointment.service_unit
procedure.company = appointment.company
consume_stock = frappe.db.get_value("Clinical Procedure Template", appointment.procedure_template, "consume_stock")
if consume_stock == 1:
procedure.consume_stock = True
warehouse = False
if appointment.service_unit:
warehouse = frappe.db.get_value("Healthcare Service Unit", appointment.service_unit, "warehouse")
if not warehouse: if not warehouse:
warehouse = frappe.db.get_value("Stock Settings", None, "default_warehouse") warehouse = frappe.db.get_value('Stock Settings', None, 'default_warehouse')
if warehouse: if warehouse:
procedure.warehouse = warehouse target.warehouse = warehouse
return procedure.as_dict()
set_stock_items(target, source.procedure_template, 'Clinical Procedure Template')
doc = get_mapped_doc('Patient Appointment', source_name, {
'Patient Appointment': {
'doctype': 'Clinical Procedure',
'field_map': [
['appointment', 'name'],
['patient', 'patient'],
['patient_age', 'patient_age'],
['patient_sex', 'patient_sex'],
['procedure_template', 'procedure_template'],
['prescription', 'procedure_prescription'],
['practitioner', 'practitioner'],
['medical_department', 'department'],
['start_date', 'appointment_date'],
['start_time', 'appointment_time'],
['notes', 'notes'],
['service_unit', 'service_unit'],
['company', 'company'],
['invoiced', 'invoiced']
]
}
}, target_doc, set_missing_values)
return doc
def insert_clinical_procedure_to_medical_record(doc): def insert_clinical_procedure_to_medical_record(doc):
subject = cstr(doc.procedure_template) subject = cstr(doc.procedure_template)
if doc.practitioner: if doc.practitioner:
subject += " "+doc.practitioner subject += ' ' + doc.practitioner
if subject and doc.notes: if subject and doc.notes:
subject += "<br/>"+doc.notes subject += '<br/>' + doc.notes
medical_record = frappe.new_doc("Patient Medical Record") medical_record = frappe.new_doc('Patient Medical Record')
medical_record.patient = doc.patient medical_record.patient = doc.patient
medical_record.subject = subject medical_record.subject = subject
medical_record.status = "Open" medical_record.status = 'Open'
medical_record.communication_date = doc.start_date medical_record.communication_date = doc.start_date
medical_record.reference_doctype = "Clinical Procedure" medical_record.reference_doctype = 'Clinical Procedure'
medical_record.reference_name = doc.name medical_record.reference_name = doc.name
medical_record.reference_owner = doc.owner medical_record.reference_owner = doc.owner
medical_record.save(ignore_permissions=True) medical_record.save(ignore_permissions=True)

View File

@ -0,0 +1,11 @@
frappe.listview_settings['Clinical Procedure'] = {
get_indicator: function(doc) {
var colors = {
'Completed': 'green',
'In Progress': 'orange',
'Pending': 'orange',
'Cancelled': 'grey'
};
return [__(doc.status), colors[doc.status], 'status,=,' + doc.status];
}
};

View File

@ -4,6 +4,60 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest import unittest
import frappe
from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_healthcare_docs, create_clinical_procedure_template
class TestClinicalProcedure(unittest.TestCase): class TestClinicalProcedure(unittest.TestCase):
pass def test_procedure_template_item(self):
patient, medical_department, practitioner = create_healthcare_docs()
procedure_template = create_clinical_procedure_template()
self.assertTrue(frappe.db.exists('Item', procedure_template.item))
procedure_template.disabled = 1
procedure_template.save()
self.assertEquals(frappe.db.get_value('Item', procedure_template.item, 'disabled'), 1)
def test_consumables(self):
patient, medical_department, practitioner = create_healthcare_docs()
procedure_template = create_clinical_procedure_template()
procedure_template.allow_stock_consumption = 1
consumable = create_consumable()
procedure_template.append('items', {
'item_code': consumable.item_code,
'qty': 1,
'uom': consumable.stock_uom,
'stock_uom': consumable.stock_uom
})
procedure_template.save()
procedure = create_procedure(procedure_template, patient, practitioner)
result = procedure.start_procedure()
if result == 'insufficient stock':
procedure.make_material_receipt(submit=True)
result = procedure.start_procedure()
self.assertEqual(procedure.status, 'In Progress')
result = procedure.complete_procedure()
# check consumption
self.assertTrue(frappe.db.exists('Stock Entry', result))
def create_consumable():
if frappe.db.exists('Item', 'Syringe'):
return frappe.get_doc('Item', 'Syringe')
consumable = frappe.new_doc('Item')
consumable.item_code = 'Syringe'
consumable.item_group = '_Test Item Group'
consumable.stock_uom = 'Nos'
consumable.valuation_rate = 5.00
consumable.save()
return consumable
def create_procedure(procedure_template, patient, practitioner):
procedure = frappe.new_doc('Clinical Procedure')
procedure.procedure_template = procedure_template.name
procedure.patient = patient
procedure.practitioner = practitioner
procedure.consume_stock = procedure_template.allow_stock_consumption
procedure.items = procedure_template.items
procedure.warehouse = frappe.db.get_single_value('Stock Settings', 'default_warehouse')
procedure.submit()
return procedure

View File

@ -1,431 +1,123 @@
{ {
"allow_copy": 0, "actions": [],
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 1, "beta": 1,
"creation": "2017-10-05 16:15:10.876952", "creation": "2017-10-05 16:15:10.876952",
"custom": 0,
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [
"item_code",
"item_name",
"qty",
"barcode",
"uom",
"invoice_separately_as_consumables",
"column_break_5",
"batch_no",
"conversion_factor",
"stock_uom",
"transfer_qty",
"actual_qty"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0,
"columns": 3, "columns": 3,
"fieldname": "item_code", "fieldname": "item_code",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1, "ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 1, "in_global_search": 1,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Item", "label": "Item",
"length": 0,
"no_copy": 0,
"options": "Item", "options": "Item",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1, "reqd": 1,
"search_index": 1, "search_index": 1
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "barcode", "fieldname": "barcode",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "label": "Barcode"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Barcode",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "item_name", "fieldname": "item_name",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Item Name", "label": "Item Name",
"length": 0, "read_only": 1
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "qty", "fieldname": "qty",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Quantity", "label": "Quantity",
"length": 0, "reqd": 1
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "uom", "fieldname": "uom",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "UOM", "label": "UOM",
"length": 0,
"no_copy": 0,
"options": "UOM", "options": "UOM",
"permlevel": 0, "reqd": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "invoice_separately_as_consumables", "fieldname": "invoice_separately_as_consumables",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "label": "Invoice Separately as Consumables"
"label": "Invoice Separately as Consumables",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_5", "fieldname": "column_break_5",
"fieldtype": "Column Break", "fieldtype": "Column Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "batch_no", "fieldname": "batch_no",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Batch", "label": "Batch",
"length": 0, "options": "Batch"
"no_copy": 0,
"options": "Batch",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "conversion_factor", "fieldname": "conversion_factor",
"fieldtype": "Float", "fieldtype": "Float",
"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": "Conversion Factor", "label": "Conversion Factor",
"length": 0, "read_only": 1
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "stock_uom", "fieldname": "stock_uom",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Stock UOM", "label": "Stock UOM",
"length": 0,
"no_copy": 0,
"options": "UOM", "options": "UOM",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1, "read_only": 1,
"remember_last_selected_value": 0, "reqd": 1
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "transfer_qty", "fieldname": "transfer_qty",
"fieldtype": "Float", "fieldtype": "Float",
"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 Qty", "label": "Transfer Qty",
"length": 0, "read_only": 1
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "actual_qty", "fieldname": "actual_qty",
"fieldtype": "Float", "fieldtype": "Float",
"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": "Actual Qty (at source/target)", "label": "Actual Qty (at source/target)",
"length": 0,
"no_copy": 1, "no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1, "read_only": 1,
"remember_last_selected_value": 0, "search_index": 1
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
} }
], ],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "links": [],
"modified": "2018-11-04 03:33:16.833884", "modified": "2020-03-01 15:34:54.226722",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Healthcare", "module": "Healthcare",
"name": "Clinical Procedure Item", "name": "Clinical Procedure Item",
"name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [], "permissions": [],
"quick_entry": 1, "quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"restrict_to_domain": "Healthcare", "restrict_to_domain": "Healthcare",
"show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "track_changes": 1
"track_seen": 0,
"track_views": 0
} }

View File

@ -3,170 +3,141 @@
frappe.ui.form.on('Clinical Procedure Template', { frappe.ui.form.on('Clinical Procedure Template', {
template: function(frm) { template: function(frm) {
if(!frm.doc.item_code) if (!frm.doc.item_code)
frm.set_value("item_code", frm.doc.template); frm.set_value('item_code', frm.doc.template);
if(!frm.doc.description) if (!frm.doc.description)
frm.set_value("description", frm.doc.template); frm.set_value('description', frm.doc.template);
mark_change_in_item(frm); mark_change_in_item(frm);
}, },
rate: function(frm) { rate: function(frm) {
mark_change_in_item(frm); mark_change_in_item(frm);
}, },
is_billable: function (frm) { is_billable: function (frm) {
mark_change_in_item(frm); mark_change_in_item(frm);
}, },
item_group: function(frm) { item_group: function(frm) {
mark_change_in_item(frm); mark_change_in_item(frm);
}, },
description: function(frm) { description: function(frm) {
mark_change_in_item(frm); mark_change_in_item(frm);
}, },
medical_department: function(frm) { medical_department: function(frm) {
mark_change_in_item(frm); mark_change_in_item(frm);
}, },
refresh: function(frm) { refresh: function(frm) {
frm.fields_dict["items"].grid.set_column_disp("barcode", false); frm.fields_dict['items'].grid.set_column_disp('barcode', false);
frm.fields_dict["items"].grid.set_column_disp("batch_no", false); frm.fields_dict['items'].grid.set_column_disp('batch_no', false);
cur_frm.set_df_property("item_code", "read_only", frm.doc.__islocal ? 0 : 1);
if(!frm.doc.__islocal) { if (!frm.doc.__islocal) {
cur_frm.add_custom_button(__('Change Item Code'), function() { cur_frm.add_custom_button(__('Change Item Code'), function() {
change_template_code(frm.doc); change_template_code(frm.doc);
} ); });
if(frm.doc.disabled == 1){
cur_frm.add_custom_button(__('Enable Template'), function() {
enable_template(frm.doc);
} );
}
else{
cur_frm.add_custom_button(__('Disable Template'), function() {
disable_template(frm.doc);
} );
}
} }
} }
}); });
var mark_change_in_item = function(frm) { let mark_change_in_item = function(frm) {
if(!frm.doc.__islocal){ if (!frm.doc.__islocal) {
frm.doc.change_in_item = 1; frm.doc.change_in_item = 1;
} }
}; };
var disable_template = function(doc){ let change_template_code = function(doc) {
frappe.call({ let d = new frappe.ui.Dialog({
method: "erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.disable_enable_template", title:__('Change Item Code'),
args: {status: 1, name: doc.name, item_code: doc.item_code, is_billable: doc.is_billable},
callback: function(){
cur_frm.reload_doc();
}
});
};
var enable_template = function(doc){
frappe.call({
method: "erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.disable_enable_template",
args: {status: 0, name: doc.name, item_code: doc.item_code, is_billable: doc.is_billable},
callback: function(){
cur_frm.reload_doc();
}
});
};
var change_template_code = function(doc){
var d = new frappe.ui.Dialog({
title:__("Change Template Code"),
fields:[ fields:[
{ {
"fieldtype": "Data", 'fieldtype': 'Data',
"label": "Template Code", 'label': 'Item Code',
"fieldname": "Item Code", 'fieldname': 'item_code',
reqd:1 reqd: 1
},
{
"fieldtype": "Button",
"label": __("Change Code"),
click: function() {
var values = d.get_values();
if(!values)
return;
change_item_code_from_template(values["Item Code"], doc);
d.hide();
} }
} ],
] primary_action: function() {
}); let values = d.get_values();
d.show();
d.set_values({
'Item Code': doc.item_code
});
};
var change_item_code_from_template = function(item_code, doc){ if (values) {
frappe.call({ frappe.call({
"method": "erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.change_item_code_from_template", 'method': 'erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.change_item_code_from_template',
"args": {item_code: item_code, doc: doc}, 'args': {item_code: values.item_code, doc: doc},
callback: function () { callback: function () {
cur_frm.reload_doc(); cur_frm.reload_doc();
frappe.show_alert({ frappe.show_alert({
message: "Item Code renamed successfully", message: 'Item Code renamed successfully',
indicator: "green" indicator: 'green'
}); });
} }
}); });
}
d.hide();
},
primary_action_label: __('Change Item Code')
});
d.show();
d.set_values({
'item_code': doc.item_code
});
}; };
frappe.ui.form.on('Clinical Procedure Item', { frappe.ui.form.on('Clinical Procedure Item', {
qty: function(frm, cdt, cdn){ qty: function(frm, cdt, cdn) {
var d = locals[cdt][cdn]; let d = locals[cdt][cdn];
frappe.model.set_value(cdt, cdn, "transfer_qty", d.qty*d.conversion_factor); frappe.model.set_value(cdt, cdn, 'transfer_qty', d.qty * d.conversion_factor);
}, },
uom: function(doc, cdt, cdn){ uom: function(doc, cdt, cdn){
var d = locals[cdt][cdn]; let d = locals[cdt][cdn];
if(d.uom && d.item_code){ if (d.uom && d.item_code) {
return frappe.call({ return frappe.call({
method: "erpnext.stock.doctype.stock_entry.stock_entry.get_uom_details", method: 'erpnext.stock.doctype.stock_entry.stock_entry.get_uom_details',
args: { args: {
item_code: d.item_code, item_code: d.item_code,
uom: d.uom, uom: d.uom,
qty: d.qty qty: d.qty
}, },
callback: function(r) { callback: function(r) {
if(r.message) { if (r.message) {
frappe.model.set_value(cdt, cdn, r.message); frappe.model.set_value(cdt, cdn, r.message);
} }
} }
}); });
} }
}, },
item_code: function(frm, cdt, cdn) { item_code: function(frm, cdt, cdn) {
var d = locals[cdt][cdn]; let d = locals[cdt][cdn];
if(d.item_code) { if (d.item_code) {
let args = { let args = {
'item_code' : d.item_code, 'item_code' : d.item_code,
'transfer_qty' : d.transfer_qty, 'transfer_qty' : d.transfer_qty,
'company' : frm.doc.company,
'quantity' : d.qty 'quantity' : d.qty
}; };
return frappe.call({ return frappe.call({
doc: frm.doc, method: 'erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.get_item_details',
method: "get_item_details", args: {args: args},
args: args,
callback: function(r) { callback: function(r) {
if(r.message) { if (r.message) {
var d = locals[cdt][cdn]; let d = locals[cdt][cdn];
$.each(r.message, function(k, v){ $.each(r.message, function(k, v) {
d[k] = v; d[k] = v;
}); });
refresh_field("items"); refresh_field('items');
} }
} }
}); });
} }
} }
}); });
// List Stock items // List Stock items
cur_frm.set_query("item_code", "items", function() { cur_frm.set_query('item_code', 'items', function() {
return { return {
filters: { filters: {
is_stock_item:1 is_stock_item:1

View File

@ -1,807 +1,236 @@
{ {
"allow_copy": 0, "actions": [],
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 1, "allow_rename": 1,
"autoname": "field:template", "autoname": "field:template",
"beta": 1, "beta": 1,
"creation": "2017-10-05 14:59:55.438359", "creation": "2017-10-05 14:59:55.438359",
"custom": 0,
"description": "Procedure Template", "description": "Procedure Template",
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "Setup", "document_type": "Setup",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [
"template",
"item",
"item_code",
"item_group",
"description",
"column_break_5",
"disabled",
"is_billable",
"rate",
"medical_department",
"consumables",
"consume_stock",
"items",
"sample_collection",
"sample",
"sample_uom",
"sample_qty",
"column_break_21",
"sample_details",
"change_in_item"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "template", "fieldname": "template",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 1, "in_global_search": 1,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Template Name", "label": "Template Name",
"length": 0,
"no_copy": 0,
"options": "",
"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, "reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 1 "unique": 1
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "item_code", "fieldname": "item_code",
"fieldtype": "Link", "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": "Item Code", "label": "Item Code",
"length": 0,
"no_copy": 1,
"options": "Item", "options": "Item",
"permlevel": 0, "read_only_depends_on": "eval: !doc.__islocal ",
"precision": "", "reqd": 1
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "item_group", "fieldname": "item_group",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1, "ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "Item Group", "label": "Item Group",
"length": 0,
"no_copy": 0,
"options": "Item Group", "options": "Item Group",
"permlevel": 0, "reqd": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "medical_department", "fieldname": "medical_department",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Medical Department", "label": "Medical Department",
"length": 0, "options": "Medical Department"
"no_copy": 0,
"options": "Medical Department",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_5", "fieldname": "column_break_5",
"fieldtype": "Column Break", "fieldtype": "Column Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "is_billable", "fieldname": "is_billable",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "label": "Is Billable"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Is Billable",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "is_billable", "depends_on": "is_billable",
"fieldname": "rate", "fieldname": "rate",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "in_list_view": 1,
"ignore_user_permissions": 0, "in_standard_filter": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Rate", "label": "Rate",
"length": 0, "mandatory_depends_on": "is_billable"
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "description", "fieldname": "description",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 1, "ignore_xss_filter": 1,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Description", "label": "Description",
"length": 0,
"no_copy": 1, "no_copy": 1,
"permlevel": 0, "reqd": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "section_break_9",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "consume_stock", "fieldname": "consume_stock",
"fieldtype": "Check", "fieldtype": "Check",
"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": "Allow Stock Consumption", "label": "Allow Stock Consumption",
"length": 0, "search_index": 1
"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": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.consume_stock == 1",
"fieldname": "consumables", "fieldname": "consumables",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "label": "Consumables"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Consumables",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0, "depends_on": "eval:doc.consume_stock == 1",
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "items", "fieldname": "items",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 1, "ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Items", "label": "Items",
"length": 0, "options": "Clinical Procedure Item"
"no_copy": 0,
"options": "Clinical Procedure Item",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0,
"depends_on": "",
"fieldname": "sample_collection", "fieldname": "sample_collection",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "label": "Sample Collection"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Sample Collection",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "sample", "fieldname": "sample",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1, "ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Sample", "label": "Sample",
"length": 0, "options": "Lab Test Sample"
"no_copy": 0,
"options": "Lab Test Sample",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "sample.sample_uom", "fetch_from": "sample.sample_uom",
"fieldname": "sample_uom", "fieldname": "sample_uom",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "label": "Sample UOM",
"ignore_user_permissions": 0, "read_only": 1
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "UOM",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "sample_qty", "fieldname": "sample_qty",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "label": "Quantity"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Quantity",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_21", "fieldname": "column_break_21",
"fieldtype": "Column Break", "fieldtype": "Column Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "sample_details", "fieldname": "sample_details",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 1, "ignore_xss_filter": 1,
"in_filter": 0, "label": "Collection Details"
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Collection Details",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "change_in_item", "fieldname": "change_in_item",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 1, "hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Change In Item", "label": "Change In Item",
"length": 0,
"no_copy": 1, "no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0, "report_hide": 1
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "disabled", "fieldname": "disabled",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 1, "label": "Disabled"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Disabled",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "item", "fieldname": "item",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 1, "in_list_view": 1,
"ignore_user_permissions": 0, "in_standard_filter": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Item", "label": "Item",
"length": 0,
"no_copy": 1, "no_copy": 1,
"options": "Item", "options": "Item",
"permlevel": 0, "read_only": 1
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
} }
], ],
"has_web_view": 0, "links": [],
"hide_heading": 0, "modified": "2020-02-28 14:16:13.184981",
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-02-12 11:37:18.713344",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Healthcare", "module": "Healthcare",
"name": "Clinical Procedure Template", "name": "Clinical Procedure Template",
"name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 0,
"cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "System Manager", "role": "System Manager",
"set_user_permissions": 0,
"share": 1, "share": 1,
"submit": 0,
"write": 1 "write": 1
}, },
{ {
"amend": 0,
"cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Healthcare Administrator", "role": "Healthcare Administrator",
"set_user_permissions": 0,
"share": 1, "share": 1,
"submit": 0,
"write": 1 "write": 1
}, },
{ {
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Nursing User", "role": "Nursing User",
"set_user_permissions": 0, "share": 1
"share": 1,
"submit": 0,
"write": 0
}, },
{ {
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Physician", "role": "Physician",
"set_user_permissions": 0,
"share": 1, "share": 1,
"submit": 0,
"write": 1 "write": 1
} }
], ],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"restrict_to_domain": "Healthcare", "restrict_to_domain": "Healthcare",
"search_fields": "template", "search_fields": "template",
"show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"title_field": "template", "title_field": "template",
"track_changes": 1, "track_changes": 1,
"track_seen": 1, "track_seen": 1
"track_views": 0
} }

View File

@ -7,126 +7,114 @@ import frappe, json
from frappe import _ from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
from frappe.model.rename_doc import rename_doc from frappe.model.rename_doc import rename_doc
from frappe.utils import nowdate
class ClinicalProcedureTemplate(Document): class ClinicalProcedureTemplate(Document):
def on_update(self): def validate(self):
#Item and Price List update --> if (change_in_item) self.enable_disable_item()
if(self.change_in_item and self.is_billable == 1 and self.item):
updating_item(self)
if(self.rate != 0.0):
updating_rate(self)
elif(self.is_billable == 0 and self.item):
frappe.db.set_value("Item",self.item,"disabled",1)
frappe.db.set_value(self.doctype,self.name,"change_in_item",0)
self.reload()
def after_insert(self): def after_insert(self):
create_item_from_template(self) create_item_from_template(self)
#Call before delete the template def on_update(self):
def on_trash(self): if self.change_in_item:
if(self.item): self.update_item_and_item_price()
try:
frappe.delete_doc("Item",self.item) def enable_disable_item(self):
except Exception: if self.is_billable:
frappe.throw(_("""Not permitted. Please disable the Procedure Template""")) if self.disabled:
frappe.db.set_value('Item', self.item, 'disabled', 1)
else:
frappe.db.set_value('Item', self.item, 'disabled', 0)
def update_item_and_item_price(self):
if self.is_billable and self.item:
item_doc = frappe.get_doc('Item', {'item_code': self.item})
item_doc.item_name = self.template
item_doc.item_group = self.item_group
item_doc.description = self.description
item_doc.disabled = 0
item_doc.save(ignore_permissions=True)
if self.rate:
item_price = frappe.get_doc('Item Price', {'item_code': self.item})
item_price.item_name = self.template
item_price.price_list_rate = self.rate
item_price.save()
elif not self.is_billable and self.item:
frappe.db.set_value('Item', self.item, 'disabled', 1)
self.db_set('change_in_item', 0)
@frappe.whitelist()
def get_item_details(args=None):
if not isinstance(args, dict):
args = json.loads(args)
item = frappe.db.get_all('Item',
filters={
'disabled': 0,
'name': args.get('item_code')
},
fields=['stock_uom', 'item_name']
)
def get_item_details(self, args=None):
item = frappe.db.sql("""select stock_uom, item_name
from `tabItem`
where name = %s
and disabled=0
and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %s)""",
(args.get('item_code'), nowdate()), as_dict = 1)
if not item: if not item:
frappe.throw(_("Item {0} is not active or end of life has been reached").format(args.get('item_code'))) frappe.throw(_('Item {0} is not active').format(args.get('item_code')))
item = item[0] item = item[0]
ret = { ret = {
'uom' : item.stock_uom, 'uom': item.stock_uom,
'stock_uom' : item.stock_uom, 'stock_uom': item.stock_uom,
'item_name' : item.item_name, 'item_name': item.item_name,
'quantity' : 0, 'qty': 1,
'transfer_qty' : 0, 'transfer_qty': 0,
'conversion_factor' : 1 'conversion_factor': 1
} }
return ret return ret
def updating_item(self):
frappe.db.sql("""update `tabItem` set item_name=%s, item_group=%s, disabled=0,
description=%s, modified=NOW() where item_code=%s""",
(self.template, self.item_group , self.description, self.item))
def updating_rate(self):
frappe.db.sql("""update `tabItem Price` set item_name=%s, price_list_rate=%s, modified=NOW() where
item_code=%s""",(self.template, self.rate, self.item))
def create_item_from_template(doc): def create_item_from_template(doc):
disabled = 1 disabled = doc.disabled
if doc.is_billable and not doc.disabled:
if(doc.is_billable == 1):
disabled = 0 disabled = 0
#insert item
item = frappe.get_doc({ item = frappe.get_doc({
"doctype": "Item", 'doctype': 'Item',
"item_code": doc.template, 'item_code': doc.template,
"item_name":doc.template, 'item_name':doc.template,
"item_group": doc.item_group, 'item_group': doc.item_group,
"description":doc.description, 'description':doc.description,
"is_sales_item": 1, 'is_sales_item': 1,
"is_service_item": 1, 'is_service_item': 1,
"is_purchase_item": 0, 'is_purchase_item': 0,
"is_stock_item": 0, 'is_stock_item': 0,
"show_in_website": 0, 'show_in_website': 0,
"is_pro_applicable": 0, 'is_pro_applicable': 0,
"disabled": disabled, 'disabled': disabled,
"stock_uom": "Unit" 'stock_uom': 'Unit'
}).insert(ignore_permissions=True) }).insert(ignore_permissions=True, ignore_mandatory=True)
#insert item price make_item_price(item.name, doc.rate)
#get item price list to insert item price doc.db_set('item', item.name)
if(doc.rate != 0.0):
price_list_name = frappe.db.get_value("Price List", {"selling": 1})
if(doc.rate):
make_item_price(item.name, price_list_name, doc.rate)
else:
make_item_price(item.name, price_list_name, 0.0)
#Set item to the template
frappe.db.set_value("Clinical Procedure Template", doc.name, "item", item.name)
doc.reload() #refresh the doc after insert. def make_item_price(item, item_price):
price_list_name = frappe.db.get_value('Price List', {'selling': 1})
def make_item_price(item, price_list_name, item_price):
frappe.get_doc({ frappe.get_doc({
"doctype": "Item Price", 'doctype': 'Item Price',
"price_list": price_list_name, 'price_list': price_list_name,
"item_code": item, 'item_code': item,
"price_list_rate": item_price 'price_list_rate': item_price
}).insert(ignore_permissions=True) }).insert(ignore_permissions=True, ignore_mandatory=True)
@frappe.whitelist() @frappe.whitelist()
def change_item_code_from_template(item_code, doc): def change_item_code_from_template(item_code, doc):
args = json.loads(doc) doc = frappe._dict(json.loads(doc))
doc = frappe._dict(args)
if(frappe.db.exists({ if frappe.db.exists('Item', {'item_code': item_code}):
"doctype": "Item", frappe.throw(_('Item with Item Code {0} already exists').format(item_code))
"item_code": item_code})):
frappe.throw(_("Code {0} already exist").format(item_code))
else: else:
rename_doc("Item", doc.item_code, item_code, ignore_permissions=True) rename_doc('Item', doc.item_code, item_code, ignore_permissions=True)
frappe.db.set_value("Clinical Procedure Template", doc.name, "item_code", item_code) frappe.db.set_value('Clinical Procedure Template', doc.name, 'item_code', item_code)
return return
@frappe.whitelist()
def disable_enable_template(status, name, item_code):
frappe.db.set_value("Clinical Procedure Template", name, "disabled", status)
if (frappe.db.exists({ #set Item's disabled field to status
"doctype": "Item",
"item_code": item_code})):
frappe.db.set_value("Item", item_code, "disabled", status)
return

View File

@ -0,0 +1,13 @@
from __future__ import unicode_literals
from frappe import _
def get_data():
return {
'fieldname': 'procedure_template',
'transactions': [
{
'label': _('Consultations'),
'items': ['Clinical Procedure']
}
]
}

View File

@ -1,140 +1,56 @@
{ {
"actions": [],
"allow_copy": 1, "allow_copy": 1,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 1, "beta": 1,
"creation": "2017-06-22 13:09:23.159579", "creation": "2017-06-22 13:09:23.159579",
"custom": 0,
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [
"medical_code",
"code",
"description"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "medical_code", "fieldname": "medical_code",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1, "ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Medical Code", "label": "Medical Code",
"length": 0,
"no_copy": 0,
"options": "Medical Code", "options": "Medical Code",
"permlevel": 0, "reqd": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "medical_code.code", "fetch_from": "medical_code.code",
"fieldname": "code", "fieldname": "code",
"fieldtype": "Read Only", "fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 1, "ignore_xss_filter": 1,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Code", "label": "Code",
"length": 0, "read_only": 1
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "medical_code.description", "fetch_from": "medical_code.description",
"fieldname": "description", "fieldname": "description",
"fieldtype": "Read Only", "fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 1, "ignore_xss_filter": 1,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Description", "label": "Description",
"length": 0, "read_only": 1
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
} }
], ],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "links": [],
"modified": "2018-05-16 22:43:27.047479", "modified": "2020-02-26 13:17:49.016293",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Healthcare", "module": "Healthcare",
"name": "Codification Table", "name": "Codification Table",
"name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [], "permissions": [],
"quick_entry": 1, "quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"restrict_to_domain": "Healthcare", "restrict_to_domain": "Healthcare",
"show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "track_changes": 1
"track_seen": 0
} }

View File

@ -1,381 +1,116 @@
{ {
"actions": [],
"allow_copy": 1, "allow_copy": 1,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 1, "beta": 1,
"creation": "2016-09-16 16:41:45.533374", "creation": "2016-09-16 16:41:45.533374",
"custom": 0,
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "Document", "document_type": "Document",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [
"drug_code",
"drug_name",
"dosage",
"period",
"dosage_form",
"column_break_7",
"comment",
"usage_interval",
"interval",
"interval_uom",
"update_schedule"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "drug_code", "fieldname": "drug_code",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1, "ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "label": "Drug",
"label": "Drug Code",
"length": 0,
"no_copy": 0,
"options": "Item", "options": "Item",
"permlevel": 0, "reqd": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0, "fetch_from": "drug_code.item_name",
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "drug_name", "fieldname": "drug_name",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "label": "Drug Name / Description"
"label": "Description/Strength",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "dosage", "fieldname": "dosage",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1, "ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Dosage", "label": "Dosage",
"length": 0, "options": "Prescription Dosage"
"no_copy": 0,
"options": "Prescription Dosage",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "period", "fieldname": "period",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1, "ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Period", "label": "Period",
"length": 0, "options": "Prescription Duration"
"no_copy": 0,
"options": "Prescription Duration",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "dosage_form", "fieldname": "dosage_form",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1, "ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Dosage Form", "label": "Dosage Form",
"length": 0, "options": "Dosage Form"
"no_copy": 0,
"options": "Dosage Form",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_7", "fieldname": "column_break_7",
"fieldtype": "Column Break", "fieldtype": "Column Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "comment", "fieldname": "comment",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 1, "ignore_xss_filter": 1,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "label": "Comment"
"label": "Comment",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "use_interval",
"fieldtype": "Check",
"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": "Dosage by time interval",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "use_interval", "depends_on": "use_interval",
"fieldname": "interval", "fieldname": "interval",
"fieldtype": "Int", "fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "label": "Interval"
"label": "Interval",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "use_interval",
"fieldname": "in_every",
"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": "Interval UOM",
"length": 0,
"no_copy": 0,
"options": "\nHour\nDay",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1", "default": "1",
"fieldname": "update_schedule", "fieldname": "update_schedule",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 1, "hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Update Schedule", "label": "Update Schedule",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0, "report_hide": 1
"read_only": 0, },
"remember_last_selected_value": 0, {
"report_hide": 1, "depends_on": "use_interval",
"reqd": 0, "fieldname": "interval_uom",
"search_index": 0, "fieldtype": "Select",
"set_only_once": 0, "in_list_view": 1,
"unique": 0 "label": "Interval UOM",
"options": "\nHour\nDay"
},
{
"default": "0",
"fieldname": "usage_interval",
"fieldtype": "Check",
"label": "Dosage by Time Interval"
} }
], ],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "links": [],
"modified": "2017-10-04 17:09:54.998517", "modified": "2020-02-26 17:02:42.741338",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Healthcare", "module": "Healthcare",
"name": "Drug Prescription", "name": "Drug Prescription",
"name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [], "permissions": [],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"restrict_to_domain": "Healthcare", "restrict_to_domain": "Healthcare",
"show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC"
"track_changes": 0,
"track_seen": 0
} }

View File

@ -12,21 +12,21 @@ class DrugPrescription(Document):
dosage = None dosage = None
period = None period = None
if(self.dosage): if self.dosage:
dosage = frappe.get_doc("Prescription Dosage",self.dosage) dosage = frappe.get_doc('Prescription Dosage', self.dosage)
for item in dosage.dosage_strength: for item in dosage.dosage_strength:
quantity += item.strength quantity += item.strength
if(self.period and self.interval): if self.period and self.interval:
period = frappe.get_doc("Prescription Duration",self.period) period = frappe.get_doc('Prescription Duration', self.period)
if(self.interval < period.get_days()): if self.interval < period.get_days():
quantity = quantity*(period.get_days()/self.interval) quantity = quantity * (period.get_days()/self.interval)
elif(self.interval and self.in_every and self.period): elif self.interval and self.interval_uom and self.period:
period = frappe.get_doc("Prescription Duration",self.period) period = frappe.get_doc('Prescription Duration', self.period)
interval_in = self.in_every interval_in = self.interval_uom
if(interval_in == 'Day' and (self.interval < period.get_days())): if interval_in == 'Day' and self.interval < period.get_days():
quantity = period.get_days()/self.interval quantity = period.get_days()/self.interval
elif(interval_in == 'Hour' and (self.interval < period.get_hours())): elif interval_in == 'Hour' and self.interval < period.get_hours():
quantity = period.get_hours()/self.interval quantity = period.get_hours()/self.interval
if quantity > 0: if quantity > 0:
return quantity return quantity

View File

@ -1,259 +1,134 @@
{ {
"actions": [],
"allow_copy": 1, "allow_copy": 1,
"allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 0,
"beta": 1, "beta": 1,
"creation": "2017-01-05 10:56:29.564806", "creation": "2017-01-05 10:56:29.564806",
"custom": 0,
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "Setup", "document_type": "Setup",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [
"practitioner",
"patient",
"column_break_3",
"status",
"section_break_5",
"section_break_3",
"max_visits",
"visited",
"ref_appointments",
"column_break_6",
"start_date",
"valid_till"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "practitioner", "fieldname": "practitioner",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "in_list_view": 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": "Healthcare Practitioner", "label": "Healthcare Practitioner",
"length": 0,
"no_copy": 0,
"options": "Healthcare Practitioner", "options": "Healthcare Practitioner",
"permlevel": 0, "read_only": 1,
"precision": "", "reqd": 1,
"print_hide": 0, "search_index": 1
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "patient", "fieldname": "patient",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "in_list_view": 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": "Patient", "label": "Patient",
"length": 0,
"no_copy": 0,
"options": "Patient", "options": "Patient",
"permlevel": 0, "read_only": 1,
"precision": "", "reqd": 1,
"print_hide": 0, "search_index": 1
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "max_visit",
"fieldtype": "Int",
"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": "Max number of visit",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "visited", "fieldname": "visited",
"fieldtype": "Int", "fieldtype": "Int",
"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": "Visited yet", "label": "Visited yet",
"length": 0, "read_only": 1
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "valid_till", "fieldname": "valid_till",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Valid till", "label": "Valid till",
"length": 0, "read_only": 1
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0, "fieldname": "section_break_3",
"allow_in_quick_entry": 0, "fieldtype": "Section Break",
"allow_on_submit": 0, "label": "Validity",
"bold": 0, "read_only": 1
"collapsible": 0, },
"columns": 0, {
"fieldname": "ref_invoice", "fieldname": "column_break_6",
"fieldtype": "Link", "fieldtype": "Column Break"
"hidden": 0, },
"ignore_user_permissions": 0, {
"ignore_xss_filter": 0, "fieldname": "max_visits",
"in_filter": 0, "fieldtype": "Int",
"in_global_search": 0, "label": "Max number of visit",
"in_list_view": 0, "read_only": 1
"in_standard_filter": 0, },
"label": "Reference Inv", {
"length": 0, "fieldname": "column_break_3",
"no_copy": 0, "fieldtype": "Column Break"
"options": "Sales Invoice", },
"permlevel": 0, {
"precision": "", "fieldname": "status",
"print_hide": 0, "fieldtype": "Select",
"print_hide_if_no_value": 0, "in_list_view": 1,
"read_only": 0, "in_standard_filter": 1,
"remember_last_selected_value": 0, "label": "Status",
"report_hide": 0, "options": "Completed\nPending",
"reqd": 0, "read_only": 1
"search_index": 0, },
"set_only_once": 0, {
"translatable": 0, "fetch_from": "ref_appointment.appointment_date",
"unique": 0 "fieldname": "start_date",
"fieldtype": "Date",
"label": "Start Date",
"read_only": 1
},
{
"fieldname": "ref_appointments",
"fieldtype": "Table MultiSelect",
"label": "Reference Appointments",
"options": "Fee Validity Reference",
"read_only": 1
},
{
"collapsible": 1,
"fieldname": "section_break_5",
"fieldtype": "Section Break"
} }
], ],
"has_web_view": 0, "in_create": 1,
"hide_heading": 0, "links": [],
"hide_toolbar": 0, "modified": "2020-03-17 20:25:06.487418",
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-07-16 12:43:45.635230",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Healthcare", "module": "Healthcare",
"name": "Fee Validity", "name": "Fee Validity",
"name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 0,
"cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Healthcare Administrator", "role": "Healthcare Administrator",
"set_user_permissions": 0,
"share": 1, "share": 1,
"submit": 0,
"write": 1 "write": 1
} }
], ],
"quick_entry": 1, "quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"restrict_to_domain": "Healthcare", "restrict_to_domain": "Healthcare",
"search_fields": "practitioner, patient", "search_fields": "practitioner, patient",
"show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"title_field": "practitioner", "title_field": "practitioner"
"track_changes": 0,
"track_seen": 0
} }

View File

@ -9,28 +9,55 @@ from frappe.utils import getdate
import datetime import datetime
class FeeValidity(Document): class FeeValidity(Document):
pass def validate(self):
self.update_status()
self.set_start_date()
def update_fee_validity(fee_validity, date, ref_invoice=None): def update_status(self):
max_visit = frappe.db.get_value("Healthcare Settings", None, "max_visit") if self.visited >= self.max_visits:
valid_days = frappe.db.get_value("Healthcare Settings", None, "valid_days") self.status = 'Completed'
if not valid_days: else:
valid_days = 1 self.status = 'Pending'
if not max_visit:
max_visit = 1 def set_start_date(self):
date = getdate(date) self.start_date = getdate()
valid_till = date + datetime.timedelta(days=int(valid_days)) for appointment in self.ref_appointments:
fee_validity.max_visit = max_visit appointment_date = frappe.db.get_value('Patient Appointment', appointment.appointment, 'appointment_date')
if getdate(appointment_date) < self.start_date:
self.start_date = getdate(appointment_date)
def create_fee_validity(appointment):
if not check_is_new_patient(appointment):
return
fee_validity = frappe.new_doc('Fee Validity')
fee_validity.practitioner = appointment.practitioner
fee_validity.patient = appointment.patient
fee_validity.max_visits = frappe.db.get_single_value('Healthcare Settings', 'max_visits') or 1
valid_days = frappe.db.get_single_value('Healthcare Settings', 'valid_days') or 1
fee_validity.visited = 1 fee_validity.visited = 1
fee_validity.valid_till = valid_till fee_validity.valid_till = getdate(appointment.appointment_date) + datetime.timedelta(days=int(valid_days))
fee_validity.ref_invoice = ref_invoice fee_validity.append('ref_appointments', {
'appointment': appointment.name
})
fee_validity.save(ignore_permissions=True) fee_validity.save(ignore_permissions=True)
return fee_validity return fee_validity
def check_is_new_patient(appointment):
validity_exists = frappe.db.exists('Fee Validity', {
'practitioner': appointment.practitioner,
'patient': appointment.patient
})
if validity_exists:
return False
def create_fee_validity(practitioner, patient, date, ref_invoice=None): appointment_exists = frappe.db.get_all('Patient Appointment', {
fee_validity = frappe.new_doc("Fee Validity") 'name': ('!=', appointment.name),
fee_validity.practitioner = practitioner 'status': ('!=', 'Cancelled'),
fee_validity.patient = patient 'patient': appointment.patient,
fee_validity = update_fee_validity(fee_validity, date, ref_invoice) 'practitioner': appointment.practitioner
return fee_validity })
if len(appointment_exists) and appointment_exists[0]:
return False
return True

View File

@ -5,100 +5,44 @@ from __future__ import unicode_literals
import frappe import frappe
import unittest import unittest
from frappe.utils.make_random import get_random from frappe.utils import nowdate, add_days
from frappe.utils import nowdate, add_days, getdate from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_healthcare_docs, create_appointment, create_healthcare_service_items
test_dependencies = ["Company"] test_dependencies = ["Company"]
class TestFeeValidity(unittest.TestCase): class TestFeeValidity(unittest.TestCase):
def test_fee_validity(self): def setUp(self):
frappe.db.sql("""delete from `tabPatient Appointment`""") frappe.db.sql("""delete from `tabPatient Appointment`""")
frappe.db.sql("""delete from `tabFee Validity`""") frappe.db.sql("""delete from `tabFee Validity`""")
patient = get_random("Patient") frappe.db.sql("""delete from `tabPatient`""")
practitioner = get_random("Healthcare Practitioner")
department = get_random("Medical Department")
if not patient: def test_fee_validity(self):
patient = frappe.new_doc("Patient") item = create_healthcare_service_items()
patient.patient_name = "_Test Patient" healthcare_settings = frappe.get_single("Healthcare Settings")
patient.sex = "Male" healthcare_settings.enable_free_follow_ups = 1
patient.save(ignore_permissions=True) healthcare_settings.max_visits = 2
patient = patient.name healthcare_settings.valid_days = 7
healthcare_settings.automate_appointment_invoicing = 1
healthcare_settings.op_consulting_charge_item = item
healthcare_settings.save(ignore_permissions=True)
patient, medical_department, practitioner = create_healthcare_docs()
if not department: # appointment should not be invoiced. Check Fee Validity created for new patient
medical_department = frappe.new_doc("Medical Department") appointment = create_appointment(patient, practitioner, nowdate())
medical_department.department = "_Test Medical Department"
medical_department.save(ignore_permissions=True)
department = medical_department.name
if not practitioner:
practitioner = frappe.new_doc("Healthcare Practitioner")
practitioner.first_name = "_Test Healthcare Practitioner"
practitioner.department = department
practitioner.save(ignore_permissions=True)
practitioner = practitioner.name
frappe.db.set_value("Healthcare Settings", None, "max_visit", 2)
frappe.db.set_value("Healthcare Settings", None, "valid_days", 7)
appointment = create_appointment(patient, practitioner, nowdate(), department)
invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced")
self.assertEqual(invoiced, 0) self.assertEqual(invoiced, 0)
invoice_appointment(appointment) # appointment should not be invoiced as it is within fee validity
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 4))
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 4), department)
invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced")
self.assertTrue(invoiced)
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 5), department)
invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced")
self.assertEqual(invoiced, 0) self.assertEqual(invoiced, 0)
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 10), department) # appointment should be invoiced as it is within fee validity but the max_visits are exceeded
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 5), invoice=1)
invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced")
self.assertEqual(invoiced, 0) self.assertEqual(invoiced, 1)
def create_appointment(patient, practitioner, appointment_date, department): # appointment should be invoiced as it is not within fee validity and the max_visits are exceeded
appointment = frappe.new_doc("Patient Appointment") appointment = create_appointment(patient, practitioner, add_days(nowdate(), 10), invoice=1)
appointment.patient = patient invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced")
appointment.practitioner = practitioner self.assertEqual(invoiced, 1)
appointment.department = department
appointment.appointment_date = appointment_date
appointment.company = "_Test Company"
appointment.duration = 15
appointment.save(ignore_permissions=True)
return appointment
def invoice_appointment(appointment_doc):
if not appointment_doc.name:
return False
sales_invoice = frappe.new_doc("Sales Invoice")
sales_invoice.customer = frappe.get_value("Patient", appointment_doc.patient, "customer")
sales_invoice.due_date = getdate()
sales_invoice.is_pos = 0
sales_invoice.company = appointment_doc.company
sales_invoice.debit_to = "_Test Receivable - _TC"
create_invoice_items(appointment_doc, sales_invoice)
sales_invoice.save(ignore_permissions=True)
sales_invoice.submit()
def create_invoice_items(appointment, invoice):
item_line = invoice.append("items")
item_line.item_name = "Consulting Charges"
item_line.description = "Consulting Charges: " + appointment.practitioner
item_line.uom = "Nos"
item_line.conversion_factor = 1
item_line.income_account = "_Test Account Cost for Goods Sold - _TC"
item_line.cost_center = "_Test Cost Center - _TC"
item_line.rate = 250
item_line.amount = 250
item_line.qty = 1
item_line.reference_dt = "Patient Appointment"
item_line.reference_dn = appointment.name
return invoice

View File

@ -0,0 +1,32 @@
{
"actions": [],
"creation": "2020-03-13 16:08:42.859996",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"appointment"
],
"fields": [
{
"fieldname": "appointment",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Patient Appointment",
"options": "Patient Appointment",
"reqd": 1
}
],
"istable": 1,
"links": [],
"modified": "2020-03-15 00:27:02.076470",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Fee Validity Reference",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
class FeeValidityReference(Document):
pass

View File

@ -4,7 +4,7 @@
frappe.ui.form.on('Healthcare Practitioner', { frappe.ui.form.on('Healthcare Practitioner', {
setup: function(frm) { setup: function(frm) {
frm.set_query('account', 'accounts', function(doc, cdt, cdn) { frm.set_query('account', 'accounts', function(doc, cdt, cdn) {
var d = locals[cdt][cdn]; let d = locals[cdt][cdn];
return { return {
filters: { filters: {
'root_type': 'Income', 'root_type': 'Income',
@ -16,23 +16,28 @@ frappe.ui.form.on('Healthcare Practitioner', {
}, },
refresh: function(frm) { refresh: function(frm) {
frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Healthcare Practitioner'}; frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Healthcare Practitioner'};
if(!frm.is_new()) {
if (!frm.is_new()) {
frappe.contacts.render_address_and_contact(frm); frappe.contacts.render_address_and_contact(frm);
} else {
frappe.contacts.clear_address_and_contact(frm);
} }
frm.set_query("service_unit", "practitioner_schedules", function(){
frm.set_query('service_unit', 'practitioner_schedules', function(){
return { return {
filters: { filters: {
"is_group": false, 'is_group': false,
"allow_appointments": true 'allow_appointments': true
} }
}; };
}); });
set_query_service_item(frm, 'inpatient_visit_charge_item'); set_query_service_item(frm, 'inpatient_visit_charge_item');
set_query_service_item(frm, 'op_consulting_charge_item'); set_query_service_item(frm, 'op_consulting_charge_item');
} }
}); });
var set_query_service_item = function(frm, service_item_field) { let set_query_service_item = function(frm, service_item_field) {
frm.set_query(service_item_field, function() { frm.set_query(service_item_field, function() {
return { return {
filters: { filters: {
@ -43,62 +48,62 @@ var set_query_service_item = function(frm, service_item_field) {
}); });
}; };
frappe.ui.form.on("Healthcare Practitioner", "user_id",function(frm) { frappe.ui.form.on('Healthcare Practitioner', 'user_id',function(frm) {
if(frm.doc.user_id){ if (frm.doc.user_id) {
frappe.call({ frappe.call({
"method": "frappe.client.get", 'method': 'frappe.client.get',
args: { args: {
doctype: "User", doctype: 'User',
name: frm.doc.user_id name: frm.doc.user_id
}, },
callback: function (data) { callback: function (data) {
frappe.model.get_value('Employee', {'user_id': frm.doc.user_id}, 'name', frappe.model.get_value('Employee', {'user_id': frm.doc.user_id}, 'name',
function(data) { function(data) {
if(data){ if (data) {
if(!frm.doc.employee || frm.doc.employee != data.name) if (!frm.doc.employee || frm.doc.employee != data.name)
frappe.model.set_value(frm.doctype,frm.docname, "employee", data.name); frappe.model.set_value(frm.doctype, frm.docname, 'employee', data.name);
}else{ } else {
frappe.model.set_value(frm.doctype,frm.docname, "employee", ""); frappe.model.set_value(frm.doctype, frm.docname, 'employee', '');
} }
} }
); );
if(!frm.doc.first_name || frm.doc.first_name != data.message.first_name) if (!frm.doc.first_name || frm.doc.first_name != data.message.first_name)
frappe.model.set_value(frm.doctype,frm.docname, "first_name", data.message.first_name); frappe.model.set_value(frm.doctype,frm.docname, 'first_name', data.message.first_name);
if(!frm.doc.middle_name || frm.doc.middle_name != data.message.middle_name) if (!frm.doc.middle_name || frm.doc.middle_name != data.message.middle_name)
frappe.model.set_value(frm.doctype,frm.docname, "middle_name", data.message.middle_name); frappe.model.set_value(frm.doctype,frm.docname, 'middle_name', data.message.middle_name);
if(!frm.doc.last_name || frm.doc.last_name != data.message.last_name) if (!frm.doc.last_name || frm.doc.last_name != data.message.last_name)
frappe.model.set_value(frm.doctype,frm.docname, "last_name", data.message.last_name); frappe.model.set_value(frm.doctype,frm.docname, 'last_name', data.message.last_name);
if(!frm.doc.mobile_phone || frm.doc.mobile_phone != data.message.mobile_no) if (!frm.doc.mobile_phone || frm.doc.mobile_phone != data.message.mobile_no)
frappe.model.set_value(frm.doctype,frm.docname, "mobile_phone", data.message.mobile_no); frappe.model.set_value(frm.doctype,frm.docname, 'mobile_phone', data.message.mobile_no);
} }
}); });
} }
}); });
frappe.ui.form.on("Healthcare Practitioner", "employee", function(frm) { frappe.ui.form.on('Healthcare Practitioner', 'employee', function(frm) {
if(frm.doc.employee){ if (frm.doc.employee){
frappe.call({ frappe.call({
"method": "frappe.client.get", 'method': 'frappe.client.get',
args: { args: {
doctype: "Employee", doctype: 'Employee',
name: frm.doc.employee name: frm.doc.employee
}, },
callback: function (data) { callback: function (data) {
if(!frm.doc.user_id || frm.doc.user_id != data.message.user_id) if (!frm.doc.user_id || frm.doc.user_id != data.message.user_id)
frm.set_value("user_id", data.message.user_id); frm.set_value('user_id', data.message.user_id);
if(!frm.doc.designation || frm.doc.designation != data.message.designation) if (!frm.doc.designation || frm.doc.designation != data.message.designation)
frappe.model.set_value(frm.doctype,frm.docname, "designation", data.message.designation); frappe.model.set_value(frm.doctype,frm.docname, 'designation', data.message.designation);
if(!frm.doc.first_name || !frm.doc.user_id){ if (!frm.doc.first_name || !frm.doc.user_id){
frappe.model.set_value(frm.doctype,frm.docname, "first_name", data.message.employee_name); frappe.model.set_value(frm.doctype,frm.docname, 'first_name', data.message.first_name);
frappe.model.set_value(frm.doctype,frm.docname, "middle_name", ""); frappe.model.set_value(frm.doctype,frm.docname, 'middle_name', '');
frappe.model.set_value(frm.doctype,frm.docname, "last_name", ""); frappe.model.set_value(frm.doctype,frm.docname, 'last_name', data.message.last_name);
} }
if(!frm.doc.mobile_phone || !frm.doc.user_id) if (!frm.doc.mobile_phone || !frm.doc.user_id)
frappe.model.set_value(frm.doctype,frm.docname, "mobile_phone", data.message.cell_number); frappe.model.set_value(frm.doctype,frm.docname, 'mobile_phone', data.message.cell_number);
if(!frm.doc.address || frm.doc.address != data.message.current_address) if (!frm.doc.address || frm.doc.address != data.message.current_address)
frappe.model.set_value(frm.doctype,frm.docname, "address", data.message.current_address); frappe.model.set_value(frm.doctype,frm.docname, 'address', data.message.current_address);
} }
}); });
} }

View File

@ -5,10 +5,10 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe.model.document import Document from frappe.model.document import Document
from frappe import throw, _ from frappe import _
from frappe.utils import cstr
from erpnext.accounts.party import validate_party_accounts from erpnext.accounts.party import validate_party_accounts
from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address
from frappe.model.naming import append_number_if_name_exists
from frappe.desk.reportview import build_match_conditions, get_filters_cond from frappe.desk.reportview import build_match_conditions, get_filters_cond
class HealthcarePractitioner(Document): class HealthcarePractitioner(Document):
@ -16,63 +16,66 @@ class HealthcarePractitioner(Document):
load_address_and_contact(self) load_address_and_contact(self)
def autoname(self): def autoname(self):
# practitioner first_name and last_name # concat first and last name
self.name = " ".join(filter(None, self.name = self.practitioner_name
[cstr(self.get(f)).strip() for f in ["first_name","middle_name","last_name"]]))
if frappe.db.exists('Healthcare Practitioner', self.name):
self.name = append_number_if_name_exists('Contact', self.name)
def validate(self): def validate(self):
self.set_full_name()
validate_party_accounts(self) validate_party_accounts(self)
if self.inpatient_visit_charge_item: if self.inpatient_visit_charge_item:
validate_service_item(self.inpatient_visit_charge_item, "Configure a service Item for Inpatient Visit Charge Item") validate_service_item(self.inpatient_visit_charge_item, 'Configure a service Item for Inpatient Consulting Charge Item')
if self.op_consulting_charge_item: if self.op_consulting_charge_item:
validate_service_item(self.op_consulting_charge_item, "Configure a service Item for Out Patient Consulting Charge Item") validate_service_item(self.op_consulting_charge_item, 'Configure a service Item for Out Patient Consulting Charge Item')
if self.user_id: if self.user_id:
self.validate_for_enabled_user_id() self.validate_user_id()
self.validate_duplicate_user_id()
existing_user_id = frappe.db.get_value("Healthcare Practitioner", self.name, "user_id")
if self.user_id != existing_user_id:
frappe.permissions.remove_user_permission(
"Healthcare Practitioner", self.name, existing_user_id)
else: else:
existing_user_id = frappe.db.get_value("Healthcare Practitioner", self.name, "user_id") existing_user_id = frappe.db.get_value('Healthcare Practitioner', self.name, 'user_id')
if existing_user_id: if existing_user_id:
frappe.permissions.remove_user_permission( frappe.permissions.remove_user_permission(
"Healthcare Practitioner", self.name, existing_user_id) 'Healthcare Practitioner', self.name, existing_user_id)
def on_update(self): def on_update(self):
if self.user_id: if self.user_id:
frappe.permissions.add_user_permission("Healthcare Practitioner", self.name, self.user_id) frappe.permissions.add_user_permission('Healthcare Practitioner', self.name, self.user_id)
def set_full_name(self):
if self.last_name:
self.practitioner_name = ' '.join(filter(None, [self.first_name, self.last_name]))
else:
self.practitioner_name = self.first_name
def validate_for_enabled_user_id(self): def validate_user_id(self):
enabled = frappe.db.get_value("User", self.user_id, "enabled") if not frappe.db.exists('User', self.user_id):
if enabled is None: frappe.throw(_('User {0} does not exist').format(self.user_id))
frappe.throw(_("User {0} does not exist").format(self.user_id)) elif not frappe.db.exists('User', self.user_id, 'enabled'):
if enabled == 0: frappe.throw(_('User {0} is disabled').format(self.user_id))
frappe.throw(_("User {0} is disabled").format(self.user_id))
def validate_duplicate_user_id(self): # check duplicate
practitioner = frappe.db.sql_list("""select name from `tabHealthcare Practitioner` where practitioner = frappe.db.exists('Healthcare Practitioner', {
user_id=%s and name!=%s""", (self.user_id, self.name)) 'user_id': self.user_id,
'name': ('!=', self.name)
})
if practitioner: if practitioner:
throw(_("User {0} is already assigned to Healthcare Practitioner {1}").format( frappe.throw(_('User {0} is already assigned to Healthcare Practitioner {1}').format(
self.user_id, practitioner[0]), frappe.DuplicateEntryError) self.user_id, practitioner))
def on_trash(self): def on_trash(self):
delete_contact_and_address('Healthcare Practitioner', self.name) delete_contact_and_address('Healthcare Practitioner', self.name)
def validate_service_item(item, msg): def validate_service_item(item, msg):
if frappe.db.get_value("Item", item, "is_stock_item") == 1: if frappe.db.get_value('Item', item, 'is_stock_item'):
frappe.throw(_(msg)) frappe.throw(_(msg))
def get_practitioner_list(doctype, txt, searchfield, start, page_len, filters=None): def get_practitioner_list(doctype, txt, searchfield, start, page_len, filters=None):
fields = ["name", "first_name", "mobile_phone"] fields = ['name', 'practitioner_name', 'mobile_phone']
filters = { filters = {
'name': ("like", "%%%s%%" % txt) 'name': ('like', '%%%s%%' % txt)
} }
return frappe.get_all("Healthcare Practitioner", fields = fields, return frappe.get_all('Healthcare Practitioner', fields = fields,
filters = filters, start=start, page_length=page_len, order_by="name, first_name", as_list=1) filters = filters, start=start, page_length=page_len, order_by='name, practitioner_name', as_list=1)

View File

@ -9,7 +9,11 @@ def get_data():
'transactions': [ 'transactions': [
{ {
'label': _('Appointments and Patient Encounters'), 'label': _('Appointments and Patient Encounters'),
'items': ['Patient Appointment', 'Patient Encounter'] 'items': ['Patient Appointment', 'Patient Encounter', 'Fee Validity']
},
{
'label': _('Consultation'),
'items': ['Clinical Procedure', 'Lab Test']
} }
] ]
} }

View File

@ -3,7 +3,7 @@
frappe.ui.form.on('Healthcare Service Unit', { frappe.ui.form.on('Healthcare Service Unit', {
onload: function(frm) { onload: function(frm) {
frm.list_route = "Tree/Healthcare Service Unit"; frm.list_route = 'Tree/Healthcare Service Unit';
// get query select healthcare service unit // get query select healthcare service unit
frm.fields_dict['parent_healthcare_service_unit'].get_query = function(doc) { frm.fields_dict['parent_healthcare_service_unit'].get_query = function(doc) {
@ -16,32 +16,32 @@ frappe.ui.form.on('Healthcare Service Unit', {
}; };
}, },
refresh: function(frm) { refresh: function(frm) {
frm.trigger("set_root_readonly"); frm.trigger('set_root_readonly');
frm.set_df_property("service_unit_type", "reqd", 1); frm.set_df_property('service_unit_type', 'reqd', 1);
frm.add_custom_button(__("Healthcare Service Unit Tree"), function() { frm.add_custom_button(__('Healthcare Service Unit Tree'), function() {
frappe.set_route("Tree", "Healthcare Service Unit"); frappe.set_route('Tree', 'Healthcare Service Unit');
}); });
}, },
set_root_readonly: function(frm) { set_root_readonly: function(frm) {
// read-only for root healthcare service unit // read-only for root healthcare service unit
frm.set_intro(""); frm.set_intro('');
if(!frm.doc.parent_healthcare_service_unit) { if (!frm.doc.parent_healthcare_service_unit) {
frm.set_read_only(); frm.set_read_only();
frm.set_intro(__("This is a root healthcare service unit and cannot be edited."), true); frm.set_intro(__('This is a root healthcare service unit and cannot be edited.'), true);
} }
}, },
allow_appointments: function(frm) { allow_appointments: function(frm) {
if(!frm.doc.allow_appointments){ if (!frm.doc.allow_appointments) {
frm.set_value("overlap_appointments", false); frm.set_value('overlap_appointments', false);
} }
}, },
is_group: function(frm) { is_group: function(frm) {
if(frm.doc.is_group == 1){ if (frm.doc.is_group == 1) {
frm.set_value("allow_appointments", false); frm.set_value('allow_appointments', false);
frm.set_df_property("service_unit_type", "reqd", 0); frm.set_df_property('service_unit_type', 'reqd', 0);
} }
else{ else {
frm.set_df_property("service_unit_type", "reqd", 1); frm.set_df_property('service_unit_type', 'reqd', 1);
} }
} }
}); });

View File

@ -9,6 +9,7 @@
"doctype": "DocType", "doctype": "DocType",
"document_type": "Setup", "document_type": "Setup",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB",
"field_order": [ "field_order": [
"healthcare_service_unit_name", "healthcare_service_unit_name",
"parent_healthcare_service_unit", "parent_healthcare_service_unit",
@ -18,6 +19,7 @@
"overlap_appointments", "overlap_appointments",
"inpatient_occupancy", "inpatient_occupancy",
"occupancy_status", "occupancy_status",
"column_break_9",
"warehouse", "warehouse",
"company", "company",
"lft", "lft",
@ -99,9 +101,13 @@
"fieldtype": "Select", "fieldtype": "Select",
"label": "Occupancy Status", "label": "Occupancy Status",
"no_copy": 1, "no_copy": 1,
"options": "Vacant\nOccupied", "options": "\nVacant\nOccupied",
"read_only": 1 "read_only": 1
}, },
{
"fieldname": "column_break_9",
"fieldtype": "Column Break"
},
{ {
"bold": 1, "bold": 1,
"depends_on": "eval:doc.is_group != 1", "depends_on": "eval:doc.is_group != 1",
@ -153,13 +159,11 @@
"report_hide": 1 "report_hide": 1
} }
], ],
"is_tree": 1,
"links": [], "links": [],
"modified": "2020-03-18 18:02:23.713439", "modified": "2020-03-26 16:13:08.675952",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Healthcare", "module": "Healthcare",
"name": "Healthcare Service Unit", "name": "Healthcare Service Unit",
"nsm_parent_field": "parent_healthcare_service_unit",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {

View File

@ -23,9 +23,9 @@ class HealthcareServiceUnit(NestedSet):
self.validate_one_root() self.validate_one_root()
def validate(self): def validate(self):
if self.is_group == 1: if self.is_group:
self.allow_appointments = 0 self.allow_appointments = 0
self.overlap_appointments = 0 self.overlap_appointments = 0
self.inpatient_occupancy = 0 self.inpatient_occupancy = 0
elif self.allow_appointments != 1: elif not self.allow_appointments:
self.overlap_appointments = 0 self.overlap_appointments = 0

View File

@ -2,118 +2,85 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Healthcare Service Unit Type', { frappe.ui.form.on('Healthcare Service Unit Type', {
refresh: function(frm) {
frm.set_df_property('item_code', 'read_only', frm.doc.__islocal ? 0 : 1);
if (!frm.doc.__islocal && frm.doc.is_billable) {
frm.add_custom_button(__('Change Item Code'), function() {
change_item_code(cur_frm, frm.doc);
});
}
},
service_unit_type: function(frm) { service_unit_type: function(frm) {
set_item_details(frm); set_item_details(frm);
if(!frm.doc.__islocal){
if (!frm.doc.__islocal) {
frm.doc.change_in_item = 1; frm.doc.change_in_item = 1;
} }
}, },
is_billable: function(frm) { is_billable: function(frm) {
set_item_details(frm); set_item_details(frm);
}, },
refresh: function(frm) {
frm.set_df_property("item_code", "read_only", frm.doc.__islocal ? 0 : 1);
if(!frm.doc.__islocal) {
frm.add_custom_button(__('Change Item Code'), function() {
change_item_code(cur_frm,frm.doc);
} );
if(frm.doc.disabled == 1){
frm.add_custom_button(__('Enable'), function() {
enable(cur_frm);
} );
}
else{
frm.add_custom_button(__('Disable'), function() {
disable(cur_frm);
} );
}
}
},
rate: function(frm) { rate: function(frm) {
if(!frm.doc.__islocal){ if (!frm.doc.__islocal) {
frm.doc.change_in_item = 1; frm.doc.change_in_item = 1;
} }
}, },
item_group: function(frm) { item_group: function(frm) {
if(!frm.doc.__islocal){ if (!frm.doc.__islocal) {
frm.doc.change_in_item = 1; frm.doc.change_in_item = 1;
} }
}, },
description: function(frm) { description: function(frm) {
if(!frm.doc.__islocal){ if (!frm.doc.__islocal) {
frm.doc.change_in_item = 1; frm.doc.change_in_item = 1;
} }
} }
}); });
var disable = function(frm){ let set_item_details = function(frm) {
var doc = frm.doc; if (frm.doc.service_unit_type && frm.doc.is_billable) {
frappe.call({ if (!frm.doc.item_code)
method: "erpnext.healthcare.doctype.healthcare_service_unit_type.healthcare_service_unit_type.disable_enable", frm.set_value('item_code', frm.doc.service_unit_type);
args: {status: 1, doc_name: doc.name, item: doc.item, is_billable: doc.is_billable}, if (!frm.doc.description)
callback: function(){ frm.set_value('description', frm.doc.service_unit_type);
cur_frm.reload_doc(); if (!frm.doc.item_group)
frm.set_value('item_group', 'Services');
} }
});
}; };
var enable = function(frm){ let change_item_code = function(frm, doc) {
var doc = frm.doc; let d = new frappe.ui.Dialog({
frappe.call({ title: __('Change Item Code'),
method: "erpnext.healthcare.doctype.healthcare_service_unit_type.healthcare_service_unit_type.disable_enable", fields: [
args: {status: 0, doc_name: doc.name, item: doc.item, is_billable: doc.is_billable},
callback: function(){
cur_frm.reload_doc();
}
});
};
var change_item_code = function(frm, doc){
var d = new frappe.ui.Dialog({
title:__("Change Item Code"),
fields:[
{ {
"fieldtype": "Data", 'fieldtype': 'Data',
"label": "Item Code", 'label': 'Item Code',
"fieldname": "Item Code", 'fieldname': 'item_code',
reqd:1 'default': doc.item_code,
}, reqd: 1,
{
"fieldtype": "Button",
"label": __("Change Code"),
click: function() {
var values = d.get_values();
if(!values)
return;
change_item_code_from_unit_type(values["Item Code"], doc);
d.hide();
} }
} ],
] primary_action: function() {
}); let values = d.get_values();
d.show(); if (values) {
d.set_values({
'Item Code': frm.doc.item_code
});
var change_item_code_from_unit_type = function(item_code, doc){
frappe.call({ frappe.call({
"method": "erpnext.healthcare.doctype.healthcare_service_unit_type.healthcare_service_unit_type.change_item_code", "method": "erpnext.healthcare.doctype.healthcare_service_unit_type.healthcare_service_unit_type.change_item_code",
"args": {item: doc.item, item_code: item_code, doc_name: doc.name}, "args": {item: doc.item, item_code: values['item_code'], doc_name: doc.name},
callback: function () { callback: function () {
frm.reload_doc(); frm.reload_doc();
} }
}); });
};
};
var set_item_details = function(frm) {
if(frm.doc.service_unit_type && frm.doc.is_billable == 1){
if(!frm.doc.item_code)
frm.set_value("item_code", frm.doc.service_unit_type);
if(!frm.doc.description)
frm.set_value("description", frm.doc.service_unit_type);
if(!frm.doc.item_group)
frm.set_value("item_group", 'Services');
} }
d.hide();
},
primary_action_label: __("Change Template Code")
});
d.show();
d.set_values({
'Item Code': frm.doc.item_code
});
}; };

View File

@ -1,588 +1,164 @@
{ {
"allow_copy": 0, "actions": [],
"allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 1, "allow_rename": 1,
"autoname": "field:service_unit_type", "autoname": "field:service_unit_type",
"beta": 0,
"creation": "2018-07-11 16:47:51.414675", "creation": "2018-07-11 16:47:51.414675",
"custom": 0,
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [
"disabled",
"service_unit_type",
"allow_appointments",
"overlap_appointments",
"inpatient_occupancy",
"is_billable",
"item_details",
"item",
"item_code",
"item_group",
"uom",
"no_of_hours",
"column_break_11",
"rate",
"description",
"change_in_item"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "service_unit_type", "fieldname": "service_unit_type",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Service Unit Type", "label": "Service Unit Type",
"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, "reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 1 "unique": 1
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0,
"columns": 0,
"default": "0", "default": "0",
"depends_on": "eval:doc.inpatient_occupancy != 1", "depends_on": "eval:doc.inpatient_occupancy != 1",
"fieldname": "allow_appointments", "fieldname": "allow_appointments",
"fieldtype": "Check", "fieldtype": "Check",
"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": "Allow Appointments", "label": "Allow Appointments",
"length": 0, "no_copy": 1
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0,
"columns": 0,
"default": "0", "default": "0",
"depends_on": "eval:doc.allow_appointments == 1 && doc.inpatient_occupany != 1", "depends_on": "eval:doc.allow_appointments == 1 && doc.inpatient_occupany != 1",
"fieldname": "overlap_appointments", "fieldname": "overlap_appointments",
"fieldtype": "Check", "fieldtype": "Check",
"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": "Allow Overlap", "label": "Allow Overlap",
"length": 0, "no_copy": 1
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0,
"columns": 0,
"default": "0", "default": "0",
"depends_on": "eval:doc.allow_appointments != 1", "depends_on": "eval:doc.allow_appointments != 1",
"fieldname": "inpatient_occupancy", "fieldname": "inpatient_occupancy",
"fieldtype": "Check", "fieldtype": "Check",
"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", "label": "Inpatient Occupancy",
"length": 0, "no_copy": 1
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0, "default": "0",
"columns": 0,
"depends_on": "eval:doc.inpatient_occupancy == 1 && doc.allow_appointments != 1", "depends_on": "eval:doc.inpatient_occupancy == 1 && doc.allow_appointments != 1",
"fieldname": "is_billable", "fieldname": "is_billable",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "label": "Is Billable"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Is Billable",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "is_billable", "depends_on": "is_billable",
"fieldname": "item_details", "fieldname": "item_details",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "label": "Item Details"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Item Details",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "item", "fieldname": "item",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Item", "label": "Item",
"length": 0,
"no_copy": 0,
"options": "Item", "options": "Item",
"permlevel": 0, "read_only": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "item_code", "fieldname": "item_code",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Item Code", "label": "Item Code",
"length": 0, "mandatory_depends_on": "eval: doc.is_billable == 1"
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "item_group", "fieldname": "item_group",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Item Group", "label": "Item Group",
"length": 0, "mandatory_depends_on": "eval: doc.is_billable == 1",
"no_copy": 0, "options": "Item Group"
"options": "Item Group",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "uom", "fieldname": "uom",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "UOM", "label": "UOM",
"length": 0, "mandatory_depends_on": "eval: doc.is_billable == 1",
"no_copy": 0, "options": "UOM"
"options": "UOM",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "no_of_hours", "fieldname": "no_of_hours",
"fieldtype": "Int", "fieldtype": "Int",
"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": "UOM Conversion in Hours", "label": "UOM Conversion in Hours",
"length": 0, "mandatory_depends_on": "eval: doc.is_billable == 1"
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_11", "fieldname": "column_break_11",
"fieldtype": "Column Break", "fieldtype": "Column Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "rate", "fieldname": "rate",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "label": "Rate / UOM"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Rate / UOM",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0", "default": "0",
"fieldname": "disabled", "fieldname": "disabled",
"fieldtype": "Check", "fieldtype": "Check",
"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": "Disabled", "label": "Disabled",
"length": 0, "no_copy": 1
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "description", "fieldname": "description",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0, "label": "Description"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "change_in_item", "fieldname": "change_in_item",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 1, "hidden": 1,
"ignore_user_permissions": 0, "label": "Change in Item"
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Change in Item",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
} }
], ],
"has_web_view": 0, "links": [],
"hide_heading": 0, "modified": "2020-01-30 16:06:00.624496",
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-08-08 13:00:23.751635",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Healthcare", "module": "Healthcare",
"name": "Healthcare Service Unit Type", "name": "Healthcare Service Unit Type",
"name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 0,
"cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Healthcare Administrator", "role": "Healthcare Administrator",
"set_user_permissions": 0,
"share": 1, "share": 1,
"submit": 0,
"write": 1 "write": 1
} }
], ],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"restrict_to_domain": "Healthcare", "restrict_to_domain": "Healthcare",
"show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"title_field": "service_unit_type", "title_field": "service_unit_type"
"track_changes": 0,
"track_seen": 0,
"track_views": 0
} }

View File

@ -10,109 +10,107 @@ from frappe.model.rename_doc import rename_doc
class HealthcareServiceUnitType(Document): class HealthcareServiceUnitType(Document):
def validate(self): def validate(self):
if self.is_billable == 1: if self.is_billable:
if not self.uom or not self.item_group or not self.description or not self.no_of_hours > 0: if self.disabled:
frappe.throw(_("Configure Item Fields like UOM, Item Group, Description and No of Hours.")) frappe.db.set_value('Item', self.item, 'disabled', 1)
else:
frappe.db.set_value('Item', self.item, 'disabled', 0)
def after_insert(self): def after_insert(self):
if self.inpatient_occupancy and self.is_billable: if self.inpatient_occupancy and self.is_billable:
create_item(self) create_item(self)
def on_trash(self): def on_trash(self):
if(self.item): if self.item:
try: try:
frappe.delete_doc("Item",self.item) frappe.delete_doc('Item', self.item)
except Exception: except Exception:
frappe.throw(_("""Not permitted. Please disable the Service Unit Type""")) frappe.throw(_('Not permitted. Please disable the Service Unit Type'))
def on_update(self): def on_update(self):
if(self.change_in_item and self.is_billable == 1 and self.item): if self.change_in_item and self.is_billable and self.item:
updating_item(self) update_item(self)
item_price = item_price_exist(self)
item_price = item_price_exists(self)
if not item_price: if not item_price:
if(self.rate != 0.0): price_list_name = frappe.db.get_value('Price List', {'selling': 1})
price_list_name = frappe.db.get_value("Price List", {"selling": 1}) if self.rate:
if(self.rate):
make_item_price(self.item_code, price_list_name, self.rate) make_item_price(self.item_code, price_list_name, self.rate)
else: else:
make_item_price(self.item_code, price_list_name, 0.0) make_item_price(self.item_code, price_list_name, 0.0)
else: else:
frappe.db.set_value("Item Price", item_price, "price_list_rate", self.rate) frappe.db.set_value('Item Price', item_price, 'price_list_rate', self.rate)
frappe.db.set_value(self.doctype,self.name,"change_in_item",0) frappe.db.set_value(self.doctype, self.name, 'change_in_item',0)
elif(self.is_billable == 0 and self.item): elif not self.is_billable and self.item:
frappe.db.set_value("Item",self.item,"disabled",1) frappe.db.set_value('Item', self.item, 'disabled', 1)
self.reload() self.reload()
def item_price_exist(doc):
item_price = frappe.db.exists({ def item_price_exists(doc):
"doctype": "Item Price", item_price = frappe.db.exists({'doctype': 'Item Price', 'item_code': doc.item_code})
"item_code": doc.item_code}) if len(item_price):
if(item_price):
return item_price[0][0] return item_price[0][0]
else:
return False return False
def updating_item(doc):
frappe.db.sql("""update `tabItem` set item_name=%s, item_group=%s, disabled=0, standard_rate=%s,
description=%s, modified=NOW() where item_code=%s""",
(doc.service_unit_type, doc.item_group , doc.rate, doc.description, doc.item))
def create_item(doc): def create_item(doc):
#insert item # insert item
item = frappe.get_doc({ item = frappe.get_doc({
"doctype": "Item", 'doctype': 'Item',
"item_code": doc.item_code, 'item_code': doc.item_code,
"item_name":doc.service_unit_type, 'item_name': doc.service_unit_type,
"item_group": doc.item_group, 'item_group': doc.item_group,
"description":doc.description, 'description': doc.description or doc.item_code,
"is_sales_item": 1, 'is_sales_item': 1,
"is_service_item": 1, 'is_service_item': 1,
"is_purchase_item": 0, 'is_purchase_item': 0,
"is_stock_item": 0, 'is_stock_item': 0,
"show_in_website": 0, 'show_in_website': 0,
"is_pro_applicable": 0, 'is_pro_applicable': 0,
"disabled": 0, 'disabled': 0,
"stock_uom": doc.uom 'stock_uom': doc.uom
}).insert(ignore_permissions=True) }).insert(ignore_permissions=True, ignore_mandatory=True)
#insert item price # insert item price
#get item price list to insert item price # get item price list to insert item price
if(doc.rate != 0.0): price_list_name = frappe.db.get_value('Price List', {'selling': 1})
price_list_name = frappe.db.get_value("Price List", {"selling": 1}) if doc.rate:
if(doc.rate):
make_item_price(item.name, price_list_name, doc.rate) make_item_price(item.name, price_list_name, doc.rate)
item.standard_rate = doc.rate item.standard_rate = doc.rate
else: else:
make_item_price(item.name, price_list_name, 0.0) make_item_price(item.name, price_list_name, 0.0)
item.standard_rate = 0.0 item.standard_rate = 0.0
item.save(ignore_permissions = True)
#Set item to the Doc
frappe.db.set_value("Healthcare Service Unit Type", doc.name, "item", item.name)
doc.reload() #refresh the doc after insert. item.save(ignore_permissions=True)
# Set item in the doc
doc.db_set('item', item.name)
def make_item_price(item, price_list_name, item_price): def make_item_price(item, price_list_name, item_price):
frappe.get_doc({ frappe.get_doc({
"doctype": "Item Price", 'doctype': 'Item Price',
"price_list": price_list_name, 'price_list': price_list_name,
"item_code": item, 'item_code': item,
"price_list_rate": item_price 'price_list_rate': item_price
}).insert(ignore_permissions=True) }).insert(ignore_permissions=True, ignore_mandatory=True)
def update_item(doc):
item = frappe.get_doc("Item", doc.item)
if item:
item.update({
"item_name": doc.service_unit_type,
"item_group": doc.item_group,
"disabled": 0,
"standard_rate": doc.rate,
"description": doc.description
})
item.db_update()
@frappe.whitelist() @frappe.whitelist()
def change_item_code(item, item_code, doc_name): def change_item_code(item, item_code, doc_name):
item_exist = frappe.db.exists({ if frappe.db.exists({'doctype': 'Item', 'item_code': item_code}):
"doctype": "Item", frappe.throw(_('Item with Item Code {0} already exists').format(item_code))
"item_code": item_code})
if(item_exist):
frappe.throw(_("Code {0} already exist").format(item_code))
else: else:
rename_doc("Item", item, item_code, ignore_permissions=True) rename_doc('Item', item, item_code, ignore_permissions=True)
frappe.db.set_value("Healthcare Service Unit Type", doc_name, "item_code", item_code) frappe.db.set_value('Healthcare Service Unit Type', doc_name, 'item_code', item_code)
@frappe.whitelist()
def disable_enable(status, doc_name, item=None, is_billable=None):
frappe.db.set_value("Healthcare Service Unit Type", doc_name, "disabled", status)
if(is_billable == 1):
frappe.db.set_value("Item", item, "disabled", status)

View File

@ -0,0 +1,13 @@
from __future__ import unicode_literals
from frappe import _
def get_data():
return {
'fieldname': 'service_unit_type',
'transactions': [
{
'label': _('Healthcare Service Units'),
'items': ['Healthcare Service Unit']
},
]
}

View File

@ -3,6 +3,31 @@
# See license.txt # See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest import unittest
import frappe
class TestHealthcareServiceUnitType(unittest.TestCase): class TestHealthcareServiceUnitType(unittest.TestCase):
pass def test_item_creation(self):
unit_type = get_unit_type()
self.assertTrue(frappe.db.exists('Item', unit_type.item))
# check item disabled
unit_type.disabled = 1
unit_type.save()
self.assertEqual(frappe.db.get_value('Item', unit_type.item, 'disabled'), 1)
def get_unit_type():
if frappe.db.exists('Healthcare Service Unit Type', 'Inpatient Rooms'):
return frappe.get_doc('Healthcare Service Unit Type', 'Inpatient Rooms')
unit_type = frappe.new_doc('Healthcare Service Unit Type')
unit_type.service_unit_type = 'Inpatient Rooms'
unit_type.inpatient_occupancy = 1
unit_type.is_billable = 1
unit_type.item_code = 'Inpatient Rooms'
unit_type.item_group = 'Services'
unit_type.uom = 'Hour'
unit_type.no_of_hours = 1
unit_type.rate = 4000
unit_type.save()
return unit_type

Some files were not shown because too many files have changed in this diff Show More