fix(stock): pick list serial batch posting date (#56957) (#57014)

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

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 8b3caeb578)
This commit is contained in:
Pandiyan P
2026-07-10 11:51:03 +05:30
committed by GitHub
parent 6b022a5a7e
commit 4091188908

View File

@@ -26,6 +26,7 @@ from frappe.utils import (
)
from frappe.utils.csvutils import build_csv_response
from erpnext.stock.doctype.purchase_receipt_item.purchase_receipt_item import PurchaseReceiptItem
from erpnext.stock.serial_batch_bundle import (
BatchNoValuation,
SerialNoValuation,
@@ -2092,9 +2093,14 @@ def get_reference_serial_and_batch_bundle(child_row):
@frappe.whitelist()
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)
if isinstance(entries, str):
entries = parse_json(entries)
@@ -2126,7 +2132,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 +2251,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", [])