refactor: simpler batching for GLE reposting (#31374)

* refactor: simpler batching for GLE reposting

* test: add "actual" test for chunked GLE reposting
This commit is contained in:
Ankush Menat
2022-06-15 19:30:26 +05:30
committed by GitHub
parent d9c6b7218a
commit 5c6f22f275
3 changed files with 63 additions and 8 deletions

View File

@@ -2,7 +2,6 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
import itertools
from json import loads from json import loads
from typing import TYPE_CHECKING, List, Optional, Tuple from typing import TYPE_CHECKING, List, Optional, Tuple
@@ -11,7 +10,17 @@ import frappe.defaults
from frappe import _, qb, throw from frappe import _, qb, throw
from frappe.model.meta import get_field_precision from frappe.model.meta import get_field_precision
from frappe.query_builder.utils import DocType 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 import Order
from pypika.terms import ExistsCriterion from pypika.terms import ExistsCriterion
@@ -1149,9 +1158,7 @@ def repost_gle_for_stock_vouchers(
precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit")) or 2 precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit")) or 2
stock_vouchers_iterator = iter(stock_vouchers) for stock_vouchers_chunk in create_batch(stock_vouchers, GL_REPOSTING_CHUNK):
while stock_vouchers_chunk := list(itertools.islice(stock_vouchers_iterator, GL_REPOSTING_CHUNK)):
gle = get_voucherwise_gl_entries(stock_vouchers_chunk, posting_date) gle = get_voucherwise_gl_entries(stock_vouchers_chunk, posting_date)
for voucher_type, voucher_no in stock_vouchers_chunk: for voucher_type, voucher_no in stock_vouchers_chunk:
@@ -1173,7 +1180,7 @@ def repost_gle_for_stock_vouchers(
if repost_doc: if repost_doc:
repost_doc.db_set( repost_doc.db_set(
"gl_reposting_index", "gl_reposting_index",
cint(repost_doc.gl_reposting_index) + GL_REPOSTING_CHUNK, cint(repost_doc.gl_reposting_index) + len(stock_vouchers_chunk),
) )

View File

@@ -87,6 +87,7 @@ class RepostItemValuation(Document):
self.current_index = 0 self.current_index = 0
self.distinct_item_and_warehouse = None self.distinct_item_and_warehouse = None
self.items_to_be_repost = None self.items_to_be_repost = None
self.gl_reposting_index = 0
self.db_update() self.db_update()
def deduplicate_similar_repost(self): def deduplicate_similar_repost(self):

View File

@@ -7,7 +7,7 @@ from unittest.mock import MagicMock, call
import frappe import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests.utils import FrappeTestCase
from frappe.utils import nowdate 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.accounts.utils import repost_gle_for_stock_vouchers
from erpnext.controllers.stock_controller import create_item_wise_repost_entries from erpnext.controllers.stock_controller import create_item_wise_repost_entries
@@ -17,10 +17,11 @@ from erpnext.stock.doctype.repost_item_valuation.repost_item_valuation import (
in_configured_timeslot, in_configured_timeslot,
) )
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry 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 from erpnext.stock.utils import PendingRepostingError
class TestRepostItemValuation(FrappeTestCase): class TestRepostItemValuation(FrappeTestCase, StockTestMixin):
def tearDown(self): def tearDown(self):
frappe.flags.dont_execute_stock_reposts = False frappe.flags.dont_execute_stock_reposts = False
@@ -225,3 +226,49 @@ class TestRepostItemValuation(FrappeTestCase):
repost_gle_for_stock_vouchers(stock_vouchers=vouchers, posting_date=posting_date, repost_doc=doc) 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) 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"},
)