From ad4e13991719ad361187001a8124d4062da344b8 Mon Sep 17 00:00:00 2001 From: Ninad Parikh <109862100+Ninad1306@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:07:56 +0530 Subject: [PATCH] fix: only show warning for subcontracting receipt (#2652) * fix: only show warning for subcontracting receipt * chore: better formatting * test: test case to validate doc references --------- --- .../overrides/subcontracting_transaction.py | 36 ++- .../test_subcontracting_transaction.py | 207 +++++++++++++++++- india_compliance/hooks.py | 2 +- 3 files changed, 230 insertions(+), 15 deletions(-) diff --git a/india_compliance/gst_india/overrides/subcontracting_transaction.py b/india_compliance/gst_india/overrides/subcontracting_transaction.py index 108d797ef..97d85421c 100644 --- a/india_compliance/gst_india/overrides/subcontracting_transaction.py +++ b/india_compliance/gst_india/overrides/subcontracting_transaction.py @@ -187,21 +187,39 @@ def validate(doc, method=None): update_gst_details(doc) +def before_save(doc, method=None): + if ignore_gst_validations(doc): + return + + validate_doc_references(doc) + + def before_submit(doc, method=None): # Stock Entries with Subcontracting Order should only be considered if ignore_gst_validation_for_subcontracting(doc): return - if (doc.doctype == "Stock Entry" and doc.purpose == "Material Transfer") or ( + validate_doc_references(doc) + + +def validate_doc_references(doc): + is_stock_entry = doc.doctype == "Stock Entry" and doc.purpose == "Material Transfer" + is_subcontracting_receipt = ( doc.doctype == "Subcontracting Receipt" and not doc.is_return - ): - if not doc.doc_references: - frappe.throw( - _("Please Select Original Document Reference for ITC-04 Reporting"), - title=_("Mandatory Field"), - ) - else: - remove_duplicates(doc) + ) + + if not (is_stock_entry or is_subcontracting_receipt): + return + + if doc.doc_references: + remove_duplicates(doc) + return + + error_msg = _("Please Select Original Document Reference for ITC-04 Reporting") + if is_stock_entry: + frappe.throw(error_msg, title=_("Mandatory Field")) + else: + frappe.msgprint(error_msg, alert=True, indicator="yellow") def validate_transaction(doc, method=None): diff --git a/india_compliance/gst_india/overrides/test_subcontracting_transaction.py b/india_compliance/gst_india/overrides/test_subcontracting_transaction.py index 3498826a5..6e6cac85c 100644 --- a/india_compliance/gst_india/overrides/test_subcontracting_transaction.py +++ b/india_compliance/gst_india/overrides/test_subcontracting_transaction.py @@ -1,9 +1,169 @@ +import re + +import frappe from frappe.tests import IntegrationTestCase +from erpnext.controllers.subcontracting_controller import ( + get_materials_from_supplier, + make_rm_stock_entry, +) +from erpnext.controllers.tests.test_subcontracting_controller import get_rm_items +from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom +from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import ( + make_subcontracting_receipt, +) +from erpnext.subcontracting.doctype.subcontracting_order.test_subcontracting_order import ( + create_subcontracting_order, +) from india_compliance.gst_india.utils.tests import create_transaction +def make_raw_materials(): + raw_materials = { + "Subcontracted SRM Item 1": {"valuation_rate": 20}, + "Subcontracted SRM Item 2": {"valuation_rate": 20}, + } + + for item, properties in raw_materials.items(): + if not frappe.db.exists("Item", item): + properties.update({"is_stock_item": 1}) + make_item(item, properties) + + +def make_service_items(): + service_items = { + "Subcontracted Service Item 1": {}, + } + + for item, properties in service_items.items(): + if not frappe.db.exists("Item", item): + properties.update({"is_stock_item": 0}) + make_item(item, properties) + + +def make_subcontracted_items(): + sub_contracted_items = { + "Subcontracted Item SA1": {}, + } + + for item, properties in sub_contracted_items.items(): + if not frappe.db.exists("Item", item): + properties.update({"is_stock_item": 1, "is_sub_contracted_item": 1}) + make_item(item, properties) + + +def make_boms(): + boms = { + "Subcontracted Item SA1": [ + "Subcontracted SRM Item 1", + "Subcontracted SRM Item 2", + ], + } + + for item_code, raw_materials in boms.items(): + if not frappe.db.exists("BOM", {"item": item_code}): + make_bom( + item=item_code, + raw_materials=raw_materials, + rate=100, + company="_Test Indian Registered Company", + ) + + +def make_item(item_code=None, properties=None): + if not item_code: + item_code = frappe.generate_hash(length=16) + + if frappe.db.exists("Item", item_code): + return frappe.get_doc("Item", item_code) + + item = frappe.get_doc( + { + "doctype": "Item", + "item_code": item_code, + "item_name": item_code, + "description": item_code, + "item_group": "Products", + "gst_hsn_code": "85011011", + } + ) + + if properties: + item.update(properties) + + if item.is_stock_item: + for item_default in [ + doc for doc in item.get("item_defaults") if not doc.default_warehouse + ]: + item_default.default_warehouse = "Stores - _TIRC" + item_default.company = "_Test Indian Registered Company" + + return item.insert() + + +def create_purchase_order(**args): + po_dict = { + "doctype": "Purchase Order", + "supplier": "_Test Registered Supplier", + "is_subcontracted": 1, + "items": args["items"], + "supplier_warehouse": "Finished Goods - _TIRC", + "do_not_save": 1, + "do_not_submit": 1, + } + + po = create_transaction(**po_dict) + + if po.is_subcontracted: + supp_items = po.get("supplied_items") + for d in supp_items: + if not d.reserve_warehouse: + d.reserve_warehouse = "Stores - _TIRC" + + return po.submit() + + +def make_stock_transfer_entry(**args): + args = frappe._dict(args) + + items = [] + for row in args.rm_items: + row = frappe._dict(row) + + item = { + "item_code": row.main_item_code or args.main_item_code, + "rm_item_code": row.item_code, + "qty": row.qty or 1, + "item_name": row.item_code, + "rate": row.rate or 100, + "stock_uom": row.stock_uom or "Nos", + "warehouse": row.warehouse, + } + + items.append(item) + + ste_dict = make_rm_stock_entry(args.sco_no, items) + ste_dict.update( + { + "bill_from_address": "_Test Indian Registered Company-Billing", + "bill_to_address": "_Test Registered Supplier-Billing", + } + ) + + doc = frappe.get_doc(ste_dict) + doc.insert() + + return doc.submit() + + class TestSubcontractingTransaction(IntegrationTestCase): + def _create_stock_entry(self, doc_args): + """Generate Stock Entry to test e-Waybill functionalities""" + doc_args.update({"doctype": "Stock Entry"}) + + stock_entry = create_transaction(**doc_args) + return stock_entry + def test_create_and_update_stock_entry(self): # Create a subcontracting transaction args = { @@ -35,9 +195,46 @@ def test_create_and_update_stock_entry(self): self.assertEqual(stock_entry.select_print_heading, "Credit Note") - def _create_stock_entry(self, doc_args): - """Generate Stock Entry to test e-Waybill functionalities""" - doc_args.update({"doctype": "Stock Entry"}) + def test_validation_for_doc_references(self): + make_raw_materials() + make_service_items() + make_subcontracted_items() + make_boms() - stock_entry = create_transaction(**doc_args) - return stock_entry + service_item = [ + { + "warehouse": "Stores - _TIRC", + "item_code": "Subcontracted Service Item 1", + "qty": 10, + "rate": 100, + "fg_item": "Subcontracted Item SA1", + "fg_item_qty": 10, + } + ] + + po = create_purchase_order(items=service_item) + sco = create_subcontracting_order(po_name=po.name) + + rm_items = get_rm_items(sco.supplied_items) + se = make_stock_transfer_entry(sco_no=sco.name, rm_items=rm_items) + + return_se = get_materials_from_supplier( + sco.name, [d.name for d in sco.supplied_items] + ) + return_se.save() + + scr = make_subcontracting_receipt(sco.name) + scr.submit() + + self.assertRaisesRegex( + frappe.ValidationError, + re.compile(r"^(Please Select Original Document Reference*)"), + return_se.submit, + ) + + return_se.reload() + return_se.append( + "doc_references", + {"link_doctype": "Stock Entry", "link_name": se.name}, + ) + return_se.submit() diff --git a/india_compliance/hooks.py b/india_compliance/hooks.py index 78485ce80..eb3e26494 100644 --- a/india_compliance/hooks.py +++ b/india_compliance/hooks.py @@ -244,7 +244,7 @@ "Subcontracting Receipt": { "onload": "india_compliance.gst_india.overrides.subcontracting_transaction.onload", "validate": "india_compliance.gst_india.overrides.subcontracting_transaction.validate", - "before_submit": "india_compliance.gst_india.overrides.subcontracting_transaction.before_submit", + "before_save": "india_compliance.gst_india.overrides.subcontracting_transaction.before_save", "before_mapping": "india_compliance.gst_india.overrides.subcontracting_transaction.before_mapping_subcontracting_receipt", }, "Supplier": {