Compare commits
43 Commits
v13.34.1
...
enterprise
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2dec3389b | ||
|
|
bffd7feadb | ||
|
|
1fe608ea23 | ||
|
|
9464b3c3e6 | ||
|
|
8da929635f | ||
|
|
1f6e0b871b | ||
|
|
18ac08413b | ||
|
|
0f83ba221f | ||
|
|
e5898a37dc | ||
|
|
f4b3e208b7 | ||
|
|
eeb3d72dc0 | ||
|
|
29ca1950a2 | ||
|
|
8a4de134ac | ||
|
|
69c9856bee | ||
|
|
4343bdd8db | ||
|
|
2bf30db3d1 | ||
|
|
8b1be1db4c | ||
|
|
13d501c0b9 | ||
|
|
59ae7e09cb | ||
|
|
4425442bbb | ||
|
|
ed98125807 | ||
|
|
5aae91e6cb | ||
|
|
c6725d43cb | ||
|
|
f36ed34907 | ||
|
|
ccf1472c56 | ||
|
|
bb95287357 | ||
|
|
35d6c6ade4 | ||
|
|
f9c46e766b | ||
|
|
1c183c16d4 | ||
|
|
a4140a1487 | ||
|
|
3c20553104 | ||
|
|
b169558885 | ||
|
|
21d2efbbdc | ||
|
|
591b57a02a | ||
|
|
be55fb31e4 | ||
|
|
0419ba1d78 | ||
|
|
945214771a | ||
|
|
0e10f69c6e | ||
|
|
3d039d0fac | ||
|
|
b74db6f2b8 | ||
|
|
efc76f4245 | ||
|
|
653e1455ed | ||
|
|
ac5e7f2b74 |
@@ -108,6 +108,10 @@ frappe.ui.form.on('Asset', {
|
||||
frm.trigger("create_asset_repair");
|
||||
}, __("Manage"));
|
||||
|
||||
frm.add_custom_button(__("Split Asset"), function() {
|
||||
frm.trigger("split_asset");
|
||||
}, __("Manage"));
|
||||
|
||||
if (frm.doc.status != 'Fully Depreciated') {
|
||||
frm.add_custom_button(__("Adjust Asset Value"), function() {
|
||||
frm.trigger("create_asset_value_adjustment");
|
||||
@@ -322,6 +326,43 @@ frappe.ui.form.on('Asset', {
|
||||
});
|
||||
},
|
||||
|
||||
split_asset: function(frm) {
|
||||
const title = __('Split Asset');
|
||||
|
||||
const fields = [
|
||||
{
|
||||
fieldname: 'split_qty',
|
||||
fieldtype: 'Int',
|
||||
label: __('Split Qty'),
|
||||
reqd: 1
|
||||
}
|
||||
];
|
||||
|
||||
let dialog = new frappe.ui.Dialog({
|
||||
title: title,
|
||||
fields: fields
|
||||
});
|
||||
|
||||
dialog.set_primary_action(__('Split'), function() {
|
||||
const dialog_data = dialog.get_values();
|
||||
frappe.call({
|
||||
args: {
|
||||
"asset_name": frm.doc.name,
|
||||
"split_qty": cint(dialog_data.split_qty)
|
||||
},
|
||||
method: "erpnext.assets.doctype.asset.asset.split_asset",
|
||||
callback: function(r) {
|
||||
let doclist = frappe.model.sync(r.message);
|
||||
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
|
||||
}
|
||||
});
|
||||
|
||||
dialog.hide();
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
},
|
||||
|
||||
create_asset_value_adjustment: function(frm) {
|
||||
frappe.call({
|
||||
args: {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2016-03-01 17:01:27.920130",
|
||||
"creation": "2022-01-18 02:26:55.975005",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Document",
|
||||
"engine": "InnoDB",
|
||||
@@ -23,6 +23,7 @@
|
||||
"asset_name",
|
||||
"asset_category",
|
||||
"location",
|
||||
"split_from",
|
||||
"custodian",
|
||||
"department",
|
||||
"disposal_date",
|
||||
@@ -35,6 +36,7 @@
|
||||
"available_for_use_date",
|
||||
"column_break_23",
|
||||
"gross_purchase_amount",
|
||||
"asset_quantity",
|
||||
"purchase_date",
|
||||
"section_break_23",
|
||||
"calculate_depreciation",
|
||||
@@ -481,6 +483,18 @@
|
||||
"fieldname": "section_break_36",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Finance Books"
|
||||
},
|
||||
{
|
||||
"fieldname": "split_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Split From",
|
||||
"options": "Asset",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "asset_quantity",
|
||||
"fieldtype": "Int",
|
||||
"label": "Asset Quantity"
|
||||
}
|
||||
],
|
||||
"idx": 72,
|
||||
@@ -507,6 +521,7 @@
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset",
|
||||
"naming_rule": "By \"Naming Series\" field",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
@@ -543,6 +558,7 @@
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "asset_name",
|
||||
"track_changes": 1
|
||||
}
|
||||
|
||||
@@ -39,7 +39,8 @@ class Asset(AccountsController):
|
||||
self.validate_item()
|
||||
self.validate_cost_center()
|
||||
self.set_missing_values()
|
||||
self.prepare_depreciation_data()
|
||||
if not self.split_from:
|
||||
self.prepare_depreciation_data()
|
||||
self.validate_gross_and_purchase_amount()
|
||||
if self.get("schedules"):
|
||||
self.validate_expected_value_after_useful_life()
|
||||
@@ -235,175 +236,180 @@ class Asset(AccountsController):
|
||||
start = self.clear_depreciation_schedule()
|
||||
|
||||
for finance_book in self.get("finance_books"):
|
||||
self.validate_asset_finance_books(finance_book)
|
||||
self._make_depreciation_schedule(finance_book, start, date_of_sale)
|
||||
|
||||
# value_after_depreciation - current Asset value
|
||||
if self.docstatus == 1 and finance_book.value_after_depreciation:
|
||||
value_after_depreciation = flt(finance_book.value_after_depreciation)
|
||||
else:
|
||||
value_after_depreciation = flt(self.gross_purchase_amount) - flt(
|
||||
self.opening_accumulated_depreciation
|
||||
def _make_depreciation_schedule(self, finance_book, start, date_of_sale):
|
||||
self.validate_asset_finance_books(finance_book)
|
||||
|
||||
value_after_depreciation = self._get_value_after_depreciation(finance_book)
|
||||
finance_book.value_after_depreciation = value_after_depreciation
|
||||
|
||||
number_of_pending_depreciations = cint(finance_book.total_number_of_depreciations) - cint(
|
||||
self.number_of_depreciations_booked
|
||||
)
|
||||
|
||||
has_pro_rata = self.check_is_pro_rata(finance_book)
|
||||
if has_pro_rata:
|
||||
number_of_pending_depreciations += 1
|
||||
|
||||
skip_row = False
|
||||
|
||||
for n in range(start[finance_book.idx - 1], number_of_pending_depreciations):
|
||||
# If depreciation is already completed (for double declining balance)
|
||||
if skip_row:
|
||||
continue
|
||||
|
||||
depreciation_amount = get_depreciation_amount(self, value_after_depreciation, finance_book)
|
||||
|
||||
if not has_pro_rata or n < cint(number_of_pending_depreciations) - 1:
|
||||
schedule_date = add_months(
|
||||
finance_book.depreciation_start_date, n * cint(finance_book.frequency_of_depreciation)
|
||||
)
|
||||
|
||||
finance_book.value_after_depreciation = value_after_depreciation
|
||||
# schedule date will be a year later from start date
|
||||
# so monthly schedule date is calculated by removing 11 months from it
|
||||
monthly_schedule_date = add_months(schedule_date, -finance_book.frequency_of_depreciation + 1)
|
||||
|
||||
number_of_pending_depreciations = cint(finance_book.total_number_of_depreciations) - cint(
|
||||
self.number_of_depreciations_booked
|
||||
)
|
||||
|
||||
has_pro_rata = self.check_is_pro_rata(finance_book)
|
||||
|
||||
if has_pro_rata:
|
||||
number_of_pending_depreciations += 1
|
||||
|
||||
skip_row = False
|
||||
|
||||
for n in range(start[finance_book.idx - 1], number_of_pending_depreciations):
|
||||
# If depreciation is already completed (for double declining balance)
|
||||
if skip_row:
|
||||
continue
|
||||
|
||||
depreciation_amount = get_depreciation_amount(self, value_after_depreciation, finance_book)
|
||||
|
||||
if not has_pro_rata or n < cint(number_of_pending_depreciations) - 1:
|
||||
schedule_date = add_months(
|
||||
finance_book.depreciation_start_date, n * cint(finance_book.frequency_of_depreciation)
|
||||
)
|
||||
|
||||
# schedule date will be a year later from start date
|
||||
# so monthly schedule date is calculated by removing 11 months from it
|
||||
monthly_schedule_date = add_months(schedule_date, -finance_book.frequency_of_depreciation + 1)
|
||||
|
||||
# if asset is being sold
|
||||
if date_of_sale:
|
||||
from_date = self.get_from_date(finance_book.finance_book)
|
||||
depreciation_amount, days, months = self.get_pro_rata_amt(
|
||||
finance_book, depreciation_amount, from_date, date_of_sale
|
||||
)
|
||||
|
||||
if depreciation_amount > 0:
|
||||
self.append(
|
||||
"schedules",
|
||||
{
|
||||
"schedule_date": date_of_sale,
|
||||
"depreciation_amount": depreciation_amount,
|
||||
"depreciation_method": finance_book.depreciation_method,
|
||||
"finance_book": finance_book.finance_book,
|
||||
"finance_book_id": finance_book.idx,
|
||||
},
|
||||
)
|
||||
|
||||
break
|
||||
|
||||
# For first row
|
||||
if has_pro_rata and not self.opening_accumulated_depreciation and n == 0:
|
||||
from_date = add_days(
|
||||
self.available_for_use_date, -1
|
||||
) # needed to calc depr amount for available_for_use_date too
|
||||
depreciation_amount, days, months = self.get_pro_rata_amt(
|
||||
finance_book, depreciation_amount, from_date, finance_book.depreciation_start_date
|
||||
)
|
||||
|
||||
# For first depr schedule date will be the start date
|
||||
# so monthly schedule date is calculated by removing month difference between use date and start date
|
||||
monthly_schedule_date = add_months(finance_book.depreciation_start_date, -months + 1)
|
||||
|
||||
# For last row
|
||||
elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1:
|
||||
if not self.flags.increase_in_asset_life:
|
||||
# In case of increase_in_asset_life, the self.to_date is already set on asset_repair submission
|
||||
self.to_date = add_months(
|
||||
self.available_for_use_date,
|
||||
(n + self.number_of_depreciations_booked) * cint(finance_book.frequency_of_depreciation),
|
||||
)
|
||||
|
||||
depreciation_amount_without_pro_rata = depreciation_amount
|
||||
|
||||
depreciation_amount, days, months = self.get_pro_rata_amt(
|
||||
finance_book, depreciation_amount, schedule_date, self.to_date
|
||||
)
|
||||
|
||||
depreciation_amount = self.get_adjusted_depreciation_amount(
|
||||
depreciation_amount_without_pro_rata, depreciation_amount, finance_book.finance_book
|
||||
)
|
||||
|
||||
monthly_schedule_date = add_months(schedule_date, 1)
|
||||
schedule_date = add_days(schedule_date, days)
|
||||
last_schedule_date = schedule_date
|
||||
|
||||
if not depreciation_amount:
|
||||
continue
|
||||
value_after_depreciation -= flt(depreciation_amount, self.precision("gross_purchase_amount"))
|
||||
|
||||
# Adjust depreciation amount in the last period based on the expected value after useful life
|
||||
if finance_book.expected_value_after_useful_life and (
|
||||
(
|
||||
n == cint(number_of_pending_depreciations) - 1
|
||||
and value_after_depreciation != finance_book.expected_value_after_useful_life
|
||||
)
|
||||
or value_after_depreciation < finance_book.expected_value_after_useful_life
|
||||
):
|
||||
depreciation_amount += (
|
||||
value_after_depreciation - finance_book.expected_value_after_useful_life
|
||||
)
|
||||
skip_row = True
|
||||
# if asset is being sold
|
||||
if date_of_sale:
|
||||
from_date = self.get_from_date(finance_book.finance_book)
|
||||
depreciation_amount, days, months = self.get_pro_rata_amt(
|
||||
finance_book, depreciation_amount, from_date, date_of_sale
|
||||
)
|
||||
|
||||
if depreciation_amount > 0:
|
||||
# With monthly depreciation, each depreciation is divided by months remaining until next date
|
||||
if self.allow_monthly_depreciation:
|
||||
# month range is 1 to 12
|
||||
# In pro rata case, for first and last depreciation, month range would be different
|
||||
month_range = (
|
||||
months
|
||||
if (has_pro_rata and n == 0)
|
||||
or (has_pro_rata and n == cint(number_of_pending_depreciations) - 1)
|
||||
else finance_book.frequency_of_depreciation
|
||||
)
|
||||
self._add_depreciation_row(
|
||||
date_of_sale,
|
||||
depreciation_amount,
|
||||
finance_book.depreciation_method,
|
||||
finance_book.finance_book,
|
||||
finance_book.idx,
|
||||
)
|
||||
|
||||
for r in range(month_range):
|
||||
if has_pro_rata and n == 0:
|
||||
# For first entry of monthly depr
|
||||
if r == 0:
|
||||
days_until_first_depr = date_diff(monthly_schedule_date, self.available_for_use_date)
|
||||
per_day_amt = depreciation_amount / days
|
||||
depreciation_amount_for_current_month = per_day_amt * days_until_first_depr
|
||||
depreciation_amount -= depreciation_amount_for_current_month
|
||||
date = monthly_schedule_date
|
||||
amount = depreciation_amount_for_current_month
|
||||
else:
|
||||
date = add_months(monthly_schedule_date, r)
|
||||
amount = depreciation_amount / (month_range - 1)
|
||||
elif (has_pro_rata and n == cint(number_of_pending_depreciations) - 1) and r == cint(
|
||||
month_range
|
||||
) - 1:
|
||||
# For last entry of monthly depr
|
||||
date = last_schedule_date
|
||||
amount = depreciation_amount / month_range
|
||||
break
|
||||
|
||||
# For first row
|
||||
if has_pro_rata and not self.opening_accumulated_depreciation and n == 0:
|
||||
from_date = add_days(
|
||||
self.available_for_use_date, -1
|
||||
) # needed to calc depr amount for available_for_use_date too
|
||||
depreciation_amount, days, months = self.get_pro_rata_amt(
|
||||
finance_book, depreciation_amount, from_date, finance_book.depreciation_start_date
|
||||
)
|
||||
|
||||
# For first depr schedule date will be the start date
|
||||
# so monthly schedule date is calculated by removing month difference between use date and start date
|
||||
monthly_schedule_date = add_months(finance_book.depreciation_start_date, -months + 1)
|
||||
|
||||
# For last row
|
||||
elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1:
|
||||
if not self.flags.increase_in_asset_life:
|
||||
# In case of increase_in_asset_life, the self.to_date is already set on asset_repair submission
|
||||
self.to_date = add_months(
|
||||
self.available_for_use_date,
|
||||
(n + self.number_of_depreciations_booked) * cint(finance_book.frequency_of_depreciation),
|
||||
)
|
||||
|
||||
depreciation_amount_without_pro_rata = depreciation_amount
|
||||
|
||||
depreciation_amount, days, months = self.get_pro_rata_amt(
|
||||
finance_book, depreciation_amount, schedule_date, self.to_date
|
||||
)
|
||||
|
||||
depreciation_amount = self.get_adjusted_depreciation_amount(
|
||||
depreciation_amount_without_pro_rata, depreciation_amount, finance_book.finance_book
|
||||
)
|
||||
|
||||
monthly_schedule_date = add_months(schedule_date, 1)
|
||||
schedule_date = add_days(schedule_date, days)
|
||||
last_schedule_date = schedule_date
|
||||
|
||||
if not depreciation_amount:
|
||||
continue
|
||||
value_after_depreciation -= flt(depreciation_amount, self.precision("gross_purchase_amount"))
|
||||
|
||||
# Adjust depreciation amount in the last period based on the expected value after useful life
|
||||
if finance_book.expected_value_after_useful_life and (
|
||||
(
|
||||
n == cint(number_of_pending_depreciations) - 1
|
||||
and value_after_depreciation != finance_book.expected_value_after_useful_life
|
||||
)
|
||||
or value_after_depreciation < finance_book.expected_value_after_useful_life
|
||||
):
|
||||
depreciation_amount += value_after_depreciation - finance_book.expected_value_after_useful_life
|
||||
skip_row = True
|
||||
|
||||
if depreciation_amount > 0:
|
||||
# With monthly depreciation, each depreciation is divided by months remaining until next date
|
||||
if self.allow_monthly_depreciation:
|
||||
# month range is 1 to 12
|
||||
# In pro rata case, for first and last depreciation, month range would be different
|
||||
month_range = (
|
||||
months
|
||||
if (has_pro_rata and n == 0)
|
||||
or (has_pro_rata and n == cint(number_of_pending_depreciations) - 1)
|
||||
else finance_book.frequency_of_depreciation
|
||||
)
|
||||
|
||||
for r in range(month_range):
|
||||
if has_pro_rata and n == 0:
|
||||
# For first entry of monthly depr
|
||||
if r == 0:
|
||||
days_until_first_depr = date_diff(monthly_schedule_date, self.available_for_use_date)
|
||||
per_day_amt = depreciation_amount / days
|
||||
depreciation_amount_for_current_month = per_day_amt * days_until_first_depr
|
||||
depreciation_amount -= depreciation_amount_for_current_month
|
||||
date = monthly_schedule_date
|
||||
amount = depreciation_amount_for_current_month
|
||||
else:
|
||||
date = add_months(monthly_schedule_date, r)
|
||||
amount = depreciation_amount / month_range
|
||||
amount = depreciation_amount / (month_range - 1)
|
||||
elif (has_pro_rata and n == cint(number_of_pending_depreciations) - 1) and r == cint(
|
||||
month_range
|
||||
) - 1:
|
||||
# For last entry of monthly depr
|
||||
date = last_schedule_date
|
||||
amount = depreciation_amount / month_range
|
||||
else:
|
||||
date = add_months(monthly_schedule_date, r)
|
||||
amount = depreciation_amount / month_range
|
||||
|
||||
self.append(
|
||||
"schedules",
|
||||
{
|
||||
"schedule_date": date,
|
||||
"depreciation_amount": amount,
|
||||
"depreciation_method": finance_book.depreciation_method,
|
||||
"finance_book": finance_book.finance_book,
|
||||
"finance_book_id": finance_book.idx,
|
||||
},
|
||||
)
|
||||
else:
|
||||
self.append(
|
||||
"schedules",
|
||||
{
|
||||
"schedule_date": schedule_date,
|
||||
"depreciation_amount": depreciation_amount,
|
||||
"depreciation_method": finance_book.depreciation_method,
|
||||
"finance_book": finance_book.finance_book,
|
||||
"finance_book_id": finance_book.idx,
|
||||
},
|
||||
self._add_depreciation_row(
|
||||
date, amount, finance_book.depreciation_method, finance_book.finance_book, finance_book.idx
|
||||
)
|
||||
else:
|
||||
self._add_depreciation_row(
|
||||
schedule_date,
|
||||
depreciation_amount,
|
||||
finance_book.depreciation_method,
|
||||
finance_book.finance_book,
|
||||
finance_book.idx,
|
||||
)
|
||||
|
||||
def _add_depreciation_row(
|
||||
self, schedule_date, depreciation_amount, depreciation_method, finance_book, finance_book_id
|
||||
):
|
||||
self.append(
|
||||
"schedules",
|
||||
{
|
||||
"schedule_date": schedule_date,
|
||||
"depreciation_amount": depreciation_amount,
|
||||
"depreciation_method": depreciation_method,
|
||||
"finance_book": finance_book,
|
||||
"finance_book_id": finance_book_id,
|
||||
},
|
||||
)
|
||||
|
||||
def _get_value_after_depreciation(self, finance_book):
|
||||
# value_after_depreciation - current Asset value
|
||||
if self.docstatus == 1 and finance_book.value_after_depreciation:
|
||||
value_after_depreciation = flt(finance_book.value_after_depreciation)
|
||||
else:
|
||||
value_after_depreciation = flt(self.gross_purchase_amount) - flt(
|
||||
self.opening_accumulated_depreciation
|
||||
)
|
||||
|
||||
return value_after_depreciation
|
||||
|
||||
# depreciation schedules need to be cleared before modification due to increase in asset life/asset sales
|
||||
# JE: Journal Entry, FB: Finance Book
|
||||
@@ -413,7 +419,6 @@ class Asset(AccountsController):
|
||||
depr_schedule = []
|
||||
|
||||
for schedule in self.get("schedules"):
|
||||
|
||||
# to update start when there are JEs linked with all the schedule rows corresponding to an FB
|
||||
if len(start) == (int(schedule.finance_book_id) - 2):
|
||||
start.append(num_of_depreciations_completed)
|
||||
@@ -1124,3 +1129,150 @@ def get_depreciation_amount(asset, depreciable_value, row):
|
||||
depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100))
|
||||
|
||||
return depreciation_amount
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def split_asset(asset_name, split_qty):
|
||||
asset = frappe.get_doc("Asset", asset_name)
|
||||
split_qty = cint(split_qty)
|
||||
|
||||
if split_qty >= asset.asset_quantity:
|
||||
frappe.throw(_("Split qty cannot be grater than or equal to asset qty"))
|
||||
|
||||
remaining_qty = asset.asset_quantity - split_qty
|
||||
|
||||
new_asset = create_new_asset_after_split(asset, split_qty)
|
||||
update_existing_asset(asset, remaining_qty)
|
||||
|
||||
return new_asset
|
||||
|
||||
|
||||
def update_existing_asset(asset, remaining_qty):
|
||||
remaining_gross_purchase_amount = flt(
|
||||
(asset.gross_purchase_amount * remaining_qty) / asset.asset_quantity
|
||||
)
|
||||
opening_accumulated_depreciation = flt(
|
||||
(asset.opening_accumulated_depreciation * remaining_qty) / asset.asset_quantity
|
||||
)
|
||||
|
||||
frappe.db.set_value(
|
||||
"Asset",
|
||||
asset.name,
|
||||
{
|
||||
"opening_accumulated_depreciation": opening_accumulated_depreciation,
|
||||
"gross_purchase_amount": remaining_gross_purchase_amount,
|
||||
"asset_quantity": remaining_qty,
|
||||
},
|
||||
)
|
||||
|
||||
for finance_book in asset.get("finance_books"):
|
||||
value_after_depreciation = flt(
|
||||
(finance_book.value_after_depreciation * remaining_qty) / asset.asset_quantity
|
||||
)
|
||||
expected_value_after_useful_life = flt(
|
||||
(finance_book.expected_value_after_useful_life * remaining_qty) / asset.asset_quantity
|
||||
)
|
||||
frappe.db.set_value(
|
||||
"Asset Finance Book", finance_book.name, "value_after_depreciation", value_after_depreciation
|
||||
)
|
||||
frappe.db.set_value(
|
||||
"Asset Finance Book",
|
||||
finance_book.name,
|
||||
"expected_value_after_useful_life",
|
||||
expected_value_after_useful_life,
|
||||
)
|
||||
|
||||
accumulated_depreciation = 0
|
||||
|
||||
for term in asset.get("schedules"):
|
||||
depreciation_amount = flt((term.depreciation_amount * remaining_qty) / asset.asset_quantity)
|
||||
frappe.db.set_value(
|
||||
"Depreciation Schedule", term.name, "depreciation_amount", depreciation_amount
|
||||
)
|
||||
accumulated_depreciation += depreciation_amount
|
||||
frappe.db.set_value(
|
||||
"Depreciation Schedule", term.name, "accumulated_depreciation_amount", accumulated_depreciation
|
||||
)
|
||||
|
||||
|
||||
def create_new_asset_after_split(asset, split_qty):
|
||||
new_asset = frappe.copy_doc(asset)
|
||||
new_gross_purchase_amount = flt((asset.gross_purchase_amount * split_qty) / asset.asset_quantity)
|
||||
opening_accumulated_depreciation = flt(
|
||||
(asset.opening_accumulated_depreciation * split_qty) / asset.asset_quantity
|
||||
)
|
||||
|
||||
new_asset.gross_purchase_amount = new_gross_purchase_amount
|
||||
new_asset.opening_accumulated_depreciation = opening_accumulated_depreciation
|
||||
new_asset.asset_quantity = split_qty
|
||||
new_asset.split_from = asset.name
|
||||
accumulated_depreciation = 0
|
||||
|
||||
for finance_book in new_asset.get("finance_books"):
|
||||
finance_book.value_after_depreciation = flt(
|
||||
(finance_book.value_after_depreciation * split_qty) / asset.asset_quantity
|
||||
)
|
||||
finance_book.expected_value_after_useful_life = flt(
|
||||
(finance_book.expected_value_after_useful_life * split_qty) / asset.asset_quantity
|
||||
)
|
||||
|
||||
for term in new_asset.get("schedules"):
|
||||
depreciation_amount = flt((term.depreciation_amount * split_qty) / asset.asset_quantity)
|
||||
term.depreciation_amount = depreciation_amount
|
||||
accumulated_depreciation += depreciation_amount
|
||||
term.accumulated_depreciation_amount = accumulated_depreciation
|
||||
|
||||
new_asset.submit()
|
||||
new_asset.set_status()
|
||||
|
||||
for term in new_asset.get("schedules"):
|
||||
# Update references in JV
|
||||
if term.journal_entry:
|
||||
add_reference_in_jv_on_split(
|
||||
term.journal_entry, new_asset.name, asset.name, term.depreciation_amount
|
||||
)
|
||||
|
||||
return new_asset
|
||||
|
||||
|
||||
def add_reference_in_jv_on_split(entry_name, new_asset_name, old_asset_name, depreciation_amount):
|
||||
journal_entry = frappe.get_doc("Journal Entry", entry_name)
|
||||
entries_to_add = []
|
||||
idx = len(journal_entry.get("accounts")) + 1
|
||||
|
||||
for account in journal_entry.get("accounts"):
|
||||
if account.reference_name == old_asset_name:
|
||||
entries_to_add.append(frappe.copy_doc(account).as_dict())
|
||||
if account.credit:
|
||||
account.credit = account.credit - depreciation_amount
|
||||
account.credit_in_account_currency = (
|
||||
account.credit_in_account_currency - account.exchange_rate * depreciation_amount
|
||||
)
|
||||
elif account.debit:
|
||||
account.debit = account.debit - depreciation_amount
|
||||
account.debit_in_account_currency = (
|
||||
account.debit_in_account_currency - account.exchange_rate * depreciation_amount
|
||||
)
|
||||
|
||||
for entry in entries_to_add:
|
||||
entry.reference_name = new_asset_name
|
||||
if entry.credit:
|
||||
entry.credit = depreciation_amount
|
||||
entry.credit_in_account_currency = entry.exchange_rate * depreciation_amount
|
||||
elif entry.debit:
|
||||
entry.debit = depreciation_amount
|
||||
entry.debit_in_account_currency = entry.exchange_rate * depreciation_amount
|
||||
|
||||
entry.idx = idx
|
||||
idx += 1
|
||||
|
||||
journal_entry.append("accounts", entry)
|
||||
|
||||
journal_entry.flags.ignore_validate_update_after_submit = True
|
||||
journal_entry.save()
|
||||
|
||||
# Repost GL Entries
|
||||
journal_entry.docstatus = 2
|
||||
journal_entry.make_gl_entries(1)
|
||||
journal_entry.docstatus = 1
|
||||
journal_entry.make_gl_entries()
|
||||
|
||||
@@ -7,7 +7,7 @@ import frappe
|
||||
from frappe.utils import add_days, add_months, cstr, flt, get_last_day, getdate, nowdate
|
||||
|
||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||
from erpnext.assets.doctype.asset.asset import make_sales_invoice
|
||||
from erpnext.assets.doctype.asset.asset import make_sales_invoice, split_asset
|
||||
from erpnext.assets.doctype.asset.depreciation import (
|
||||
post_depreciation_entries,
|
||||
restore_asset,
|
||||
@@ -232,6 +232,57 @@ class TestAsset(AssetSetup):
|
||||
si.cancel()
|
||||
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
|
||||
|
||||
def test_asset_splitting(self):
|
||||
asset = create_asset(
|
||||
calculate_depreciation=1,
|
||||
asset_quantity=10,
|
||||
available_for_use_date="2020-01-01",
|
||||
purchase_date="2020-01-01",
|
||||
expected_value_after_useful_life=0,
|
||||
total_number_of_depreciations=6,
|
||||
number_of_depreciations_booked=1,
|
||||
frequency_of_depreciation=10,
|
||||
depreciation_start_date="2021-01-01",
|
||||
opening_accumulated_depreciation=20000,
|
||||
gross_purchase_amount=120000,
|
||||
submit=1,
|
||||
)
|
||||
|
||||
post_depreciation_entries(date="2021-01-01")
|
||||
|
||||
self.assertEqual(asset.asset_quantity, 10)
|
||||
self.assertEqual(asset.gross_purchase_amount, 120000)
|
||||
self.assertEqual(asset.opening_accumulated_depreciation, 20000)
|
||||
|
||||
new_asset = split_asset(asset.name, 2)
|
||||
asset.load_from_db()
|
||||
|
||||
self.assertEqual(new_asset.asset_quantity, 2)
|
||||
self.assertEqual(new_asset.gross_purchase_amount, 24000)
|
||||
self.assertEqual(new_asset.opening_accumulated_depreciation, 4000)
|
||||
self.assertEqual(new_asset.split_from, asset.name)
|
||||
self.assertEqual(new_asset.schedules[0].depreciation_amount, 4000)
|
||||
self.assertEqual(new_asset.schedules[1].depreciation_amount, 4000)
|
||||
|
||||
self.assertEqual(asset.asset_quantity, 8)
|
||||
self.assertEqual(asset.gross_purchase_amount, 96000)
|
||||
self.assertEqual(asset.opening_accumulated_depreciation, 16000)
|
||||
self.assertEqual(asset.schedules[0].depreciation_amount, 16000)
|
||||
self.assertEqual(asset.schedules[1].depreciation_amount, 16000)
|
||||
|
||||
journal_entry = asset.schedules[0].journal_entry
|
||||
|
||||
jv = frappe.get_doc("Journal Entry", journal_entry)
|
||||
self.assertEqual(jv.accounts[0].credit_in_account_currency, 16000)
|
||||
self.assertEqual(jv.accounts[1].debit_in_account_currency, 16000)
|
||||
self.assertEqual(jv.accounts[2].credit_in_account_currency, 4000)
|
||||
self.assertEqual(jv.accounts[3].debit_in_account_currency, 4000)
|
||||
|
||||
self.assertEqual(jv.accounts[0].reference_name, asset.name)
|
||||
self.assertEqual(jv.accounts[1].reference_name, asset.name)
|
||||
self.assertEqual(jv.accounts[2].reference_name, new_asset.name)
|
||||
self.assertEqual(jv.accounts[3].reference_name, new_asset.name)
|
||||
|
||||
def test_expense_head(self):
|
||||
pr = make_purchase_receipt(
|
||||
item_code="Macbook Pro", qty=2, rate=200000.0, location="Test Location"
|
||||
@@ -1291,6 +1342,7 @@ def create_asset(**args):
|
||||
"location": args.location or "Test Location",
|
||||
"asset_owner": args.asset_owner or "Company",
|
||||
"is_existing_asset": args.is_existing_asset or 1,
|
||||
"asset_quantity": args.get("asset_quantity") or 1,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -627,7 +627,7 @@ class BuyingController(StockController, Subcontracting):
|
||||
}
|
||||
)
|
||||
|
||||
validate_expense_against_budget(args)
|
||||
validate_expense_against_budget(args)
|
||||
|
||||
def process_fixed_asset(self):
|
||||
if self.doctype == "Purchase Invoice" and not self.update_stock:
|
||||
|
||||
@@ -79,11 +79,11 @@ erpnext.setup.slides_settings = [
|
||||
slide.get_input("company_name").on("change", function () {
|
||||
var parts = slide.get_input("company_name").val().split(" ");
|
||||
var abbr = $.map(parts, function (p) { return p ? p.substr(0, 1) : null }).join("");
|
||||
slide.get_field("company_abbr").set_value(abbr.slice(0, 5).toUpperCase());
|
||||
slide.get_field("company_abbr").set_value(abbr.slice(0, 10).toUpperCase());
|
||||
}).val(frappe.boot.sysdefaults.company_name || "").trigger("change");
|
||||
|
||||
slide.get_input("company_abbr").on("change", function () {
|
||||
if (slide.get_input("company_abbr").val().length > 5) {
|
||||
if (slide.get_input("company_abbr").val().length > 10) {
|
||||
frappe.msgprint(__("Company Abbreviation cannot have more than 5 characters"));
|
||||
slide.get_field("company_abbr").set_value("");
|
||||
}
|
||||
@@ -97,7 +97,7 @@ erpnext.setup.slides_settings = [
|
||||
if (!this.values.company_abbr) {
|
||||
return false;
|
||||
}
|
||||
if (this.values.company_abbr.length > 5) {
|
||||
if (this.values.company_abbr.length > 10) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user