CLIENT-SCRIPT-- frappe.ui.form.on("Bill of Entry", { after_save: async function (frm) { // ===================================================== // Execute only for saved BOE in Ready for Lot Number Staging // ===================================================== if (frm.is_new()) return; if (frm.__lot_automation_running) return; if (frm.doc.workflow_state !== "Ready for Lot Number Staging") return; frm.__lot_automation_running = true; try { frappe.dom.freeze("Generating Lot Numbers. Please wait..."); // ================================================= // STEP 1 // Create Lot Number Staging // ================================================= await frappe.call({ method: "canofy_ddit.canofy_ddit.doctype.lot_number_staging.lot_number_staging.create_lot_no_staging", args: { doc_name: frm.doc.name } }); // Wait for database commit await new Promise(resolve => setTimeout(resolve, 2000)); // ================================================= // STEP 2 // Fetch Latest Lot Number Staging // ================================================= const lns_list = await frappe.db.get_list( "Lot Number Staging", { filters: { linked_be_no: frm.doc.name }, fields: ["name"], order_by: "creation desc", limit: 1 } ); if (!lns_list.length) { throw "Lot Number Staging document was not created."; } const lns_name = lns_list[0].name; // ================================================= // STEP 3 // Load Lot Number Staging // ================================================= let lns = await frappe.db.get_doc( "Lot Number Staging", lns_name ); // ================================================= // STEP 4 // Header & Item Validations // ================================================= let validation_errors = []; // -------------------------------------------- // Validation 1 // BOE Number = LNS Transaction ID // -------------------------------------------- if ( String(frm.doc.p_0_beno || "").trim() !== String(lns.transaction_id || "").trim() ) { validation_errors.push( "BE Number and Transaction ID do not match." ); } // -------------------------------------------- // Validation 2 // BOE System Doc No = LNS Source EXIM Txn ID // -------------------------------------------- if ( String(frm.doc.name || "").trim() !== String(lns.linked_be_no || "").trim() ) { validation_errors.push( "System Doc. No. and Source EXIM Txn ID do not match." ); } // -------------------------------------------- // Validation 3 // Item Count // -------------------------------------------- const boe_items = frm.doc.items || []; const lns_items = lns.item_details || []; if (!boe_items.length) { validation_errors.push( "Bill of Entry contains no items." ); } if (!lns_items.length) { validation_errors.push( "Lot Number Staging contains no items." ); } if ( boe_items.length && lns_items.length && boe_items.length !== lns_items.length ) { validation_errors.push( `Item count mismatch. BOE : ${boe_items.length}, LNS : ${lns_items.length}.` ); } // ================================================= // Stop if Validation Failed // ================================================= if (validation_errors.length) { throw validation_errors.join("
"); } frappe.show_alert({ message: "Lot Number Staging validation completed successfully.", indicator: "green" }); // ================================================= // STEP 5 // Submit Lot Number Staging // ================================================= await frappe.xcall( "frappe.model.workflow.apply_workflow", { doc: lns, action: "Submit" } ); // Reload latest document lns = await frappe.db.get_doc( "Lot Number Staging", lns_name ); // ================================================= // STEP 6 // Create Lot Numbers // ================================================= const response = await frappe.call({ method: "run_doc_method", args: { docs: lns, method: "create_lot_number", args: {} } }); // ================================================= // STEP 7 // Verify API Execution // ================================================= if (response.exc) { throw "Lot Number creation process failed."; } // Wait for server commit await new Promise(resolve => setTimeout(resolve, 2000)); frappe.show_alert({ message: "Lot Numbers created successfully.", indicator: "green" }); // ================================================= // SUCCESS // ================================================= frappe.msgprint({ title: "Automation Completed", indicator: "green", message: "Bill of Entry Automation Completed Successfully

" + "✓ Bill of Entry validated.
" + "✓ Workflow moved to Ready for Lot Number Staging.
" + "✓ Lot Number Staging created.
" + "✓ Header validations passed.
" + "✓ Item validations passed.
" + "✓ Lot Number Staging submitted.
" + "✓ Lot Numbers created successfully." }); frm.reload_doc(); } catch (e) { console.error(e); frappe.msgprint({ title: "Automation Failed", indicator: "red", message: e.message || e }); } finally { frappe.dom.unfreeze(); frm.__lot_automation_running = false; } } }); ##------------------------------------------------------------------ SERVER-CLIENT-- # ========================================================== # Bill of Entry Automation # Trigger : After Save # Purpose : # 1. Validate Bill of Entry # 2. Move Workflow # Pending Review # ↓ # Reviewed # ↓ # Ready for Lot Number Staging # ========================================================== # Execute only for Draft Bill of Entry if doc.docstatus == 0 and doc.workflow_state == "Pending Review": validation_errors = [] # ====================================================== # Header Validations # ====================================================== # BE Number if not doc.p_0_beno: validation_errors.append("• Bill of Entry Number is mandatory.") # BE Type if not doc.p_0_betype: validation_errors.append("• Bill of Entry Type is mandatory.") # Inventory Workflow if doc.inventory_workflow_allowed != 1: validation_errors.append( "• Inventory Workflow Allowed must be enabled." ) # ====================================================== # Item Validations # ====================================================== if not doc.items: validation_errors.append( "• At least one item must be available in the Item table." ) # ====================================================== # Stop Processing # ====================================================== if validation_errors: frappe.throw( "

Bill of Entry Validation Failed

" + "
".join(validation_errors) ) # ====================================================== # Workflow Transition # ====================================================== # Stage 1 doc.workflow_state = "Reviewed" doc.save(ignore_permissions=True) # Reload latest values doc.reload() # Stage 2 doc.workflow_state = "Ready for Lot Number Staging" doc.save(ignore_permissions=True) # ====================================================== # Success Message # ====================================================== frappe.msgprint( "Bill of Entry Validation Successful

" "Workflow has been assigned to " "Ready for Lot Number Staging." )