mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-18 17:15:04 +00:00
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:
@@ -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");
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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."))
|
||||
|
||||
Reference in New Issue
Block a user