fix: consider previous balance is missing
Also remove `total`, total of total is a meaningless value.
diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.py b/erpnext/stock/report/stock_analytics/stock_analytics.py
index da0776b..77faa1f 100644
--- a/erpnext/stock/report/stock_analytics/stock_analytics.py
+++ b/erpnext/stock/report/stock_analytics/stock_analytics.py
@@ -1,6 +1,7 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import datetime
+from typing import List
import frappe
from frappe import _, scrub
@@ -148,11 +149,19 @@
- Warehouse A : bal_qty/value
- Warehouse B : bal_qty/value
"""
+
+ expected_ranges = get_period_date_ranges(filters)
+ expected_periods = []
+ for _start_date, end_date in expected_ranges:
+ expected_periods.append(get_period(end_date, filters))
+
periodic_data = {}
for d in entry:
period = get_period(d.posting_date, filters)
bal_qty = 0
+ fill_intermediate_periods(periodic_data, d.item_code, period, expected_periods)
+
# if period against item does not exist yet, instantiate it
# insert existing balance dict against period, and add/subtract to it
if periodic_data.get(d.item_code) and not periodic_data.get(d.item_code).get(period):
@@ -186,6 +195,36 @@
return periodic_data
+def fill_intermediate_periods(
+ periodic_data, item_code: str, current_period: str, all_periods: List[str]
+) -> None:
+ """There might be intermediate periods where no stock ledger entry exists, copy previous previous data.
+
+ Previous data is ONLY copied if period falls in report range and before period being processed currently.
+
+ args:
+ current_period: process till this period (exclusive)
+ all_periods: all periods expected in report via filters
+ periodic_data: report's periodic data
+ item_code: item_code being processed
+ """
+
+ previous_period_data = None
+ for period in all_periods:
+ if period == current_period:
+ return
+
+ if (
+ periodic_data.get(item_code)
+ and not periodic_data.get(item_code).get(period)
+ and previous_period_data
+ ):
+ # This period should exist since it's in report range, assign previous period data
+ periodic_data[item_code][period] = previous_period_data.copy()
+
+ previous_period_data = periodic_data.get(item_code, {}).get(period)
+
+
def get_data(filters):
data = []
items = get_items(filters)
@@ -202,14 +241,15 @@
"uom": item_data.stock_uom,
"brand": item_data.brand,
}
- total = 0
- for dummy, end_date in ranges:
+ previous_period_value = 0.0
+ for _start_date, end_date in ranges:
period = get_period(end_date, filters)
period_data = periodic_data.get(item_data.name, {}).get(period)
- amount = sum(period_data.values()) if period_data else 0
- row[scrub(period)] = amount
- total += amount
- row["total"] = total
+ if period_data:
+ row[scrub(period)] = previous_period_value = sum(period_data.values())
+ else:
+ row[scrub(period)] = previous_period_value
+
data.append(row)
return data
diff --git a/erpnext/stock/report/stock_analytics/test_stock_analytics.py b/erpnext/stock/report/stock_analytics/test_stock_analytics.py
index d9f10e5..dd8f8d8 100644
--- a/erpnext/stock/report/stock_analytics/test_stock_analytics.py
+++ b/erpnext/stock/report/stock_analytics/test_stock_analytics.py
@@ -102,3 +102,15 @@
(20, add_to_date(today, months=3).replace(day=15)),
]
self.assert_single_item_report(movement, [100, 50, 50, 70])
+
+ def test_multi_month_missings(self):
+ today = getdate()
+ movement = [
+ (100, add_to_date(today, months=0).replace(day=15)),
+ (-50, add_to_date(today, months=1).replace(day=15)),
+ # Skip a month
+ (20, add_to_date(today, months=3).replace(day=15)),
+ # Skip another month
+ (-10, add_to_date(today, months=5).replace(day=15)),
+ ]
+ self.assert_single_item_report(movement, [100, 50, 50, 70, 70, 60])