Merge pull request #33382 from rohitwaghchaure/fixed-pick-list-issue
fix: unsupported operand type(s) for +=: 'int' and 'NoneType'
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index fd19d25..7d72c76 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -420,6 +420,7 @@
"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.crm.utils.open_leads_opportunities_based_on_todays_event",
+ "erpnext.stock.doctype.stock_entry.stock_entry.audit_incorrect_valuation_entries",
],
"monthly_long": [
"erpnext.accounts.deferred_revenue.process_deferred_accounting",
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index d401f81..a047a9b 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -4,12 +4,24 @@
import json
from collections import defaultdict
+from typing import Dict
import frappe
from frappe import _
from frappe.model.mapper import get_mapped_doc
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
from erpnext.accounts.general_ledger import process_gl_map
@@ -2700,3 +2712,62 @@
)
.orderby(stock_entry.creation, stock_entry_detail.item_code, stock_entry_detail.idx)
).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
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index b574b71..680d209 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -5,7 +5,7 @@
import frappe
from frappe.permissions import add_user_permission, remove_user_permission
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.stock.doctype.item.test_item import (
@@ -17,6 +17,8 @@
from erpnext.stock.doctype.serial_no.serial_no import * # noqa
from erpnext.stock.doctype.stock_entry.stock_entry import (
FinishedGoodError,
+ audit_incorrect_valuation_entries,
+ get_incorrect_stock_entries,
move_sample_to_retention_warehouse,
)
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
@@ -1614,6 +1616,44 @@
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):
args = frappe._dict(args)