feat: Asset Capitalization
- manual selection of entry type
- GLE cleanup with smaller functions
- GLE considering periodical inventory
- test cases
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 132840e..e7af9bd 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -1425,6 +1425,16 @@
"depreciation_expense_account": "_Test Depreciations - _TC",
},
)
+ 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.insert()
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js
index d135e60..9c7f70b 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js
@@ -27,7 +27,11 @@
me.setup_warehouse_query();
me.frm.set_query("target_item_code", function() {
- return erpnext.queries.item();
+ if (me.frm.doc.entry_type == "Capitalization") {
+ return erpnext.queries.item({"is_stock_item": 0, "is_fixed_asset": 1});
+ } else {
+ return erpnext.queries.item({"is_stock_item": 1, "is_fixed_asset": 0});
+ }
});
me.frm.set_query("target_asset", function() {
@@ -410,5 +414,4 @@
}
};
-//$.extend(cur_frm.cscript, new erpnext.assets.AssetCapitalization({frm: cur_frm}));
cur_frm.cscript = new erpnext.assets.AssetCapitalization({frm: cur_frm});
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json
index d7e6b54..d1be575 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json
@@ -8,29 +8,28 @@
"engine": "InnoDB",
"field_order": [
"title",
+ "naming_series",
+ "entry_type",
"target_item_code",
"target_item_name",
"target_is_fixed_asset",
"target_has_batch_no",
"target_has_serial_no",
- "entry_type",
- "finance_book",
- "naming_series",
"column_break_9",
+ "target_asset",
+ "target_asset_name",
+ "target_warehouse",
+ "target_qty",
+ "target_stock_uom",
+ "target_batch_no",
+ "target_serial_no",
+ "column_break_5",
"company",
+ "finance_book",
"posting_date",
"posting_time",
"set_posting_time",
"amended_from",
- "target_item_details_section",
- "target_asset",
- "target_asset_name",
- "target_warehouse",
- "target_batch_no",
- "target_serial_no",
- "column_break_5",
- "target_qty",
- "target_stock_uom",
"section_break_16",
"stock_items",
"stock_items_total",
@@ -86,16 +85,17 @@
"fieldtype": "Column Break"
},
{
- "depends_on": "eval:!doc.target_item_code || doc.target_is_fixed_asset",
+ "depends_on": "eval:doc.entry_type=='Capitalization'",
"fieldname": "target_asset",
"fieldtype": "Link",
"in_standard_filter": 1,
"label": "Target Asset",
+ "mandatory_depends_on": "eval:doc.entry_type=='Capitalization'",
"no_copy": 1,
"options": "Asset"
},
{
- "depends_on": "target_asset",
+ "depends_on": "eval:doc.entry_type=='Capitalization'",
"fetch_from": "target_asset.asset_name",
"fieldname": "target_asset_name",
"fieldtype": "Data",
@@ -170,15 +170,11 @@
"options": "Asset Capitalization Stock Item"
},
{
- "fieldname": "target_item_details_section",
- "fieldtype": "Section Break",
- "label": "Target Item Details"
- },
- {
- "depends_on": "eval:!doc.target_is_fixed_asset",
+ "depends_on": "eval:doc.entry_type=='Decapitalization'",
"fieldname": "target_warehouse",
"fieldtype": "Link",
"label": "Target Warehouse",
+ "mandatory_depends_on": "eval:doc.entry_type=='Decapitalization'",
"options": "Warehouse"
},
{
@@ -240,13 +236,14 @@
"options": "Asset Capitalization Asset Item"
},
{
+ "default": "Capitalization",
"fieldname": "entry_type",
"fieldtype": "Select",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Entry Type",
- "options": "\nCapitalization\nDecapitalization",
- "read_only": 1
+ "options": "Capitalization\nDecapitalization",
+ "reqd": 1
},
{
"fieldname": "stock_items_total",
@@ -337,7 +334,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-09-15 15:41:27.917458",
+ "modified": "2022-09-12 15:09:40.771332",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Capitalization",
@@ -377,6 +374,7 @@
],
"sort_field": "modified",
"sort_order": "DESC",
+ "states": [],
"title_field": "title",
"track_changes": 1,
"track_seen": 1
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
index a8f2d79..2e6f0ad 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
@@ -10,9 +10,9 @@
from frappe.utils import cint, flt
from six import string_types
+import erpnext
from erpnext.assets.doctype.asset.depreciation import (
get_gl_entries_on_asset_disposal,
- get_gl_entries_on_asset_regain,
get_value_after_depreciation_on_disposal_date,
)
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
@@ -32,16 +32,26 @@
from erpnext.stock.stock_ledger import get_previous_sle
from erpnext.stock.utils import get_incoming_rate
-force_fields = ['target_item_name', 'target_asset_name', 'item_name', 'asset_name',
- 'target_is_fixed_asset', 'target_has_serial_no', 'target_has_batch_no',
- 'target_stock_uom', 'stock_uom', 'target_fixed_asset_account', 'fixed_asset_account']
+force_fields = [
+ "target_item_name",
+ "target_asset_name",
+ "item_name",
+ "asset_name",
+ "target_is_fixed_asset",
+ "target_has_serial_no",
+ "target_has_batch_no",
+ "target_stock_uom",
+ "stock_uom",
+ "target_fixed_asset_account",
+ "fixed_asset_account",
+ "valuation_rate",
+]
class AssetCapitalization(StockController):
def validate(self):
self.validate_posting_time()
self.set_missing_values(for_validate=True)
- self.set_entry_type()
self.validate_target_item()
self.validate_target_asset()
self.validate_consumed_stock_item()
@@ -58,14 +68,13 @@
def on_submit(self):
self.update_stock_ledger()
self.make_gl_entries()
+ self.update_target_asset()
def on_cancel(self):
- self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry', 'Repost Item Valuation')
+ self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Repost Item Valuation")
self.update_stock_ledger()
self.make_gl_entries()
-
- def set_entry_type(self):
- self.entry_type = "Capitalization" if self.target_is_fixed_asset else "Decapitalization"
+ self.update_target_asset()
def set_title(self):
self.title = self.target_asset_name or self.target_item_name or self.target_item_code
@@ -90,7 +99,7 @@
args.update(d.as_dict())
args.doctype = self.doctype
args.name = self.name
- consumed_stock_item_details = get_consumed_stock_item_details(args, get_valuation_rate=False)
+ consumed_stock_item_details = get_consumed_stock_item_details(args)
for k, v in consumed_stock_item_details.items():
if d.meta.has_field(k) and (not d.get(k) or k in force_fields):
d.set(k, v)
@@ -100,8 +109,8 @@
args.update(d.as_dict())
args.doctype = self.doctype
args.name = self.name
- args.finance_book = d.get('finance_book') or self.get('finance_book')
- consumed_asset_details = get_consumed_asset_details(args, get_asset_value=False)
+ args.finance_book = d.get("finance_book") or self.get("finance_book")
+ consumed_asset_details = get_consumed_asset_details(args)
for k, v in consumed_asset_details.items():
if d.meta.has_field(k) and (not d.get(k) or k in force_fields):
d.set(k, v)
@@ -120,8 +129,14 @@
target_item = frappe.get_cached_doc("Item", self.target_item_code)
if not target_item.is_fixed_asset and not target_item.is_stock_item:
- frappe.throw(_("Target Item {0} is neither a Fixed Asset nor a Stock Item")
- .format(target_item.name))
+ frappe.throw(
+ _("Target Item {0} is neither a Fixed Asset nor a Stock Item").format(target_item.name)
+ )
+
+ if self.entry_type == "Capitalization" and not target_item.is_fixed_asset:
+ frappe.throw(_("Target Item {0} must be a Fixed Asset item").format(target_item.name))
+ elif self.entry_type == "Decapitalization" and not target_item.is_stock_item:
+ frappe.throw(_("Target Item {0} must be a Stock Item").format(target_item.name))
if target_item.is_fixed_asset:
self.target_qty = 1
@@ -144,14 +159,13 @@
self.validate_item(target_item)
def validate_target_asset(self):
- if self.target_is_fixed_asset and not self.target_asset:
- frappe.throw(_("Target Asset is mandatory for Capitalization"))
-
if self.target_asset:
target_asset = self.get_asset_for_validation(self.target_asset)
if target_asset.item_code != self.target_item_code:
- frappe.throw(_("Asset {0} does not belong to Item {1}").format(self.target_asset, self.target_item_code))
+ frappe.throw(
+ _("Asset {0} does not belong to Item {1}").format(self.target_asset, self.target_item_code)
+ )
self.validate_asset(target_asset)
@@ -172,8 +186,11 @@
for d in self.asset_items:
if d.asset:
if d.asset == self.target_asset:
- frappe.throw(_("Row #{0}: Consumed Asset {1} cannot be the same as the Target Asset")
- .format(d.idx, d.asset))
+ frappe.throw(
+ _("Row #{0}: Consumed Asset {1} cannot be the same as the Target Asset").format(
+ d.idx, d.asset
+ )
+ )
asset = self.get_asset_for_validation(d.asset)
self.validate_asset(asset)
@@ -198,18 +215,21 @@
d.cost_center = frappe.get_cached_value("Company", self.company, "cost_center")
def validate_source_mandatory(self):
- if not self.target_is_fixed_asset and not self.get('asset_items'):
+ if not self.target_is_fixed_asset and not self.get("asset_items"):
frappe.throw(_("Consumed Asset Items is mandatory for Decapitalization"))
- if not self.get('stock_items') and not self.get('asset_items'):
+ if not self.get("stock_items") and not self.get("asset_items"):
frappe.throw(_("Consumed Stock Items or Consumed Asset Items is mandatory for Capitalization"))
def validate_item(self, item):
from erpnext.stock.doctype.item.item import validate_end_of_life
+
validate_end_of_life(item.name, item.end_of_life, item.disabled)
def get_asset_for_validation(self, asset):
- return frappe.db.get_value("Asset", asset, ["name", "item_code", "company", "status", "docstatus"], as_dict=1)
+ return frappe.db.get_value(
+ "Asset", asset, ["name", "item_code", "company", "status", "docstatus"], as_dict=1
+ )
def validate_asset(self, asset):
if asset.status in ("Draft", "Scrapped", "Sold", "Capitalized", "Decapitalized"):
@@ -225,7 +245,7 @@
@frappe.whitelist()
def set_warehouse_details(self):
- for d in self.get('stock_items'):
+ for d in self.get("stock_items"):
if d.item_code and d.warehouse:
args = self.get_args_for_incoming_rate(d)
warehouse_details = get_warehouse_details(args)
@@ -233,27 +253,30 @@
@frappe.whitelist()
def set_asset_values(self):
- for d in self.get('asset_items'):
+ for d in self.get("asset_items"):
if d.asset:
- finance_book = d.get('finance_book') or self.get('finance_book')
+ finance_book = d.get("finance_book") or self.get("finance_book")
d.current_asset_value = flt(get_current_asset_value(d.asset, finance_book=finance_book))
- d.asset_value = get_value_after_depreciation_on_disposal_date(d.asset, self.posting_date,
- finance_book=finance_book)
+ d.asset_value = get_value_after_depreciation_on_disposal_date(
+ d.asset, self.posting_date, finance_book=finance_book
+ )
def get_args_for_incoming_rate(self, item):
- return frappe._dict({
- "item_code": item.item_code,
- "warehouse": item.warehouse,
- "posting_date": self.posting_date,
- "posting_time": self.posting_time,
- "qty": -1 * flt(item.stock_qty),
- "serial_no": item.serial_no,
- "batch_no": item.batch_no,
- "voucher_type": self.doctype,
- "voucher_no": self.name,
- "company": self.company,
- "allow_zero_valuation": cint(item.get('allow_zero_valuation_rate')),
- })
+ return frappe._dict(
+ {
+ "item_code": item.item_code,
+ "warehouse": item.warehouse,
+ "posting_date": self.posting_date,
+ "posting_time": self.posting_time,
+ "qty": -1 * flt(item.stock_qty),
+ "serial_no": item.serial_no,
+ "batch_no": item.batch_no,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "company": self.company,
+ "allow_zero_valuation": cint(item.get("allow_zero_valuation_rate")),
+ }
+ )
def calculate_totals(self):
self.stock_items_total = 0
@@ -261,45 +284,51 @@
self.service_items_total = 0
for d in self.stock_items:
- d.amount = flt(flt(d.stock_qty) * flt(d.valuation_rate), d.precision('amount'))
+ d.amount = flt(flt(d.stock_qty) * flt(d.valuation_rate), d.precision("amount"))
self.stock_items_total += d.amount
for d in self.asset_items:
- d.asset_value = flt(flt(d.asset_value), d.precision('asset_value'))
+ d.asset_value = flt(flt(d.asset_value), d.precision("asset_value"))
self.asset_items_total += d.asset_value
for d in self.service_items:
- d.amount = flt(flt(d.qty) * flt(d.rate), d.precision('amount'))
+ d.amount = flt(flt(d.qty) * flt(d.rate), d.precision("amount"))
self.service_items_total += d.amount
- self.stock_items_total = flt(self.stock_items_total, self.precision('stock_items_total'))
- self.asset_items_total = flt(self.asset_items_total, self.precision('asset_items_total'))
- self.service_items_total = flt(self.service_items_total, self.precision('service_items_total'))
+ self.stock_items_total = flt(self.stock_items_total, self.precision("stock_items_total"))
+ self.asset_items_total = flt(self.asset_items_total, self.precision("asset_items_total"))
+ self.service_items_total = flt(self.service_items_total, self.precision("service_items_total"))
self.total_value = self.stock_items_total + self.asset_items_total + self.service_items_total
- self.total_value = flt(self.total_value, self.precision('total_value'))
+ self.total_value = flt(self.total_value, self.precision("total_value"))
- self.target_qty = flt(self.target_qty, self.precision('target_qty'))
+ self.target_qty = flt(self.target_qty, self.precision("target_qty"))
self.target_incoming_rate = self.total_value / self.target_qty
def update_stock_ledger(self):
sl_entries = []
for d in self.stock_items:
- sle = self.get_sl_entries(d, {
- "actual_qty": -flt(d.stock_qty),
- })
+ sle = self.get_sl_entries(
+ d,
+ {
+ "actual_qty": -flt(d.stock_qty),
+ },
+ )
sl_entries.append(sle)
- if not frappe.db.get_value("Item", self.target_item_code, "is_fixed_asset", cache=1):
- sle = self.get_sl_entries(self, {
- "item_code": self.target_item_code,
- "warehouse": self.target_warehouse,
- "batch_no": self.target_batch_no,
- "serial_no": self.target_serial_no,
- "actual_qty": flt(self.target_qty),
- "incoming_rate": flt(self.target_incoming_rate)
- })
+ if self.entry_type == "Decapitalization" and not self.target_is_fixed_asset:
+ sle = self.get_sl_entries(
+ self,
+ {
+ "item_code": self.target_item_code,
+ "warehouse": self.target_warehouse,
+ "batch_no": self.target_batch_no,
+ "serial_no": self.target_serial_no,
+ "actual_qty": flt(self.target_qty),
+ "incoming_rate": flt(self.target_incoming_rate),
+ },
+ )
sl_entries.append(sle)
# reverse sl entries if cancel
@@ -312,139 +341,183 @@
def make_gl_entries(self, gl_entries=None, from_repost=False):
from erpnext.accounts.general_ledger import make_gl_entries, make_reverse_gl_entries
- if not gl_entries:
- gl_entries = self.get_gl_entries()
-
if self.docstatus == 1:
+ if not gl_entries:
+ gl_entries = self.get_gl_entries()
+
if gl_entries:
make_gl_entries(gl_entries, from_repost=from_repost)
elif self.docstatus == 2:
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
- def get_gl_entries(self, warehouse_account=None, default_expense_account=None, default_cost_center=None):
+ def get_gl_entries(
+ self, warehouse_account=None, default_expense_account=None, default_cost_center=None
+ ):
# Stock GL Entries
gl_entries = []
- if not warehouse_account:
- warehouse_account = get_warehouse_account_map(self.company)
+ self.warehouse_account = warehouse_account
+ if not self.warehouse_account:
+ self.warehouse_account = get_warehouse_account_map(self.company)
precision = self.get_debit_field_precision()
- sle_map = self.get_stock_ledger_details()
+ self.sle_map = self.get_stock_ledger_details()
- if self.target_is_fixed_asset:
- target_account = self.target_fixed_asset_account
- else:
- target_account = warehouse_account[self.target_warehouse]["account"]
-
+ target_account = self.get_target_account()
target_against = set()
+ self.get_gl_entries_for_consumed_stock_items(
+ gl_entries, target_account, target_against, precision
+ )
+ self.get_gl_entries_for_consumed_asset_items(
+ gl_entries, target_account, target_against, precision
+ )
+ self.get_gl_entries_for_consumed_service_items(
+ gl_entries, target_account, target_against, precision
+ )
+
+ self.get_gl_entries_for_target_item(gl_entries, target_against, precision)
+ return gl_entries
+
+ def get_target_account(self):
+ if self.target_is_fixed_asset:
+ return self.target_fixed_asset_account
+ else:
+ return self.warehouse_account[self.target_warehouse]["account"]
+
+ def get_gl_entries_for_consumed_stock_items(
+ self, gl_entries, target_account, target_against, precision
+ ):
# Consumed Stock Items
- total_consumed_stock_value = 0
for item_row in self.stock_items:
- sle_list = sle_map.get(item_row.name)
+ sle_list = self.sle_map.get(item_row.name)
if sle_list:
for sle in sle_list:
stock_value_difference = flt(sle.stock_value_difference, precision)
- total_consumed_stock_value += -1 * sle.stock_value_difference
- account = warehouse_account[sle.warehouse]["account"]
+ if erpnext.is_perpetual_inventory_enabled(self.company):
+ account = self.warehouse_account[sle.warehouse]["account"]
+ else:
+ account = self.get_company_default("default_expense_account")
+
target_against.add(account)
+ gl_entries.append(
+ self.get_gl_dict(
+ {
+ "account": account,
+ "against": target_account,
+ "cost_center": item_row.cost_center,
+ "project": item_row.get("project") or self.get("project"),
+ "remarks": self.get("remarks") or "Accounting Entry for Stock",
+ "credit": -1 * stock_value_difference,
+ },
+ self.warehouse_account[sle.warehouse]["account_currency"],
+ item=item_row,
+ )
+ )
- gl_entries.append(self.get_gl_dict({
- "account": account,
- "against": target_account,
- "cost_center": item_row.cost_center,
- "project": item_row.get('project') or self.get('project'),
- "remarks": self.get("remarks") or "Accounting Entry for Stock",
- "credit": -1 * stock_value_difference,
- }, warehouse_account[sle.warehouse]["account_currency"], item=item_row))
-
+ def get_gl_entries_for_consumed_asset_items(
+ self, gl_entries, target_account, target_against, precision
+ ):
# Consumed Assets
for item in self.asset_items:
asset = self.get_asset(item)
- if self.docstatus == 2:
- fixed_asset_gl_entries = get_gl_entries_on_asset_regain(asset,
- item.asset_value, item.get('finance_book') or self.get('finance_book'))
- asset.db_set("disposal_date", None)
+ if asset.calculate_depreciation:
+ self.depreciate_asset(asset)
+ asset.reload()
+ fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(
+ asset, item.asset_value, item.get("finance_book") or self.get("finance_book")
+ )
+
+ asset.db_set("disposal_date", self.posting_date)
+
+ self.set_consumed_asset_status(asset)
+
+ for gle in fixed_asset_gl_entries:
+ gle["against"] = target_account
+ gl_entries.append(self.get_gl_dict(gle, item=item))
+ target_against.add(gle["account"])
+
+ def get_gl_entries_for_consumed_service_items(
+ self, gl_entries, target_account, target_against, precision
+ ):
+ # Service Expenses
+ for item_row in self.service_items:
+ expense_amount = flt(item_row.amount, precision)
+ target_against.add(item_row.expense_account)
+
+ gl_entries.append(
+ self.get_gl_dict(
+ {
+ "account": item_row.expense_account,
+ "against": target_account,
+ "cost_center": item_row.cost_center,
+ "project": item_row.get("project") or self.get("project"),
+ "remarks": self.get("remarks") or "Accounting Entry for Stock",
+ "credit": expense_amount,
+ },
+ item=item_row,
+ )
+ )
+
+ def get_gl_entries_for_target_item(self, gl_entries, target_against, precision):
+ if self.target_is_fixed_asset:
+ # Capitalization
+ gl_entries.append(
+ self.get_gl_dict(
+ {
+ "account": self.target_fixed_asset_account,
+ "against": ", ".join(target_against),
+ "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
+ "debit": flt(self.total_value, precision),
+ "cost_center": self.get("cost_center"),
+ },
+ item=self,
+ )
+ )
+ else:
+ # Target Stock Item
+ sle_list = self.sle_map.get(self.name)
+ for sle in sle_list:
+ stock_value_difference = flt(sle.stock_value_difference, precision)
+ account = self.warehouse_account[sle.warehouse]["account"]
+
+ gl_entries.append(
+ self.get_gl_dict(
+ {
+ "account": account,
+ "against": ", ".join(target_against),
+ "cost_center": self.cost_center,
+ "project": self.get("project"),
+ "remarks": self.get("remarks") or "Accounting Entry for Stock",
+ "debit": stock_value_difference,
+ },
+ self.warehouse_account[sle.warehouse]["account_currency"],
+ item=self,
+ )
+ )
+
+ def update_target_asset(self):
+ total_target_asset_value = flt(self.total_value, self.precision("total_value"))
+ if self.docstatus == 1 and self.entry_type == "Capitalization":
+ asset_doc = frappe.get_doc("Asset", self.target_asset)
+ asset_doc.purchase_date = self.posting_date
+ asset_doc.gross_purchase_amount = total_target_asset_value
+ asset_doc.purchase_receipt_amount = total_target_asset_value
+ asset_doc.prepare_depreciation_data()
+ asset_doc.flags.ignore_validate_update_after_submit = True
+ asset_doc.save()
+ elif self.docstatus == 2:
+ for item in self.asset_items:
+ asset = self.get_asset(item)
+ asset.db_set("disposal_date", None)
self.set_consumed_asset_status(asset)
if asset.calculate_depreciation:
self.reverse_depreciation_entry_made_after_disposal(asset)
self.reset_depreciation_schedule(asset)
- else:
- if asset.calculate_depreciation:
- self.depreciate_asset(asset)
- asset.reload()
-
- fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(asset,
- item.asset_value, item.get('finance_book') or self.get('finance_book'))
- asset.db_set("disposal_date", self.posting_date)
-
- self.set_consumed_asset_status(asset)
-
- for gle in fixed_asset_gl_entries:
- gle["against"] = target_account
- gl_entries.append(self.get_gl_dict(gle, item=item))
-
- # Service Expenses
- total_service_expenses = 0
- for item_row in self.service_items:
- expense_amount = flt(item_row.amount, precision)
- total_service_expenses += expense_amount
- target_against.add(item_row.expense_account)
-
- gl_entries.append(self.get_gl_dict({
- "account": item_row.expense_account,
- "against": target_account,
- "cost_center": item_row.cost_center,
- "project": item_row.get('project') or self.get('project'),
- "remarks": self.get("remarks") or "Accounting Entry for Stock",
- "credit": expense_amount,
- }, item=item_row))
-
- target_against = ", ".join(target_against)
- total_target_stock_value = 0
- total_target_asset_value = 0
-
- if self.target_is_fixed_asset:
- # Target Asset Item
- total_target_asset_value = flt(self.total_value, precision)
- gl_entries.append(self.get_gl_dict({
- "account": self.target_fixed_asset_account,
- "against": target_against,
- "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
- "debit": total_target_asset_value,
- "cost_center": self.get('cost_center')
- }, item=self))
-
- if self.docstatus == 1:
- asset_doc = frappe.get_doc("Asset", self.target_asset)
- asset_doc.purchase_date = self.posting_date
- asset_doc.gross_purchase_amount = total_target_asset_value
- asset_doc.purchase_receipt_amount = total_target_asset_value
- asset_doc.prepare_depreciation_data()
- asset_doc.flags.ignore_validate_update_after_submit = True
- asset_doc.save()
- else:
- # Target Stock Item
- sle_list = sle_map.get(self.name)
- for sle in sle_list:
- stock_value_difference = flt(sle.stock_value_difference, precision)
- total_target_stock_value += sle.stock_value_difference
- account = warehouse_account[sle.warehouse]["account"]
-
- gl_entries.append(self.get_gl_dict({
- "account": account,
- "against": target_against,
- "cost_center": self.cost_center,
- "project": self.get('project'),
- "remarks": self.get("remarks") or "Accounting Entry for Stock",
- "debit": stock_value_difference,
- }, warehouse_account[sle.warehouse]["account_currency"], item=self))
-
- return gl_entries
def get_asset(self, item):
asset = frappe.get_doc("Asset", item.asset)
@@ -489,16 +562,12 @@
item_defaults = get_item_defaults(item.name, company)
item_group_defaults = get_item_group_defaults(item.name, company)
brand_defaults = get_brand_defaults(item.name, company)
- out.cost_center = get_default_cost_center(frappe._dict({'item_code': item.name, 'company': company}),
- item_defaults, item_group_defaults, brand_defaults)
-
- # Set Entry Type
- if not item_code:
- out.entry_type = ""
- elif out.target_is_fixed_asset:
- out.entry_type = "Capitalization"
- else:
- out.entry_type = "Decapitalization"
+ out.cost_center = get_default_cost_center(
+ frappe._dict({"item_code": item.name, "company": company}),
+ item_defaults,
+ item_group_defaults,
+ brand_defaults,
+ )
return out
@@ -510,7 +579,7 @@
# Get Asset Details
asset_details = frappe._dict()
if asset:
- asset_details = frappe.db.get_value("Asset", asset, ['asset_name', 'item_code'], as_dict=1)
+ asset_details = frappe.db.get_value("Asset", asset, ["asset_name", "item_code"], as_dict=1)
if not asset_details:
frappe.throw(_("Asset {0} does not exist").format(asset))
@@ -521,8 +590,9 @@
out.asset_name = asset_details.asset_name
if asset_details.item_code:
- out.target_fixed_asset_account = get_asset_category_account('fixed_asset_account', item=asset_details.item_code,
- company=company)
+ out.target_fixed_asset_account = get_asset_category_account(
+ "fixed_asset_account", item=asset_details.item_code, company=company
+ )
else:
out.target_fixed_asset_account = None
@@ -530,7 +600,7 @@
@frappe.whitelist()
-def get_consumed_stock_item_details(args, get_valuation_rate=True):
+def get_consumed_stock_item_details(args):
if isinstance(args, string_types):
args = json.loads(args)
@@ -554,24 +624,29 @@
item_defaults = get_item_defaults(item.name, args.company)
item_group_defaults = get_item_group_defaults(item.name, args.company)
brand_defaults = get_brand_defaults(item.name, args.company)
- out.cost_center = get_default_cost_center(args, item_defaults, item_group_defaults, brand_defaults)
+ out.cost_center = get_default_cost_center(
+ args, item_defaults, item_group_defaults, brand_defaults
+ )
- if get_valuation_rate:
- if args.item_code and out.warehouse:
- incoming_rate_args = frappe._dict({
- 'item_code': args.item_code,
- 'warehouse': out.warehouse,
- 'posting_date': args.posting_date,
- 'posting_time': args.posting_time,
- 'qty': -1 * flt(out.stock_qty),
+ if args.item_code and out.warehouse:
+ incoming_rate_args = frappe._dict(
+ {
+ "item_code": args.item_code,
+ "warehouse": out.warehouse,
+ "posting_date": args.posting_date,
+ "posting_time": args.posting_time,
+ "qty": -1 * flt(out.stock_qty),
"voucher_type": args.doctype,
"voucher_no": args.name,
"company": args.company,
- })
- out.update(get_warehouse_details(incoming_rate_args))
- else:
- out.valuation_rate = 0
- out.actual_qty = 0
+ "serial_no": args.serial_no,
+ "batch_no": args.batch_no,
+ }
+ )
+ out.update(get_warehouse_details(incoming_rate_args))
+ else:
+ out.valuation_rate = 0
+ out.actual_qty = 0
return out
@@ -587,13 +662,13 @@
if args.warehouse and args.item_code:
out = {
"actual_qty": get_previous_sle(args).get("qty_after_transaction") or 0,
- "valuation_rate": get_incoming_rate(args, raise_error_if_no_rate=False)
+ "valuation_rate": get_incoming_rate(args, raise_error_if_no_rate=False),
}
return out
@frappe.whitelist()
-def get_consumed_asset_details(args, get_asset_value=True):
+def get_consumed_asset_details(args):
if isinstance(args, string_types):
args = json.loads(args)
@@ -602,7 +677,9 @@
asset_details = frappe._dict()
if args.asset:
- asset_details = frappe.db.get_value("Asset", args.asset, ['asset_name', 'item_code', 'item_name'], as_dict=1)
+ asset_details = frappe.db.get_value(
+ "Asset", args.asset, ["asset_name", "item_code", "item_name"], as_dict=1
+ )
if not asset_details:
frappe.throw(_("Asset {0} does not exist").format(args.asset))
@@ -610,19 +687,22 @@
out.asset_name = asset_details.asset_name
out.item_name = asset_details.item_name
- if get_asset_value:
- if args.asset:
- out.current_asset_value = flt(get_current_asset_value(args.asset, finance_book=args.finance_book))
- out.asset_value = get_value_after_depreciation_on_disposal_date(args.asset, args.posting_date,
- finance_book=args.finance_book)
- else:
- out.current_asset_value = 0
- out.asset_value = 0
+ if args.asset:
+ out.current_asset_value = flt(
+ get_current_asset_value(args.asset, finance_book=args.finance_book)
+ )
+ out.asset_value = get_value_after_depreciation_on_disposal_date(
+ args.asset, args.posting_date, finance_book=args.finance_book
+ )
+ else:
+ out.current_asset_value = 0
+ out.asset_value = 0
# Account
if asset_details.item_code:
- out.fixed_asset_account = get_asset_category_account('fixed_asset_account', item=asset_details.item_code,
- company=args.company)
+ out.fixed_asset_account = get_asset_category_account(
+ "fixed_asset_account", item=asset_details.item_code, company=args.company
+ )
else:
out.fixed_asset_account = None
@@ -632,7 +712,9 @@
item_defaults = get_item_defaults(item.name, args.company)
item_group_defaults = get_item_group_defaults(item.name, args.company)
brand_defaults = get_brand_defaults(item.name, args.company)
- out.cost_center = get_default_cost_center(args, item_defaults, item_group_defaults, brand_defaults)
+ out.cost_center = get_default_cost_center(
+ args, item_defaults, item_group_defaults, brand_defaults
+ )
return out
@@ -657,7 +739,11 @@
item_group_defaults = get_item_group_defaults(item.name, args.company)
brand_defaults = get_brand_defaults(item.name, args.company)
- out.expense_account = get_default_expense_account(args, item_defaults, item_group_defaults, brand_defaults)
- out.cost_center = get_default_cost_center(args, item_defaults, item_group_defaults, brand_defaults)
+ out.expense_account = get_default_expense_account(
+ args, item_defaults, item_group_defaults, brand_defaults
+ )
+ out.cost_center = get_default_cost_center(
+ args, item_defaults, item_group_defaults, brand_defaults
+ )
return out
diff --git a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py
index 7046de6..86861f0 100644
--- a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py
+++ b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py
@@ -22,9 +22,12 @@
create_asset_capitalization_data()
frappe.db.sql("delete from `tabTax Rule`")
- def test_capitalization(self):
+ def test_capitalization_with_perpetual_inventory(self):
+ company = "_Test Company with perpetual inventory"
+ set_depreciation_settings_in_company(company=company)
+
# Variables
- consumed_asset_value = 100_000
+ consumed_asset_value = 100000
stock_rate = 1000
stock_qty = 2
@@ -34,23 +37,39 @@
service_qty = 2
service_amount = 1000
- total_amount = 103_000
+ total_amount = 103000
# Create assets
- target_asset = create_asset(asset_name='Asset Capitalization Target Asset', submit=1)
- consumed_asset = create_asset(asset_name='Asset Capitalization Consumable Asset', asset_value=consumed_asset_value,
- submit=1)
+ target_asset = create_asset(
+ asset_name="Asset Capitalization Target Asset",
+ submit=1,
+ warehouse="Stores - TCP1",
+ company=company,
+ )
+ consumed_asset = create_asset(
+ asset_name="Asset Capitalization Consumable Asset",
+ asset_value=consumed_asset_value,
+ submit=1,
+ warehouse="Stores - TCP1",
+ company=company,
+ )
# Create and submit Asset Captitalization
- asset_capitalization = create_asset_capitalization(target_asset=target_asset.name,
- stock_qty=stock_qty, stock_rate=stock_rate,
+ asset_capitalization = create_asset_capitalization(
+ entry_type="Capitalization",
+ target_asset=target_asset.name,
+ stock_qty=stock_qty,
+ stock_rate=stock_rate,
consumed_asset=consumed_asset.name,
- service_qty=service_qty, service_rate=service_rate,
- service_expense_account='Expenses Included In Asset Valuation - _TC',
- submit=1)
+ service_qty=service_qty,
+ service_rate=service_rate,
+ service_expense_account="Expenses Included In Asset Valuation - TCP1",
+ company=company,
+ submit=1,
+ )
# Test Asset Capitalization values
- self.assertEqual(asset_capitalization.entry_type, 'Capitalization')
+ self.assertEqual(asset_capitalization.entry_type, "Capitalization")
self.assertEqual(asset_capitalization.target_qty, 1)
self.assertEqual(asset_capitalization.stock_items[0].valuation_rate, stock_rate)
@@ -72,13 +91,13 @@
self.assertEqual(target_asset.purchase_receipt_amount, total_amount)
# Test Consumed Asset values
- self.assertEqual(consumed_asset.db_get('status'), 'Capitalized')
+ self.assertEqual(consumed_asset.db_get("status"), "Capitalized")
# Test General Ledger Entries
expected_gle = {
- '_Test Fixed Asset - _TC': 3000,
- 'Expenses Included In Asset Valuation - _TC': -1000,
- 'Stock In Hand - _TC' : -2000
+ "_Test Fixed Asset - TCP1": 3000,
+ "Expenses Included In Asset Valuation - TCP1": -1000,
+ "_Test Warehouse - TCP1": -2000,
}
actual_gle = get_actual_gle_dict(asset_capitalization.name)
@@ -86,25 +105,121 @@
# Test Stock Ledger Entries
expected_sle = {
- ('Capitalization Source Stock Item', '_Test Warehouse - _TC'): {
- 'actual_qty': -stock_qty, 'stock_value_difference': -stock_amount
+ ("Capitalization Source Stock Item", "_Test Warehouse - TCP1"): {
+ "actual_qty": -stock_qty,
+ "stock_value_difference": -stock_amount,
}
}
actual_sle = get_actual_sle_dict(asset_capitalization.name)
-
self.assertEqual(actual_sle, expected_sle)
# Cancel Asset Capitalization and make test entries and status are reversed
asset_capitalization.cancel()
- self.assertEqual(consumed_asset.db_get('status'), 'Submitted')
+ self.assertEqual(consumed_asset.db_get("status"), "Submitted")
+ self.assertFalse(get_actual_gle_dict(asset_capitalization.name))
+ self.assertFalse(get_actual_sle_dict(asset_capitalization.name))
+
+ def test_capitalization_with_periodical_inventory(self):
+ company = "_Test Company"
+ # Variables
+ consumed_asset_value = 100000
+
+ stock_rate = 1000
+ stock_qty = 2
+ stock_amount = 2000
+
+ service_rate = 500
+ service_qty = 2
+ service_amount = 1000
+
+ total_amount = 103000
+
+ # Create assets
+ target_asset = create_asset(
+ asset_name="Asset Capitalization Target Asset",
+ submit=1,
+ warehouse="Stores - _TC",
+ company=company,
+ )
+ consumed_asset = create_asset(
+ asset_name="Asset Capitalization Consumable Asset",
+ asset_value=consumed_asset_value,
+ submit=1,
+ warehouse="Stores - _TC",
+ company=company,
+ )
+
+ # Create and submit Asset Captitalization
+ asset_capitalization = create_asset_capitalization(
+ entry_type="Capitalization",
+ target_asset=target_asset.name,
+ stock_qty=stock_qty,
+ stock_rate=stock_rate,
+ consumed_asset=consumed_asset.name,
+ service_qty=service_qty,
+ service_rate=service_rate,
+ service_expense_account="Expenses Included In Asset Valuation - _TC",
+ company=company,
+ submit=1,
+ )
+
+ # Test Asset Capitalization values
+ self.assertEqual(asset_capitalization.entry_type, "Capitalization")
+ self.assertEqual(asset_capitalization.target_qty, 1)
+
+ self.assertEqual(asset_capitalization.stock_items[0].valuation_rate, stock_rate)
+ self.assertEqual(asset_capitalization.stock_items[0].amount, stock_amount)
+ self.assertEqual(asset_capitalization.stock_items_total, stock_amount)
+
+ self.assertEqual(asset_capitalization.asset_items[0].asset_value, consumed_asset_value)
+ self.assertEqual(asset_capitalization.asset_items_total, consumed_asset_value)
+
+ self.assertEqual(asset_capitalization.service_items[0].amount, service_amount)
+ self.assertEqual(asset_capitalization.service_items_total, service_amount)
+
+ self.assertEqual(asset_capitalization.total_value, total_amount)
+ self.assertEqual(asset_capitalization.target_incoming_rate, total_amount)
+
+ # Test Target Asset values
+ target_asset.reload()
+ self.assertEqual(target_asset.gross_purchase_amount, total_amount)
+ self.assertEqual(target_asset.purchase_receipt_amount, total_amount)
+
+ # Test Consumed Asset values
+ self.assertEqual(consumed_asset.db_get("status"), "Capitalized")
+
+ # Test General Ledger Entries
+ default_expense_account = frappe.db.get_value("Company", company, "default_expense_account")
+ expected_gle = {
+ "_Test Fixed Asset - _TC": 3000,
+ "Expenses Included In Asset Valuation - _TC": -1000,
+ default_expense_account: -2000,
+ }
+ actual_gle = get_actual_gle_dict(asset_capitalization.name)
+
+ self.assertEqual(actual_gle, expected_gle)
+
+ # Test Stock Ledger Entries
+ expected_sle = {
+ ("Capitalization Source Stock Item", "_Test Warehouse - _TC"): {
+ "actual_qty": -stock_qty,
+ "stock_value_difference": -stock_amount,
+ }
+ }
+ actual_sle = get_actual_sle_dict(asset_capitalization.name)
+ self.assertEqual(actual_sle, expected_sle)
+
+ # Cancel Asset Capitalization and make test entries and status are reversed
+ asset_capitalization.cancel()
+ self.assertEqual(consumed_asset.db_get("status"), "Submitted")
self.assertFalse(get_actual_gle_dict(asset_capitalization.name))
self.assertFalse(get_actual_sle_dict(asset_capitalization.name))
def test_decapitalization_with_depreciation(self):
# Variables
- purchase_date = '2020-01-01'
- depreciation_start_date = '2020-12-31'
- capitalization_date = '2021-06-30'
+ purchase_date = "2020-01-01"
+ depreciation_start_date = "2020-12-31"
+ capitalization_date = "2021-06-30"
total_number_of_depreciations = 3
expected_value_after_useful_life = 10_000
@@ -126,29 +241,38 @@
# Create assets
consumed_asset = create_depreciation_asset(
- asset_name='Asset Capitalization Consumable Asset',
+ asset_name="Asset Capitalization Consumable Asset",
asset_value=consumed_asset_purchase_value,
purchase_date=purchase_date,
depreciation_start_date=depreciation_start_date,
- depreciation_method='Straight Line',
+ depreciation_method="Straight Line",
total_number_of_depreciations=total_number_of_depreciations,
frequency_of_depreciation=12,
expected_value_after_useful_life=expected_value_after_useful_life,
- submit=1)
+ company="_Test Company with perpetual inventory",
+ submit=1,
+ )
# Create and submit Asset Captitalization
asset_capitalization = create_asset_capitalization(
+ entry_type="Decapitalization",
posting_date=capitalization_date, # half a year
target_item_code="Capitalization Target Stock Item",
target_qty=target_qty,
consumed_asset=consumed_asset.name,
- submit=1)
+ company="_Test Company with perpetual inventory",
+ submit=1,
+ )
# Test Asset Capitalization values
- self.assertEqual(asset_capitalization.entry_type, 'Decapitalization')
+ self.assertEqual(asset_capitalization.entry_type, "Decapitalization")
- self.assertEqual(asset_capitalization.asset_items[0].current_asset_value, consumed_asset_current_value)
- self.assertEqual(asset_capitalization.asset_items[0].asset_value, consumed_asset_value_before_disposal)
+ self.assertEqual(
+ asset_capitalization.asset_items[0].current_asset_value, consumed_asset_current_value
+ )
+ self.assertEqual(
+ asset_capitalization.asset_items[0].asset_value, consumed_asset_value_before_disposal
+ )
self.assertEqual(asset_capitalization.asset_items_total, consumed_asset_value_before_disposal)
self.assertEqual(asset_capitalization.total_value, consumed_asset_value_before_disposal)
@@ -156,38 +280,45 @@
# Test Consumed Asset values
consumed_asset.reload()
- self.assertEqual(consumed_asset.status, 'Decapitalized')
+ self.assertEqual(consumed_asset.status, "Decapitalized")
- consumed_depreciation_schedule = [d for d in consumed_asset.schedules
- if getdate(d.schedule_date) == getdate(capitalization_date)]
- self.assertTrue(consumed_depreciation_schedule and consumed_depreciation_schedule[0].journal_entry)
- self.assertEqual(consumed_depreciation_schedule[0].depreciation_amount, depreciation_before_disposal_amount)
+ consumed_depreciation_schedule = [
+ d for d in consumed_asset.schedules if getdate(d.schedule_date) == getdate(capitalization_date)
+ ]
+ self.assertTrue(
+ consumed_depreciation_schedule and consumed_depreciation_schedule[0].journal_entry
+ )
+ self.assertEqual(
+ consumed_depreciation_schedule[0].depreciation_amount, depreciation_before_disposal_amount
+ )
# Test General Ledger Entries
expected_gle = {
- 'Stock In Hand - _TC': consumed_asset_value_before_disposal,
- '_Test Accumulated Depreciations - _TC': accumulated_depreciation,
- '_Test Fixed Asset - _TC': -consumed_asset_purchase_value,
+ "_Test Warehouse - TCP1": consumed_asset_value_before_disposal,
+ "_Test Accumulated Depreciations - TCP1": accumulated_depreciation,
+ "_Test Fixed Asset - TCP1": -consumed_asset_purchase_value,
}
actual_gle = get_actual_gle_dict(asset_capitalization.name)
-
self.assertEqual(actual_gle, expected_gle)
# Cancel Asset Capitalization and make test entries and status are reversed
asset_capitalization.reload()
asset_capitalization.cancel()
- self.assertEqual(consumed_asset.db_get('status'), 'Partially Depreciated')
+ self.assertEqual(consumed_asset.db_get("status"), "Partially Depreciated")
self.assertFalse(get_actual_gle_dict(asset_capitalization.name))
self.assertFalse(get_actual_sle_dict(asset_capitalization.name))
def create_asset_capitalization_data():
- create_item("Capitalization Target Stock Item",
- is_stock_item=1, is_fixed_asset=0, is_purchase_item=0)
- create_item("Capitalization Source Stock Item",
- is_stock_item=1, is_fixed_asset=0, is_purchase_item=0)
- create_item("Capitalization Source Service Item",
- is_stock_item=0, is_fixed_asset=0, is_purchase_item=0)
+ create_item(
+ "Capitalization Target Stock Item", is_stock_item=1, is_fixed_asset=0, is_purchase_item=0
+ )
+ create_item(
+ "Capitalization Source Stock Item", is_stock_item=1, is_fixed_asset=0, is_purchase_item=0
+ )
+ create_item(
+ "Capitalization Source Service Item", is_stock_item=0, is_fixed_asset=0, is_purchase_item=0
+ )
def create_asset_capitalization(**args):
@@ -204,43 +335,55 @@
source_warehouse = args.source_warehouse or warehouse
asset_capitalization = frappe.new_doc("Asset Capitalization")
- asset_capitalization.update({
- "company": company,
- "posting_date": args.posting_date or now.strftime('%Y-%m-%d'),
- "posting_time": args.posting_time or now.strftime('%H:%M:%S.%f'),
- "target_item_code": target_item_code,
- "target_asset": target_asset.name,
- "target_warehouse": target_warehouse,
- "target_qty": flt(args.target_qty) or 1,
- "target_batch_no": args.target_batch_no,
- "target_serial_no": args.target_serial_no,
- "finance_book": args.finance_book
- })
+ asset_capitalization.update(
+ {
+ "entry_type": args.entry_type or "Capitalization",
+ "company": company,
+ "posting_date": args.posting_date or now.strftime("%Y-%m-%d"),
+ "posting_time": args.posting_time or now.strftime("%H:%M:%S.%f"),
+ "target_item_code": target_item_code,
+ "target_asset": target_asset.name,
+ "target_warehouse": target_warehouse,
+ "target_qty": flt(args.target_qty) or 1,
+ "target_batch_no": args.target_batch_no,
+ "target_serial_no": args.target_serial_no,
+ "finance_book": args.finance_book,
+ }
+ )
if args.posting_date or args.posting_time:
asset_capitalization.set_posting_time = 1
if flt(args.stock_rate):
- asset_capitalization.append("stock_items", {
- "item_code": args.stock_item or "Capitalization Source Stock Item",
- "warehouse": source_warehouse,
- "stock_qty": flt(args.stock_qty) or 1,
- "batch_no": args.stock_batch_no,
- "serial_no": args.stock_serial_no,
- })
+ asset_capitalization.append(
+ "stock_items",
+ {
+ "item_code": args.stock_item or "Capitalization Source Stock Item",
+ "warehouse": source_warehouse,
+ "stock_qty": flt(args.stock_qty) or 1,
+ "batch_no": args.stock_batch_no,
+ "serial_no": args.stock_serial_no,
+ },
+ )
if args.consumed_asset:
- asset_capitalization.append("asset_items", {
- "asset": args.consumed_asset,
- })
+ asset_capitalization.append(
+ "asset_items",
+ {
+ "asset": args.consumed_asset,
+ },
+ )
if flt(args.service_rate):
- asset_capitalization.append("service_items", {
- "item_code": args.service_item or "Capitalization Source Service Item",
- "expense_account": args.service_expense_account,
- "qty": flt(args.service_qty) or 1,
- "rate": flt(args.service_rate)
- })
+ asset_capitalization.append(
+ "service_items",
+ {
+ "item_code": args.service_item or "Capitalization Source Service Item",
+ "expense_account": args.service_expense_account,
+ "qty": flt(args.service_qty) or 1,
+ "rate": flt(args.service_rate),
+ },
+ )
if args.submit:
create_stock_reconciliation(asset_capitalization, stock_rate=args.stock_rate)
@@ -255,17 +398,23 @@
def create_stock_reconciliation(asset_capitalization, stock_rate=0):
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
+ EmptyStockReconciliationItemsError,
create_stock_reconciliation,
)
- if not asset_capitalization.get('stock_items'):
+
+ if not asset_capitalization.get("stock_items"):
return
- return create_stock_reconciliation(
- item_code=asset_capitalization.stock_items[0].item_code,
- warehouse=asset_capitalization.stock_items[0].warehouse,
- qty=flt(asset_capitalization.stock_items[0].stock_qty),
- rate=flt(stock_rate),
- company=asset_capitalization.company)
+ try:
+ create_stock_reconciliation(
+ item_code=asset_capitalization.stock_items[0].item_code,
+ warehouse=asset_capitalization.stock_items[0].warehouse,
+ qty=flt(asset_capitalization.stock_items[0].stock_qty),
+ rate=flt(stock_rate),
+ company=asset_capitalization.company,
+ )
+ except EmptyStockReconciliationItemsError:
+ pass
def create_depreciation_asset(**args):
@@ -281,15 +430,15 @@
asset.asset_name = args.asset_name or asset.item_code
asset.location = args.location or "Test Location"
- asset.purchase_date = args.purchase_date or '2020-01-01'
+ asset.purchase_date = args.purchase_date or "2020-01-01"
asset.available_for_use_date = args.available_for_use_date or asset.purchase_date
asset.gross_purchase_amount = args.asset_value or 100000
asset.purchase_receipt_amount = asset.gross_purchase_amount
- finance_book = asset.append('finance_books')
- finance_book.depreciation_start_date = args.depreciation_start_date or '2020-12-31'
- finance_book.depreciation_method = args.depreciation_method or 'Straight Line'
+ finance_book = asset.append("finance_books")
+ finance_book.depreciation_start_date = args.depreciation_start_date or "2020-12-31"
+ finance_book.depreciation_method = args.depreciation_method or "Straight Line"
finance_book.total_number_of_depreciations = cint(args.total_number_of_depreciations) or 3
finance_book.frequency_of_depreciation = cint(args.frequency_of_depreciation) or 12
finance_book.expected_value_after_useful_life = flt(args.expected_value_after_useful_life)
@@ -305,17 +454,23 @@
def get_actual_gle_dict(name):
- return dict(frappe.db.sql("""
+ return dict(
+ frappe.db.sql(
+ """
select account, sum(debit-credit) as diff
from `tabGL Entry`
where voucher_type = 'Asset Capitalization' and voucher_no = %s
group by account
having diff != 0
- """, name))
+ """,
+ name,
+ )
+ )
def get_actual_sle_dict(name):
- sles = frappe.db.sql("""
+ sles = frappe.db.sql(
+ """
select
item_code, warehouse,
sum(actual_qty) as actual_qty,
@@ -324,12 +479,16 @@
where voucher_type = 'Asset Capitalization' and voucher_no = %s
group by item_code, warehouse
having actual_qty != 0
- """, name, as_dict=1)
+ """,
+ name,
+ as_dict=1,
+ )
sle_dict = {}
for d in sles:
sle_dict[(d.item_code, d.warehouse)] = {
- 'actual_qty': d.actual_qty, 'stock_value_difference': d.stock_value_difference
+ "actual_qty": d.actual_qty,
+ "stock_value_difference": d.stock_value_difference,
}
return sle_dict
diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
index 6e06f52..2786349 100644
--- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
@@ -129,18 +129,6 @@
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,
diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
index 191c03f..4e76ae7 100644
--- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
@@ -727,7 +727,12 @@
sr.set_posting_time = 1
sr.company = args.company or "_Test Company"
sr.expense_account = args.expense_account or (
- "Stock Adjustment - _TC" if frappe.get_all("Stock Ledger Entry") else "Temporary Opening - _TC"
+ (
+ frappe.get_cached_value("Company", sr.company, "stock_adjustment_account")
+ or "Stock Adjustment - _TC"
+ )
+ if frappe.get_all("Stock Ledger Entry", {"company": sr.company})
+ else "Temporary Opening - _TC"
)
sr.cost_center = (
args.cost_center