Merge branch 'develop' into project-template-and-tasks
This commit is contained in:
commit
8a07de9ee0
@ -6,6 +6,7 @@ import unittest
|
||||
|
||||
from erpnext.stock.doctype.item.test_item import set_item_variant_settings
|
||||
from erpnext.controllers.item_variant import copy_attributes_to_variant, make_variant_item_code
|
||||
from erpnext.stock.doctype.quality_inspection.test_quality_inspection import create_quality_inspection_parameter
|
||||
|
||||
from six import string_types
|
||||
|
||||
@ -56,6 +57,8 @@ def make_quality_inspection_template():
|
||||
|
||||
qc = frappe.new_doc("Quality Inspection Template")
|
||||
qc.quality_inspection_template_name = qc_template
|
||||
|
||||
create_quality_inspection_parameter("Moisture")
|
||||
qc.append('item_quality_inspection_parameter', {
|
||||
"specification": "Moisture",
|
||||
"value": "< 5%",
|
||||
|
@ -744,3 +744,4 @@ erpnext.patches.v13_0.add_po_to_global_search
|
||||
erpnext.patches.v13_0.update_returned_qty_in_pr_dn
|
||||
erpnext.patches.v13_0.update_project_template_tasks
|
||||
erpnext.patches.v13_0.set_company_in_leave_ledger_entry
|
||||
erpnext.patches.v13_0.convert_qi_parameter_to_link_field
|
||||
|
23
erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py
Normal file
23
erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py
Normal file
@ -0,0 +1,23 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc('stock', 'doctype', 'quality_inspection_parameter')
|
||||
|
||||
# get all distinct parameters from QI readigs table
|
||||
reading_params = frappe.db.get_all("Quality Inspection Reading", fields=["distinct specification"])
|
||||
reading_params = [d.specification for d in reading_params]
|
||||
|
||||
# get all distinct parameters from QI Template as some may be unused in QI
|
||||
template_params = frappe.db.get_all("Item Quality Inspection Parameter", fields=["distinct specification"])
|
||||
template_params = [d.specification for d in template_params]
|
||||
|
||||
params = list(set(reading_params + template_params))
|
||||
|
||||
for parameter in params:
|
||||
if not frappe.db.exists("Quality Inspection Parameter", parameter):
|
||||
frappe.get_doc({
|
||||
"doctype": "Quality Inspection Parameter",
|
||||
"parameter": parameter,
|
||||
"description": parameter
|
||||
}).insert(ignore_permissions=True)
|
@ -577,7 +577,7 @@ class SalarySlip(TransactionBase):
|
||||
'default_amount': amount if not struct_row.get("is_additional_component") else 0,
|
||||
'depends_on_payment_days' : struct_row.depends_on_payment_days,
|
||||
'salary_component' : struct_row.salary_component,
|
||||
'abbr' : struct_row.abbr,
|
||||
'abbr' : struct_row.abbr or struct_row.get("salary_component_abbr"),
|
||||
'additional_salary': additional_salary,
|
||||
'do_not_include_in_total' : struct_row.do_not_include_in_total,
|
||||
'is_tax_applicable': struct_row.is_tax_applicable,
|
||||
|
@ -8,26 +8,32 @@
|
||||
"field_order": [
|
||||
"specification",
|
||||
"value",
|
||||
"non_numeric",
|
||||
"column_break_3",
|
||||
"min_value",
|
||||
"max_value",
|
||||
"formula_based_criteria",
|
||||
"acceptance_formula"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "specification",
|
||||
"fieldtype": "Data",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Parameter",
|
||||
"oldfieldname": "specification",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "Quality Inspection Parameter",
|
||||
"print_width": "200px",
|
||||
"reqd": 1,
|
||||
"width": "200px"
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:(!doc.formula_based_criteria && doc.non_numeric)",
|
||||
"fieldname": "value",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Acceptance Criteria",
|
||||
"label": "Acceptance Criteria Value",
|
||||
"oldfieldname": "value",
|
||||
"oldfieldtype": "Data"
|
||||
},
|
||||
@ -36,17 +42,45 @@
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"description": "Simple Python formula based on numeric Readings.<br> Example 1: <b>reading_1 > 0.2 and reading_1 < 0.5</b><br>\nExample 2: <b>(reading_1 + reading_2) / 2 < 10</b>",
|
||||
"depends_on": "formula_based_criteria",
|
||||
"description": "Simple Python formula applied on Reading fields.<br> Numeric eg. 1: <b>reading_1 > 0.2 and reading_1 < 0.5</b><br>\nNumeric eg. 2: <b>mean > 3.5</b> (mean of populated fields)<br>\nValue based eg.: <b>reading_value in (\"A\", \"B\", \"C\")</b>",
|
||||
"fieldname": "acceptance_formula",
|
||||
"fieldtype": "Code",
|
||||
"in_list_view": 1,
|
||||
"label": "Acceptance Criteria Formula"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "formula_based_criteria",
|
||||
"fieldtype": "Check",
|
||||
"label": "Formula Based Criteria"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:(!doc.formula_based_criteria && !doc.non_numeric)",
|
||||
"fieldname": "min_value",
|
||||
"fieldtype": "Float",
|
||||
"in_list_view": 1,
|
||||
"label": "Minimum Value"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:(!doc.formula_based_criteria && !doc.non_numeric)",
|
||||
"fieldname": "max_value",
|
||||
"fieldtype": "Float",
|
||||
"in_list_view": 1,
|
||||
"label": "Maximum Value"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "non_numeric",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Non-Numeric",
|
||||
"width": "80px"
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-11-16 16:33:42.421842",
|
||||
"modified": "2021-01-07 21:32:49.866439",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Item Quality Inspection Parameter",
|
||||
|
@ -4,6 +4,55 @@
|
||||
cur_frm.cscript.refresh = cur_frm.cscript.inspection_type;
|
||||
|
||||
frappe.ui.form.on("Quality Inspection", {
|
||||
|
||||
setup: function(frm) {
|
||||
frm.set_query("batch_no", function() {
|
||||
return {
|
||||
filters: {
|
||||
"item": frm.doc.item_code
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// Serial No based on item_code
|
||||
frm.set_query("item_serial_no", function() {
|
||||
let filters = {};
|
||||
if (frm.doc.item_code) {
|
||||
filters = {
|
||||
'item_code': frm.doc.item_code
|
||||
};
|
||||
}
|
||||
return { filters: filters };
|
||||
});
|
||||
|
||||
// item code based on GRN/DN
|
||||
frm.set_query("item_code", function(doc) {
|
||||
let doctype = doc.reference_type;
|
||||
|
||||
if (doc.reference_type !== "Job Card") {
|
||||
doctype = (doc.reference_type == "Stock Entry") ?
|
||||
"Stock Entry Detail" : doc.reference_type + " Item";
|
||||
}
|
||||
|
||||
if (doc.reference_type && doc.reference_name) {
|
||||
let filters = {
|
||||
"from": doctype,
|
||||
"inspection_type": doc.inspection_type
|
||||
};
|
||||
|
||||
if (doc.reference_type == doctype)
|
||||
filters["reference_name"] = doc.reference_name;
|
||||
else
|
||||
filters["parent"] = doc.reference_name;
|
||||
|
||||
return {
|
||||
query: "erpnext.stock.doctype.quality_inspection.quality_inspection.item_query",
|
||||
filters: filters
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
// Ignore cancellation of reference doctype on cancel all.
|
||||
frm.ignore_doctypes_on_cancel_all = [frm.doc.reference_type];
|
||||
@ -31,55 +80,5 @@ frappe.ui.form.on("Quality Inspection", {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// item code based on GRN/DN
|
||||
cur_frm.fields_dict['item_code'].get_query = function(doc, cdt, cdn) {
|
||||
let doctype = doc.reference_type;
|
||||
|
||||
if (doc.reference_type !== "Job Card") {
|
||||
doctype = (doc.reference_type == "Stock Entry") ?
|
||||
"Stock Entry Detail" : doc.reference_type + " Item";
|
||||
}
|
||||
|
||||
if (doc.reference_type && doc.reference_name) {
|
||||
let filters = {
|
||||
"from": doctype,
|
||||
"inspection_type": doc.inspection_type
|
||||
};
|
||||
|
||||
if (doc.reference_type == doctype)
|
||||
filters["reference_name"] = doc.reference_name;
|
||||
else
|
||||
filters["parent"] = doc.reference_name;
|
||||
|
||||
return {
|
||||
query: "erpnext.stock.doctype.quality_inspection.quality_inspection.item_query",
|
||||
filters: filters
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// Serial No based on item_code
|
||||
cur_frm.fields_dict['item_serial_no'].get_query = function(doc, cdt, cdn) {
|
||||
var filters = {};
|
||||
if (doc.item_code) {
|
||||
filters = {
|
||||
'item_code': doc.item_code
|
||||
}
|
||||
}
|
||||
return { filters: filters }
|
||||
}
|
||||
|
||||
cur_frm.set_query("batch_no", function(doc) {
|
||||
return {
|
||||
filters: {
|
||||
"item": doc.item_code
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
cur_frm.add_fetch('item_code', 'item_name', 'item_name');
|
||||
cur_frm.add_fetch('item_code', 'description', 'description');
|
||||
|
||||
},
|
||||
});
|
@ -136,6 +136,7 @@
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"fetch_from": "item_code.item_name",
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Data",
|
||||
"in_global_search": 1,
|
||||
@ -143,6 +144,7 @@
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "item_code.description",
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Description",
|
||||
@ -236,7 +238,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-11-19 17:06:05.409963",
|
||||
"modified": "2020-12-18 19:59:55.710300",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Quality Inspection",
|
||||
|
@ -6,7 +6,7 @@ import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
from frappe import _
|
||||
from frappe.utils import flt
|
||||
from frappe.utils import flt, cint
|
||||
from erpnext.stock.doctype.quality_inspection_template.quality_inspection_template \
|
||||
import get_template_details
|
||||
|
||||
@ -16,7 +16,7 @@ class QualityInspection(Document):
|
||||
self.get_item_specification_details()
|
||||
|
||||
if self.readings:
|
||||
self.set_status_based_on_acceptance_formula()
|
||||
self.inspect_and_set_status()
|
||||
|
||||
def get_item_specification_details(self):
|
||||
if not self.quality_inspection_template:
|
||||
@ -29,9 +29,7 @@ class QualityInspection(Document):
|
||||
parameters = get_template_details(self.quality_inspection_template)
|
||||
for d in parameters:
|
||||
child = self.append('readings', {})
|
||||
child.specification = d.specification
|
||||
child.value = d.value
|
||||
child.acceptance_formula = d.acceptance_formula
|
||||
child.update(d)
|
||||
child.status = "Accepted"
|
||||
|
||||
def get_quality_inspection_template(self):
|
||||
@ -69,35 +67,98 @@ class QualityInspection(Document):
|
||||
doctype = 'Stock Entry Detail'
|
||||
|
||||
if self.reference_type and self.reference_name:
|
||||
conditions = ""
|
||||
if self.batch_no and self.docstatus == 1:
|
||||
conditions += " and t1.batch_no = '%s'"%(self.batch_no)
|
||||
|
||||
if self.docstatus == 2: # if cancel, then remove qi link wherever same name
|
||||
conditions += " and t1.quality_inspection = '%s'"%(self.name)
|
||||
|
||||
frappe.db.sql("""
|
||||
UPDATE `tab{child_doc}` t1, `tab{parent_doc}` t2
|
||||
SET t1.quality_inspection = %s, t2.modified = %s
|
||||
WHERE t1.parent = %s and t1.item_code = %s and t1.parent = t2.name
|
||||
""".format(parent_doc=self.reference_type, child_doc=doctype),
|
||||
UPDATE
|
||||
`tab{child_doc}` t1, `tab{parent_doc}` t2
|
||||
SET
|
||||
t1.quality_inspection = %s, t2.modified = %s
|
||||
WHERE
|
||||
t1.parent = %s
|
||||
and t1.item_code = %s
|
||||
and t1.parent = t2.name
|
||||
{conditions}
|
||||
""".format(parent_doc=self.reference_type, child_doc=doctype, conditions=conditions),
|
||||
(quality_inspection, self.modified, self.reference_name, self.item_code))
|
||||
|
||||
def set_status_based_on_acceptance_formula(self):
|
||||
def inspect_and_set_status(self):
|
||||
for reading in self.readings:
|
||||
if not reading.acceptance_formula: continue
|
||||
if not reading.manual_inspection: # dont auto set status if manual
|
||||
if reading.formula_based_criteria:
|
||||
self.set_status_based_on_acceptance_formula(reading)
|
||||
else:
|
||||
# if not formula based check acceptance values set
|
||||
self.set_status_based_on_acceptance_values(reading)
|
||||
|
||||
condition = reading.acceptance_formula
|
||||
data = {}
|
||||
def set_status_based_on_acceptance_values(self, reading):
|
||||
if cint(reading.non_numeric):
|
||||
result = reading.get("reading_value") == reading.get("value")
|
||||
else:
|
||||
# numeric readings
|
||||
result = self.min_max_criteria_passed(reading)
|
||||
|
||||
reading.status = "Accepted" if result else "Rejected"
|
||||
|
||||
def min_max_criteria_passed(self, reading):
|
||||
"""Determine whether all readings fall in the acceptable range."""
|
||||
for i in range(1, 11):
|
||||
reading_value = reading.get("reading_" + str(i))
|
||||
if reading_value is not None and reading_value.strip():
|
||||
result = flt(reading.get("min_value")) <= flt(reading_value) <= flt(reading.get("max_value"))
|
||||
if not result: return False
|
||||
return True
|
||||
|
||||
def set_status_based_on_acceptance_formula(self, reading):
|
||||
if not reading.acceptance_formula:
|
||||
frappe.throw(_("Row #{0}: Acceptance Criteria Formula is required.").format(reading.idx),
|
||||
title=_("Missing Formula"))
|
||||
|
||||
condition = reading.acceptance_formula
|
||||
data = self.get_formula_evaluation_data(reading)
|
||||
|
||||
try:
|
||||
result = frappe.safe_eval(condition, None, data)
|
||||
reading.status = "Accepted" if result else "Rejected"
|
||||
except NameError as e:
|
||||
field = frappe.bold(e.args[0].split()[1])
|
||||
frappe.throw(_("Row #{0}: {1} is not a valid reading field. Please refer to the field description.")
|
||||
.format(reading.idx, field),
|
||||
title=_("Invalid Formula"))
|
||||
except Exception:
|
||||
frappe.throw(_("Row #{0}: Acceptance Criteria Formula is incorrect.").format(reading.idx),
|
||||
title=_("Invalid Formula"))
|
||||
|
||||
def get_formula_evaluation_data(self, reading):
|
||||
data = {}
|
||||
if cint(reading.non_numeric):
|
||||
data = {"reading_value": reading.get("reading_value")}
|
||||
else:
|
||||
# numeric readings
|
||||
for i in range(1, 11):
|
||||
field = "reading_" + str(i)
|
||||
data[field] = flt(reading.get(field)) or 0
|
||||
data[field] = flt(reading.get(field))
|
||||
data["mean"] = self.calculate_mean(reading)
|
||||
|
||||
try:
|
||||
result = frappe.safe_eval(condition, None, data)
|
||||
reading.status = "Accepted" if result else "Rejected"
|
||||
except SyntaxError:
|
||||
frappe.throw(_("Row #{0}: Acceptance Criteria Formula is incorrect.").format(reading.idx),
|
||||
title=_("Invalid Formula"))
|
||||
except NameError as e:
|
||||
field = frappe.bold(e.args[0].split()[1])
|
||||
frappe.throw(_("Row #{0}: {1} is not a valid reading field. Please refer to the field description.")
|
||||
.format(reading.idx, field),
|
||||
title=_("Invalid Formula"))
|
||||
return data
|
||||
|
||||
def calculate_mean(self, reading):
|
||||
"""Calculate mean of all non-empty readings."""
|
||||
from statistics import mean
|
||||
readings_list = []
|
||||
|
||||
for i in range(1, 11):
|
||||
reading_value = reading.get("reading_" + str(i))
|
||||
if reading_value is not None and reading_value.strip():
|
||||
readings_list.append(flt(reading_value))
|
||||
|
||||
actual_mean = mean(readings_list) if readings_list else 0
|
||||
return actual_mean
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.validate_and_sanitize_search_inputs
|
||||
|
@ -44,24 +44,61 @@ class TestQualityInspection(unittest.TestCase):
|
||||
qa.delete()
|
||||
dn.delete()
|
||||
|
||||
def test_value_based_qi_readings(self):
|
||||
# Test QI based on acceptance values (Non formula)
|
||||
dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True)
|
||||
readings = [{
|
||||
"specification": "Iron Content", # numeric reading
|
||||
"min_value": 0.1,
|
||||
"max_value": 0.9,
|
||||
"reading_1": "0.4"
|
||||
},
|
||||
{
|
||||
"specification": "Particle Inspection Needed", # non-numeric reading
|
||||
"non_numeric": 1,
|
||||
"value": "Yes",
|
||||
"reading_value": "Yes"
|
||||
}]
|
||||
|
||||
qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name,
|
||||
readings=readings, do_not_save=True)
|
||||
qa.save()
|
||||
|
||||
# status must be auto set as per formula
|
||||
self.assertEqual(qa.readings[0].status, "Accepted")
|
||||
self.assertEqual(qa.readings[1].status, "Accepted")
|
||||
|
||||
qa.delete()
|
||||
dn.delete()
|
||||
|
||||
def test_formula_based_qi_readings(self):
|
||||
dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True)
|
||||
readings = [{
|
||||
"specification": "Iron Content",
|
||||
"specification": "Iron Content", # numeric reading
|
||||
"formula_based_criteria": 1,
|
||||
"acceptance_formula": "reading_1 > 0.35 and reading_1 < 0.50",
|
||||
"reading_1": 0.4
|
||||
"reading_1": "0.4"
|
||||
},
|
||||
{
|
||||
"specification": "Calcium Content",
|
||||
"specification": "Calcium Content", # numeric reading
|
||||
"formula_based_criteria": 1,
|
||||
"acceptance_formula": "reading_1 > 0.20 and reading_1 < 0.50",
|
||||
"reading_1": 0.7
|
||||
"reading_1": "0.7"
|
||||
},
|
||||
{
|
||||
"specification": "Mg Content",
|
||||
"acceptance_formula": "(reading_1 + reading_2 + reading_3) / 3 < 0.9",
|
||||
"reading_1": 0.5,
|
||||
"reading_2": 0.7,
|
||||
"specification": "Mg Content", # numeric reading
|
||||
"formula_based_criteria": 1,
|
||||
"acceptance_formula": "mean < 0.9",
|
||||
"reading_1": "0.5",
|
||||
"reading_2": "0.7",
|
||||
"reading_3": "random text" # check if random string input causes issues
|
||||
},
|
||||
{
|
||||
"specification": "Calcium Content", # non-numeric reading
|
||||
"formula_based_criteria": 1,
|
||||
"non_numeric": 1,
|
||||
"acceptance_formula": "reading_value in ('Grade A', 'Grade B', 'Grade C')",
|
||||
"reading_value": "Grade B"
|
||||
}]
|
||||
|
||||
qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name,
|
||||
@ -72,6 +109,7 @@ class TestQualityInspection(unittest.TestCase):
|
||||
self.assertEqual(qa.readings[0].status, "Accepted")
|
||||
self.assertEqual(qa.readings[1].status, "Rejected")
|
||||
self.assertEqual(qa.readings[2].status, "Accepted")
|
||||
self.assertEqual(qa.readings[3].status, "Accepted")
|
||||
|
||||
qa.delete()
|
||||
dn.delete()
|
||||
@ -86,11 +124,20 @@ def create_quality_inspection(**args):
|
||||
qa.item_code = args.item_code or "_Test Item with QA"
|
||||
qa.sample_size = 1
|
||||
qa.inspected_by = frappe.session.user
|
||||
qa.status = args.status or "Accepted"
|
||||
|
||||
readings = args.readings or {"specification": "Size", "status": args.status}
|
||||
if not args.readings:
|
||||
create_quality_inspection_parameter("Size")
|
||||
readings = {"specification": "Size", "min_value": 0, "max_value": 10}
|
||||
else:
|
||||
readings = args.readings
|
||||
|
||||
if args.status == "Rejected":
|
||||
readings["reading_1"] = "12" # status is auto set in child on save
|
||||
|
||||
if isinstance(readings, list):
|
||||
for entry in readings:
|
||||
create_quality_inspection_parameter(entry["specification"])
|
||||
qa.append("readings", entry)
|
||||
else:
|
||||
qa.append("readings", readings)
|
||||
@ -101,3 +148,11 @@ def create_quality_inspection(**args):
|
||||
qa.submit()
|
||||
|
||||
return qa
|
||||
|
||||
def create_quality_inspection_parameter(parameter):
|
||||
if not frappe.db.exists("Quality Inspection Parameter", parameter):
|
||||
frappe.get_doc({
|
||||
"doctype": "Quality Inspection Parameter",
|
||||
"parameter": parameter,
|
||||
"description": parameter
|
||||
}).insert()
|
@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Quality Inspection Parameter', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
@ -0,0 +1,86 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "field:parameter",
|
||||
"creation": "2020-12-28 17:06:00.254129",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"parameter",
|
||||
"description"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "parameter",
|
||||
"fieldtype": "Data",
|
||||
"label": "Parameter",
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text Editor",
|
||||
"label": "Description"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2020-12-28 18:06:54.897317",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Quality Inspection Parameter",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Stock User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Quality Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Manufacturing User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class QualityInspectionParameter(Document):
|
||||
pass
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestQualityInspectionParameter(unittest.TestCase):
|
||||
pass
|
@ -7,21 +7,28 @@
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"specification",
|
||||
"value",
|
||||
"status",
|
||||
"value",
|
||||
"non_numeric",
|
||||
"manual_inspection",
|
||||
"column_break_4",
|
||||
"min_value",
|
||||
"max_value",
|
||||
"formula_based_criteria",
|
||||
"acceptance_formula",
|
||||
"section_break_3",
|
||||
"reading_value",
|
||||
"section_break_14",
|
||||
"reading_1",
|
||||
"reading_2",
|
||||
"reading_3",
|
||||
"column_break_10",
|
||||
"reading_4",
|
||||
"column_break_10",
|
||||
"reading_5",
|
||||
"reading_6",
|
||||
"column_break_14",
|
||||
"reading_7",
|
||||
"reading_8",
|
||||
"column_break_14",
|
||||
"reading_9",
|
||||
"reading_10"
|
||||
],
|
||||
@ -29,19 +36,20 @@
|
||||
{
|
||||
"columns": 3,
|
||||
"fieldname": "specification",
|
||||
"fieldtype": "Data",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Parameter",
|
||||
"oldfieldname": "specification",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "Quality Inspection Parameter",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"columns": 2,
|
||||
"depends_on": "eval:(!doc.formula_based_criteria && doc.non_numeric)",
|
||||
"fieldname": "value",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Acceptance Criteria",
|
||||
"label": "Acceptance Criteria Value",
|
||||
"oldfieldname": "value",
|
||||
"oldfieldtype": "Data"
|
||||
},
|
||||
@ -67,7 +75,6 @@
|
||||
"columns": 1,
|
||||
"fieldname": "reading_3",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Reading 3",
|
||||
"oldfieldname": "reading_3",
|
||||
"oldfieldtype": "Data"
|
||||
@ -133,15 +140,18 @@
|
||||
"options": "Accepted\nRejected"
|
||||
},
|
||||
{
|
||||
"depends_on": "non_numeric",
|
||||
"fieldname": "section_break_3",
|
||||
"fieldtype": "Section Break"
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Value Based Inspection"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"description": "Simple Python formula based on numeric Readings.<br> Example 1: <b>reading_1 > 0.2 and reading_1 < 0.5</b><br>\nExample 2: <b>(reading_1 + reading_2) / 2 < 10</b>",
|
||||
"depends_on": "formula_based_criteria",
|
||||
"description": "Simple Python formula applied on Reading fields.<br> Numeric eg. 1: <b>reading_1 > 0.2 and reading_1 < 0.5</b><br>\nNumeric eg. 2: <b>mean > 3.5</b> (mean of populated fields)<br>\nValue based eg.: <b>reading_value in (\"A\", \"B\", \"C\")</b>",
|
||||
"fieldname": "acceptance_formula",
|
||||
"fieldtype": "Code",
|
||||
"label": "Acceptance Criteria Formula"
|
||||
@ -153,12 +163,59 @@
|
||||
{
|
||||
"fieldname": "column_break_14",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "formula_based_criteria",
|
||||
"fieldtype": "Check",
|
||||
"label": "Formula Based Criteria"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:(!doc.formula_based_criteria && !doc.non_numeric)",
|
||||
"description": "Applied on each reading.",
|
||||
"fieldname": "min_value",
|
||||
"fieldtype": "Float",
|
||||
"label": "Minimum Value"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:(!doc.formula_based_criteria && !doc.non_numeric)",
|
||||
"description": "Applied on each reading.",
|
||||
"fieldname": "max_value",
|
||||
"fieldtype": "Float",
|
||||
"label": "Maximum Value"
|
||||
},
|
||||
{
|
||||
"depends_on": "non_numeric",
|
||||
"fieldname": "reading_value",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Reading Value"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.non_numeric",
|
||||
"fieldname": "section_break_14",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Numeric Inspection"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "non_numeric",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Non-Numeric"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "Set the status manually.",
|
||||
"fieldname": "manual_inspection",
|
||||
"fieldtype": "Check",
|
||||
"label": "Manual Inspection"
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-11-16 16:34:29.947856",
|
||||
"modified": "2021-01-07 21:56:40.235579",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Quality Inspection Reading",
|
||||
|
@ -13,6 +13,7 @@ def get_template_details(template):
|
||||
if not template: return []
|
||||
|
||||
return frappe.get_all('Item Quality Inspection Parameter',
|
||||
fields=["specification", "value", "acceptance_formula"],
|
||||
fields=["specification", "value", "acceptance_formula",
|
||||
"non_numeric", "formula_based_criteria", "min_value", "max_value"],
|
||||
filters={'parenttype': 'Quality Inspection Template', 'parent': template},
|
||||
order_by="idx")
|
Loading…
x
Reference in New Issue
Block a user