fix: not able to reconcile expired batches (#44012)

(cherry picked from commit 8805e74784)
This commit is contained in:
rohitwaghchaure
2024-11-12 15:48:28 +05:30
committed by Mergify
parent 73661ac633
commit 4ba07a40eb
7 changed files with 40 additions and 5 deletions

View File

@@ -415,7 +415,6 @@ def get_batches_from_stock_ledger_entries(searchfields, txt, filters, start=0, p
stock_ledger_entry.batch_no,
Sum(stock_ledger_entry.actual_qty).as_("qty"),
)
.where((batch_table.expiry_date >= expiry_date) | (batch_table.expiry_date.isnull()))
.where(stock_ledger_entry.is_cancelled == 0)
.where(
(stock_ledger_entry.item_code == filters.get("item_code"))
@@ -428,6 +427,9 @@ def get_batches_from_stock_ledger_entries(searchfields, txt, filters, start=0, p
.limit(page_len)
)
if not filters.get("include_expired_batches"):
query = query.where((batch_table.expiry_date >= expiry_date) | (batch_table.expiry_date.isnull()))
query = query.select(
Concat("MFG-", batch_table.manufacturing_date).as_("manufacturing_date"),
Concat("EXP-", batch_table.expiry_date).as_("expiry_date"),
@@ -466,7 +468,6 @@ def get_batches_from_serial_and_batch_bundle(searchfields, txt, filters, start=0
bundle.batch_no,
Sum(bundle.qty).as_("qty"),
)
.where((batch_table.expiry_date >= expiry_date) | (batch_table.expiry_date.isnull()))
.where(stock_ledger_entry.is_cancelled == 0)
.where(
(stock_ledger_entry.item_code == filters.get("item_code"))
@@ -479,6 +480,11 @@ def get_batches_from_serial_and_batch_bundle(searchfields, txt, filters, start=0
.limit(page_len)
)
if not filters.get("include_expired_batches"):
bundle_query = bundle_query.where(
(batch_table.expiry_date >= expiry_date) | (batch_table.expiry_date.isnull())
)
bundle_query = bundle_query.select(
Concat("MFG-", batch_table.manufacturing_date),
Concat("EXP-", batch_table.expiry_date),

View File

@@ -462,6 +462,8 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
is_inward = true;
}
let include_expired_batches = me.include_expired_batches();
return {
query: "erpnext.controllers.queries.get_batch_no",
filters: {
@@ -469,6 +471,7 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
warehouse:
this.item.s_warehouse || this.item.t_warehouse || this.item.warehouse,
is_inward: is_inward,
include_expired_batches: include_expired_batches,
},
};
},
@@ -497,6 +500,14 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
return fields;
}
include_expired_batches() {
return (
this.frm.doc.doctype === "Stock Reconciliation" ||
(this.frm.doc.doctype === "Stock Entry" &&
["Material Receipt", "Material Transfer", "Material Issue"].includes(this.frm.doc.purpose))
);
}
get_auto_data() {
let { qty, based_on } = this.dialog.get_values();

View File

@@ -689,6 +689,9 @@ class SerialandBatchBundle(Document):
serial_batches = {}
for row in self.entries:
if not row.qty and row.batch_no and not row.serial_no:
if self.voucher_type == "Stock Reconciliation" and self.type_of_transaction == "Inward":
continue
frappe.throw(
_("At row {0}: Qty is mandatory for the batch {1}").format(
bold(row.idx), bold(row.batch_no)

View File

@@ -117,6 +117,10 @@ frappe.ui.form.on("Stock Entry", {
filters["is_inward"] = 1;
}
if (["Material Receipt", "Material Transfer", "Material Issue"].includes(doc.purpose)) {
filters["include_expired_batches"] = 1;
}
return {
query: "erpnext.controllers.queries.get_batch_no",
filters: filters,

View File

@@ -324,6 +324,7 @@ class StockReconciliation(StockController):
row.item_code,
posting_date=self.posting_date,
posting_time=self.posting_time,
for_stock_levels=True,
)
total_current_qty += current_qty
@@ -1322,7 +1323,16 @@ def get_stock_balance_for(
qty, rate = data
if item_dict.get("has_batch_no"):
qty = get_batch_qty(batch_no, warehouse, posting_date=posting_date, posting_time=posting_time) or 0
qty = (
get_batch_qty(
batch_no,
warehouse,
posting_date=posting_date,
posting_time=posting_time,
for_stock_levels=True,
)
or 0
)
return {
"qty": qty,

View File

@@ -124,7 +124,7 @@ class SerialBatchBundle:
"Outward": self.sle.actual_qty < 0,
}.get(sn_doc.type_of_transaction)
if not condition:
if not condition and self.sle.actual_qty:
correct_type = "Inward"
if sn_doc.type_of_transaction == "Inward":
correct_type = "Outward"
@@ -133,7 +133,7 @@ class SerialBatchBundle:
frappe.throw(_(msg), title=_("Incorrect Type of Transaction"))
precision = sn_doc.precision("total_qty")
if flt(sn_doc.total_qty, precision) != flt(self.sle.actual_qty, precision):
if self.sle.actual_qty and flt(sn_doc.total_qty, precision) != flt(self.sle.actual_qty, precision):
msg = f"Total qty {flt(sn_doc.total_qty, precision)} of Serial and Batch Bundle {link} is not equal to Actual Qty {flt(self.sle.actual_qty, precision)} in the {self.sle.voucher_type} {self.sle.voucher_no}"
frappe.throw(_(msg))

View File

@@ -1183,6 +1183,7 @@ class update_entries_after:
stock_entry.calculate_rate_and_amount(reset_outgoing_rate=False, raise_error_if_no_rate=False)
stock_entry.db_update()
for d in stock_entry.items:
# Update only the row that matches the voucher_detail_no or the row containing the FG/Scrap Item.
if d.name == voucher_detail_no or (not d.s_warehouse and d.t_warehouse):
d.db_update()