Skip to content

Commit

Permalink
fix: stock ageing data for stock balance report
Browse files Browse the repository at this point in the history
  • Loading branch information
rohitwaghchaure committed Dec 10, 2024
1 parent 1edbd04 commit 4a76720
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
"item_group",
"column_break_ljle",
"stock_uom",
"inventory_dimension_key"
"inventory_dimension_key",
"stock_ageing_section",
"fifo_queue"
],
"fields": [
{
Expand Down Expand Up @@ -216,14 +218,25 @@
"options": "Batch",
"read_only": 1,
"search_index": 1
},
{
"fieldname": "stock_ageing_section",
"fieldtype": "Section Break",
"label": "Stock Ageing"
},
{
"fieldname": "fifo_queue",
"fieldtype": "Long Text",
"label": "FIFO Queue",
"read_only": 1
}
],
"hide_toolbar": 1,
"icon": "fa fa-list",
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-12-10 11:54:58.522295",
"modified": "2024-12-10 21:56:36.633567",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Closing Balance",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class StockClosingBalance(Document):
actual_qty: DF.Float
batch_no: DF.Link | None
company: DF.Link | None
fifo_queue: DF.LongText | None
inventory_dimension_key: DF.SmallText | None
item_code: DF.Link | None
item_group: DF.Link | None
Expand Down
43 changes: 37 additions & 6 deletions erpnext/stock/doctype/stock_closing_entry/stock_closing_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from frappe.core.doctype.prepared_report.prepared_report import create_json_gz_file
from frappe.desk.form.load import get_attachments
from frappe.model.document import Document
from frappe.utils import add_days, get_link_to_form, nowtime, parse_json
from frappe.utils import add_days, get_link_to_form, nowtime, parse_json, get_date_str
from frappe.utils.background_jobs import enqueue

from erpnext.stock.doctype.inventory_dimension.inventory_dimension import get_inventory_dimensions
Expand Down Expand Up @@ -111,13 +111,15 @@ def create_stock_closing_balance_entries(self):
stk_cl_obj = StockClosing(self.company, self.from_date, self.to_date)

entries = stk_cl_obj.get_stock_closing_entries()

for key in entries:
row = entries[key]

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

if row.fifo_queue is not None:
row.fifo_queue = json.dumps(row.fifo_queue)

new_doc = frappe.new_doc("Stock Closing Balance")
new_doc.update(row)
new_doc.posting_date = self.to_date
Expand Down Expand Up @@ -174,38 +176,62 @@ def get_stock_closing_entries(self):
key = dimension_values

if key in closing_stock:
closing_stock[key].actual_qty += row.sabb_qty or row.actual_qty
actual_qty = row.sabb_qty or row.actual_qty
closing_stock[key].actual_qty += actual_qty
closing_stock[key].stock_value_difference += (
row.sabb_stock_value_difference or row.stock_value_difference
)

if not row.actual_qty and row.qty_after_transaction:
closing_stock[key].actual_qty = row.qty_after_transaction

fifo_queue = closing_stock[key].fifo_queue
if fifo_queue:
self.update_fifo_queue(fifo_queue, actual_qty, row.posting_date)
closing_stock[key].fifo_queue = fifo_queue
else:
entries = self.get_initialized_entry(row, dimension_fields)
closing_stock[key] = entries

return closing_stock

def update_fifo_queue(self, fifo_queue, actual_qty, posting_date):
if actual_qty > 0:
fifo_queue.append([actual_qty, get_date_str(posting_date)])
else:
remaining_qty = actual_qty
for idx, queue in enumerate(fifo_queue):
if queue[0] + remaining_qty >= 0:
queue[0] += remaining_qty
if queue[0] == 0:
fifo_queue.pop(idx)
break
else:
remaining_qty += queue[0]
fifo_queue.pop(0)

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
"Item", row.item_code, ["item_group", "item_name", "stock_uom", "has_serial_no"], as_dict=1
)

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

actual_qty = row.sabb_qty or row.actual_qty or row.qty_after_transaction

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,
"actual_qty": actual_qty,
"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,
"fifo_queue": [[actual_qty, get_date_str(row.posting_date)]] if not item_details.has_serial_no else [],
}
)

Expand Down Expand Up @@ -377,7 +403,12 @@ def get_stock_closing_balance(self, kwargs, for_batch=False):
query = frappe.qb.from_(table).select("*").where(table.stock_closing_entry == stock_closing_entry)

for key, value in kwargs.items():
if isinstance(value, list) or isinstance(value, tuple):
if key == "inventory_dimension_key":
if isinstance(value, tuple) and value[0] == "is" and value[1] == "not set":
query = query.where(
table.inventory_dimension_key.isnull() | (table.inventory_dimension_key == "")
)
elif isinstance(value, list) or isinstance(value, tuple):
query = query.where(table[key].isin(value))
else:
query = query.where(table[key] == value)
Expand Down
7 changes: 5 additions & 2 deletions erpnext/stock/report/stock_balance/stock_balance.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def prepare_opening_stock(self) -> None:
"item_name": entry.item_name,
"opening_qty": entry.actual_qty,
"opening_val": entry.stock_value_difference,
"opening_fifo_queue": [],
"opening_fifo_queue": json.loads(entry.fifo_queue) if entry.fifo_queue else [],
"in_qty": 0.0,
"in_val": 0.0,
"out_qty": 0.0,
Expand Down Expand Up @@ -124,6 +124,8 @@ def get_entries_from_stock_closing_balance(self) -> list:

if dimenion_keys:
query_filters["inventory_dimension_key"] = json.dumps(("item_code", "warehouse", *dimenion_keys))
else:
query_filters["inventory_dimension_key"] = ("is", "not set")

opening_entries = stk_cl_obj.get_stock_closing_balance(query_filters)
if not opening_entries:
Expand Down Expand Up @@ -210,7 +212,7 @@ def prepare_item_warehouse_map_for_current_period(self):
def prepare_new_data(self):
if self.filters.get("show_stock_ageing_data"):
self.filters["show_warehouse_wise_stock"] = True
item_wise_fifo_queue = FIFOSlots(self.filters, self.sle_entries).generate()
item_wise_fifo_queue = FIFOSlots(self.filters).generate()

_func = itemgetter(1)

Expand All @@ -237,6 +239,7 @@ def prepare_new_data(self):
opening_fifo_queue.extend(fifo_queue)

stock_ageing_data = {"average_age": 0, "earliest_age": 0, "latest_age": 0}

if opening_fifo_queue:
fifo_queue = sorted(filter(_func, opening_fifo_queue), key=_func)
if not fifo_queue:
Expand Down

0 comments on commit 4a76720

Please sign in to comment.