mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-16 08:05:00 +00:00
feat: option to recreate Stock Ledger Entries against stock transactions
This commit is contained in:
@@ -4126,6 +4126,54 @@ class TestPurchaseReceipt(IntegrationTestCase):
|
||||
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
|
||||
|
||||
@@ -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,8 @@
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -108,6 +110,10 @@ class RepostItemValuation(Document):
|
||||
)
|
||||
)
|
||||
|
||||
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,
|
||||
@@ -245,6 +251,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")
|
||||
@@ -263,6 +279,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)
|
||||
|
||||
|
||||
@@ -185,11 +185,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,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user