Merge pull request #46807 from frappe/mergify/bp/version-15-hotfix/pr-46806

feat: option to recreate Stock Ledger Entries against stock transactions (backport #46806)
This commit is contained in:
rohitwaghchaure
2025-03-31 16:06:42 +05:30
committed by GitHub
4 changed files with 86 additions and 5 deletions

View File

@@ -4077,6 +4077,54 @@ class TestPurchaseReceipt(FrappeTestCase):
pr.reload()
self.assertEqual(pr.status, "To Bill")
def test_recreate_stock_ledgers(self):
item_code = "Test Item for Recreate Stock Ledgers"
create_item(item_code)
pr = make_purchase_receipt(item_code=item_code, qty=10, rate=100)
pr.submit()
sles = frappe.get_all(
"Stock Ledger Entry",
filters={"voucher_type": pr.doctype, "voucher_no": pr.name},
pluck="name",
)
self.assertTrue(sles)
for row in sles:
doc = frappe.get_doc("Stock Ledger Entry", row)
doc.delete()
sles = frappe.get_all(
"Stock Ledger Entry",
filters={"voucher_type": pr.doctype, "voucher_no": pr.name},
pluck="name",
)
self.assertFalse(sles)
frappe.get_doc(
{
"doctype": "Repost Item Valuation",
"based_on": "Transaction",
"voucher_type": pr.doctype,
"voucher_no": pr.name,
"posting_date": pr.posting_date,
"posting_time": pr.posting_time,
"company": pr.company,
"recreate_stock_ledgers": 1,
}
).submit()
sles = frappe.get_all(
"Stock Ledger Entry",
filters={"voucher_type": pr.doctype, "voucher_no": pr.name},
pluck="name",
)
self.assertTrue(sles)
def prepare_data_for_internal_transfer():
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier

View File

@@ -19,6 +19,7 @@
"allow_negative_stock",
"via_landed_cost_voucher",
"allow_zero_rate",
"recreate_stock_ledgers",
"amended_from",
"error_section",
"error_log",
@@ -220,12 +221,20 @@
"label": "Reposting Data File",
"no_copy": 1,
"read_only": 1
},
{
"default": "0",
"depends_on": "eval:doc.based_on == \"Transaction\"",
"fieldname": "recreate_stock_ledgers",
"fieldtype": "Check",
"label": "Recreate Stock Ledgers"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2024-06-27 16:55:23.150146",
"modified": "2025-03-31 12:38:20.566196",
"modified_by": "Administrator",
"module": "Stock",
"name": "Repost Item Valuation",
@@ -274,7 +283,7 @@
"write": 1
}
],
"sort_field": "modified",
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}

View File

@@ -47,6 +47,7 @@ class RepostItemValuation(Document):
items_to_be_repost: DF.Code | None
posting_date: DF.Date
posting_time: DF.Time | None
recreate_stock_ledgers: DF.Check
reposting_data_file: DF.Attach | None
status: DF.Literal["Queued", "In Progress", "Completed", "Skipped", "Failed"]
total_reposting_count: DF.Int
@@ -74,6 +75,7 @@ class RepostItemValuation(Document):
self.reset_field_values()
self.set_company()
self.validate_accounts_freeze()
self.reset_recreate_stock_ledgers()
def validate_period_closing_voucher(self):
# Period Closing Voucher
@@ -105,6 +107,10 @@ class RepostItemValuation(Document):
msg = f"Due to closing stock balance {name}, you cannot repost item valuation before {to_date}"
frappe.throw(_(msg))
def reset_recreate_stock_ledgers(self):
if self.recreate_stock_ledgers and self.based_on != "Transaction":
self.recreate_stock_ledgers = 0
def get_closing_stock_balance(self):
filters = {
"company": self.company,
@@ -250,6 +256,16 @@ class RepostItemValuation(Document):
filters,
)
def recreate_stock_ledger_entries(self):
"""Recreate Stock Ledger Entries for the transaction."""
if self.based_on == "Transaction" and self.recreate_stock_ledgers:
doc = frappe.get_doc(self.voucher_type, self.voucher_no)
doc.docstatus = 2
doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True)
doc.docstatus = 1
doc.update_stock_ledger(allow_negative_stock=True)
def on_doctype_update():
frappe.db.add_index("Repost Item Valuation", ["warehouse", "item_code"], "item_warehouse")
@@ -268,6 +284,9 @@ def repost(doc):
if not frappe.flags.in_test:
frappe.db.commit()
if doc.recreate_stock_ledgers:
doc.recreate_stock_ledger_entries()
repost_sl_entries(doc)
repost_gl_entries(doc)

View File

@@ -184,11 +184,16 @@ def validate_serial_no(sle):
frappe.throw(_(msg), title=_(title), exc=SerialNoExistsInFutureTransaction)
def validate_cancellation(args):
if args[0].get("is_cancelled"):
def validate_cancellation(kargs):
if kargs[0].get("is_cancelled"):
repost_entry = frappe.db.get_value(
"Repost Item Valuation",
{"voucher_type": args[0].voucher_type, "voucher_no": args[0].voucher_no, "docstatus": 1},
{
"voucher_type": kargs[0].voucher_type,
"voucher_no": kargs[0].voucher_no,
"docstatus": 1,
"recreate_stock_ledgers": 0,
},
["name", "status"],
as_dict=1,
)