From 5a9579bae40967955b219602546ae377a00948ec Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 24 Dec 2018 14:54:42 +0530 Subject: [PATCH] feat(quality): Check quality status before receipt/delivery (#16169) --- erpnext/controllers/stock_controller.py | 22 ++++++++--- erpnext/stock/doctype/item/test_item.py | 1 - .../test_quality_inspection.py | 39 ++++++++++++++++++- .../includes/itemised_tax_breakup.html | 2 +- 4 files changed, 55 insertions(+), 9 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 7b3f740462..63e89ab6e3 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -12,6 +12,9 @@ from erpnext.controllers.accounts_controller import AccountsController 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 @@ class StockController(AccountsController): 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 @@ class StockController(AccountsController): 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 24292f7b4f..abdd6765bd 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -392,4 +392,3 @@ def create_item(item_code, is_stock_item=None, valuation_rate=0, warehouse=None) "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 1c8ec23ebd..60cc9a0972 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 982397e133..c27e4cede0 100644 --- a/erpnext/templates/includes/itemised_tax_breakup.html +++ b/erpnext/templates/includes/itemised_tax_breakup.html @@ -16,7 +16,7 @@ {{ item }} - {{ frappe.utils.fmt_money(itemised_taxable_amount.get(item), None, currency) }} + {{ frappe.utils.fmt_money(itemised_taxable_amount.get(item, 0), None, currency) }} {% for tax_account in tax_accounts %} {% set tax_details = taxes.get(tax_account) %}