From d16d0efde5f26c7be4f877d7fa3e5ebf8593778b Mon Sep 17 00:00:00 2001 From: Afshan Date: Wed, 8 Jul 2020 19:23:13 +0530 Subject: [PATCH 01/16] feat: added range for age in stock ageing --- .../stock/report/stock_ageing/stock_ageing.js | 21 +++++++++ .../stock/report/stock_ageing/stock_ageing.py | 43 +++++++++++++++++-- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.js b/erpnext/stock/report/stock_ageing/stock_ageing.js index ccde61a167..8495142ba5 100644 --- a/erpnext/stock/report/stock_ageing/stock_ageing.js +++ b/erpnext/stock/report/stock_ageing/stock_ageing.js @@ -36,6 +36,27 @@ frappe.query_reports["Stock Ageing"] = { "fieldtype": "Link", "options": "Brand" }, + { + "fieldname":"range1", + "label": __("Ageing Range 1"), + "fieldtype": "Int", + "default": "30", + "reqd": 1 + }, + { + "fieldname":"range2", + "label": __("Ageing Range 2"), + "fieldtype": "Int", + "default": "60", + "reqd": 1 + }, + { + "fieldname":"range3", + "label": __("Ageing Range 3"), + "fieldtype": "Int", + "default": "90", + "reqd": 1 + }, { "fieldname":"show_warehouse_wise_stock", "label": __("Show Warehouse-wise Stock"), diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py index d5878cb662..41b8f12da5 100644 --- a/erpnext/stock/report/stock_ageing/stock_ageing.py +++ b/erpnext/stock/report/stock_ageing/stock_ageing.py @@ -4,12 +4,12 @@ from __future__ import unicode_literals import frappe from frappe import _ -from frappe.utils import date_diff, flt +from frappe.utils import date_diff, flt, cint +# from frappe.utils import getdate, nowdate, flt, cint, formatdate, cstr, now, time_diff_in_seconds from six import iteritems from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos def execute(filters=None): - columns = get_columns(filters) item_details = get_fifo_queue(filters) to_date = filters["to_date"] @@ -25,6 +25,7 @@ def execute(filters=None): average_age = get_average_age(fifo_queue, to_date) earliest_age = date_diff(to_date, fifo_queue[0][1]) latest_age = date_diff(to_date, fifo_queue[-1][1]) + range1, range2, range3, above_range3 = get_range_age(filters, fifo_queue, to_date) row = [details.name, details.item_name, details.description, details.item_group, details.brand] @@ -33,6 +34,7 @@ def execute(filters=None): row.append(details.warehouse) row.extend([item_dict.get("total_qty"), average_age, + range1, range2, range3, above_range3, earliest_age, latest_age, details.stock_uom]) data.append(row) @@ -55,7 +57,25 @@ def get_average_age(fifo_queue, to_date): return flt(age_qty / total_qty, 2) if total_qty else 0.0 +def get_range_age(filters, fifo_queue, to_date): + range1 = range2 = range3 = above_range3 = 0.0 + for item in fifo_queue: + age = date_diff(to_date, item[1]) + + if age <= filters.range1: + range1 = item[0] + elif age <= filters.range2: + range2 = item[0] + elif age <= filters.range3: + range3 = item[0] + else: + above_range3 = item[0] + + return range1, range2, range3, above_range3 + def get_columns(filters): + range_columns = [] + setup_ageing_columns(filters, range_columns) columns = [ { "label": _("Item Code"), @@ -112,7 +132,9 @@ def get_columns(filters): "fieldname": "average_age", "fieldtype": "Float", "width": 100 - }, + }]) + columns.extend(range_columns) + columns.extend([ { "label": _("Earliest"), "fieldname": "earliest", @@ -263,3 +285,18 @@ def get_chart_data(data, filters): }, "type" : "bar" } + +def setup_ageing_columns(filters, range_columns): + for i, label in enumerate(["0-{range1}".format(range1=filters["range1"]), + "{range1}-{range2}".format(range1=cint(filters["range1"])+ 1, range2=filters["range2"]), + "{range2}-{range3}".format(range2=cint(filters["range2"])+ 1, range3=filters["range3"]), + "{range3}-{above}".format(range3=cint(filters["range3"])+ 1, above=_("Above"))]): + add_column(range_columns, label="Age in ("+ label +")", fieldname='range' + str(i+1)) + +def add_column(range_columns, label, fieldname, fieldtype='Float', width=140): + range_columns.append(dict( + label=label, + fieldname=fieldname, + fieldtype=fieldtype, + width=width + )) \ No newline at end of file From a629c9e1bc444554b5696e1ad9aeacd150776c4e Mon Sep 17 00:00:00 2001 From: Afshan Date: Wed, 8 Jul 2020 19:28:28 +0530 Subject: [PATCH 02/16] style: remove import comment --- erpnext/stock/report/stock_ageing/stock_ageing.py | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py index 41b8f12da5..4e6923f760 100644 --- a/erpnext/stock/report/stock_ageing/stock_ageing.py +++ b/erpnext/stock/report/stock_ageing/stock_ageing.py @@ -5,7 +5,6 @@ from __future__ import unicode_literals import frappe from frappe import _ from frappe.utils import date_diff, flt, cint -# from frappe.utils import getdate, nowdate, flt, cint, formatdate, cstr, now, time_diff_in_seconds from six import iteritems from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos From 767ee1cdb8681dc72d47219d638a4a7190bf9a5d Mon Sep 17 00:00:00 2001 From: Afshan Date: Thu, 23 Jul 2020 15:39:27 +0530 Subject: [PATCH 03/16] fix: logic to get other items also other than just 1st one --- erpnext/stock/report/stock_ageing/stock_ageing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py index 4e6923f760..d5d2bc3999 100644 --- a/erpnext/stock/report/stock_ageing/stock_ageing.py +++ b/erpnext/stock/report/stock_ageing/stock_ageing.py @@ -70,7 +70,7 @@ def get_range_age(filters, fifo_queue, to_date): else: above_range3 = item[0] - return range1, range2, range3, above_range3 + return range1, range2, range3, above_range3 def get_columns(filters): range_columns = [] From cb45836cda5df030571c769761f1a9afa9f6a101 Mon Sep 17 00:00:00 2001 From: Abhishek Balam Date: Thu, 23 Jul 2020 19:07:11 +0530 Subject: [PATCH 04/16] feat(CRM): Email Group Option In Email Campaign (#22731) * new parent updating logic, made requested changes * feat: adding Email Group option in Email Campaign * fix: inv commas --- .../crm/doctype/email_campaign/email_campaign.json | 6 ++++-- erpnext/crm/doctype/email_campaign/email_campaign.py | 11 ++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/erpnext/crm/doctype/email_campaign/email_campaign.json b/erpnext/crm/doctype/email_campaign/email_campaign.json index 736a9d6173..0340364bd5 100644 --- a/erpnext/crm/doctype/email_campaign/email_campaign.json +++ b/erpnext/crm/doctype/email_campaign/email_campaign.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "format:MAIL-CAMP-{YYYY}-{#####}", "creation": "2019-06-30 16:05:30.015615", "doctype": "DocType", @@ -52,7 +53,7 @@ "fieldtype": "Select", "in_list_view": 1, "label": "Email Campaign For ", - "options": "\nLead\nContact", + "options": "\nLead\nContact\nEmail Group", "reqd": 1 }, { @@ -70,7 +71,8 @@ "options": "User" } ], - "modified": "2019-11-11 17:18:47.342839", + "links": [], + "modified": "2020-07-15 12:43:25.548682", "modified_by": "Administrator", "module": "CRM", "name": "Email Campaign", diff --git a/erpnext/crm/doctype/email_campaign/email_campaign.py b/erpnext/crm/doctype/email_campaign/email_campaign.py index 8f60ecf621..71c93e8d39 100644 --- a/erpnext/crm/doctype/email_campaign/email_campaign.py +++ b/erpnext/crm/doctype/email_campaign/email_campaign.py @@ -70,10 +70,15 @@ def send_email_to_leads_or_contacts(): send_mail(entry, email_campaign) def send_mail(entry, email_campaign): - recipient = frappe.db.get_value(email_campaign.email_campaign_for, email_campaign.get("recipient"), 'email_id') + recipient_list = [] + if email_campaign.email_campaign_for == "Email Group": + for member in frappe.db.get_list("Email Group Member", filters={"email_group": email_campaign.get("recipient")}, fields=["email"]): + recipient_list.append(member['email']) + else: + recipient_list.append(frappe.db.get_value(email_campaign.email_campaign_for, email_campaign.get("recipient"), "email_id")) email_template = frappe.get_doc("Email Template", entry.get("email_template")) - sender = frappe.db.get_value("User", email_campaign.get("sender"), 'email') + sender = frappe.db.get_value("User", email_campaign.get("sender"), "email") context = {"doc": frappe.get_doc(email_campaign.email_campaign_for, email_campaign.recipient)} # send mail and link communication to document comm = make( @@ -82,7 +87,7 @@ def send_mail(entry, email_campaign): subject = frappe.render_template(email_template.get("subject"), context), content = frappe.render_template(email_template.get("response"), context), sender = sender, - recipients = recipient, + recipients = recipient_list, communication_medium = "Email", sent_or_received = "Sent", send_email = True, From aa94abf60112ad3deba5fbea7f1584cbcfdc5d07 Mon Sep 17 00:00:00 2001 From: Afshan <33727827+AfshanKhan@users.noreply.github.com> Date: Thu, 23 Jul 2020 19:12:38 +0530 Subject: [PATCH 05/16] fix: asset dashboard report changes (#22759) * fix: asset dashboard report changes * fix: moved static filters to dynamic filters Co-authored-by: Nabin Hait Co-authored-by: Marica --- .../assets/assets_dashboard/asset/asset.json | 39 +++++++++++++++++++ .../asset_value_analytics.json | 27 +++++++++++++ .../category_wise_asset_value.json | 29 ++++++++++++++ .../location_wise_asset_value.json | 29 ++++++++++++++ .../number_card/asset_value/asset_value.json | 21 ++++++++++ .../new_assets_(this_year).json | 20 ++++++++++ .../total_assets/total_assets.json | 20 ++++++++++ 7 files changed, 185 insertions(+) create mode 100644 erpnext/assets/assets_dashboard/asset/asset.json create mode 100644 erpnext/assets/dashboard_chart/asset_value_analytics/asset_value_analytics.json create mode 100644 erpnext/assets/dashboard_chart/category_wise_asset_value/category_wise_asset_value.json create mode 100644 erpnext/assets/dashboard_chart/location_wise_asset_value/location_wise_asset_value.json create mode 100644 erpnext/assets/number_card/asset_value/asset_value.json create mode 100644 erpnext/assets/number_card/new_assets_(this_year)/new_assets_(this_year).json create mode 100644 erpnext/assets/number_card/total_assets/total_assets.json diff --git a/erpnext/assets/assets_dashboard/asset/asset.json b/erpnext/assets/assets_dashboard/asset/asset.json new file mode 100644 index 0000000000..56b1e2a71c --- /dev/null +++ b/erpnext/assets/assets_dashboard/asset/asset.json @@ -0,0 +1,39 @@ +{ + "cards": [ + { + "card": "Total Assets" + }, + { + "card": "New Assets (This Year)" + }, + { + "card": "Asset Value" + } + ], + "charts": [ + { + "chart": "Asset Value Analytics", + "width": "Full" + }, + { + "chart": "Category-wise Asset Value", + "width": "Half" + }, + { + "chart": "Location-wise Asset Value", + "width": "Half" + } + ], + "creation": "2020-07-14 18:23:53.343082", + "dashboard_name": "Asset", + "docstatus": 0, + "doctype": "Dashboard", + "idx": 0, + "is_default": 0, + "is_standard": 1, + "modified": "2020-07-21 18:14:25.078929", + "modified_by": "Administrator", + "module": "Assets", + "name": "Asset", + "owner": "Administrator" +} \ No newline at end of file diff --git a/erpnext/assets/dashboard_chart/asset_value_analytics/asset_value_analytics.json b/erpnext/assets/dashboard_chart/asset_value_analytics/asset_value_analytics.json new file mode 100644 index 0000000000..bc2edc9d7d --- /dev/null +++ b/erpnext/assets/dashboard_chart/asset_value_analytics/asset_value_analytics.json @@ -0,0 +1,27 @@ +{ + "chart_name": "Asset Value Analytics", + "chart_type": "Report", + "creation": "2020-07-14 18:23:53.091233", + "custom_options": "{\"type\": \"bar\", \"barOptions\": {\"stacked\": 1}, \"axisOptions\": {\"shortenYAxisNumbers\": 1}, \"tooltipOptions\": {}}", + "docstatus": 0, + "doctype": "Dashboard Chart", + "dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_fiscal_year\":\"frappe.sys_defaults.fiscal_year\",\"to_fiscal_year\":\"frappe.sys_defaults.fiscal_year\",\"from_date\":\"frappe.datetime.add_months(frappe.datetime.nowdate(), -12)\",\"to_date\":\"frappe.datetime.nowdate()\"}", + "filters_json": "{\"status\":\"In Location\",\"filter_based_on\":\"Fiscal Year\",\"period_start_date\":\"2020-04-01\",\"period_end_date\":\"2021-03-31\",\"date_based_on\":\"Purchase Date\",\"group_by\":\"--Select a group--\"}", + "group_by_type": "Count", + "idx": 0, + "is_public": 0, + "is_standard": 1, + "modified": "2020-07-23 13:53:33.211371", + "modified_by": "Administrator", + "module": "Assets", + "name": "Asset Value Analytics", + "number_of_groups": 0, + "owner": "Administrator", + "report_name": "Fixed Asset Register", + "time_interval": "Yearly", + "timeseries": 0, + "timespan": "Last Year", + "type": "Bar", + "use_report_chart": 1, + "y_axis": [] +} \ No newline at end of file diff --git a/erpnext/assets/dashboard_chart/category_wise_asset_value/category_wise_asset_value.json b/erpnext/assets/dashboard_chart/category_wise_asset_value/category_wise_asset_value.json new file mode 100644 index 0000000000..e79d2d7372 --- /dev/null +++ b/erpnext/assets/dashboard_chart/category_wise_asset_value/category_wise_asset_value.json @@ -0,0 +1,29 @@ +{ + "chart_name": "Category-wise Asset Value", + "chart_type": "Report", + "creation": "2020-07-14 18:23:53.146304", + "custom_options": "{\"type\": \"donut\", \"height\": 300, \"axisOptions\": {\"shortenYAxisNumbers\": 1}}", + "docstatus": 0, + "doctype": "Dashboard Chart", + "dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_date\":\"frappe.datetime.add_months(frappe.datetime.nowdate(), -12)\",\"to_date\":\"frappe.datetime.nowdate()\"}", + "filters_json": "{\"status\":\"In Location\",\"group_by\":\"Asset Category\",\"is_existing_asset\":0}", + "idx": 0, + "is_public": 0, + "is_standard": 1, + "modified": "2020-07-23 13:39:32.429240", + "modified_by": "Administrator", + "module": "Assets", + "name": "Category-wise Asset Value", + "number_of_groups": 0, + "owner": "Administrator", + "report_name": "Fixed Asset Register", + "timeseries": 0, + "type": "Donut", + "use_report_chart": 0, + "x_field": "asset_category", + "y_axis": [ + { + "y_field": "asset_value" + } + ] +} \ No newline at end of file diff --git a/erpnext/assets/dashboard_chart/location_wise_asset_value/location_wise_asset_value.json b/erpnext/assets/dashboard_chart/location_wise_asset_value/location_wise_asset_value.json new file mode 100644 index 0000000000..481586e7ca --- /dev/null +++ b/erpnext/assets/dashboard_chart/location_wise_asset_value/location_wise_asset_value.json @@ -0,0 +1,29 @@ +{ + "chart_name": "Location-wise Asset Value", + "chart_type": "Report", + "creation": "2020-07-14 18:23:53.195389", + "custom_options": "{\"type\": \"donut\", \"height\": 300, \"axisOptions\": {\"shortenYAxisNumbers\": 1}}", + "docstatus": 0, + "doctype": "Dashboard Chart", + "dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_date\":\"frappe.datetime.add_months(frappe.datetime.nowdate(), -12)\",\"to_date\":\"frappe.datetime.nowdate()\"}", + "filters_json": "{\"status\":\"In Location\",\"group_by\":\"Location\",\"is_existing_asset\":0}", + "idx": 0, + "is_public": 0, + "is_standard": 1, + "modified": "2020-07-23 13:42:44.912551", + "modified_by": "Administrator", + "module": "Assets", + "name": "Location-wise Asset Value", + "number_of_groups": 0, + "owner": "Administrator", + "report_name": "Fixed Asset Register", + "timeseries": 0, + "type": "Donut", + "use_report_chart": 0, + "x_field": "location", + "y_axis": [ + { + "y_field": "asset_value" + } + ] +} \ No newline at end of file diff --git a/erpnext/assets/number_card/asset_value/asset_value.json b/erpnext/assets/number_card/asset_value/asset_value.json new file mode 100644 index 0000000000..68e5f54c78 --- /dev/null +++ b/erpnext/assets/number_card/asset_value/asset_value.json @@ -0,0 +1,21 @@ +{ + "aggregate_function_based_on": "value_after_depreciation", + "creation": "2020-07-14 18:23:53.302457", + "docstatus": 0, + "doctype": "Number Card", + "document_type": "Asset", + "filters_json": "[]", + "function": "Sum", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "label": "Asset Value", + "modified": "2020-07-21 18:13:47.647997", + "modified_by": "Administrator", + "module": "Assets", + "name": "Asset Value", + "owner": "Administrator", + "show_percentage_stats": 1, + "stats_time_interval": "Monthly", + "type": "Document Type" +} \ No newline at end of file diff --git a/erpnext/assets/number_card/new_assets_(this_year)/new_assets_(this_year).json b/erpnext/assets/number_card/new_assets_(this_year)/new_assets_(this_year).json new file mode 100644 index 0000000000..6c8fb35657 --- /dev/null +++ b/erpnext/assets/number_card/new_assets_(this_year)/new_assets_(this_year).json @@ -0,0 +1,20 @@ +{ + "creation": "2020-07-14 18:23:53.267919", + "docstatus": 0, + "doctype": "Number Card", + "document_type": "Asset", + "filters_json": "[[\"Asset\",\"creation\",\"Timespan\",\"this year\",false]]", + "function": "Count", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "label": "New Assets (This Year)", + "modified": "2020-07-23 13:45:20.418766", + "modified_by": "Administrator", + "module": "Assets", + "name": "New Assets (This Year)", + "owner": "Administrator", + "show_percentage_stats": 1, + "stats_time_interval": "Monthly", + "type": "Document Type" +} \ No newline at end of file diff --git a/erpnext/assets/number_card/total_assets/total_assets.json b/erpnext/assets/number_card/total_assets/total_assets.json new file mode 100644 index 0000000000..d127de8f2c --- /dev/null +++ b/erpnext/assets/number_card/total_assets/total_assets.json @@ -0,0 +1,20 @@ +{ + "creation": "2020-07-14 18:23:53.233328", + "docstatus": 0, + "doctype": "Number Card", + "document_type": "Asset", + "filters_json": "[]", + "function": "Count", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "label": "Total Assets", + "modified": "2020-07-21 18:12:51.664292", + "modified_by": "Administrator", + "module": "Assets", + "name": "Total Assets", + "owner": "Administrator", + "show_percentage_stats": 1, + "stats_time_interval": "Monthly", + "type": "Document Type" +} \ No newline at end of file From 9bd5f1e4b02f6b6b73faeef88c25f462ef48cc49 Mon Sep 17 00:00:00 2001 From: Sun Howwrongbum Date: Thu, 23 Jul 2020 20:06:26 +0530 Subject: [PATCH 06/16] fix: incorrect available_qty being set (#22539) * fix: incorrect available_qty being set * style: descriptive variables --- erpnext/public/js/utils/serial_no_batch_selector.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js index 42f9cabc27..d9f6e1d433 100644 --- a/erpnext/public/js/utils/serial_no_batch_selector.js +++ b/erpnext/public/js/utils/serial_no_batch_selector.js @@ -338,8 +338,8 @@ erpnext.SerialNoBatchSelector = Class.extend({ }; }, change: function () { - let val = this.get_value(); - if (val.length === 0) { + const batch_no = this.get_value(); + if (!batch_no) { this.grid_row.on_grid_fields_dict .available_qty.set_value(0); return; @@ -359,14 +359,11 @@ erpnext.SerialNoBatchSelector = Class.extend({ return; } - let batch_number = me.item.batch_no || - this.grid_row.on_grid_fields_dict.batch_no.get_value(); - if (me.warehouse_details.name) { frappe.call({ method: 'erpnext.stock.doctype.batch.batch.get_batch_qty', args: { - batch_no: batch_number, + batch_no, warehouse: me.warehouse_details.name, item_code: me.item_code }, From 775fbe74c50f5b6f95e1d71a080259c732f1c2b8 Mon Sep 17 00:00:00 2001 From: Afshan Date: Thu, 23 Jul 2020 20:33:07 +0530 Subject: [PATCH 07/16] fix: fixed the logic --- erpnext/stock/report/stock_ageing/stock_ageing.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py index d5d2bc3999..63cad526fc 100644 --- a/erpnext/stock/report/stock_ageing/stock_ageing.py +++ b/erpnext/stock/report/stock_ageing/stock_ageing.py @@ -62,13 +62,13 @@ def get_range_age(filters, fifo_queue, to_date): age = date_diff(to_date, item[1]) if age <= filters.range1: - range1 = item[0] + range1 += item[0] elif age <= filters.range2: - range2 = item[0] + range2 += item[0] elif age <= filters.range3: - range3 = item[0] + range3 += item[0] else: - above_range3 = item[0] + above_range3 += item[0] return range1, range2, range3, above_range3 @@ -290,7 +290,7 @@ def setup_ageing_columns(filters, range_columns): "{range1}-{range2}".format(range1=cint(filters["range1"])+ 1, range2=filters["range2"]), "{range2}-{range3}".format(range2=cint(filters["range2"])+ 1, range3=filters["range3"]), "{range3}-{above}".format(range3=cint(filters["range3"])+ 1, above=_("Above"))]): - add_column(range_columns, label="Age in ("+ label +")", fieldname='range' + str(i+1)) + add_column(range_columns, label="Age ("+ label +")", fieldname='range' + str(i+1)) def add_column(range_columns, label, fieldname, fieldtype='Float', width=140): range_columns.append(dict( From 9843e9f917815ca0ea2f8221cd2f1c869f001c48 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Thu, 23 Jul 2020 20:58:57 +0530 Subject: [PATCH 08/16] fix: Expnese claim outstanding while making payment entry (#22735) --- erpnext/accounts/doctype/payment_entry/payment_entry.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index f9db14b90f..9df8655ccf 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -911,7 +911,7 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre elif reference_doctype != "Journal Entry": if party_account_currency == company_currency: if ref_doc.doctype == "Expense Claim": - total_amount = ref_doc.total_sanctioned_amount + total_amount = flt(ref_doc.total_sanctioned_amount) + flt(ref_doc.total_taxes_and_charges) elif ref_doc.doctype == "Employee Advance": total_amount = ref_doc.advance_amount else: @@ -929,8 +929,8 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre outstanding_amount = ref_doc.get("outstanding_amount") bill_no = ref_doc.get("bill_no") elif reference_doctype == "Expense Claim": - outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) \ - - flt(ref_doc.get("total_amount+reimbursed")) - flt(ref_doc.get("total_advance_amount")) + outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) + flt(ref_doc.get("total_taxes_and_charges"))\ + - flt(ref_doc.get("total_amount_reimbursed")) - flt(ref_doc.get("total_advance_amount")) elif reference_doctype == "Employee Advance": outstanding_amount = ref_doc.advance_amount - flt(ref_doc.paid_amount) else: From 89f93461858dc7203f4de11f166b80800be830e2 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Thu, 23 Jul 2020 20:59:56 +0530 Subject: [PATCH 09/16] fix(Education): descriptions not copied while creating fees from fee structure (#22792) Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> --- erpnext/education/api.py | 2 +- erpnext/education/doctype/fees/fees.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/education/api.py b/erpnext/education/api.py index fe033d4fc5..bf9f2215f3 100644 --- a/erpnext/education/api.py +++ b/erpnext/education/api.py @@ -152,7 +152,7 @@ def get_fee_components(fee_structure): :param fee_structure: Fee Structure. """ if fee_structure: - fs = frappe.get_list("Fee Component", fields=["fees_category", "amount"] , filters={"parent": fee_structure}, order_by= "idx") + fs = frappe.get_list("Fee Component", fields=["fees_category", "description", "amount"] , filters={"parent": fee_structure}, order_by= "idx") return fs diff --git a/erpnext/education/doctype/fees/fees.js b/erpnext/education/doctype/fees/fees.js index 867866fbf1..aaf42b4751 100644 --- a/erpnext/education/doctype/fees/fees.js +++ b/erpnext/education/doctype/fees/fees.js @@ -162,6 +162,7 @@ frappe.ui.form.on("Fees", { $.each(r.message, function(i, d) { var row = frappe.model.add_child(frm.doc, "Fee Component", "components"); row.fees_category = d.fees_category; + row.description = d.description; row.amount = d.amount; }); } From 73b86d241c3dcac57835368bf0272d0f9029f863 Mon Sep 17 00:00:00 2001 From: Afshan Date: Thu, 23 Jul 2020 21:09:27 +0530 Subject: [PATCH 10/16] fix: conversion to float --- erpnext/stock/report/stock_ageing/stock_ageing.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py index 63cad526fc..4af3c541a6 100644 --- a/erpnext/stock/report/stock_ageing/stock_ageing.py +++ b/erpnext/stock/report/stock_ageing/stock_ageing.py @@ -62,13 +62,13 @@ def get_range_age(filters, fifo_queue, to_date): age = date_diff(to_date, item[1]) if age <= filters.range1: - range1 += item[0] + range1 += flt(item[0]) elif age <= filters.range2: - range2 += item[0] + range2 += flt(item[0]) elif age <= filters.range3: - range3 += item[0] + range3 += flt(item[0]) else: - above_range3 += item[0] + above_range3 += flt(item[0]) return range1, range2, range3, above_range3 From 6bbd4d0c14632a4f931303e279b9298d271f0ee8 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 24 Jul 2020 09:20:48 +0530 Subject: [PATCH 11/16] fix: Other charges on income tax (#22797) --- erpnext/payroll/doctype/salary_slip/salary_slip.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py index 1e2983e421..4ccf56435d 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py @@ -869,10 +869,10 @@ class SalarySlip(TransactionBase): # other taxes and charges on income tax for d in tax_slab.other_taxes_and_charges: - if flt(d.min_taxable_income) and flt(d.min_taxable_income) > tax_amount: + if flt(d.min_taxable_income) and flt(d.min_taxable_income) > annual_taxable_earning: continue - if flt(d.max_taxable_income) and flt(d.max_taxable_income) < tax_amount: + if flt(d.max_taxable_income) and flt(d.max_taxable_income) < annual_taxable_earning: continue tax_amount += tax_amount * flt(d.percent) / 100 From 39969647cabb3dd78139772c661e2d0acca07a24 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 24 Jul 2020 09:48:54 +0530 Subject: [PATCH 12/16] fix: Added missing project field in Purchase invoice (#22799) --- .../doctype/purchase_invoice/purchase_invoice.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index 639ef6cae3..df77dc8417 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json @@ -26,6 +26,7 @@ "accounting_dimensions_section", "cost_center", "dimension_col_break", + "project", "supplier_invoice_details", "bill_no", "column_break_15", @@ -1319,13 +1320,19 @@ "fieldtype": "Small Text", "label": "Billing Address", "read_only": 1 + }, + { + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" } ], "icon": "fa fa-file-text", "idx": 204, "is_submittable": 1, "links": [], - "modified": "2020-07-18 05:06:08.488761", + "modified": "2020-07-24 09:46:40.405463", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice", From 91fe10666e9b375d62c7ef9c879a17320164853d Mon Sep 17 00:00:00 2001 From: Afshan <33727827+AfshanKhan@users.noreply.github.com> Date: Fri, 24 Jul 2020 09:49:17 +0530 Subject: [PATCH 13/16] fix: buying price for non stock item in gross profit report (#22616) * fix: buying price for non stock item in gross profit report * fix: refactor query --- .../report/gross_profit/gross_profit.py | 57 +++++++++---------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 4e22b05a81..2563b66d1c 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -223,9 +223,9 @@ class GrossProfitGenerator(object): # IMP NOTE # stock_ledger_entries should already be filtered by item_code and warehouse and # sorted by posting_date desc, posting_time desc - if item_code in self.non_stock_items: + if item_code in self.non_stock_items and (row.project or row.cost_center): #Issue 6089-Get last purchasing rate for non-stock item - item_rate = self.get_last_purchase_rate(item_code) + item_rate = self.get_last_purchase_rate(item_code, row) return flt(row.qty) * item_rate else: @@ -253,38 +253,34 @@ class GrossProfitGenerator(object): def get_average_buying_rate(self, row, item_code): args = row if not item_code in self.average_buying_rate: - if item_code in self.non_stock_items: - self.average_buying_rate[item_code] = flt(frappe.db.sql(""" - select sum(base_net_amount) / sum(qty * conversion_factor) - from `tabPurchase Invoice Item` - where item_code = %s and docstatus=1""", item_code)[0][0]) - else: - args.update({ - 'voucher_type': row.parenttype, - 'voucher_no': row.parent, - 'allow_zero_valuation': True, - 'company': self.filters.company - }) + args.update({ + 'voucher_type': row.parenttype, + 'voucher_no': row.parent, + 'allow_zero_valuation': True, + 'company': self.filters.company + }) - average_buying_rate = get_incoming_rate(args) - self.average_buying_rate[item_code] = flt(average_buying_rate) + average_buying_rate = get_incoming_rate(args) + self.average_buying_rate[item_code] = flt(average_buying_rate) return self.average_buying_rate[item_code] - def get_last_purchase_rate(self, item_code): + def get_last_purchase_rate(self, item_code, row): + condition = '' + if row.project: + condition += " AND a.project='%s'" % (row.project) + elif row.cost_center: + condition += " AND a.cost_center='%s'" % (row.cost_center) if self.filters.to_date: - last_purchase_rate = frappe.db.sql(""" - select (a.base_rate / a.conversion_factor) - from `tabPurchase Invoice Item` a - where a.item_code = %s and a.docstatus=1 - and modified <= %s - order by a.modified desc limit 1""", (item_code, self.filters.to_date)) - else: - last_purchase_rate = frappe.db.sql(""" - select (a.base_rate / a.conversion_factor) - from `tabPurchase Invoice Item` a - where a.item_code = %s and a.docstatus=1 - order by a.modified desc limit 1""", item_code) + condition += " AND modified='%s'" % (self.filters.to_date) + + last_purchase_rate = frappe.db.sql(""" + select (a.base_rate / a.conversion_factor) + from `tabPurchase Invoice Item` a + where a.item_code = %s and a.docstatus=1 + {0} + order by a.modified desc limit 1""".format(condition), item_code) + return flt(last_purchase_rate[0][0]) if last_purchase_rate else 0 def load_invoice_items(self): @@ -321,7 +317,8 @@ class GrossProfitGenerator(object): `tabSales Invoice Item`.brand, `tabSales Invoice Item`.dn_detail, `tabSales Invoice Item`.delivery_note, `tabSales Invoice Item`.stock_qty as qty, `tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount, - `tabSales Invoice Item`.name as "item_row", `tabSales Invoice`.is_return + `tabSales Invoice Item`.name as "item_row", `tabSales Invoice`.is_return, + `tabSales Invoice Item`.cost_center {sales_person_cols} from `tabSales Invoice` inner join `tabSales Invoice Item` From ecb1460440ee1657bb2cd8d4ae29d056b235fe1b Mon Sep 17 00:00:00 2001 From: Afshan <33727827+AfshanKhan@users.noreply.github.com> Date: Fri, 24 Jul 2020 10:48:16 +0530 Subject: [PATCH 14/16] =?UTF-8?q?fix:=20update=20the=20project=20after=20t?= =?UTF-8?q?ask=20deletion=20so=20that=20the=20%=20completed=20s=E2=80=A6?= =?UTF-8?q?=20(#22591)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: update the project after task deletion so that the % completed shows correct value * fix: patch to correct % complete of previous projects * fix: for version-13 * fix: removed patch from v13 Co-authored-by: Marica Co-authored-by: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Co-authored-by: Nabin Hait --- erpnext/patches.txt | 1 + .../v12_0/fix_percent_complete_for_projects.py | 14 ++++++++++++++ erpnext/projects/doctype/task/task.py | 3 +++ 3 files changed, 18 insertions(+) create mode 100644 erpnext/patches/v12_0/fix_percent_complete_for_projects.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 2fb9d7f870..a24f5f76c8 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -713,6 +713,7 @@ erpnext.patches.v13_0.move_payroll_setting_separately_from_hr_settings #22-06-20 erpnext.patches.v13_0.check_is_income_tax_component #22-06-2020 erpnext.patches.v13_0.loyalty_points_entry_for_pos_invoice #22-07-2020 erpnext.patches.v12_0.add_taxjar_integration_field +erpnext.patches.v12_0.fix_percent_complete_for_projects erpnext.patches.v13_0.delete_report_requested_items_to_order erpnext.patches.v12_0.update_item_tax_template_company erpnext.patches.v13_0.move_branch_code_to_bank_account diff --git a/erpnext/patches/v12_0/fix_percent_complete_for_projects.py b/erpnext/patches/v12_0/fix_percent_complete_for_projects.py new file mode 100644 index 0000000000..3622df6bc8 --- /dev/null +++ b/erpnext/patches/v12_0/fix_percent_complete_for_projects.py @@ -0,0 +1,14 @@ +import frappe +from frappe.utils import flt + +def execute(): + for project in frappe.get_all("Project", fields=["name", "percent_complete_method"]): + total = frappe.db.count('Task', dict(project=project.name)) + if project.percent_complete_method == "Task Completion" and total > 0: + completed = frappe.db.sql("""select count(name) from tabTask where + project=%s and status in ('Cancelled', 'Completed')""", project.name)[0][0] + percent_complete = flt(flt(completed) / total * 100, 2) + if project.percent_complete != percent_complete: + frappe.db.set_value("Project", project.name, "percent_complete", percent_complete) + if percent_complete == 100: + frappe.db.set_value("Project", project.name, "status", "Completed") diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py index 4bdda68b69..cf2fd26e57 100755 --- a/erpnext/projects/doctype/task/task.py +++ b/erpnext/projects/doctype/task/task.py @@ -175,6 +175,9 @@ class Task(NestedSet): self.update_nsm_model() + def after_delete(self): + self.update_project() + def update_status(self): if self.status not in ('Cancelled', 'Completed') and self.exp_end_date: from datetime import datetime From 1010feefe023d7908e25c9dd32dd7ba47bdadc34 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Fri, 24 Jul 2020 10:49:04 +0530 Subject: [PATCH 15/16] feat: Patient Progress Page (#22474) * feat: add patient progress page * feat: patient progress sidebar * feat: Patient Progress Charts * feat: set up sidebar links * feat: added heatmap chart for patient interactions * fix: styles * fix: add markers for max score in assessment charts * fix(style): mobile view css * fix: heatmap and percentage chart filters * feat: add time span filters to line charts * fix: make date fields mandatory in healthcare doctypes for better analytics * fix: title and filter styles * fix: handle null state for charts * feat: add Patient Progress Page to desk * feat: add date range filter to all charts * fix: code clean-up * fix: assign roles for Patient Progress Page Co-authored-by: Nabin Hait --- .../desk_page/healthcare/healthcare.json | 4 +- erpnext/healthcare/doctype/patient/patient.py | 12 + .../patient_assessment.json | 5 +- .../doctype/therapy_plan/therapy_plan.py | 3 + .../therapy_session/therapy_session.json | 5 +- .../page/patient_progress/__init__.py | 0 .../patient_progress/patient_progress.css | 165 ++++++ .../patient_progress/patient_progress.html | 68 +++ .../page/patient_progress/patient_progress.js | 531 ++++++++++++++++++ .../patient_progress/patient_progress.json | 33 ++ .../page/patient_progress/patient_progress.py | 197 +++++++ .../patient_progress_sidebar.html | 29 + 12 files changed, 1046 insertions(+), 6 deletions(-) create mode 100644 erpnext/healthcare/page/patient_progress/__init__.py create mode 100644 erpnext/healthcare/page/patient_progress/patient_progress.css create mode 100644 erpnext/healthcare/page/patient_progress/patient_progress.html create mode 100644 erpnext/healthcare/page/patient_progress/patient_progress.js create mode 100644 erpnext/healthcare/page/patient_progress/patient_progress.json create mode 100644 erpnext/healthcare/page/patient_progress/patient_progress.py create mode 100644 erpnext/healthcare/page/patient_progress/patient_progress_sidebar.html diff --git a/erpnext/healthcare/desk_page/healthcare/healthcare.json b/erpnext/healthcare/desk_page/healthcare/healthcare.json index 334b65563b..6546b08db9 100644 --- a/erpnext/healthcare/desk_page/healthcare/healthcare.json +++ b/erpnext/healthcare/desk_page/healthcare/healthcare.json @@ -38,7 +38,7 @@ { "hidden": 0, "label": "Records and History", - "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]" + "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\": \"page\",\n\t\t\"name\": \"patient-progress\",\n\t\t\"label\": \"Patient Progress\"\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]" }, { "hidden": 0, @@ -64,7 +64,7 @@ "idx": 0, "is_standard": 1, "label": "Healthcare", - "modified": "2020-05-28 19:02:28.824995", + "modified": "2020-06-25 23:50:56.951698", "modified_by": "Administrator", "module": "Healthcare", "name": "Healthcare", diff --git a/erpnext/healthcare/doctype/patient/patient.py b/erpnext/healthcare/doctype/patient/patient.py index 30a1e45f0e..63dd8d4793 100644 --- a/erpnext/healthcare/doctype/patient/patient.py +++ b/erpnext/healthcare/doctype/patient/patient.py @@ -172,3 +172,15 @@ def get_patient_detail(patient): if vital_sign: details.update(vital_sign[0]) return details + +def get_timeline_data(doctype, name): + """Return timeline data from medical records""" + return dict(frappe.db.sql(''' + SELECT + unix_timestamp(communication_date), count(*) + FROM + `tabPatient Medical Record` + WHERE + patient=%s + and `communication_date` > date_sub(curdate(), interval 1 year) + GROUP BY communication_date''', name)) diff --git a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.json b/erpnext/healthcare/doctype/patient_assessment/patient_assessment.json index 15c94344e9..eb0021ff75 100644 --- a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.json +++ b/erpnext/healthcare/doctype/patient_assessment/patient_assessment.json @@ -63,7 +63,8 @@ { "fieldname": "assessment_datetime", "fieldtype": "Datetime", - "label": "Assessment Datetime" + "label": "Assessment Datetime", + "reqd": 1 }, { "fieldname": "section_break_7", @@ -139,7 +140,7 @@ ], "is_submittable": 1, "links": [], - "modified": "2020-05-25 14:38:38.302399", + "modified": "2020-06-25 00:25:13.208400", "modified_by": "Administrator", "module": "Healthcare", "name": "Patient Assessment", diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py index c19be17ba8..e0f015f3d7 100644 --- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py +++ b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document +from frappe.utils import today class TherapyPlan(Document): def validate(self): @@ -45,4 +46,6 @@ def make_therapy_session(therapy_plan, patient, therapy_type): therapy_session.rate = therapy_type.rate therapy_session.exercises = therapy_type.exercises + if frappe.flags.in_test: + therapy_session.start_date = today() return therapy_session.as_dict() \ No newline at end of file diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.json b/erpnext/healthcare/doctype/therapy_session/therapy_session.json index c75d9342ef..dc0cafcf9c 100644 --- a/erpnext/healthcare/doctype/therapy_session/therapy_session.json +++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.json @@ -154,7 +154,8 @@ { "fieldname": "start_date", "fieldtype": "Date", - "label": "Start Date" + "label": "Start Date", + "reqd": 1 }, { "fieldname": "start_time", @@ -219,7 +220,7 @@ ], "is_submittable": 1, "links": [], - "modified": "2020-06-29 14:33:34.836594", + "modified": "2020-06-30 10:56:10.354268", "modified_by": "Administrator", "module": "Healthcare", "name": "Therapy Session", diff --git a/erpnext/healthcare/page/patient_progress/__init__.py b/erpnext/healthcare/page/patient_progress/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.css b/erpnext/healthcare/page/patient_progress/patient_progress.css new file mode 100644 index 0000000000..5d85a7487f --- /dev/null +++ b/erpnext/healthcare/page/patient_progress/patient_progress.css @@ -0,0 +1,165 @@ +/* sidebar */ + +.layout-side-section .frappe-control[data-fieldname='patient'] { + max-width: 300px; +} + +.patient-image-container { + margin-top: 17px; +} + +.patient-image { + display: inline-block; + width: 100%; + height: 0; + padding: 50% 0px; + background-size: cover; + background-repeat: no-repeat; + background-position: center center; + border-radius: 4px; +} + +.patient-details { + margin: -5px 5px; +} + +.important-links { + margin: 30px 5px; +} + +.patient-name { + font-size: 20px; +} + +/* heatmap */ + +.heatmap-container { + height: 170px; +} + +.patient-heatmap { + width: 80%; + display: inline-block; +} + +.patient-heatmap .chart-container { + margin-left: 30px; +} + +.patient-heatmap .frappe-chart { + margin-top: 5px; +} + +.patient-heatmap .frappe-chart .chart-legend { + display: none; +} + +.heatmap-container .chart-filter { + position: relative; + top: 5px; + margin-right: 10px; +} + +/* percentage chart */ + +.percentage-chart-container { + height: 130px; +} + +.percentage-chart-container .chart-filter { + position: relative; + top: 5px; + margin-right: 10px; +} + +.therapy-session-percentage-chart .frappe-chart { + position: absolute; + top: 5px; +} + +/* line charts */ + +.date-field .clearfix { + display: none; +} + +.date-field .help-box { + display: none; +} + +.date-field .frappe-control { + margin-bottom: 0px !important; +} + +.date-field .form-group { + margin-bottom: 0px !important; +} + +/* common */ + +text.title { + text-transform: uppercase; + font-size: 11px; + margin-left: 20px; + margin-top: 20px; + display: block; +} + +.chart-filter-search { + margin-left: 35px; + width: 25%; +} + +.chart-column-container { + border-bottom: 1px solid #d1d8dd; + margin: 5px 0; +} + +.line-chart-container .frappe-chart { + margin-top: -20px; +} + +.line-chart-container { + margin-bottom: 20px; +} + +.chart-control { + align-self: center; + display: flex; + flex-direction: row-reverse; + margin-top: -25px; +} + +.chart-control > * { + margin-right: 10px; +} + +/* mobile */ + +@media (max-width: 991px) { + .patient-progress-sidebar { + display: flex; + } + + .percentage-chart-container { + border-top: 1px solid #d1d8dd; + } + + .percentage-chart-container .chart-filter { + position: relative; + top: 12px; + margin-right: 10px; + } + + .patient-progress-sidebar .important-links { + margin: 0; + } + + .patient-progress-sidebar .patient-details { + width: 50%; + } + + .chart-filter-search { + width: 40%; + } +} diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.html b/erpnext/healthcare/page/patient_progress/patient_progress.html new file mode 100644 index 0000000000..c20537ea81 --- /dev/null +++ b/erpnext/healthcare/page/patient_progress/patient_progress.html @@ -0,0 +1,68 @@ +
+
+
+ +
+
+
+ +
+
+ Therapy Progress +
+
+
+ +
+
+
+
+
+
+ +
+
+ Assessment Results +
+
+
+ +
+
+
+
+
+
+ +
+
+ Therapy Type and Assessment Correlation +
+
+
+ +
+
+
+
+
+
+ +
+
+ Assessment Parameter Wise Progress +
+
+
+ +
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.js b/erpnext/healthcare/page/patient_progress/patient_progress.js new file mode 100644 index 0000000000..2410b0ce84 --- /dev/null +++ b/erpnext/healthcare/page/patient_progress/patient_progress.js @@ -0,0 +1,531 @@ +frappe.pages['patient-progress'].on_page_load = function(wrapper) { + + frappe.ui.make_app_page({ + parent: wrapper, + title: __('Patient Progress') + }); + + let patient_progress = new PatientProgress(wrapper); + $(wrapper).bind('show', ()=> { + patient_progress.show(); + }); +}; + +class PatientProgress { + + constructor(wrapper) { + this.wrapper = $(wrapper); + this.page = wrapper.page; + this.sidebar = this.wrapper.find('.layout-side-section'); + this.main_section = this.wrapper.find('.layout-main-section'); + } + + show() { + frappe.breadcrumbs.add('Healthcare'); + this.sidebar.empty(); + + let me = this; + let patient = frappe.ui.form.make_control({ + parent: me.sidebar, + df: { + fieldtype: 'Link', + options: 'Patient', + fieldname: 'patient', + placeholder: __('Select Patient'), + only_select: true, + change: () => { + me.patient_id = ''; + if (me.patient_id != patient.get_value() && patient.get_value()) { + me.start = 0; + me.patient_id = patient.get_value(); + me.make_patient_profile(); + } + } + } + }); + patient.refresh(); + + if (frappe.route_options && !this.patient) { + patient.set_value(frappe.route_options.patient); + this.patient_id = frappe.route_options.patient; + } + + this.sidebar.find('[data-fieldname="patient"]').append('
'); + } + + make_patient_profile() { + this.page.set_title(__('Patient Progress')); + this.main_section.empty().append(frappe.render_template('patient_progress')); + this.render_patient_details(); + this.render_heatmap(); + this.render_percentage_chart('therapy_type', 'Therapy Type Distribution'); + this.create_percentage_chart_filters(); + this.show_therapy_progress(); + this.show_assessment_results(); + this.show_therapy_assessment_correlation(); + this.show_assessment_parameter_progress(); + } + + get_patient_info() { + return frappe.xcall('frappe.client.get', { + doctype: 'Patient', + name: this.patient_id + }).then((patient) => { + if (patient) { + this.patient = patient; + } + }); + } + + get_therapy_sessions_count() { + return frappe.xcall( + 'erpnext.healthcare.page.patient_progress.patient_progress.get_therapy_sessions_count', { + patient: this.patient_id, + } + ).then(data => { + if (data) { + this.total_therapy_sessions = data.total_therapy_sessions; + this.therapy_sessions_this_month = data.therapy_sessions_this_month; + } + }); + } + + render_patient_details() { + this.get_patient_info().then(() => { + this.get_therapy_sessions_count().then(() => { + $('.patient-info').empty().append(frappe.render_template('patient_progress_sidebar', { + patient_image: this.patient.image, + patient_name: this.patient.patient_name, + patient_gender: this.patient.sex, + patient_mobile: this.patient.mobile, + total_therapy_sessions: this.total_therapy_sessions, + therapy_sessions_this_month: this.therapy_sessions_this_month + })); + + this.setup_patient_profile_links(); + }); + }); + } + + setup_patient_profile_links() { + this.wrapper.find('.patient-profile-link').on('click', () => { + frappe.set_route('Form', 'Patient', this.patient_id); + }); + + this.wrapper.find('.therapy-plan-link').on('click', () => { + frappe.route_options = { + 'patient': this.patient_id, + 'docstatus': 1 + }; + frappe.set_route('List', 'Therapy Plan'); + }); + + this.wrapper.find('.patient-history').on('click', () => { + frappe.route_options = { + 'patient': this.patient_id + }; + frappe.set_route('patient_history'); + }); + } + + render_heatmap() { + this.heatmap = new frappe.Chart('.patient-heatmap', { + type: 'heatmap', + countLabel: 'Interactions', + data: {}, + discreteDomains: 0 + }); + this.update_heatmap_data(); + this.create_heatmap_chart_filters(); + } + + update_heatmap_data(date_from) { + frappe.xcall('erpnext.healthcare.page.patient_progress.patient_progress.get_patient_heatmap_data', { + patient: this.patient_id, + date: date_from || frappe.datetime.year_start(), + }).then((data) => { + this.heatmap.update( {dataPoints: data} ); + }); + } + + create_heatmap_chart_filters() { + this.get_patient_info().then(() => { + let filters = [ + { + label: frappe.dashboard_utils.get_year(frappe.datetime.now_date()), + options: frappe.dashboard_utils.get_years_since_creation(this.patient.creation), + action: (selected_item) => { + this.update_heatmap_data(frappe.datetime.obj_to_str(selected_item)); + } + }, + ]; + frappe.dashboard_utils.render_chart_filters(filters, 'chart-filter', '.heatmap-container'); + }); + } + + render_percentage_chart(field, title) { + frappe.xcall( + 'erpnext.healthcare.page.patient_progress.patient_progress.get_therapy_sessions_distribution_data', { + patient: this.patient_id, + field: field + } + ).then(chart => { + if (chart.labels.length) { + this.percentage_chart = new frappe.Chart('.therapy-session-percentage-chart', { + title: title, + type: 'percentage', + data: { + labels: chart.labels, + datasets: chart.datasets + }, + truncateLegends: 1, + barOptions: { + height: 11, + depth: 1 + }, + height: 160, + maxSlices: 8, + colors: ['#5e64ff', '#743ee2', '#ff5858', '#ffa00a', '#feef72', '#28a745', '#98d85b', '#a9a7ac'], + }); + } else { + this.wrapper.find('.percentage-chart-container').hide(); + } + }); + } + + create_percentage_chart_filters() { + let filters = [ + { + label: 'Therapy Type', + options: ['Therapy Type', 'Exercise Type'], + fieldnames: ['therapy_type', 'exercise_type'], + action: (selected_item, fieldname) => { + let title = selected_item + ' Distribution'; + this.render_percentage_chart(fieldname, title); + } + }, + ]; + frappe.dashboard_utils.render_chart_filters(filters, 'chart-filter', '.percentage-chart-container'); + } + + create_time_span_filters(action_method, parent) { + let chart_control = $(parent).find('.chart-control'); + let filters = [ + { + label: 'Last Month', + options: ['Select Date Range', 'Last Week', 'Last Month', 'Last Quarter', 'Last Year'], + action: (selected_item) => { + if (selected_item === 'Select Date Range') { + this.render_date_range_fields(action_method, chart_control); + } else { + // hide date range field if visible + let date_field = $(parent).find('.date-field'); + if (date_field.is(':visible')) { + date_field.hide(); + } + this[action_method](selected_item); + } + } + } + ]; + frappe.dashboard_utils.render_chart_filters(filters, 'chart-filter', chart_control, 1); + } + + render_date_range_fields(action_method, parent) { + let date_field = $(parent).find('.date-field'); + + if (!date_field.length) { + let date_field_wrapper = $( + `
` + ).appendTo(parent); + + let date_range_field = frappe.ui.form.make_control({ + df: { + fieldtype: 'DateRange', + fieldname: 'from_date', + placeholder: 'Date Range', + input_class: 'input-xs', + reqd: 1, + change: () => { + let selected_date_range = date_range_field.get_value(); + if (selected_date_range && selected_date_range.length === 2) { + this[action_method](selected_date_range); + } + } + }, + parent: date_field_wrapper, + render_input: 1 + }); + } else if (!date_field.is(':visible')) { + date_field.show(); + } + } + + show_therapy_progress() { + let me = this; + let therapy_type = frappe.ui.form.make_control({ + parent: $('.therapy-type-search'), + df: { + fieldtype: 'Link', + options: 'Therapy Type', + fieldname: 'therapy_type', + placeholder: __('Select Therapy Type'), + only_select: true, + change: () => { + if (me.therapy_type != therapy_type.get_value() && therapy_type.get_value()) { + me.therapy_type = therapy_type.get_value(); + me.render_therapy_progress_chart(); + } + } + } + }); + therapy_type.refresh(); + this.create_time_span_filters('render_therapy_progress_chart', '.therapy-progress'); + } + + render_therapy_progress_chart(time_span='Last Month') { + if (!this.therapy_type) return; + + frappe.xcall( + 'erpnext.healthcare.page.patient_progress.patient_progress.get_therapy_progress_data', { + patient: this.patient_id, + therapy_type: this.therapy_type, + time_span: time_span + } + ).then(chart => { + let data = { + labels: chart.labels, + datasets: chart.datasets + } + let parent = '.therapy-progress-line-chart'; + if (!chart.labels.length) { + this.show_null_state(parent); + } else { + if (!this.therapy_line_chart) { + this.therapy_line_chart = new frappe.Chart(parent, { + type: 'axis-mixed', + height: 250, + data: data, + lineOptions: { + regionFill: 1 + }, + axisOptions: { + xIsSeries: 1 + }, + }); + } else { + $(parent).find('.chart-container').show(); + $(parent).find('.chart-empty-state').hide(); + this.therapy_line_chart.update(data); + } + } + }); + } + + show_assessment_results() { + let me = this; + let assessment_template = frappe.ui.form.make_control({ + parent: $('.assessment-template-search'), + df: { + fieldtype: 'Link', + options: 'Patient Assessment Template', + fieldname: 'assessment_template', + placeholder: __('Select Assessment Template'), + only_select: true, + change: () => { + if (me.assessment_template != assessment_template.get_value() && assessment_template.get_value()) { + me.assessment_template = assessment_template.get_value(); + me.render_assessment_result_chart(); + } + } + } + }); + assessment_template.refresh(); + this.create_time_span_filters('render_assessment_result_chart', '.assessment-results'); + } + + render_assessment_result_chart(time_span='Last Month') { + if (!this.assessment_template) return; + + frappe.xcall( + 'erpnext.healthcare.page.patient_progress.patient_progress.get_patient_assessment_data', { + patient: this.patient_id, + assessment_template: this.assessment_template, + time_span: time_span + } + ).then(chart => { + let data = { + labels: chart.labels, + datasets: chart.datasets, + yMarkers: [ + { label: 'Max Score', value: chart.max_score } + ], + } + let parent = '.assessment-results-line-chart'; + if (!chart.labels.length) { + this.show_null_state(parent); + } else { + if (!this.assessment_line_chart) { + this.assessment_line_chart = new frappe.Chart(parent, { + type: 'axis-mixed', + height: 250, + data: data, + lineOptions: { + regionFill: 1 + }, + axisOptions: { + xIsSeries: 1 + }, + tooltipOptions: { + formatTooltipY: d => d + __(' out of ') + chart.max_score + } + }); + } else { + $(parent).find('.chart-container').show(); + $(parent).find('.chart-empty-state').hide(); + this.assessment_line_chart.update(data); + } + } + }); + } + + show_therapy_assessment_correlation() { + let me = this; + let assessment = frappe.ui.form.make_control({ + parent: $('.assessment-correlation-template-search'), + df: { + fieldtype: 'Link', + options: 'Patient Assessment Template', + fieldname: 'assessment', + placeholder: __('Select Assessment Template'), + only_select: true, + change: () => { + if (me.assessment != assessment.get_value() && assessment.get_value()) { + me.assessment = assessment.get_value(); + me.render_therapy_assessment_correlation_chart(); + } + } + } + }); + assessment.refresh(); + this.create_time_span_filters('render_therapy_assessment_correlation_chart', '.therapy-assessment-correlation'); + } + + render_therapy_assessment_correlation_chart(time_span='Last Month') { + if (!this.assessment) return; + + frappe.xcall( + 'erpnext.healthcare.page.patient_progress.patient_progress.get_therapy_assessment_correlation_data', { + patient: this.patient_id, + assessment_template: this.assessment, + time_span: time_span + } + ).then(chart => { + let data = { + labels: chart.labels, + datasets: chart.datasets, + yMarkers: [ + { label: 'Max Score', value: chart.max_score } + ], + } + let parent = '.therapy-assessment-correlation-chart'; + if (!chart.labels.length) { + this.show_null_state(parent); + } else { + if (!this.correlation_chart) { + this.correlation_chart = new frappe.Chart(parent, { + type: 'axis-mixed', + height: 300, + data: data, + axisOptions: { + xIsSeries: 1 + } + }); + } else { + $(parent).find('.chart-container').show(); + $(parent).find('.chart-empty-state').hide(); + this.correlation_chart.update(data); + } + } + }); + } + + show_assessment_parameter_progress() { + let me = this; + let parameter = frappe.ui.form.make_control({ + parent: $('.assessment-parameter-search'), + df: { + fieldtype: 'Link', + options: 'Patient Assessment Parameter', + fieldname: 'assessment', + placeholder: __('Select Assessment Parameter'), + only_select: true, + change: () => { + if (me.parameter != parameter.get_value() && parameter.get_value()) { + me.parameter = parameter.get_value(); + me.render_assessment_parameter_progress_chart(); + } + } + } + }); + parameter.refresh(); + this.create_time_span_filters('render_assessment_parameter_progress_chart', '.assessment-parameter-progress'); + } + + render_assessment_parameter_progress_chart(time_span='Last Month') { + if (!this.parameter) return; + + frappe.xcall( + 'erpnext.healthcare.page.patient_progress.patient_progress.get_assessment_parameter_data', { + patient: this.patient_id, + parameter: this.parameter, + time_span: time_span + } + ).then(chart => { + let data = { + labels: chart.labels, + datasets: chart.datasets + } + let parent = '.assessment-parameter-progress-chart'; + if (!chart.labels.length) { + this.show_null_state(parent); + } else { + if (!this.parameter_chart) { + this.parameter_chart = new frappe.Chart(parent, { + type: 'line', + height: 250, + data: data, + lineOptions: { + regionFill: 1 + }, + axisOptions: { + xIsSeries: 1 + }, + tooltipOptions: { + formatTooltipY: d => d + '%' + } + }); + } else { + $(parent).find('.chart-container').show(); + $(parent).find('.chart-empty-state').hide(); + this.parameter_chart.update(data); + } + } + }); + } + + show_null_state(parent) { + let null_state = $(parent).find('.chart-empty-state'); + if (null_state.length) { + $(null_state).show(); + } else { + null_state = $( + `
${__( + "No Data..." + )}
` + ); + $(parent).append(null_state); + } + $(parent).find('.chart-container').hide(); + } +} \ No newline at end of file diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.json b/erpnext/healthcare/page/patient_progress/patient_progress.json new file mode 100644 index 0000000000..0175cb9c45 --- /dev/null +++ b/erpnext/healthcare/page/patient_progress/patient_progress.json @@ -0,0 +1,33 @@ +{ + "content": null, + "creation": "2020-06-12 15:46:23.111928", + "docstatus": 0, + "doctype": "Page", + "idx": 0, + "modified": "2020-07-23 21:45:45.540055", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "patient-progress", + "owner": "Administrator", + "page_name": "patient-progress", + "restrict_to_domain": "Healthcare", + "roles": [ + { + "role": "Healthcare Administrator" + }, + { + "role": "Physician" + }, + { + "role": "Patient" + }, + { + "role": "System Manager" + } + ], + "script": null, + "standard": "Yes", + "style": null, + "system_page": 0, + "title": "Patient Progress" +} \ No newline at end of file diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.py b/erpnext/healthcare/page/patient_progress/patient_progress.py new file mode 100644 index 0000000000..a04fb2b592 --- /dev/null +++ b/erpnext/healthcare/page/patient_progress/patient_progress.py @@ -0,0 +1,197 @@ +import frappe +from datetime import datetime +from frappe import _ +from frappe.utils import getdate, get_timespan_date_range +import json + +@frappe.whitelist() +def get_therapy_sessions_count(patient): + total = frappe.db.count('Therapy Session', filters={ + 'docstatus': 1, + 'patient': patient + }) + + month_start = datetime.today().replace(day=1) + this_month = frappe.db.count('Therapy Session', filters={ + 'creation': ['>', month_start], + 'docstatus': 1, + 'patient': patient + }) + + return { + 'total_therapy_sessions': total, + 'therapy_sessions_this_month': this_month + } + + +@frappe.whitelist() +def get_patient_heatmap_data(patient, date): + return dict(frappe.db.sql(""" + SELECT + unix_timestamp(communication_date), count(*) + FROM + `tabPatient Medical Record` + WHERE + communication_date > subdate(%(date)s, interval 1 year) and + communication_date < subdate(%(date)s, interval -1 year) and + patient = %(patient)s + GROUP BY communication_date + ORDER BY communication_date asc""", {'date': date, 'patient': patient})) + + +@frappe.whitelist() +def get_therapy_sessions_distribution_data(patient, field): + if field == 'therapy_type': + result = frappe.db.get_all('Therapy Session', + filters = {'patient': patient, 'docstatus': 1}, + group_by = field, + order_by = field, + fields = [field, 'count(*)'], + as_list = True) + + elif field == 'exercise_type': + data = frappe.db.get_all('Therapy Session', filters={ + 'docstatus': 1, + 'patient': patient + }, as_list=True) + therapy_sessions = [entry[0] for entry in data] + + result = frappe.db.get_all('Exercise', + filters = { + 'parenttype': 'Therapy Session', + 'parent': ['in', therapy_sessions], + 'docstatus': 1 + }, + group_by = field, + order_by = field, + fields = [field, 'count(*)'], + as_list = True) + + return { + 'labels': [r[0] for r in result if r[0] != None], + 'datasets': [{ + 'values': [r[1] for r in result] + }] + } + + +@frappe.whitelist() +def get_therapy_progress_data(patient, therapy_type, time_span): + date_range = get_date_range(time_span) + query_values = {'from_date': date_range[0], 'to_date': date_range[1], 'therapy_type': therapy_type, 'patient': patient} + result = frappe.db.sql(""" + SELECT + start_date, total_counts_targeted, total_counts_completed + FROM + `tabTherapy Session` + WHERE + start_date BETWEEN %(from_date)s AND %(to_date)s and + docstatus = 1 and + therapy_type = %(therapy_type)s and + patient = %(patient)s + ORDER BY start_date""", query_values, as_list=1) + + return { + 'labels': [r[0] for r in result if r[0] != None], + 'datasets': [ + { 'name': _('Targetted'), 'values': [r[1] for r in result if r[0] != None] }, + { 'name': _('Completed'), 'values': [r[2] for r in result if r[0] != None] } + ] + } + +@frappe.whitelist() +def get_patient_assessment_data(patient, assessment_template, time_span): + date_range = get_date_range(time_span) + query_values = {'from_date': date_range[0], 'to_date': date_range[1], 'assessment_template': assessment_template, 'patient': patient} + result = frappe.db.sql(""" + SELECT + assessment_datetime, total_score, total_score_obtained + FROM + `tabPatient Assessment` + WHERE + DATE(assessment_datetime) BETWEEN %(from_date)s AND %(to_date)s and + docstatus = 1 and + assessment_template = %(assessment_template)s and + patient = %(patient)s + ORDER BY assessment_datetime""", query_values, as_list=1) + + return { + 'labels': [getdate(r[0]) for r in result if r[0] != None], + 'datasets': [ + { 'name': _('Score Obtained'), 'values': [r[2] for r in result if r[0] != None] } + ], + 'max_score': result[0][1] if result else None + } + +@frappe.whitelist() +def get_therapy_assessment_correlation_data(patient, assessment_template, time_span): + date_range = get_date_range(time_span) + query_values = {'from_date': date_range[0], 'to_date': date_range[1], 'assessment': assessment_template, 'patient': patient} + result = frappe.db.sql(""" + SELECT + therapy.therapy_type, count(*), avg(assessment.total_score_obtained), total_score + FROM + `tabPatient Assessment` assessment INNER JOIN `tabTherapy Session` therapy + ON + assessment.therapy_session = therapy.name + WHERE + DATE(assessment.assessment_datetime) BETWEEN %(from_date)s AND %(to_date)s and + assessment.docstatus = 1 and + assessment.patient = %(patient)s and + assessment.assessment_template = %(assessment)s + GROUP BY therapy.therapy_type + """, query_values, as_list=1) + + return { + 'labels': [r[0] for r in result if r[0] != None], + 'datasets': [ + { 'name': _('Sessions'), 'chartType': 'bar', 'values': [r[1] for r in result if r[0] != None] }, + { 'name': _('Average Score'), 'chartType': 'line', 'values': [round(r[2], 2) for r in result if r[0] != None] } + ], + 'max_score': result[0][1] if result else None + } + +@frappe.whitelist() +def get_assessment_parameter_data(patient, parameter, time_span): + date_range = get_date_range(time_span) + query_values = {'from_date': date_range[0], 'to_date': date_range[1], 'parameter': parameter, 'patient': patient} + results = frappe.db.sql(""" + SELECT + assessment.assessment_datetime, + sheet.score, + template.scale_max + FROM + `tabPatient Assessment Sheet` sheet + INNER JOIN `tabPatient Assessment` assessment + ON sheet.parent = assessment.name + INNER JOIN `tabPatient Assessment Template` template + ON template.name = assessment.assessment_template + WHERE + DATE(assessment.assessment_datetime) BETWEEN %(from_date)s AND %(to_date)s and + assessment.docstatus = 1 and + sheet.parameter = %(parameter)s and + assessment.patient = %(patient)s + ORDER BY + assessment.assessment_datetime asc + """, query_values, as_list=1) + + score_percentages = [] + for r in results: + if r[2] != 0 and r[0] != None: + score = round((int(r[1]) / int(r[2])) * 100, 2) + score_percentages.append(score) + + return { + 'labels': [getdate(r[0]) for r in results if r[0] != None], + 'datasets': [ + { 'name': _('Score'), 'values': score_percentages } + ] + } + +def get_date_range(time_span): + try: + time_span = json.loads(time_span) + return time_span + except json.decoder.JSONDecodeError: + return get_timespan_date_range(time_span.lower()) + diff --git a/erpnext/healthcare/page/patient_progress/patient_progress_sidebar.html b/erpnext/healthcare/page/patient_progress/patient_progress_sidebar.html new file mode 100644 index 0000000000..cd62dd3903 --- /dev/null +++ b/erpnext/healthcare/page/patient_progress/patient_progress_sidebar.html @@ -0,0 +1,29 @@ +
+
+ {% if patient_image %} +
+ {% endif %} +
+
+ {% if patient_name %} +

{{patient_name}}

+ {% endif %} + {% if patient_gender %} +

{%=__("Gender: ") %} {{patient_gender}}

+ {% endif %} + {% if patient_mobile %} +

{%=__("Contact: ") %} {{patient_mobile}}

+ {% endif %} + {% if total_therapy_sessions %} +

{%=__("Total Therapy Sessions: ") %} {{total_therapy_sessions}}

+ {% endif %} + {% if therapy_sessions_this_month %} +

{%=__("Monthly Therapy Sessions: ") %} {{therapy_sessions_this_month}}

+ {% endif %} +
+ +
\ No newline at end of file From 8721530b4b80a1daea0c92d3410d44ac654fd31c Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Fri, 24 Jul 2020 17:19:56 +0530 Subject: [PATCH 16/16] fix(payment-request): do not set guest as administrator (#22801) --- erpnext/accounts/doctype/payment_request/payment_request.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 287e00f70f..e93ec951fb 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -140,9 +140,6 @@ class PaymentRequest(Document): }) def set_as_paid(self): - if frappe.session.user == "Guest": - frappe.set_user("Administrator") - payment_entry = self.create_payment_entry() self.make_invoice() @@ -254,7 +251,7 @@ class PaymentRequest(Document): if status in ["Authorized", "Completed"]: redirect_to = None - self.run_method("set_as_paid") + self.set_as_paid() # if shopping cart enabled and in session if (shopping_cart_settings.enabled and hasattr(frappe.local, "session")