feat: Asset Capitalization

- manual selection of entry type
- GLE cleanup with smaller functions
- GLE considering periodical inventory
- test cases
This commit is contained in:
Nabin Hait 2022-09-13 14:56:21 +05:30
parent fefe95052d
commit 58d430fe3e
7 changed files with 583 additions and 334 deletions

View File

@ -1425,6 +1425,16 @@ def create_asset_category():
"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()

View File

@ -27,7 +27,11 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
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 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
}
};
//$.extend(cur_frm.cscript, new erpnext.assets.AssetCapitalization({frm: cur_frm}));
cur_frm.cscript = new erpnext.assets.AssetCapitalization({frm: cur_frm});

View File

@ -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

View File

@ -10,9 +10,9 @@ from frappe import _
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.get_item_details import (
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 @@ class AssetCapitalization(StockController):
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 @@ class AssetCapitalization(StockController):
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 @@ class AssetCapitalization(StockController):
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 @@ class AssetCapitalization(StockController):
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 @@ class AssetCapitalization(StockController):
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 @@ class AssetCapitalization(StockController):
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 @@ class AssetCapitalization(StockController):
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 @@ class AssetCapitalization(StockController):
@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 @@ class AssetCapitalization(StockController):
@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 @@ class AssetCapitalization(StockController):
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 @@ class AssetCapitalization(StockController):
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()
if self.target_is_fixed_asset:
target_account = self.target_fixed_asset_account
else:
target_account = warehouse_account[self.target_warehouse]["account"]
self.sle_map = self.get_stock_ledger_details()
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 @@ def get_target_item_details(item_code=None, company=None):
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 @@ def get_target_asset_details(asset=None, company=None):
# 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 @@ def get_target_asset_details(asset=None, company=None):
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 @@ def get_target_asset_details(asset=None, company=None):
@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 @@ def get_consumed_stock_item_details(args, get_valuation_rate=True):
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 @@ def get_warehouse_details(args):
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 @@ def get_consumed_asset_details(args, get_asset_value=True):
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 @@ def get_consumed_asset_details(args, get_asset_value=True):
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 @@ def get_consumed_asset_details(args, get_asset_value=True):
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 @@ def get_service_item_details(args):
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

View File

@ -22,9 +22,12 @@ class TestAssetCapitalization(unittest.TestCase):
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 @@ class TestAssetCapitalization(unittest.TestCase):
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 @@ class TestAssetCapitalization(unittest.TestCase):
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 @@ class TestAssetCapitalization(unittest.TestCase):
# 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 @@ class TestAssetCapitalization(unittest.TestCase):
# 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 @@ class TestAssetCapitalization(unittest.TestCase):
# 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 @@ def create_asset_capitalization(**args):
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_asset_capitalization(**args):
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 @@ def create_depreciation_asset(**args):
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 create_depreciation_asset(**args):
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 @@ def get_actual_sle_dict(name):
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

View File

@ -129,18 +129,6 @@ class TestAssetRepair(unittest.TestCase):
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,

View File

@ -727,7 +727,12 @@ def create_stock_reconciliation(**args):
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