Merge pull request #33387 from rohitwaghchaure/audit-to-fix-incorrect-valuation-entry
fix: daily scheduler to identify and fix stock transfer entries having incorrect valuation
This commit is contained in:
commit
eaa04abe29
@ -420,6 +420,7 @@ scheduler_events = {
|
|||||||
"erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall.create_process_loan_security_shortfall",
|
"erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall.create_process_loan_security_shortfall",
|
||||||
"erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual.process_loan_interest_accrual_for_term_loans",
|
"erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual.process_loan_interest_accrual_for_term_loans",
|
||||||
"erpnext.crm.utils.open_leads_opportunities_based_on_todays_event",
|
"erpnext.crm.utils.open_leads_opportunities_based_on_todays_event",
|
||||||
|
"erpnext.stock.doctype.stock_entry.stock_entry.audit_incorrect_valuation_entries",
|
||||||
],
|
],
|
||||||
"monthly_long": [
|
"monthly_long": [
|
||||||
"erpnext.accounts.deferred_revenue.process_deferred_accounting",
|
"erpnext.accounts.deferred_revenue.process_deferred_accounting",
|
||||||
|
@ -4,12 +4,24 @@
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
from frappe.query_builder.functions import Sum
|
from frappe.query_builder.functions import Sum
|
||||||
from frappe.utils import cint, comma_or, cstr, flt, format_time, formatdate, getdate, nowdate
|
from frappe.utils import (
|
||||||
|
add_days,
|
||||||
|
cint,
|
||||||
|
comma_or,
|
||||||
|
cstr,
|
||||||
|
flt,
|
||||||
|
format_time,
|
||||||
|
formatdate,
|
||||||
|
getdate,
|
||||||
|
nowdate,
|
||||||
|
today,
|
||||||
|
)
|
||||||
|
|
||||||
import erpnext
|
import erpnext
|
||||||
from erpnext.accounts.general_ledger import process_gl_map
|
from erpnext.accounts.general_ledger import process_gl_map
|
||||||
@ -2700,3 +2712,62 @@ def get_stock_entry_data(work_order):
|
|||||||
)
|
)
|
||||||
.orderby(stock_entry.creation, stock_entry_detail.item_code, stock_entry_detail.idx)
|
.orderby(stock_entry.creation, stock_entry_detail.item_code, stock_entry_detail.idx)
|
||||||
).run(as_dict=1)
|
).run(as_dict=1)
|
||||||
|
|
||||||
|
|
||||||
|
def audit_incorrect_valuation_entries():
|
||||||
|
# Audit of stock transfer entries having incorrect valuation
|
||||||
|
from erpnext.controllers.stock_controller import create_repost_item_valuation_entry
|
||||||
|
|
||||||
|
stock_entries = get_incorrect_stock_entries()
|
||||||
|
|
||||||
|
for stock_entry, values in stock_entries.items():
|
||||||
|
reposting_data = frappe._dict(
|
||||||
|
{
|
||||||
|
"posting_date": values.posting_date,
|
||||||
|
"posting_time": values.posting_time,
|
||||||
|
"voucher_type": "Stock Entry",
|
||||||
|
"voucher_no": stock_entry,
|
||||||
|
"company": values.company,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
create_repost_item_valuation_entry(reposting_data)
|
||||||
|
|
||||||
|
|
||||||
|
def get_incorrect_stock_entries() -> Dict:
|
||||||
|
stock_entry = frappe.qb.DocType("Stock Entry")
|
||||||
|
stock_ledger_entry = frappe.qb.DocType("Stock Ledger Entry")
|
||||||
|
transfer_purposes = [
|
||||||
|
"Material Transfer",
|
||||||
|
"Material Transfer for Manufacture",
|
||||||
|
"Send to Subcontractor",
|
||||||
|
]
|
||||||
|
|
||||||
|
query = (
|
||||||
|
frappe.qb.from_(stock_entry)
|
||||||
|
.inner_join(stock_ledger_entry)
|
||||||
|
.on(stock_entry.name == stock_ledger_entry.voucher_no)
|
||||||
|
.select(
|
||||||
|
stock_entry.name,
|
||||||
|
stock_entry.company,
|
||||||
|
stock_entry.posting_date,
|
||||||
|
stock_entry.posting_time,
|
||||||
|
Sum(stock_ledger_entry.stock_value_difference).as_("stock_value"),
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
(stock_entry.docstatus == 1)
|
||||||
|
& (stock_entry.purpose.isin(transfer_purposes))
|
||||||
|
& (stock_ledger_entry.modified > add_days(today(), -2))
|
||||||
|
)
|
||||||
|
.groupby(stock_ledger_entry.voucher_detail_no)
|
||||||
|
.having(Sum(stock_ledger_entry.stock_value_difference) != 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
data = query.run(as_dict=True)
|
||||||
|
stock_entries = {}
|
||||||
|
|
||||||
|
for row in data:
|
||||||
|
if abs(row.stock_value) > 0.1 and row.name not in stock_entries:
|
||||||
|
stock_entries.setdefault(row.name, row)
|
||||||
|
|
||||||
|
return stock_entries
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe.permissions import add_user_permission, remove_user_permission
|
from frappe.permissions import add_user_permission, remove_user_permission
|
||||||
from frappe.tests.utils import FrappeTestCase, change_settings
|
from frappe.tests.utils import FrappeTestCase, change_settings
|
||||||
from frappe.utils import add_days, flt, nowdate, nowtime, today
|
from frappe.utils import add_days, flt, now, nowdate, nowtime, today
|
||||||
|
|
||||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||||
from erpnext.stock.doctype.item.test_item import (
|
from erpnext.stock.doctype.item.test_item import (
|
||||||
@ -17,6 +17,8 @@ from erpnext.stock.doctype.item.test_item import (
|
|||||||
from erpnext.stock.doctype.serial_no.serial_no import * # noqa
|
from erpnext.stock.doctype.serial_no.serial_no import * # noqa
|
||||||
from erpnext.stock.doctype.stock_entry.stock_entry import (
|
from erpnext.stock.doctype.stock_entry.stock_entry import (
|
||||||
FinishedGoodError,
|
FinishedGoodError,
|
||||||
|
audit_incorrect_valuation_entries,
|
||||||
|
get_incorrect_stock_entries,
|
||||||
move_sample_to_retention_warehouse,
|
move_sample_to_retention_warehouse,
|
||||||
)
|
)
|
||||||
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
|
||||||
@ -1614,6 +1616,44 @@ class TestStockEntry(FrappeTestCase):
|
|||||||
|
|
||||||
self.assertRaises(BatchExpiredError, se.save)
|
self.assertRaises(BatchExpiredError, se.save)
|
||||||
|
|
||||||
|
def test_audit_incorrect_stock_entries(self):
|
||||||
|
item_code = "Test Incorrect Valuation Rate Item - 001"
|
||||||
|
create_item(item_code=item_code, is_stock_item=1)
|
||||||
|
|
||||||
|
make_stock_entry(
|
||||||
|
item_code=item_code,
|
||||||
|
purpose="Material Receipt",
|
||||||
|
posting_date=add_days(nowdate(), -10),
|
||||||
|
qty=2,
|
||||||
|
rate=500,
|
||||||
|
to_warehouse="_Test Warehouse - _TC",
|
||||||
|
)
|
||||||
|
|
||||||
|
transfer_entry = make_stock_entry(
|
||||||
|
item_code=item_code,
|
||||||
|
purpose="Material Transfer",
|
||||||
|
qty=2,
|
||||||
|
rate=500,
|
||||||
|
from_warehouse="_Test Warehouse - _TC",
|
||||||
|
to_warehouse="_Test Warehouse 1 - _TC",
|
||||||
|
)
|
||||||
|
|
||||||
|
sle_name = frappe.db.get_value(
|
||||||
|
"Stock Ledger Entry", {"voucher_no": transfer_entry.name, "actual_qty": (">", 0)}, "name"
|
||||||
|
)
|
||||||
|
|
||||||
|
frappe.db.set_value(
|
||||||
|
"Stock Ledger Entry", sle_name, {"modified": add_days(now(), -1), "stock_value_difference": 10}
|
||||||
|
)
|
||||||
|
|
||||||
|
stock_entries = get_incorrect_stock_entries()
|
||||||
|
self.assertTrue(transfer_entry.name in stock_entries)
|
||||||
|
|
||||||
|
audit_incorrect_valuation_entries()
|
||||||
|
|
||||||
|
stock_entries = get_incorrect_stock_entries()
|
||||||
|
self.assertFalse(transfer_entry.name in stock_entries)
|
||||||
|
|
||||||
|
|
||||||
def make_serialized_item(**args):
|
def make_serialized_item(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
Loading…
Reference in New Issue
Block a user