refactor: pick list from material request

This commit is contained in:
Mihir Kandoi
2025-12-17 14:41:09 +05:30
parent 5f6ed62c03
commit 1778e2c564
6 changed files with 65 additions and 30 deletions

View File

@@ -393,12 +393,16 @@ class StatusUpdater(Document):
self.item_allowance, self.item_allowance,
self.global_qty_allowance, self.global_qty_allowance,
self.global_amount_allowance, self.global_amount_allowance,
) = get_allowance_for( ) = (
item["item_code"], get_allowance_for(
self.item_allowance, item["item_code"],
self.global_qty_allowance, self.item_allowance,
self.global_amount_allowance, self.global_qty_allowance,
qty_or_amount, self.global_amount_allowance,
qty_or_amount,
)
if args["source_dt"] != "Pick List Item"
else (0, {}, None, None)
) )
role_allowed_to_over_deliver_receive = frappe.get_single_value( role_allowed_to_over_deliver_receive = frappe.get_single_value(
@@ -436,14 +440,17 @@ class StatusUpdater(Document):
): ):
return return
if qty_or_amount == "qty": if args["source_dt"] != "Pick List Item":
action_msg = _( if qty_or_amount == "qty":
'To allow over receipt / delivery, update "Over Receipt/Delivery Allowance" in Stock Settings or the Item.' action_msg = _(
) 'To allow over receipt / delivery, update "Over Receipt/Delivery Allowance" in Stock Settings or the Item.'
)
else:
action_msg = _(
'To allow over billing, update "Over Billing Allowance" in Accounts Settings or the Item.'
)
else: else:
action_msg = _( action_msg = None
'To allow over billing, update "Over Billing Allowance" in Accounts Settings or the Item.'
)
frappe.throw( frappe.throw(
_( _(
@@ -455,8 +462,7 @@ class StatusUpdater(Document):
frappe.bold(_(self.doctype)), frappe.bold(_(self.doctype)),
frappe.bold(item.get("item_code")), frappe.bold(item.get("item_code")),
) )
+ "<br><br>" + ("<br><br>" + action_msg if action_msg else ""),
+ action_msg,
OverAllowanceError, OverAllowanceError,
title=_("Limit Crossed"), title=_("Limit Crossed"),
) )

View File

@@ -139,11 +139,13 @@ frappe.ui.form.on("Material Request", {
if (flt(frm.doc.per_ordered, precision) < 100) { if (flt(frm.doc.per_ordered, precision) < 100) {
let add_create_pick_list_button = () => { let add_create_pick_list_button = () => {
frm.add_custom_button( if (frm.doc.items.some((item) => item.stock_qty - item.picked_qty > 0)) {
__("Pick List"), frm.add_custom_button(
() => frm.events.create_pick_list(frm), __("Pick List"),
__("Create") () => frm.events.create_pick_list(frm),
); __("Create")
);
}
}; };
if (frm.doc.material_request_type === "Material Transfer") { if (frm.doc.material_request_type === "Material Transfer") {

View File

@@ -911,11 +911,7 @@ def raise_work_orders(material_request, company):
@frappe.whitelist() @frappe.whitelist()
def create_pick_list(source_name, target_doc=None): def create_pick_list(source_name, target_doc=None):
def update_item(obj, target, source_parent): def update_item(obj, target, source_parent):
qty = ( qty = flt((obj.stock_qty - obj.picked_qty) / target.conversion_factor, obj.precision("qty"))
flt(flt(obj.stock_qty) - flt(obj.ordered_qty)) / target.conversion_factor
if flt(obj.stock_qty) > flt(obj.ordered_qty)
else 0
)
target.qty = qty target.qty = qty
target.stock_qty = qty * obj.conversion_factor target.stock_qty = qty * obj.conversion_factor
target.conversion_factor = obj.conversion_factor target.conversion_factor = obj.conversion_factor
@@ -931,11 +927,15 @@ def create_pick_list(source_name, target_doc=None):
}, },
"Material Request Item": { "Material Request Item": {
"doctype": "Pick List Item", "doctype": "Pick List Item",
"field_map": {"name": "material_request_item", "stock_qty": "stock_qty"}, "field_map": {
"name": "material_request_item",
"stock_qty": "stock_qty",
"from_warehouse": "warehouse",
},
"postprocess": update_item, "postprocess": update_item,
"condition": lambda doc: ( "condition": lambda doc: (
flt(doc.ordered_qty, doc.precision("ordered_qty")) flt(doc.picked_qty, doc.precision("picked_qty"))
< flt(doc.stock_qty, doc.precision("ordered_qty")) < flt(doc.stock_qty, doc.precision("stock_qty"))
), ),
}, },
}, },

View File

@@ -29,6 +29,7 @@
"qty_info_sec_break", "qty_info_sec_break",
"min_order_qty", "min_order_qty",
"projected_qty", "projected_qty",
"picked_qty",
"qty_info_col_break", "qty_info_col_break",
"actual_qty", "actual_qty",
"ordered_qty", "ordered_qty",
@@ -518,13 +519,22 @@
"fieldtype": "Float", "fieldtype": "Float",
"label": "Projected On Hand", "label": "Projected On Hand",
"read_only": 1 "read_only": 1
},
{
"fieldname": "picked_qty",
"fieldtype": "Float",
"hidden": 1,
"label": "Picked Qty",
"no_copy": 1,
"non_negative": 1,
"read_only": 1
} }
], ],
"idx": 1, "idx": 1,
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2025-12-02 14:14:45.972664", "modified": "2025-12-17 13:47:27.317226",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Material Request Item", "name": "Material Request Item",

