Merge pull request #46801 from rohitwaghchaure/fixed-ux-for-job-card

fix: UX for partial job card completion
This commit is contained in:
rohitwaghchaure
2025-03-30 22:51:30 +05:30
committed by GitHub
3 changed files with 76 additions and 14 deletions

View File

@@ -45,6 +45,7 @@ frappe.ui.form.on("Job Card", {
setup_stock_entry(frm) {
if (
frm.doc.manufactured_qty &&
frm.doc.finished_good &&
frm.doc.docstatus === 1 &&
!frm.doc.is_subcontracted &&
@@ -91,11 +92,11 @@ frappe.ui.form.on("Job Card", {
frm.fields_dict["time_logs"].grid.update_docfield_property("time_in_mins", "read_only", 1);
}
if (!frm.is_new() && !frm.doc.skip_material_transfer && has_items && frm.doc.docstatus < 2) {
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;
if (to_request || excess_transfer_allowed) {
if (has_items && (to_request || excess_transfer_allowed)) {
frm.add_custom_button(__("Material Request"), () => {
frm.trigger("make_material_request");
});
@@ -105,7 +106,7 @@ frappe.ui.form.on("Job Card", {
// in case of multiple items in JC
let to_transfer = frm.doc.items.some((row) => row.transferred_qty < row.required_qty);
if (to_transfer || excess_transfer_allowed) {
if (has_items && (to_transfer || excess_transfer_allowed)) {
frm.add_custom_button(__("Material Transfer"), () => {
frm.trigger("make_stock_entry");
});
@@ -132,7 +133,8 @@ frappe.ui.form.on("Job Card", {
frm.doc.for_quantity + frm.doc.process_loss_qty > frm.doc.total_completed_qty &&
(frm.doc.skip_material_transfer ||
frm.doc.transferred_qty >= frm.doc.for_quantity + frm.doc.process_loss_qty ||
!frm.doc.finished_good)
!frm.doc.finished_good ||
!has_items?.length)
) {
if (!frm.doc.time_logs?.length) {
frm.add_custom_button(__("Start Job"), () => {
@@ -168,7 +170,8 @@ frappe.ui.form.on("Job Card", {
});
});
} else {
if (frm.doc.for_quantity - frm.doc.manufactured_qty > 0) {
let manufactured_qty = frm.doc.manufactured_qty || frm.doc.total_completed_qty;
if (frm.doc.for_quantity - (manufactured_qty + frm.doc.process_loss_qty) > 0) {
if (!frm.doc.is_paused) {
frm.add_custom_button(__("Pause Job"), () => {
frm.call({
@@ -217,12 +220,48 @@ frappe.ui.form.on("Job Card", {
complete_job_card(frm) {
let fields = [
{
fieldtype: "Float",
label: __("Qty to Manufacture"),
fieldname: "for_quantity",
reqd: 1,
default: frm.doc.for_quantity,
change() {
let doc = frm.job_completion_dialog;
doc.set_value("completed_qty", doc.get_value("for_quantity"));
doc.set_value("process_loss_qty", 0);
},
},
{
fieldtype: "Float",
label: __("Completed Quantity"),
fieldname: "qty",
fieldname: "completed_qty",
reqd: 1,
default: frm.doc.for_quantity - frm.doc.total_completed_qty,
change() {
let doc = frm.job_completion_dialog;
let process_loss_qty = doc.get_value("for_quantity") - doc.get_value("completed_qty");
if (process_loss_qty > 0 && process_loss_qty != doc.get_value("process_loss_qty")) {
doc.set_value("process_loss_qty", process_loss_qty);
}
},
},
{
fieldtype: "Float",
label: __("Process Loss Quantity"),
fieldname: "process_loss_qty",
reqd: 1,
onchange() {
let doc = frm.job_completion_dialog;
let completed_qty = doc.get_value("for_quantity") - doc.get_value("process_loss_qty");
doc.set_value("completed_qty", completed_qty);
},
},
{
fieldtype: "Section Break",
},
];
@@ -236,7 +275,7 @@ frappe.ui.form.on("Job Card", {
});
}
frappe.prompt(
frm.job_completion_dialog = frappe.prompt(
fields,
(data) => {
if (data.qty <= 0) {
@@ -247,7 +286,8 @@ frappe.ui.form.on("Job Card", {
method: "complete_job_card",
doc: frm.doc,
args: {
qty: data.qty,
qty: data.completed_qty,
for_quantity: data.for_quantity,
end_time: data.end_time,
},
callback: function (r) {
@@ -628,7 +668,15 @@ frappe.ui.form.on("Job Card", {
});
frappe.ui.form.on("Job Card Time Log", {
completed_qty: function (frm) {
completed_qty: function (frm, cdt, cdn) {
let row = locals[cdt][cdn];
if (!row.completed_qty) {
frappe.model.set_value(row.doctype, row.name, {
time_in_mins: 0,
to_time: "",
});
}
frm.events.set_total_completed_qty(frm);
},

View File

@@ -73,6 +73,7 @@
"status",
"operation_row_id",
"is_paused",
"track_semi_finished_goods",
"column_break_20",
"operation_row_number",
"operation_id",
@@ -530,10 +531,11 @@
"read_only": 1
},
{
"depends_on": "eval:doc.track_semi_finished_goods",
"fieldname": "target_warehouse",
"fieldtype": "Link",
"label": "Target Warehouse",
"mandatory_depends_on": "eval:doc.finished_good",
"mandatory_depends_on": "eval:doc.track_semi_finished_goods",
"options": "Warehouse"
},
{
@@ -610,12 +612,19 @@
"fieldtype": "Check",
"label": "Is Paused",
"read_only": 1
},
{
"default": "0",
"fetch_from": "work_order.track_semi_finished_goods",
"fieldname": "track_semi_finished_goods",
"fieldtype": "Check",
"label": "Track Semi Finished Goods"
}
],
"grid_page_length": 50,
"is_submittable": 1,
"links": [],
"modified": "2025-03-25 17:50:18.608869",
"modified": "2025-03-30 18:53:38.206399",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Job Card",

View File

@@ -129,6 +129,7 @@ class JobCard(Document):
time_required: DF.Float
total_completed_qty: DF.Float
total_time_in_mins: DF.Float
track_semi_finished_goods: DF.Check
transferred_qty: DF.Float
wip_warehouse: DF.Link | None
work_order: DF.Link
@@ -723,7 +724,7 @@ class JobCard(Document):
)
def validate_job_card(self):
if self.finished_good:
if self.track_semi_finished_goods:
return
if self.work_order and frappe.get_cached_value("Work Order", self.work_order, "status") == "Stopped":
@@ -794,7 +795,7 @@ class JobCard(Document):
)
def update_work_order(self):
if self.finished_good:
if self.track_semi_finished_goods:
return
if not self.work_order:
@@ -1037,7 +1038,7 @@ class JobCard(Document):
if self.docstatus == 0 and self.time_logs:
self.status = "Work In Progress"
if not self.finished_good and self.docstatus < 2:
if not self.track_semi_finished_goods and self.docstatus < 2:
if flt(self.for_quantity) <= flt(self.transferred_qty):
self.status = "Material Transferred"
@@ -1254,6 +1255,10 @@ class JobCard(Document):
if kwargs.end_time:
self.add_time_logs(to_time=kwargs.end_time, completed_qty=kwargs.qty, employees=self.employee)
if kwargs.for_quantity:
self.for_quantity = kwargs.for_quantity
self.save()
else:
self.add_time_logs(completed_qty=kwargs.qty, employees=self.employee)