added onboarding for manufacturing

This commit is contained in:
Rohit Waghchaure 2020-05-06 02:38:27 +05:30
parent 34f4a2398b
commit 366bce678f
19 changed files with 545 additions and 296 deletions

View File

@ -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"
}]

View File

@ -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"
}
]
}

View File

@ -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",

View File

@ -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
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -47,8 +47,7 @@ def get_chart_data(data, columns):
{"name": "Dataset 1", "values": datasets}
]
},
"type": "bar",
"colors": ["#ff5858"]
"type": "bar"
}
return chart

View File

@ -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

View File

@ -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

View File

@ -50,8 +50,7 @@ def get_chart_data(periodic_data, columns):
'datasets': datasets
},
"type": "donut",
"height": 300,
"colors": ["#ff5858", "#98d85b"]
"height": 300
}
return chart

View File

@ -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"
},
]
};

View File

@ -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 = [
{

View File

@ -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, "") = ""
""")
""")

View File

@ -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