diff --git a/erpnext/buying/__init__.py b/erpnext/buying/__init__.py
index e69de29bb2..baffc48825 100644
--- a/erpnext/buying/__init__.py
+++ b/erpnext/buying/__init__.py
@@ -0,0 +1 @@
+from __future__ import unicode_literals
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 7e5020a08d..26c8c61167 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -39,6 +39,8 @@ class PurchaseOrder(BuyingController):
super(PurchaseOrder, self).validate()
self.set_status()
+
+ self.validate_supplier()
validate_for_items(self)
self.check_for_closed_status()
@@ -65,6 +67,17 @@ class PurchaseOrder(BuyingController):
}
})
+ def validate_supplier(self):
+ prevent_po = frappe.db.get_value("Supplier", self.supplier, 'prevent_pos')
+ if prevent_po:
+ standing = frappe.db.get_value("Supplier Scorecard",self.supplier, 'status')
+ frappe.throw(_("Purchase Orders are not allowed for {0} due to a scorecard standing of {1}.").format(self.supplier, standing))
+
+ warn_po = frappe.db.get_value("Supplier", self.supplier, 'warn_pos')
+ if warn_po:
+ standing = frappe.db.get_value("Supplier Scorecard",self.supplier, 'status')
+ frappe.msgprint(_("{0} currently has a {1} Supplier Scorecard standing, and Purchase Orders to this supplier should be issued with caution.").format(self.supplier, standing), title=_("Caution"), indicator='orange')
+
def validate_minimum_order_qty(self):
items = list(set([d.item_code for d in self.get("items")]))
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
index 9109239e93..666a1c6e8a 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
@@ -21,6 +21,7 @@ STANDARD_USERS = ("Guest", "Administrator")
class RequestforQuotation(BuyingController):
def validate(self):
self.validate_duplicate_supplier()
+ self.validate_supplier_list()
validate_for_items(self)
self.update_email_id()
@@ -29,6 +30,17 @@ class RequestforQuotation(BuyingController):
if len(supplier_list) != len(set(supplier_list)):
frappe.throw(_("Same supplier has been entered multiple times"))
+ def validate_supplier_list(self):
+ for d in self.suppliers:
+ prevent_rfqs = frappe.db.get_value("Supplier", d.supplier, 'prevent_rfqs')
+ if prevent_rfqs:
+ standing = frappe.db.get_value("Supplier Scorecard",d.supplier, 'status')
+ frappe.throw(_("RFQs are not allowed for {0} due to a scorecard standing of {1}").format(d.supplier, standing))
+ warn_rfqs = frappe.db.get_value("Supplier", d.supplier, 'warn_rfqs')
+ if warn_rfqs:
+ standing = frappe.db.get_value("Supplier Scorecard",d.supplier, 'status')
+ frappe.msgprint(_("{0} currently has a {1} Supplier Scorecard standing, and RFQs to this supplier should be issued with caution.").format(d.supplier, standing), title=_("Caution"), indicator='orange')
+
def update_email_id(self):
for rfq_supplier in self.suppliers:
if not rfq_supplier.email_id:
diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json
index 58a1fc7464..711e05d913 100644
--- a/erpnext/buying/doctype/supplier/supplier.json
+++ b/erpnext/buying/doctype/supplier/supplier.json
@@ -322,6 +322,126 @@
"set_only_once": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "warn_rfqs",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Warn RFQs",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "warn_pos",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Warn POs",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "prevent_rfqs",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Prevent RFQs",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "prevent_pos",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Prevent POs",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -850,7 +970,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-06-13 14:29:16.310834",
+ "modified": "2017-07-06 16:40:46.935608",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier",
diff --git a/erpnext/buying/doctype/supplier_scorecard/__init__.py b/erpnext/buying/doctype/supplier_scorecard/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.js b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.js
new file mode 100644
index 0000000000..a3a14147f2
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.js
@@ -0,0 +1,146 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+/* global frappe, refresh_field */
+
+frappe.ui.form.on("Supplier Scorecard", {
+
+ onload: function(frm) {
+
+ if (frm.doc.indicator_color !== "") {
+ frm.set_indicator_formatter("status", function(doc) {
+ return doc.indicator_color.toLowerCase();
+ });
+ }
+ if (frm.doc.__unsaved == 1) {
+ loadAllCriteria(frm);
+ loadAllStandings(frm);
+ }
+
+ },
+ refresh: function(frm) {
+ if (frm.dashboard.hasOwnProperty('heatmap')) {
+ frm.dashboard.heatmap.setLegend([0,20,40,60,80,101],["#991600","#169900"]);
+ }
+ }
+
+});
+
+frappe.ui.form.on("Supplier Scorecard Scoring Standing", {
+
+ standing_name: function(frm, cdt, cdn) {
+ if (frm.doc.standing_name != undefined) {
+ var d = frappe.get_doc(cdt, cdn);
+ return frm.call({
+ method: "erpnext.buying.doctype.supplier_scorecard_standing.supplier_scorecard_standing.get_scoring_standing",
+ child: d,
+ args: {
+ standing_name: d.standing_name
+ }
+ });
+ }
+ }
+});
+
+frappe.ui.form.on("Supplier Scorecard Scoring Variable", {
+
+ variable_label: function(frm, cdt, cdn) {
+ if (frm.doc.variable_label != undefined) {
+ var d = frappe.get_doc(cdt, cdn);
+ return frm.call({
+ method: "erpnext.buying.doctype.supplier_scorecard_variable.supplier_scorecard_variable.get_scoring_variable",
+ child: d,
+ args: {
+ variable_label: d.variable_label
+ }
+ });
+ }
+ }
+});
+
+frappe.ui.form.on("Supplier Scorecard Scoring Criteria", {
+
+ criteria_name: function(frm, cdt, cdn) {
+ if (frm.doc.criteria_name != undefined) {
+ var d = frappe.get_doc(cdt, cdn);
+ frm.call({
+ method: "erpnext.buying.doctype.supplier_scorecard_criteria.supplier_scorecard_criteria.get_variables",
+ args: {
+ criteria_name: d.criteria_name
+ },
+ callback: function(r) {
+ for (var i = 0; i < r.message.length; i++)
+ {
+ var exists = false;
+ for (var j = 0; j < frm.doc.variables.length; j++)
+ {
+ if(!frm.doc.variables[j].hasOwnProperty("variable_label")) {
+ frm.get_field("variables").grid.grid_rows[j].remove();
+ }
+ else if(frm.doc.variables[j].variable_label === r.message[i]) {
+ exists = true;
+ }
+ }
+ if (!exists){
+ var new_row = frm.add_child("variables");
+ new_row.variable_label = r.message[i];
+ frm.script_manager.trigger("variable_label", new_row.doctype, new_row.name);
+ }
+
+ }
+ refresh_field("variables");
+ }
+ });
+ return frm.call({
+ method: "erpnext.buying.doctype.supplier_scorecard_criteria.supplier_scorecard_criteria.get_scoring_criteria",
+ child: d,
+ args: {
+ criteria_name: d.criteria_name
+ }
+ });
+ }
+ }
+});
+
+var loadAllCriteria = function(frm) {
+ frappe.call({
+ method: "erpnext.buying.doctype.supplier_scorecard_criteria.supplier_scorecard_criteria.get_criteria_list",
+ callback: function(r) {
+ for (var j = 0; j < frm.doc.criteria.length; j++)
+ {
+ if(!frm.doc.criteria[j].hasOwnProperty("criteria_name")) {
+ frm.get_field("criteria").grid.grid_rows[j].remove();
+ }
+ }
+ for (var i = 0; i < r.message.length; i++)
+ {
+ var new_row = frm.add_child("criteria");
+ new_row.criteria_name = r.message[i].name;
+ frm.script_manager.trigger("criteria_name", new_row.doctype, new_row.name);
+ }
+ refresh_field("criteria");
+ }
+ });
+};
+var loadAllStandings = function(frm) {
+ frappe.call({
+ method: "erpnext.buying.doctype.supplier_scorecard_standing.supplier_scorecard_standing.get_standings_list",
+ callback: function(r) {
+ for (var j = 0; j < frm.doc.standings.length; j++)
+ {
+ if(!frm.doc.standings[j].hasOwnProperty("standing_name")) {
+ frm.get_field("standings").grid.grid_rows[j].remove();
+ }
+ }
+ for (var i = 0; i < r.message.length; i++)
+ {
+ var new_row = frm.add_child("standings");
+ new_row.standing_name = r.message[i].name;
+ frm.script_manager.trigger("standing_name", new_row.doctype, new_row.name);
+ }
+ refresh_field("standings");
+ }
+ });
+};
+
+
diff --git a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.json b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.json
new file mode 100644
index 0000000000..d7f24c9082
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.json
@@ -0,0 +1,701 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "field:supplier",
+ "beta": 1,
+ "creation": "2017-05-29 01:40:54.786555",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "supplier",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Supplier",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Supplier",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "supplier_score",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Supplier Score",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "indicator_color",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Indicator Color",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "status",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Status",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "Per Month",
+ "fieldname": "period",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Evaluation Period",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Per Month\nPer Week\nPer Year",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 1,
+ "columns": 0,
+ "fieldname": "scoring_setup",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Scoring Setup",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "{total_score} * max( 0, min ( 1 , (12 - {period_number}) / 12) )",
+ "description": "Scorecard variables can be used, as well as:\n{total_score} (the total score from that period),\n{period_number} (the number of periods to present day)\n",
+ "fieldname": "weighting_function",
+ "fieldtype": "Small Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Weighting Function",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "standings",
+ "fieldtype": "Table",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Scoring Standings",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Supplier Scorecard Scoring Standing",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 1,
+ "columns": 0,
+ "fieldname": "criteria_setup",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Criteria Setup",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "criteria",
+ "fieldtype": "Table",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Scoring Criteria",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Supplier Scorecard Scoring Criteria",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "variables",
+ "fieldtype": "Table",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Supplier Variables",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Supplier Scorecard Scoring Variable",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 1,
+ "collapsible_depends_on": "eval: doc.status != 'Unknown'",
+ "columns": 0,
+ "fieldname": "scorecard_actions",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Scorecard Actions",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "warn_rfqs",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Warn for new Request for Quotations",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "warn_pos",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Warn for new Purchase Orders",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "prevent_rfqs",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Prevent RFQs",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "prevent_pos",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Prevent POs",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_16",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "notify_supplier",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Notify Supplier",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "notify_employee",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Notify Employee",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Employee",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-07-12 07:33:11.874949",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Supplier Scorecard",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 0,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py
new file mode 100644
index 0000000000..e13d22ab57
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py
@@ -0,0 +1,262 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import throw, _
+from frappe.model.document import Document
+import time
+from datetime import timedelta
+from frappe.utils import nowdate, get_last_day, getdate, add_days, add_years
+from erpnext.buying.doctype.supplier_scorecard_period.supplier_scorecard_period import make_supplier_scorecard
+
+class SupplierScorecard(Document):
+
+ def validate(self):
+ self.validate_standings()
+ self.validate_criteria_weights()
+ self.calculate_total_score()
+ self.update_standing()
+
+ def on_update(self):
+ score = make_all_scorecards(self.name)
+ if score > 0:
+ self.save()
+
+ def validate_standings(self):
+ # Check that there are no overlapping scores and check that there are no missing scores
+ score = 0
+ for c1 in self.standings:
+ for c2 in self.standings:
+ if c1 != c2:
+ if (c1.max_grade > c2.min_grade and c1.min_grade < c2.max_grade):
+ throw(_('Overlap in scoring between {0} and {1}').format(c1.standing_name,c2.standing_name))
+ if c2.min_grade == score:
+ score = c2.max_grade
+ if score < 100:
+ throw(_('Unable to find score starting at {0}. You need to have standing scores covering 0 to 100').format(score))
+
+ def validate_criteria_weights(self):
+
+ weight = 0
+ for c in self.criteria:
+ weight += c.weight
+
+ if weight != 100:
+ throw(_('Criteria weights must add up to 100%'))
+
+ def calculate_total_score(self):
+ scorecards = frappe.db.sql("""
+ SELECT
+ scp.name
+ FROM
+ `tabSupplier Scorecard Period` scp
+ WHERE
+ scp.scorecard = %(sc)s
+ ORDER BY
+ scp.end_date DESC""",
+ {"sc": self.name}, as_dict=1)
+
+ period = 0
+ total_score = 0
+ total_max_score = 0
+ for scp in scorecards:
+ my_sc = frappe.get_doc('Supplier Scorecard Period', scp.name)
+ my_scp_weight = self.weighting_function
+ my_scp_weight = my_scp_weight.replace('{period_number}', str(period))
+
+ my_scp_maxweight = my_scp_weight.replace('{total_score}', '100')
+ my_scp_weight = my_scp_weight.replace('{total_score}', str(my_sc.total_score))
+
+ max_score = my_sc.calculate_weighted_score(my_scp_maxweight)
+ score = my_sc.calculate_weighted_score(my_scp_weight)
+
+ total_score += score
+ total_max_score += max_score
+ period += 1
+ if total_max_score > 0:
+ self.supplier_score = round(100.0 * (total_score / total_max_score) ,1)
+ else:
+ self.supplier_score = 100
+
+ def update_standing(self):
+ # Get the setup document
+
+ for standing in self.standings:
+ if (not standing.min_grade or (standing.min_grade <= self.supplier_score)) and \
+ (not standing.max_grade or (standing.max_grade > self.supplier_score)):
+ self.status = standing.standing_name
+ self.indicator_color = standing.standing_color
+ self.notify_supplier = standing.notify_supplier
+ self.notify_employee = standing.notify_employee
+ self.employee_link = standing.employee_link
+
+ #Update supplier standing info
+ for fieldname in ('prevent_pos', 'prevent_rfqs','warn_rfqs','warn_pos'):
+ self.set(fieldname, standing.get(fieldname))
+ frappe.db.set_value("Supplier", self.supplier, fieldname, self.get(fieldname))
+
+
+@frappe.whitelist()
+def get_timeline_data(doctype, name):
+ # Get a list of all the associated scorecards
+ scs = frappe.get_doc(doctype, name)
+ out = {}
+ timeline_data = {}
+ scorecards = frappe.db.sql("""
+ SELECT
+ sc.name
+ FROM
+ `tabSupplier Scorecard Period` sc
+ WHERE
+ sc.scorecard = %(scs)s""",
+ {"scs": scs.name}, as_dict=1)
+
+ for sc in scorecards:
+ start_date, end_date, total_score = frappe.db.get_value('Supplier Scorecard Period', sc.name, ['start_date', 'end_date', 'total_score'])
+ for single_date in daterange(start_date, end_date):
+ timeline_data[time.mktime(single_date.timetuple())] = total_score
+
+ out['timeline_data'] = timeline_data
+ return out
+
+def daterange(start_date, end_date):
+ for n in range(int ((end_date - start_date).days)+1):
+ yield start_date + timedelta(n)
+
+def refresh_scorecards():
+ scorecards = frappe.db.sql("""
+ SELECT
+ sc.name
+ FROM
+ `tabSupplier Scorecard` sc""",
+ {}, as_dict=1)
+ for sc in scorecards:
+ # Check to see if any new scorecard periods are created
+ if make_all_scorecards(sc.name) > 0:
+ # Save the scorecard to update the score and standings
+ sc.save()
+
+
+@frappe.whitelist()
+def make_all_scorecards(docname):
+
+ sc = frappe.get_doc('Supplier Scorecard', docname)
+ supplier = frappe.get_doc('Supplier',sc.supplier)
+
+ start_date = getdate(supplier.creation)
+ end_date = get_scorecard_date(sc.period, start_date)
+ todays = getdate(nowdate())
+
+ scp_count = 0
+ first_start_date = todays
+ last_end_date = todays
+
+ while (start_date < todays) and (end_date <= todays):
+ # check to make sure there is no scorecard period already created
+ scorecards = frappe.db.sql("""
+ SELECT
+ scp.name
+ FROM
+ `tabSupplier Scorecard Period` scp
+ WHERE
+ scp.scorecard = %(sc)s
+ AND (
+ (scp.start_date > %(end_date)s
+ AND scp.end_date < %(start_date)s)
+ OR
+ (scp.start_date < %(end_date)s
+ AND scp.end_date > %(start_date)s))
+ ORDER BY
+ scp.end_date DESC""",
+ {"sc": docname, "start_date": start_date, "end_date": end_date, "supplier": supplier}, as_dict=1)
+ if len(scorecards) == 0:
+ period_card = make_supplier_scorecard(docname, None)
+ period_card.start_date = start_date
+ period_card.end_date = end_date
+ period_card.save()
+ scp_count = scp_count + 1
+ if start_date < first_start_date:
+ first_start_date = start_date
+ last_end_date = end_date
+
+ start_date = getdate(add_days(end_date,1))
+ end_date = get_scorecard_date(sc.period, start_date)
+ if scp_count > 0:
+ frappe.msgprint(_("Created {0} scorecards for {1} between: ").format(scp_count, sc.supplier) + str(first_start_date) + " - " + str(last_end_date))
+ return scp_count
+
+def get_scorecard_date(period, start_date):
+ if period == 'Per Week':
+ end_date = getdate(add_days(start_date,7))
+ elif period == 'Per Month':
+ end_date = get_last_day(start_date)
+ elif period == 'Per Year':
+ end_date = add_days(add_years(start_date,1), -1)
+ return end_date
+
+def make_default_records():
+ install_variable_docs = [
+ {"param_name": "total_accepted_items", "variable_label": "Total Accepted Items", \
+ "path": "get_total_accepted_items"},
+ {"param_name": "total_accepted_amount", "variable_label": "Total Accepted Amount", \
+ "path": "get_total_accepted_amount"},
+ {"param_name": "total_rejected_items", "variable_label": "Total Rejected Items", \
+ "path": "get_total_rejected_items"},
+ {"param_name": "total_rejected_amount", "variable_label": "Total Rejected Amount", \
+ "path": "get_total_rejected_amount"},
+ {"param_name": "total_received_items", "variable_label": "Total Received Items", \
+ "path": "get_total_received_items"},
+ {"param_name": "total_received_amount", "variable_label": "Total Received Amount", \
+ "path": "get_total_received_amount"},
+ {"param_name": "rfq_response_days", "variable_label": "RFQ Response Days", \
+ "path": "get_rfq_response_days"},
+ {"param_name": "sq_total_items", "variable_label": "SQ Total Items", \
+ "path": "get_sq_total_items"},
+ {"param_name": "sq_total_number", "variable_label": "SQ Total Number", \
+ "path": "get_sq_total_number"},
+ {"param_name": "rfq_total_number", "variable_label": "RFQ Total Number", \
+ "path": "get_rfq_total_number"},
+ {"param_name": "rfq_total_items", "variable_label": "RFQ Total Items", \
+ "path": "get_rfq_total_items"},
+ {"param_name": "tot_item_days", "variable_label": "Total Item Days", \
+ "path": "get_item_workdays"},
+ {"param_name": "on_time_shipment_num", "variable_label": "# of On Time Shipments", "path": \
+ "get_on_time_shipments"},
+ {"param_name": "cost_of_delayed_shipments", "variable_label": "Cost of Delayed Shipments", \
+ "path": "get_cost_of_delayed_shipments"},
+ {"param_name": "cost_of_on_time_shipments", "variable_label": "Cost of On Time Shipments", \
+ "path": "get_cost_of_on_time_shipments"},
+ {"param_name": "total_working_days", "variable_label": "Total Working Days", \
+ "path": "get_total_workdays"},
+ {"param_name": "tot_cost_shipments", "variable_label": "Total Cost of Shipments", \
+ "path": "get_total_cost_of_shipments"},
+ {"param_name": "tot_days_late", "variable_label": "Total Days Late", \
+ "path": "get_total_days_late"},
+ {"param_name": "total_shipments", "variable_label": "Total Shipments", \
+ "path": "get_total_shipments"}
+ ]
+ install_standing_docs = [
+ {"min_grade": 0.0, "prevent_rfqs": 1, "notify_supplier": 0, "max_grade": 30.0, "prevent_pos": 1, \
+ "standing_color": "Red", "notify_employee": 0, "standing_name": "Very Poor"},
+ {"min_grade": 30.0, "prevent_rfqs": 1, "notify_supplier": 0, "max_grade": 50.0, "prevent_pos": 0, \
+ "standing_color": "Red", "notify_employee": 0, "standing_name": "Poor"},
+ {"min_grade": 50.0, "prevent_rfqs": 0, "notify_supplier": 0, "max_grade": 80.0, "prevent_pos": 0, \
+ "standing_color": "Green", "notify_employee": 0, "standing_name": "Average"},
+ {"min_grade": 80.0, "prevent_rfqs": 0, "notify_supplier": 0, "max_grade": 100.0, "prevent_pos": 0, \
+ "standing_color": "Blue", "notify_employee": 0, "standing_name": "Excellent"},
+ ]
+
+ for d in install_variable_docs:
+ try:
+ d['doctype'] = "Supplier Scorecard Variable"
+ frappe.get_doc(d).insert()
+ except frappe.NameError:
+ pass
+ for d in install_standing_docs:
+ try:
+ d['doctype'] = "Supplier Scorecard Standing"
+ frappe.get_doc(d).insert()
+ except frappe.NameError:
+ pass
diff --git a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_dashboard.py b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_dashboard.py
new file mode 100644
index 0000000000..ff7f119253
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_dashboard.py
@@ -0,0 +1,15 @@
+from frappe import _
+
+def get_data():
+ return {
+ 'heatmap': True,
+ 'heatmap_message': _('This covers all scorecards tied to this Setup'),
+ 'fieldname': 'supplier',
+ 'method' : 'erpnext.buying.doctype.supplier_scorecard.supplier_scorecard.get_timeline_data',
+ 'transactions': [
+ {
+ 'label': _('Scorecards'),
+ 'items': ['Supplier Scorecard Period']
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_list.js b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_list.js
new file mode 100644
index 0000000000..c50916e4fa
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_list.js
@@ -0,0 +1,17 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+/* global frappe, __ */
+
+frappe.listview_settings["Supplier Scorecard"] = {
+ add_fields: ["indicator_color", "status"],
+ get_indicator: function(doc) {
+
+ if (doc.indicator_color) {
+ return [__(doc.status), doc.indicator_color.toLowerCase(), "status,=," + doc.status];
+ } else {
+ return [__("Unknown"), "darkgrey", "status,=,''"];
+ }
+ },
+
+};
diff --git a/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py b/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py
new file mode 100644
index 0000000000..d64d3f683f
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py
@@ -0,0 +1,190 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestSupplierScorecard(unittest.TestCase):
+
+ def test_create_scorecard(self):
+ delete_test_scorecards()
+ my_doc = make_supplier_scorecard()
+ doc = my_doc.insert()
+ self.assertEqual(doc.name, valid_scorecard[0].get("supplier"))
+
+ def test_criteria_weight(self):
+ delete_test_scorecards()
+ my_doc = make_supplier_scorecard()
+ for d in my_doc.criteria:
+ d.weight = 0
+ self.assertRaises(frappe.ValidationError,my_doc.insert)
+
+ def test_missing_variable(self):
+ delete_test_scorecards()
+ my_doc = make_supplier_scorecard()
+ del my_doc.variables
+ self.assertRaises(frappe.ValidationError,my_doc.insert)
+
+def make_supplier_scorecard():
+ my_doc = frappe.get_doc(valid_scorecard[0])
+
+ # Make sure the criteria exist (making them)
+ for d in valid_scorecard[0].get("criteria"):
+ if not frappe.db.exists("Supplier Scorecard Criteria", d.get("criteria_name")):
+ d["doctype"] = "Supplier Scorecard Criteria"
+ d["name"] = d.get("criteria_name")
+ my_criteria = frappe.get_doc(d)
+ my_criteria.insert()
+ return my_doc
+
+
+def delete_test_scorecards():
+ my_doc = make_supplier_scorecard()
+ if frappe.db.exists("Supplier Scorecard", my_doc.name):
+ # Delete all the periods, then delete the scorecard
+ frappe.db.sql("""delete from `tabSupplier Scorecard Period` where scorecard = %(scorecard)s""", {'scorecard': my_doc.name})
+ frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Criteria` where parenttype = 'Supplier Scorecard Period'""")
+ frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Standing` where parenttype = 'Supplier Scorecard Period'""")
+ frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Variable` where parenttype = 'Supplier Scorecard Period'""")
+ frappe.delete_doc(my_doc.doctype, my_doc.name)
+
+valid_scorecard = [
+ {
+ "standings":[
+ {
+ "min_grade":0.0,"name":"Very Poor",
+ "prevent_rfqs":1,
+ "notify_supplier":0,
+ "doctype":"Supplier Scorecard Standing",
+ "max_grade":30.0,
+ "prevent_pos":1,
+ "warn_pos":0,
+ "warn_rfqs":0,
+ "standing_color":"Red",
+ "notify_employee":0,
+ "standing_name":"Very Poor",
+ "parenttype":"Supplier Scorecard",
+ "parentfield":"standings"
+ },
+ {
+ "min_grade":30.0,
+ "name":"Poor",
+ "prevent_rfqs":1,
+ "notify_supplier":0,
+ "doctype":"Supplier Scorecard Standing",
+ "max_grade":50.0,
+ "prevent_pos":0,
+ "warn_pos":0,
+ "warn_rfqs":0,
+ "standing_color":"Red",
+ "notify_employee":0,
+ "standing_name":"Poor",
+ "parenttype":"Supplier Scorecard",
+ "parentfield":"standings"
+ },
+ {
+ "min_grade":50.0,
+ "name":"Average",
+ "prevent_rfqs":0,
+ "notify_supplier":0,
+ "doctype":"Supplier Scorecard Standing",
+ "max_grade":80.0,
+ "prevent_pos":0,
+ "warn_pos":0,
+ "warn_rfqs":0,
+ "standing_color":"Green",
+ "notify_employee":0,
+ "standing_name":"Average",
+ "parenttype":"Supplier Scorecard",
+ "parentfield":"standings"
+ },
+ {
+ "min_grade":80.0,
+ "name":"Excellent",
+ "prevent_rfqs":0,
+ "notify_supplier":0,
+ "doctype":"Supplier Scorecard Standing",
+ "max_grade":100.0,
+ "prevent_pos":0,
+ "warn_pos":0,
+ "warn_rfqs":0,
+ "standing_color":"Blue",
+ "notify_employee":0,
+ "standing_name":"Excellent",
+ "parenttype":"Supplier Scorecard",
+ "parentfield":"standings"
+ }
+ ],
+ "prevent_pos":0,
+ "variables": [
+ {
+ "param_name":"cost_of_on_time_shipments",
+ "doctype":"Supplier Scorecard Scoring Variable",
+ "parenttype":"Supplier Scorecard",
+ "variable_label":"Cost of On Time Shipments",
+ "path":"get_cost_of_on_time_shipments",
+ "parentfield":"variables"
+ },
+ {
+ "param_name":"tot_cost_shipments",
+ "doctype":"Supplier Scorecard Scoring Variable",
+ "parenttype":"Supplier Scorecard",
+ "variable_label":"Total Cost of Shipments",
+ "path":"get_total_cost_of_shipments",
+ "parentfield":"variables"
+ },
+ {
+ "param_name":"tot_days_late",
+ "doctype":"Supplier Scorecard Scoring Variable",
+ "parenttype":"Supplier Scorecard",
+ "variable_label":"Total Days Late",
+ "path":"get_total_days_late",
+ "parentfield":"variables"
+ },
+ {
+ "param_name":"total_working_days",
+ "doctype":"Supplier Scorecard Scoring Variable",
+ "parenttype":"Supplier Scorecard",
+ "variable_label":"Total Working Days",
+ "path":"get_total_workdays",
+ "parentfield":"variables"
+ },
+ {
+ "param_name":"on_time_shipment_num",
+ "doctype":"Supplier Scorecard Scoring Variable",
+ "parenttype":"Supplier Scorecard",
+ "variable_label":"# of On Time Shipments",
+ "path":"get_on_time_shipments",
+ "parentfield":"variables"
+ },
+ {
+ "param_name":"total_shipments",
+ "doctype":"Supplier Scorecard Scoring Variable",
+ "parenttype":"Supplier Scorecard",
+ "variable_label":"Total Shipments",
+ "path":"get_total_shipments",
+ "parentfield":"variables"
+ }
+ ],
+ "period":"Per Month",
+ "doctype":"Supplier Scorecard",
+ "warn_pos":0,
+ "warn_rfqs":0,
+ "notify_supplier":0,
+ "criteria":[
+ {
+ "weight":100.0,
+ "doctype":"Supplier Scorecard Scoring Criteria",
+ "formula":"(({cost_of_on_time_shipments} / {tot_cost_shipments}) if {tot_cost_shipments} > 0 else 1 )* 100 ",
+ "criteria_name":"Delivery",
+ "max_score":100.0,
+ }
+ ],
+ "supplier":"_Test Supplier",
+ "name":"_Test Supplier",
+ "weighting_function":"{total_score} * max( 0, min ( 1 , (12 - {period_number}) / 12) )",
+ }
+]
+
diff --git a/erpnext/buying/doctype/supplier_scorecard_criteria/__init__.py b/erpnext/buying/doctype/supplier_scorecard_criteria/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.js b/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.js
new file mode 100644
index 0000000000..9f8a2dee81
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+/* global frappe */
+
+frappe.ui.form.on("Supplier Scorecard Criteria", {
+ refresh: function() {}
+});
diff --git a/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.json b/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.json
new file mode 100644
index 0000000000..229c386120
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.json
@@ -0,0 +1,184 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "field:criteria_name",
+ "beta": 1,
+ "creation": "2017-05-29 01:32:43.064891",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "criteria_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Criteria Name",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 1
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "weight",
+ "fieldtype": "Percent",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Criteria Weight",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "100",
+ "fieldname": "max_score",
+ "fieldtype": "Float",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Max Score",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "formula",
+ "fieldtype": "Small Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Criteria Formula",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-07-17 10:30:47.458285",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Supplier Scorecard Criteria",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.py b/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.py
new file mode 100644
index 0000000000..8514022b78
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+import re
+from frappe.model.document import Document
+
+class InvalidFormulaVariable(frappe.ValidationError): pass
+
+class SupplierScorecardCriteria(Document):
+ def validate(self):
+ self.validate_variables()
+ self.validate_formula()
+
+ def validate_variables(self):
+ # make sure all the variables exist
+ _get_variables(self)
+
+ def validate_formula(self):
+ # evaluate the formula with 0's to make sure it is valid
+ test_formula = self.formula.replace("\r", "").replace("\n", "")
+
+ regex = r"\{(.*?)\}"
+
+ mylist = re.finditer(regex, test_formula, re.MULTILINE | re.DOTALL)
+ for dummy1, match in enumerate(mylist):
+ for dummy2 in range(0, len(match.groups())):
+ test_formula = test_formula.replace('{' + match.group(1) + '}', "0")
+
+ test_formula = test_formula.replace('<','<').replace('>','>')
+ try:
+ frappe.safe_eval(test_formula, None, {'max':max, 'min': min})
+ except Exception:
+ frappe.throw(_("Error evaluating the criteria formula"))
+
+
+
+@frappe.whitelist()
+def get_scoring_criteria(criteria_name):
+ criteria = frappe.get_doc("Supplier Scorecard Criteria", criteria_name)
+
+ return criteria
+
+
+@frappe.whitelist()
+def get_criteria_list():
+ criteria = frappe.db.sql("""
+ SELECT
+ scs.name
+ FROM
+ `tabSupplier Scorecard Criteria` scs""",
+ {}, as_dict=1)
+
+ return criteria
+
+@frappe.whitelist()
+def get_variables(criteria_name):
+ criteria = frappe.get_doc("Supplier Scorecard Criteria", criteria_name)
+ return _get_variables(criteria)
+
+def _get_variables(criteria):
+ my_variables = []
+ regex = r"\{(.*?)\}"
+
+ mylist = re.finditer(regex, criteria.formula, re.MULTILINE | re.DOTALL)
+ for dummy1, match in enumerate(mylist):
+ for dummy2 in range(0, len(match.groups())):
+ try:
+ #var = frappe.get_doc("Supplier Scorecard Variable", {'param_name' : d})
+ var = frappe.db.sql("""
+ SELECT
+ scv.name
+ FROM
+ `tabSupplier Scorecard Variable` scv
+ WHERE
+ param_name=%(param)s""",
+ {'param':match.group(1)},)[0][0]
+ my_variables.append(var)
+ except Exception:
+ # Ignore the ones where the variable can't be found
+ frappe.throw(_('Unable to find variable: ') + str(match.group(1)), InvalidFormulaVariable)
+ #pass
+
+
+ #frappe.msgprint(str(my_variables))
+ return my_variables
diff --git a/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py b/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py
new file mode 100644
index 0000000000..4eef4b4e03
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestSupplierScorecardCriteria(unittest.TestCase):
+ def test_variables_exist(self):
+ delete_test_scorecards()
+ for d in test_good_criteria:
+ frappe.get_doc(d).insert()
+
+ self.assertRaises(frappe.ValidationError,frappe.get_doc(test_bad_criteria[0]).insert)
+
+ def test_formula_validate(self):
+ delete_test_scorecards()
+ self.assertRaises(frappe.ValidationError,frappe.get_doc(test_bad_criteria[1]).insert)
+ self.assertRaises(frappe.ValidationError,frappe.get_doc(test_bad_criteria[2]).insert)
+
+def delete_test_scorecards():
+ # Delete all the periods so we can delete all the criteria
+ frappe.db.sql("""delete from `tabSupplier Scorecard Period`""")
+ frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Criteria` where parenttype = 'Supplier Scorecard Period'""")
+ frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Standing` where parenttype = 'Supplier Scorecard Period'""")
+ frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Variable` where parenttype = 'Supplier Scorecard Period'""")
+
+ for d in test_good_criteria:
+ if frappe.db.exists("Supplier Scorecard Criteria", d.get("name")):
+ # Delete all the periods, then delete the scorecard
+ frappe.delete_doc(d.get("doctype"), d.get("name"))
+
+ for d in test_bad_criteria:
+ if frappe.db.exists("Supplier Scorecard Criteria", d.get("name")):
+ # Delete all the periods, then delete the scorecard
+ frappe.delete_doc(d.get("doctype"), d.get("name"))
+
+test_good_criteria = [
+ {
+ "name":"Delivery",
+ "weight":40.0,
+ "doctype":"Supplier Scorecard Criteria",
+ "formula":"(({cost_of_on_time_shipments} / {tot_cost_shipments}) if {tot_cost_shipments} > 0 else 1 )* 100",
+ "criteria_name":"Delivery",
+ "max_score":100.0
+ },
+]
+
+test_bad_criteria = [
+ {
+ "name":"Fake Criteria 1",
+ "weight":40.0,
+ "doctype":"Supplier Scorecard Criteria",
+ "formula":"(({fake_variable} / {tot_cost_shipments}) if {tot_cost_shipments} > 0 else 1 )* 100", # Invalid variable name
+ "criteria_name":"Fake Criteria 1",
+ "max_score":100.0
+ },
+ {
+ "name":"Fake Criteria 2",
+ "weight":40.0,
+ "doctype":"Supplier Scorecard Criteria",
+ "formula":"(({cost_of_on_time_shipments} / {tot_cost_shipments}))* 100", # Force 0 divided by 0
+ "criteria_name":"Fake Criteria 2",
+ "max_score":100.0
+ },
+ {
+ "name":"Fake Criteria 3",
+ "weight":40.0,
+ "doctype":"Supplier Scorecard Criteria",
+ "formula":"(({cost_of_on_time_shipments} {cost_of_on_time_shipments} / {tot_cost_shipments}))* 100", # Two variables beside eachother
+ "criteria_name":"Fake Criteria 3",
+ "max_score":100.0
+ },
+]
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_scorecard_period/__init__.py b/erpnext/buying/doctype/supplier_scorecard_period/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.js b/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.js
new file mode 100644
index 0000000000..c51e8ab2df
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.js
@@ -0,0 +1,14 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+/* global frappe */
+
+
+frappe.ui.form.on("Supplier Scorecard Period", {
+ onload: function(frm) {
+ frm.get_field("variables").grid.toggle_display("value", true);
+ frm.get_field("criteria").grid.toggle_display("score", true);
+
+
+ }
+});
diff --git a/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.json b/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.json
new file mode 100644
index 0000000000..0cf651454b
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.json
@@ -0,0 +1,397 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "naming_series:",
+ "beta": 1,
+ "creation": "2017-05-30 00:38:18.773013",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "supplier",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Supplier",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Supplier",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Naming Series",
+ "length": 0,
+ "no_copy": 0,
+ "options": "SSC-",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "total_score",
+ "fieldtype": "Percent",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Period Score",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "start_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Start Date",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "end_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "End Date",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 1,
+ "columns": 0,
+ "fieldname": "section_break_11",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Calculations",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "criteria",
+ "fieldtype": "Table",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Criteria",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Supplier Scorecard Scoring Criteria",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "variables",
+ "fieldtype": "Table",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Variables",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Supplier Scorecard Scoring Variable",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 1,
+ "columns": 0,
+ "fieldname": "sec_ref",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Reference",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "scorecard",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Supplier Scorecard Setup",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Supplier Scorecard",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 1,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-07-12 07:33:26.130861",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Supplier Scorecard Period",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 0,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.py b/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.py
new file mode 100644
index 0000000000..90b65bd35a
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.py
@@ -0,0 +1,133 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import throw, _
+from frappe.model.document import Document
+from frappe.model.mapper import get_mapped_doc
+import erpnext.buying.doctype.supplier_scorecard_variable.supplier_scorecard_variable as variable_functions
+
+class SupplierScorecardPeriod(Document):
+
+ def validate(self):
+ self.validate_criteria_weights()
+ self.calculate_variables()
+ self.calculate_criteria()
+ self.calculate_score()
+
+ def validate_criteria_weights(self):
+
+ weight = 0
+ for c in self.criteria:
+ weight += c.weight
+
+ if weight != 100:
+ throw(_('Criteria weights must add up to 100%'))
+
+ def calculate_variables(self):
+ for var in self.variables:
+
+ if '.' in var.path:
+ method_to_call = import_string_path(var.path)
+ var.value = method_to_call(self)
+ else:
+ method_to_call = getattr(variable_functions, var.path)
+ var.value = method_to_call(self)
+
+
+
+ def calculate_criteria(self):
+ #Get the criteria
+ for crit in self.criteria:
+
+ #me = ""
+ my_eval_statement = crit.formula.replace("\r", "").replace("\n", "")
+ #for let in my_eval_statement:
+ # me += let.encode('hex') + " "
+ #frappe.msgprint(me)
+
+ for var in self.variables:
+ if var.value:
+ if var.param_name in my_eval_statement:
+ my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', "{:.2f}".format(var.value))
+ else:
+ if var.param_name in my_eval_statement:
+ my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', '0.0')
+
+ #frappe.msgprint(my_eval_statement )
+
+ my_eval_statement = my_eval_statement.replace('<','<').replace('>','>')
+
+ try:
+ crit.score = min(crit.max_score, max( 0 ,frappe.safe_eval(my_eval_statement, None, {'max':max, 'min': min})))
+ except Exception:
+ frappe.throw(_("Could not solve criteria score function for {0}. Make sure the formula is valid.".format(crit.criteria_name)),frappe.ValidationError)
+ crit.score = 0
+
+ def calculate_score(self):
+ myscore = 0
+ for crit in self.criteria:
+ myscore += crit.score * crit.weight/100.0
+ self.total_score = myscore
+
+ def calculate_weighted_score(self, weighing_function):
+ my_eval_statement = weighing_function.replace("\r", "").replace("\n", "")
+
+ for var in self.variables:
+ if var.value:
+ if var.param_name in my_eval_statement:
+ my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', "{:.2f}".format(var.value))
+ else:
+ if var.param_name in my_eval_statement:
+ my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', '0.0')
+
+ my_eval_statement = my_eval_statement.replace('<','<').replace('>','>')
+
+ try:
+ weighed_score = frappe.safe_eval(my_eval_statement, None, {'max':max, 'min': min})
+ except Exception:
+ frappe.throw(_("Could not solve weighted score function. Make sure the formula is valid."),frappe.ValidationError)
+ weighed_score = 0
+ return weighed_score
+
+
+
+def import_string_path(path):
+ components = path.split('.')
+ mod = __import__(components[0])
+ for comp in components[1:]:
+ mod = getattr(mod, comp)
+ return mod
+
+
+def post_process(source, target):
+ pass
+
+
+@frappe.whitelist()
+def make_supplier_scorecard(source_name, target_doc=None):
+ #def update_item(obj, target, source_parent):
+ # target.qty = flt(obj.qty) - flt(obj.received_qty)
+ # target.stock_qty = (flt(obj.qty) - flt(obj.received_qty)) * flt(obj.conversion_factor)
+ # target.amount = (flt(obj.qty) - flt(obj.received_qty)) * flt(obj.rate)
+ # target.base_amount = (flt(obj.qty) - flt(obj.received_qty)) * \
+ # flt(obj.rate) * flt(source_parent.conversion_rate)
+
+ doc = get_mapped_doc("Supplier Scorecard", source_name, {
+ "Supplier Scorecard": {
+ "doctype": "Supplier Scorecard Period"
+ },
+ "Supplier Scorecard Scoring Variable": {
+ "doctype": "Supplier Scorecard Scoring Variable",
+ "add_if_empty": True
+ },
+ "Supplier Scorecard Scoring Constraint": {
+ "doctype": "Supplier Scorecard Scoring Constraint",
+ "add_if_empty": True
+ }
+ }, target_doc, post_process)
+
+ return doc
+
diff --git a/erpnext/buying/doctype/supplier_scorecard_period/test_supplier_scorecard_period.py b/erpnext/buying/doctype/supplier_scorecard_period/test_supplier_scorecard_period.py
new file mode 100644
index 0000000000..8baa3185ba
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_period/test_supplier_scorecard_period.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import unittest
+
+class TestSupplierScorecardPeriod(unittest.TestCase):
+ pass
diff --git a/erpnext/buying/doctype/supplier_scorecard_scoring_criteria/__init__.py b/erpnext/buying/doctype/supplier_scorecard_scoring_criteria/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/buying/doctype/supplier_scorecard_scoring_criteria/supplier_scorecard_scoring_criteria.json b/erpnext/buying/doctype/supplier_scorecard_scoring_criteria/supplier_scorecard_scoring_criteria.json
new file mode 100644
index 0000000000..567738a6d0
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_scoring_criteria/supplier_scorecard_scoring_criteria.json
@@ -0,0 +1,280 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 1,
+ "creation": "2017-05-29 01:32:17.988454",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 3,
+ "fieldname": "criteria_name",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Criteria Name",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Supplier Scorecard Criteria",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "section_break_2",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 2,
+ "fieldname": "weight",
+ "fieldtype": "Percent",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Criteria Weight",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "100",
+ "fieldname": "max_score",
+ "fieldtype": "Float",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Max Score",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "formula",
+ "fieldtype": "Small Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Criteria Formula",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "score",
+ "fieldtype": "Percent",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Score",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2017-07-12 07:33:41.532361",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Supplier Scorecard Scoring Criteria",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_scorecard_scoring_criteria/supplier_scorecard_scoring_criteria.py b/erpnext/buying/doctype/supplier_scorecard_scoring_criteria/supplier_scorecard_scoring_criteria.py
new file mode 100644
index 0000000000..b64abed8a6
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_scoring_criteria/supplier_scorecard_scoring_criteria.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+
+class SupplierScorecardScoringCriteria(Document):
+ pass
diff --git a/erpnext/buying/doctype/supplier_scorecard_scoring_standing/__init__.py b/erpnext/buying/doctype/supplier_scorecard_scoring_standing/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/buying/doctype/supplier_scorecard_scoring_standing/supplier_scorecard_scoring_standing.json b/erpnext/buying/doctype/supplier_scorecard_scoring_standing/supplier_scorecard_scoring_standing.json
new file mode 100644
index 0000000000..1fc04bb120
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_scoring_standing/supplier_scorecard_scoring_standing.json
@@ -0,0 +1,491 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 1,
+ "creation": "2017-05-29 01:36:22.697234",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 3,
+ "fieldname": "standing_name",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Standing Name",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Supplier Scorecard Standing",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "standing_color",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Color",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Blue\nPurple\nGreen\nYellow\nOrange\nRed",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 2,
+ "fieldname": "min_grade",
+ "fieldtype": "Percent",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Min Grade",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 2,
+ "fieldname": "max_grade",
+ "fieldtype": "Percent",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Max Grade",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "actions",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Actions",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "warn_rfqs",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Warn RFQs",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "warn_pos",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Warn Purchase Orders",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "prevent_rfqs",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Prevent RFQs",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "prevent_pos",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Prevent Purchase Orders",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_10",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "notify_supplier",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Notify Supplier",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "notify_employee",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Notify Employee",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "employee_link",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Employee ",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2017-07-12 07:33:20.615684",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Supplier Scorecard Scoring Standing",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_scorecard_scoring_standing/supplier_scorecard_scoring_standing.py b/erpnext/buying/doctype/supplier_scorecard_scoring_standing/supplier_scorecard_scoring_standing.py
new file mode 100644
index 0000000000..e8ad79f33d
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_scoring_standing/supplier_scorecard_scoring_standing.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+
+class SupplierScorecardScoringStanding(Document):
+ pass
diff --git a/erpnext/buying/doctype/supplier_scorecard_scoring_variable/__init__.py b/erpnext/buying/doctype/supplier_scorecard_scoring_variable/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/buying/doctype/supplier_scorecard_scoring_variable/supplier_scorecard_scoring_variable.json b/erpnext/buying/doctype/supplier_scorecard_scoring_variable/supplier_scorecard_scoring_variable.json
new file mode 100644
index 0000000000..f0e043e47a
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_scoring_variable/supplier_scorecard_scoring_variable.json
@@ -0,0 +1,222 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 1,
+ "creation": "2017-05-29 01:30:06.105240",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 3,
+ "fieldname": "variable_label",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Variable Name",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Supplier Scorecard Variable",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Description",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "is_custom",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Custom?",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "param_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Parameter Name",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "path",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Path",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 2,
+ "fieldname": "value",
+ "fieldtype": "Float",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Value",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2017-07-12 07:33:36.671502",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Supplier Scorecard Scoring Variable",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_scorecard_scoring_variable/supplier_scorecard_scoring_variable.py b/erpnext/buying/doctype/supplier_scorecard_scoring_variable/supplier_scorecard_scoring_variable.py
new file mode 100644
index 0000000000..58a8a99a09
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_scoring_variable/supplier_scorecard_scoring_variable.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+
+class SupplierScorecardScoringVariable(Document):
+ pass
diff --git a/erpnext/buying/doctype/supplier_scorecard_standing/__init__.py b/erpnext/buying/doctype/supplier_scorecard_standing/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.js b/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.js
new file mode 100644
index 0000000000..dccfcc34bb
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.js
@@ -0,0 +1,10 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+/* global frappe */
+
+frappe.ui.form.on("Supplier Scorecard Standing", {
+ refresh: function() {
+
+ }
+});
diff --git a/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.json b/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.json
new file mode 100644
index 0000000000..b61b4edd72
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.json
@@ -0,0 +1,424 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "field:standing_name",
+ "beta": 1,
+ "creation": "2017-05-29 01:36:47.893639",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "standing_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Standing Name",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 1
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "standing_color",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Color",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Blue\nPurple\nGreen\nYellow\nOrange\nRed",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "min_grade",
+ "fieldtype": "Percent",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Min Grade",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "max_grade",
+ "fieldtype": "Percent",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Max Grade",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "warn_rfqs",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Warn RFQs",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "warn_pos",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Warn Purchase Orders",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "prevent_rfqs",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Prevent RFQs",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "prevent_pos",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Prevent Purchase Orders",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "notify_supplier",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Notify Supplier",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "notify_employee",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Notify Other",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "employee_link",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Other",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-07-12 07:33:16.560273",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Supplier Scorecard Standing",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 0,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.py b/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.py
new file mode 100644
index 0000000000..1ba5d06c53
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class SupplierScorecardStanding(Document):
+ pass
+
+
+@frappe.whitelist()
+def get_scoring_standing(standing_name):
+ standing = frappe.get_doc("Supplier Scorecard Standing", standing_name)
+
+ return standing
+
+
+@frappe.whitelist()
+def get_standings_list():
+ standings = frappe.db.sql("""
+ SELECT
+ scs.name
+ FROM
+ `tabSupplier Scorecard Standing` scs""",
+ {}, as_dict=1)
+
+ return standings
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_scorecard_standing/test_supplier_scorecard_standing.py b/erpnext/buying/doctype/supplier_scorecard_standing/test_supplier_scorecard_standing.py
new file mode 100644
index 0000000000..4d96651313
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_standing/test_supplier_scorecard_standing.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import unittest
+
+class TestSupplierScorecardStanding(unittest.TestCase):
+ pass
diff --git a/erpnext/buying/doctype/supplier_scorecard_variable/__init__.py b/erpnext/buying/doctype/supplier_scorecard_variable/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.js b/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.js
new file mode 100644
index 0000000000..2d74fdd190
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.js
@@ -0,0 +1,10 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+/* global frappe */
+
+frappe.ui.form.on("Supplier Scorecard Variable", {
+ refresh: function() {
+
+ }
+});
diff --git a/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.json b/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.json
new file mode 100644
index 0000000000..d24484025c
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.json
@@ -0,0 +1,242 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "field:variable_label",
+ "beta": 1,
+ "creation": "2017-05-29 01:30:34.688389",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "variable_label",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Variable Name",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 1
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "is_custom",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Custom?",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "param_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Parameter Name",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "path",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Path",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Description",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-07-12 07:33:31.395262",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Supplier Scorecard Variable",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.py b/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.py
new file mode 100644
index 0000000000..17c911a000
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.py
@@ -0,0 +1,503 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+import sys
+from frappe import _
+from frappe.model.document import Document
+from frappe.utils import getdate
+
+class VariablePathNotFound(frappe.ValidationError): pass
+
+class SupplierScorecardVariable(Document):
+ def validate(self):
+ self.validate_path_exists()
+
+ def validate_path_exists(self):
+ if '.' in self.path:
+ try:
+ from erpnext.buying.doctype.supplier_scorecard_period.supplier_scorecard_period import import_string_path
+ import_string_path(self.path)
+ except AttributeError:
+ frappe.throw(_("Could not find path for " + self.path), VariablePathNotFound)
+
+ else:
+ if not hasattr(sys.modules[__name__], self.path):
+ frappe.throw(_("Could not find path for " + self.path), VariablePathNotFound)
+
+
+@frappe.whitelist()
+def get_scoring_variable(variable_label):
+ variable = frappe.get_doc("Supplier Scorecard Variable", variable_label)
+
+ return variable
+
+def get_total_workdays(scorecard):
+ """ Gets the number of days in this period"""
+ delta = getdate(scorecard.end_date) - getdate(scorecard.start_date)
+ return delta.days
+
+def get_item_workdays(scorecard):
+ """ Gets the number of days in this period"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+ total_item_days = frappe.db.sql("""
+ SELECT
+ SUM(DATEDIFF( %(end_date)s, po_item.schedule_date) * (po_item.qty))
+ FROM
+ `tabPurchase Order Item` po_item,
+ `tabPurchase Order` po
+ WHERE
+ po.supplier = %(supplier)s
+ AND po_item.received_qty < po_item.qty
+ AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
+ AND po_item.parent = po.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+
+ if not total_item_days:
+ total_item_days = 0
+ return total_item_days
+
+
+
+def get_total_cost_of_shipments(scorecard):
+ """ Gets the total cost of all shipments in the period (based on Purchase Orders)"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+
+ # Look up all PO Items with delivery dates between our dates
+ data = frappe.db.sql("""
+ SELECT
+ SUM(po_item.base_amount)
+ FROM
+ `tabPurchase Order Item` po_item,
+ `tabPurchase Order` po
+ WHERE
+ po.supplier = %(supplier)s
+ AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
+ AND po_item.docstatus = 1
+ AND po_item.parent = po.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+
+ if data:
+ return data
+ else:
+ return 0
+
+def get_cost_of_delayed_shipments(scorecard):
+ """ Gets the total cost of all delayed shipments in the period (based on Purchase Receipts - POs)"""
+ return get_total_cost_of_shipments(scorecard) - get_cost_of_on_time_shipments(scorecard)
+
+def get_cost_of_on_time_shipments(scorecard):
+ """ Gets the total cost of all on_time shipments in the period (based on Purchase Receipts)"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+
+ # Look up all PO Items with delivery dates between our dates
+
+ total_delivered_on_time_costs = frappe.db.sql("""
+ SELECT
+ SUM(pr_item.base_amount)
+ FROM
+ `tabPurchase Order Item` po_item,
+ `tabPurchase Receipt Item` pr_item,
+ `tabPurchase Order` po,
+ `tabPurchase Receipt` pr
+ WHERE
+ po.supplier = %(supplier)s
+ AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
+ AND po_item.schedule_date >= pr.posting_date
+ AND pr_item.docstatus = 1
+ AND pr_item.purchase_order_item = po_item.name
+ AND po_item.parent = po.name
+ AND pr_item.parent = pr.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+
+ if total_delivered_on_time_costs:
+ return total_delivered_on_time_costs
+ else:
+ return 0
+
+
+def get_total_days_late(scorecard):
+ """ Gets the number of item days late in the period (based on Purchase Receipts vs POs)"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+ total_delivered_late_days = frappe.db.sql("""
+ SELECT
+ SUM(DATEDIFF(pr.posting_date,po_item.schedule_date)* pr_item.qty)
+ FROM
+ `tabPurchase Order Item` po_item,
+ `tabPurchase Receipt Item` pr_item,
+ `tabPurchase Order` po,
+ `tabPurchase Receipt` pr
+ WHERE
+ po.supplier = %(supplier)s
+ AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
+ AND po_item.schedule_date < pr.posting_date
+ AND pr_item.docstatus = 1
+ AND pr_item.purchase_order_item = po_item.name
+ AND po_item.parent = po.name
+ AND pr_item.parent = pr.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+ if not total_delivered_late_days:
+ total_delivered_late_days = 0
+
+ total_missed_late_days = frappe.db.sql("""
+ SELECT
+ SUM(DATEDIFF( %(end_date)s, po_item.schedule_date) * (po_item.qty - po_item.received_qty))
+ FROM
+ `tabPurchase Order Item` po_item,
+ `tabPurchase Order` po
+ WHERE
+ po.supplier = %(supplier)s
+ AND po_item.received_qty < po_item.qty
+ AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
+ AND po_item.parent = po.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+
+ if not total_missed_late_days:
+ total_missed_late_days = 0
+ return total_missed_late_days + total_delivered_late_days
+
+def get_on_time_shipments(scorecard):
+ """ Gets the number of late shipments (counting each item) in the period (based on Purchase Receipts vs POs)"""
+
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+
+ # Look up all PO Items with delivery dates between our dates
+ total_items_delivered_on_time = frappe.db.sql("""
+ SELECT
+ COUNT(pr_item.qty)
+ FROM
+ `tabPurchase Order Item` po_item,
+ `tabPurchase Receipt Item` pr_item,
+ `tabPurchase Order` po,
+ `tabPurchase Receipt` pr
+ WHERE
+ po.supplier = %(supplier)s
+ AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
+ AND po_item.schedule_date <= pr.posting_date
+ AND po_item.qty = pr_item.qty
+ AND pr_item.docstatus = 1
+ AND pr_item.purchase_order_item = po_item.name
+ AND po_item.parent = po.name
+ AND pr_item.parent = pr.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+
+ if not total_items_delivered_on_time:
+ total_items_delivered_on_time = 0
+ return total_items_delivered_on_time
+
+def get_late_shipments(scorecard):
+ """ Gets the number of late shipments (counting each item) in the period (based on Purchase Receipts vs POs)"""
+ return get_total_shipments(scorecard) - get_on_time_shipments(scorecard)
+
+def get_total_received(scorecard):
+ """ Gets the total number of received shipments in the period (based on Purchase Receipts)"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+
+ # Look up all PO Items with delivery dates between our dates
+ data = frappe.db.sql("""
+ SELECT
+ COUNT(pr_item.base_amount)
+ FROM
+ `tabPurchase Receipt Item` pr_item,
+ `tabPurchase Receipt` pr
+ WHERE
+ pr.supplier = %(supplier)s
+ AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
+ AND pr_item.docstatus = 1
+ AND pr_item.parent = pr.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+
+ if not data:
+ data = 0
+ return data
+
+def get_total_received_amount(scorecard):
+ """ Gets the total amount (in company currency) received in the period (based on Purchase Receipts)"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+
+ # Look up all PO Items with delivery dates between our dates
+ data = frappe.db.sql("""
+ SELECT
+ SUM(pr_item.received_qty * pr_item.base_rate)
+ FROM
+ `tabPurchase Receipt Item` pr_item,
+ `tabPurchase Receipt` pr
+ WHERE
+ pr.supplier = %(supplier)s
+ AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
+ AND pr_item.docstatus = 1
+ AND pr_item.parent = pr.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+
+ if not data:
+ data = 0
+ return data
+
+def get_total_received_items(scorecard):
+ """ Gets the total number of received shipments in the period (based on Purchase Receipts)"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+
+ # Look up all PO Items with delivery dates between our dates
+ data = frappe.db.sql("""
+ SELECT
+ SUM(pr_item.received_qty)
+ FROM
+ `tabPurchase Receipt Item` pr_item,
+ `tabPurchase Receipt` pr
+ WHERE
+ pr.supplier = %(supplier)s
+ AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
+ AND pr_item.docstatus = 1
+ AND pr_item.parent = pr.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+
+ if not data:
+ data = 0
+ return data
+
+def get_total_rejected_amount(scorecard):
+ """ Gets the total amount (in company currency) rejected in the period (based on Purchase Receipts)"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+
+ # Look up all PO Items with delivery dates between our dates
+ data = frappe.db.sql("""
+ SELECT
+ SUM(pr_item.rejected_qty * pr_item.base_rate)
+ FROM
+ `tabPurchase Receipt Item` pr_item,
+ `tabPurchase Receipt` pr
+ WHERE
+ pr.supplier = %(supplier)s
+ AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
+ AND pr_item.docstatus = 1
+ AND pr_item.parent = pr.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+
+ if not data:
+ data = 0
+ return data
+
+def get_total_rejected_items(scorecard):
+ """ Gets the total number of rejected items in the period (based on Purchase Receipts)"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+
+ # Look up all PO Items with delivery dates between our dates
+ data = frappe.db.sql("""
+ SELECT
+ SUM(pr_item.rejected_qty)
+ FROM
+ `tabPurchase Receipt Item` pr_item,
+ `tabPurchase Receipt` pr
+ WHERE
+ pr.supplier = %(supplier)s
+ AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
+ AND pr_item.docstatus = 1
+ AND pr_item.parent = pr.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+
+ if not data:
+ data = 0
+ return data
+
+def get_total_accepted_amount(scorecard):
+ """ Gets the total amount (in company currency) accepted in the period (based on Purchase Receipts)"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+
+ # Look up all PO Items with delivery dates between our dates
+ data = frappe.db.sql("""
+ SELECT
+ SUM(pr_item.qty * pr_item.base_rate)
+ FROM
+ `tabPurchase Receipt Item` pr_item,
+ `tabPurchase Receipt` pr
+ WHERE
+ pr.supplier = %(supplier)s
+ AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
+ AND pr_item.docstatus = 1
+ AND pr_item.parent = pr.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+
+ if not data:
+ data = 0
+ return data
+
+def get_total_accepted_items(scorecard):
+ """ Gets the total number of rejected items in the period (based on Purchase Receipts)"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+
+ # Look up all PO Items with delivery dates between our dates
+ data = frappe.db.sql("""
+ SELECT
+ SUM(pr_item.qty)
+ FROM
+ `tabPurchase Receipt Item` pr_item,
+ `tabPurchase Receipt` pr
+ WHERE
+ pr.supplier = %(supplier)s
+ AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
+ AND pr_item.docstatus = 1
+ AND pr_item.parent = pr.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+
+ if not data:
+ data = 0
+ return data
+
+def get_total_shipments(scorecard):
+ """ Gets the total number of ordered shipments to arrive in the period (based on Purchase Receipts)"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+
+ # Look up all PO Items with delivery dates between our dates
+ data = frappe.db.sql("""
+ SELECT
+ COUNT(po_item.base_amount)
+ FROM
+ `tabPurchase Order Item` po_item,
+ `tabPurchase Order` po
+ WHERE
+ po.supplier = %(supplier)s
+ AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
+ AND po_item.docstatus = 1
+ AND po_item.parent = po.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+
+ if not data:
+ data = 0
+ return data
+
+def get_rfq_total_number(scorecard):
+ """ Gets the total number of RFQs sent to supplier"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+
+ # Look up all PO Items with delivery dates between our dates
+ data = frappe.db.sql("""
+ SELECT
+ COUNT(rfq.name) as total_rfqs
+ FROM
+ `tabRequest for Quotation Item` rfq_item,
+ `tabRequest for Quotation Supplier` rfq_sup,
+ `tabRequest for Quotation` rfq
+ WHERE
+ rfq_sup.supplier = %(supplier)s
+ AND rfq.transaction_date BETWEEN %(start_date)s AND %(end_date)s
+ AND rfq_item.docstatus = 1
+ AND rfq_item.parent = rfq.name
+ AND rfq_sup.parent = rfq.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+
+ if not data:
+ data = 0
+ return data
+
+def get_rfq_total_items(scorecard):
+ """ Gets the total number of RFQ items sent to supplier"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+
+ # Look up all PO Items with delivery dates between our dates
+ data = frappe.db.sql("""
+ SELECT
+ COUNT(rfq_item.name) as total_rfqs
+ FROM
+ `tabRequest for Quotation Item` rfq_item,
+ `tabRequest for Quotation Supplier` rfq_sup,
+ `tabRequest for Quotation` rfq
+ WHERE
+ rfq_sup.supplier = %(supplier)s
+ AND rfq.transaction_date BETWEEN %(start_date)s AND %(end_date)s
+ AND rfq_item.docstatus = 1
+ AND rfq_item.parent = rfq.name
+ AND rfq_sup.parent = rfq.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+ if not data:
+ data = 0
+ return data
+
+
+def get_sq_total_number(scorecard):
+ """ Gets the total number of RFQ items sent to supplier"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+
+ # Look up all PO Items with delivery dates between our dates
+ data = frappe.db.sql("""
+ SELECT
+ COUNT(sq.name) as total_sqs
+ FROM
+ `tabRequest for Quotation Item` rfq_item,
+ `tabSupplier Quotation Item` sq_item,
+ `tabRequest for Quotation Supplier` rfq_sup,
+ `tabRequest for Quotation` rfq,
+ `tabSupplier Quotation` sq
+ WHERE
+ rfq_sup.supplier = %(supplier)s
+ AND rfq.transaction_date BETWEEN %(start_date)s AND %(end_date)s
+ AND sq_item.request_for_quotation_item = rfq_item.name
+ AND sq_item.docstatus = 1
+ AND rfq_item.docstatus = 1
+ AND sq.supplier = %(supplier)s
+ AND sq_item.parent = sq.name
+ AND rfq_item.parent = rfq.name
+ AND rfq_sup.parent = rfq.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+ if not data:
+ data = 0
+ return data
+
+def get_sq_total_items(scorecard):
+ """ Gets the total number of RFQ items sent to supplier"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+
+ # Look up all PO Items with delivery dates between our dates
+ data = frappe.db.sql("""
+ SELECT
+ COUNT(sq_item.name) as total_sqs
+ FROM
+ `tabRequest for Quotation Item` rfq_item,
+ `tabSupplier Quotation Item` sq_item,
+ `tabSupplier Quotation` sq,
+ `tabRequest for Quotation Supplier` rfq_sup,
+ `tabRequest for Quotation` rfq
+ WHERE
+ rfq_sup.supplier = %(supplier)s
+ AND rfq.transaction_date BETWEEN %(start_date)s AND %(end_date)s
+ AND sq_item.request_for_quotation_item = rfq_item.name
+ AND sq_item.docstatus = 1
+ AND sq.supplier = %(supplier)s
+ AND sq_item.parent = sq.name
+ AND rfq_item.docstatus = 1
+ AND rfq_item.parent = rfq.name
+ AND rfq_sup.parent = rfq.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+ if not data:
+ data = 0
+ return data
+
+def get_rfq_response_days(scorecard):
+ """ Gets the total number of days it has taken a supplier to respond to rfqs in the period"""
+ supplier = frappe.get_doc('Supplier', scorecard.supplier)
+ total_sq_days = frappe.db.sql("""
+ SELECT
+ SUM(DATEDIFF(sq.transaction_date, rfq.transaction_date))
+ FROM
+ `tabRequest for Quotation Item` rfq_item,
+ `tabSupplier Quotation Item` sq_item,
+ `tabSupplier Quotation` sq,
+ `tabRequest for Quotation Supplier` rfq_sup,
+ `tabRequest for Quotation` rfq
+ WHERE
+ rfq_sup.supplier = %(supplier)s
+ AND rfq.transaction_date BETWEEN %(start_date)s AND %(end_date)s
+ AND sq_item.request_for_quotation_item = rfq_item.name
+ AND sq_item.docstatus = 1
+ AND sq.supplier = %(supplier)s
+ AND sq_item.parent = sq.name
+ AND rfq_item.docstatus = 1
+ AND rfq_item.parent = rfq.name
+ AND rfq_sup.parent = rfq.name""",
+ {"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
+ if not total_sq_days:
+ total_sq_days = 0
+
+
+ return total_sq_days
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py b/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py
new file mode 100644
index 0000000000..45a2c6250a
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+from erpnext.buying.doctype.supplier_scorecard_variable.supplier_scorecard_variable import VariablePathNotFound
+
+
+class TestSupplierScorecardVariable(unittest.TestCase):
+ def test_variable_exist(self):
+ for d in test_existing_variables:
+ my_doc = frappe.get_doc("Supplier Scorecard Variable", d.get("name"))
+ self.assertEquals(my_doc.param_name, d.get('param_name'))
+ self.assertEquals(my_doc.variable_label, d.get('variable_label'))
+ self.assertEquals(my_doc.path, d.get('path'))
+
+ def test_path_exists(self):
+ for d in test_good_variables:
+ if frappe.db.exists(d):
+ frappe.delete_doc(d.get("doctype"), d.get("name"))
+ frappe.get_doc(d).insert()
+
+ for d in test_bad_variables:
+ self.assertRaises(VariablePathNotFound,frappe.get_doc(d).insert)
+
+test_existing_variables = [
+ {
+ "param_name":"total_accepted_items",
+ "name":"Total Accepted Items",
+ "doctype":"Supplier Scorecard Variable",
+ "variable_label":"Total Accepted Items",
+ "path":"get_total_accepted_items"
+ },
+]
+
+test_good_variables = [
+ {
+ "param_name":"good_variable1",
+ "name":"Good Variable 1",
+ "doctype":"Supplier Scorecard Variable",
+ "variable_label":"Good Variable 1",
+ "path":"get_total_accepted_items"
+ },
+]
+
+test_bad_variables = [
+ {
+ "param_name":"fake_variable1",
+ "name":"Fake Variable 1",
+ "doctype":"Supplier Scorecard Variable",
+ "variable_label":"Fake Variable 1",
+ "path":"get_fake_variable1"
+ },
+]
\ No newline at end of file
diff --git a/erpnext/config/buying.py b/erpnext/config/buying.py
index 990ca7a8ba..ba29125ca0 100644
--- a/erpnext/config/buying.py
+++ b/erpnext/config/buying.py
@@ -141,6 +141,32 @@ def get_data():
},
]
},
+ {
+ "label": _("Supplier Scorecard"),
+ "items": [
+ {
+ "type": "doctype",
+ "name": "Supplier Scorecard",
+ "description": _("All Supplier scorecards."),
+ },
+ {
+ "type": "doctype",
+ "name": "Supplier Scorecard Variable",
+ "description": _("Templates of supplier scorecard variables.")
+ },
+ {
+ "type": "doctype",
+ "name": "Supplier Scorecard Criteria",
+ "description": _("Templates of supplier scorecard criteria."),
+ },
+ {
+ "type": "doctype",
+ "name": "Supplier Scorecard Standing",
+ "description": _("Templates of supplier standings."),
+ },
+
+ ]
+ },
{
"label": _("Other Reports"),
"icon": "fa fa-list",
diff --git a/erpnext/docs/assets/img/buying/supplier-scorecard-criteria.png b/erpnext/docs/assets/img/buying/supplier-scorecard-criteria.png
new file mode 100644
index 0000000000..0bc73c81ee
Binary files /dev/null and b/erpnext/docs/assets/img/buying/supplier-scorecard-criteria.png differ
diff --git a/erpnext/docs/assets/img/buying/supplier-scorecard-standing.png b/erpnext/docs/assets/img/buying/supplier-scorecard-standing.png
new file mode 100644
index 0000000000..8c507cb77f
Binary files /dev/null and b/erpnext/docs/assets/img/buying/supplier-scorecard-standing.png differ
diff --git a/erpnext/docs/assets/img/buying/supplier-scorecard-weighing.png b/erpnext/docs/assets/img/buying/supplier-scorecard-weighing.png
new file mode 100644
index 0000000000..d32e69e2fc
Binary files /dev/null and b/erpnext/docs/assets/img/buying/supplier-scorecard-weighing.png differ
diff --git a/erpnext/docs/assets/img/buying/supplier-scorecard.png b/erpnext/docs/assets/img/buying/supplier-scorecard.png
new file mode 100644
index 0000000000..1f8de1736d
Binary files /dev/null and b/erpnext/docs/assets/img/buying/supplier-scorecard.png differ
diff --git a/erpnext/docs/user/manual/en/buying/index.txt b/erpnext/docs/user/manual/en/buying/index.txt
index 25c8797e18..4bd75f1047 100644
--- a/erpnext/docs/user/manual/en/buying/index.txt
+++ b/erpnext/docs/user/manual/en/buying/index.txt
@@ -5,3 +5,4 @@ purchase-order
setup
articles
purchase-taxes
+supplier-scorecard
\ No newline at end of file
diff --git a/erpnext/docs/user/manual/en/buying/supplier-scorecard.md b/erpnext/docs/user/manual/en/buying/supplier-scorecard.md
new file mode 100644
index 0000000000..cecdf9cd21
--- /dev/null
+++ b/erpnext/docs/user/manual/en/buying/supplier-scorecard.md
@@ -0,0 +1,76 @@
+A Supplier Scorecard is an evaluation tool used to assess the performance of
+suppliers. Supplier scorecards can be used to keep track of item quality,
+delivery and responsiveness of suppliers across long periods of time. This data
+is typically used to help in purchasing decisions.
+
+A Supplier Scorecard is manually created for each supplier.
+
+In ERPNext, you can create a supplier scorecard by going to:
+
+> Buying > Documents > Supplier Scorecard > New Supplier Scorecard
+
+### Create Supplier Scorecard
+A supplier scorecard is created for each supplier individually. Only one supplier scorecard can be created for each
+supplier.
+
+
+#### Final Score and Standings
+The supplier scorecard consists of a set evaluation periods, during which the performance of a supplier is
+evaluated. This period can be daily, monthly or yearly. The current score is calculated from the score of each evaluation
+period based on the weighting function. The default formula is linearly weight over the previous 12 scoring periods.
+
+This formula is customizable.
+
+The supplier standing is used to quickly sort suppliers based on their performance. These are customizable for each supplier.
+The scorecard standing of a supplier can also be used to restrict suppliers from being included in Request for Quotations or
+being issued Purchase Orders.
+
+
+#### Evaluation Criteria and Variables
+A supplier can be evaluated on several individual evaluation criteria, including (but not limited to) quotation response time,
+delivered item quality, and delivery timeliness. These criteria are weighed to determine the final period score.
+
+The method for calculating each criteria is determined through the criteria formula field, which can use a number of pre-established variables.
+The value of each of these variables is calculated over the scoring period for each supplier. Examples of such variables include:
+ - The total number of items received from the supplier
+ - The total number of accepted items from the supplier
+ - The total number of rejected items from the supplier
+ - The total number of deliveries from the supplier
+ - The total amount (in dollars) received from a supplier
+Additional variables can be added through server-side customizations.
+
+The criteria formula should be customized to evaluate the suppliers in each criteria in a way that best fits the Company requirements.
+
+##### Evaluation Formulas
+The evaluation formula uses the pre-established or custom variables to evaluate an aspect of supplier performance over the scoring period. Formulas can use the following mathematical functions:
+
+* addition: +
+* subtraction: -
+* multiplication: *
+* division: /
+* min: min(x,y)
+* max: max(x,y)
+* if/else: (x) if (formula) else (y)
+* less than: <
+* greated than: >
+* variables: {variable_name}
+
+It is crucial that the formula be solvable for all variable values. This is most often an issue if the value resolves to 0. For example:
+```
+{total_accepted_items} / {total_received_items}
+```
+
+This example would resolve to 0 / 0 in periods where there are no received items, and therefore should have a check to protect in this case:
+```
+({total_accepted_items} / {total_received_items}) if {total_received_items} > 0 else 1.
+```
+
+### Evaluating the Supplier
+An evaluation is generated for each Supplier Scorecard Period by clicking the "Generate Missing Scorecard Periods" button. The supplier
+current score can be seen, as well as a visual graphic showing the performance of the supplier over time. Any actions against the supplier
+are also noted here, including warnings when create RFQs and POs or locking out those features for this supplier altogether.
+
+
+
+
+{next}
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 5f0b19ebd7..860aac2ee7 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -191,6 +191,7 @@ scheduler_events = {
"erpnext.accounts.doctype.asset.depreciation.post_depreciation_entries",
"erpnext.hr.doctype.daily_work_summary_settings.daily_work_summary_settings.send_summary",
"erpnext.stock.doctype.serial_no.serial_no.update_maintenance_status",
+ "erpnext.buying.doctype.supplier_scorecard.supplier_scorecard.refresh_scorecards",
"erpnext.setup.doctype.company.company.cache_companies_monthly_sales_history"
]
}
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 834ed2fdf4..00f395fe8c 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -422,6 +422,7 @@ erpnext.patches.v8_1.add_indexes_in_transaction_doctypes
erpnext.patches.v8_3.set_restrict_to_domain_for_module_def
erpnext.patches.v8_1.update_expense_claim_status
erpnext.patches.v8_3.update_company_total_sales
+erpnext.patches.v8_4.make_scorecard_records
erpnext.patches.v8_1.set_delivery_date_in_so_item
erpnext.patches.v8_5.fix_tax_breakup_for_non_invoice_docs
-erpnext.patches.v8_5.remove_quotations_route_in_sidebar
\ No newline at end of file
+erpnext.patches.v8_5.remove_quotations_route_in_sidebar
diff --git a/erpnext/patches/v8_4/__init__.py b/erpnext/patches/v8_4/__init__.py
new file mode 100644
index 0000000000..baffc48825
--- /dev/null
+++ b/erpnext/patches/v8_4/__init__.py
@@ -0,0 +1 @@
+from __future__ import unicode_literals
diff --git a/erpnext/patches/v8_4/make_scorecard_records.py b/erpnext/patches/v8_4/make_scorecard_records.py
new file mode 100644
index 0000000000..37789d711a
--- /dev/null
+++ b/erpnext/patches/v8_4/make_scorecard_records.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import make_default_records
+def execute():
+
+ make_default_records()
\ No newline at end of file
diff --git a/erpnext/setup/setup_wizard/install_fixtures.py b/erpnext/setup/setup_wizard/install_fixtures.py
index 43baf2f4fb..1301d33856 100644
--- a/erpnext/setup/setup_wizard/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/install_fixtures.py
@@ -213,6 +213,10 @@ def install(country=None):
records += [{'doctype': 'Lead Source', 'source_name': _(d)} for d in default_lead_sources]
+ # Records for the Supplier Scorecard
+ from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import make_default_records
+ make_default_records()
+
from frappe.modules import scrub
for r in records:
doc = frappe.new_doc(r.get("doctype"))