Skip to content

Commit

Permalink
perf: batchwise balance history report
Browse files Browse the repository at this point in the history
  • Loading branch information
rohitwaghchaure committed Dec 10, 2024
1 parent 65839f3 commit 9763a0b
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,27 +100,23 @@ def validate_period_closing_voucher(self):
# Stock Closing Balance
closing_stock = self.get_closing_stock_balance()
if closing_stock and closing_stock[0].name:
name = get_link_to_form("Stock Closing Balance", closing_stock[0].name)
name = get_link_to_form("Stock Closing Entry", closing_stock[0].stock_closing_entry)
to_date = frappe.format(closing_stock[0].to_date, "Date")
frappe.throw(
_("Due to stock closing balance {0}, you cannot repost item valuation before {1}").format(
_("Due to stock closing entry {0}, you cannot repost item valuation before {1}").format(
name, to_date
)
)

def get_closing_stock_balance(self):
filters = {
"company": self.company,
"status": "Completed",
"docstatus": 1,
"to_date": (">=", self.posting_date),
}

for field in ["warehouse", "item_code"]:
if self.get(field):
filters.update({field: ("in", ["", self.get(field)])})

return frappe.get_all("Stock Closing Balance", fields=["name", "posting_date"], filters=filters, limit=1)
return frappe.get_all(
"Stock Closing Balance", fields=["stock_closing_entry", "posting_date"], filters=filters, limit=1
)

@staticmethod
def get_max_period_closing_date(company):
Expand Down
95 changes: 53 additions & 42 deletions erpnext/stock/doctype/stock_closing_entry/stock_closing_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,7 @@ def enqueue_job(self):
@frappe.whitelist()
def regenerate_closing_balance(self):
self.remove_stock_closing()
# self.enqueue_job()
self.create_stock_closing_balance_entries()
self.enqueue_job()

def create_stock_closing_balance_entries(self):
from erpnext.stock.utils import get_combine_datetime
Expand All @@ -113,14 +112,14 @@ def create_stock_closing_balance_entries(self):

entries = stk_cl_obj.get_stock_closing_entries()

for row in entries:
data = entries[row]
for key in entries:
row = entries[key]

if data.actual_qty == 0.0 and data.stock_value_difference == 0.0:
if row.actual_qty == 0.0 and row.stock_value_difference == 0.0:
continue

new_doc = frappe.new_doc("Stock Closing Balance")
new_doc.update(data)
new_doc.update(row)
new_doc.posting_date = self.to_date
new_doc.posting_time = nowtime()
new_doc.posting_datetime = get_combine_datetime(self.to_date, new_doc.posting_time)
Expand Down Expand Up @@ -169,10 +168,10 @@ def get_stock_closing_entries(self):

closing_stock = frappe._dict()
for row in sl_entries:
keys = self.get_keys(row)
for data in keys:
for fields, values in data.items():
key = values
dimensions_keys = self.get_keys(row)
for dimension_key in dimensions_keys:
for dimension_fields, dimension_values in dimension_key.items():
key = dimension_values

if key in closing_stock:
closing_stock[key].actual_qty += row.sabb_qty or row.actual_qty
Expand All @@ -183,36 +182,42 @@ def get_stock_closing_entries(self):
if not row.actual_qty and row.qty_after_transaction:
closing_stock[key].actual_qty = row.qty_after_transaction
else:
item_details = frappe.get_cached_value(
"Item", row.item_code, ["item_group", "item_name", "stock_uom"], as_dict=1
)
entries = self.get_initialized_entry(row, dimension_fields)
closing_stock[key] = entries

inventory_dimension_key = ""
if fields not in [("item_code", "warehouse"), ("item_code", "warehouse", "batch_no")]:
inventory_dimension_key = json.dumps(fields)

closing_stock[key] = frappe._dict(
{
"item_code": row.item_code,
"warehouse": row.warehouse,
"actual_qty": row.sabb_qty or row.actual_qty or row.qty_after_transaction,
"stock_value_difference": (
row.sabb_stock_value_difference or row.stock_value_difference
),
"item_group": item_details.item_group,
"item_name": item_details.item_name,
"stock_uom": item_details.stock_uom,
"inventory_dimension_key": inventory_dimension_key,
"batch_no": row.batch_no or row.sabb_batch_no,
}
)
return closing_stock

# To update dimensions
for field in fields:
if row.get(field):
closing_stock[key][field] = row.get(field)
def get_initialized_entry(self, row, dimension_fields):
item_details = frappe.get_cached_value(
"Item", row.item_code, ["item_group", "item_name", "stock_uom"], as_dict=1
)

return closing_stock
inventory_dimension_key = None
if dimension_fields not in [("item_code", "warehouse"), ("item_code", "warehouse", "batch_no")]:
inventory_dimension_key = json.dumps(dimension_fields)

entry = frappe._dict(
{
"item_code": row.item_code,
"warehouse": row.warehouse,
"actual_qty": row.sabb_qty or row.actual_qty or row.qty_after_transaction,
"stock_value_difference": row.sabb_stock_value_difference or row.stock_value_difference,
"item_group": item_details.item_group,
"item_name": item_details.item_name,
"stock_uom": item_details.stock_uom,
"inventory_dimension_key": inventory_dimension_key,
}
)

if row.sabb_batch_no:
row.batch_no = row.sabb_batch_no

# To update dimensions
for field in dimension_fields:
if row.get(field):
entry[field] = row.get(field)

return entry

def get_sle_entries(self):
sl_entries = []
Expand Down Expand Up @@ -330,7 +335,7 @@ def get_keys(self, row):
{("item_code", "warehouse", "batch_no"): (row.item_code, row.warehouse, row.sabb_batch_no)}
)

