refactor: simpler batching for GLE reposting (#31374)

* refactor: simpler batching for GLE reposting

* test: add "actual" test for chunked GLE reposting
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 2d86dea..f824a00 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -2,7 +2,6 @@
 # License: GNU General Public License v3. See license.txt
 
 
-import itertools
 from json import loads
 from typing import TYPE_CHECKING, List, Optional, Tuple
 
@@ -11,7 +10,17 @@
 from frappe import _, qb, throw
 from frappe.model.meta import get_field_precision
 from frappe.query_builder.utils import DocType
-from frappe.utils import cint, cstr, flt, formatdate, get_number_format_info, getdate, now, nowdate
+from frappe.utils import (
+	cint,
+	create_batch,
+	cstr,
+	flt,
+	formatdate,
+	get_number_format_info,
+	getdate,
+	now,
+	nowdate,
+)
 from pypika import Order
 from pypika.terms import ExistsCriterion
 
@@ -1149,9 +1158,7 @@
 
 	precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit")) or 2
 
-	stock_vouchers_iterator = iter(stock_vouchers)
-
-	while stock_vouchers_chunk := list(itertools.islice(stock_vouchers_iterator, GL_REPOSTING_CHUNK)):
+	for stock_vouchers_chunk in create_batch(stock_vouchers, GL_REPOSTING_CHUNK):
 		gle = get_voucherwise_gl_entries(stock_vouchers_chunk, posting_date)
 
 		for voucher_type, voucher_no in stock_vouchers_chunk:
@@ -1173,7 +1180,7 @@
 		if repost_doc:
 			repost_doc.db_set(
 				"gl_reposting_index",
-				cint(repost_doc.gl_reposting_index) + GL_REPOSTING_CHUNK,
+				cint(repost_doc.gl_reposting_index) + len(stock_vouchers_chunk),
 			)
 
 
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
index ea24b47..b1017d2 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -87,6 +87,7 @@
 		self.current_index = 0
 		self.distinct_item_and_warehouse = None
 		self.items_to_be_repost = None
+		self.gl_reposting_index = 0
 		self.db_update()
 
 	def deduplicate_similar_repost(self):
diff --git a/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py
index 3c74619..edd2553 100644
--- a/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py
@@ -7,7 +7,7 @@
 import frappe
 from frappe.tests.utils import FrappeTestCase
 from frappe.utils import nowdate
-from frappe.utils.data import today
+from frappe.utils.data import add_to_date, today
 
 from erpnext.accounts.utils import repost_gle_for_stock_vouchers
 from erpnext.controllers.stock_controller import create_item_wise_repost_entries
@@ -17,10 +17,11 @@
 	in_configured_timeslot,
 )
 from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+from erpnext.stock.tests.test_utils import StockTestMixin
 from erpnext.stock.utils import PendingRepostingError
 
 
-class TestRepostItemValuation(FrappeTestCase):
+class TestRepostItemValuation(FrappeTestCase, StockTestMixin):
 	def tearDown(self):
 		frappe.flags.dont_execute_stock_reposts = False
 
@@ -225,3 +226,49 @@
 		repost_gle_for_stock_vouchers(stock_vouchers=vouchers, posting_date=posting_date, repost_doc=doc)
 
 		self.assertNotIn(call("gl_reposting_index", 1), doc.db_set.mock_calls)
+
+	def test_gl_complete_gl_reposting(self):
+		from erpnext.accounts import utils
+
+		# lower numbers to simplify test
+		orig_chunk_size = utils.GL_REPOSTING_CHUNK
+		utils.GL_REPOSTING_CHUNK = 2
+		self.addCleanup(setattr, utils, "GL_REPOSTING_CHUNK", orig_chunk_size)
+
+		item = self.make_item().name
+
+		company = "_Test Company with perpetual inventory"
+
+		for _ in range(10):
+			make_stock_entry(item=item, company=company, qty=1, rate=10, target="Stores - TCP1")
+
+		# consume
+		consumption = make_stock_entry(item=item, company=company, qty=1, source="Stores - TCP1")
+
+		self.assertGLEs(
+			consumption,
+			[{"credit": 10, "debit": 0}],
+			gle_filters={"account": "Stock In Hand - TCP1"},
+		)
+
+		# backdated receipt
+		backdated_receipt = make_stock_entry(
+			item=item,
+			company=company,
+			qty=1,
+			rate=50,
+			target="Stores - TCP1",
+			posting_date=add_to_date(today(), days=-1),
+		)
+		self.assertGLEs(
+			backdated_receipt,
+			[{"credit": 0, "debit": 50}],
+			gle_filters={"account": "Stock In Hand - TCP1"},
+		)
+
+		# check that original consumption GLe is updated
+		self.assertGLEs(
+			consumption,
+			[{"credit": 50, "debit": 0}],
+			gle_filters={"account": "Stock In Hand - TCP1"},
+		)