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."
)