Merge pull request #50252 from frappe/mergify/bp/version-15-hotfix/pr-50247

fix: provision to find and fix incorrect serial and batch bundles (backport #50247)
This commit is contained in:
rohitwaghchaure
2025-10-28 18:21:46 +05:30
committed by GitHub
2 changed files with 86 additions and 28 deletions

View File

@@ -24,24 +24,26 @@ frappe.query_reports["Incorrect Serial and Batch Bundle"] = {
},
onload(report) {
report.page.add_inner_button(__("Remove SABB Entry"), () => {
let indexes = frappe.query_report.datatable.rowmanager.getCheckedRows();
let selected_rows = indexes.map((i) => frappe.query_report.data[i]);
report.page
.add_inner_button(__("Fix SABB Entry"), () => {
let indexes = frappe.query_report.datatable.rowmanager.getCheckedRows();
let selected_rows = indexes.map((i) => frappe.query_report.data[i]);
if (!selected_rows.length) {
frappe.throw(__("Please select a row to create a Reposting Entry"));
} else {
frappe.call({
method: "erpnext.stock.report.incorrect_serial_and_batch_bundle.incorrect_serial_and_batch_bundle.remove_sabb_entry",
freeze: true,
args: {
selected_rows: selected_rows,
},
callback: function (r) {
frappe.query_report.refresh();
},
});
}
});
if (!selected_rows.length) {
frappe.throw(__("Please select at least one row to fix"));
} else {
frappe.call({
method: "erpnext.stock.report.incorrect_serial_and_batch_bundle.incorrect_serial_and_batch_bundle.fix_sabb_entries",
freeze: true,
args: {
selected_rows: selected_rows,
},
callback: function (r) {
frappe.query_report.refresh();
},
});
}
})
.addClass("btn-primary");
},
};

View File

@@ -13,7 +13,10 @@ def execute(filters: dict | None = None):
every time the report is refreshed or a filter is updated.
"""
columns = get_columns()
data = get_data(filters)
unlinked_bundles = get_unlinked_serial_batch_bundles(filters) or []
linked_cancelled_bundles = get_linked_cancelled_sabb(filters) or []
data = unlinked_bundles + linked_cancelled_bundles
return columns, data
@@ -50,14 +53,17 @@ def get_columns() -> list[dict]:
"fieldtype": "Data",
"width": 200,
},
{
"label": _("Is Cancelled"),
"fieldname": "is_cancelled",
"fieldtype": "Check",
"width": 200,
},
]
def get_data(filters) -> list[list]:
"""Return data for the report.
The report data is a list of rows, with each row being a list of cell values.
"""
def get_unlinked_serial_batch_bundles(filters) -> list[list]:
# SABB has not been linked to any SLE
SABB = frappe.qb.DocType("Serial and Batch Bundle")
SLE = frappe.qb.DocType("Stock Ledger Entry")
@@ -77,6 +83,7 @@ def get_data(filters) -> list[list]:
SABB.voucher_type,
SABB.voucher_no,
SABB.voucher_detail_no,
SABB.is_cancelled,
)
.where(
(SLE.serial_and_batch_bundle.isnull())
@@ -94,14 +101,63 @@ def get_data(filters) -> list[list]:
return data
def get_linked_cancelled_sabb(filters):
# SABB has cancelled but voucher is not cancelled
SABB = frappe.qb.DocType("Serial and Batch Bundle")
SLE = frappe.qb.DocType("Stock Ledger Entry")
query = (
frappe.qb.from_(SABB)
.inner_join(SLE)
.on(SABB.name == SLE.serial_and_batch_bundle)
.select(
SABB.name,
SABB.voucher_type,
SABB.voucher_no,
SABB.voucher_detail_no,
SABB.is_cancelled,
)
.where(
(SLE.serial_and_batch_bundle.isnotnull())
& (SABB.docstatus == 2)
& (SABB.is_cancelled == 1)
& (SLE.is_cancelled == 0)
)
)
for field in filters:
query = query.where(SABB[field] == filters[field])
data = query.run(as_dict=1)
return data
@frappe.whitelist()
def remove_sabb_entry(selected_rows):
def fix_sabb_entries(selected_rows):
if isinstance(selected_rows, str):
selected_rows = frappe.parse_json(selected_rows)
for row in selected_rows:
doc = frappe.get_doc("Serial and Batch Bundle", row.get("name"))
doc.cancel()
doc.delete()
if doc.is_cancelled == 0 and not frappe.db.get_value(
"Stock Ledger Entry",
{"serial_and_batch_bundle": doc.name, "is_cancelled": 0},
"name",
):
doc.db_set({"is_cancelled": 1, "docstatus": 2})
frappe.msgprint(_("Selected Serial and Batch Bundle entries have been removed."))
for row in doc.entries:
row.db_set("docstatus", 2)
elif doc.is_cancelled == 1 and frappe.db.get_value(
"Stock Ledger Entry",
{"serial_and_batch_bundle": doc.name, "is_cancelled": 0},
"name",
):
doc.db_set({"is_cancelled": 0, "docstatus": 1})
for row in doc.entries:
row.db_set("docstatus", 1)
frappe.msgprint(_("Selected Serial and Batch Bundle entries have been fixed."))