From 78bbf98ee0af1cc127d7cca80d7f1c2c494eaaea Mon Sep 17 00:00:00 2001 From: Pandiyan P Date: Thu, 9 Jul 2026 17:28:03 +0530 Subject: [PATCH] fix(stock): pick list serial batch posting date (#56957) * fix(stock): fall back to current date/time for serial and batch bundle posting datetime Pick List has no posting_date/posting_time fields, so creating or updating a Serial and Batch Bundle from a Pick List row crashed with "TypeError: combine() argument 1 must be datetime.date, not None". Fall back to today/now when the parent voucher doesn't carry its own posting date. Fixes #56951 * fix(stock): accept a plain dict for add_serial_batch_ledgers' doc and child_row The whitelisted add_serial_batch_ledgers only converted child_row into an attribute-accessible frappe._dict when it arrived as a JSON string, and doc's type hint only allowed Document | str. Frappe's JSON API delivers both as plain dicts (see frappe.app.make_form_dict, which parses the request body with orjson and only wraps the top-level dict, not nested values), so every real request was rejected before the handler body ever ran: first with a FrappeTypeError on doc, and once that's fixed, with an AttributeError on child_row.serial_and_batch_bundle. parse_json already wraps a plain dict in frappe._dict (and leaves a real Document instance untouched), so routing child_row through it unconditionally fixes both. (cherry picked from commit 8b3caeb5787fdfd3e32d52111ca1eda66698be00) # Conflicts: # erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py --- .../serial_and_batch_bundle.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py index 4fa630fb8a8..9ef0eb453fc 100644 --- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py +++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py @@ -2092,9 +2092,20 @@ def get_reference_serial_and_batch_bundle(child_row): @frappe.whitelist() +<<<<<<< HEAD def add_serial_batch_ledgers(entries, child_row, doc, warehouse, do_not_save=False) -> object: if isinstance(child_row, str): child_row = frappe._dict(parse_json(child_row)) +======= +def add_serial_batch_ledgers( + entries: list | str, + child_row: PurchaseReceiptItem | dict | str, + doc: Document | dict | str, + warehouse: str | None = None, + do_not_save: bool = False, +): + child_row = parse_json(child_row) +>>>>>>> 8b3caeb578 (fix(stock): pick list serial batch posting date (#56957)) if isinstance(entries, str): entries = parse_json(entries) @@ -2126,7 +2137,9 @@ def create_serial_batch_no_ledgers( if parent_doc.get("doctype") == "Stock Entry": warehouse = warehouse or child_row.s_warehouse or child_row.t_warehouse - posting_datetime = combine_datetime(parent_doc.get("posting_date"), parent_doc.get("posting_time")) + posting_datetime = combine_datetime( + parent_doc.get("posting_date") or today(), parent_doc.get("posting_time") or nowtime() + ) doc = frappe.get_doc( { @@ -2243,7 +2256,9 @@ def update_serial_batch_no_ledgers(bundle, entries, child_row, parent_doc, wareh ) doc.voucher_detail_no = child_row.name - doc.posting_datetime = combine_datetime(parent_doc.get("posting_date"), parent_doc.get("posting_time")) + doc.posting_datetime = combine_datetime( + parent_doc.get("posting_date") or today(), parent_doc.get("posting_time") or nowtime() + ) doc.warehouse = warehouse or doc.warehouse doc.set("entries", [])