From 366bce678f0b3754dfa00202530f135178fc78a9 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 6 May 2020 02:38:27 +0530 Subject: [PATCH] added onboarding for manufacturing --- erpnext/manufacturing/dashboard_fixtures.py | 216 +++++++++++++++ .../manufacturing/manufacturing.json | 43 ++- .../doctype/work_order/work_order.json | 2 +- .../manufacturing/manufacturing.json | 54 ++++ .../create_bom/create_bom.json | 16 ++ .../create_product/create_product.json | 16 ++ .../introduction_to_manufacturing.json | 17 ++ .../onboarding_step/operation/operation.json | 15 ++ .../onboarding_step/warehouse/warehouse.json | 15 ++ .../work_order/work_order.json | 15 ++ .../workstation/workstation.json | 15 ++ .../downtime_analysis/downtime_analysis.py | 3 +- .../job_card_summary/job_card_summary.py | 33 +-- .../production_analytics.py | 12 +- .../quality_inspection_summary.py | 3 +- .../work_order_summary/work_order_summary.js | 7 + .../work_order_summary/work_order_summary.py | 107 +++++++- .../update_actual_start_and_end_date_in_wo.py | 5 +- .../setup_wizard/data/dashboard_charts.py | 247 ------------------ 19 files changed, 545 insertions(+), 296 deletions(-) create mode 100644 erpnext/manufacturing/dashboard_fixtures.py create mode 100644 erpnext/manufacturing/onboarding/manufacturing/manufacturing.json create mode 100644 erpnext/manufacturing/onboarding_step/create_bom/create_bom.json create mode 100644 erpnext/manufacturing/onboarding_step/create_product/create_product.json create mode 100644 erpnext/manufacturing/onboarding_step/introduction_to_manufacturing/introduction_to_manufacturing.json create mode 100644 erpnext/manufacturing/onboarding_step/operation/operation.json create mode 100644 erpnext/manufacturing/onboarding_step/warehouse/warehouse.json create mode 100644 erpnext/manufacturing/onboarding_step/work_order/work_order.json create mode 100644 erpnext/manufacturing/onboarding_step/workstation/workstation.json delete mode 100644 erpnext/setup/setup_wizard/data/dashboard_charts.py diff --git a/erpnext/manufacturing/dashboard_fixtures.py b/erpnext/manufacturing/dashboard_fixtures.py new file mode 100644 index 0000000000..de3775f52c --- /dev/null +++ b/erpnext/manufacturing/dashboard_fixtures.py @@ -0,0 +1,216 @@ +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +import frappe, erpnext, json +from frappe import _ + +def get_data(): + return frappe._dict({ + "dashboards": get_dashboards(), + "charts": get_charts(), + "number_cards": get_number_cards(), + }) + +def get_dashboards(): + return [{ + "name": "Manufacturing Dashboard", + "dashboard_name": "Manufacturing Dashboard", + "charts": [ + { "chart": "Produced Quantity", "width": "Half" }, + { "chart": "Completed Operation", "width": "Half" }, + { "chart": "Work Order Analysis", "width": "Half" }, + { "chart": "Quality Inspection Analysis", "width": "Half" }, + { "chart": "Pending Work Order", "width": "Half" }, + { "chart": "Last Month Downtime Analysis", "width": "Half" }, + { "chart": "Work Order Qty Analysis", "width": "Full" }, + { "chart": "Job Card Analysis", "width": "Full" } + ], + "cards": [ + { "card": "Total Work Order" }, + { "card": "Completed Work Order" }, + { "card": "Ongoing Job Card" }, + { "card": "Total Quality Inspection"} + ] + }] + +def get_charts(): + company = erpnext.get_default_company() + + if not company: + company = frappe.db.get_value("Company", {"is_group": 0}, "name") + + return [{ + "doctype": "Dashboard Chart", + "based_on": "creation", + "time_interval": "Yearly", + "chart_type": "Sum", + "chart_name": "Produced Quantity", + "document_type": "Work Order", + "filters_json": json.dumps({}), + "group_by_type": "Count", + "time_interval": "Quarterly", + "timespan": "Last Year", + "owner": "Administrator", + "type": "Line", + "value_based_on": "qty", + "is_public": 1, + "timeseries": 1 + }, { + "doctype": "Dashboard Chart", + "based_on": "creation", + "time_interval": "Yearly", + "chart_type": "Sum", + "chart_name": "Completed Operation", + "document_type": "Work Order Operation", + "filters_json": json.dumps({}), + "group_by_type": "Count", + "time_interval": "Quarterly", + "timespan": "Last Year", + "owner": "Administrator", + "type": "Line", + "value_based_on": "completed_qty", + "is_public": 1, + "timeseries": 1 + }, { + "doctype": "Dashboard Chart", + "time_interval": "Yearly", + "chart_type": "Report", + "chart_name": "Work Order Analysis", + "timespan": "Last Year", + "report_name": "Work Order Summary", + "owner": "Administrator", + "filters_json": json.dumps({"company": company, "charts_based_on": "Status"}), + "type": "Donut", + "is_public": 1, + "is_custom": 1, + "custom_options": json.dumps({ + "axisOptions": { + "shortenYAxisNumbers": 1 + }, + "height": 300 + }), + }, { + "doctype": "Dashboard Chart", + "time_interval": "Yearly", + "chart_type": "Report", + "chart_name": "Quality Inspection Analysis", + "timespan": "Last Year", + "report_name": "Quality Inspection Summary", + "owner": "Administrator", + "filters_json": json.dumps({}), + "type": "Donut", + "is_public": 1, + "is_custom": 1, + "custom_options": json.dumps({ + "axisOptions": { + "shortenYAxisNumbers": 1 + }, + "height": 300 + }), + }, { + "doctype": "Dashboard Chart", + "time_interval": "Yearly", + "chart_type": "Report", + "chart_name": "Pending Work Order", + "timespan": "Last Year", + "report_name": "Work Order Summary", + "filters_json": json.dumps({"company": company, "charts_based_on": "Age"}), + "owner": "Administrator", + "type": "Donut", + "is_public": 1, + "is_custom": 1, + "custom_options": json.dumps({ + "axisOptions": { + "shortenYAxisNumbers": 1 + }, + "height": 300 + }), + }, { + "doctype": "Dashboard Chart", + "time_interval": "Yearly", + "chart_type": "Report", + "chart_name": "Last Month Downtime Analysis", + "timespan": "Last Year", + "filters_json": json.dumps({}), + "report_name": "Downtime Analysis", + "owner": "Administrator", + "is_public": 1, + "is_custom": 1, + "type": "Bar" + }, { + "doctype": "Dashboard Chart", + "time_interval": "Yearly", + "chart_type": "Report", + "chart_name": _("Work Order Qty Analysis"), + "timespan": "Last Year", + "report_name": "Work Order Summary", + "filters_json": json.dumps({"company": company, "charts_based_on": "Quantity"}), + "owner": "Administrator", + "type": "Bar", + "is_public": 1, + "is_custom": 1, + "custom_options": json.dumps({ + "barOptions": { "stacked": 1 } + }), + }, { + "doctype": "Dashboard Chart", + "time_interval": "Yearly", + "chart_type": "Report", + "chart_name": "Job Card Analysis", + "timespan": "Last Year", + "report_name": "Job Card Summary", + "owner": "Administrator", + "is_public": 1, + "is_custom": 1, + "filters_json": json.dumps({"company": company, "range":"Monthly"}), + "custom_options": json.dumps({ + "barOptions": { "stacked": 1 } + }), + "type": "Bar" + }] + +def get_number_cards(): + return [{ + "doctype": "Number Card", + "document_type": "Work Order", + "name": "Total Work Order", + "filters_json": json.dumps([]), + "function": "Count", + "is_public": 1, + "label": _("Total Work Order"), + "show_percentage_stats": 1, + "stats_time_interval": "Daily" + }, + { + "doctype": "Number Card", + "document_type": "Work Order", + "name": "Completed Work Order", + "filters_json": json.dumps([['Work Order', 'status','=','Completed', False]]), + "function": "Count", + "is_public": 1, + "label": _("Completed Work Order"), + "show_percentage_stats": 1, + "stats_time_interval": "Daily" + }, + { + "doctype": "Number Card", + "document_type": "Job Card", + "name": "Ongoing Job Card", + "filters_json": json.dumps([['Job Card', 'status','!=','Completed', False]]), + "function": "Count", + "is_public": 1, + "label": _("Ongoing Job Card"), + "show_percentage_stats": 1, + "stats_time_interval": "Daily" + }, + { + "doctype": "Number Card", + "document_type": "Quality Inspection", + "name": "Total Quality Inspection", + "filters_json": json.dumps([]), + "function": "Count", + "is_public": 1, + "label": _("Total Quality Inspection"), + "show_percentage_stats": 1, + "stats_time_interval": "Daily" + }] \ No newline at end of file diff --git a/erpnext/manufacturing/desk_page/manufacturing/manufacturing.json b/erpnext/manufacturing/desk_page/manufacturing/manufacturing.json index 0464b763c0..f6bbf3db85 100644 --- a/erpnext/manufacturing/desk_page/manufacturing/manufacturing.json +++ b/erpnext/manufacturing/desk_page/manufacturing/manufacturing.json @@ -3,7 +3,7 @@ { "hidden": 0, "label": "Production", - "links": "[\n {\n \"dependencies\": [\n \"Item\",\n \"BOM\"\n ],\n \"description\": \"Orders released for production.\",\n \"label\": \"Work Order\",\n \"name\": \"Work Order\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"BOM\"\n ],\n \"description\": \"Generate Material Requests (MRP) and Work Orders.\",\n \"label\": \"Production Plan\",\n \"name\": \"Production Plan\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Stock Entry\",\n \"name\": \"Stock Entry\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Job Card\",\n \"name\": \"Job Card\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Downtime Entry\",\n \"name\": \"Downtime Entry\",\n \"type\": \"doctype\"\n }\n]" + "links": "[\n {\n \"dependencies\": [\n \"Item\",\n \"BOM\"\n ],\n \"description\": \"Orders released for production.\",\n \"label\": \"Work Order\",\n \"name\": \"Work Order\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"BOM\"\n ],\n \"description\": \"Generate Material Requests (MRP) and Work Orders.\",\n \"label\": \"Production Plan\",\n \"name\": \"Production Plan\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Stock Entry\",\n \"name\": \"Stock Entry\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Activity Type\"\n ],\n \"description\": \"Time Sheet for manufacturing.\",\n \"label\": \"Timesheet\",\n \"name\": \"Timesheet\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Job Card\",\n \"name\": \"Job Card\",\n \"type\": \"doctype\"\n }\n]" }, { "hidden": 0, @@ -13,7 +13,7 @@ { "hidden": 0, "label": "Reports", - "links": "[\n {\n \"dependencies\": [\n \"Work Order\"\n ],\n \"doctype\": \"Work Order\",\n \"is_query_report\": true,\n \"label\": \"Work Order Summary\",\n \"name\": \"Work Order Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Work Order\"\n ],\n \"doctype\": \"Work Order\",\n \"is_query_report\": true,\n \"label\": \"Issued Items Against Work Order\",\n \"name\": \"Issued Items Against Work Order\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Work Order\"\n ],\n \"doctype\": \"Work Order\",\n \"is_query_report\": true,\n \"label\": \"Production Analytics\",\n \"name\": \"Production Analytics\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Quality Inspection\"\n ],\n \"doctype\": \"Quality Inspection\",\n \"is_query_report\": true,\n \"label\": \"Quality Inspection Summary\",\n \"name\": \"Quality Inspection Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Downtime Entry\"\n ],\n \"doctype\": \"Downtime Entry\",\n \"is_query_report\": true,\n \"label\": \"Downtime Analysis\",\n \"name\": \"Downtime Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Job Card\"\n ],\n \"doctype\": \"Job Card\",\n \"is_query_report\": true,\n \"label\": \"Job Card Summary\",\n \"name\": \"Job Card Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"BOM\"\n ],\n \"doctype\": \"BOM\",\n \"is_query_report\": true,\n \"label\": \"BOM Search\",\n \"name\": \"BOM Search\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"BOM\"\n ],\n \"doctype\": \"BOM\",\n \"is_query_report\": true,\n \"label\": \"BOM Stock Report\",\n \"name\": \"BOM Stock Report\",\n \"type\": \"report\"\n }\n]" + "links": "[{\n\t\"dependencies\": [\"Work Order\"],\n\t\"name\": \"Work Order Summary\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"Work Order\",\n\t\"label\": \"Work Order Summary\"\n}, {\n\t\"dependencies\": [\"Work Order\"],\n\t\"name\": \"Production Analytics\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"Work Order\",\n\t\"label\": \"Production Analytics\"\n}, {\n\t\"dependencies\": [\"Quality Inspection\"],\n\t\"name\": \"Quality Inspection Summary\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"Quality Inspection\",\n\t\"label\": \"Quality Inspection Summary\"\n}, {\n\t\"dependencies\": [\"Downtime Entry\"],\n\t\"name\": \"Downtime Analysis\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"Downtime Entry\",\n\t\"label\": \"Downtime Analysis\"\n}, {\n\t\"dependencies\": [\"Job Card\"],\n\t\"name\": \"Job Card Summary\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"Job Card\",\n\t\"label\": \"Job Card Summary\"\n}, {\n\t\"dependencies\": [\"BOM\"],\n\t\"name\": \"BOM Search\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"BOM\",\n\t\"label\": \"BOM Search\"\n}, {\n\t\"dependencies\": [\"BOM\"],\n\t\"name\": \"BOM Stock Report\",\n\t\"is_query_report\": true,\n\t\"type\": \"report\",\n\t\"doctype\": \"BOM\",\n\t\"label\": \"BOM Stock Report\"\n}]" }, { "hidden": 0, @@ -32,12 +32,7 @@ } ], "category": "Domains", - "charts": [ - { - "chart_name": "Production Analysis", - "label": "Production Analysis" - } - ], + "charts": [], "creation": "2020-03-02 17:11:37.032604", "developer_mode_only": 0, "disable_user_customization": 0, @@ -47,29 +42,59 @@ "idx": 0, "is_standard": 1, "label": "Manufacturing", - "modified": "2020-04-27 00:17:26.323677", + "modified": "2020-05-14 15:06:45.963942", "modified_by": "Administrator", "module": "Manufacturing", "name": "Manufacturing", + "onboarding": "Manufacturing", "owner": "Administrator", "pin_to_bottom": 0, "pin_to_top": 0, "restrict_to_domain": "Manufacturing", "shortcuts": [ { + "format": "{} Active", "label": "Item", "link_to": "Item", + "restrict_to_domain": "Manufacturing", + "stats_filter": "{\n \"disabled\": 0\n}", "type": "DocType" }, { + "format": "{} Active", "label": "BOM", "link_to": "BOM", + "restrict_to_domain": "Manufacturing", + "stats_filter": "{\n \"is_active\": 1\n}", "type": "DocType" }, { + "format": "{} Open", "label": "Work Order", "link_to": "Work Order", + "restrict_to_domain": "Manufacturing", + "stats_filter": "{ \"status\": \n (\n \"in\", [\"Draft\", \"Not Started\", \"In Process\"]\n )\n}", "type": "DocType" + }, + { + "format": "{} Open", + "label": "Production Plan", + "link_to": "Production Plan", + "restrict_to_domain": "Manufacturing", + "stats_filter": "{ \"status\": \n (\n \"!=\", \"Completed\"\n )\n}", + "type": "DocType" + }, + { + "label": "Work Order Summary", + "link_to": "Work Order Summary", + "restrict_to_domain": "Manufacturing", + "type": "Report" + }, + { + "label": "BOM Stock Report", + "link_to": "BOM Stock Report", + "restrict_to_domain": "Manufacturing", + "type": "Report" } ] } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/work_order/work_order.json b/erpnext/manufacturing/doctype/work_order/work_order.json index 8be22875a3..585a09db2b 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.json +++ b/erpnext/manufacturing/doctype/work_order/work_order.json @@ -496,7 +496,7 @@ "image_field": "image", "is_submittable": 1, "links": [], - "modified": "2020-04-24 19:32:43.323054", + "modified": "2020-05-05 19:32:43.323054", "modified_by": "Administrator", "module": "Manufacturing", "name": "Work Order", diff --git a/erpnext/manufacturing/onboarding/manufacturing/manufacturing.json b/erpnext/manufacturing/onboarding/manufacturing/manufacturing.json new file mode 100644 index 0000000000..50584e19ca --- /dev/null +++ b/erpnext/manufacturing/onboarding/manufacturing/manufacturing.json @@ -0,0 +1,54 @@ +{ + "allow_roles": [ + { + "role": "Manufacturing User" + }, + { + "role": "Manufacturing Manager" + }, + { + "role": "Item Manager" + }, + { + "role": "Stock User" + } + ], + "creation": "2020-05-05 16:37:08.238935", + "docstatus": 0, + "doctype": "Onboarding", + "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/manufacturing", + "idx": 0, + "is_complete": 0, + "modified": "2020-05-12 16:22:07.050224", + "modified_by": "Administrator", + "module": "Manufacturing", + "name": "Manufacturing", + "owner": "Administrator", + "steps": [ + { + "step": "Introduction to Manufacturing" + }, + { + "step": "Warehouse" + }, + { + "step": "Workstation" + }, + { + "step": "Operation" + }, + { + "step": "Create Product" + }, + { + "step": "Create BOM" + }, + { + "step": "Work Order" + } + ], + "subtitle": "Products, Raw Materials, BOM, Work Order and more.", + "success_message": "Manufacturing module is all setup!", + "title": "Let's Setup Manufacturing Module", + "user_can_dismiss": 1 +} \ No newline at end of file diff --git a/erpnext/manufacturing/onboarding_step/create_bom/create_bom.json b/erpnext/manufacturing/onboarding_step/create_bom/create_bom.json new file mode 100644 index 0000000000..969c2fa5fe --- /dev/null +++ b/erpnext/manufacturing/onboarding_step/create_bom/create_bom.json @@ -0,0 +1,16 @@ +{ + "action": "Create Entry", + "creation": "2020-05-05 16:41:20.239696", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 1, + "is_skipped": 0, + "modified": "2020-05-05 16:41:20.239696", + "modified_by": "Administrator", + "name": "Create BOM", + "owner": "Administrator", + "reference_document": "BOM", + "title": "Create BOM" +} \ No newline at end of file diff --git a/erpnext/manufacturing/onboarding_step/create_product/create_product.json b/erpnext/manufacturing/onboarding_step/create_product/create_product.json new file mode 100644 index 0000000000..082f31ed6e --- /dev/null +++ b/erpnext/manufacturing/onboarding_step/create_product/create_product.json @@ -0,0 +1,16 @@ +{ + "action": "Create Entry", + "creation": "2020-05-05 16:42:31.476275", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 1, + "is_skipped": 0, + "modified": "2020-05-05 16:42:31.476275", + "modified_by": "Administrator", + "name": "Create Product", + "owner": "Administrator", + "reference_document": "Item", + "title": "Create Product" +} \ No newline at end of file diff --git a/erpnext/manufacturing/onboarding_step/introduction_to_manufacturing/introduction_to_manufacturing.json b/erpnext/manufacturing/onboarding_step/introduction_to_manufacturing/introduction_to_manufacturing.json new file mode 100644 index 0000000000..6e5c3a9f45 --- /dev/null +++ b/erpnext/manufacturing/onboarding_step/introduction_to_manufacturing/introduction_to_manufacturing.json @@ -0,0 +1,17 @@ +{ + "action": "Update Settings", + "creation": "2020-05-05 16:40:23.676406", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 0, + "is_skipped": 0, + "modified": "2020-05-05 16:40:23.676406", + "modified_by": "Administrator", + "name": "Introduction to Manufacturing", + "owner": "Administrator", + "reference_document": "Manufacturing Settings", + "title": "Manufacturing Settings", + "video_url": "https://www.youtube.com/watch?v=UVGfzwOOZC4" +} \ No newline at end of file diff --git a/erpnext/manufacturing/onboarding_step/operation/operation.json b/erpnext/manufacturing/onboarding_step/operation/operation.json new file mode 100644 index 0000000000..6f84db13ec --- /dev/null +++ b/erpnext/manufacturing/onboarding_step/operation/operation.json @@ -0,0 +1,15 @@ +{ + "action": "Create Entry", + "creation": "2020-05-12 16:15:31.706756", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 0, + "is_skipped": 0, + "modified": "2020-05-12 16:17:06.943067", + "modified_by": "Administrator", + "name": "Operation", + "owner": "Administrator", + "title": "Create Operation" +} \ No newline at end of file diff --git a/erpnext/manufacturing/onboarding_step/warehouse/warehouse.json b/erpnext/manufacturing/onboarding_step/warehouse/warehouse.json new file mode 100644 index 0000000000..36f5204e0b --- /dev/null +++ b/erpnext/manufacturing/onboarding_step/warehouse/warehouse.json @@ -0,0 +1,15 @@ +{ + "action": "Create Entry", + "creation": "2020-05-12 16:13:34.014554", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 0, + "is_skipped": 0, + "modified": "2020-05-12 16:16:48.345846", + "modified_by": "Administrator", + "name": "Warehouse", + "owner": "Administrator", + "title": "Create Warehouse" +} \ No newline at end of file diff --git a/erpnext/manufacturing/onboarding_step/work_order/work_order.json b/erpnext/manufacturing/onboarding_step/work_order/work_order.json new file mode 100644 index 0000000000..57e4e7b3bc --- /dev/null +++ b/erpnext/manufacturing/onboarding_step/work_order/work_order.json @@ -0,0 +1,15 @@ +{ + "action": "Create Entry", + "creation": "2020-05-12 16:15:56.084682", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 0, + "is_skipped": 0, + "modified": "2020-05-12 16:17:33.675304", + "modified_by": "Administrator", + "name": "Work Order", + "owner": "Administrator", + "title": "Create Work Order" +} \ No newline at end of file diff --git a/erpnext/manufacturing/onboarding_step/workstation/workstation.json b/erpnext/manufacturing/onboarding_step/workstation/workstation.json new file mode 100644 index 0000000000..6c1a06938b --- /dev/null +++ b/erpnext/manufacturing/onboarding_step/workstation/workstation.json @@ -0,0 +1,15 @@ +{ + "action": "Create Entry", + "creation": "2020-05-12 16:14:14.930214", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 0, + "is_skipped": 0, + "modified": "2020-05-12 16:16:58.808906", + "modified_by": "Administrator", + "name": "Workstation", + "owner": "Administrator", + "title": "Create Workstation" +} \ No newline at end of file diff --git a/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py b/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py index d69ec189ba..dfc6b02b84 100644 --- a/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py +++ b/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py @@ -47,8 +47,7 @@ def get_chart_data(data, columns): {"name": "Dataset 1", "values": datasets} ] }, - "type": "bar", - "colors": ["#ff5858"] + "type": "bar" } return chart diff --git a/erpnext/manufacturing/report/job_card_summary/job_card_summary.py b/erpnext/manufacturing/report/job_card_summary/job_card_summary.py index 0f60c132ec..ae1e4f3046 100644 --- a/erpnext/manufacturing/report/job_card_summary/job_card_summary.py +++ b/erpnext/manufacturing/report/job_card_summary/job_card_summary.py @@ -49,33 +49,22 @@ def get_data(filters): def get_chart_data(job_card_details, filters): labels, periodic_data = prepare_chart_data(job_card_details, filters) - not_start, in_progress, on_hold, completed = [], [], [] , [] + pending, completed = [], [] datasets = [] for d in labels: - not_start.append(periodic_data.get("Open").get(d)) - in_progress.append(periodic_data.get("Work In Progress").get(d)) - on_hold.append(periodic_data.get("On Hold").get(d)) + pending.append(periodic_data.get("Pending").get(d)) completed.append(periodic_data.get("Completed").get(d)) - datasets.append({'name':'Open', 'values': not_start}) - datasets.append({'name':'Work In Progress', 'values': in_progress}) - datasets.append({'name':'On Hold', 'values': on_hold}) - datasets.append({'name':'Completed', 'values': completed}) + datasets.append({"name": "Pending", "values": pending}) + datasets.append({"name": "Completed", "values": completed}) chart = { "data": { 'labels': labels, 'datasets': datasets }, - "type": "bar", - "colors": ["#ff5858", "#ffa00a", "#5e64ff", "#98d85b"], - "axisOptions": { - "xAxisMode": "tick" - }, - "barOptions": { - "stacked": 1 - } + "type": "bar" } return chart @@ -84,9 +73,7 @@ def prepare_chart_data(job_card_details, filters): labels = [] periodic_data = { - "Open": {}, - "Work In Progress": {}, - "On Hold": {}, + "Pending": {}, "Completed": {} } @@ -100,10 +87,12 @@ def prepare_chart_data(job_card_details, filters): for d in job_card_details: if getdate(d.from_time) >= from_date and getdate(d.to_time) <= end_date: - if periodic_data.get(d.status) and periodic_data.get(d.status).get(period): - periodic_data[d.status][period] += 1 + status = "Completed" if d.status == "Completed" else "Pending" + + if periodic_data.get(status) and periodic_data.get(status).get(period): + periodic_data[status][period] += 1 else: - periodic_data[d.status][period] = 1 + periodic_data[status][period] = 1 return labels, periodic_data diff --git a/erpnext/manufacturing/report/production_analytics/production_analytics.py b/erpnext/manufacturing/report/production_analytics/production_analytics.py index f0bdfeda21..f62cd255b5 100644 --- a/erpnext/manufacturing/report/production_analytics/production_analytics.py +++ b/erpnext/manufacturing/report/production_analytics/production_analytics.py @@ -38,6 +38,7 @@ def get_columns(filters): def get_periodic_data(filters, entry): periodic_data = { + "All Work Orders": {}, "Not Started": {}, "Overdue": {}, "Pending": {}, @@ -50,6 +51,7 @@ def get_periodic_data(filters, entry): period = get_period(end_date, filters) for d in entry: if getdate(d.creation) <= getdate(from_date) or getdate(d.creation) <= getdate(end_date) : + periodic_data = update_periodic_data(periodic_data, "All Work Orders", period) if d.status == 'Completed': if getdate(d.actual_end_date) < getdate(from_date) or getdate(d.modified) < getdate(from_date): periodic_data = update_periodic_data(periodic_data, "Completed", period) @@ -97,7 +99,7 @@ def get_data(filters, columns): periodic_data = get_periodic_data(filters,entry) - labels = ["Not Started", "Overdue", "Pending", "Completed"] + labels = ["All Work Orders", "Not Started", "Overdue", "Pending", "Completed"] chart_data = get_chart_data(periodic_data,columns) ranges = get_period_date_ranges(filters) @@ -121,11 +123,13 @@ def get_chart_data(periodic_data, columns): datasets = [] for d in labels: + all_data.append(periodic_data.get("All Work Orders").get(d)) not_start.append(periodic_data.get("Not Started").get(d)) overdue.append(periodic_data.get("Overdue").get(d)) pending.append(periodic_data.get("Pending").get(d)) completed.append(periodic_data.get("Completed").get(d)) + datasets.append({'name':'All Work Orders', 'values': all_data}) datasets.append({'name':'Not Started', 'values': not_start}) datasets.append({'name':'Overdue', 'values': overdue}) datasets.append({'name':'Pending', 'values': pending}) @@ -135,14 +139,12 @@ def get_chart_data(periodic_data, columns): "data": { 'labels': labels, 'datasets': datasets - }, - "type": "bar", - "colors": ["#5e64ff", "#ff5858", "#ffa00a", "#98d85b"] + } } + chart["type"] = "line" return chart - diff --git a/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py b/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py index 9c1bfa4630..6192632bda 100644 --- a/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py +++ b/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py @@ -50,8 +50,7 @@ def get_chart_data(periodic_data, columns): 'datasets': datasets }, "type": "donut", - "height": 300, - "colors": ["#ff5858", "#98d85b"] + "height": 300 } return chart diff --git a/erpnext/manufacturing/report/work_order_summary/work_order_summary.js b/erpnext/manufacturing/report/work_order_summary/work_order_summary.js index 33b147df49..ec9fe35d63 100644 --- a/erpnext/manufacturing/report/work_order_summary/work_order_summary.js +++ b/erpnext/manufacturing/report/work_order_summary/work_order_summary.js @@ -54,5 +54,12 @@ frappe.query_reports["Work Order Summary"] = { fieldtype: "Int", default: "0" }, + { + label: __("Charts Based On"), + fieldname:"charts_based_on", + fieldtype: "Select", + options: ["Status", "Age", "Quantity"], + default: "Status" + }, ] }; diff --git a/erpnext/manufacturing/report/work_order_summary/work_order_summary.py b/erpnext/manufacturing/report/work_order_summary/work_order_summary.py index 92c31ab382..bc09ed4335 100644 --- a/erpnext/manufacturing/report/work_order_summary/work_order_summary.py +++ b/erpnext/manufacturing/report/work_order_summary/work_order_summary.py @@ -3,8 +3,9 @@ from __future__ import unicode_literals import frappe -from frappe.utils import date_diff, today +from frappe.utils import date_diff, today, getdate, flt from frappe import _ +from erpnext.stock.report.stock_analytics.stock_analytics import (get_period_date_ranges, get_period) def execute(filters=None): columns, data = [], [] @@ -46,7 +47,15 @@ def get_data(filters): return res -def get_chart_data(periodic_data, columns): +def get_chart_data(data, filters): + if filters.get("charts_based_on") == "Status": + return get_chart_based_on_status(data) + elif filters.get("charts_based_on") == "Age": + return get_chart_based_on_age(data) + else: + return get_chart_based_on_qty(data, filters) + +def get_chart_based_on_status(data): labels = ["Not Started", "In Process", "Stopped", "Completed"] status_wise_data = { @@ -56,7 +65,7 @@ def get_chart_data(periodic_data, columns): "Completed": 0 } - for d in periodic_data: + for d in data: if d.status == "In Process" and d.produced_qty: status_wise_data["Completed"] += d.produced_qty @@ -71,12 +80,100 @@ def get_chart_data(periodic_data, columns): 'datasets': [{'name':'Qty Wise Chart', 'values': values}] }, "type": "donut", - "height": 300, - "colors": ["#ff5858", "#ffa00a", "#5e64ff", "#98d85b"] + "height": 300 } return chart +def get_chart_based_on_age(data): + labels = ["0-30 Days", "30-60 Days", "60-90 Days", "90 Above"] + + age_wise_data = { + "0-30 Days": 0, + "30-60 Days": 0, + "60-90 Days": 0, + "90 Above": 0 + } + + for d in data: + if d.age > 0 and d.age <= 30: + age_wise_data["0-30 Days"] += 1 + elif d.age > 30 and d.age <= 60: + age_wise_data["30-60 Days"] += 1 + elif d.age > 60 and d.age <= 90: + age_wise_data["60-90 Days"] += 1 + else: + age_wise_data["90 Above"] += 1 + + values = [age_wise_data["0-30 Days"], age_wise_data["30-60 Days"], + age_wise_data["60-90 Days"], age_wise_data["90 Above"]] + + chart = { + "data": { + 'labels': labels, + 'datasets': [{'name':'Qty Wise Chart', 'values': values}] + }, + "type": "donut", + "height": 300 + } + + return chart + +def get_chart_based_on_qty(data, filters): + labels, periodic_data = prepare_chart_data(data, filters) + + pending, completed = [], [] + datasets = [] + + for d in labels: + pending.append(periodic_data.get("Pending").get(d)) + completed.append(periodic_data.get("Completed").get(d)) + + datasets.append({"name": "Pending", "values": pending}) + datasets.append({"name": "Completed", "values": completed}) + + chart = { + "data": { + 'labels': labels, + 'datasets': datasets + }, + "type": "bar", + "barOptions": { + "stacked": 1 + } + } + + return chart + +def prepare_chart_data(data, filters): + labels = [] + + periodic_data = { + "Pending": {}, + "Completed": {} + } + + filters.range = "Monthly" + + ranges = get_period_date_ranges(filters) + for from_date, end_date in ranges: + period = get_period(end_date, filters) + if period not in labels: + labels.append(period) + + if period not in periodic_data["Pending"]: + periodic_data["Pending"][period] = 0 + + if period not in periodic_data["Completed"]: + periodic_data["Completed"][period] = 0 + + for d in data: + if getdate(d.planned_start_date) >= from_date and getdate(d.planned_start_date) <= end_date: + periodic_data["Pending"][period] += (flt(d.qty) - flt(d.produced_qty)) + periodic_data["Completed"][period] += flt(d.produced_qty) + + return labels, periodic_data + def get_columns(filters): columns = [ { diff --git a/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py b/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py index 3fab0040fb..331c5590e5 100644 --- a/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py +++ b/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py @@ -6,6 +6,7 @@ from __future__ import unicode_literals import frappe from frappe.utils import add_to_date +from frappe.utils.dashboard import get_config, make_records def execute(): frappe.reload_doc("manufacturing", "doctype", "work_order") @@ -33,11 +34,9 @@ def execute(): planned_end_date = add_to_date(doc.planned_start_date, minutes=doc.lead_time) doc.db_set("planned_end_date", doc.actual_start_date, update_modified=False) - frappe.db.sql(""" UPDATE `tabJob Card` as jc, `tabWork Order` as wo SET jc.production_item = wo.production_item, jc.item_name = wo.item_name WHERE jc.work_order = wo.name and IFNULL(jc.production_item, "") = "" - """) - + """) \ No newline at end of file diff --git a/erpnext/setup/setup_wizard/data/dashboard_charts.py b/erpnext/setup/setup_wizard/data/dashboard_charts.py deleted file mode 100644 index f5b6681767..0000000000 --- a/erpnext/setup/setup_wizard/data/dashboard_charts.py +++ /dev/null @@ -1,247 +0,0 @@ -from __future__ import unicode_literals -from frappe import _ -import frappe -import json - -def get_company_for_dashboards(): - company = frappe.defaults.get_defaults().company - if company: - return company - else: - company_list = frappe.get_list("Company") - if company_list: - return company_list[0].name - return None - -def get_default_dashboards(): - company = frappe.get_doc("Company", get_company_for_dashboards()) - income_account = company.default_income_account or get_account("Income Account", company.name) - expense_account = company.default_expense_account or get_account("Expense Account", company.name) - bank_account = company.default_bank_account or get_account("Bank", company.name) - - return { - "Dashboards": [ - { - "doctype": "Dashboard", - "dashboard_name": "Accounts", - "charts": [ - { "chart": "Outgoing Bills (Sales Invoice)" }, - { "chart": "Incoming Bills (Purchase Invoice)" }, - { "chart": "Bank Balance" }, - { "chart": "Income" }, - { "chart": "Expenses" }, - { "chart": "Patient Appointments" } - ] - }, - { - "doctype": "Dashboard", - "dashboard_name": "Manufacturing", - "charts": [ - { "chart": "Work Order Analysis", "width": "Half" }, - { "chart": "Quality Inspection Analysis", "width": "Half" }, - { "chart": "Long Time Pending Work Orders", "width": "Half" }, - { "chart": "Downtime Analysis", "width": "Half" }, - { "chart": "Production Analysis", "width": "Full" }, - { "chart": "Job Card Analysis", "width": "Full" } - ] - } - ], - "Charts": [ - { - "doctype": "Dashboard Chart", - "time_interval": "Quarterly", - "chart_name": "Income", - "timespan": "Last Year", - "color": None, - "filters_json": json.dumps({"company": company.name, "account": income_account}), - "source": "Account Balance Timeline", - "chart_type": "Custom", - "timeseries": 1, - "owner": "Administrator", - "type": "Line", - "width": "Half" - }, - { - "doctype": "Dashboard Chart", - "time_interval": "Quarterly", - "chart_name": "Expenses", - "timespan": "Last Year", - "color": None, - "filters_json": json.dumps({"company": company.name, "account": expense_account}), - "source": "Account Balance Timeline", - "chart_type": "Custom", - "timeseries": 1, - "owner": "Administrator", - "type": "Line", - "width": "Half" - }, - { - "doctype": "Dashboard Chart", - "time_interval": "Quarterly", - "chart_name": "Bank Balance", - "timespan": "Last Year", - "color": "#ffb868", - "filters_json": json.dumps({"company": company.name, "account": bank_account}), - "source": "Account Balance Timeline", - "chart_type": "Custom", - "timeseries": 1, - "owner": "Administrator", - "type": "Line", - "width": "Half" - }, - { - "doctype": "Dashboard Chart", - "time_interval": "Monthly", - "chart_name": "Incoming Bills (Purchase Invoice)", - "timespan": "Last Year", - "color": "#a83333", - "value_based_on": "base_grand_total", - "filters_json": json.dumps({}), - "chart_type": "Sum", - "timeseries": 1, - "based_on": "posting_date", - "owner": "Administrator", - "document_type": "Purchase Invoice", - "type": "Bar", - "width": "Half" - }, - { - "doctype": "Dashboard Chart", - "time_interval": "Monthly", - "chart_name": "Outgoing Bills (Sales Invoice)", - "timespan": "Last Year", - "color": "#7b933d", - "value_based_on": "base_grand_total", - "filters_json": json.dumps({}), - "chart_type": "Sum", - "timeseries": 1, - "based_on": "posting_date", - "owner": "Administrator", - "document_type": "Sales Invoice", - "type": "Bar", - "width": "Half" - }, - { - "doctype": "Dashboard Chart", - "time_interval": "Daily", - "chart_name": "Patient Appointments", - "timespan": "Last Month", - "color": "#77ecca", - "filters_json": json.dumps({}), - "chart_type": "Count", - "timeseries": 1, - "based_on": "appointment_datetime", - "owner": "Administrator", - "document_type": "Patient Appointment", - "type": "Line", - "width": "Half" - } - { - "doctype": "Dashboard Chart", - "time_interval": "Yearly", - "chart_type": "Report", - "chart_name": "Work Order Analysis", - "timespan": "Last Year", - "report_name": "Work Order Summary", - "owner": "Administrator", - "filters_json": json.dumps({"company": company.name}), - "bar": "Donut", - "custom_options": json.dumps({ - "axisOptions": { - "shortenYAxisNumbers": 1 - }, - "height": 300, - "colors": ["#ff5858", "#ffa00a", "#5e64ff", "#98d85b"] - }), - }, - { - "doctype": "Dashboard Chart", - "time_interval": "Yearly", - "chart_type": "Report", - "chart_name": "Quality Inspection Analysis", - "timespan": "Last Year", - "report_name": "Quality Inspection Summary", - "owner": "Administrator", - "filters_json": json.dumps({}), - "bar": "Donut", - "custom_options": json.dumps({ - "axisOptions": { - "shortenYAxisNumbers": 1 - }, - "height": 300, - "colors": ["#ff5858", "#98d85b"] - }), - }, - { - "doctype": "Dashboard Chart", - "time_interval": "Yearly", - "chart_type": "Report", - "chart_name": "Long Time Pending Work Orders", - "timespan": "Last Year", - "report_name": "Work Order Summary", - "filters_json": json.dumps({"company": company.name, "age":180}), - "owner": "Administrator", - "bar": "Bar", - "custom_options": json.dumps({ - "colors": ["#ff5858"], - "x_field": "name", - "y_fields": ["age"], - "y_axis_fields": [{"__islocal": "true", "idx": 1, "y_field": "age"}], - "chart_type": "Bar" - }), - }, - { - "doctype": "Dashboard Chart", - "time_interval": "Yearly", - "chart_type": "Report", - "chart_name": "Downtime Analysis", - "timespan": "Last Year", - "filters_json": json.dumps({}), - "report_name": "Downtime Analysis", - "owner": "Administrator", - "bar": "Bar", - "custom_options": json.dumps({ - "colors": ["#ff5858"] - }), - }, - { - "doctype": "Dashboard Chart", - "time_interval": "Yearly", - "chart_type": "Report", - "chart_name": "Production Analysis", - "timespan": "Last Year", - "report_name": "Production Analytics", - "owner": "Administrator", - "filters_json": json.dumps({"company": company.name, "range":"Monthly"}), - "bar": "Bar", - "custom_options": json.dumps({ - "colors": ["#7cd6fd", "#ff5858", "#ffa00a", "#98d85b"] - }), - }, - { - "doctype": "Dashboard Chart", - "time_interval": "Yearly", - "chart_type": "Report", - "chart_name": "Job Card Analysis", - "timespan": "Last Year", - "report_name": "Job Card Summary", - "owner": "Administrator", - "filters_json": json.dumps({"company": company.name, "range":"Monthly"}), - "bar": "Bar", - "custom_options": json.dumps({ - "axisOptions": { - "xAxisMode": "tick" - }, - "barOptions": { - "stacked": 1 - }, - "colors": ["#ff5858", "#ffa00a", "#5e64ff", "#98d85b"] - }), - }, - ] - } - -def get_account(account_type, company): - accounts = frappe.get_list("Account", filters={"account_type": account_type, "company": company}) - if accounts: - return accounts[0].name