mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-27 00:44:45 +00:00
refactor: job_card.js code for better readability
(cherry picked from commit 0a215b0717)
# Conflicts:
# erpnext/manufacturing/doctype/job_card/job_card.js
This commit is contained in:
committed by
Mergify
parent
b372e6f118
commit
3081368aad
@@ -2,79 +2,53 @@
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on("Job Card", {
|
||||
setup: function (frm) {
|
||||
frm.set_query("operation", function () {
|
||||
return {
|
||||
query: "erpnext.manufacturing.doctype.job_card.job_card.get_operations",
|
||||
filters: {
|
||||
work_order: frm.doc.work_order,
|
||||
},
|
||||
};
|
||||
});
|
||||
setup(frm) {
|
||||
frm.set_query("operation", () => ({
|
||||
query: "erpnext.manufacturing.doctype.job_card.job_card.get_operations",
|
||||
filters: { work_order: frm.doc.work_order },
|
||||
}));
|
||||
|
||||
frm.set_query("serial_and_batch_bundle", () => {
|
||||
return {
|
||||
filters: {
|
||||
item_code: frm.doc.production_item,
|
||||
voucher_type: frm.doc.doctype,
|
||||
voucher_no: ["in", [frm.doc.name, ""]],
|
||||
is_cancelled: 0,
|
||||
},
|
||||
};
|
||||
});
|
||||
frm.set_query("serial_and_batch_bundle", () => ({
|
||||
filters: {
|
||||
item_code: frm.doc.production_item,
|
||||
voucher_type: frm.doc.doctype,
|
||||
voucher_no: ["in", [frm.doc.name, ""]],
|
||||
is_cancelled: 0,
|
||||
},
|
||||
}));
|
||||
|
||||
frm.set_query("item_code", "secondary_items", () => {
|
||||
return {
|
||||
filters: {
|
||||
disabled: 0,
|
||||
},
|
||||
};
|
||||
});
|
||||
frm.set_query("item_code", "secondary_items", () => ({
|
||||
filters: { disabled: 0 },
|
||||
}));
|
||||
|
||||
frm.set_query("operation", "time_logs", () => {
|
||||
let operations = (frm.doc.sub_operations || []).map((d) => d.sub_operation);
|
||||
return {
|
||||
filters: {
|
||||
name: ["in", operations],
|
||||
},
|
||||
};
|
||||
const operations = (frm.doc.sub_operations || []).map((d) => d.sub_operation);
|
||||
return { filters: { name: ["in", operations] } };
|
||||
});
|
||||
|
||||
frm.set_query("work_order", function () {
|
||||
return {
|
||||
filters: {
|
||||
status: ["not in", ["Cancelled", "Closed", "Stopped"]],
|
||||
},
|
||||
};
|
||||
});
|
||||
frm.set_query("work_order", () => ({
|
||||
filters: { status: ["not in", ["Cancelled", "Closed", "Stopped"]] },
|
||||
}));
|
||||
|
||||
frm.events.set_company_filters(frm, "target_warehouse");
|
||||
frm.events.set_company_filters(frm, "source_warehouse");
|
||||
frm.events.set_company_filters(frm, "wip_warehouse");
|
||||
frm.set_query("source_warehouse", "items", () => {
|
||||
return {
|
||||
filters: {
|
||||
company: frm.doc.company,
|
||||
},
|
||||
};
|
||||
|
||||
frm.set_query("source_warehouse", "items", () => ({
|
||||
filters: { company: frm.doc.company },
|
||||
}));
|
||||
|
||||
frm.set_indicator_formatter("sub_operation", (doc) => {
|
||||
if (doc.status === "Pending") return "red";
|
||||
return doc.status === "Complete" ? "green" : "orange";
|
||||
});
|
||||
|
||||
frm.set_indicator_formatter("sub_operation", function (doc) {
|
||||
if (doc.status == "Pending") {
|
||||
return "red";
|
||||
} else {
|
||||
return doc.status === "Complete" ? "green" : "orange";
|
||||
}
|
||||
});
|
||||
|
||||
frm.set_query("employee", () => {
|
||||
return {
|
||||
filters: {
|
||||
company: frm.doc.company,
|
||||
status: "Active",
|
||||
},
|
||||
};
|
||||
});
|
||||
frm.set_query("employee", () => ({
|
||||
filters: {
|
||||
company: frm.doc.company,
|
||||
status: "Active",
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
||||
pending_qty(frm) {
|
||||
@@ -88,7 +62,7 @@ frappe.ui.form.on("Job Card", {
|
||||
frappe.throw(__("Pending Quantity cannot be less than 0"));
|
||||
}
|
||||
|
||||
let remaining_qty = flt(frm.doc.for_quantity) - flt(frm.doc.total_completed_qty);
|
||||
const remaining_qty = flt(frm.doc.for_quantity) - flt(frm.doc.total_completed_qty);
|
||||
|
||||
if (remaining_qty < frm.doc.pending_qty) {
|
||||
frm.doc.pending_qty = 0.0;
|
||||
@@ -96,19 +70,15 @@ frappe.ui.form.on("Job Card", {
|
||||
frappe.throw(__("Pending Quantity cannot be greater than {0}", [remaining_qty]));
|
||||
}
|
||||
|
||||
let process_loss_qty = flt(remaining_qty) - flt(frm.doc.pending_qty);
|
||||
const process_loss_qty = flt(remaining_qty) - flt(frm.doc.pending_qty);
|
||||
frm.doc.process_loss_qty = process_loss_qty >= 0 ? process_loss_qty : 0;
|
||||
refresh_field("process_loss_qty");
|
||||
},
|
||||
|
||||
set_company_filters(frm, fieldname) {
|
||||
frm.set_query(fieldname, () => {
|
||||
return {
|
||||
filters: {
|
||||
company: frm.doc.company,
|
||||
},
|
||||
};
|
||||
});
|
||||
frm.set_query(fieldname, () => ({
|
||||
filters: { company: frm.doc.company },
|
||||
}));
|
||||
},
|
||||
|
||||
make_fields_read_only(frm) {
|
||||
@@ -123,33 +93,29 @@ frappe.ui.form.on("Job Card", {
|
||||
},
|
||||
|
||||
setup_stock_entry(frm) {
|
||||
if (
|
||||
frm.doc.track_semi_finished_goods &&
|
||||
frm.doc.docstatus === 1 &&
|
||||
!frm.doc.is_subcontracted &&
|
||||
(frm.doc.skip_material_transfer || frm.doc.transferred_qty > 0) &&
|
||||
flt(frm.doc.manufactured_qty) + flt(frm.doc.process_loss_qty) < flt(frm.doc.for_quantity)
|
||||
) {
|
||||
frm.add_custom_button(__("Make Stock Entry"), () => {
|
||||
frappe.confirm(
|
||||
__("Do you want to submit the stock entry?"),
|
||||
() => {
|
||||
frm.events.make_manufacture_stock_entry(frm, 1);
|
||||
},
|
||||
() => {
|
||||
frm.events.make_manufacture_stock_entry(frm, 0);
|
||||
}
|
||||
);
|
||||
}).addClass("btn-primary");
|
||||
}
|
||||
const { doc } = frm;
|
||||
const can_make_stock_entry =
|
||||
doc.track_semi_finished_goods &&
|
||||
doc.docstatus === 1 &&
|
||||
!doc.is_subcontracted &&
|
||||
(doc.skip_material_transfer || doc.transferred_qty > 0) &&
|
||||
flt(doc.manufactured_qty) + flt(doc.process_loss_qty) < flt(doc.for_quantity);
|
||||
|
||||
if (!can_make_stock_entry) return;
|
||||
|
||||
frm.add_custom_button(__("Make Stock Entry"), () => {
|
||||
frappe.confirm(
|
||||
__("Do you want to submit the stock entry?"),
|
||||
() => frm.events.make_manufacture_stock_entry(frm, 1),
|
||||
() => frm.events.make_manufacture_stock_entry(frm, 0)
|
||||
);
|
||||
}).addClass("btn-primary");
|
||||
},
|
||||
|
||||
make_manufacture_stock_entry(frm, submit_entry) {
|
||||
frm.call({
|
||||
method: "make_stock_entry_for_semi_fg_item",
|
||||
args: {
|
||||
auto_submit: submit_entry,
|
||||
},
|
||||
args: { auto_submit: submit_entry },
|
||||
doc: frm.doc,
|
||||
freeze: true,
|
||||
callback() {
|
||||
@@ -158,80 +124,58 @@ frappe.ui.form.on("Job Card", {
|
||||
});
|
||||
},
|
||||
|
||||
<<<<<<< HEAD
|
||||
refresh: function (frm) {
|
||||
frm.trigger("setup_stock_entry");
|
||||
|
||||
let has_items = frm.doc.items && frm.doc.items.length;
|
||||
=======
|
||||
refresh(frm) {
|
||||
const { doc } = frm;
|
||||
const has_items = doc.items && doc.items.length;
|
||||
|
||||
>>>>>>> 0a215b0717 (refactor: job_card.js code for better readability)
|
||||
frm.trigger("make_fields_read_only");
|
||||
|
||||
if (!frm.is_new() && frm.doc.__onload?.work_order_closed) {
|
||||
if (!frm.is_new() && doc.__onload?.work_order_closed) {
|
||||
frm.disable_save();
|
||||
return;
|
||||
}
|
||||
|
||||
if (frm.doc.is_subcontracted) {
|
||||
if (doc.is_subcontracted) {
|
||||
frm.trigger("make_subcontracting_po");
|
||||
return;
|
||||
}
|
||||
|
||||
if (frm.doc.docstatus > 0) {
|
||||
if (doc.docstatus > 0) {
|
||||
frm.set_df_property("pending_qty", "read_only", 1);
|
||||
}
|
||||
|
||||
let has_stock_entry = frm.doc.__onload && frm.doc.__onload.has_stock_entry ? true : false;
|
||||
|
||||
const has_stock_entry = !!doc.__onload?.has_stock_entry;
|
||||
frm.toggle_enable("for_quantity", !has_stock_entry);
|
||||
|
||||
if (frm.doc.docstatus != 0) {
|
||||
if (doc.docstatus != 0) {
|
||||
frm.fields_dict["time_logs"].grid.update_docfield_property("completed_qty", "read_only", 1);
|
||||
frm.fields_dict["time_logs"].grid.update_docfield_property("time_in_mins", "read_only", 1);
|
||||
}
|
||||
|
||||
if (!frm.is_new() && !frm.doc.skip_material_transfer && frm.doc.docstatus < 2) {
|
||||
let to_request = frm.doc.for_quantity > frm.doc.transferred_qty;
|
||||
let excess_transfer_allowed = frm.doc.__onload.job_card_excess_transfer;
|
||||
frm.events.setup_material_transfer_buttons(frm, has_items);
|
||||
|
||||
if (has_items && (to_request || excess_transfer_allowed)) {
|
||||
frm.add_custom_button(
|
||||
__("Material Request"),
|
||||
() => {
|
||||
frm.trigger("make_material_request");
|
||||
},
|
||||
__("Create")
|
||||
);
|
||||
}
|
||||
|
||||
// check if any row has untransferred materials
|
||||
// in case of multiple items in JC
|
||||
let to_transfer = frm.doc.items.some((row) => row.transferred_qty < row.required_qty);
|
||||
|
||||
if (has_items && (to_transfer || excess_transfer_allowed)) {
|
||||
frm.add_custom_button(
|
||||
__("Material Transfer"),
|
||||
() => {
|
||||
frm.trigger("make_stock_entry");
|
||||
},
|
||||
__("Create")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (frm.doc.docstatus == 1 && !frm.doc.is_corrective_job_card && !frm.doc.finished_good) {
|
||||
if (doc.docstatus == 1 && !doc.is_corrective_job_card && !doc.finished_good) {
|
||||
frm.trigger("setup_corrective_job_card");
|
||||
}
|
||||
|
||||
frm.set_query("quality_inspection", function () {
|
||||
return {
|
||||
query: "erpnext.stock.doctype.quality_inspection.quality_inspection.quality_inspection_query",
|
||||
filters: {
|
||||
item_code: frm.doc.production_item,
|
||||
reference_name: frm.doc.name,
|
||||
},
|
||||
};
|
||||
});
|
||||
frm.set_query("quality_inspection", () => ({
|
||||
query: "erpnext.stock.doctype.quality_inspection.quality_inspection.quality_inspection_query",
|
||||
filters: {
|
||||
item_code: doc.production_item,
|
||||
reference_name: doc.name,
|
||||
},
|
||||
}));
|
||||
|
||||
frm.trigger("toggle_operation_number");
|
||||
|
||||
<<<<<<< HEAD
|
||||
if (
|
||||
frm.doc.for_quantity + frm.doc.process_loss_qty > frm.doc.total_completed_qty &&
|
||||
(frm.doc.skip_material_transfer ||
|
||||
@@ -312,36 +256,165 @@ frappe.ui.form.on("Job Card", {
|
||||
frm.trigger("make_dashboard");
|
||||
}
|
||||
}
|
||||
=======
|
||||
const is_timer_running = frm.events.setup_job_action_buttons(frm, has_items);
|
||||
>>>>>>> 0a215b0717 (refactor: job_card.js code for better readability)
|
||||
|
||||
frm.trigger("setup_quality_inspection");
|
||||
|
||||
if (frm.doc.work_order) {
|
||||
frappe.db.get_value("Work Order", frm.doc.work_order, "transfer_material_against").then((r) => {
|
||||
if (r.message.transfer_material_against == "Work Order" && !frm.doc.operation_row_id) {
|
||||
if (doc.work_order) {
|
||||
frappe.db.get_value("Work Order", doc.work_order, "transfer_material_against").then((r) => {
|
||||
if (r.message.transfer_material_against == "Work Order" && !doc.operation_row_id) {
|
||||
frm.set_df_property("items", "hidden", 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let sbb_field = frm.get_docfield("serial_and_batch_bundle");
|
||||
const sbb_field = frm.get_docfield("serial_and_batch_bundle");
|
||||
if (sbb_field) {
|
||||
sbb_field.get_route_options_for_new_doc = () => {
|
||||
return {
|
||||
item_code: frm.doc.production_item,
|
||||
warehouse: frm.doc.wip_warehouse,
|
||||
voucher_type: frm.doc.doctype,
|
||||
};
|
||||
};
|
||||
sbb_field.get_route_options_for_new_doc = () => ({
|
||||
item_code: doc.production_item,
|
||||
warehouse: doc.wip_warehouse,
|
||||
voucher_type: doc.doctype,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Adds Material Request and Material Transfer buttons when items need to be transferred.
|
||||
setup_material_transfer_buttons(frm, has_items) {
|
||||
const { doc } = frm;
|
||||
|
||||
if (frm.is_new() || doc.skip_material_transfer || doc.docstatus >= 2) return;
|
||||
|
||||
const excess_transfer_allowed = doc.__onload.job_card_excess_transfer;
|
||||
const to_request = doc.for_quantity > doc.transferred_qty;
|
||||
|
||||
if (has_items && (to_request || excess_transfer_allowed)) {
|
||||
frm.add_custom_button(
|
||||
__("Material Request"),
|
||||
() => frm.trigger("make_material_request"),
|
||||
__("Create")
|
||||
);
|
||||
}
|
||||
|
||||
// check if any row has untransferred materials in case of multiple items in JC
|
||||
const to_transfer = doc.items.some((row) => row.transferred_qty < row.required_qty);
|
||||
|
||||
if (has_items && (to_transfer || excess_transfer_allowed)) {
|
||||
frm.add_custom_button(
|
||||
__("Material Transfer"),
|
||||
() => frm.trigger("make_stock_entry"),
|
||||
__("Create")
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
// Renders the correct action button (Start / Resume / Pause + Complete) based on job state.
|
||||
// Returns true if the job timer is actively running, so the caller can skip the stock entry button.
|
||||
setup_job_action_buttons(frm, has_items) {
|
||||
const { doc } = frm;
|
||||
|
||||
const has_remaining_qty = doc.for_quantity + doc.process_loss_qty > doc.total_completed_qty;
|
||||
const materials_ready =
|
||||
doc.skip_material_transfer ||
|
||||
doc.transferred_qty >= doc.for_quantity + doc.process_loss_qty ||
|
||||
!doc.finished_good ||
|
||||
!has_items?.length;
|
||||
|
||||
if (!has_remaining_qty || !materials_ready) return false;
|
||||
|
||||
let last_row = {};
|
||||
const has_sub_ops_or_pending_qty = doc.sub_operations?.length || doc.pending_qty > 0;
|
||||
if (has_sub_ops_or_pending_qty && doc.time_logs?.length) {
|
||||
last_row = get_last_row(doc.time_logs);
|
||||
}
|
||||
|
||||
const no_time_logs_yet = !doc.time_logs?.length;
|
||||
const pending_qty_cycle_done = flt(doc.pending_qty) > 0.0 && last_row?.to_time;
|
||||
const sub_operation_cycle_done = doc.sub_operations?.length && last_row?.to_time;
|
||||
const should_show_start =
|
||||
(no_time_logs_yet || pending_qty_cycle_done || sub_operation_cycle_done) && !doc.is_paused;
|
||||
|
||||
if (should_show_start) {
|
||||
frm.events.add_start_job_button(frm);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (doc.is_paused) {
|
||||
frm.add_custom_button(__("Resume Job"), () => {
|
||||
frm.call({
|
||||
method: "resume_job",
|
||||
doc: frm.doc,
|
||||
args: { start_time: frappe.datetime.now_datetime() },
|
||||
callback() {
|
||||
frm.reload_doc();
|
||||
},
|
||||
});
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
// Job is actively running — show Pause and Complete buttons.
|
||||
const manufactured_qty = doc.manufactured_qty || doc.total_completed_qty;
|
||||
const qty_yet_to_manufacture = doc.for_quantity - (manufactured_qty + doc.process_loss_qty);
|
||||
|
||||
if (qty_yet_to_manufacture > 0) {
|
||||
if (!doc.is_paused) {
|
||||
frm.add_custom_button(__("Pause Job"), () => {
|
||||
frm.call({
|
||||
method: "pause_job",
|
||||
doc: frm.doc,
|
||||
args: { end_time: frappe.datetime.now_datetime() },
|
||||
callback() {
|
||||
frm.reload_doc();
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
frm.add_custom_button(__("Complete Job"), () => {
|
||||
frm.trigger("complete_job_card");
|
||||
});
|
||||
|
||||
frm.trigger("make_dashboard");
|
||||
return true;
|
||||
}
|
||||
|
||||
frm.trigger("make_dashboard");
|
||||
return false;
|
||||
},
|
||||
|
||||
add_start_job_button(frm) {
|
||||
frm.add_custom_button(__("Start Job"), () => {
|
||||
const from_time = frappe.datetime.now_datetime();
|
||||
const has_no_employee = (frm.doc.employee && !frm.doc.employee.length) || !frm.doc.employee;
|
||||
|
||||
if (has_no_employee) {
|
||||
frappe.prompt(
|
||||
{
|
||||
fieldtype: "Table MultiSelect",
|
||||
label: __("Select Employees"),
|
||||
options: "Job Card Time Log",
|
||||
fieldname: "employees",
|
||||
reqd: 1,
|
||||
filters: { status: "Active" },
|
||||
},
|
||||
(d) => frm.events.start_timer(frm, from_time, d.employees),
|
||||
__("Assign Job to Employee")
|
||||
);
|
||||
} else {
|
||||
frm.events.start_timer(frm, from_time, frm.doc.employee);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
complete_job_card(frm) {
|
||||
let pending_qty = frm.doc.for_quantity - frm.doc.total_completed_qty;
|
||||
if (frm.doc.pending_qty > 0) {
|
||||
pending_qty = frm.doc.pending_qty;
|
||||
}
|
||||
|
||||
let fields = [
|
||||
const fields = [
|
||||
{
|
||||
fieldtype: "Float",
|
||||
label: __("Qty to Manufacture"),
|
||||
@@ -349,10 +422,9 @@ frappe.ui.form.on("Job Card", {
|
||||
reqd: 1,
|
||||
default: pending_qty,
|
||||
change() {
|
||||
let doc = frm.job_completion_dialog;
|
||||
|
||||
doc.set_value("completed_qty", doc.get_value("for_quantity"));
|
||||
doc.set_value("process_loss_qty", 0);
|
||||
const dialog = frm.job_completion_dialog;
|
||||
dialog.set_value("completed_qty", dialog.get_value("for_quantity"));
|
||||
dialog.set_value("process_loss_qty", 0);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -362,11 +434,10 @@ frappe.ui.form.on("Job Card", {
|
||||
reqd: 1,
|
||||
default: pending_qty,
|
||||
change() {
|
||||
let doc = frm.job_completion_dialog;
|
||||
|
||||
let pending_qty = doc.get_value("for_quantity") - doc.get_value("completed_qty");
|
||||
if (pending_qty > 0 && pending_qty != doc.get_value("pending_qty")) {
|
||||
doc.set_value("pending_qty", pending_qty);
|
||||
const dialog = frm.job_completion_dialog;
|
||||
const remaining = dialog.get_value("for_quantity") - dialog.get_value("completed_qty");
|
||||
if (remaining > 0 && remaining != dialog.get_value("pending_qty")) {
|
||||
dialog.set_value("pending_qty", remaining);
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -376,14 +447,13 @@ frappe.ui.form.on("Job Card", {
|
||||
fieldname: "pending_qty",
|
||||
default: 0.0,
|
||||
change() {
|
||||
let doc = frm.job_completion_dialog;
|
||||
|
||||
let process_loss_qty =
|
||||
doc.get_value("for_quantity") -
|
||||
doc.get_value("completed_qty") -
|
||||
doc.get_value("pending_qty");
|
||||
if (process_loss_qty >= 0 && process_loss_qty != doc.get_value("process_loss_qty")) {
|
||||
doc.set_value("process_loss_qty", process_loss_qty);
|
||||
const dialog = frm.job_completion_dialog;
|
||||
const process_loss_qty =
|
||||
dialog.get_value("for_quantity") -
|
||||
dialog.get_value("completed_qty") -
|
||||
dialog.get_value("pending_qty");
|
||||
if (process_loss_qty >= 0 && process_loss_qty != dialog.get_value("process_loss_qty")) {
|
||||
dialog.set_value("process_loss_qty", process_loss_qty);
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -392,14 +462,13 @@ frappe.ui.form.on("Job Card", {
|
||||
label: __("Process Loss Quantity"),
|
||||
fieldname: "process_loss_qty",
|
||||
onchange() {
|
||||
let doc = frm.job_completion_dialog;
|
||||
|
||||
let pending_qty =
|
||||
doc.get_value("for_quantity") -
|
||||
doc.get_value("completed_qty") -
|
||||
doc.get_value("process_loss_qty");
|
||||
if (pending_qty >= 0 && pending_qty != doc.get_value("pending_qty")) {
|
||||
doc.set_value("pending_qty", pending_qty);
|
||||
const dialog = frm.job_completion_dialog;
|
||||
const remaining =
|
||||
dialog.get_value("for_quantity") -
|
||||
dialog.get_value("completed_qty") -
|
||||
dialog.get_value("process_loss_qty");
|
||||
if (remaining >= 0 && remaining != dialog.get_value("pending_qty")) {
|
||||
dialog.set_value("pending_qty", remaining);
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -415,20 +484,16 @@ frappe.ui.form.on("Job Card", {
|
||||
fieldname: "sub_operation",
|
||||
options: "Operation",
|
||||
get_query() {
|
||||
let non_completed_operations = frm.doc.sub_operations.filter(
|
||||
(d) => d.status === "Pending"
|
||||
);
|
||||
const non_completed = frm.doc.sub_operations.filter((d) => d.status === "Pending");
|
||||
return {
|
||||
filters: {
|
||||
name: ["in", non_completed_operations.map((d) => d.sub_operation)],
|
||||
},
|
||||
filters: { name: ["in", non_completed.map((d) => d.sub_operation)] },
|
||||
};
|
||||
},
|
||||
reqd: 1,
|
||||
});
|
||||
}
|
||||
|
||||
let last_completed_row = get_last_completed_row(frm.doc.time_logs);
|
||||
const last_completed_row = get_last_completed_row(frm.doc.time_logs);
|
||||
let last_row = {};
|
||||
if (frm.doc.sub_operations?.length && frm.doc.time_logs?.length) {
|
||||
last_row = get_last_row(frm.doc.time_logs);
|
||||
@@ -461,7 +526,7 @@ frappe.ui.form.on("Job Card", {
|
||||
end_time: data.end_time,
|
||||
sub_operation: data.sub_operation,
|
||||
},
|
||||
callback: function (r) {
|
||||
callback() {
|
||||
frm.reload_doc();
|
||||
},
|
||||
});
|
||||
@@ -487,11 +552,8 @@ frappe.ui.form.on("Job Card", {
|
||||
frm.call({
|
||||
method: "start_timer",
|
||||
doc: frm.doc,
|
||||
args: {
|
||||
start_time: start_time,
|
||||
employees: employees,
|
||||
},
|
||||
callback: function (r) {
|
||||
args: { start_time, employees },
|
||||
callback() {
|
||||
frm.reload_doc();
|
||||
frm.trigger("make_dashboard");
|
||||
},
|
||||
@@ -499,7 +561,7 @@ frappe.ui.form.on("Job Card", {
|
||||
},
|
||||
|
||||
make_finished_good(frm) {
|
||||
let fields = [
|
||||
const fields = [
|
||||
{
|
||||
fieldtype: "Float",
|
||||
label: __("Completed Quantity"),
|
||||
@@ -525,12 +587,9 @@ frappe.ui.form.on("Job Card", {
|
||||
frm.call({
|
||||
method: "make_finished_good",
|
||||
doc: frm.doc,
|
||||
args: {
|
||||
qty: data.qty,
|
||||
end_time: data.end_time,
|
||||
},
|
||||
callback: function (r) {
|
||||
var doc = frappe.model.sync(r.message);
|
||||
args: { qty: data.qty, end_time: data.end_time },
|
||||
callback(r) {
|
||||
const doc = frappe.model.sync(r.message);
|
||||
frappe.set_route("Form", doc[0].doctype, doc[0].name);
|
||||
},
|
||||
});
|
||||
@@ -541,8 +600,8 @@ frappe.ui.form.on("Job Card", {
|
||||
);
|
||||
},
|
||||
|
||||
setup_quality_inspection: function (frm) {
|
||||
let quality_inspection_field = frm.get_docfield("quality_inspection");
|
||||
setup_quality_inspection(frm) {
|
||||
const quality_inspection_field = frm.get_docfield("quality_inspection");
|
||||
quality_inspection_field.get_route_options_for_new_doc = function (frm) {
|
||||
return {
|
||||
inspection_type: "In Process",
|
||||
@@ -557,24 +616,22 @@ frappe.ui.form.on("Job Card", {
|
||||
};
|
||||
},
|
||||
|
||||
setup_corrective_job_card: function (frm) {
|
||||
setup_corrective_job_card(frm) {
|
||||
frm.add_custom_button(
|
||||
__("Corrective Job Card"),
|
||||
() => {
|
||||
let operations = frm.doc.sub_operations.map((d) => d.sub_operation).concat(frm.doc.operation);
|
||||
const operations = frm.doc.sub_operations
|
||||
.map((d) => d.sub_operation)
|
||||
.concat(frm.doc.operation);
|
||||
|
||||
let fields = [
|
||||
const fields = [
|
||||
{
|
||||
fieldtype: "Link",
|
||||
label: __("Corrective Operation"),
|
||||
options: "Operation",
|
||||
fieldname: "operation",
|
||||
get_query() {
|
||||
return {
|
||||
filters: {
|
||||
is_corrective_operation: 1,
|
||||
},
|
||||
};
|
||||
return { filters: { is_corrective_operation: 1 } };
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -583,20 +640,14 @@ frappe.ui.form.on("Job Card", {
|
||||
options: "Operation",
|
||||
fieldname: "for_operation",
|
||||
get_query() {
|
||||
return {
|
||||
filters: {
|
||||
name: ["in", operations],
|
||||
},
|
||||
};
|
||||
return { filters: { name: ["in", operations] } };
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
frappe.prompt(
|
||||
fields,
|
||||
(d) => {
|
||||
frm.events.make_corrective_job_card(frm, d.operation, d.for_operation);
|
||||
},
|
||||
(d) => frm.events.make_corrective_job_card(frm, d.operation, d.for_operation),
|
||||
__("Select Corrective Operation")
|
||||
);
|
||||
},
|
||||
@@ -604,7 +655,7 @@ frappe.ui.form.on("Job Card", {
|
||||
);
|
||||
},
|
||||
|
||||
make_corrective_job_card: function (frm, operation, for_operation) {
|
||||
make_corrective_job_card(frm, operation, for_operation) {
|
||||
frappe.call({
|
||||
method: "erpnext.manufacturing.doctype.job_card.job_card.make_corrective_job_card",
|
||||
args: {
|
||||
@@ -612,7 +663,7 @@ frappe.ui.form.on("Job Card", {
|
||||
operation: operation,
|
||||
for_operation: for_operation,
|
||||
},
|
||||
callback: function (r) {
|
||||
callback(r) {
|
||||
if (r.message) {
|
||||
frappe.model.sync(r.message);
|
||||
frappe.set_route("Form", r.message.doctype, r.message.name);
|
||||
@@ -621,7 +672,7 @@ frappe.ui.form.on("Job Card", {
|
||||
});
|
||||
},
|
||||
|
||||
operation: function (frm) {
|
||||
operation(frm) {
|
||||
frm.trigger("toggle_operation_number");
|
||||
|
||||
if (frm.doc.operation && frm.doc.work_order) {
|
||||
@@ -631,28 +682,22 @@ frappe.ui.form.on("Job Card", {
|
||||
work_order: frm.doc.work_order,
|
||||
operation: frm.doc.operation,
|
||||
},
|
||||
callback: function (r) {
|
||||
if (r.message) {
|
||||
if (r.message.length == 1) {
|
||||
frm.set_value("operation_id", r.message[0].name);
|
||||
} else {
|
||||
let args = [];
|
||||
callback(r) {
|
||||
if (!r.message) return;
|
||||
|
||||
r.message.forEach((row) => {
|
||||
args.push({ label: row.idx, value: row.name });
|
||||
});
|
||||
|
||||
let description = __("Operation {0} added multiple times in the work order {1}", [
|
||||
frm.doc.operation,
|
||||
frm.doc.work_order,
|
||||
]);
|
||||
|
||||
frm.set_df_property("operation_row_number", "options", args);
|
||||
frm.set_df_property("operation_row_number", "description", description);
|
||||
}
|
||||
|
||||
frm.trigger("toggle_operation_number");
|
||||
if (r.message.length == 1) {
|
||||
frm.set_value("operation_id", r.message[0].name);
|
||||
} else {
|
||||
const args = r.message.map((row) => ({ label: row.idx, value: row.name }));
|
||||
const description = __("Operation {0} added multiple times in the work order {1}", [
|
||||
frm.doc.operation,
|
||||
frm.doc.work_order,
|
||||
]);
|
||||
frm.set_df_property("operation_row_number", "options", args);
|
||||
frm.set_df_property("operation_row_number", "description", description);
|
||||
}
|
||||
|
||||
frm.trigger("toggle_operation_number");
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -669,65 +714,35 @@ frappe.ui.form.on("Job Card", {
|
||||
frm.toggle_reqd("operation_row_number", !frm.doc.operation_id && frm.doc.operation);
|
||||
},
|
||||
|
||||
make_time_log: function (frm, args) {
|
||||
make_time_log(frm, args) {
|
||||
frm.events.update_sub_operation(frm, args);
|
||||
|
||||
frappe.call({
|
||||
method: "erpnext.manufacturing.doctype.job_card.job_card.make_time_log",
|
||||
args: {
|
||||
args: args,
|
||||
},
|
||||
args: { args },
|
||||
freeze: true,
|
||||
callback: function () {
|
||||
callback() {
|
||||
frm.reload_doc();
|
||||
frm.trigger("make_dashboard");
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
update_sub_operation: function (frm, args) {
|
||||
if (frm.doc.sub_operations && frm.doc.sub_operations.length) {
|
||||
let sub_operations = frm.doc.sub_operations.filter((d) => d.status != "Complete");
|
||||
if (sub_operations && sub_operations.length) {
|
||||
args["sub_operation"] = sub_operations[0].sub_operation;
|
||||
update_sub_operation(frm, args) {
|
||||
if (frm.doc.sub_operations?.length) {
|
||||
const pending_sub_ops = frm.doc.sub_operations.filter((d) => d.status != "Complete");
|
||||
if (pending_sub_ops.length) {
|
||||
args["sub_operation"] = pending_sub_ops[0].sub_operation;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
make_dashboard: function (frm) {
|
||||
make_dashboard(frm) {
|
||||
if (frm.doc.__islocal) return;
|
||||
var section = "";
|
||||
|
||||
function setCurrentIncrement() {
|
||||
currentIncrement += 1;
|
||||
return currentIncrement;
|
||||
}
|
||||
|
||||
function updateStopwatch(increment) {
|
||||
var hours = Math.floor(increment / 3600);
|
||||
var minutes = Math.floor((increment - hours * 3600) / 60);
|
||||
var seconds = Math.floor(flt(increment - hours * 3600 - minutes * 60, 2));
|
||||
|
||||
$(section)
|
||||
.find(".hours")
|
||||
.text(hours < 10 ? "0" + hours.toString() : hours.toString());
|
||||
$(section)
|
||||
.find(".minutes")
|
||||
.text(minutes < 10 ? "0" + minutes.toString() : minutes.toString());
|
||||
$(section)
|
||||
.find(".seconds")
|
||||
.text(seconds < 10 ? "0" + seconds.toString() : seconds.toString());
|
||||
}
|
||||
|
||||
function initialiseTimer() {
|
||||
const interval = setInterval(function () {
|
||||
var current = setCurrentIncrement();
|
||||
updateStopwatch(current);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
frm.dashboard.refresh();
|
||||
const timer = `
|
||||
|
||||
const timer_html = `
|
||||
<div class="stopwatch" style="font-weight:bold;margin:0px 13px 0px 2px;
|
||||
color:#545454;font-size:18px;display:inline-block;vertical-align:text-bottom;">
|
||||
<span class="hours">00</span>
|
||||
@@ -737,20 +752,44 @@ frappe.ui.form.on("Job Card", {
|
||||
<span class="seconds">00</span>
|
||||
</div>`;
|
||||
|
||||
let section;
|
||||
if (frappe.utils.is_xs()) {
|
||||
frm.dashboard.add_comment(timer, "white", true);
|
||||
frm.dashboard.add_comment(timer_html, "white", true);
|
||||
section = frm.layout.wrapper.find(".form-message-container");
|
||||
} else {
|
||||
section = frm.toolbar.page.add_inner_message(timer);
|
||||
section = frm.toolbar.page.add_inner_message(timer_html);
|
||||
}
|
||||
|
||||
let currentIncrement = frm.events.get_current_time(frm);
|
||||
if (frm.doc.time_logs?.length && frm.doc.time_logs[cint(frm.doc.time_logs.length) - 1].to_time) {
|
||||
updateStopwatch(currentIncrement);
|
||||
} else if (frm.doc.status == "On Hold") {
|
||||
updateStopwatch(currentIncrement);
|
||||
const pad = (n) => String(n).padStart(2, "0");
|
||||
|
||||
const update_stopwatch = (increment) => {
|
||||
const hours = Math.floor(increment / 3600);
|
||||
const minutes = Math.floor((increment - hours * 3600) / 60);
|
||||
const seconds = Math.floor(flt(increment - hours * 3600 - minutes * 60, 2));
|
||||
|
||||
section.find(".hours").text(pad(hours));
|
||||
section.find(".minutes").text(pad(minutes));
|
||||
section.find(".seconds").text(pad(seconds));
|
||||
};
|
||||
|
||||
let current_increment = frm.events.get_current_time(frm);
|
||||
|
||||
const start_timer = () => {
|
||||
setInterval(() => {
|
||||
current_increment += 1;
|
||||
update_stopwatch(current_increment);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const { time_logs, status } = frm.doc;
|
||||
const last_log_complete = time_logs?.length && time_logs[cint(time_logs.length) - 1].to_time;
|
||||
|
||||
if (last_log_complete) {
|
||||
update_stopwatch(current_increment);
|
||||
} else if (status == "On Hold") {
|
||||
update_stopwatch(current_increment);
|
||||
} else {
|
||||
initialiseTimer();
|
||||
start_timer();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -772,22 +811,22 @@ frappe.ui.form.on("Job Card", {
|
||||
return current_time;
|
||||
},
|
||||
|
||||
hide_timer: function (frm) {
|
||||
hide_timer(frm) {
|
||||
frm.toolbar.page.inner_toolbar.find(".stopwatch").remove();
|
||||
},
|
||||
|
||||
for_quantity: function (frm) {
|
||||
for_quantity(frm) {
|
||||
frm.doc.items = [];
|
||||
frm.call({
|
||||
method: "get_required_items",
|
||||
doc: frm.doc,
|
||||
callback: function () {
|
||||
callback() {
|
||||
refresh_field("items");
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
make_material_request: function (frm) {
|
||||
make_material_request(frm) {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.manufacturing.doctype.job_card.job_card.make_material_request",
|
||||
frm: frm,
|
||||
@@ -795,7 +834,7 @@ frappe.ui.form.on("Job Card", {
|
||||
});
|
||||
},
|
||||
|
||||
make_stock_entry: function (frm) {
|
||||
make_stock_entry(frm) {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.manufacturing.doctype.job_card.job_card.make_stock_entry",
|
||||
frm: frm,
|
||||
@@ -803,11 +842,11 @@ frappe.ui.form.on("Job Card", {
|
||||
});
|
||||
},
|
||||
|
||||
timer: function (frm) {
|
||||
timer(frm) {
|
||||
return `<button> Start </button>`;
|
||||
},
|
||||
|
||||
set_total_completed_qty: function (frm) {
|
||||
set_total_completed_qty(frm) {
|
||||
frm.doc.total_completed_qty = 0;
|
||||
frm.doc.time_logs.forEach((d) => {
|
||||
if (d.completed_qty) {
|
||||
@@ -816,10 +855,9 @@ frappe.ui.form.on("Job Card", {
|
||||
});
|
||||
|
||||
if (frm.doc.total_completed_qty && frm.doc.for_quantity > frm.doc.total_completed_qty) {
|
||||
let flt_precision = precision("for_quantity", frm.doc);
|
||||
let process_loss_qty =
|
||||
const flt_precision = precision("for_quantity", frm.doc);
|
||||
const process_loss_qty =
|
||||
flt(frm.doc.for_quantity, flt_precision) - flt(frm.doc.total_completed_qty, flt_precision);
|
||||
|
||||
frm.set_value("process_loss_qty", process_loss_qty);
|
||||
}
|
||||
|
||||
@@ -836,8 +874,8 @@ frappe.ui.form.on("Job Card", {
|
||||
});
|
||||
|
||||
frappe.ui.form.on("Job Card Time Log", {
|
||||
completed_qty: function (frm, cdt, cdn) {
|
||||
let row = locals[cdt][cdn];
|
||||
completed_qty(frm, cdt, cdn) {
|
||||
const row = locals[cdt][cdn];
|
||||
if (!row.completed_qty) {
|
||||
frappe.model.set_value(row.doctype, row.name, {
|
||||
time_in_mins: 0,
|
||||
@@ -854,12 +892,8 @@ function get_seconds_diff(d1, d2) {
|
||||
}
|
||||
|
||||
function get_last_completed_row(time_logs) {
|
||||
let completed_rows = time_logs.filter((d) => d.to_time);
|
||||
|
||||
if (completed_rows?.length) {
|
||||
let last_completed_row = completed_rows[completed_rows.length - 1];
|
||||
return last_completed_row;
|
||||
}
|
||||
const completed_rows = time_logs.filter((d) => d.to_time);
|
||||
return completed_rows[completed_rows.length - 1];
|
||||
}
|
||||
|
||||
function get_last_row(time_logs) {
|
||||
|
||||
Reference in New Issue
Block a user