mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-17 08:35:00 +00:00
fix: operation status and bom validation
(cherry picked from commit 95baf953a8)
This commit is contained in:
committed by
Mergify
parent
8c536df5f2
commit
11222653ce
@@ -580,9 +580,12 @@ frappe.ui.form.on("BOM", {
|
||||
frappe.ui.form.on("BOM Operation", {
|
||||
finished_good(frm, cdt, cdn) {
|
||||
let row = locals[cdt][cdn];
|
||||
if (row.finished_good === frm.doc.item) {
|
||||
frappe.model.set_value(row.doctype, row.name, "is_final_finished_good", 1);
|
||||
}
|
||||
frappe.model.set_value(
|
||||
row.doctype,
|
||||
row.name,
|
||||
"is_final_finished_good",
|
||||
row.finished_good === frm.doc.item
|
||||
);
|
||||
},
|
||||
|
||||
bom_no(frm, cdt, cdn) {
|
||||
|
||||
@@ -296,6 +296,55 @@ class BOM(WebsiteGenerator):
|
||||
self.set_process_loss_qty()
|
||||
self.validate_scrap_items()
|
||||
self.set_default_uom()
|
||||
self.validate_semi_finished_goods()
|
||||
self.validate_raw_materials_of_operation()
|
||||
|
||||
def validate_semi_finished_goods(self):
|
||||
if not self.track_semi_finished_goods or not self.operations:
|
||||
return
|
||||
|
||||
fg_items = []
|
||||
for row in self.operations:
|
||||
if not row.is_final_finished_good:
|
||||
continue
|
||||
|
||||
fg_items.append(row.finished_good)
|
||||
|
||||
if not fg_items:
|
||||
frappe.throw(
|
||||
_(
|
||||
"Since you have enabled 'Track Semi Finished Goods', at least one operation must have 'Is Final Finished Good' checked. For that set the FG / Semi FG Item as {0} against an operation."
|
||||
).format(bold(self.item)),
|
||||
)
|
||||
|
||||
if fg_items and len(fg_items) > 1:
|
||||
frappe.throw(
|
||||
_(
|
||||
"Only one operation can have 'Is Final Finished Good' checked when 'Track Semi Finished Goods' is enabled."
|
||||
),
|
||||
)
|
||||
|
||||
def validate_raw_materials_of_operation(self):
|
||||
if not self.track_semi_finished_goods or not self.operations:
|
||||
return
|
||||
|
||||
operation_idx_with_no_rm = {}
|
||||
for row in self.operations:
|
||||
if row.bom_no:
|
||||
continue
|
||||
|
||||
operation_idx_with_no_rm[row.idx] = row.operation
|
||||
|
||||
for row in self.items:
|
||||
if row.operation_row_id and row.operation_row_id in operation_idx_with_no_rm:
|
||||
del operation_idx_with_no_rm[row.operation_row_id]
|
||||
|
||||
for idx, row in operation_idx_with_no_rm.items():
|
||||
frappe.throw(
|
||||
_("For operation {0} at row {1}, please add raw materials or set a BOM against it.").format(
|
||||
bold(row.operation), idx
|
||||
),
|
||||
)
|
||||
|
||||
def set_default_uom(self):
|
||||
if not self.get("items"):
|
||||
|
||||
@@ -166,6 +166,25 @@ class JobCard(Document):
|
||||
|
||||
self.validate_work_order()
|
||||
self.set_employees()
|
||||
self.validate_semi_finished_goods()
|
||||
|
||||
def validate_semi_finished_goods(self):
|
||||
if not self.track_semi_finished_goods:
|
||||
return
|
||||
|
||||
if self.items and not self.transferred_qty and not self.skip_material_transfer:
|
||||
frappe.throw(
|
||||
_(
|
||||
"Materials needs to be transferred to the work in progress warehouse for the job card {0}"
|
||||
).format(self.name)
|
||||
)
|
||||
|
||||
if self.docstatus == 1 and not self.total_completed_qty:
|
||||
frappe.throw(
|
||||
_(
|
||||
"Total Completed Qty is required for Job Card {0}, please start and complete the job card before submission"
|
||||
).format(self.name)
|
||||
)
|
||||
|
||||
def on_update(self):
|
||||
self.validate_job_card_qty()
|
||||
@@ -1354,6 +1373,9 @@ class JobCard(Document):
|
||||
employees=self.employee,
|
||||
sub_operation=kwargs.get("sub_operation"),
|
||||
)
|
||||
|
||||
if self.docstatus == 1:
|
||||
self.update_work_order()
|
||||
else:
|
||||
self.add_time_logs(completed_qty=kwargs.qty, employees=self.employee)
|
||||
self.save()
|
||||
|
||||
@@ -809,7 +809,7 @@ erpnext.work_order = {
|
||||
}
|
||||
}
|
||||
|
||||
if (frm.doc.status != "Stopped") {
|
||||
if (frm.doc.status != "Stopped" && !frm.doc.track_semi_finished_goods) {
|
||||
// If "Material Consumption is check in Manufacturing Settings, allow Material Consumption
|
||||
if (frm.doc.__onload && frm.doc.__onload.material_consumption == 1) {
|
||||
if (flt(doc.material_transferred_for_manufacturing) > 0 || frm.doc.skip_transfer) {
|
||||
|
||||
@@ -248,6 +248,16 @@ class WorkOrder(Document):
|
||||
if self.is_new() and frappe.db.get_single_value("Stock Settings", "auto_reserve_stock"):
|
||||
self.reserve_stock = 1
|
||||
|
||||
def before_save(self):
|
||||
self.set_skip_transfer_for_operations()
|
||||
|
||||
def set_skip_transfer_for_operations(self):
|
||||
if not self.track_semi_finished_goods:
|
||||
return
|
||||
|
||||
for op in self.operations:
|
||||
op.skip_material_transfer = self.skip_transfer
|
||||
|
||||
def validate_operations_sequence(self):
|
||||
if all([not op.sequence_id for op in self.operations]):
|
||||
for op in self.operations:
|
||||
|
||||
@@ -2006,6 +2006,7 @@ class StockEntry(StockController, SubcontractingInwardController):
|
||||
else:
|
||||
job_doc.set_consumed_qty_in_job_card_item(self)
|
||||
job_doc.set_manufactured_qty()
|
||||
job_doc.update_work_order()
|
||||
|
||||
if self.work_order:
|
||||
pro_doc = frappe.get_doc("Work Order", self.work_order)
|
||||
|
||||
@@ -110,7 +110,9 @@ class ManufactureEntry:
|
||||
_dict.from_warehouse = self.source_wh.get(item_code) or self.wip_warehouse
|
||||
_dict.to_warehouse = ""
|
||||
|
||||
if backflush_based_on != "BOM":
|
||||
if backflush_based_on != "BOM" and not frappe.db.get_value(
|
||||
"Job Card", self.job_card, "skip_material_transfer"
|
||||
):
|
||||
calculated_qty = flt(_dict.transferred_qty) - flt(_dict.consumed_qty)
|
||||
if calculated_qty < 0:
|
||||
frappe.throw(
|
||||
|
||||
Reference in New Issue
Block a user