mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-14 18:51:21 +00:00
feat: enable item wise inventory account
This commit is contained in:
509
erpnext/controllers/tests/test_item_wise_inventory_account.py
Normal file
509
erpnext/controllers/tests/test_item_wise_inventory_account.py
Normal file
@@ -0,0 +1,509 @@
|
||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import copy
|
||||
from collections import defaultdict
|
||||
|
||||
import frappe
|
||||
from frappe.tests import IntegrationTestCase
|
||||
from frappe.utils import cint
|
||||
|
||||
from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
|
||||
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
|
||||
from erpnext.manufacturing.doctype.work_order.work_order import make_stock_entry
|
||||
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||
|
||||
|
||||
class TestItemWiseInventoryAccount(IntegrationTestCase):
|
||||
def setUp(self):
|
||||
self.company = make_company()
|
||||
self.company_abbr = frappe.db.get_value("Company", self.company, "abbr")
|
||||
self.default_warehouse = frappe.db.get_value(
|
||||
"Warehouse",
|
||||
{"company": self.company, "is_group": 0, "warehouse_name": ("like", "%Stores%")},
|
||||
)
|
||||
|
||||
def test_item_account_for_purchase_receipt_entry(self):
|
||||
items = {
|
||||
"Stock Item A": {"is_stock_item": 1},
|
||||
"Stock Item B": {"is_stock_item": 1, "has_serial_no": 1, "serial_no_series": "SER-TT-.####"},
|
||||
}
|
||||
|
||||
for item_name, item_data in items.items():
|
||||
item = make_item(
|
||||
item_name,
|
||||
properties=item_data,
|
||||
)
|
||||
|
||||
account = self.add_inventory_account(item)
|
||||
items[item_name]["account"] = account
|
||||
|
||||
pr = make_purchase_receipt(
|
||||
item_code="Stock Item A",
|
||||
qty=5,
|
||||
rate=100,
|
||||
warehouse=self.default_warehouse,
|
||||
company=self.company,
|
||||
do_not_submit=True,
|
||||
)
|
||||
|
||||
pr.append(
|
||||
"items",
|
||||
{
|
||||
"item_code": "Stock Item B",
|
||||
"qty": 2,
|
||||
"rate": 200,
|
||||
"warehouse": self.default_warehouse,
|
||||
},
|
||||
)
|
||||
|
||||
pr.submit()
|
||||
|
||||
for row in items:
|
||||
item_code = row
|
||||
account = items[item_code]["account"]
|
||||
|
||||
sle_value = frappe.db.get_value(
|
||||
"Stock Ledger Entry",
|
||||
{"voucher_type": "Purchase Receipt", "voucher_no": pr.name, "item_code": item_code},
|
||||
"stock_value_difference",
|
||||
)
|
||||
|
||||
gl_value = frappe.db.get_value(
|
||||
"GL Entry",
|
||||
{
|
||||
"voucher_type": "Purchase Receipt",
|
||||
"voucher_no": pr.name,
|
||||
"account": account,
|
||||
},
|
||||
"debit",
|
||||
)
|
||||
|
||||
self.assertEqual(sle_value, gl_value, f"GL Entry not created for {item_code} correctly")
|
||||
|
||||
def test_item_account_for_delivery_note_entry(self):
|
||||
items = {
|
||||
"Stock Item A": {"is_stock_item": 1},
|
||||
"Stock Item B": {"is_stock_item": 1, "has_serial_no": 1, "serial_no_series": "SER-TT-.####"},
|
||||
}
|
||||
|
||||
for item_name, item_data in items.items():
|
||||
item = make_item(
|
||||
item_name,
|
||||
properties=item_data,
|
||||
)
|
||||
|
||||
account = self.add_inventory_account(item)
|
||||
items[item_name]["account"] = account
|
||||
|
||||
pr = make_purchase_receipt(
|
||||
item_code="Stock Item A",
|
||||
qty=5,
|
||||
rate=100,
|
||||
warehouse=self.default_warehouse,
|
||||
company=self.company,
|
||||
do_not_submit=True,
|
||||
)
|
||||
|
||||
pr.append(
|
||||
"items",
|
||||
{
|
||||
"item_code": "Stock Item B",
|
||||
"qty": 2,
|
||||
"rate": 200,
|
||||
"warehouse": self.default_warehouse,
|
||||
},
|
||||
)
|
||||
|
||||
pr.submit()
|
||||
|
||||
dn = create_delivery_note(
|
||||
item_code="Stock Item A",
|
||||
qty=5,
|
||||
rate=200,
|
||||
warehouse=self.default_warehouse,
|
||||
company=self.company,
|
||||
cost_center=frappe.db.get_value("Company", self.company, "cost_center"),
|
||||
expense_account=frappe.db.get_value("Company", self.company, "default_expense_account"),
|
||||
do_not_submit=True,
|
||||
)
|
||||
|
||||
dn.append(
|
||||
"items",
|
||||
{
|
||||
"item_code": "Stock Item B",
|
||||
"qty": 2,
|
||||
"rate": 300,
|
||||
"warehouse": self.default_warehouse,
|
||||
},
|
||||
)
|
||||
|
||||
dn.submit()
|
||||
|
||||
for row in items:
|
||||
item_code = row
|
||||
account = items[item_code]["account"]
|
||||
|
||||
sle_value = frappe.db.get_value(
|
||||
"Stock Ledger Entry",
|
||||
{"voucher_type": "Delivery Note", "voucher_no": dn.name, "item_code": item_code},
|
||||
"stock_value_difference",
|
||||
)
|
||||
|
||||
gl_value = (
|
||||
frappe.db.get_value(
|
||||
"GL Entry",
|
||||
{
|
||||
"voucher_type": "Delivery Note",
|
||||
"voucher_no": dn.name,
|
||||
"account": account,
|
||||
},
|
||||
"credit",
|
||||
)
|
||||
* -1
|
||||
)
|
||||
|
||||
self.assertEqual(sle_value, gl_value, f"GL Entry not created for {item_code} correctly")
|
||||
|
||||
def test_item_group_account_for_purchase_receipt_entry(self):
|
||||
items = {
|
||||
"Stock Item C": {"is_stock_item": 1, "item_group": "Test Item Group C"},
|
||||
"Stock Item C1": {"is_stock_item": 1, "item_group": "Test Item Group C", "qty": 3, "rate": 150},
|
||||
"Stock Item D": {
|
||||
"is_stock_item": 1,
|
||||
"has_serial_no": 1,
|
||||
"serial_no_series": "SER-TT-.####",
|
||||
"item_group": "Test Item Group D",
|
||||
"qty": 2,
|
||||
"rate": 250,
|
||||
},
|
||||
"Stock Item D1": {"is_stock_item": 1, "item_group": "Test Item Group D", "qty": 4, "rate": 300},
|
||||
}
|
||||
|
||||
for row in items:
|
||||
self.make_item_group(items[row]["item_group"])
|
||||
|
||||
inventory_account_dict = frappe._dict()
|
||||
for item_name, item_data in items.items():
|
||||
item_data = frappe._dict(item_data)
|
||||
make_item(
|
||||
item_name,
|
||||
properties=item_data,
|
||||
)
|
||||
|
||||
item_group = frappe.get_doc("Item Group", item_data.item_group)
|
||||
account = self.add_inventory_account(item_group, "item_group_defaults")
|
||||
inventory_account_dict[item_data.item_group] = account
|
||||
|
||||
pr = make_purchase_receipt(
|
||||
item_code="Stock Item C",
|
||||
qty=5,
|
||||
rate=100,
|
||||
warehouse=self.default_warehouse,
|
||||
company=self.company,
|
||||
do_not_submit=True,
|
||||
)
|
||||
|
||||
for item_code, values in items.items():
|
||||
if item_code == "Stock Item C":
|
||||
continue
|
||||
|
||||
pr.append(
|
||||
"items",
|
||||
{
|
||||
"item_code": item_code,
|
||||
"qty": values.get("qty", 1),
|
||||
"rate": values.get("rate", 200),
|
||||
"warehouse": self.default_warehouse,
|
||||
},
|
||||
)
|
||||
|
||||
pr.submit()
|
||||
|
||||
for item_group, account in inventory_account_dict.items():
|
||||
items = frappe.get_all(
|
||||
"Item",
|
||||
filters={"item_group": item_group},
|
||||
pluck="name",
|
||||
)
|
||||
|
||||
sle_value = frappe.get_all(
|
||||
"Stock Ledger Entry",
|
||||
filters={
|
||||
"voucher_type": "Purchase Receipt",
|
||||
"voucher_no": pr.name,
|
||||
"item_code": ("in", items),
|
||||
},
|
||||
fields=["sum(stock_value_difference) as value"],
|
||||
)
|
||||
|
||||
gl_value = frappe.db.get_value(
|
||||
"GL Entry",
|
||||
{
|
||||
"voucher_type": "Purchase Receipt",
|
||||
"voucher_no": pr.name,
|
||||
"account": account,
|
||||
},
|
||||
"debit",
|
||||
)
|
||||
|
||||
self.assertEqual(sle_value[0].value, gl_value, f"GL Entry not created for {item_code} correctly")
|
||||
|
||||
def test_item_group_account_for_delivery_note_entry(self):
|
||||
items = {
|
||||
"Stock Item E": {"is_stock_item": 1, "item_group": "Test Item Group E"},
|
||||
"Stock Item E1": {"is_stock_item": 1, "item_group": "Test Item Group E", "qty": 3, "rate": 150},
|
||||
"Stock Item F": {
|
||||
"is_stock_item": 1,
|
||||
"has_serial_no": 1,
|
||||
"serial_no_series": "SER-TT-.####",
|
||||
"item_group": "Test Item Group F",
|
||||
"qty": 2,
|
||||
"rate": 250,
|
||||
},
|
||||
"Stock Item F1": {"is_stock_item": 1, "item_group": "Test Item Group F", "qty": 4, "rate": 300},
|
||||
}
|
||||
|
||||
for row in items:
|
||||
self.make_item_group(items[row]["item_group"])
|
||||
|
||||
inventory_account_dict = frappe._dict()
|
||||
for item_name, item_data in items.items():
|
||||
item_data = frappe._dict(item_data)
|
||||
make_item(
|
||||
item_name,
|
||||
properties=item_data,
|
||||
)
|
||||
|
||||
item_group = frappe.get_doc("Item Group", item_data.item_group)
|
||||
account = self.add_inventory_account(item_group, "item_group_defaults")
|
||||
inventory_account_dict[item_data.item_group] = account
|
||||
|
||||
pr = make_purchase_receipt(
|
||||
item_code="Stock Item E",
|
||||
qty=5,
|
||||
rate=100,
|
||||
warehouse=self.default_warehouse,
|
||||
company=self.company,
|
||||
do_not_submit=True,
|
||||
)
|
||||
|
||||
for item_code, values in items.items():
|
||||
if item_code == "Stock Item E":
|
||||
continue
|
||||
|
||||
pr.append(
|
||||
"items",
|
||||
{
|
||||
"item_code": item_code,
|
||||
"qty": values.get("qty", 1),
|
||||
"rate": values.get("rate", 200),
|
||||
"warehouse": self.default_warehouse,
|
||||
},
|
||||
)
|
||||
|
||||
pr.submit()
|
||||
|
||||
dn = create_delivery_note(
|
||||
item_code="Stock Item E",
|
||||
qty=5,
|
||||
rate=200,
|
||||
warehouse=self.default_warehouse,
|
||||
company=self.company,
|
||||
cost_center=frappe.db.get_value("Company", self.company, "cost_center"),
|
||||
expense_account=frappe.db.get_value("Company", self.company, "default_expense_account"),
|
||||
do_not_submit=True,
|
||||
)
|
||||
|
||||
for item_code, values in items.items():
|
||||
if item_code == "Stock Item E":
|
||||
continue
|
||||
|
||||
dn.append(
|
||||
"items",
|
||||
{
|
||||
"item_code": item_code,
|
||||
"qty": values.get("qty", 1),
|
||||
"rate": values.get("rate", 200),
|
||||
"warehouse": self.default_warehouse,
|
||||
},
|
||||
)
|
||||
|
||||
dn.submit()
|
||||
|
||||
for item_group, account in inventory_account_dict.items():
|
||||
items = frappe.get_all(
|
||||
"Item",
|
||||
filters={"item_group": item_group},
|
||||
pluck="name",
|
||||
)
|
||||
|
||||
sle_value = frappe.get_all(
|
||||
"Stock Ledger Entry",
|
||||
filters={"voucher_type": "Delivery Note", "voucher_no": dn.name, "item_code": ("in", items)},
|
||||
fields=["sum(stock_value_difference) as value"],
|
||||
)
|
||||
|
||||
gl_value = (
|
||||
frappe.db.get_value(
|
||||
"GL Entry",
|
||||
{
|
||||
"voucher_type": "Delivery Note",
|
||||
"voucher_no": dn.name,
|
||||
"account": account,
|
||||
},
|
||||
"credit",
|
||||
)
|
||||
* -1
|
||||
)
|
||||
|
||||
self.assertEqual(sle_value[0].value, gl_value, f"GL Entry not created for {item_code} correctly")
|
||||
|
||||
def make_item_group(self, item_name):
|
||||
if not frappe.db.exists("Item Group", item_name):
|
||||
item_group = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Item Group",
|
||||
"item_group_name": item_name,
|
||||
"is_group": 0,
|
||||
}
|
||||
)
|
||||
item_group.insert()
|
||||
return item_group
|
||||
|
||||
return frappe.get_doc("Item Group", item_name)
|
||||
|
||||
def add_inventory_account(self, item, table_name=None):
|
||||
if not table_name:
|
||||
table_name = "item_defaults"
|
||||
|
||||
account = item.name + " - " + self.company_abbr
|
||||
if not frappe.db.exists("Account", account):
|
||||
account_doc = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Account",
|
||||
"account_name": item.name,
|
||||
"account_type": "Stock",
|
||||
"company": self.company,
|
||||
"is_group": 0,
|
||||
"parent_account": "Stock Assets - " + self.company_abbr,
|
||||
}
|
||||
)
|
||||
account_doc.insert()
|
||||
|
||||
if not frappe.db.get_value("Item Default", {"parent": item.name, "company": self.company}):
|
||||
item.append(
|
||||
table_name,
|
||||
{
|
||||
"company": self.company,
|
||||
"default_inventory_account": account,
|
||||
"default_warehouse": self.default_warehouse,
|
||||
},
|
||||
)
|
||||
item.save()
|
||||
|
||||
return account
|
||||
|
||||
def test_item_account_for_manufacture_entry(self):
|
||||
items = {
|
||||
"Stock Item A1": {"is_stock_item": 1},
|
||||
"Stock Item B1": {"is_stock_item": 1, "has_serial_no": 1, "serial_no_series": "SER-TT-.####"},
|
||||
}
|
||||
|
||||
for item_name, item_data in items.items():
|
||||
item = make_item(
|
||||
item_name,
|
||||
properties=item_data,
|
||||
)
|
||||
|
||||
account = self.add_inventory_account(item)
|
||||
items[item_name]["account"] = account
|
||||
|
||||
make_purchase_receipt(
|
||||
item_code="Stock Item B1",
|
||||
qty=5,
|
||||
rate=100,
|
||||
warehouse=self.default_warehouse,
|
||||
company=self.company,
|
||||
)
|
||||
|
||||
bom = make_bom(
|
||||
item="Stock Item A1",
|
||||
company=self.company,
|
||||
source_warehouse=self.default_warehouse,
|
||||
raw_materials=["Stock Item B1"],
|
||||
)
|
||||
|
||||
wip_warehouse = frappe.db.get_value(
|
||||
"Warehouse",
|
||||
{"company": self.company, "is_group": 0, "warehouse_name": ("like", "%Work In Progress%")},
|
||||
)
|
||||
|
||||
fg_warehouse = frappe.db.get_value(
|
||||
"Warehouse",
|
||||
{"company": self.company, "is_group": 0, "warehouse_name": ("like", "%Finished Goods%")},
|
||||
)
|
||||
|
||||
wo_order = make_wo_order_test_record(
|
||||
item="Stock Item A1",
|
||||
qty=5,
|
||||
company=self.company,
|
||||
source_warehouse=self.default_warehouse,
|
||||
bom=bom.name,
|
||||
wip_warehouse=wip_warehouse,
|
||||
fg_warehouse=fg_warehouse,
|
||||
)
|
||||
|
||||
stock_entry = frappe.get_doc(make_stock_entry(wo_order.name, "Material Transfer for Manufacture", 5))
|
||||
stock_entry.submit()
|
||||
|
||||
stock_entry = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 5))
|
||||
stock_entry.submit()
|
||||
|
||||
for row in stock_entry.items:
|
||||
item_code = row.item_code
|
||||
account = items[item_code]["account"]
|
||||
|
||||
sle_value = frappe.db.get_value(
|
||||
"Stock Ledger Entry",
|
||||
{"voucher_type": "Stock Entry", "voucher_no": stock_entry.name, "item_code": item_code},
|
||||
"stock_value_difference",
|
||||
)
|
||||
|
||||
field = "debit" if row.t_warehouse == fg_warehouse else "credit"
|
||||
gl_value = frappe.db.get_value(
|
||||
"GL Entry",
|
||||
{
|
||||
"voucher_type": "Stock Entry",
|
||||
"voucher_no": stock_entry.name,
|
||||
"account": account,
|
||||
},
|
||||
field,
|
||||
)
|
||||
|
||||
if row.s_warehouse:
|
||||
gl_value = gl_value * -1
|
||||
|
||||
self.assertEqual(sle_value, gl_value, f"GL Entry not created for {item_code} correctly")
|
||||
|
||||
|
||||
def make_company():
|
||||
company = "_Test Company for Item Wise Inventory Account"
|
||||
if frappe.db.exists("Company", company):
|
||||
return company
|
||||
|
||||
company = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Company",
|
||||
"company_name": "_Test Company for Item Wise Inventory Account",
|
||||
"abbr": "_TCIWIA",
|
||||
"default_currency": "INR",
|
||||
"country": "India",
|
||||
"enable_perpetual_inventory": 1,
|
||||
"enable_item_wise_inventory_account": 1,
|
||||
}
|
||||
).insert()
|
||||
|
||||
return company.name
|
||||
Reference in New Issue
Block a user