Merge pull request #31943 from nabinhait/asset-repair
fix: gl entries for asset repair
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 986b700..132840e 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -1454,12 +1454,14 @@
return item
-def set_depreciation_settings_in_company():
- company = frappe.get_doc("Company", "_Test Company")
- company.accumulated_depreciation_account = "_Test Accumulated Depreciations - _TC"
- company.depreciation_expense_account = "_Test Depreciations - _TC"
- company.disposal_account = "_Test Gain/Loss on Asset Disposal - _TC"
- company.depreciation_cost_center = "_Test Cost Center - _TC"
+def set_depreciation_settings_in_company(company=None):
+ if not company:
+ company = "_Test Company"
+ company = frappe.get_doc("Company", company)
+ company.accumulated_depreciation_account = "_Test Accumulated Depreciations - " + company.abbr
+ company.depreciation_expense_account = "_Test Depreciations - " + company.abbr
+ company.disposal_account = "_Test Gain/Loss on Asset Disposal - " + company.abbr
+ company.depreciation_cost_center = "Main - " + company.abbr
company.save()
# Enable booking asset depreciation entry automatically
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.js b/erpnext/assets/doctype/asset_repair/asset_repair.js
index f5e4e72..f9ed2cc 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.js
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.js
@@ -76,7 +76,7 @@
'warehouse': frm.doc.warehouse,
'qty': item.consumed_quantity,
'serial_no': item.serial_no,
- 'company': frm.doc.company
+ 'company': frm.doc.company,
};
frappe.call({
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index ba31898..accb5bf 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -238,7 +238,6 @@
"no_copy": 1
},
{
- "depends_on": "eval:!doc.__islocal",
"fieldname": "purchase_invoice",
"fieldtype": "Link",
"label": "Purchase Invoice",
@@ -257,6 +256,7 @@
"fieldname": "stock_entry",
"fieldtype": "Link",
"label": "Stock Entry",
+ "no_copy": 1,
"options": "Stock Entry",
"read_only": 1
}
@@ -264,10 +264,11 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-25 13:14:38.307723",
+ "modified": "2022-08-16 15:55:25.023471",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
+ "naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{
@@ -303,6 +304,7 @@
],
"sort_field": "modified",
"sort_order": "DESC",
+ "states": [],
"title_field": "asset_name",
"track_changes": 1,
"track_seen": 1
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 5bf6011..8758e9c 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -1,11 +1,11 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-
import frappe
from frappe import _
from frappe.utils import add_months, cint, flt, getdate, time_diff_in_hours
+import erpnext
from erpnext.accounts.general_ledger import make_gl_entries
from erpnext.assets.doctype.asset.asset import get_asset_account
from erpnext.controllers.accounts_controller import AccountsController
@@ -17,7 +17,7 @@
self.update_status()
if self.get("stock_items"):
- self.set_total_value()
+ self.set_stock_items_cost()
self.calculate_total_repair_cost()
def update_status(self):
@@ -26,7 +26,7 @@
else:
self.asset_doc.set_status()
- def set_total_value(self):
+ def set_stock_items_cost(self):
for item in self.get("stock_items"):
item.total_value = flt(item.valuation_rate) * flt(item.consumed_quantity)
@@ -66,6 +66,7 @@
if self.get("capitalize_repair_cost"):
self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry")
self.make_gl_entries(cancel=True)
+ self.db_set("stock_entry", None)
if (
frappe.db.get_value("Asset", self.asset, "calculate_depreciation")
and self.increase_in_asset_life
@@ -133,6 +134,7 @@
"qty": stock_item.consumed_quantity,
"basic_rate": stock_item.valuation_rate,
"serial_no": stock_item.serial_no,
+ "cost_center": self.cost_center,
},
)
@@ -142,72 +144,42 @@
self.db_set("stock_entry", stock_entry.name)
def increase_stock_quantity(self):
- stock_entry = frappe.get_doc("Stock Entry", self.stock_entry)
- stock_entry.flags.ignore_links = True
- stock_entry.cancel()
+ if self.stock_entry:
+ stock_entry = frappe.get_doc("Stock Entry", self.stock_entry)
+ stock_entry.flags.ignore_links = True
+ stock_entry.cancel()
def make_gl_entries(self, cancel=False):
- if flt(self.repair_cost) > 0:
+ if flt(self.total_repair_cost) > 0:
gl_entries = self.get_gl_entries()
make_gl_entries(gl_entries, cancel)
def get_gl_entries(self):
gl_entries = []
- repair_and_maintenance_account = frappe.db.get_value(
- "Company", self.company, "repair_and_maintenance_account"
- )
+
fixed_asset_account = get_asset_account(
"fixed_asset_account", asset=self.asset, company=self.company
)
- expense_account = (
+ self.get_gl_entries_for_repair_cost(gl_entries, fixed_asset_account)
+ self.get_gl_entries_for_consumed_items(gl_entries, fixed_asset_account)
+
+ return gl_entries
+
+ def get_gl_entries_for_repair_cost(self, gl_entries, fixed_asset_account):
+ if flt(self.repair_cost) <= 0:
+ return
+
+ pi_expense_account = (
frappe.get_doc("Purchase Invoice", self.purchase_invoice).items[0].expense_account
)
gl_entries.append(
self.get_gl_dict(
{
- "account": expense_account,
- "credit": self.repair_cost,
- "credit_in_account_currency": self.repair_cost,
- "against": repair_and_maintenance_account,
- "voucher_type": self.doctype,
- "voucher_no": self.name,
- "cost_center": self.cost_center,
- "posting_date": getdate(),
- "company": self.company,
- },
- item=self,
- )
- )
-
- if self.get("stock_consumption"):
- # creating GL Entries for each row in Stock Items based on the Stock Entry created for it
- stock_entry = frappe.get_doc("Stock Entry", self.stock_entry)
- for item in stock_entry.items:
- gl_entries.append(
- self.get_gl_dict(
- {
- "account": item.expense_account,
- "credit": item.amount,
- "credit_in_account_currency": item.amount,
- "against": repair_and_maintenance_account,
- "voucher_type": self.doctype,
- "voucher_no": self.name,
- "cost_center": self.cost_center,
- "posting_date": getdate(),
- "company": self.company,
- },
- item=self,
- )
- )
-
- gl_entries.append(
- self.get_gl_dict(
- {
"account": fixed_asset_account,
- "debit": self.total_repair_cost,
- "debit_in_account_currency": self.total_repair_cost,
- "against": expense_account,
+ "debit": self.repair_cost,
+ "debit_in_account_currency": self.repair_cost,
+ "against": pi_expense_account,
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
@@ -220,7 +192,75 @@
)
)
- return gl_entries
+ gl_entries.append(
+ self.get_gl_dict(
+ {
+ "account": pi_expense_account,
+ "credit": self.repair_cost,
+ "credit_in_account_currency": self.repair_cost,
+ "against": fixed_asset_account,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "cost_center": self.cost_center,
+ "posting_date": getdate(),
+ "company": self.company,
+ },
+ item=self,
+ )
+ )
+
+ def get_gl_entries_for_consumed_items(self, gl_entries, fixed_asset_account):
+ if not (self.get("stock_consumption") and self.get("stock_items")):
+ return
+
+ # creating GL Entries for each row in Stock Items based on the Stock Entry created for it
+ stock_entry = frappe.get_doc("Stock Entry", self.stock_entry)
+
+ default_expense_account = None
+ if not erpnext.is_perpetual_inventory_enabled(self.company):
+ default_expense_account = frappe.get_cached_value(
+ "Company", self.company, "default_expense_account"
+ )
+ if not default_expense_account:
+ frappe.throw(_("Please set default Expense Account in Company {0}").format(self.company))
+
+ for item in stock_entry.items:
+ if flt(item.amount) > 0:
+ gl_entries.append(
+ self.get_gl_dict(
+ {
+ "account": item.expense_account or default_expense_account,
+ "credit": item.amount,
+ "credit_in_account_currency": item.amount,
+ "against": fixed_asset_account,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "cost_center": self.cost_center,
+ "posting_date": getdate(),
+ "company": self.company,
+ },
+ item=self,
+ )
+ )
+
+ gl_entries.append(
+ self.get_gl_dict(
+ {
+ "account": fixed_asset_account,
+ "debit": item.amount,
+ "debit_in_account_currency": item.amount,
+ "against": item.expense_account or default_expense_account,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "cost_center": self.cost_center,
+ "posting_date": getdate(),
+ "against_voucher_type": "Stock Entry",
+ "against_voucher": self.stock_entry,
+ "company": self.company,
+ },
+ item=self,
+ )
+ )
def modify_depreciation_schedule(self):
for row in self.asset_doc.finance_books:
diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
index 4e7cf78..6e06f52 100644
--- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
@@ -6,6 +6,7 @@
import frappe
from frappe.utils import flt, nowdate
+from erpnext.assets.doctype.asset.asset import get_asset_account
from erpnext.assets.doctype.asset.test_asset import (
create_asset,
create_asset_data,
@@ -125,10 +126,109 @@
asset_repair = create_asset_repair(capitalize_repair_cost=1, submit=1)
self.assertTrue(asset_repair.purchase_invoice)
- def test_gl_entries(self):
- asset_repair = create_asset_repair(capitalize_repair_cost=1, submit=1)
- gl_entry = frappe.get_last_doc("GL Entry")
- self.assertEqual(asset_repair.name, gl_entry.voucher_no)
+ def test_gl_entries_with_perpetual_inventory(self):
+ set_depreciation_settings_in_company(company="_Test Company with perpetual inventory")
+
+ asset_category = frappe.get_doc("Asset Category", "Computers")
+ asset_category.append(
+ "accounts",
+ {
+ "company_name": "_Test Company with perpetual inventory",
+ "fixed_asset_account": "_Test Fixed Asset - TCP1",
+ "accumulated_depreciation_account": "_Test Accumulated Depreciations - TCP1",
+ "depreciation_expense_account": "_Test Depreciations - TCP1",
+ },
+ )
+ asset_category.save()
+
+ asset_repair = create_asset_repair(
+ capitalize_repair_cost=1,
+ stock_consumption=1,
+ warehouse="Stores - TCP1",
+ company="_Test Company with perpetual inventory",
+ submit=1,
+ )
+
+ gl_entries = frappe.db.sql(
+ """
+ select
+ account,
+ sum(debit) as debit,
+ sum(credit) as credit
+ from `tabGL Entry`
+ where
+ voucher_type='Asset Repair'
+ and voucher_no=%s
+ group by
+ account
+ """,
+ asset_repair.name,
+ as_dict=1,
+ )
+
+ self.assertTrue(gl_entries)
+
+ fixed_asset_account = get_asset_account(
+ "fixed_asset_account", asset=asset_repair.asset, company=asset_repair.company
+ )
+ pi_expense_account = (
+ frappe.get_doc("Purchase Invoice", asset_repair.purchase_invoice).items[0].expense_account
+ )
+ stock_entry_expense_account = (
+ frappe.get_doc("Stock Entry", asset_repair.stock_entry).get("items")[0].expense_account
+ )
+
+ expected_values = {
+ fixed_asset_account: [asset_repair.total_repair_cost, 0],
+ pi_expense_account: [0, asset_repair.repair_cost],
+ stock_entry_expense_account: [0, 100],
+ }
+
+ for d in gl_entries:
+ self.assertEqual(expected_values[d.account][0], d.debit)
+ self.assertEqual(expected_values[d.account][1], d.credit)
+
+ def test_gl_entries_with_periodical_inventory(self):
+ frappe.db.set_value(
+ "Company", "_Test Company", "default_expense_account", "Cost of Goods Sold - _TC"
+ )
+ asset_repair = create_asset_repair(
+ capitalize_repair_cost=1,
+ stock_consumption=1,
+ submit=1,
+ )
+
+ gl_entries = frappe.db.sql(
+ """
+ select
+ account,
+ sum(debit) as debit,
+ sum(credit) as credit
+ from `tabGL Entry`
+ where
+ voucher_type='Asset Repair'
+ and voucher_no=%s
+ group by
+ account
+ """,
+ asset_repair.name,
+ as_dict=1,
+ )
+
+ self.assertTrue(gl_entries)
+
+ fixed_asset_account = get_asset_account(
+ "fixed_asset_account", asset=asset_repair.asset, company=asset_repair.company
+ )
+ default_expense_account = frappe.get_cached_value(
+ "Company", asset_repair.company, "default_expense_account"
+ )
+
+ expected_values = {fixed_asset_account: [1100, 0], default_expense_account: [0, 1100]}
+
+ for d in gl_entries:
+ self.assertEqual(expected_values[d.account][0], d.debit)
+ self.assertEqual(expected_values[d.account][1], d.credit)
def test_increase_in_asset_life(self):
asset = create_asset(calculate_depreciation=1, submit=1)
@@ -160,7 +260,7 @@
if args.asset:
asset = args.asset
else:
- asset = create_asset(is_existing_asset=1, submit=1)
+ asset = create_asset(is_existing_asset=1, submit=1, company=args.company)
asset_repair = frappe.new_doc("Asset Repair")
asset_repair.update(
{
@@ -192,7 +292,7 @@
if args.submit:
asset_repair.repair_status = "Completed"
- asset_repair.cost_center = "_Test Cost Center - _TC"
+ asset_repair.cost_center = frappe.db.get_value("Company", asset.company, "cost_center")
if args.stock_consumption:
stock_entry = frappe.get_doc(
@@ -204,6 +304,8 @@
"t_warehouse": asset_repair.warehouse,
"item_code": asset_repair.stock_items[0].item_code,
"qty": asset_repair.stock_items[0].consumed_quantity,
+ "basic_rate": args.rate if args.get("rate") is not None else 100,
+ "cost_center": asset_repair.cost_center,
},
)
stock_entry.submit()
@@ -213,7 +315,13 @@
asset_repair.repair_cost = 1000
if asset.calculate_depreciation:
asset_repair.increase_in_asset_life = 12
- asset_repair.purchase_invoice = make_purchase_invoice().name
+ pi = make_purchase_invoice(
+ company=asset.company,
+ expense_account=frappe.db.get_value("Company", asset.company, "default_expense_account"),
+ cost_center=asset_repair.cost_center,
+ warehouse=asset_repair.warehouse,
+ )
+ asset_repair.purchase_invoice = pi.name
asset_repair.submit()
return asset_repair
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index f34ec56..f087d99 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -85,7 +85,6 @@
"depreciation_expense_account",
"series_for_depreciation_entry",
"expenses_included_in_asset_valuation",
- "repair_and_maintenance_account",
"column_break_40",
"disposal_account",
"depreciation_cost_center",
@@ -234,7 +233,6 @@
"label": "Default Warehouse for Sales Return",
"options": "Warehouse"
},
-
{
"fieldname": "country",
"fieldtype": "Link",
@@ -679,12 +677,6 @@
"label": "Fixed Asset Defaults"
},
{
- "fieldname": "repair_and_maintenance_account",
- "fieldtype": "Link",
- "label": "Repair and Maintenance Account",
- "options": "Account"
- },
- {
"fieldname": "section_break_28",
"fieldtype": "Section Break",
"label": "Chart of Accounts"
@@ -709,7 +701,7 @@
"image_field": "company_logo",
"is_tree": 1,
"links": [],
- "modified": "2022-06-30 18:03:18.701314",
+ "modified": "2022-08-16 16:09:02.327724",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",