View File

@@ -41,6 +41,7 @@ class MaterialRequestItem(Document):
parent: DF.Data parent: DF.Data
parentfield: DF.Data parentfield: DF.Data
parenttype: DF.Data parenttype: DF.Data
picked_qty: DF.Float
price_list_rate: DF.Currency price_list_rate: DF.Currency
production_plan: DF.Link | None production_plan: DF.Link | None
project: DF.Link | None project: DF.Link | None

View File

@@ -19,7 +19,6 @@ from erpnext.selling.doctype.sales_order.sales_order import (
) )
from erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle import ( from erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle import (
get_auto_batch_nos, get_auto_batch_nos,
get_picked_serial_nos,
) )
from erpnext.stock.get_item_details import get_company_total_stock, get_conversion_factor from erpnext.stock.get_item_details import get_company_total_stock, get_conversion_factor
from erpnext.stock.serial_batch_bundle import ( from erpnext.stock.serial_batch_bundle import (
@@ -66,6 +65,21 @@ class PickList(TransactionBase):
work_order: DF.Link | None work_order: DF.Link | None
# end: auto-generated types # end: auto-generated types
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.status_updater = [
{
"source_dt": "Pick List Item",
"target_dt": "Material Request Item",
"target_field": "picked_qty",
"target_parent_dt": "Material Request",
"target_parent_field": "",
"join_field": "material_request_item",
"target_ref_field": "stock_qty",
"source_field": "stock_qty",
}
]
def onload(self) -> None: def onload(self) -> None:
if frappe.get_cached_value("Stock Settings", None, "enable_stock_reservation"): if frappe.get_cached_value("Stock Settings", None, "enable_stock_reservation"):
if self.has_unreserved_stock(): if self.has_unreserved_stock():
@@ -228,6 +242,7 @@ class PickList(TransactionBase):
self.update_bundle_picked_qty() self.update_bundle_picked_qty()
self.update_reference_qty() self.update_reference_qty()
self.update_sales_order_picking_status() self.update_sales_order_picking_status()
self.update_prevdoc_status()
def validate_expired_batches(self): def validate_expired_batches(self):
batches = [] batches = []
@@ -305,6 +320,7 @@ class PickList(TransactionBase):
self.update_reference_qty() self.update_reference_qty()
self.update_sales_order_picking_status() self.update_sales_order_picking_status()
self.delink_serial_and_batch_bundle() self.delink_serial_and_batch_bundle()
self.update_prevdoc_status()
def delink_serial_and_batch_bundle(self): def delink_serial_and_batch_bundle(self):
for row in self.locations: for row in self.locations: