Merge pull request #29641 from deepeshgarg007/jv_cancel_ignore
fix: Ignore linked invoices on Journal Entry cancel
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 279557a..76d9cc7 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -537,8 +537,11 @@
voucher_wise_stock_value = {}
if self.update_stock:
- for d in frappe.get_all('Stock Ledger Entry',
- fields = ["voucher_detail_no", "stock_value_difference", "warehouse"], filters={'voucher_no': self.name}):
+ stock_ledger_entries = frappe.get_all("Stock Ledger Entry",
+ fields = ["voucher_detail_no", "stock_value_difference", "warehouse"],
+ filters={"voucher_no": self.name, "voucher_type": self.doctype, "is_cancelled": 0}
+ )
+ for d in stock_ledger_entries:
voucher_wise_stock_value.setdefault((d.voucher_detail_no, d.warehouse), d.stock_value_difference)
valuation_tax_accounts = [d.account_head for d in self.get("taxes")
diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure.json b/erpnext/payroll/doctype/salary_structure/salary_structure.json
index 5dd1d70..8df9957 100644
--- a/erpnext/payroll/doctype/salary_structure/salary_structure.json
+++ b/erpnext/payroll/doctype/salary_structure/salary_structure.json
@@ -58,6 +58,7 @@
"width": "50%"
},
{
+ "allow_on_submit": 1,
"default": "Yes",
"fieldname": "is_active",
"fieldtype": "Select",
@@ -232,10 +233,11 @@
"idx": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-03-31 15:41:12.342380",
+ "modified": "2022-02-03 23:50:10.205676",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Salary Structure",
+ "naming_rule": "Set by user",
"owner": "Administrator",
"permissions": [
{
@@ -271,5 +273,6 @@
],
"show_name_in_global_search": 1,
"sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "states": []
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index 9204842..df8cadd 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -4,10 +4,11 @@
import frappe
-from frappe.utils import flt
+from frappe.utils import add_to_date, flt, now
from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
+from erpnext.accounts.utils import update_gl_entries_after
from erpnext.assets.doctype.asset.test_asset import create_asset_category, create_fixed_asset_item
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import (
get_gl_entries,
@@ -28,7 +29,8 @@
"voucher_type": pr.doctype,
"voucher_no": pr.name,
"item_code": "_Test Item",
- "warehouse": "Stores - TCP1"
+ "warehouse": "Stores - TCP1",
+ "is_cancelled": 0,
},
fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
@@ -41,14 +43,39 @@
"voucher_type": pr.doctype,
"voucher_no": pr.name,
"item_code": "_Test Item",
- "warehouse": "Stores - TCP1"
+ "warehouse": "Stores - TCP1",
+ "is_cancelled": 0,
},
fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
self.assertEqual(last_sle.qty_after_transaction, last_sle_after_landed_cost.qty_after_transaction)
-
self.assertEqual(last_sle_after_landed_cost.stock_value - last_sle.stock_value, 25.0)
+ # assert after submit
+ self.assertPurchaseReceiptLCVGLEntries(pr)
+
+ # Mess up cancelled SLE modified timestamp to check
+ # if they aren't effective in any business logic.
+ frappe.db.set_value("Stock Ledger Entry",
+ {
+ "is_cancelled": 1,
+ "voucher_type": pr.doctype,
+ "voucher_no": pr.name
+ },
+ "is_cancelled", 1,
+ modified=add_to_date(now(), hours=1, as_datetime=True, as_string=True)
+ )
+
+ items, warehouses = pr.get_items_and_warehouses()
+ update_gl_entries_after(pr.posting_date, pr.posting_time,
+ warehouses, items, company=pr.company)
+
+ # reassert after reposting
+ self.assertPurchaseReceiptLCVGLEntries(pr)
+
+
+ def assertPurchaseReceiptLCVGLEntries(self, pr):
+
gl_entries = get_gl_entries("Purchase Receipt", pr.name)
self.assertTrue(gl_entries)
@@ -74,8 +101,8 @@
for gle in gl_entries:
if not gle.get('is_cancelled'):
- self.assertEqual(expected_values[gle.account][0], gle.debit)
- self.assertEqual(expected_values[gle.account][1], gle.credit)
+ self.assertEqual(expected_values[gle.account][0], gle.debit, msg=f"incorrect debit for {gle.account}")
+ self.assertEqual(expected_values[gle.account][1], gle.credit, msg=f"incorrect credit for {gle.account}")
def test_landed_cost_voucher_against_purchase_invoice(self):
diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py
index e3b5795..07c2f1f 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.py
+++ b/erpnext/stock/doctype/packed_item/packed_item.py
@@ -27,8 +27,7 @@
stale_packed_items_table = get_indexed_packed_items_table(doc)
- if not doc.is_new():
- reset = reset_packing_list_if_deleted_items_exist(doc)
+ reset = reset_packing_list(doc)
for item_row in doc.get("items"):
if frappe.db.exists("Product Bundle", {"new_item_code": item_row.item_code}):
@@ -64,20 +63,24 @@
return indexed_table
-def reset_packing_list_if_deleted_items_exist(doc):
- doc_before_save = doc.get_doc_before_save()
+def reset_packing_list(doc):
+ "Conditionally reset the table and return if it was reset or not."
reset_table = False
+ doc_before_save = doc.get_doc_before_save()
if doc_before_save:
# reset table if:
# 1. items were deleted
# 2. if bundle item replaced by another item (same no. of items but different items)
- # we maintain list to maintain repeated item rows as well
+ # we maintain list to track recurring item rows as well
items_before_save = [item.item_code for item in doc_before_save.get("items")]
items_after_save = [item.item_code for item in doc.get("items")]
reset_table = items_before_save != items_after_save
else:
- reset_table = True # reset if via Update Items (cannot determine action)
+ # reset: if via Update Items OR
+ # if new mapped doc with packed items set (SO -> DN)
+ # (cannot determine action)
+ reset_table = True
if reset_table:
doc.set("packed_items", [])
diff --git a/erpnext/stock/doctype/packed_item/test_packed_item.py b/erpnext/stock/doctype/packed_item/test_packed_item.py
index ed4eecd..5cbaa1e 100644
--- a/erpnext/stock/doctype/packed_item/test_packed_item.py
+++ b/erpnext/stock/doctype/packed_item/test_packed_item.py
@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
+from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.tests.utils import ERPNextTestCase, change_settings
@@ -22,7 +23,7 @@
qty=2
)
- def test_sales_order_adding_bundle_item(self):
+ def test_adding_bundle_item(self):
"Test impact on packed items if bundle item row is added."
so = make_sales_order(item_code = "_Test Product Bundle X", qty=1,
do_not_submit=True)
@@ -32,7 +33,7 @@
self.assertEqual(so.packed_items[0].item_code, "_Test Bundle Item 1")
self.assertEqual(so.packed_items[0].qty, 2)
- def test_sales_order_updating_bundle_item(self):
+ def test_updating_bundle_item(self):
"Test impact on packed items if bundle item row is updated."
so = make_sales_order(item_code = "_Test Product Bundle X", qty=1,
do_not_submit=True)
@@ -49,7 +50,7 @@
self.assertEqual(len(so.packed_items), 0)
- def test_sales_order_recurring_bundle_item(self):
+ def test_recurring_bundle_item(self):
"Test impact on packed items if same bundle item is added and removed."
so_items = []
for qty in [2, 4, 6, 8]:
@@ -91,7 +92,7 @@
self.assertEqual(so.packed_items[3].qty, 12)
@change_settings("Selling Settings", {"editable_bundle_item_rates": 1})
- def test_sales_order_bundle_item_cumulative_price(self):
+ def test_bundle_item_cumulative_price(self):
"Test if Bundle Item rate is cumulative from packed items."
so = make_sales_order(item_code = "_Test Product Bundle X", qty=2,
do_not_submit=True)
@@ -102,3 +103,25 @@
self.assertEqual(so.items[0].rate, 350)
self.assertEqual(so.items[0].amount, 700)
+
+ def test_newly_mapped_doc_packed_items(self):
+ "Test impact on packed items in newly mapped DN from SO."
+ so_items = []
+ for qty in [2, 4]:
+ so_items.append({
+ "item_code": "_Test Product Bundle X",
+ "qty": qty,
+ "rate": 400,
+ "warehouse": "_Test Warehouse - _TC"
+ })
+
+ # create SO with recurring bundle item
+ so = make_sales_order(item_list=so_items)
+
+ dn = make_delivery_note(so.name)
+ dn.items[1].qty = 3 # change second row qty for inserting doc
+ dn.save()
+
+ self.assertEqual(len(dn.packed_items), 4)
+ self.assertEqual(dn.packed_items[2].qty, 6)
+ self.assertEqual(dn.packed_items[3].qty, 6)
\ No newline at end of file
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 1257057..ffdf8c4 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -286,7 +286,7 @@
if warehouse_account.get(d.warehouse):
stock_value_diff = frappe.db.get_value("Stock Ledger Entry",
{"voucher_type": "Purchase Receipt", "voucher_no": self.name,
- "voucher_detail_no": d.name, "warehouse": d.warehouse}, "stock_value_difference")
+ "voucher_detail_no": d.name, "warehouse": d.warehouse, "is_cancelled": 0}, "stock_value_difference")
if not stock_value_diff:
continue