feat(quality): Check quality status before receipt/delivery (#16169)
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 7b3f740..63e89ab 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -12,6 +12,9 @@
from erpnext.stock.stock_ledger import get_valuation_rate
from erpnext.stock import get_warehouse_account_map
+class QualityInspectionRequiredError(frappe.ValidationError): pass
+class QualityInspectionRejectedError(frappe.ValidationError): pass
+
class StockController(AccountsController):
def validate(self):
super(StockController, self).validate()
@@ -317,7 +320,6 @@
def validate_inspection(self):
'''Checks if quality inspection is set for Items that require inspection.
On submit, throw an exception'''
-
inspection_required_fieldname = None
if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
inspection_required_fieldname = "inspection_required_before_purchase"
@@ -330,17 +332,25 @@
return
for d in self.get('items'):
- raise_exception = False
+ qa_required = False
if (inspection_required_fieldname and not d.quality_inspection and
frappe.db.get_value("Item", d.item_code, inspection_required_fieldname)):
- raise_exception = True
+ qa_required = True
elif self.doctype == "Stock Entry" and not d.quality_inspection and d.t_warehouse:
- raise_exception = True
+ qa_required = True
- if raise_exception:
+ if qa_required:
frappe.msgprint(_("Quality Inspection required for Item {0}").format(d.item_code))
if self.docstatus==1:
- raise frappe.ValidationError
+ raise QualityInspectionRequiredError
+ elif self.docstatus == 1:
+ if d.quality_inspection:
+ qa_doc = frappe.get_doc("Quality Inspection", d.quality_inspection)
+ qa_failed = any([r.status=="Rejected" for r in qa_doc.readings])
+ if qa_failed:
+ frappe.throw(_("Row {0}: Quality Inspection rejected for item {1}")
+ .format(d.idx, d.item_code), QualityInspectionRejectedError)
+
def update_blanket_order(self):
blanket_orders = list(set([d.blanket_order for d in self.items if d.blanket_order]))
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index 24292f7..abdd676 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -392,4 +392,3 @@
"company": "_Test Company"
})
item.save()
-
diff --git a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
index 1c8ec23..60cc9a0 100644
--- a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
@@ -3,8 +3,45 @@
import frappe
import unittest
+from frappe.utils import nowdate
+from erpnext.stock.doctype.item.test_item import create_item
+from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+from erpnext.controllers.stock_controller import QualityInspectionRejectedError, QualityInspectionRequiredError
# test_records = frappe.get_test_records('Quality Inspection')
class TestQualityInspection(unittest.TestCase):
- pass
+ def setUp(self):
+ create_item("_Test Item with QA")
+ frappe.db.set_value("Item", "_Test Item with QA", "inspection_required_before_delivery", 1)
+
+ def test_qa_for_delivery(self):
+ dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True)
+ self.assertRaises(QualityInspectionRequiredError, dn.submit)
+
+ qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, status="Rejected")
+ dn.reload()
+ self.assertRaises(QualityInspectionRejectedError, dn.submit)
+
+ frappe.db.set_value("Quality Inspection Reading", {"parent": qa.name}, "status", "Accepted")
+ dn.reload()
+ dn.submit()
+
+def create_quality_inspection(**args):
+ args = frappe._dict(args)
+ qa = frappe.new_doc("Quality Inspection")
+ qa.report_date = nowdate()
+ qa.inspection_type = args.inspection_type or "Outgoing"
+ qa.reference_type = args.reference_type
+ qa.reference_name = args.reference_name
+ qa.item_code = args.item_code or "_Test Item with QA"
+ qa.sample_size = 1
+ qa.inspected_by = frappe.session.user
+ qa.append("readings", {
+ "specification": "Size",
+ "status": args.status
+ })
+ qa.save()
+ qa.submit()
+
+ return qa
diff --git a/erpnext/templates/includes/itemised_tax_breakup.html b/erpnext/templates/includes/itemised_tax_breakup.html
index 982397e..c27e4ce 100644
--- a/erpnext/templates/includes/itemised_tax_breakup.html
+++ b/erpnext/templates/includes/itemised_tax_breakup.html
@@ -16,7 +16,7 @@
<tr>
<td>{{ item }}</td>
<td class='text-right'>
- {{ frappe.utils.fmt_money(itemised_taxable_amount.get(item), None, currency) }}
+ {{ frappe.utils.fmt_money(itemised_taxable_amount.get(item, 0), None, currency) }}
</td>
{% for tax_account in tax_accounts %}
{% set tax_details = taxes.get(tax_account) %}