dimensions_has_value = []
dimension_fields = []
dimension_values = []
for dimension in self.inv_dimensions:
if row.get(dimension.fieldname):
Expand All @@ -344,13 +349,13 @@ def get_keys(self, row):
}
)

dimensions_has_value.append(dimension.fieldname)
dimension_fields.append(dimension.fieldname)
dimension_values.append(row.get(dimension.fieldname))

if dimensions_has_value and len(dimensions_has_value) > 1:
if dimension_fields and len(dimension_fields) > 1:
keys.append(
{
("item_code", "warehouse", *dimensions_has_value): (
("item_code", "warehouse", *dimension_fields): (
row.item_code,
row.warehouse,
*dimension_values,
Expand All @@ -360,7 +365,7 @@ def get_keys(self, row):

return keys

def get_stock_closing_balance(self, kwargs):
def get_stock_closing_balance(self, kwargs, for_batch=False):
if not self.last_closing_balance:
return []

Expand All @@ -377,4 +382,10 @@ def get_stock_closing_balance(self, kwargs):
else:
query = query.where(table[key] == value)

if for_batch:
query = query.where(table.batch_no.isnotnull())
query = query.where(
table.inventory_dimension_key.isnull() | (table.inventory_dimension_key == "")
)

return query.run(as_dict=True)
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from pypika import functions as fn

from erpnext.deprecation_dumpster import deprecated
from erpnext.stock.doctype.stock_closing_entry.stock_closing_entry import StockClosing
from erpnext.stock.doctype.warehouse.warehouse import apply_warehouse_filter

SLE_COUNT_LIMIT = 10_000
Expand Down Expand Up @@ -94,12 +95,36 @@ def get_columns(filters):


def get_stock_ledger_entries(filters):
entries = get_stock_ledger_entries_for_batch_no(filters)
entries = []

stk_cl_obj = StockClosing(filters.company, filters.from_date, filters.from_date)
if stk_cl_obj.last_closing_balance:
entries += get_stock_closing_balance(stk_cl_obj, filters)
filters.start_from = stk_cl_obj.last_closing_balance.to_date

entries += get_stock_ledger_entries_for_batch_no(filters)
entries += get_stock_ledger_entries_for_batch_bundle(filters)

return entries


def get_stock_closing_balance(stk_cl_obj, filters):
query_filters = {}
for field in ["item_code", "warehouse", "company", "batch_no"]:
if filters.get(field):
query_filters[field] = filters.get(field)

if filters.warehouse_type:
warehouses = frappe.get_all(
"Warehouse",
filters={"warehouse_type": filters.warehouse_type, "is_group": 0},
pluck="name",
)
query_filters["warehouse"] = warehouses

return stk_cl_obj.get_stock_closing_balance(query_filters, for_batch=True)


@deprecated(f"{__name__}.get_stock_ledger_entries_for_batch_no", "unknown", "v16", "No known instructions.")
def get_stock_ledger_entries_for_batch_no(filters):
if not filters.get("from_date"):
Expand Down Expand Up @@ -144,6 +169,9 @@ def get_stock_ledger_entries_for_batch_no(filters):
if filters.get(field):
query = query.where(sle[field] == filters.get(field))

if filters.start_from:
query = query.where(sle.posting_datetime > get_datetime(filters.start_from))

return query.run(as_dict=True) or []


Expand Down Expand Up @@ -190,6 +218,9 @@ def get_stock_ledger_entries_for_batch_bundle(filters):
else:
query = query.where(sle[field] == filters.get(field))

if filters.start_from:
query = query.where(sle.posting_date > getdate(filters.start_from))

return query.run(as_dict=True) or []


Expand Down

0 comments on commit 9763a0b

Please sign in to comment.