feat: Available batches report as on specific date

(cherry picked from commit b8f7979794)
This commit is contained in:
Rohit Waghchaure
2024-04-22 15:23:16 +05:30
committed by Mergify
parent 3df5aa04b5
commit 791e4269d2
4 changed files with 300 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
// Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.query_reports["Available Batch Report"] = {
filters: [
{
fieldname: "company",
label: __("Company"),
fieldtype: "Link",
width: "80",
options: "Company",
default: frappe.defaults.get_default("company"),
},
{
fieldname: "to_date",
label: __("On This Date"),
fieldtype: "Date",
width: "80",
reqd: 1,
default: frappe.datetime.add_months(frappe.datetime.get_today(), -1),
},
{
fieldname: "item_code",
label: __("Item"),
fieldtype: "Link",
width: "80",
options: "Item",
get_query: () => {
return {
filters: {
has_batch_no: 1,
disabled: 0,
},
};
},
},
{
fieldname: "warehouse",
label: __("Warehouse"),
fieldtype: "Link",
width: "80",
options: "Warehouse",
get_query: () => {
let warehouse_type = frappe.query_report.get_filter_value("warehouse_type");
let company = frappe.query_report.get_filter_value("company");
return {
filters: {
...(warehouse_type && { warehouse_type }),
...(company && { company }),
},
};
},
},
{
fieldname: "warehouse_type",
label: __("Warehouse Type"),
fieldtype: "Link",
width: "80",
options: "Warehouse Type",
},
{
fieldname: "batch_no",
label: __("Batch No"),
fieldtype: "Link",
width: "80",
options: "Batch",
get_query: () => {
let item = frappe.query_report.get_filter_value("item_code");
return {
filters: {
...(item && { item }),
},
};
},
},
{
fieldname: "include_expired_batches",
label: __("Include Expired Batches"),
fieldtype: "Check",
width: "80",
},
{
fieldname: "show_item_name",
label: __("Show Item Name"),
fieldtype: "Check",
width: "80",
},
],
};

View File

@@ -0,0 +1,31 @@
{
"add_total_row": 1,
"columns": [],
"creation": "2024-04-11 17:03:32.253275",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 0,
"is_standard": "Yes",
"json": "{}",
"letter_head": "",
"letterhead": null,
"modified": "2024-04-23 17:18:19.779036",
"modified_by": "Administrator",
"module": "Stock",
"name": "Available Batch Report",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Stock Ledger Entry",
"report_name": "Available Batch Report",
"report_type": "Script Report",
"roles": [
{
"role": "Stock User"
},
{
"role": "Accounts Manager"
}
]
}

View File

@@ -0,0 +1,178 @@
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from collections import defaultdict
import frappe
from frappe import _
from frappe.query_builder.functions import Sum
from frappe.utils import flt, today
def execute(filters=None):
columns, data = [], []
data = get_data(filters)
columns = get_columns(filters)
return columns, data
def get_columns(filters):
columns = [
{
"label": _("Item Code"),
"fieldname": "item_code",
"fieldtype": "Link",
"options": "Item",
"width": 200,
}
]
if filters.show_item_name:
columns.append(
{
"label": _("Item Name"),
"fieldname": "item_name",
"fieldtype": "Link",
"options": "Item",
"width": 200,
}
)
columns.extend(
[
{
"label": _("Warehouse"),
"fieldname": "warehouse",
"fieldtype": "Link",
"options": "Warehouse",
"width": 200,
},
{
"label": _("Batch No"),
"fieldname": "batch_no",
"fieldtype": "Link",
"width": 150,
"options": "Batch",
},
{"label": _("Balance Qty"), "fieldname": "balance_qty", "fieldtype": "Float", "width": 150},
]
)
return columns
def get_data(filters):
data = []
batchwise_data = get_batchwise_data_from_stock_ledger(filters)
batchwise_data = get_batchwise_data_from_serial_batch_bundle(batchwise_data, filters)
data = parse_batchwise_data(batchwise_data)
return data
def parse_batchwise_data(batchwise_data):
data = []
for key in batchwise_data:
d = batchwise_data[key]
if d.balance_qty == 0:
continue
data.append(d)
return data
def get_batchwise_data_from_stock_ledger(filters):
batchwise_data = frappe._dict({})
table = frappe.qb.DocType("Stock Ledger Entry")
batch = frappe.qb.DocType("Batch")
query = (
frappe.qb.from_(table)
.inner_join(batch)
.on(table.batch_no == batch.name)
.select(
table.item_code,
table.batch_no,
table.warehouse,
Sum(table.actual_qty).as_("balance_qty"),
)
.where(table.is_cancelled == 0)
.groupby(table.batch_no, table.item_code, table.warehouse)
)
query = get_query_based_on_filters(query, batch, table, filters)
for d in query.run(as_dict=True):
key = (d.item_code, d.warehouse, d.batch_no)
batchwise_data.setdefault(key, d)
return batchwise_data
def get_batchwise_data_from_serial_batch_bundle(batchwise_data, filters):
table = frappe.qb.DocType("Stock Ledger Entry")
ch_table = frappe.qb.DocType("Serial and Batch Entry")
batch = frappe.qb.DocType("Batch")
query = (
frappe.qb.from_(table)
.inner_join(ch_table)
.on(table.serial_and_batch_bundle == ch_table.parent)
.inner_join(batch)
.on(ch_table.batch_no == batch.name)
.select(
table.item_code,
ch_table.batch_no,
table.warehouse,
Sum(ch_table.qty).as_("balance_qty"),
)
.where((table.is_cancelled == 0) & (table.docstatus == 1))
.groupby(ch_table.batch_no, table.item_code, ch_table.warehouse)
)
query = get_query_based_on_filters(query, batch, table, filters)
for d in query.run(as_dict=True):
key = (d.item_code, d.warehouse, d.batch_no)
if key in batchwise_data:
batchwise_data[key].balance_qty += flt(d.balance_qty)
else:
batchwise_data.setdefault(key, d)
return batchwise_data
def get_query_based_on_filters(query, batch, table, filters):
if filters.item_code:
query = query.where(table.item_code == filters.item_code)
if filters.batch_no:
query = query.where(batch.name == filters.batch_no)
if not filters.include_expired_batches:
query = query.where((batch.expiry_date >= today()) | (batch.expiry_date.isnull()))
if filters.to_date == today():
query = query.where(batch.batch_qty > 0)
if filters.warehouse:
lft, rgt = frappe.db.get_value("Warehouse", filters.warehouse, ["lft", "rgt"])
warehouses = frappe.get_all(
"Warehouse", filters={"lft": (">=", lft), "rgt": ("<=", rgt), "is_group": 0}, pluck="name"
)
query = query.where(table.warehouse.isin(warehouses))
elif filters.warehouse_type:
warehouses = frappe.get_all(
"Warehouse", filters={"warehouse_type": filters.warehouse_type, "is_group": 0}, pluck="name"
)
query = query.where(table.warehouse.isin(warehouses))
if filters.show_item_name:
query = query.select(batch.item_name)
return query