mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-26 00:14:50 +00:00
feat: allow to transfer additional materials
This commit is contained in:
@@ -24,6 +24,9 @@
|
|||||||
"overproduction_percentage_for_sales_order",
|
"overproduction_percentage_for_sales_order",
|
||||||
"column_break_16",
|
"column_break_16",
|
||||||
"overproduction_percentage_for_work_order",
|
"overproduction_percentage_for_work_order",
|
||||||
|
"section_break_xhtl",
|
||||||
|
"transfer_extra_materials_percentage",
|
||||||
|
"column_break_kemp",
|
||||||
"job_card_section",
|
"job_card_section",
|
||||||
"add_corrective_operation_cost_in_finished_good_valuation",
|
"add_corrective_operation_cost_in_finished_good_valuation",
|
||||||
"enforce_time_logs",
|
"enforce_time_logs",
|
||||||
@@ -243,13 +246,28 @@
|
|||||||
"fieldname": "enforce_time_logs",
|
"fieldname": "enforce_time_logs",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Enforce Time Logs"
|
"label": "Enforce Time Logs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_xhtl",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Extra Material Transfer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_kemp",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "The user will be able to transfer additional materials from the store to the Work in Progress (WIP) warehouse.",
|
||||||
|
"fieldname": "transfer_extra_materials_percentage",
|
||||||
|
"fieldtype": "Percent",
|
||||||
|
"label": "Transfer Extra Raw Materials to WIP (%)"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "icon-wrench",
|
"icon": "icon-wrench",
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2025-05-16 11:23:16.916512",
|
"modified": "2025-09-08 19:48:31.726126",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Manufacturing Settings",
|
"name": "Manufacturing Settings",
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class ManufacturingSettings(Document):
|
|||||||
overproduction_percentage_for_sales_order: DF.Percent
|
overproduction_percentage_for_sales_order: DF.Percent
|
||||||
overproduction_percentage_for_work_order: DF.Percent
|
overproduction_percentage_for_work_order: DF.Percent
|
||||||
set_op_cost_and_scrap_from_sub_assemblies: DF.Check
|
set_op_cost_and_scrap_from_sub_assemblies: DF.Check
|
||||||
|
transfer_extra_materials_percentage: DF.Percent
|
||||||
update_bom_costs_automatically: DF.Check
|
update_bom_costs_automatically: DF.Check
|
||||||
validate_components_quantities_per_bom: DF.Check
|
validate_components_quantities_per_bom: DF.Check
|
||||||
# end: auto-generated types
|
# end: auto-generated types
|
||||||
|
|||||||
@@ -732,6 +732,19 @@ erpnext.work_order = {
|
|||||||
let pending_to_transfer = frm.doc.required_items.some(
|
let pending_to_transfer = frm.doc.required_items.some(
|
||||||
(item) => flt(item.transferred_qty) < flt(item.required_qty)
|
(item) => flt(item.transferred_qty) < flt(item.required_qty)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let transfer_extra_materials_percentage =
|
||||||
|
frm.doc.__onload?.transfer_extra_materials_percentage;
|
||||||
|
let allowed_qty = 0;
|
||||||
|
let transfer_extra_materials = false;
|
||||||
|
if (!pending_to_transfer && transfer_extra_materials_percentage) {
|
||||||
|
allowed_qty = frm.doc.qty + (transfer_extra_materials_percentage / 100) * frm.doc.qty;
|
||||||
|
|
||||||
|
if (allowed_qty > frm.doc.material_transferred_for_manufacturing) {
|
||||||
|
transfer_extra_materials = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (pending_to_transfer && frm.doc.status != "Stopped") {
|
if (pending_to_transfer && frm.doc.status != "Stopped") {
|
||||||
frm.has_start_btn = true;
|
frm.has_start_btn = true;
|
||||||
frm.add_custom_button(__("Create Pick List"), function () {
|
frm.add_custom_button(__("Create Pick List"), function () {
|
||||||
@@ -742,6 +755,14 @@ erpnext.work_order = {
|
|||||||
erpnext.work_order.make_se(frm, "Material Transfer for Manufacture");
|
erpnext.work_order.make_se(frm, "Material Transfer for Manufacture");
|
||||||
});
|
});
|
||||||
start_btn.addClass("btn-primary");
|
start_btn.addClass("btn-primary");
|
||||||
|
} else if (transfer_extra_materials && allowed_qty) {
|
||||||
|
let qty = allowed_qty - flt(frm.doc.material_transferred_for_manufacturing);
|
||||||
|
|
||||||
|
if (qty > 0) {
|
||||||
|
frm.add_custom_button(__("Transfer Extra Material"), function () {
|
||||||
|
erpnext.work_order.make_se(frm, "Material Transfer for Manufacture", qty);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -967,19 +988,35 @@ erpnext.work_order = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
make_se: function (frm, purpose) {
|
make_se: function (frm, purpose, qty) {
|
||||||
this.show_prompt_for_qty_input(frm, purpose)
|
if (qty) {
|
||||||
.then((data) => {
|
frappe
|
||||||
return frappe.xcall("erpnext.manufacturing.doctype.work_order.work_order.make_stock_entry", {
|
.xcall("erpnext.manufacturing.doctype.work_order.work_order.make_stock_entry", {
|
||||||
work_order_id: frm.doc.name,
|
work_order_id: frm.doc.name,
|
||||||
purpose: purpose,
|
purpose: purpose,
|
||||||
qty: data.qty,
|
qty: qty,
|
||||||
|
})
|
||||||
|
.then((stock_entry) => {
|
||||||
|
frappe.model.sync(stock_entry);
|
||||||
|
frappe.set_route("Form", stock_entry.doctype, stock_entry.name);
|
||||||
});
|
});
|
||||||
})
|
} else {
|
||||||
.then((stock_entry) => {
|
this.show_prompt_for_qty_input(frm, purpose)
|
||||||
frappe.model.sync(stock_entry);
|
.then((data) => {
|
||||||
frappe.set_route("Form", stock_entry.doctype, stock_entry.name);
|
return frappe.xcall(
|
||||||
});
|
"erpnext.manufacturing.doctype.work_order.work_order.make_stock_entry",
|
||||||
|
{
|
||||||
|
work_order_id: frm.doc.name,
|
||||||
|
purpose: purpose,
|
||||||
|
qty: data.qty,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.then((stock_entry) => {
|
||||||
|
frappe.model.sync(stock_entry);
|
||||||
|
frappe.set_route("Form", stock_entry.doctype, stock_entry.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
create_pick_list: function (frm, purpose = "Material Transfer for Manufacture") {
|
create_pick_list: function (frm, purpose = "Material Transfer for Manufacture") {
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ class WorkOrder(Document):
|
|||||||
self.set_onload("material_consumption", ms.material_consumption)
|
self.set_onload("material_consumption", ms.material_consumption)
|
||||||
self.set_onload("backflush_raw_materials_based_on", ms.backflush_raw_materials_based_on)
|
self.set_onload("backflush_raw_materials_based_on", ms.backflush_raw_materials_based_on)
|
||||||
self.set_onload("overproduction_percentage", ms.overproduction_percentage_for_work_order)
|
self.set_onload("overproduction_percentage", ms.overproduction_percentage_for_work_order)
|
||||||
|
self.set_onload("transfer_extra_materials_percentage", ms.transfer_extra_materials_percentage)
|
||||||
self.set_onload("show_create_job_card_button", self.show_create_job_card_button())
|
self.set_onload("show_create_job_card_button", self.show_create_job_card_button())
|
||||||
self.set_onload(
|
self.set_onload(
|
||||||
"enable_stock_reservation",
|
"enable_stock_reservation",
|
||||||
@@ -485,6 +486,13 @@ class WorkOrder(Document):
|
|||||||
|
|
||||||
qty = self.get_transferred_or_manufactured_qty(purpose)
|
qty = self.get_transferred_or_manufactured_qty(purpose)
|
||||||
|
|
||||||
|
if not allowance_percentage and purpose == "Material Transfer for Manufacture":
|
||||||
|
allowance_percentage = flt(
|
||||||
|
frappe.db.get_single_value(
|
||||||
|
"Manufacturing Settings", "transfer_extra_materials_percentage"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
completed_qty = self.qty + (allowance_percentage / 100 * self.qty)
|
completed_qty = self.qty + (allowance_percentage / 100 * self.qty)
|
||||||
if qty > completed_qty:
|
if qty > completed_qty:
|
||||||
frappe.throw(
|
frappe.throw(
|
||||||
|
|||||||
@@ -2640,10 +2640,16 @@ class StockEntry(StockController):
|
|||||||
frappe.db.get_single_value("Manufacturing Settings", "overproduction_percentage_for_work_order")
|
frappe.db.get_single_value("Manufacturing Settings", "overproduction_percentage_for_work_order")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
transfer_extra_materials_percentage = flt(
|
||||||
|
frappe.db.get_single_value("Manufacturing Settings", "transfer_extra_materials_percentage")
|
||||||
|
)
|
||||||
|
|
||||||
to_transfer_qty = flt(self.pro_doc.material_transferred_for_manufacturing) + flt(
|
to_transfer_qty = flt(self.pro_doc.material_transferred_for_manufacturing) + flt(
|
||||||
self.fg_completed_qty
|
self.fg_completed_qty
|
||||||
)
|
)
|
||||||
transfer_limit_qty = max_qty + ((max_qty * overproduction_percentage) / 100)
|
transfer_limit_qty = max_qty + ((max_qty * overproduction_percentage) / 100)
|
||||||
|
if transfer_extra_materials_percentage:
|
||||||
|
transfer_limit_qty = max_qty + ((max_qty * transfer_extra_materials_percentage) / 100)
|
||||||
|
|
||||||
if transfer_limit_qty >= to_transfer_qty:
|
if transfer_limit_qty >= to_transfer_qty:
|
||||||
allow_overproduction = True
|
allow_overproduction = True
|
||||||
@@ -2693,11 +2699,22 @@ class StockEntry(StockController):
|
|||||||
else:
|
else:
|
||||||
wip_warehouse = None
|
wip_warehouse = None
|
||||||
|
|
||||||
|
transfer_extra_materials_percentage = flt(
|
||||||
|
frappe.db.get_single_value("Manufacturing Settings", "transfer_extra_materials_percentage")
|
||||||
|
)
|
||||||
|
|
||||||
for d in work_order.get("required_items"):
|
for d in work_order.get("required_items"):
|
||||||
if consider_job_card and (d.item_code not in job_card_items):
|
if consider_job_card and (d.item_code not in job_card_items):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
additional_qty = 0.0
|
||||||
|
if transfer_extra_materials_percentage:
|
||||||
|
additional_qty = transfer_extra_materials_percentage * flt(d.required_qty) / 100
|
||||||
|
|
||||||
transfer_pending = flt(d.required_qty) > flt(d.transferred_qty)
|
transfer_pending = flt(d.required_qty) > flt(d.transferred_qty)
|
||||||
|
if additional_qty:
|
||||||
|
transfer_pending = (flt(d.required_qty) + additional_qty) > flt(d.transferred_qty)
|
||||||
|
|
||||||
can_transfer = transfer_pending or (backflush_based_on == "Material Transferred for Manufacture")
|
can_transfer = transfer_pending or (backflush_based_on == "Material Transferred for Manufacture")
|
||||||
|
|
||||||
if not can_transfer:
|
if not can_transfer:
|
||||||
|
|||||||
Reference in New Issue
Block a user