From 961d2d9926a1a9c0396c3292d431d3bad6865e62 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 19 Oct 2023 17:51:34 +0530 Subject: [PATCH] refactor: rename field `against_pick_list` --- erpnext/stock/doctype/pick_list/pick_list.js | 3 +- erpnext/stock/doctype/pick_list/pick_list.py | 6 +- .../doctype/pick_list/pick_list_dashboard.py | 2 +- .../stock_reservation_entry.js | 2 +- .../stock_reservation_entry.json | 30 ++++---- .../stock_reservation_entry.py | 70 +++++++++++-------- .../test_stock_reservation_entry.py | 2 +- .../report/reserved_stock/reserved_stock.js | 20 +++++- .../report/reserved_stock/reserved_stock.py | 23 +++--- 9 files changed, 96 insertions(+), 62 deletions(-) diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js index ae05b80727..7cd171ea92 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.js +++ b/erpnext/stock/doctype/pick_list/pick_list.js @@ -265,7 +265,8 @@ frappe.ui.form.on('Pick List', { from_date: moment(frm.doc.creation).format('YYYY-MM-DD'), to_date: to_date, voucher_type: "Sales Order", - against_pick_list: frm.doc.name, + from_voucher_type: "Pick List", + from_voucher_no: frm.doc.name, } frappe.set_route("query-report", "Reserved Stock"); } diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index 8c9d03c1bd..3503556f3e 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -242,7 +242,7 @@ class PickList(Document): for so, locations in so_details.items(): so_doc = frappe.get_doc("Sales Order", so) create_stock_reservation_entries_for_so_items( - sales_order=so_doc, items_details=locations, against_pick_list=True, notify=notify + sales_order=so_doc, items_details=locations, from_voucher_type="Pick List", notify=notify ) @frappe.whitelist() @@ -253,7 +253,9 @@ class PickList(Document): cancel_stock_reservation_entries, ) - cancel_stock_reservation_entries(against_pick_list=self.name, notify=notify) + cancel_stock_reservation_entries( + from_voucher_type="Pick List", from_voucher_no=self.name, notify=notify + ) def validate_picked_qty(self, data): over_delivery_receipt_allowance = 100 + flt( diff --git a/erpnext/stock/doctype/pick_list/pick_list_dashboard.py b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py index 0830fa2143..29571a5400 100644 --- a/erpnext/stock/doctype/pick_list/pick_list_dashboard.py +++ b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py @@ -2,7 +2,7 @@ def get_data(): return { "fieldname": "pick_list", "non_standard_fieldnames": { - "Stock Reservation Entry": "against_pick_list", + "Stock Reservation Entry": "from_voucher_no", }, "internal_links": { "Sales Order": ["locations", "sales_order"], diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.js b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.js index c5df319e22..f60a0378b6 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.js +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.js @@ -92,7 +92,7 @@ frappe.ui.form.on('Stock Reservation Entry', { 'qty', 'read_only', frm.doc.has_serial_no ); - frm.set_df_property('sb_entries', 'allow_on_submit', frm.doc.against_pick_list ? 0 : 1); + frm.set_df_property('sb_entries', 'allow_on_submit', frm.doc.from_voucher_type == "Pick List" ? 0 : 1); }, hide_rate_related_fields(frm) { diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json index 1a518fa38a..76cedd4b1e 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json @@ -18,7 +18,7 @@ "voucher_detail_no", "column_break_7dxj", "from_voucher_type", - "against_pick_list", + "from_voucher_no", "from_voucher_detail_no", "section_break_xt4m", "stock_uom", @@ -159,7 +159,7 @@ "oldfieldname": "actual_qty", "oldfieldtype": "Currency", "print_width": "150px", - "read_only_depends_on": "eval: ((doc.reservation_based_on == \"Serial and Batch\") || (doc.against_pick_list) || (doc.delivered_qty > 0))", + "read_only_depends_on": "eval: ((doc.reservation_based_on == \"Serial and Batch\") || (doc.from_voucher_type == \"Pick List\") || (doc.delivered_qty > 0))", "width": "150px" }, { @@ -269,18 +269,7 @@ "label": "Reservation Based On", "no_copy": 1, "options": "Qty\nSerial and Batch", - "read_only_depends_on": "eval: (doc.delivered_qty > 0 || doc.against_pick_list)" - }, - { - "fieldname": "against_pick_list", - "fieldtype": "Dynamic Link", - "label": "From Voucher No", - "no_copy": 1, - "options": "from_voucher_type", - "print_hide": 1, - "read_only": 1, - "report_hide": 1, - "search_index": 1 + "read_only_depends_on": "eval: (doc.delivered_qty > 0 || doc.from_voucher_type == \"Pick List\")" }, { "fieldname": "column_break_7dxj", @@ -308,6 +297,17 @@ "print_hide": 1, "read_only": 1, "report_hide": 1 + }, + { + "fieldname": "from_voucher_no", + "fieldtype": "Dynamic Link", + "label": "From Voucher No", + "no_copy": 1, + "options": "from_voucher_type", + "print_hide": 1, + "read_only": 1, + "report_hide": 1, + "search_index": 1 } ], "hide_toolbar": 1, @@ -315,7 +315,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2023-10-19 16:26:46.598043", + "modified": "2023-10-19 16:41:16.545416", "modified_by": "Administrator", "module": "Stock", "name": "Stock Reservation Entry", diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py index 66e246a86a..9097e621e6 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py @@ -1,6 +1,8 @@ # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt +from typing import Literal + import frappe from frappe import _ from frappe.model.document import Document @@ -113,7 +115,7 @@ class StockReservationEntry(Document): """Auto pick Serial and Batch Nos to reserve when `Reservation Based On` is `Serial and Batch`.""" if ( - not self.against_pick_list + not self.from_voucher_type and (self.get("_action") == "submit") and (self.has_serial_no or self.has_batch_no) and cint(frappe.db.get_single_value("Stock Settings", "auto_reserve_serial_and_batch")) @@ -317,7 +319,7 @@ class StockReservationEntry(Document): """Updates total reserved qty in the Pick List.""" if ( - self.from_voucher_type == "Pick List" and self.against_pick_list and self.from_voucher_detail_no + self.from_voucher_type == "Pick List" and self.from_voucher_no and self.from_voucher_detail_no ): sre = frappe.qb.DocType("Stock Reservation Entry") reserved_qty = ( @@ -326,7 +328,7 @@ class StockReservationEntry(Document): .where( (sre.docstatus == 1) & (sre.from_voucher_type == "Pick List") - & (sre.against_pick_list == self.against_pick_list) + & (sre.from_voucher_no == self.from_voucher_no) & (sre.from_voucher_detail_no == self.from_voucher_detail_no) ) ).run(as_list=True)[0][0] or 0 @@ -368,7 +370,7 @@ class StockReservationEntry(Document): ).format(self.status, self.doctype) frappe.throw(msg) - if self.against_pick_list: + if self.from_voucher_type == "Pick List": msg = _( "Stock Reservation Entry created against a Pick List cannot be updated. If you need to make changes, we recommend canceling the existing entry and creating a new one." ) @@ -766,14 +768,14 @@ def has_reserved_stock(voucher_type: str, voucher_no: str, voucher_detail_no: st def create_stock_reservation_entries_for_so_items( sales_order: object, items_details: list[dict] = None, - against_pick_list: bool = False, + from_voucher_type: Literal["Pick List", "Purchase Receipt"] = None, notify=True, ) -> None: """Creates Stock Reservation Entries for Sales Order Items.""" from erpnext.selling.doctype.sales_order.sales_order import get_unreserved_qty - if not against_pick_list and ( + if not from_voucher_type and ( sales_order.get("_action") == "submit" and sales_order.set_warehouse and cint(frappe.get_cached_value("Warehouse", sales_order.set_warehouse, "is_group")) @@ -792,20 +794,20 @@ def create_stock_reservation_entries_for_so_items( items = [] if items_details: - item_field = "sales_order_item" if against_pick_list else "name" + item_field = "sales_order_item" if from_voucher_type == "Pick List" else "name" for item in items_details: so_item = frappe.get_doc("Sales Order Item", item.get(item_field)) so_item.warehouse = item.get("warehouse") so_item.qty_to_reserve = ( item.get("picked_qty") - item.get("stock_reserved_qty", 0) - if against_pick_list + if from_voucher_type == "Pick List" else (flt(item.get("qty_to_reserve")) * flt(so_item.conversion_factor, 1)) ) so_item.serial_and_batch_bundle = item.get("serial_and_batch_bundle") - if against_pick_list: - so_item.pick_list = item.get("parent") + if from_voucher_type == "Pick List": + so_item.from_voucher_no = item.get("parent") so_item.from_voucher_detail_no = item.get("name") items.append(so_item) @@ -819,7 +821,7 @@ def create_stock_reservation_entries_for_so_items( continue # Stock should be reserved from the Pick List if has Picked Qty. - if not against_pick_list and flt(item.picked_qty) > 0: + if not from_voucher_type == "Pick List" and flt(item.picked_qty) > 0: frappe.throw( _("Row #{0}: Item {1} has been picked, please reserve stock from the Pick List.").format( item.idx, frappe.bold(item.item_code) @@ -929,9 +931,9 @@ def create_stock_reservation_entries_for_so_items( sre.stock_uom = item.stock_uom sre.project = sales_order.project - if against_pick_list: - sre.from_voucher_type = "Pick List" - sre.against_pick_list = item.pick_list + if from_voucher_type: + sre.from_voucher_type = from_voucher_type + sre.from_voucher_no = item.from_voucher_no sre.from_voucher_detail_no = item.from_voucher_detail_no if item.serial_and_batch_bundle: @@ -961,29 +963,37 @@ def cancel_stock_reservation_entries( voucher_type: str = None, voucher_no: str = None, voucher_detail_no: str = None, - against_pick_list: str = None, + from_voucher_type: Literal["Pick List", "Purchase Receipt"] = None, + from_voucher_no: str = None, + from_voucher_detail_no: str = None, sre_list: list[dict] = None, notify: bool = True, ) -> None: """Cancel Stock Reservation Entries.""" - if not sre_list and against_pick_list: - sre = frappe.qb.DocType("Stock Reservation Entry") - sre_list = ( - frappe.qb.from_(sre) - .select(sre.name) - .where( - (sre.docstatus == 1) - & (sre.against_pick_list == against_pick_list) - & (sre.status.notin(["Delivered", "Cancelled"])) + if not sre_list: + if voucher_type and voucher_no: + sre_list = get_stock_reservation_entries_for_voucher( + voucher_type, voucher_no, voucher_detail_no, fields=["name"] + ) + elif from_voucher_type and from_voucher_no: + sre = frappe.qb.DocType("Stock Reservation Entry") + query = ( + frappe.qb.from_(sre) + .select(sre.name) + .where( + (sre.docstatus == 1) + & (sre.from_voucher_type == from_voucher_type) + & (sre.from_voucher_no == from_voucher_no) + & (sre.status.notin(["Delivered", "Cancelled"])) + ) + .orderby(sre.creation) ) - .orderby(sre.creation) - ).run(as_dict=True) - elif not sre_list and (voucher_type and voucher_no): - sre_list = get_stock_reservation_entries_for_voucher( - voucher_type, voucher_no, voucher_detail_no, fields=["name"] - ) + if from_voucher_detail_no: + query = query.where(sre.from_voucher_detail_no == from_voucher_detail_no) + + sre_list = query.run(as_dict=True) if sre_list: for sre in sre_list: diff --git a/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py index 27f43bf668..9ea35ecacb 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py @@ -556,7 +556,7 @@ class TestStockReservationEntry(FrappeTestCase): & (sre.voucher_no == location.sales_order) & (sre.voucher_detail_no == location.sales_order_item) & (sre.from_voucher_type == "Pick List") - & (sre.against_pick_list == pl.name) + & (sre.from_voucher_no == pl.name) & (sre.from_voucher_detail_no == location.name) ) ).run(as_dict=True) diff --git a/erpnext/stock/report/reserved_stock/reserved_stock.js b/erpnext/stock/report/reserved_stock/reserved_stock.js index 2199f52df0..68727411d5 100644 --- a/erpnext/stock/report/reserved_stock/reserved_stock.js +++ b/erpnext/stock/report/reserved_stock/reserved_stock.js @@ -91,16 +91,30 @@ frappe.query_reports["Reserved Stock"] = { }, }, { - fieldname: "against_pick_list", - label: __("Against Pick List"), + fieldname: "from_voucher_type", + label: __("From Voucher Type"), fieldtype: "Link", - options: "Pick List", + options: "DocType", + get_query: () => ({ + filters: { + name: ["in", ["Pick List", "Purchase Receipt"]], + } + }), + }, + { + fieldname: "from_voucher_no", + label: __("From Voucher No"), + fieldtype: "Dynamic Link", + options: "from_voucher_type", get_query: () => ({ filters: { docstatus: 1, company: frappe.query_report.get_filter_value("company"), }, }), + get_options: function () { + return frappe.query_report.get_filter_value("from_voucher_type"); + }, }, { fieldname: "reservation_based_on", diff --git a/erpnext/stock/report/reserved_stock/reserved_stock.py b/erpnext/stock/report/reserved_stock/reserved_stock.py index d93ee1c88f..21ce203ad6 100644 --- a/erpnext/stock/report/reserved_stock/reserved_stock.py +++ b/erpnext/stock/report/reserved_stock/reserved_stock.py @@ -44,7 +44,8 @@ def get_data(filters): (sre.available_qty - sre.reserved_qty).as_("available_qty"), sre.voucher_type, sre.voucher_no, - sre.against_pick_list, + sre.from_voucher_type, + sre.from_voucher_no, sre.name.as_("stock_reservation_entry"), sre.status, sre.project, @@ -65,7 +66,8 @@ def get_data(filters): "warehouse", "voucher_type", "voucher_no", - "against_pick_list", + "from_voucher_type", + "from_voucher_no", "reservation_based_on", "status", "project", @@ -142,7 +144,6 @@ def get_columns(): "fieldname": "voucher_type", "label": _("Voucher Type"), "fieldtype": "Data", - "options": "Warehouse", "width": 110, }, { @@ -153,11 +154,17 @@ def get_columns(): "width": 120, }, { - "fieldname": "against_pick_list", - "label": _("Against Pick List"), - "fieldtype": "Link", - "options": "Pick List", - "width": 130, + "fieldname": "from_voucher_type", + "label": _("From Voucher Type"), + "fieldtype": "Data", + "width": 110, + }, + { + "fieldname": "from_voucher_no", + "label": _("From Voucher No"), + "fieldtype": "Dynamic Link", + "options": "from_voucher_type", + "width": 120, }, { "fieldname": "stock_reservation_entry",