diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 436b2c3907883386f0c16f84317f0001c0d90b26..24b82b29cb6496bf228ebbe1aa1b8fcd613734ff 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -197,7 +197,8 @@ class JournalEntry(AccountsController):
self.update_asset_value()
self.update_inter_company_jv()
self.update_invoice_discounting()
- self.update_unreconciled_amount()
+ self.update_unreconciled_amount() # @dokos
+ self.update_booked_depreciation()
def on_update_after_submit(self):
if hasattr(self, "repost_required"):
@@ -231,6 +232,7 @@ class JournalEntry(AccountsController):
self.unlink_inter_company_jv()
self.unlink_asset_adjustment_entry()
self.update_invoice_discounting()
+ self.update_booked_depreciation()
def get_title(self):
return self.pay_to_recd_from or self.accounts[0].account
@@ -443,6 +445,28 @@ class JournalEntry(AccountsController):
if status:
inv_disc_doc.set_status(status=status)
+ def update_booked_depreciation(self):
+ for d in self.get("accounts"):
+ if (
+ self.voucher_type == "Depreciation Entry"
+ and d.reference_type == "Asset"
+ and d.reference_name
+ and frappe.get_cached_value("Account", d.account, "root_type") == "Expense"
+ and d.debit
+ ):
+ asset = frappe.get_doc("Asset", d.reference_name)
+ for fb_row in asset.get("finance_books"):
+ if fb_row.finance_book == self.finance_book:
+ depr_schedule = get_depr_schedule(asset.name, "Active", fb_row.finance_book)
+ total_number_of_booked_depreciations = asset.opening_number_of_booked_depreciations
+ for je in depr_schedule:
+ if je.journal_entry:
+ total_number_of_booked_depreciations += 1
+ fb_row.db_set(
+ "total_number_of_booked_depreciations", total_number_of_booked_depreciations
+ )
+ break
+
def unlink_advance_entry_reference(self):
for d in self.get("accounts"):
if d.is_advance == "Yes" and d.reference_type in ("Sales Invoice", "Purchase Invoice"):
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index cb3ce813b9a10c56b7d84d53b3f5cadc37681599..46dbe0742017f02e46fa8d1e4ea3c739a0da3b7f 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -4,77 +4,77 @@
frappe.provide("erpnext.asset");
frappe.provide("erpnext.accounts.dimensions");
-frappe.ui.form.on('Asset', {
- onload: function(frm) {
- frm.set_query("item_code", function() {
+frappe.ui.form.on("Asset", {
+ onload: function (frm) {
+ frm.set_query("item_code", function () {
return {
- "filters": {
- "is_fixed_asset": 1,
- "is_stock_item": 0
- }
+ filters: {
+ is_fixed_asset: 1,
+ is_stock_item: 0,
+ },
};
});
- frm.set_query("warehouse", function() {
+ frm.set_query("warehouse", function () {
return {
- "filters": {
- "company": frm.doc.company,
- "is_group": 0
- }
+ filters: {
+ company: frm.doc.company,
+ is_group: 0,
+ },
};
});
- frm.set_query("department", function() {
+ frm.set_query("department", function () {
return {
- "filters": {
- "company": frm.doc.company,
- }
+ filters: {
+ company: frm.doc.company,
+ },
};
});
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
- company: function(frm) {
+ company: function (frm) {
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
- setup: function(frm) {
- frm.ignore_doctypes_on_cancel_all = ['Journal Entry'];
+ setup: function (frm) {
+ frm.ignore_doctypes_on_cancel_all = ["Journal Entry"];
frm.make_methods = {
- 'Asset Movement': () => {
+ "Asset Movement": () => {
frappe.call({
- method: "erpnext.assets.doctype.asset.asset.make_asset_movement",
- freeze: true,
- args:{
- "assets": [{ name: cur_frm.doc.name }]
- },
- callback: function (r) {
- if (r.message) {
- var doc = frappe.model.sync(r.message)[0];
- frappe.set_route("Form", doc.doctype, doc.name);
- }
- }
- });
+ method: "erpnext.assets.doctype.asset.asset.make_asset_movement",
+ freeze: true,
+ args: {
+ assets: [{ name: frm.doc.name }],
+ },
+ callback: function (r) {
+ if (r.message) {
+ var doc = frappe.model.sync(r.message)[0];
+ frappe.set_route("Form", doc.doctype, doc.name);
+ }
+ },
+ });
},
- }
+ };
frm.set_query("purchase_receipt", (doc) => {
return {
query: "erpnext.controllers.queries.get_purchase_receipts",
- filters: { item_code: doc.item_code }
- }
+ filters: { item_code: doc.item_code },
+ };
});
frm.set_query("purchase_invoice", (doc) => {
return {
query: "erpnext.controllers.queries.get_purchase_invoices",
- filters: { item_code: doc.item_code }
- }
+ filters: { item_code: doc.item_code },
+ };
});
},
- refresh: function(frm) {
+ refresh: function (frm) {
frappe.ui.form.trigger("Asset", "is_existing_asset");
frm.toggle_display("next_depreciation_date", frm.doc.docstatus < 1);
@@ -114,41 +114,65 @@ frappe.ui.form.on('Asset', {
}
if (frm.doc.maintenance_required && !frm.doc.maintenance_schedule) {
- frm.add_custom_button(__("Maintain Asset"), function() {
- frm.trigger("create_asset_maintenance");
- }, __("Manage"));
+ frm.add_custom_button(
+ __("Maintain Asset"),
+ function () {
+ frm.trigger("create_asset_maintenance");
+ },
+ __("Manage")
+ );
}
- frm.add_custom_button(__("Repair Asset"), function() {
- frm.trigger("create_asset_repair");
- }, __("Manage"));
+ frm.add_custom_button(
+ __("Repair Asset"),
+ function () {
+ frm.trigger("create_asset_repair");
+ },
+ __("Manage")
+ );
- frm.add_custom_button(__("Split Asset"), function() {
- frm.trigger("split_asset");
- }, __("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");
- }, __("Manage"));
+ if (frm.doc.status != "Fully Depreciated") {
+ frm.add_custom_button(
+ __("Adjust Asset Value"),
+ function () {
+ frm.trigger("create_asset_value_adjustment");
+ },
+ __("Manage")
+ );
}
if (!frm.doc.calculate_depreciation) {
- frm.add_custom_button(__("Create Depreciation Entry"), function() {
- frm.trigger("make_journal_entry");
- }, __("Manage"));
+ frm.add_custom_button(
+ __("Create Depreciation Entry"),
+ function () {
+ frm.trigger("make_journal_entry");
+ },
+ __("Manage")
+ );
}
if (frm.doc.purchase_receipt || !frm.doc.is_existing_asset) {
- frm.add_custom_button(__("View General Ledger"), function() {
- frappe.route_options = {
- "voucher_no": frm.doc.name,
- "from_date": frm.doc.available_for_use_date,
- "to_date": frm.doc.available_for_use_date,
- "company": frm.doc.company
- };
- frappe.set_route("query-report", "General Ledger");
- }, __("Manage"));
+ frm.add_custom_button(
+ __("View General Ledger"),
+ function () {
+ frappe.route_options = {
+ voucher_no: frm.doc.name,
+ from_date: frm.doc.available_for_use_date,
+ to_date: frm.doc.available_for_use_date,
+ company: frm.doc.company,
+ };
+ frappe.set_route("query-report", "General Ledger");
+ },
+ __("Manage")
+ );
}
if (frm.doc.depr_entry_posting_status === "Failed") {
@@ -164,21 +188,26 @@ frappe.ui.form.on('Asset', {
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
if (frm.doc.is_composite_asset && !frm.doc.capitalized_in) {
- $('.primary-action').prop('hidden', true);
- $('.form-message').text('Capitalize this asset to confirm');
+ $(".primary-action").prop("hidden", true);
+ $(".form-message").text("Capitalize this asset to confirm");
- frm.add_custom_button(__("Capitalize Asset"), function() {
+ frm.add_custom_button(__("Capitalize Asset"), function () {
frm.trigger("create_asset_capitalization");
});
}
}
if (frm.doc.docstatus === 1) {
- frm.add_custom_button(__('Accounting Journal Adjustment'), () => {
+ frm.add_custom_button(
+ __("Accounting Journal Adjustment"),
+ () => {
frappe.require("assets/erpnext/js/accounting_journal_adjustment.js", () => {
- new erpnext.journalAdjustment({doctype: frm.doctype, docnames: [frm.docname]})
+ new erpnext.journalAdjustment({ doctype: frm.doctype, docnames: [frm.docname] });
});
- }, __('Create'), true);
+ },
+ __("Create"),
+ true
+ );
}
},
@@ -195,146 +224,192 @@ frappe.ui.form.on('Asset', {
frm.dashboard.set_headline_alert(alert);
},
- toggle_reference_doc: function(frm) {
+ toggle_reference_doc: function (frm) {
if (frm.doc.purchase_receipt && frm.doc.purchase_invoice && frm.doc.docstatus === 1) {
- frm.set_df_property('purchase_invoice', 'read_only', 1);
- frm.set_df_property('purchase_receipt', 'read_only', 1);
- }
- else if (frm.doc.is_existing_asset || frm.doc.is_composite_asset) {
- frm.toggle_reqd('purchase_receipt', 0);
- frm.toggle_reqd('purchase_invoice', 0);
- }
- else if (frm.doc.purchase_receipt) {
+ frm.set_df_property("purchase_invoice", "read_only", 1);
+ frm.set_df_property("purchase_receipt", "read_only", 1);
+ } else if (frm.doc.is_existing_asset || frm.doc.is_composite_asset) {
+ frm.toggle_reqd("purchase_receipt", 0);
+ frm.toggle_reqd("purchase_invoice", 0);
+ } else if (frm.doc.purchase_receipt) {
// if purchase receipt link is set then set PI disabled
- frm.toggle_reqd('purchase_invoice', 0);
- frm.set_df_property('purchase_invoice', 'read_only', 1);
- }
- else if (frm.doc.purchase_invoice) {
+ frm.toggle_reqd("purchase_invoice", 0);
+ frm.set_df_property("purchase_invoice", "read_only", 1);
+ } else if (frm.doc.purchase_invoice) {
// if purchase invoice link is set then set PR disabled
- frm.toggle_reqd('purchase_receipt', 0);
- frm.set_df_property('purchase_receipt', 'read_only', 1);
- }
- else {
- frm.toggle_reqd('purchase_receipt', 1);
- frm.set_df_property('purchase_receipt', 'read_only', 0);
- frm.toggle_reqd('purchase_invoice', 1);
- frm.set_df_property('purchase_invoice', 'read_only', 0);
+ frm.toggle_reqd("purchase_receipt", 0);
+ frm.set_df_property("purchase_receipt", "read_only", 1);
+ } else {
+ frm.toggle_reqd("purchase_receipt", 1);
+ frm.set_df_property("purchase_receipt", "read_only", 0);
+ frm.toggle_reqd("purchase_invoice", 1);
+ frm.set_df_property("purchase_invoice", "read_only", 0);
}
},
- make_journal_entry: function(frm) {
+ make_journal_entry: function (frm) {
frappe.call({
method: "erpnext.assets.doctype.asset.asset.make_journal_entry",
args: {
- asset_name: frm.doc.name
+ asset_name: frm.doc.name,
},
- callback: function(r) {
+ callback: function (r) {
if (r.message) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
}
- }
- })
+ },
+ });
},
- render_depreciation_schedule_view: function(frm, depr_schedule) {
+ render_depreciation_schedule_view: function (frm, asset_depr_schedule_doc) {
let wrapper = $(frm.fields_dict["depreciation_schedule_view"].wrapper).empty();
let data = [];
- depr_schedule.forEach((sch) => {
+ asset_depr_schedule_doc.depreciation_schedule.forEach((sch) => {
const row = [
- sch['idx'],
- frappe.format(sch['schedule_date'], { fieldtype: 'Date' }),
- frappe.format(sch['depreciation_amount'], { fieldtype: 'Currency' }),
- frappe.format(sch['accumulated_depreciation_amount'], { fieldtype: 'Currency' }),
- sch['journal_entry'] || ''
+ sch["idx"],
+ frappe.format(sch["schedule_date"], { fieldtype: "Date" }),
+ frappe.format(sch["depreciation_amount"], { fieldtype: "Currency" }),
+ frappe.format(sch["accumulated_depreciation_amount"], { fieldtype: "Currency" }),
+ sch["journal_entry"] || "",
];
+
+ if (asset_depr_schedule_doc.shift_based) {
+ row.push(sch["shift"]);
+ }
+
data.push(row);
});
+ let columns = [
+ { name: __("No."), editable: false, resizable: false, format: (value) => value, width: 60 },
+ { name: __("Schedule Date"), editable: false, resizable: false, width: 270 },
+ { name: __("Depreciation Amount"), editable: false, resizable: false, width: 164 },
+ { name: __("Accumulated Depreciation Amount"), editable: false, resizable: false, width: 164 },
+ ];
+
+ if (asset_depr_schedule_doc.shift_based) {
+ columns.push({
+ name: __("Journal Entry"),
+ editable: false,
+ resizable: false,
+ format: (value) => `${value}`,
+ width: 245,
+ });
+ columns.push({ name: __("Shift"), editable: false, resizable: false, width: 59 });
+ } else {
+ columns.push({
+ name: __("Journal Entry"),
+ editable: false,
+ resizable: false,
+ format: (value) => `${value}`,
+ width: 304,
+ });
+ }
+
let datatable = new frappe.DataTable(wrapper.get(0), {
- columns: [
- {name: __("No."), editable: false, resizable: false, format: value => value, width: 60},
- {name: __("Schedule Date"), editable: false, resizable: false, width: 270},
- {name: __("Depreciation Amount"), editable: false, resizable: false, width: 164},
- {name: __("Accumulated Depreciation Amount"), editable: false, resizable: false, width: 164},
- {name: __("Journal Entry"), editable: false, resizable: false, format: value => `${value}`, width: 304}
- ],
+ columns: columns,
data: data,
layout: "fluid",
serialNoColumn: false,
checkboxColumn: true,
- cellHeight: 35
+ cellHeight: 35,
});
- datatable.style.setStyle(`.dt-scrollable`, {'font-size': '0.75rem', 'margin-bottom': '1rem', 'margin-left': '0.35rem', 'margin-right': '0.35rem'});
- datatable.style.setStyle(`.dt-header`, {'margin-left': '0.35rem', 'margin-right': '0.35rem'});
- datatable.style.setStyle(`.dt-cell--header .dt-cell__content`, {'color': 'var(--gray-600)', 'font-size': 'var(--text-sm)'});
- datatable.style.setStyle(`.dt-cell`, {'color': 'var(--text-color)'});
- datatable.style.setStyle(`.dt-cell--col-1`, {'text-align': 'center'});
- datatable.style.setStyle(`.dt-cell--col-2`, {'font-weight': 600});
- datatable.style.setStyle(`.dt-cell--col-3`, {'font-weight': 600});
+ datatable.style.setStyle(`.dt-scrollable`, {
+ "font-size": "0.75rem",
+ "margin-bottom": "1rem",
+ "margin-left": "0.35rem",
+ "margin-right": "0.35rem",
+ });
+ datatable.style.setStyle(`.dt-header`, { "margin-left": "0.35rem", "margin-right": "0.35rem" });
+ datatable.style.setStyle(`.dt-cell--header .dt-cell__content`, {
+ color: "var(--gray-600)",
+ "font-size": "var(--text-sm)",
+ });
+ datatable.style.setStyle(`.dt-cell`, { color: "var(--text-color)" });
+ datatable.style.setStyle(`.dt-cell--col-1`, { "text-align": "center" });
+ datatable.style.setStyle(`.dt-cell--col-2`, { "font-weight": 600 });
+ datatable.style.setStyle(`.dt-cell--col-3`, { "font-weight": 600 });
},
- setup_chart_and_depr_schedule_view: async function(frm) {
- if(frm.doc.finance_books.length > 1) {
- return
+ setup_chart_and_depr_schedule_view: async function (frm) {
+ if (frm.doc.finance_books.length > 1) {
+ return;
}
- var x_intervals = [frappe.format(frm.doc.purchase_date, { fieldtype: 'Date' })];
+ var x_intervals = [frappe.format(frm.doc.purchase_date, { fieldtype: "Date" })];
var asset_values = [frm.doc.gross_purchase_amount];
- if(frm.doc.calculate_depreciation) {
- if(frm.doc.opening_accumulated_depreciation) {
+ if (frm.doc.calculate_depreciation) {
+ if (frm.doc.opening_accumulated_depreciation) {
var depreciation_date = frappe.datetime.add_months(
frm.doc.finance_books[0].depreciation_start_date,
-1 * frm.doc.finance_books[0].frequency_of_depreciation
);
- x_intervals.push(frappe.format(depreciation_date, { fieldtype: 'Date' }));
- asset_values.push(flt(frm.doc.gross_purchase_amount - frm.doc.opening_accumulated_depreciation, precision('gross_purchase_amount')));
+ x_intervals.push(frappe.format(depreciation_date, { fieldtype: "Date" }));
+ asset_values.push(
+ flt(
+ frm.doc.gross_purchase_amount - frm.doc.opening_accumulated_depreciation,
+ precision("gross_purchase_amount")
+ )
+ );
}
- let depr_schedule = (await frappe.call(
- "erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule.get_depr_schedule",
- {
- asset_name: frm.doc.name,
- status: "Active",
- finance_book: frm.doc.finance_books[0].finance_book || null
- }
- )).message;
-
- $.each(depr_schedule || [], function(i, v) {
- x_intervals.push(frappe.format(v.schedule_date, { fieldtype: 'Date' }));
- var asset_value = flt(frm.doc.gross_purchase_amount - v.accumulated_depreciation_amount, precision('gross_purchase_amount'));
- if(v.journal_entry) {
+ let asset_depr_schedule_doc = (
+ await frappe.call(
+ "erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule.get_asset_depr_schedule_doc",
+ {
+ asset_name: frm.doc.name,
+ status: "Active",
+ finance_book: frm.doc.finance_books[0].finance_book || null,
+ }
+ )
+ ).message;
+
+ $.each(asset_depr_schedule_doc.depreciation_schedule || [], function (i, v) {
+ x_intervals.push(frappe.format(v.schedule_date, { fieldtype: "Date" }));
+ var asset_value = flt(
+ frm.doc.gross_purchase_amount - v.accumulated_depreciation_amount,
+ precision("gross_purchase_amount")
+ );
+ if (v.journal_entry) {
asset_values.push(asset_value);
} else {
if (["Scrapped", "Sold"].includes(frm.doc.status)) {
asset_values.push(null);
} else {
- asset_values.push(asset_value)
+ asset_values.push(asset_value);
}
}
});
frm.toggle_display(["depreciation_schedule_view"], 1);
- frm.events.render_depreciation_schedule_view(frm, depr_schedule);
+ frm.events.render_depreciation_schedule_view(frm, asset_depr_schedule_doc);
} else {
- if(frm.doc.opening_accumulated_depreciation) {
- x_intervals.push(frappe.format(frm.doc.creation.split(" ")[0], { fieldtype: 'Date' }));
- asset_values.push(flt(frm.doc.gross_purchase_amount - frm.doc.opening_accumulated_depreciation, precision('gross_purchase_amount')));
+ if (frm.doc.opening_accumulated_depreciation) {
+ x_intervals.push(frappe.format(frm.doc.creation.split(" ")[0], { fieldtype: "Date" }));
+ asset_values.push(
+ flt(
+ frm.doc.gross_purchase_amount - frm.doc.opening_accumulated_depreciation,
+ precision("gross_purchase_amount")
+ )
+ );
}
- let depr_entries = (await frappe.call({
- method: "get_manual_depreciation_entries",
- doc: frm.doc,
- })).message;
-
- $.each(depr_entries || [], function(i, v) {
- x_intervals.push(frappe.format(v.posting_date, { fieldtype: 'Date' }));
- let last_asset_value = asset_values[asset_values.length - 1]
- asset_values.push(flt(last_asset_value - v.value, precision('gross_purchase_amount')));
+ let depr_entries = (
+ await frappe.call({
+ method: "get_manual_depreciation_entries",
+ doc: frm.doc,
+ })
+ ).message;
+
+ $.each(depr_entries || [], function (i, v) {
+ x_intervals.push(frappe.format(v.posting_date, { fieldtype: "Date" }));
+ let last_asset_value = asset_values[asset_values.length - 1];
+ asset_values.push(flt(last_asset_value - v.value, precision("gross_purchase_amount")));
});
}
@@ -347,145 +422,146 @@ frappe.ui.form.on('Asset', {
title: "Asset Value",
data: {
labels: x_intervals,
- datasets: [{
- color: 'green',
- values: asset_values,
- formatted: asset_values.map(d => d?.toFixed(2))
- }]
+ datasets: [
+ {
+ color: "green",
+ values: asset_values,
+ formatted: asset_values.map((d) => d?.toFixed(2)),
+ },
+ ],
},
- type: 'line'
+ type: "line",
});
},
-
- item_code: function(frm) {
- if(frm.doc.item_code && frm.doc.calculate_depreciation && frm.doc.gross_purchase_amount) {
- frm.trigger('set_finance_book');
+ item_code: function (frm) {
+ if (frm.doc.item_code && frm.doc.calculate_depreciation && frm.doc.gross_purchase_amount) {
+ frm.trigger("set_finance_book");
} else {
- frm.set_value('finance_books', []);
+ frm.set_value("finance_books", []);
}
},
- set_finance_book: function(frm) {
+ set_finance_book: function (frm) {
frappe.call({
method: "erpnext.assets.doctype.asset.asset.get_item_details",
args: {
item_code: frm.doc.item_code,
asset_category: frm.doc.asset_category,
- gross_purchase_amount: frm.doc.gross_purchase_amount
+ gross_purchase_amount: frm.doc.gross_purchase_amount,
},
- callback: function(r, rt) {
- if(r.message) {
- frm.set_value('finance_books', r.message);
+ callback: function (r, rt) {
+ if (r.message) {
+ frm.set_value("finance_books", r.message);
}
- }
- })
+ },
+ });
},
- is_existing_asset: function(frm) {
+ is_existing_asset: function (frm) {
frm.trigger("toggle_reference_doc");
},
- is_composite_asset: function(frm) {
- if(frm.doc.is_composite_asset) {
- frm.set_value('gross_purchase_amount', 0);
- frm.set_df_property('gross_purchase_amount', 'read_only', 1);
+ is_composite_asset: function (frm) {
+ if (frm.doc.is_composite_asset) {
+ frm.set_value("gross_purchase_amount", 0);
+ frm.set_df_property("gross_purchase_amount", "read_only", 1);
} else {
- frm.set_df_property('gross_purchase_amount', 'read_only', 0);
+ frm.set_df_property("gross_purchase_amount", "read_only", 0);
}
frm.trigger("toggle_reference_doc");
},
- make_sales_invoice: function(frm) {
+ make_sales_invoice: function (frm) {
frappe.call({
args: {
- "asset": frm.doc.name,
- "item_code": frm.doc.item_code,
- "company": frm.doc.company,
- "serial_no": frm.doc.serial_no
+ asset: frm.doc.name,
+ item_code: frm.doc.item_code,
+ company: frm.doc.company,
+ serial_no: frm.doc.serial_no,
},
method: "erpnext.assets.doctype.asset.asset.make_sales_invoice",
- callback: function(r) {
+ callback: function (r) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
- })
+ },
+ });
},
- create_asset_maintenance: function(frm) {
+ create_asset_maintenance: function (frm) {
frappe.call({
args: {
- "asset": frm.doc.name,
- "item_code": frm.doc.item_code,
- "item_name": frm.doc.item_name,
- "asset_category": frm.doc.asset_category,
- "company": frm.doc.company
+ asset: frm.doc.name,
+ item_code: frm.doc.item_code,
+ item_name: frm.doc.item_name,
+ asset_category: frm.doc.asset_category,
+ company: frm.doc.company,
},
method: "erpnext.assets.doctype.asset.asset.create_asset_maintenance",
- callback: function(r) {
+ callback: function (r) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
- })
+ },
+ });
},
- create_asset_repair: function(frm) {
+ create_asset_repair: function (frm) {
frappe.call({
args: {
- "asset": frm.doc.name,
- "asset_name": frm.doc.asset_name
+ asset: frm.doc.name,
+ asset_name: frm.doc.asset_name,
},
method: "erpnext.assets.doctype.asset.asset.create_asset_repair",
- callback: function(r) {
+ callback: function (r) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
+ },
});
},
- create_asset_capitalization: function(frm) {
+ create_asset_capitalization: function (frm) {
frappe.call({
args: {
- "asset": frm.doc.name,
+ asset: frm.doc.name,
},
method: "erpnext.assets.doctype.asset.asset.create_asset_capitalization",
- callback: function(r) {
+ callback: function (r) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
+ },
});
},
- split_asset: function(frm) {
- const title = __('Split Asset');
+ split_asset: function (frm) {
+ const title = __("Split Asset");
const fields = [
{
- fieldname: 'split_qty',
- fieldtype: 'Int',
- label: __('Split Qty'),
- reqd: 1
- }
+ fieldname: "split_qty",
+ fieldtype: "Int",
+ label: __("Split Qty"),
+ reqd: 1,
+ },
];
let dialog = new frappe.ui.Dialog({
title: title,
- fields: fields
+ fields: fields,
});
- dialog.set_primary_action(__('Split'), function() {
+ 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)
+ asset_name: frm.doc.name,
+ split_qty: cint(dialog_data.split_qty),
},
method: "erpnext.assets.doctype.asset.asset.split_asset",
- callback: function(r) {
+ callback: function (r) {
let doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
+ },
});
dialog.hide();
@@ -494,23 +570,23 @@ frappe.ui.form.on('Asset', {
dialog.show();
},
- create_asset_value_adjustment: function(frm) {
+ create_asset_value_adjustment: function (frm) {
frappe.call({
args: {
- "asset": frm.doc.name,
- "asset_category": frm.doc.asset_category,
- "company": frm.doc.company
+ asset: frm.doc.name,
+ asset_category: frm.doc.asset_category,
+ company: frm.doc.company,
},
method: "erpnext.assets.doctype.asset.asset.create_asset_value_adjustment",
freeze: 1,
- callback: function(r) {
+ callback: function (r) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
- })
+ },
+ });
},
- calculate_depreciation: function(frm) {
+ calculate_depreciation: function (frm) {
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
if (frm.doc.item_code && frm.doc.calculate_depreciation && frm.doc.gross_purchase_amount) {
frm.trigger("set_finance_book");
@@ -519,69 +595,69 @@ frappe.ui.form.on('Asset', {
}
},
- gross_purchase_amount: function(frm) {
+ gross_purchase_amount: function (frm) {
if (frm.doc.finance_books) {
- frm.doc.finance_books.forEach(d => {
+ frm.doc.finance_books.forEach((d) => {
frm.events.set_depreciation_rate(frm, d);
- })
+ });
}
},
purchase_receipt: (frm) => {
- frm.trigger('toggle_reference_doc');
+ frm.trigger("toggle_reference_doc");
if (frm.doc.purchase_receipt) {
if (frm.doc.item_code) {
- frappe.db.get_doc('Purchase Receipt', frm.doc.purchase_receipt).then(pr_doc => {
- frm.events.set_values_from_purchase_doc(frm, 'Purchase Receipt', pr_doc)
+ frappe.db.get_doc("Purchase Receipt", frm.doc.purchase_receipt).then((pr_doc) => {
+ frm.events.set_values_from_purchase_doc(frm, "Purchase Receipt", pr_doc);
});
} else {
- frm.set_value('purchase_receipt', '');
+ frm.set_value("purchase_receipt", "");
frappe.msgprint({
- title: __('Not Allowed'),
- message: __("Please select Item Code first")
+ title: __("Not Allowed"),
+ message: __("Please select Item Code first"),
});
}
}
},
purchase_invoice: (frm) => {
- frm.trigger('toggle_reference_doc');
+ frm.trigger("toggle_reference_doc");
if (frm.doc.purchase_invoice) {
if (frm.doc.item_code) {
- frappe.db.get_doc('Purchase Invoice', frm.doc.purchase_invoice).then(pi_doc => {
- frm.events.set_values_from_purchase_doc(frm, 'Purchase Invoice', pi_doc)
+ frappe.db.get_doc("Purchase Invoice", frm.doc.purchase_invoice).then((pi_doc) => {
+ frm.events.set_values_from_purchase_doc(frm, "Purchase Invoice", pi_doc);
});
} else {
- frm.set_value('purchase_invoice', '');
+ frm.set_value("purchase_invoice", "");
frappe.msgprint({
- title: __('Not Allowed'),
- message: __("Please select Item Code first")
+ title: __("Not Allowed"),
+ message: __("Please select Item Code first"),
});
}
}
},
- set_values_from_purchase_doc: function(frm, doctype, purchase_doc) {
- frm.set_value('company', purchase_doc.company);
+ set_values_from_purchase_doc: function (frm, doctype, purchase_doc) {
+ frm.set_value("company", purchase_doc.company);
if (purchase_doc.bill_date) {
- frm.set_value('purchase_date', purchase_doc.bill_date);
+ frm.set_value("purchase_date", purchase_doc.bill_date);
} else {
- frm.set_value('purchase_date', purchase_doc.posting_date);
+ frm.set_value("purchase_date", purchase_doc.posting_date);
}
if (!frm.doc.is_existing_asset && !frm.doc.available_for_use_date) {
- frm.set_value('available_for_use_date', frm.doc.purchase_date);
+ frm.set_value("available_for_use_date", frm.doc.purchase_date);
}
- const item = purchase_doc.items.find(item => item.item_code === frm.doc.item_code);
+ const item = purchase_doc.items.find((item) => item.item_code === frm.doc.item_code);
if (!item) {
- let doctype_field = frappe.scrub(doctype)
- frm.set_value(doctype_field, '');
+ let doctype_field = frappe.scrub(doctype);
+ frm.set_value(doctype_field, "");
frappe.msgprint({
- title: __('Invalid {0}', [__(doctype)]),
- message: __('The selected {0} does not contain the selected Asset Item.', [__(doctype)]),
- indicator: 'red'
+ title: __("Invalid {0}", [__(doctype)]),
+ message: __("The selected {0} does not contain the selected Asset Item.", [__(doctype)]),
+ indicator: "red",
});
}
- frappe.db.get_value('Item', item.item_code, 'is_grouped_asset', (r) => {
+ frappe.db.get_value("Item", item.item_code, "is_grouped_asset", (r) => {
var asset_quantity = r.is_grouped_asset ? item.qty : 1;
var purchase_amount = flt(
item.valuation_rate * asset_quantity,
@@ -598,129 +674,166 @@ frappe.ui.form.on('Asset', {
});
},
- set_depreciation_rate: function(frm, row) {
- if (row.total_number_of_depreciations && row.frequency_of_depreciation
- && row.expected_value_after_useful_life) {
+ set_depreciation_rate: function (frm, row) {
+ if (
+ row.total_number_of_depreciations &&
+ row.frequency_of_depreciation &&
+ row.expected_value_after_useful_life
+ ) {
frappe.call({
method: "get_depreciation_rate",
doc: frm.doc,
args: row,
- callback: function(r) {
+ callback: function (r) {
if (r.message) {
frappe.flags.dont_change_rate = true;
- frappe.model.set_value(row.doctype, row.name,
- "rate_of_depreciation", flt(r.message, precision("rate_of_depreciation", row)));
+ frappe.model.set_value(
+ row.doctype,
+ row.name,
+ "rate_of_depreciation",
+ flt(r.message, precision("rate_of_depreciation", row))
+ );
}
- }
+ },
});
}
},
- set_salvage_value_percentage_or_expected_value_after_useful_life: function(frm, row, salvage_value_percentage_changed, expected_value_after_useful_life_changed) {
+ set_salvage_value_percentage_or_expected_value_after_useful_life: function (
+ frm,
+ row,
+ salvage_value_percentage_changed,
+ expected_value_after_useful_life_changed
+ ) {
if (expected_value_after_useful_life_changed) {
frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life = true;
- const new_salvage_value_percentage = flt((row.expected_value_after_useful_life * 100) / frm.doc.gross_purchase_amount, precision("salvage_value_percentage", row));
- frappe.model.set_value(row.doctype, row.name, "salvage_value_percentage", new_salvage_value_percentage);
+ const new_salvage_value_percentage = flt(
+ (row.expected_value_after_useful_life * 100) / frm.doc.gross_purchase_amount,
+ precision("salvage_value_percentage", row)
+ );
+ frappe.model.set_value(
+ row.doctype,
+ row.name,
+ "salvage_value_percentage",
+ new_salvage_value_percentage
+ );
frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life = false;
} else if (salvage_value_percentage_changed) {
frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life = true;
- const new_expected_value_after_useful_life = flt(frm.doc.gross_purchase_amount * (row.salvage_value_percentage / 100), precision('gross_purchase_amount'));
- frappe.model.set_value(row.doctype, row.name, "expected_value_after_useful_life", new_expected_value_after_useful_life);
+ const new_expected_value_after_useful_life = flt(
+ frm.doc.gross_purchase_amount * (row.salvage_value_percentage / 100),
+ precision("gross_purchase_amount")
+ );
+ frappe.model.set_value(
+ row.doctype,
+ row.name,
+ "expected_value_after_useful_life",
+ new_expected_value_after_useful_life
+ );
frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life = false;
}
},
});
-frappe.ui.form.on('Asset Finance Book', {
- depreciation_method: function(frm, cdt, cdn) {
+frappe.ui.form.on("Asset Finance Book", {
+ depreciation_method: function (frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
},
- expected_value_after_useful_life: function(frm, cdt, cdn) {
+ expected_value_after_useful_life: function (frm, cdt, cdn) {
const row = locals[cdt][cdn];
if (!frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life) {
- frm.events.set_salvage_value_percentage_or_expected_value_after_useful_life(frm, row, false, true);
+ frm.events.set_salvage_value_percentage_or_expected_value_after_useful_life(
+ frm,
+ row,
+ false,
+ true
+ );
}
frm.events.set_depreciation_rate(frm, row);
},
- salvage_value_percentage: function(frm, cdt, cdn) {
+ salvage_value_percentage: function (frm, cdt, cdn) {
const row = locals[cdt][cdn];
if (!frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life) {
- frm.events.set_salvage_value_percentage_or_expected_value_after_useful_life(frm, row, true, false);
+ frm.events.set_salvage_value_percentage_or_expected_value_after_useful_life(
+ frm,
+ row,
+ true,
+ false
+ );
}
},
- frequency_of_depreciation: function(frm, cdt, cdn) {
+ frequency_of_depreciation: function (frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
},
- total_number_of_depreciations: function(frm, cdt, cdn) {
+ total_number_of_depreciations: function (frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
},
- rate_of_depreciation: function(frm, cdt, cdn) {
- if(!frappe.flags.dont_change_rate) {
+ rate_of_depreciation: function (frm, cdt, cdn) {
+ if (!frappe.flags.dont_change_rate) {
frappe.model.set_value(cdt, cdn, "expected_value_after_useful_life", 0);
}
frappe.flags.dont_change_rate = false;
},
- depreciation_start_date: function(frm, cdt, cdn) {
+ depreciation_start_date: function (frm, cdt, cdn) {
const book = locals[cdt][cdn];
- if (frm.doc.available_for_use_date && book.depreciation_start_date == frm.doc.available_for_use_date) {
+ if (
+ frm.doc.available_for_use_date &&
+ book.depreciation_start_date == frm.doc.available_for_use_date
+ ) {
frappe.msgprint(__("Depreciation Posting Date should not be equal to Available for Use Date."));
book.depreciation_start_date = "";
frm.refresh_field("finance_books");
}
- }
+ },
});
-erpnext.asset.scrap_asset = function(frm) {
+erpnext.asset.scrap_asset = function (frm) {
frappe.confirm(__("Do you really want to scrap this asset?"), function () {
frappe.call({
args: {
- "asset_name": frm.doc.name
+ asset_name: frm.doc.name,
},
method: "erpnext.assets.doctype.asset.depreciation.scrap_asset",
- callback: function(r) {
- cur_frm.reload_doc();
- }
- })
- })
+ callback: (r) => frm.reload_doc(),
+ });
+ });
};
-erpnext.asset.restore_asset = function(frm) {
+erpnext.asset.restore_asset = function (frm) {
frappe.confirm(__("Do you really want to restore this scrapped asset?"), function () {
frappe.call({
args: {
- "asset_name": frm.doc.name
+ asset_name: frm.doc.name,
},
method: "erpnext.assets.doctype.asset.depreciation.restore_asset",
- callback: function(r) {
- cur_frm.reload_doc();
- }
- })
- })
+ callback: (r) => frm.reload_doc(),
+ });
+ });
};
-erpnext.asset.transfer_asset = function() {
+erpnext.asset.transfer_asset = function (frm) {
frappe.call({
method: "erpnext.assets.doctype.asset.asset.make_asset_movement",
freeze: true,
- args:{
- "assets": [{ name: cur_frm.doc.name }],
- "purpose": "Transfer"
+ args: {
+ assets: [{ name: frm.doc.name }],
+ purpose: "Transfer",
},
callback: function (r) {
if (r.message) {
var doc = frappe.model.sync(r.message)[0];
frappe.set_route("Form", doc.doctype, doc.name);
}
- }
+ },
});
};
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index 3a2a942bdf2bf5d010ba83998e6d8eb9e6e097ff..99a430cbb400d38be8f9d7c3d868ffc784dc8a21 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -45,7 +45,7 @@
"calculate_depreciation",
"column_break_33",
"opening_accumulated_depreciation",
- "number_of_depreciations_booked",
+ "opening_number_of_booked_depreciations",
"is_fully_depreciated",
"section_break_36",
"finance_books",
@@ -257,12 +257,6 @@
"label": "Opening Accumulated Depreciation",
"options": "Company:company:default_currency"
},
- {
- "depends_on": "eval:(doc.is_existing_asset)",
- "fieldname": "number_of_depreciations_booked",
- "fieldtype": "Int",
- "label": "Number of Depreciations Booked"
- },
{
"collapsible": 1,
"collapsible_depends_on": "eval:doc.calculate_depreciation || doc.is_existing_asset",
@@ -546,6 +540,12 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "depends_on": "eval:(doc.is_existing_asset)",
+ "fieldname": "opening_number_of_booked_depreciations",
+ "fieldtype": "Int",
+ "label": "Opening Number of Booked Depreciations"
}
],
"idx": 72,
@@ -589,7 +589,7 @@
"link_fieldname": "target_asset"
}
],
- "modified": "2024-04-18 16:45:47.306032",
+ "modified": "2024-05-21 13:46:21.066483",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 57a8eb0eef264d3ecbf6e1091bacc78043633081..d31348d158c10e12ce5fc1e1be23963253136844 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -89,8 +89,8 @@ class Asset(AccountsController):
maintenance_required: DF.Check
naming_series: DF.Literal["ACC-ASS-.YYYY.-"]
next_depreciation_date: DF.Date | None
- number_of_depreciations_booked: DF.Int
opening_accumulated_depreciation: DF.Currency
+ opening_number_of_booked_depreciations: DF.Int
policy_number: DF.Data | None
purchase_amount: DF.Currency
purchase_date: DF.Date | None
@@ -145,7 +145,7 @@ class Asset(AccountsController):
"Asset Depreciation Schedules created:
{0}
Please check, edit if needed, and submit the Asset."
).format(asset_depr_schedules_links)
)
-
+ self.set_total_booked_depreciations()
self.total_asset_cost = self.gross_purchase_amount
self.status = self.get_status()
@@ -211,9 +211,7 @@ class Asset(AccountsController):
)
if self.is_existing_asset and self.purchase_invoice:
- frappe.throw(
- _("Purchase Invoice cannot be made against an existing asset {0}").format(self.name)
- )
+ frappe.throw(_("Purchase Invoice cannot be made against an existing asset {0}").format(self.name))
def prepare_depreciation_data(self):
if self.calculate_depreciation:
@@ -274,9 +272,9 @@ class Asset(AccountsController):
for d in self.finance_books:
if d.depreciation_start_date == self.available_for_use_date:
frappe.throw(
- _("Row #{}: Depreciation Posting Date should not be equal to Available for Use Date.").format(
- d.idx
- ),
+ _(
+ "Row #{}: Depreciation Posting Date should not be equal to Available for Use Date."
+ ).format(d.idx),
title=_("Incorrect Date"),
)
@@ -285,9 +283,7 @@ class Asset(AccountsController):
self.asset_category = frappe.get_cached_value("Item", self.item_code, "asset_category")
if self.item_code and not self.get("finance_books"):
- finance_books = get_item_details(
- self.item_code, self.asset_category, self.gross_purchase_amount
- )
+ finance_books = get_item_details(self.item_code, self.asset_category, self.gross_purchase_amount)
self.set("finance_books", finance_books)
def validate_finance_books(self):
@@ -337,7 +333,9 @@ class Asset(AccountsController):
and not frappe.db.get_value("Purchase Invoice", self.purchase_invoice, "update_stock")
):
frappe.throw(
- _("Update stock must be enabled for the purchase invoice {0}").format(self.purchase_invoice)
+ _("Update stock must be enabled for the purchase invoice {0}").format(
+ self.purchase_invoice
+ )
)
if not self.calculate_depreciation:
@@ -351,9 +349,7 @@ class Asset(AccountsController):
if self.is_existing_asset:
return
- if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(
- self.purchase_date
- ):
+ if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(self.purchase_date):
frappe.throw(_("Available-for-use Date should be after purchase date"))
def validate_gross_and_purchase_amount(self):
@@ -376,7 +372,7 @@ class Asset(AccountsController):
posting_date, posting_time = frappe.db.get_value(
reference_doctype, reference_docname, ["posting_date", "posting_time"]
)
- transaction_date = get_datetime("{} {}".format(posting_date, posting_time))
+ transaction_date = get_datetime(f"{posting_date} {posting_time}")
assets = [
{
"asset": self.name,
@@ -416,13 +412,14 @@ class Asset(AccountsController):
if not row.depreciation_start_date:
if not self.available_for_use_date:
frappe.throw(
- _("Row {0}: Depreciation Start Date is required").format(row.idx), title=_("Invalid Schedule")
+ _("Row {0}: Depreciation Start Date is required").format(row.idx),
+ title=_("Invalid Schedule"),
)
row.depreciation_start_date = get_last_day(self.available_for_use_date)
if not self.is_existing_asset:
self.opening_accumulated_depreciation = 0
- self.number_of_depreciations_booked = 0
+ self.opening_number_of_booked_depreciations = 0
else:
depreciable_amount = flt(self.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
if flt(self.opening_accumulated_depreciation) > depreciable_amount:
@@ -433,22 +430,20 @@ class Asset(AccountsController):
)
if self.opening_accumulated_depreciation:
- if not self.number_of_depreciations_booked:
- frappe.throw(_("Please set Number of Depreciations Booked"))
+ if not self.opening_number_of_booked_depreciations:
+ frappe.throw(_("Please set Opening Number of Booked Depreciations"))
else:
- self.number_of_depreciations_booked = 0
+ self.opening_number_of_booked_depreciations = 0
- if flt(row.total_number_of_depreciations) <= cint(self.number_of_depreciations_booked):
+ if flt(row.total_number_of_depreciations) <= cint(self.opening_number_of_booked_depreciations):
frappe.throw(
_(
- "Row {0}: Total Number of Depreciations cannot be less than or equal to Number of Depreciations Booked"
+ "Row {0}: Total Number of Depreciations cannot be less than or equal to Opening Number of Booked Depreciations"
).format(row.idx),
title=_("Invalid Schedule"),
)
- if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(
- self.purchase_date
- ):
+ if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(self.purchase_date):
frappe.throw(
_("Depreciation Row {0}: Next Depreciation Date cannot be before Purchase Date").format(
row.idx
@@ -464,6 +459,17 @@ class Asset(AccountsController):
).format(row.idx)
)
+ def set_total_booked_depreciations(self):
+ # set value of total number of booked depreciations field
+ for fb_row in self.get("finance_books"):
+ total_number_of_booked_depreciations = self.opening_number_of_booked_depreciations
+ depr_schedule = get_depr_schedule(self.name, "Active", fb_row.finance_book)
+ if depr_schedule:
+ for je in depr_schedule:
+ if je.journal_entry:
+ total_number_of_booked_depreciations += 1
+ fb_row.db_set("total_number_of_booked_depreciations", total_number_of_booked_depreciations)
+
def validate_expected_value_after_useful_life(self):
for row in self.get("finance_books"):
depr_schedule = get_depr_schedule(self.name, "Draft", row.finance_book)
@@ -567,11 +573,14 @@ class Asset(AccountsController):
if self.calculate_depreciation:
idx = self.get_default_finance_book_idx() or 0
- expected_value_after_useful_life = self.finance_books[idx].expected_value_after_useful_life
+ expected_value_after_useful_life = self.finance_books[
+ idx
+ ].expected_value_after_useful_life
value_after_depreciation = self.finance_books[idx].value_after_depreciation
if (
- flt(value_after_depreciation) <= expected_value_after_useful_life or self.is_fully_depreciated
+ flt(value_after_depreciation) <= expected_value_after_useful_life
+ or self.is_fully_depreciated
):
status = "Fully Depreciated"
elif flt(value_after_depreciation) < flt(self.gross_purchase_amount):
@@ -604,9 +613,7 @@ class Asset(AccountsController):
@frappe.whitelist()
def get_manual_depreciation_entries(self):
- (_, _, depreciation_expense_account) = get_depreciation_accounts(
- self.asset_category, self.company
- )
+ (_, _, depreciation_expense_account) = get_depreciation_accounts(self.asset_category, self.company)
gle = frappe.qb.DocType("GL Entry")
@@ -746,7 +753,8 @@ class Asset(AccountsController):
if args.get("depreciation_method") == "Double Declining Balance":
return 200.0 / (
(
- flt(args.get("total_number_of_depreciations"), 2) * flt(args.get("frequency_of_depreciation"))
+ flt(args.get("total_number_of_depreciations"), 2)
+ * flt(args.get("frequency_of_depreciation"))
)
/ 12
)
@@ -790,9 +798,7 @@ def update_maintenance_status():
asset = frappe.get_doc("Asset", asset.name)
if frappe.db.exists("Asset Repair", {"asset_name": asset.name, "repair_status": "Pending"}):
asset.set_status("Out of Order")
- elif frappe.db.exists(
- "Asset Maintenance Task", {"parent": asset.name, "next_due_date": today()}
- ):
+ elif frappe.db.exists("Asset Maintenance Task", {"parent": asset.name, "next_due_date": today()}):
asset.set_status("In Maintenance")
else:
asset.set_status()
@@ -876,9 +882,7 @@ def create_asset_capitalization(asset):
@frappe.whitelist()
def create_asset_value_adjustment(asset, asset_category, company):
asset_value_adjustment = frappe.new_doc("Asset Value Adjustment")
- asset_value_adjustment.update(
- {"asset": asset, "company": company, "asset_category": asset_category}
- )
+ asset_value_adjustment.update({"asset": asset, "company": company, "asset_category": asset_category})
return asset_value_adjustment
@@ -914,6 +918,8 @@ def get_item_details(item_code, asset_category, gross_purchase_amount):
"depreciation_method": d.depreciation_method,
"total_number_of_depreciations": d.total_number_of_depreciations,
"frequency_of_depreciation": d.frequency_of_depreciation,
+ "daily_prorata_based": d.daily_prorata_based,
+ "shift_based": d.shift_based,
"salvage_value_percentage": d.salvage_value_percentage,
"expected_value_after_useful_life": flt(gross_purchase_amount)
* flt(d.salvage_value_percentage / 100),
@@ -933,18 +939,14 @@ def get_asset_account(account_name, asset=None, asset_category=None, company=Non
)
if not asset and not account:
- account = get_asset_category_account(
- account_name, asset_category=asset_category, company=company
- )
+ account = get_asset_category_account(account_name, asset_category=asset_category, company=company)
if not account:
account = frappe.get_cached_value("Company", company, account_name)
if not account:
if not asset_category:
- frappe.throw(
- _("Set {0} in company {1}").format(account_name.replace("_", " ").title(), company)
- )
+ frappe.throw(_("Set {0} in company {1}").format(account_name.replace("_", " ").title(), company))
else:
frappe.throw(
_("Set {0} in asset category {1} or company {2}").format(
@@ -1044,7 +1046,7 @@ def split_asset(asset_name, split_qty):
split_qty = cint(split_qty)
if split_qty >= asset.asset_quantity:
- frappe.throw(_("Split qty cannot be greater than or equal to asset qty"))
+ frappe.throw(_("Split qty cannot be grater than or equal to asset qty"))
remaining_qty = asset.asset_quantity - split_qty
@@ -1074,15 +1076,11 @@ def update_existing_asset(asset, remaining_qty, new_asset_name):
add_asset_activity(
asset.name,
- _("Asset updated after being split into Asset {0}").format(
- get_link_to_form("Asset", new_asset_name)
- ),
+ _("Asset updated after being split into Asset {0}").format(get_link_to_form("Asset", new_asset_name)),
)
for row in asset.get("finance_books"):
- value_after_depreciation = flt(
- (row.value_after_depreciation * remaining_qty) / asset.asset_quantity
- )
+ value_after_depreciation = flt((row.value_after_depreciation * remaining_qty) / asset.asset_quantity)
expected_value_after_useful_life = flt(
(row.expected_value_after_useful_life * remaining_qty) / asset.asset_quantity
)
@@ -1096,9 +1094,7 @@ def update_existing_asset(asset, remaining_qty, new_asset_name):
expected_value_after_useful_life,
)
- current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(
- asset.name, "Active", row.finance_book
- )
+ current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, "Active", row.finance_book)
new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc)
new_asset_depr_schedule_doc.set_draft_asset_depr_schedule_details(asset, row)
@@ -1113,9 +1109,7 @@ def update_existing_asset(asset, remaining_qty, new_asset_name):
notes = _(
"This schedule was created when Asset {0} was updated after being split into new Asset {1}."
- ).format(
- get_link_to_form(asset.doctype, asset.name), get_link_to_form(asset.doctype, new_asset_name)
- )
+ ).format(get_link_to_form(asset.doctype, asset.name), get_link_to_form(asset.doctype, new_asset_name))
new_asset_depr_schedule_doc.notes = notes
current_asset_depr_schedule_doc.flags.should_not_cancel_depreciation_entries = True
@@ -1139,9 +1133,7 @@ def create_new_asset_after_split(asset, split_qty):
new_asset.split_from = asset.name
for row in new_asset.get("finance_books"):
- row.value_after_depreciation = flt(
- (row.value_after_depreciation * split_qty) / asset.asset_quantity
- )
+ row.value_after_depreciation = flt((row.value_after_depreciation * split_qty) / asset.asset_quantity)
row.expected_value_after_useful_life = flt(
(row.expected_value_after_useful_life * split_qty) / asset.asset_quantity
)
@@ -1150,18 +1142,14 @@ def create_new_asset_after_split(asset, split_qty):
add_asset_activity(
new_asset.name,
- _("Asset created after being split from Asset {0}").format(
- get_link_to_form("Asset", asset.name)
- ),
+ _("Asset created after being split from Asset {0}").format(get_link_to_form("Asset", asset.name)),
)
new_asset.submit()
new_asset.set_status()
for row in new_asset.get("finance_books"):
- current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(
- asset.name, "Active", row.finance_book
- )
+ current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, "Active", row.finance_book)
new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc)
new_asset_depr_schedule_doc.set_draft_asset_depr_schedule_details(new_asset, row)
diff --git a/erpnext/assets/doctype/asset/asset_list.js b/erpnext/assets/doctype/asset/asset_list.js
index e587e1dc715341a1b743d03ef6bb7089ae7200e4..712958adcfc5a75f0963b4fd2a21fa7ea8f4eef2 100644
--- a/erpnext/assets/doctype/asset/asset_list.js
+++ b/erpnext/assets/doctype/asset/asset_list.js
@@ -1,56 +1,46 @@
-frappe.listview_settings['Asset'] = {
- add_fields: ['status'],
+frappe.listview_settings["Asset"] = {
+ add_fields: ["status"],
get_indicator: function (doc) {
if (doc.status === "Fully Depreciated") {
return [__("Fully Depreciated"), "green", "status,=,Fully Depreciated"];
-
} else if (doc.status === "Partially Depreciated") {
- return [__("Partially Depreciated"), "gray", "status,=,Partially Depreciated"];
-
+ return [__("Partially Depreciated"), "grey", "status,=,Partially Depreciated"];
} else if (doc.status === "Sold") {
return [__("Sold"), "green", "status,=,Sold"];
-
} else if (["Capitalized", "Decapitalized"].includes(doc.status)) {
return [__(doc.status), "grey", "status,=," + doc.status];
-
} else if (doc.status === "Scrapped") {
- return [__("Scrapped"), "gray", "status,=,Scrapped"];
-
+ return [__("Scrapped"), "grey", "status,=,Scrapped"];
} else if (doc.status === "In Maintenance") {
return [__("In Maintenance"), "orange", "status,=,In Maintenance"];
-
} else if (doc.status === "Out of Order") {
- return [__("Out of Order"), "gray", "status,=,Out of Order"];
-
+ return [__("Out of Order"), "grey", "status,=,Out of Order"];
} else if (doc.status === "Issue") {
return [__("Issue"), "orange", "status,=,Issue"];
-
} else if (doc.status === "Receipt") {
return [__("Receipt"), "green", "status,=,Receipt"];
-
} else if (doc.status === "Submitted") {
return [__("Submitted"), "blue", "status,=,Submitted"];
-
} else if (doc.status === "Draft") {
return [__("Draft"), "red", "status,=,Draft"];
}
},
- onload: function(me) {
- me.page.add_action_item(__('Make Asset Movement'), function() {
+ onload: function (me) {
+ me.page.add_action_item(__("Make Asset Movement"), function () {
const assets = me.get_checked_items();
frappe.call({
method: "erpnext.assets.doctype.asset.asset.make_asset_movement",
freeze: true,
- args:{
- "assets": assets
+ args: {
+ assets: assets,
},
callback: function (r) {
if (r.message) {
var doc = frappe.model.sync(r.message)[0];
frappe.set_route("Form", doc.doctype, doc.name);
}
- }
+ },
});
});
},
-}
\ No newline at end of file
+};
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index b968736cee7f6dc2cdbc32b1541c5e49a1917796..93f32b43b4ce34d62e7dcb68657c8cd9d4e84518 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -36,7 +36,7 @@ from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_sched
def post_depreciation_entries(date=None):
# Return if automatic booking of asset depreciation is disabled
if not cint(
- frappe.db.get_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically")
+ frappe.db.get_single_value("Accounts Settings", "book_asset_depreciation_entry_automatically")
):
return
@@ -71,7 +71,10 @@ def post_depreciation_entries(date=None):
) not in credit_and_debit_accounts_for_asset_category_and_company:
credit_and_debit_accounts_for_asset_category_and_company.update(
{
- (asset_category, asset_company): get_credit_and_debit_accounts_for_asset_category_and_company(
+ (
+ asset_category,
+ asset_company,
+ ): get_credit_and_debit_accounts_for_asset_category_and_company(
asset_category, asset_company
),
}
@@ -135,9 +138,7 @@ def get_depreciable_asset_depr_schedules_data(date):
def make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date=None):
for row in asset_doc.get("finance_books"):
- asset_depr_schedule_name = get_asset_depr_schedule_name(
- asset_doc.name, "Active", row.finance_book
- )
+ asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, "Active", row.finance_book)
make_depreciation_entry(asset_depr_schedule_name, date)
@@ -147,9 +148,7 @@ def get_acc_frozen_upto():
if not acc_frozen_upto:
return
- frozen_accounts_modifier = frappe.db.get_single_value(
- "Accounts Settings", "frozen_accounts_modifier"
- )
+ frozen_accounts_modifier = frappe.db.get_single_value("Accounts Settings", "frozen_accounts_modifier")
if frozen_accounts_modifier not in frappe.get_roles() or frappe.session.user == "Administrator":
return getdate(acc_frozen_upto)
@@ -278,7 +277,7 @@ def _make_journal_entry_for_depreciation(
je.posting_date = depr_schedule.schedule_date
je.company = asset.company
je.finance_book = asset_depr_schedule_doc.finance_book
- je.remark = "Depreciation Entry against {0} worth {1}".format(
+ je.remark = frappe._("Depreciation Entry against {} worth {}").format(
asset.name, depr_schedule.depreciation_amount
)
@@ -326,6 +325,7 @@ def _make_journal_entry_for_depreciation(
if not je.meta.get_workflow():
je.submit()
+ asset.reload()
idx = cint(asset_depr_schedule_doc.finance_book_id)
row = asset.get("finance_books")[idx - 1]
row.value_after_depreciation -= depr_schedule.depreciation_amount
@@ -361,11 +361,7 @@ def get_depreciation_accounts(asset_category, company):
if not depreciation_expense_account:
depreciation_expense_account = accounts[1]
- if (
- not fixed_asset_account
- or not accumulated_depreciation_account
- or not depreciation_expense_account
- ):
+ if not fixed_asset_account or not accumulated_depreciation_account or not depreciation_expense_account:
frappe.throw(
_("Please set Depreciation related Accounts in Asset Category {0} or Company {1}").format(
asset_category, company
@@ -443,9 +439,7 @@ def scrap_asset(asset_name):
if asset.docstatus != 1:
frappe.throw(_("Asset {0} must be submitted").format(asset.name))
elif asset.status in ("Cancelled", "Sold", "Scrapped", "Capitalized", "Decapitalized"):
- frappe.throw(
- _("Asset {0} cannot be scrapped, as it is already {1}").format(asset.name, asset.status)
- )
+ frappe.throw(_("Asset {0} cannot be scrapped, as it is already {1}").format(asset.name, asset.status))
date = today()
@@ -456,16 +450,14 @@ def scrap_asset(asset_name):
depreciate_asset(asset, date, notes)
asset.reload()
- depreciation_series = frappe.get_cached_value(
- "Company", asset.company, "series_for_depreciation_entry"
- )
+ depreciation_series = frappe.get_cached_value("Company", asset.company, "series_for_depreciation_entry")
je = frappe.new_doc("Journal Entry")
je.voucher_type = "Journal Entry"
je.naming_series = depreciation_series
je.posting_date = date
je.company = asset.company
- je.remark = "Scrap Entry for asset {0}".format(asset_name)
+ je.remark = f"Scrap Entry for asset {asset_name}"
for entry in get_gl_entries_on_asset_disposal(asset, date):
entry.update({"reference_type": "Asset", "reference_name": asset_name})
@@ -513,9 +505,7 @@ def depreciate_asset(asset_doc, date, notes):
asset_doc.flags.ignore_validate_update_after_submit = True
- make_new_active_asset_depr_schedules_and_cancel_current_ones(
- asset_doc, notes, date_of_disposal=date
- )
+ make_new_active_asset_depr_schedules_and_cancel_current_ones(asset_doc, notes, date_of_disposal=date)
asset_doc.save()
@@ -536,9 +526,7 @@ def reset_depreciation_schedule(asset_doc, date, notes):
asset_doc.flags.ignore_validate_update_after_submit = True
- make_new_active_asset_depr_schedules_and_cancel_current_ones(
- asset_doc, notes, date_of_return=date
- )
+ make_new_active_asset_depr_schedules_and_cancel_current_ones(asset_doc, notes, date_of_return=date)
modify_depreciation_schedule_for_asset_repairs(asset_doc, notes)
@@ -781,9 +769,7 @@ def get_disposal_account_and_cost_center(company):
)
if not disposal_account:
- frappe.throw(
- _("Please set 'Gain/Loss Account on Asset Disposal' in Company {0}").format(company)
- )
+ frappe.throw(_("Please set 'Gain/Loss Account on Asset Disposal' in Company {0}").format(company))
if not depreciation_cost_center:
frappe.throw(_("Please set 'Asset Depreciation Cost Center' in Company {0}").format(company))
@@ -796,7 +782,7 @@ def get_value_after_depreciation_on_disposal_date(asset, disposal_date, finance_
if asset_doc.available_for_use_date > getdate(disposal_date):
frappe.throw(
- "Disposal date {0} cannot be before available for use date {1} of the asset.".format(
+ "Disposal date {} cannot be before available for use date {} of the asset.".format(
disposal_date, asset_doc.available_for_use_date
)
)
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index c0ded4b2a57e1bcf4ff3af968a41d6e152665c74..a634550089f739bb76abce094683b40136da5f36 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -49,10 +49,12 @@ class AssetSetup(unittest.TestCase):
enable_cwip_accounting("Computers")
make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location")
frappe.db.sql("delete from `tabTax Rule`")
+ set_system_settings(3) # @dokos
@classmethod
def tearDownClass(cls):
frappe.db.rollback()
+ set_system_settings() # @dokos
class TestAsset(AssetSetup):
@@ -109,9 +111,7 @@ class TestAsset(AssetSetup):
self.assertRaises(frappe.ValidationError, asset.save)
def test_purchase_asset(self):
- pr = make_purchase_receipt(
- item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location"
- )
+ pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location")
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, "name")
asset = frappe.get_doc("Asset", asset_name)
@@ -211,7 +211,7 @@ class TestAsset(AssetSetup):
)
first_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Active")
post_depreciation_entries(date=add_months(purchase_date, 2))
asset.load_from_db()
@@ -220,25 +220,29 @@ class TestAsset(AssetSetup):
asset.gross_purchase_amount - asset.finance_books[0].value_after_depreciation,
asset.precision("gross_purchase_amount"),
)
- self.assertEquals(accumulated_depr_amount, 18000.0)
+ self.assertEqual(accumulated_depr_amount, 18000.0)
scrap_asset(asset.name)
asset.load_from_db()
first_asset_depr_schedule.load_from_db()
second_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(second_asset_depr_schedule.status, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
+ self.assertEqual(second_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Cancelled")
accumulated_depr_amount = flt(
asset.gross_purchase_amount - asset.finance_books[0].value_after_depreciation,
asset.precision("gross_purchase_amount"),
)
pro_rata_amount, _, _ = _get_pro_rata_amt(
- asset.finance_books[0], 9000, get_last_day(add_months(purchase_date, 1)), date
+ asset.finance_books[0],
+ 9000,
+ get_last_day(add_months(purchase_date, 1)),
+ date,
+ original_schedule_date=get_last_day(nowdate()),
)
pro_rata_amount = flt(pro_rata_amount, asset.precision("gross_purchase_amount"))
- self.assertEquals(
+ self.assertEqual(
accumulated_depr_amount,
flt(18000.0 + pro_rata_amount, asset.precision("gross_purchase_amount")),
)
@@ -267,8 +271,8 @@ class TestAsset(AssetSetup):
second_asset_depr_schedule.load_from_db()
third_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(third_asset_depr_schedule.status, "Active")
- self.assertEquals(second_asset_depr_schedule.status, "Cancelled")
+ self.assertEqual(third_asset_depr_schedule.status, "Active")
+ self.assertEqual(second_asset_depr_schedule.status, "Cancelled")
asset.load_from_db()
self.assertFalse(asset.journal_entry_for_scrap)
@@ -280,7 +284,7 @@ class TestAsset(AssetSetup):
)
this_month_depr_amount = 9000.0 if is_last_day_of_the_month(date) else 0
- self.assertEquals(accumulated_depr_amount, 18000.0 + this_month_depr_amount)
+ self.assertEqual(accumulated_depr_amount, 18000.0 + this_month_depr_amount)
def test_gle_made_by_asset_sale(self):
date = nowdate()
@@ -297,7 +301,7 @@ class TestAsset(AssetSetup):
)
first_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Active")
post_depreciation_entries(date=add_months(purchase_date, 2))
@@ -313,11 +317,15 @@ class TestAsset(AssetSetup):
first_asset_depr_schedule.load_from_db()
second_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(second_asset_depr_schedule.status, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
+ self.assertEqual(second_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Cancelled")
pro_rata_amount, _, _ = _get_pro_rata_amt(
- asset.finance_books[0], 9000, get_last_day(add_months(purchase_date, 1)), date
+ asset.finance_books[0],
+ 9000,
+ get_last_day(add_months(purchase_date, 1)),
+ date,
+ original_schedule_date=get_last_day(nowdate()),
)
pro_rata_amount = flt(pro_rata_amount, asset.precision("gross_purchase_amount"))
@@ -335,7 +343,6 @@ class TestAsset(AssetSetup):
),
("Debtors - _TC", 25000.0, 0.0),
)
-
gle = get_gl_entries("Sales Invoice", si.name)
self.assertSequenceEqual(gle, expected_gle)
@@ -352,7 +359,7 @@ class TestAsset(AssetSetup):
purchase_date="2020-04-01",
expected_value_after_useful_life=0,
total_number_of_depreciations=5,
- number_of_depreciations_booked=2,
+ opening_number_of_booked_depreciations=2,
frequency_of_depreciation=12,
depreciation_start_date="2023-03-31",
opening_accumulated_depreciation=24000,
@@ -382,7 +389,7 @@ class TestAsset(AssetSetup):
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Sold")
- expected_values = [["2023-03-31", 12000, 36000], ["2023-05-23", 1742.47, 37742.47]]
+ expected_values = [["2023-03-31", 12000, 36000], ["2023-05-23", 1737.7, 37737.7]]
second_asset_depr_schedule = get_depr_schedule(asset.name, "Active")
@@ -395,7 +402,7 @@ class TestAsset(AssetSetup):
expected_gle = (
(
"_Test Accumulated Depreciations - _TC",
- 37742.47,
+ 37737.7,
0.0,
),
(
@@ -406,7 +413,7 @@ class TestAsset(AssetSetup):
(
"_Test Gain/Loss on Asset Disposal - _TC",
0.0,
- 17742.47,
+ 17737.7,
),
("Debtors - _TC", 40000.0, 0.0),
)
@@ -450,7 +457,7 @@ class TestAsset(AssetSetup):
purchase_date="2020-01-01",
expected_value_after_useful_life=0,
total_number_of_depreciations=6,
- number_of_depreciations_booked=1,
+ opening_number_of_booked_depreciations=1,
frequency_of_depreciation=10,
depreciation_start_date="2021-01-01",
opening_accumulated_depreciation=20000,
@@ -459,7 +466,7 @@ class TestAsset(AssetSetup):
)
first_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Active")
post_depreciation_entries(date="2021-01-01")
@@ -473,9 +480,9 @@ class TestAsset(AssetSetup):
second_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
first_asset_depr_schedule_of_new_asset = get_asset_depr_schedule_doc(new_asset.name, "Active")
- self.assertEquals(second_asset_depr_schedule.status, "Active")
- self.assertEquals(first_asset_depr_schedule_of_new_asset.status, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
+ self.assertEqual(second_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule_of_new_asset.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Cancelled")
depr_schedule_of_asset = second_asset_depr_schedule.get("depreciation_schedule")
depr_schedule_of_new_asset = first_asset_depr_schedule_of_new_asset.get("depreciation_schedule")
@@ -507,9 +514,7 @@ class TestAsset(AssetSetup):
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"
- )
+ pr = make_purchase_receipt(item_code="Macbook Pro", qty=2, rate=200000.0, location="Test Location")
doc = make_invoice(pr.name)
self.assertEqual("Asset Received But Not Billed - _TC", doc.items[0].expense_account)
@@ -619,9 +624,7 @@ class TestAsset(AssetSetup):
self.assertFalse(gle)
# case 1 -- PR with cwip disabled, Asset with cwip enabled
- pr = make_purchase_receipt(
- item_code="Macbook Pro", qty=1, rate=200000.0, location="Test Location"
- )
+ pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=200000.0, location="Test Location")
frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", 1)
frappe.db.set_value("Asset Category Account", name, "capital_work_in_progress_account", cwip_acc)
asset = frappe.db.get_value("Asset", {"purchase_receipt": pr.name, "docstatus": 0}, "name")
@@ -633,9 +636,7 @@ class TestAsset(AssetSetup):
self.assertFalse(gle)
# case 2 -- PR with cwip enabled, Asset with cwip disabled
- pr = make_purchase_receipt(
- item_code="Macbook Pro", qty=1, rate=200000.0, location="Test Location"
- )
+ pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=200000.0, location="Test Location")
frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", 0)
asset = frappe.db.get_value("Asset", {"purchase_receipt": pr.name, "docstatus": 0}, "name")
asset_doc = frappe.get_doc("Asset", asset)
@@ -702,12 +703,47 @@ class TestDepreciationMethods(AssetSetup):
self.assertEqual(schedules, expected_schedules)
+ def test_schedule_for_straight_line_method_with_daily_prorata_based(
+ self,
+ ):
+ asset = create_asset(
+ calculate_depreciation=1,
+ available_for_use_date="2023-01-01",
+ purchase_date="2023-01-01",
+ gross_purchase_amount=12000,
+ depreciation_start_date="2023-01-31",
+ total_number_of_depreciations=12,
+ frequency_of_depreciation=1,
+ daily_prorata_based=1,
+ )
+
+ expected_schedules = [
+ ["2023-01-31", 1019.18, 1019.18],
+ ["2023-02-28", 920.55, 1939.73],
+ ["2023-03-31", 1019.18, 2958.91],
+ ["2023-04-30", 986.3, 3945.21],
+ ["2023-05-31", 1019.18, 4964.39],
+ ["2023-06-30", 986.3, 5950.69],
+ ["2023-07-31", 1019.18, 6969.87],
+ ["2023-08-31", 1019.18, 7989.05],
+ ["2023-09-30", 986.3, 8975.35],
+ ["2023-10-31", 1019.18, 9994.53],
+ ["2023-11-30", 986.3, 10980.83],
+ ["2023-12-31", 1019.17, 12000.0],
+ ]
+
+ schedules = [
+ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
+ for d in get_depr_schedule(asset.name, "Draft")
+ ]
+ self.assertEqual(schedules, expected_schedules)
+
def test_schedule_for_straight_line_method_for_existing_asset(self):
asset = create_asset(
calculate_depreciation=1,
available_for_use_date="2030-06-06",
is_existing_asset=1,
- number_of_depreciations_booked=2,
+ opening_number_of_booked_depreciations=2,
opening_accumulated_depreciation=47095.89,
expected_value_after_useful_life=10000,
depreciation_start_date="2032-12-31",
@@ -739,9 +775,9 @@ class TestDepreciationMethods(AssetSetup):
self.assertEqual(asset.status, "Draft")
expected_schedules = [
- ["2030-12-31", 66666.70, 66666.70],
- ["2031-12-31", 22222.21, 88888.91],
- ["2032-12-31", 1111.09, 90000.0],
+ ["2030-12-31", 66667.00, 66667.00],
+ ["2031-12-31", 22222.11, 88889.11],
+ ["2032-12-31", 1110.89, 90000.0],
]
schedules = [
@@ -757,7 +793,7 @@ class TestDepreciationMethods(AssetSetup):
available_for_use_date="2030-01-01",
is_existing_asset=1,
depreciation_method="Double Declining Balance",
- number_of_depreciations_booked=1,
+ opening_number_of_booked_depreciations=1,
opening_accumulated_depreciation=50000,
expected_value_after_useful_life=10000,
depreciation_start_date="2031-12-31",
@@ -767,7 +803,7 @@ class TestDepreciationMethods(AssetSetup):
self.assertEqual(asset.status, "Draft")
- expected_schedules = [["2031-12-31", 33333.35, 83333.35], ["2032-12-31", 6666.65, 90000.0]]
+ expected_schedules = [["2031-12-31", 33333.50, 83333.50], ["2032-12-31", 6666.50, 90000.0]]
schedules = [
[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
@@ -885,12 +921,12 @@ class TestDepreciationMethods(AssetSetup):
)
expected_schedules = [
- ["2022-02-28", 310.88, 310.88],
- ["2022-03-31", 654.42, 965.30],
- ["2022-04-30", 654.42, 1619.72],
- ["2022-05-31", 654.42, 2274.14],
- ["2022-06-30", 654.42, 2928.56],
- ["2022-07-15", 2071.44, 5000.0],
+ ["2022-02-28", 310.89, 310.89],
+ ["2022-03-31", 654.45, 965.34],
+ ["2022-04-30", 654.45, 1619.79],
+ ["2022-05-31", 654.45, 2274.24],
+ ["2022-06-30", 654.45, 2928.69],
+ ["2022-07-15", 2071.31, 5000.0],
]
schedules = [
@@ -968,7 +1004,7 @@ class TestDepreciationBasics(AssetSetup):
asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, "Active")
- depreciation_amount = get_depreciation_amount(
+ depreciation_amount, prev_per_day_depr = get_depreciation_amount(
asset_depr_schedule_doc, asset, 100000, 100000, asset.finance_books[0]
)
self.assertEqual(depreciation_amount, 30000)
@@ -1091,8 +1127,8 @@ class TestDepreciationBasics(AssetSetup):
self.assertRaises(frappe.ValidationError, asset.save)
- def test_number_of_depreciations_booked(self):
- """Tests if an error is raised when number_of_depreciations_booked is not specified when opening_accumulated_depreciation is."""
+ def test_opening_booked_depreciations(self):
+ """Tests if an error is raised when opening_number_of_booked_depreciations is not specified when opening_accumulated_depreciation is."""
asset = create_asset(
item_code="Macbook Pro",
@@ -1108,9 +1144,9 @@ class TestDepreciationBasics(AssetSetup):
self.assertRaises(frappe.ValidationError, asset.save)
def test_number_of_depreciations(self):
- """Tests if an error is raised when number_of_depreciations_booked >= total_number_of_depreciations."""
+ """Tests if an error is raised when opening_number_of_booked_depreciations >= total_number_of_depreciations."""
- # number_of_depreciations_booked > total_number_of_depreciations
+ # opening_number_of_booked_depreciations > total_number_of_depreciations
asset = create_asset(
item_code="Macbook Pro",
calculate_depreciation=1,
@@ -1119,13 +1155,13 @@ class TestDepreciationBasics(AssetSetup):
expected_value_after_useful_life=10000,
depreciation_start_date="2020-07-01",
opening_accumulated_depreciation=10000,
- number_of_depreciations_booked=5,
+ opening_number_of_booked_depreciations=5,
do_not_save=1,
)
self.assertRaises(frappe.ValidationError, asset.save)
- # number_of_depreciations_booked = total_number_of_depreciations
+ # opening_number_of_booked_depreciations = total_number_of_depreciations
asset_2 = create_asset(
item_code="Macbook Pro",
calculate_depreciation=1,
@@ -1134,7 +1170,7 @@ class TestDepreciationBasics(AssetSetup):
expected_value_after_useful_life=10000,
depreciation_start_date="2020-07-01",
opening_accumulated_depreciation=10000,
- number_of_depreciations_booked=5,
+ opening_number_of_booked_depreciations=5,
do_not_save=1,
)
@@ -1214,8 +1250,7 @@ class TestDepreciationBasics(AssetSetup):
je = frappe.get_doc("Journal Entry", get_depr_schedule(asset.name, "Active")[0].journal_entry)
accounting_entries = [
- {"account": entry.account, "debit": entry.debit, "credit": entry.credit}
- for entry in je.accounts
+ {"account": entry.account, "debit": entry.debit, "credit": entry.credit} for entry in je.accounts
]
for entry in accounting_entries:
@@ -1250,8 +1285,7 @@ class TestDepreciationBasics(AssetSetup):
je = frappe.get_doc("Journal Entry", get_depr_schedule(asset.name, "Active")[0].journal_entry)
accounting_entries = [
- {"account": entry.account, "debit": entry.debit, "credit": entry.credit}
- for entry in je.accounts
+ {"account": entry.account, "debit": entry.debit, "credit": entry.credit} for entry in je.accounts
]
for entry in accounting_entries:
@@ -1332,21 +1366,15 @@ class TestDepreciationBasics(AssetSetup):
post_depreciation_entries(date="2020-04-01")
asset.load_from_db()
- asset_depr_schedule_doc_1 = get_asset_depr_schedule_doc(
- asset.name, "Active", "Test Finance Book 1"
- )
+ asset_depr_schedule_doc_1 = get_asset_depr_schedule_doc(asset.name, "Active", "Test Finance Book 1")
asset_depr_schedule_doc_1.clear_depr_schedule()
self.assertEqual(len(asset_depr_schedule_doc_1.get("depreciation_schedule")), 3)
- asset_depr_schedule_doc_2 = get_asset_depr_schedule_doc(
- asset.name, "Active", "Test Finance Book 2"
- )
+ asset_depr_schedule_doc_2 = get_asset_depr_schedule_doc(asset.name, "Active", "Test Finance Book 2")
asset_depr_schedule_doc_2.clear_depr_schedule()
self.assertEqual(len(asset_depr_schedule_doc_2.get("depreciation_schedule")), 3)
- asset_depr_schedule_doc_3 = get_asset_depr_schedule_doc(
- asset.name, "Active", "Test Finance Book 3"
- )
+ asset_depr_schedule_doc_3 = get_asset_depr_schedule_doc(asset.name, "Active", "Test Finance Book 3")
asset_depr_schedule_doc_3.clear_depr_schedule()
self.assertEqual(len(asset_depr_schedule_doc_3.get("depreciation_schedule")), 0)
@@ -1378,14 +1406,10 @@ class TestDepreciationBasics(AssetSetup):
)
asset.save()
- asset_depr_schedule_doc_1 = get_asset_depr_schedule_doc(
- asset.name, "Draft", "Test Finance Book 1"
- )
+ asset_depr_schedule_doc_1 = get_asset_depr_schedule_doc(asset.name, "Draft", "Test Finance Book 1")
self.assertEqual(len(asset_depr_schedule_doc_1.get("depreciation_schedule")), 3)
- asset_depr_schedule_doc_2 = get_asset_depr_schedule_doc(
- asset.name, "Draft", "Test Finance Book 2"
- )
+ asset_depr_schedule_doc_2 = get_asset_depr_schedule_doc(asset.name, "Draft", "Test Finance Book 2")
self.assertEqual(len(asset_depr_schedule_doc_2.get("depreciation_schedule")), 6)
def test_depreciation_entry_cancellation(self):
@@ -1482,18 +1506,18 @@ class TestDepreciationBasics(AssetSetup):
asset = create_asset(calculate_depreciation=1)
asset.opening_accumulated_depreciation = 2000
- asset.number_of_depreciations_booked = 1
+ asset.opening_number_of_booked_depreciations = 1
asset.finance_books[0].expected_value_after_useful_life = 100
asset.save()
asset.reload()
- self.assertEquals(asset.finance_books[0].value_after_depreciation, 98000.0)
+ self.assertEqual(asset.finance_books[0].value_after_depreciation, 98000.0)
# changing expected_value_after_useful_life shouldn't affect value_after_depreciation
asset.finance_books[0].expected_value_after_useful_life = 200
asset.save()
asset.reload()
- self.assertEquals(asset.finance_books[0].value_after_depreciation, 98000.0)
+ self.assertEqual(asset.finance_books[0].value_after_depreciation, 98000.0)
def test_asset_cost_center(self):
asset = create_asset(is_existing_asset=1, do_not_save=1)
@@ -1630,6 +1654,15 @@ class TestDepreciationBasics(AssetSetup):
self.assertTrue(get_gl_entries("Purchase Receipt", pr.name))
+def set_system_settings(float_precision=2, currency_precision=2):
+ # @dokos set number and currency precision to match tests calculation results
+ system_settings = frappe.get_doc("System Settings")
+ system_settings.float_precision = float_precision
+ system_settings.currency_precision = currency_precision
+ system_settings.rounding_method = "Banker's Rounding"
+ system_settings.save()
+
+
def get_gl_entries(doctype, docname):
gl_entry = frappe.qb.DocType("GL Entry")
return (
@@ -1676,7 +1709,7 @@ def create_asset(**args):
"purchase_date": args.purchase_date or "2015-01-01",
"calculate_depreciation": args.calculate_depreciation or 0,
"opening_accumulated_depreciation": args.opening_accumulated_depreciation or 0,
- "number_of_depreciations_booked": args.number_of_depreciations_booked or 0,
+ "opening_number_of_booked_depreciations": args.opening_number_of_booked_depreciations or 0,
"gross_purchase_amount": args.gross_purchase_amount or 100000,
"purchase_amount": args.purchase_amount or 100000,
"maintenance_required": args.maintenance_required or 0,
@@ -1701,6 +1734,9 @@ def create_asset(**args):
"total_number_of_depreciations": args.total_number_of_depreciations or 5,
"expected_value_after_useful_life": args.expected_value_after_useful_life or 0,
"depreciation_start_date": args.depreciation_start_date,
+ "daily_prorata_based": args.daily_prorata_based or 0,
+ "shift_based": args.shift_based or 0,
+ "rate_of_depreciation": args.rate_of_depreciation or 0,
},
)
@@ -1716,12 +1752,12 @@ def create_asset(**args):
return asset
-def create_asset_category():
+def create_asset_category(enable_cwip=1):
asset_category = frappe.new_doc("Asset Category")
asset_category.asset_category_name = "Computers"
asset_category.total_number_of_depreciations = 3
asset_category.frequency_of_depreciation = 3
- asset_category.enable_cwip_accounting = 1
+ asset_category.enable_cwip_accounting = enable_cwip
asset_category.append(
"accounts",
{
diff --git a/erpnext/assets/doctype/asset_activity/asset_activity.json b/erpnext/assets/doctype/asset_activity/asset_activity.json
index 2c883a0b218dd9ab906be3a2707f225c3cbd8407..96110611d082b17973b2a2be5ee6d3dea83294dc 100644
--- a/erpnext/assets/doctype/asset_activity/asset_activity.json
+++ b/erpnext/assets/doctype/asset_activity/asset_activity.json
@@ -75,7 +75,7 @@
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2023-09-29 15:56:17.608643",
+ "modified": "2024-03-27 13:06:32.933603",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Activity",
@@ -106,7 +106,7 @@
"share": 1
}
],
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": []
}
diff --git a/erpnext/assets/doctype/asset_activity/asset_activity.py b/erpnext/assets/doctype/asset_activity/asset_activity.py
index 0b3c3138792c1e5dfaf49256e7c21a3d4eff4d74..7177223b4f6b35d4f487762c40c6cb43c6d5db86 100644
--- a/erpnext/assets/doctype/asset_activity/asset_activity.py
+++ b/erpnext/assets/doctype/asset_activity/asset_activity.py
@@ -7,6 +7,20 @@ from frappe.utils import now_datetime
class AssetActivity(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ asset: DF.Link
+ date: DF.Datetime
+ subject: DF.SmallText
+ user: DF.Link
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js
index 110f2c4f2a13a9977068e830a7275b6621006195..651b75d0a70ae782ccbfc39793afe2d2aca48fac 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js
@@ -3,10 +3,9 @@
frappe.provide("erpnext.assets");
-
erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.stock.StockController {
setup() {
- this.frm.ignore_doctypes_on_cancel_all = ['Serial and Batch Bundle', 'Asset Movement'];
+ this.frm.ignore_doctypes_on_cancel_all = ["Serial and Batch Bundle", "Asset Movement"];
this.setup_posting_date_time_check();
}
@@ -17,7 +16,10 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
refresh() {
this.show_general_ledger();
- if ((this.frm.doc.stock_items && this.frm.doc.stock_items.length) || !this.frm.doc.target_is_fixed_asset) {
+ if (
+ (this.frm.doc.stock_items && this.frm.doc.stock_items.length) ||
+ !this.frm.doc.target_is_fixed_asset
+ ) {
this.show_stock_ledger();
}
@@ -32,32 +34,32 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
me.setup_warehouse_query();
- me.frm.set_query("target_item_code", function() {
+ me.frm.set_query("target_item_code", function () {
if (me.frm.doc.entry_type == "Capitalization") {
- return erpnext.queries.item({"is_stock_item": 0, "is_fixed_asset": 1});
+ 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});
+ return erpnext.queries.item({ is_stock_item: 1, is_fixed_asset: 0 });
}
});
- me.frm.set_query("target_asset", function() {
+ me.frm.set_query("target_asset", function () {
return {
- filters: {'is_composite_asset': 1, 'docstatus': 0 }
- }
+ filters: { is_composite_asset: 1, docstatus: 0 },
+ };
});
- me.frm.set_query("asset", "asset_items", function() {
+ me.frm.set_query("asset", "asset_items", function () {
var filters = {
- 'status': ["not in", ["Draft", "Scrapped", "Sold", "Capitalized", "Decapitalized"]],
- 'docstatus': 1
+ status: ["not in", ["Draft", "Scrapped", "Sold", "Capitalized", "Decapitalized"]],
+ docstatus: 1,
};
if (me.frm.doc.target_asset) {
- filters['name'] = ['!=', me.frm.doc.target_asset];
+ filters["name"] = ["!=", me.frm.doc.target_asset];
}
return {
- filters: filters
+ filters: filters,
};
});
@@ -65,58 +67,67 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
let row = locals[cdt][cdn];
return {
filters: {
- 'item_code': row.item_code,
- 'voucher_type': doc.doctype,
- 'voucher_no': ["in", [doc.name, ""]],
- 'is_cancelled': 0,
- }
- }
+ item_code: row.item_code,
+ voucher_type: doc.doctype,
+ voucher_no: ["in", [doc.name, ""]],
+ is_cancelled: 0,
+ },
+ };
});
- me.frm.set_query("item_code", "stock_items", function() {
- return erpnext.queries.item({"is_stock_item": 1});
+ me.frm.set_query("item_code", "stock_items", function () {
+ return erpnext.queries.item({ is_stock_item: 1 });
});
- me.frm.set_query("item_code", "service_items", function() {
- return erpnext.queries.item({"is_stock_item": 0, "is_fixed_asset": 0});
+ me.frm.set_query("item_code", "service_items", function () {
+ return erpnext.queries.item({ is_stock_item: 0, is_fixed_asset: 0 });
});
- me.frm.set_query('batch_no', 'stock_items', function(doc, cdt, cdn) {
+ me.frm.set_query("batch_no", "stock_items", function (doc, cdt, cdn) {
var item = locals[cdt][cdn];
if (!item.item_code) {
frappe.throw(__("Please enter Item Code to get Batch Number"));
} else {
var filters = {
- 'item_code': item.item_code,
- 'posting_date': me.frm.doc.posting_date || frappe.datetime.nowdate(),
- 'warehouse': item.warehouse
+ item_code: item.item_code,
+ posting_date: me.frm.doc.posting_date || frappe.datetime.nowdate(),
+ warehouse: item.warehouse,
};
return {
query: "erpnext.controllers.queries.get_batch_no",
- filters: filters
+ filters: filters,
};
}
});
- me.frm.set_query('expense_account', 'service_items', function() {
+ me.frm.set_query("expense_account", "service_items", function () {
return {
filters: {
- "account_type": ['in', ["Tax", "Expense Account", "Income Account", "Expenses Included In Valuation", "Expenses Included In Asset Valuation"]],
- "is_group": 0,
- "company": me.frm.doc.company
- }
+ account_type: [
+ "in",
+ [
+ "Tax",
+ "Expense Account",
+ "Income Account",
+ "Expenses Included In Valuation",
+ "Expenses Included In Asset Valuation",
+ ],
+ ],
+ is_group: 0,
+ company: me.frm.doc.company,
+ },
};
});
- let sbb_field = me.frm.get_docfield('stock_items', 'serial_and_batch_bundle');
+ let sbb_field = me.frm.get_docfield("stock_items", "serial_and_batch_bundle");
if (sbb_field) {
sbb_field.get_route_options_for_new_doc = (row) => {
return {
- 'item_code': row.doc.item_code,
- 'warehouse': row.doc.warehouse,
- 'voucher_type': me.frm.doc.doctype,
- }
+ item_code: row.doc.item_code,
+ warehouse: row.doc.warehouse,
+ voucher_type: me.frm.doc.doctype,
+ };
};
}
}
@@ -126,7 +137,10 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
}
target_asset() {
- if (this.frm.doc.target_asset && this.frm.doc.capitalization_method === "Choose a WIP composite asset") {
+ if (
+ this.frm.doc.target_asset &&
+ this.frm.doc.capitalization_method === "Choose a WIP composite asset"
+ ) {
this.set_consumed_stock_items_tagged_to_wip_composite_asset(this.frm.doc.target_asset);
this.get_target_asset_details();
}
@@ -143,7 +157,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
},
callback: function (r) {
if (!r.exc && r.message) {
- if(r.message[0] && r.message[0].length) {
+ if (r.message[0] && r.message[0].length) {
me.frm.clear_table("stock_items");
for (let item of r.message[0]) {
me.frm.add_child("stock_items", item);
@@ -160,7 +174,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
me.calculate_totals();
}
- }
+ },
});
}
}
@@ -192,7 +206,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
if (this.frm.doc.posting_date) {
frappe.run_serially([
() => this.get_all_item_warehouse_details(),
- () => this.get_all_asset_values()
+ () => this.get_all_asset_values(),
]);
}
}
@@ -248,15 +262,15 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
}
stock_items_add(doc, cdt, cdn) {
- erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, 'stock_items');
+ erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, "stock_items");
}
asset_items_add(doc, cdt, cdn) {
- erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, 'asset_items');
+ erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, "asset_items");
}
serivce_items_add(doc, cdt, cdn) {
- erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, 'service_items');
+ erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, "service_items");
}
get_target_item_details() {
@@ -274,7 +288,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
if (!r.exc) {
me.frm.refresh_fields();
}
- }
+ },
});
}
}
@@ -294,7 +308,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
if (!r.exc) {
me.frm.refresh_fields();
}
- }
+ },
});
}
}
@@ -316,13 +330,13 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
company: me.frm.doc.company,
posting_date: me.frm.doc.posting_date,
posting_time: me.frm.doc.posting_time,
- }
+ },
},
callback: function (r) {
if (!r.exc) {
me.calculate_totals();
}
- }
+ },
});
}
}
@@ -343,13 +357,13 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
finance_book: row.finance_book || me.frm.doc.finance_book,
posting_date: me.frm.doc.posting_date,
posting_time: me.frm.doc.posting_time,
- }
+ },
},
callback: function (r) {
if (!r.exc) {
me.calculate_totals();
}
- }
+ },
});
}
}
@@ -367,13 +381,13 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
qty: flt(row.qty),
expense_account: row.expense_account,
company: me.frm.doc.company,
- }
+ },
},
callback: function (r) {
if (!r.exc) {
me.calculate_totals();
}
- }
+ },
});
}
}
@@ -386,23 +400,23 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
child: item,
args: {
args: {
- 'item_code': item.item_code,
- 'warehouse': cstr(item.warehouse),
- 'qty': flt(item.stock_qty),
- 'serial_no': item.serial_no,
- 'posting_date': me.frm.doc.posting_date,
- 'posting_time': me.frm.doc.posting_time,
- 'company': me.frm.doc.company,
- 'voucher_type': me.frm.doc.doctype,
- 'voucher_no': me.frm.doc.name,
- 'allow_zero_valuation': 1
- }
+ item_code: item.item_code,
+ warehouse: cstr(item.warehouse),
+ qty: flt(item.stock_qty),
+ serial_no: item.serial_no,
+ posting_date: me.frm.doc.posting_date,
+ posting_time: me.frm.doc.posting_time,
+ company: me.frm.doc.company,
+ voucher_type: me.frm.doc.doctype,
+ voucher_no: me.frm.doc.name,
+ allow_zero_valuation: 1,
+ },
},
- callback: function(r) {
+ callback: function (r) {
if (!r.exc) {
me.calculate_totals();
}
- }
+ },
});
}
}
@@ -412,11 +426,11 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
return me.frm.call({
method: "set_warehouse_details",
doc: me.frm.doc,
- callback: function(r) {
+ callback: function (r) {
if (!r.exc) {
me.calculate_totals();
}
- }
+ },
});
}
@@ -425,11 +439,11 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
return me.frm.call({
method: "set_asset_values",
doc: me.frm.doc,
- callback: function(r) {
+ callback: function (r) {
if (!r.exc) {
me.calculate_totals();
}
- }
+ },
});
}
@@ -441,33 +455,38 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
me.frm.doc.service_items_total = 0;
$.each(me.frm.doc.stock_items || [], function (i, d) {
- d.amount = flt(flt(d.stock_qty) * flt(d.valuation_rate), precision('amount', d));
+ d.amount = flt(flt(d.stock_qty) * flt(d.valuation_rate), precision("amount", d));
me.frm.doc.stock_items_total += d.amount;
});
$.each(me.frm.doc.asset_items || [], function (i, d) {
- d.asset_value = flt(flt(d.asset_value), precision('asset_value', d));
+ d.asset_value = flt(flt(d.asset_value), precision("asset_value", d));
me.frm.doc.asset_items_total += d.asset_value;
});
$.each(me.frm.doc.service_items || [], function (i, d) {
- d.amount = flt(flt(d.qty) * flt(d.rate), precision('amount', d));
+ d.amount = flt(flt(d.qty) * flt(d.rate), precision("amount", d));
me.frm.doc.service_items_total += d.amount;
});
- me.frm.doc.stock_items_total = flt(me.frm.doc.stock_items_total, precision('stock_items_total'));
- me.frm.doc.asset_items_total = flt(me.frm.doc.asset_items_total, precision('asset_items_total'));
- me.frm.doc.service_items_total = flt(me.frm.doc.service_items_total, precision('service_items_total'));
+ me.frm.doc.stock_items_total = flt(me.frm.doc.stock_items_total, precision("stock_items_total"));
+ me.frm.doc.asset_items_total = flt(me.frm.doc.asset_items_total, precision("asset_items_total"));
+ me.frm.doc.service_items_total = flt(
+ me.frm.doc.service_items_total,
+ precision("service_items_total")
+ );
- me.frm.doc.total_value = me.frm.doc.stock_items_total + me.frm.doc.asset_items_total + me.frm.doc.service_items_total;
- me.frm.doc.total_value = flt(me.frm.doc.total_value, precision('total_value'));
+ me.frm.doc.total_value =
+ me.frm.doc.stock_items_total + me.frm.doc.asset_items_total + me.frm.doc.service_items_total;
+ me.frm.doc.total_value = flt(me.frm.doc.total_value, precision("total_value"));
- me.frm.doc.target_qty = flt(me.frm.doc.target_qty, precision('target_qty'));
- me.frm.doc.target_incoming_rate = me.frm.doc.target_qty ? me.frm.doc.total_value / flt(me.frm.doc.target_qty)
+ me.frm.doc.target_qty = flt(me.frm.doc.target_qty, precision("target_qty"));
+ me.frm.doc.target_incoming_rate = me.frm.doc.target_qty
+ ? me.frm.doc.total_value / flt(me.frm.doc.target_qty)
: me.frm.doc.total_value;
me.frm.refresh_fields();
}
};
-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 000ec65c45bae32c68024001225714fc6cee38fe..4e7ac3ee8bdbd56abfdd68aa49d0d148c5f98094 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json
@@ -356,7 +356,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2023-10-03 22:55:59.461456",
+ "modified": "2024-03-27 13:06:33.080441",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Capitalization",
@@ -394,7 +394,7 @@
"write": 1
}
],
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": [],
"title_field": "title",
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
index e6eaba5dd644a6e844f7c7cab69b185a864dd32c..9e9176f592823254249857ab493bcfc76b4f788f 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
@@ -49,6 +49,59 @@ force_fields = [
class AssetCapitalization(StockController):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ from erpnext.assets.doctype.asset_capitalization_asset_item.asset_capitalization_asset_item import (
+ AssetCapitalizationAssetItem,
+ )
+ from erpnext.assets.doctype.asset_capitalization_service_item.asset_capitalization_service_item import (
+ AssetCapitalizationServiceItem,
+ )
+ from erpnext.assets.doctype.asset_capitalization_stock_item.asset_capitalization_stock_item import (
+ AssetCapitalizationStockItem,
+ )
+
+ amended_from: DF.Link | None
+ asset_items: DF.Table[AssetCapitalizationAssetItem]
+ asset_items_total: DF.Currency
+ capitalization_method: DF.Literal["", "Create a new composite asset", "Choose a WIP composite asset"]
+ company: DF.Link
+ cost_center: DF.Link | None
+ entry_type: DF.Literal["Capitalization", "Decapitalization"]
+ finance_book: DF.Link | None
+ naming_series: DF.Literal["ACC-ASC-.YYYY.-"]
+ posting_date: DF.Date
+ posting_time: DF.Time
+ service_items: DF.Table[AssetCapitalizationServiceItem]
+ service_items_total: DF.Currency
+ set_posting_time: DF.Check
+ stock_items: DF.Table[AssetCapitalizationStockItem]
+ stock_items_total: DF.Currency
+ target_asset: DF.Link | None
+ target_asset_location: DF.Link | None
+ target_asset_name: DF.Data | None
+ target_batch_no: DF.Link | None
+ target_fixed_asset_account: DF.Link | None
+ target_has_batch_no: DF.Check
+ target_has_serial_no: DF.Check
+ target_incoming_rate: DF.Currency
+ target_is_fixed_asset: DF.Check
+ target_item_code: DF.Link | None
+ target_item_name: DF.Data | None
+ target_qty: DF.Float
+ target_serial_no: DF.SmallText | None
+ target_stock_uom: DF.Link | None
+ target_warehouse: DF.Link | None
+ title: DF.Data | None
+ total_value: DF.Currency
+ # end: auto-generated types
+
def validate(self):
self.validate_posting_time()
self.set_missing_values(for_validate=True)
@@ -90,6 +143,10 @@ class AssetCapitalization(StockController):
self.make_gl_entries()
self.restore_consumed_asset_items()
+ def on_trash(self):
+ frappe.db.set_value("Asset", self.target_asset, "capitalized_in", None)
+ super().on_trash()
+
def cancel_target_asset(self):
if self.entry_type == "Capitalization" and self.target_asset:
asset_doc = frappe.get_doc("Asset", self.target_asset)
diff --git a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py
index 32c6122609b4883ec72501066c91e7c62d4908e4..31723ef3be318497bfd38d560bf644621393aad3 100644
--- a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py
+++ b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py
@@ -321,7 +321,7 @@ class TestAssetCapitalization(unittest.TestCase):
)
first_asset_depr_schedule = get_asset_depr_schedule_doc(consumed_asset.name, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Active")
# Create and submit Asset Captitalization
asset_capitalization = create_asset_capitalization(
@@ -355,8 +355,8 @@ class TestAssetCapitalization(unittest.TestCase):
first_asset_depr_schedule.load_from_db()
second_asset_depr_schedule = get_asset_depr_schedule_doc(consumed_asset.name, "Active")
- self.assertEquals(second_asset_depr_schedule.status, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
+ self.assertEqual(second_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Cancelled")
depr_schedule_of_consumed_asset = second_asset_depr_schedule.get("depreciation_schedule")
@@ -365,9 +365,7 @@ class TestAssetCapitalization(unittest.TestCase):
for d in depr_schedule_of_consumed_asset
if getdate(d.schedule_date) == getdate(capitalization_date)
]
- self.assertTrue(
- consumed_depreciation_schedule and consumed_depreciation_schedule[0].journal_entry
- )
+ self.assertTrue(consumed_depreciation_schedule and consumed_depreciation_schedule[0].journal_entry)
self.assertEqual(
consumed_depreciation_schedule[0].depreciation_amount, depreciation_before_disposal_amount
)
@@ -390,15 +388,9 @@ class TestAssetCapitalization(unittest.TestCase):
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):
diff --git a/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.json b/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.json
index ebaaffbad15e97e6477bf55efbda65cecb52036b..9a6b02e5442329f676f7f24e58cca591c1bce73a 100644
--- a/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.json
+++ b/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.json
@@ -116,13 +116,14 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-09-12 14:30:02.915132",
+ "modified": "2024-03-27 13:06:33.350191",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Capitalization Asset Item",
"owner": "Administrator",
"permissions": [],
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
+ "states": [],
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.py b/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.py
index ba356d6b9f01448f4734f50ba3414f6f21534719..003973f94d4ab97ea79f0ae3330402acc64cc359 100644
--- a/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.py
+++ b/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.py
@@ -6,4 +6,26 @@ from frappe.model.document import Document
class AssetCapitalizationAssetItem(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ asset: DF.Link
+ asset_name: DF.Data | None
+ asset_value: DF.Currency
+ cost_center: DF.Link | None
+ current_asset_value: DF.Currency
+ finance_book: DF.Link | None
+ fixed_asset_account: DF.Link | None
+ item_code: DF.Link
+ item_name: DF.Data | None
+ parent: DF.Data
+ parentfield: DF.Data
+ parenttype: DF.Data
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.json b/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.json
index 75691eaf9de0b2bdbe6bc3b18f3a9fc78b06f2a0..6d74e873e5cc569687a884fa119c2ea00e288465 100644
--- a/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.json
+++ b/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.json
@@ -110,13 +110,13 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2024-03-05 11:23:40.766844",
+ "modified": "2024-03-27 13:06:33.503815",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Capitalization Service Item",
"owner": "Administrator",
"permissions": [],
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
diff --git a/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.py b/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.py
index 28d018ee39a5a776db3170b3d66b69bf9547eac6..93457f87853a9c1555654135ffa84e4168265e47 100644
--- a/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.py
+++ b/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.py
@@ -6,4 +6,25 @@ from frappe.model.document import Document
class AssetCapitalizationServiceItem(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ amount: DF.Currency
+ cost_center: DF.Link | None
+ expense_account: DF.Link
+ item_code: DF.Link | None
+ item_name: DF.Data | None
+ parent: DF.Data
+ parentfield: DF.Data
+ parenttype: DF.Data
+ qty: DF.Float
+ rate: DF.Currency
+ uom: DF.Link | None
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json b/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json
index 2874aedd87faa8985450bad946c69a6575ef79a5..e863298fbfd0ee477e0ebc781ade417b025f68c7 100644
--- a/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json
+++ b/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json
@@ -178,13 +178,13 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2024-03-05 11:22:57.346889",
+ "modified": "2024-03-27 13:06:33.664691",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Capitalization Stock Item",
"owner": "Administrator",
"permissions": [],
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
diff --git a/erpnext/assets/doctype/asset_category/asset_category.js b/erpnext/assets/doctype/asset_category/asset_category.js
index 7dde14ea0e61ba520a29e7d2e34c3bffda77fa1c..046b62f244e2ee63a3c7c28fbc3678714a9018d0 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.js
+++ b/erpnext/assets/doctype/asset_category/asset_category.js
@@ -1,56 +1,55 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Asset Category', {
- onload: function(frm) {
- frm.add_fetch('company_name', 'accumulated_depreciation_account', 'accumulated_depreciation_account');
- frm.add_fetch('company_name', 'depreciation_expense_account', 'depreciation_expense_account');
+frappe.ui.form.on("Asset Category", {
+ onload: function (frm) {
+ frm.add_fetch("company_name", "accumulated_depreciation_account", "accumulated_depreciation_account");
+ frm.add_fetch("company_name", "depreciation_expense_account", "depreciation_expense_account");
- frm.set_query('fixed_asset_account', 'accounts', function(doc, cdt, cdn) {
- var d = locals[cdt][cdn];
+ frm.set_query("fixed_asset_account", "accounts", function (doc, cdt, cdn) {
+ var d = locals[cdt][cdn];
return {
- "filters": {
- "account_type": "Fixed Asset",
- "root_type": "Asset",
- "is_group": 0,
- "company": d.company_name
- }
+ filters: {
+ account_type: "Fixed Asset",
+ root_type: "Asset",
+ is_group: 0,
+ company: d.company_name,
+ },
};
});
- frm.set_query('accumulated_depreciation_account', 'accounts', function(doc, cdt, cdn) {
- var d = locals[cdt][cdn];
+ frm.set_query("accumulated_depreciation_account", "accounts", function (doc, cdt, cdn) {
+ var d = locals[cdt][cdn];
return {
- "filters": {
- "account_type": "Accumulated Depreciation",
- "is_group": 0,
- "company": d.company_name
- }
+ filters: {
+ account_type: "Accumulated Depreciation",
+ is_group: 0,
+ company: d.company_name,
+ },
};
});
- frm.set_query('depreciation_expense_account', 'accounts', function(doc, cdt, cdn) {
- var d = locals[cdt][cdn];
+ frm.set_query("depreciation_expense_account", "accounts", function (doc, cdt, cdn) {
+ var d = locals[cdt][cdn];
return {
- "filters": {
- "account_type": "Depreciation",
- "root_type": ["in", ["Expense", "Income"]],
- "is_group": 0,
- "company": d.company_name
- }
+ filters: {
+ account_type: "Depreciation",
+ root_type: ["in", ["Expense", "Income"]],
+ is_group: 0,
+ company: d.company_name,
+ },
};
});
- frm.set_query('capital_work_in_progress_account', 'accounts', function(doc, cdt, cdn) {
- var d = locals[cdt][cdn];
+ frm.set_query("capital_work_in_progress_account", "accounts", function (doc, cdt, cdn) {
+ var d = locals[cdt][cdn];
return {
- "filters": {
- "account_type": "Capital Work in Progress",
- "is_group": 0,
- "company": d.company_name
- }
+ filters: {
+ account_type: "Capital Work in Progress",
+ is_group: 0,
+ company: d.company_name,
+ },
};
});
-
- }
+ },
});
diff --git a/erpnext/assets/doctype/asset_category/asset_category.json b/erpnext/assets/doctype/asset_category/asset_category.json
index 0283f095ff5a51ae5dc2c4f2dbb6804679aad590..e58e9c0676f477fe2f8d4e9df730f9df75b5765c 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.json
+++ b/erpnext/assets/doctype/asset_category/asset_category.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:asset_category_name",
@@ -65,7 +66,7 @@
}
],
"links": [],
- "modified": "2021-01-22 12:31:14.425319",
+ "modified": "2024-03-27 13:06:33.840414",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Category",
@@ -111,7 +112,8 @@
}
],
"show_name_in_global_search": 1,
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
+ "states": [],
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py
index 9cf3bf35b3706ca5cb44f09a7a6e9e6b99031369..8c2d301a8950f7937f47764f53d807982601e054 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.py
+++ b/erpnext/assets/doctype/asset_category/asset_category.py
@@ -9,6 +9,25 @@ from frappe.utils import cint, get_link_to_form
class AssetCategory(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ from erpnext.assets.doctype.asset_category_account.asset_category_account import (
+ AssetCategoryAccount,
+ )
+ from erpnext.assets.doctype.asset_finance_book.asset_finance_book import AssetFinanceBook
+
+ accounts: DF.Table[AssetCategoryAccount]
+ asset_category_name: DF.Data
+ enable_cwip_accounting: DF.Check
+ finance_books: DF.Table[AssetFinanceBook]
+ # end: auto-generated types
+
def validate(self):
self.validate_finance_books()
self.validate_account_types()
@@ -38,7 +57,9 @@ class AssetCategory(Document):
account_currency = frappe.get_value("Account", d.get(type_of_account), "account_currency")
if account_currency != company_currency:
invalid_accounts.append(
- frappe._dict({"type": type_of_account, "idx": d.idx, "account": d.get(type_of_account)})
+ frappe._dict(
+ {"type": type_of_account, "idx": d.idx, "account": d.get(type_of_account)}
+ )
)
for d in invalid_accounts:
@@ -87,8 +108,7 @@ class AssetCategory(Document):
missing_cwip_accounts_for_company.append(get_link_to_form("Company", d.company_name))
if missing_cwip_accounts_for_company:
- msg = _("""To enable Capital Work in Progress Accounting,""")
- msg += " "
+ msg = _("""To enable Capital Work in Progress Accounting,""") + " "
msg += _("""you must select Capital Work in Progress Account in accounts table""")
msg += "
"
msg += _("You can also set default CWIP account in Company {}").format(
diff --git a/erpnext/assets/doctype/asset_category/test_asset_category.py b/erpnext/assets/doctype/asset_category/test_asset_category.py
index 31aeeec5d740e2113350d50f1b9ab96de6356c6e..516e27e00fa221c5767a3fbc80a737403d51a554 100644
--- a/erpnext/assets/doctype/asset_category/test_asset_category.py
+++ b/erpnext/assets/doctype/asset_category/test_asset_category.py
@@ -1,7 +1,6 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
-
import unittest
import frappe
@@ -27,14 +26,12 @@ class TestAssetCategory(unittest.TestCase):
)
try:
- asset_category.insert()
+ asset_category.insert(ignore_if_duplicate=True)
except frappe.DuplicateEntryError:
pass
def test_cwip_accounting(self):
- company_cwip_acc = frappe.db.get_value(
- "Company", "_Test Company", "capital_work_in_progress_account"
- )
+ frappe.db.get_value("Company", "_Test Company", "capital_work_in_progress_account")
frappe.db.set_value("Company", "_Test Company", "capital_work_in_progress_account", "")
asset_category = frappe.new_doc("Asset Category")
diff --git a/erpnext/assets/doctype/asset_category_account/asset_category_account.json b/erpnext/assets/doctype/asset_category_account/asset_category_account.json
index b7df55755281f4cb6d7c184ceef5d714edf63b35..8fa7488458322079a1bc3e3637b60e163978ab64 100644
--- a/erpnext/assets/doctype/asset_category_account/asset_category_account.json
+++ b/erpnext/assets/doctype/asset_category_account/asset_category_account.json
@@ -1,196 +1,71 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2016-03-07 15:55:18.806409",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "creation": "2016-03-07 15:55:18.806409",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company_name",
+ "fixed_asset_account",
+ "accumulated_depreciation_account",
+ "depreciation_expense_account",
+ "capital_work_in_progress_account"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "company_name",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "company_name",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "fixed_asset_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Fixed Asset Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "fixed_asset_account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Fixed Asset Account",
+ "options": "Account",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "accumulated_depreciation_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Accumulated Depreciation Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "accumulated_depreciation_account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Accumulated Depreciation Account",
+ "options": "Account"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "depreciation_expense_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Depreciation Expense Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "depreciation_expense_account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Depreciation Expense Account",
+ "options": "Account"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "capital_work_in_progress_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Capital Work In Progress Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
+ "columns": 2,
+ "fieldname": "capital_work_in_progress_account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Capital Work In Progress Account",
+ "options": "Account"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2018-05-10 17:06:48.839347",
- "modified_by": "Administrator",
- "module": "Assets",
- "name": "Asset Category Account",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2024-03-27 13:06:34.012854",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset Category Account",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "states": [],
+ "track_changes": 1
+}
diff --git a/erpnext/assets/doctype/asset_category_account/asset_category_account.py b/erpnext/assets/doctype/asset_category_account/asset_category_account.py
index cce22734f9963cf34dff39759e5007a540a3a1e2..2798f1cd6b580dad35c526566cf40999cd4e5516 100644
--- a/erpnext/assets/doctype/asset_category_account/asset_category_account.py
+++ b/erpnext/assets/doctype/asset_category_account/asset_category_account.py
@@ -2,9 +2,26 @@
# For license information, please see license.txt
-import frappe
from frappe.model.document import Document
class AssetCategoryAccount(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ accumulated_depreciation_account: DF.Link | None
+ capital_work_in_progress_account: DF.Link | None
+ company_name: DF.Link
+ depreciation_expense_account: DF.Link | None
+ fixed_asset_account: DF.Link
+ parent: DF.Data
+ parentfield: DF.Data
+ parenttype: DF.Data
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js
index 3d2dff179aa0b9b2dc018b4b67e060a7af0ff24a..83b5c376ac77c01a8dfcd553671c427ff2f57a87 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js
@@ -2,50 +2,63 @@
// For license information, please see license.txt
frappe.provide("erpnext.asset");
-frappe.ui.form.on('Asset Depreciation Schedule', {
- onload: function(frm) {
+frappe.ui.form.on("Asset Depreciation Schedule", {
+ onload: function (frm) {
frm.events.make_schedules_editable(frm);
},
- make_schedules_editable: function(frm) {
- var is_editable = frm.doc.depreciation_method == "Manual" ? true : false;
+ make_schedules_editable: function (frm) {
+ var is_manual_hence_editable = frm.doc.depreciation_method === "Manual" ? true : false;
+ var is_shift_hence_editable = frm.doc.shift_based ? true : false;
- frm.toggle_enable("depreciation_schedule", is_editable);
- frm.fields_dict["depreciation_schedule"].grid.toggle_enable("schedule_date", is_editable);
- frm.fields_dict["depreciation_schedule"].grid.toggle_enable("depreciation_amount", is_editable);
- }
+ frm.toggle_enable("depreciation_schedule", is_manual_hence_editable || is_shift_hence_editable);
+ frm.fields_dict["depreciation_schedule"].grid.toggle_enable(
+ "schedule_date",
+ is_manual_hence_editable
+ );
+ frm.fields_dict["depreciation_schedule"].grid.toggle_enable(
+ "depreciation_amount",
+ is_manual_hence_editable
+ );
+ frm.fields_dict["depreciation_schedule"].grid.toggle_enable("shift", is_shift_hence_editable);
+ },
});
-frappe.ui.form.on('Depreciation Schedule', {
- make_depreciation_entry: function(frm, cdt, cdn) {
+frappe.ui.form.on("Depreciation Schedule", {
+ make_depreciation_entry: function (frm, cdt, cdn) {
var row = locals[cdt][cdn];
if (!row.journal_entry) {
frappe.call({
method: "erpnext.assets.doctype.asset.depreciation.make_depreciation_entry",
args: {
- "asset_depr_schedule_name": frm.doc.name,
- "date": row.schedule_date
+ asset_depr_schedule_name: frm.doc.name,
+ date: row.schedule_date,
},
- callback: function(r) {
+ callback: function (r) {
frappe.model.sync(r.message);
frm.refresh();
- }
- })
+ },
+ });
}
},
- depreciation_amount: function(frm, cdt, cdn) {
+ depreciation_amount: function (frm, cdt, cdn) {
erpnext.asset.set_accumulated_depreciation(frm);
- }
+ },
});
-erpnext.asset.set_accumulated_depreciation = function(frm) {
- if(frm.doc.depreciation_method != "Manual") return;
+erpnext.asset.set_accumulated_depreciation = function (frm) {
+ if (frm.doc.depreciation_method != "Manual") return;
var accumulated_depreciation = flt(frm.doc.opening_accumulated_depreciation);
- $.each(frm.doc.depreciation_schedule || [], function(i, row) {
- accumulated_depreciation += flt(row.depreciation_amount);
- frappe.model.set_value(row.doctype, row.name, "accumulated_depreciation_amount", accumulated_depreciation);
- })
+ $.each(frm.doc.depreciation_schedule || [], function (i, row) {
+ accumulated_depreciation += flt(row.depreciation_amount);
+ frappe.model.set_value(
+ row.doctype,
+ row.name,
+ "accumulated_depreciation_amount",
+ accumulated_depreciation
+ );
+ });
};
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json
index 5487cded84ab37ace5af785104a89187508b0cfb..3a540d82d0407d637b3bf907eb4d6c72eb17111f 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json
@@ -13,13 +13,15 @@
"column_break_2",
"gross_purchase_amount",
"opening_accumulated_depreciation",
- "number_of_depreciations_booked",
+ "opening_number_of_booked_depreciations",
"finance_book",
"finance_book_id",
"depreciation_details_section",
"depreciation_method",
"total_number_of_depreciations",
"rate_of_depreciation",
+ "daily_prorata_based",
+ "shift_based",
"column_break_8",
"frequency_of_depreciation",
"expected_value_after_useful_life",
@@ -169,19 +171,28 @@
"read_only": 1
},
{
- "fieldname": "number_of_depreciations_booked",
+ "fieldname": "opening_number_of_booked_depreciations",
"fieldtype": "Int",
"hidden": 1,
- "label": "Number of Depreciations Booked",
+ "label": "Opening Number of Booked Depreciations",
"print_hide": 1,
"read_only": 1
},
{
- "fetch_from": "asset.company",
- "fieldname": "company",
- "fieldtype": "Link",
- "label": "Company",
- "options": "Company",
+ "default": "0",
+ "depends_on": "eval:doc.depreciation_method == \"Straight Line\" || doc.depreciation_method == \"Manual\"",
+ "fieldname": "daily_prorata_based",
+ "fieldtype": "Check",
+ "label": "Depreciate based on daily pro-rata",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:doc.depreciation_method == \"Straight Line\"",
+ "fieldname": "shift_based",
+ "fieldtype": "Check",
+ "label": "Depreciate based on shifts",
"read_only": 1
},
{
@@ -196,7 +207,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2024-01-08 16:31:04.533928",
+ "modified": "2024-03-27 13:06:34.135004",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Depreciation Schedule",
@@ -233,7 +244,7 @@
"write": 1
}
],
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": []
}
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
index 448c34f36ce236421978a21af055c416ae2da2f2..eb0135033b0e8fbf40251295767a87a2b2990cef 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
@@ -50,7 +50,7 @@ class AssetDepreciationSchedule(Document):
gross_purchase_amount: DF.Currency
naming_series: DF.Literal["ACC-ADS-.YYYY.-"]
notes: DF.SmallText | None
- number_of_depreciations_booked: DF.Int
+ opening_number_of_booked_depreciations: DF.Int
opening_accumulated_depreciation: DF.Currency
rate_of_depreciation: DF.Percent
shift_based: DF.Check
@@ -63,6 +63,7 @@ class AssetDepreciationSchedule(Document):
self.prepare_draft_asset_depr_schedule_data_from_asset_name_and_fb_name(
self.asset, self.finance_book
)
+ self.update_shift_depr_schedule()
def validate(self):
self.validate_another_asset_depr_schedule_does_not_exist()
@@ -110,6 +111,16 @@ class AssetDepreciationSchedule(Document):
def on_cancel(self):
self.db_set("status", "Cancelled")
+ def update_shift_depr_schedule(self):
+ if not self.shift_based or self.docstatus != 0:
+ return
+
+ asset_doc = frappe.get_doc("Asset", self.asset)
+ fb_row = asset_doc.finance_books[self.finance_book_id - 1]
+
+ self.make_depr_schedule(asset_doc, fb_row)
+ self.set_accumulated_depreciation(asset_doc, fb_row)
+
def prepare_draft_asset_depr_schedule_data_from_asset_name_and_fb_name(self, asset_name, fb_name):
asset_doc = frappe.get_doc("Asset", asset_name)
@@ -150,7 +161,7 @@ class AssetDepreciationSchedule(Document):
return (
asset_doc.gross_purchase_amount != self.gross_purchase_amount
or asset_doc.opening_accumulated_depreciation != self.opening_accumulated_depreciation
- or asset_doc.number_of_depreciations_booked != self.number_of_depreciations_booked
+ or asset_doc.opening_number_of_booked_depreciations != self.opening_number_of_booked_depreciations
)
def not_manual_depr_or_have_manual_depr_details_been_modified(self, row):
@@ -183,20 +194,22 @@ class AssetDepreciationSchedule(Document):
self.finance_book = row.finance_book
self.finance_book_id = row.idx
self.opening_accumulated_depreciation = asset_doc.opening_accumulated_depreciation or 0
- self.number_of_depreciations_booked = asset_doc.number_of_depreciations_booked or 0
+ self.opening_number_of_booked_depreciations = asset_doc.opening_number_of_booked_depreciations or 0
self.gross_purchase_amount = asset_doc.gross_purchase_amount
self.depreciation_method = row.depreciation_method
self.total_number_of_depreciations = row.total_number_of_depreciations
self.frequency_of_depreciation = row.frequency_of_depreciation
self.rate_of_depreciation = row.rate_of_depreciation
self.expected_value_after_useful_life = row.expected_value_after_useful_life
+ self.daily_prorata_based = row.daily_prorata_based
+ self.shift_based = row.shift_based
self.status = "Draft"
def make_depr_schedule(
self,
asset_doc,
row,
- date_of_disposal,
+ date_of_disposal=None,
update_asset_finance_book_row=True,
value_after_depreciation=None,
):
@@ -217,6 +230,8 @@ class AssetDepreciationSchedule(Document):
num_of_depreciations_completed = 0
depr_schedule = []
+ self.schedules_before_clearing = self.get("depreciation_schedule")
+
for schedule in self.get("depreciation_schedule"):
if schedule.journal_entry:
num_of_depreciations_completed += 1
@@ -248,7 +263,7 @@ class AssetDepreciationSchedule(Document):
row.db_update()
final_number_of_depreciations = cint(row.total_number_of_depreciations) - cint(
- self.number_of_depreciations_booked
+ self.opening_number_of_booked_depreciations
)
has_pro_rata = _check_is_pro_rata(asset_doc, row)
@@ -260,9 +275,7 @@ class AssetDepreciationSchedule(Document):
row.depreciation_method in ("Written Down Value", "Double Declining Balance")
and cint(row.frequency_of_depreciation) != 12
):
- has_wdv_or_dd_non_yearly_pro_rata = _check_is_pro_rata(
- asset_doc, row, wdv_or_dd_non_yearly=True
- )
+ has_wdv_or_dd_non_yearly_pro_rata = _check_is_pro_rata(asset_doc, row, wdv_or_dd_non_yearly=True)
skip_row = False
should_get_last_day = is_last_day_of_the_month(row.depreciation_start_date)
@@ -272,6 +285,7 @@ class AssetDepreciationSchedule(Document):
number_of_pending_depreciations = final_number_of_depreciations - start
yearly_opening_wdv = value_after_depreciation
current_fiscal_year_end_date = None
+ prev_per_day_depr = True
for n in range(start, final_number_of_depreciations):
# If depreciation is already completed (for double declining balance)
if skip_row:
@@ -288,8 +302,7 @@ class AssetDepreciationSchedule(Document):
prev_depreciation_amount = self.get("depreciation_schedule")[n - 1].depreciation_amount
else:
prev_depreciation_amount = 0
-
- depreciation_amount = get_depreciation_amount(
+ depreciation_amount, prev_per_day_depr = get_depreciation_amount(
self,
asset_doc,
value_after_depreciation,
@@ -299,8 +312,8 @@ class AssetDepreciationSchedule(Document):
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
number_of_pending_depreciations,
+ prev_per_day_depr,
)
-
if not has_pro_rata or (
n < (cint(final_number_of_depreciations) - 1) or final_number_of_depreciations == 2
):
@@ -315,9 +328,8 @@ class AssetDepreciationSchedule(Document):
if date_of_disposal and getdate(schedule_date) >= getdate(date_of_disposal):
from_date = add_months(
getdate(asset_doc.available_for_use_date),
- (asset_doc.number_of_depreciations_booked * row.frequency_of_depreciation),
+ (asset_doc.opening_number_of_booked_depreciations * row.frequency_of_depreciation),
)
-
if self.depreciation_schedule:
from_date = self.depreciation_schedule[-1].schedule_date
@@ -326,13 +338,11 @@ class AssetDepreciationSchedule(Document):
depreciation_amount,
from_date,
date_of_disposal,
+ original_schedule_date=schedule_date,
)
if depreciation_amount > 0:
- self.add_depr_schedule_row(
- date_of_disposal,
- depreciation_amount,
- )
+ self.add_depr_schedule_row(date_of_disposal, depreciation_amount, n)
break
@@ -346,7 +356,6 @@ class AssetDepreciationSchedule(Document):
from_date = add_days(
asset_doc.available_for_use_date, -1
) # needed to calc depr amount for available_for_use_date too
-
depreciation_amount, days, months = _get_pro_rata_amt(
row,
depreciation_amount,
@@ -369,13 +378,16 @@ class AssetDepreciationSchedule(Document):
from_date = get_last_day(
add_months(
getdate(asset_doc.available_for_use_date),
- ((self.number_of_depreciations_booked - 1) * row.frequency_of_depreciation),
+ (
+ (self.opening_number_of_booked_depreciations - 1)
+ * row.frequency_of_depreciation
+ ),
)
)
else:
from_date = add_months(
getdate(add_days(asset_doc.available_for_use_date, -1)),
- (self.number_of_depreciations_booked * row.frequency_of_depreciation),
+ (self.opening_number_of_booked_depreciations * row.frequency_of_depreciation),
)
depreciation_amount, days, months = _get_pro_rata_amt(
row,
@@ -391,7 +403,8 @@ class AssetDepreciationSchedule(Document):
# In case of increase_in_asset_life, the asset.to_date is already set on asset_repair submission
asset_doc.to_date = add_months(
asset_doc.available_for_use_date,
- (n + self.number_of_depreciations_booked) * cint(row.frequency_of_depreciation),
+ (n + self.opening_number_of_booked_depreciations)
+ * cint(row.frequency_of_depreciation),
)
depreciation_amount_without_pro_rata = depreciation_amount
@@ -408,7 +421,7 @@ class AssetDepreciationSchedule(Document):
depreciation_amount_without_pro_rata, depreciation_amount
)
- schedule_date = asset_doc.to_date # @dokos
+ schedule_date = add_days(schedule_date, days)
if not depreciation_amount:
continue
@@ -428,10 +441,7 @@ class AssetDepreciationSchedule(Document):
skip_row = True
if flt(depreciation_amount, asset_doc.precision("gross_purchase_amount")) > 0:
- self.add_depr_schedule_row(
- schedule_date,
- depreciation_amount,
- )
+ self.add_depr_schedule_row(schedule_date, depreciation_amount, n)
# to ensure that final accumulated depreciation amount is accurate
def get_adjusted_depreciation_amount(
@@ -453,16 +463,22 @@ class AssetDepreciationSchedule(Document):
def get_depreciation_amount_for_first_row(self):
return self.get("depreciation_schedule")[0].depreciation_amount
- def add_depr_schedule_row(
- self,
- schedule_date,
- depreciation_amount,
- ):
+ def add_depr_schedule_row(self, schedule_date, depreciation_amount, schedule_idx):
+ if self.shift_based:
+ shift = (
+ self.schedules_before_clearing[schedule_idx].shift
+ if self.schedules_before_clearing and len(self.schedules_before_clearing) > schedule_idx
+ else frappe.get_cached_value("Asset Shift Factor", {"default": 1}, "shift_name")
+ )
+ else:
+ shift = None
+
self.append(
"depreciation_schedule",
{
"schedule_date": schedule_date,
"depreciation_amount": depreciation_amount,
+ "shift": shift,
},
)
@@ -504,6 +520,7 @@ class AssetDepreciationSchedule(Document):
and i == max(straight_line_idx) - 1
and not date_of_disposal
and not date_of_return
+ and not row.shift_based
):
depreciation_amount += flt(
value_after_depreciation - flt(row.expected_value_after_useful_life),
@@ -533,7 +550,7 @@ def _check_is_pro_rata(asset_doc, row, wdv_or_dd_non_yearly=False):
has_pro_rata = False
# if not existing asset, from_date = available_for_use_date
- # otherwise, if number_of_depreciations_booked = 2, available_for_use_date = 01/01/2020 and frequency_of_depreciation = 12
+ # otherwise, if opening_number_of_booked_depreciations = 2, available_for_use_date = 01/01/2020 and frequency_of_depreciation = 12
# from_date = 01/01/2022
from_date = _get_modified_available_for_use_date(asset_doc, row, wdv_or_dd_non_yearly)
days = date_diff(row.depreciation_start_date, from_date) + 1
@@ -547,9 +564,6 @@ def _check_is_pro_rata(asset_doc, row, wdv_or_dd_non_yearly=False):
if days < total_days:
has_pro_rata = True
- if row.depreciation_start_date == from_date:
- has_pro_rata = False # @dokos
-
return has_pro_rata
@@ -557,44 +571,48 @@ def _get_modified_available_for_use_date(asset_doc, row, wdv_or_dd_non_yearly=Fa
if wdv_or_dd_non_yearly:
return add_months(
asset_doc.available_for_use_date,
- (asset_doc.number_of_depreciations_booked * 12),
+ (asset_doc.opening_number_of_booked_depreciations * 12),
)
else:
return add_months(
asset_doc.available_for_use_date,
- (asset_doc.number_of_depreciations_booked * row.frequency_of_depreciation),
+ (asset_doc.opening_number_of_booked_depreciations * row.frequency_of_depreciation),
)
def _get_pro_rata_amt(
- row, depreciation_amount, from_date, to_date, has_wdv_or_dd_non_yearly_pro_rata=False
+ row,
+ depreciation_amount,
+ from_date,
+ to_date,
+ has_wdv_or_dd_non_yearly_pro_rata=False,
+ original_schedule_date=None,
):
- days = date_difference(to_date, from_date) # @dokos
+ days = date_diff(to_date, from_date)
months = month_diff(to_date, from_date)
if has_wdv_or_dd_non_yearly_pro_rata:
- total_days = get_total_days(to_date, 12)
+ total_days = get_total_days(original_schedule_date or to_date, 12)
else:
- total_days = get_total_days(to_date, row.frequency_of_depreciation)
+ total_days = get_total_days(original_schedule_date or to_date, row.frequency_of_depreciation)
- return (depreciation_amount * flt(days)) / flt(total_days), days, months
+ depreciation_days = date_difference(to_date, from_date) # @dokos
+ return (depreciation_amount * flt(depreciation_days)) / flt(total_days), days, months
-@erpnext.allow_regional
+@erpnext.allow_regional # @dokos
def get_total_days(date, frequency):
period_start_date = add_months(date, cint(frequency) * -1)
-
if is_last_day_of_the_month(date):
period_start_date = get_last_day(period_start_date)
+ return date_difference(date, period_start_date) # @dokos
- return date_difference(date, period_start_date)
-
-@erpnext.allow_regional
+@erpnext.allow_regional # @dokos
def date_difference(to_date, from_date):
return date_diff(to_date, from_date)
-@erpnext.allow_regional
+@erpnext.allow_regional # @dokos
def get_depreciation_amount(
asset_depr_schedule,
asset,
@@ -605,12 +623,12 @@ def get_depreciation_amount(
prev_depreciation_amount=0,
has_wdv_or_dd_non_yearly_pro_rata=False,
number_of_pending_depreciations=0,
+ prev_per_day_depr=0,
):
if fb_row.depreciation_method in ("Straight Line", "Manual"):
return get_straight_line_or_manual_depr_amount(
- asset, fb_row, schedule_idx, number_of_pending_depreciations
- )
-
+ asset_depr_schedule, asset, fb_row, schedule_idx, number_of_pending_depreciations
+ ), None
else:
return get_wdv_or_dd_depr_amount(
asset,
@@ -621,16 +639,20 @@ def get_depreciation_amount(
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
asset_depr_schedule,
+ prev_per_day_depr,
)
def get_straight_line_or_manual_depr_amount(
- asset, row, schedule_idx, number_of_pending_depreciations
+ asset_depr_schedule, asset, row, schedule_idx, number_of_pending_depreciations
):
+ if row.shift_based:
+ return get_shift_depr_amount(asset_depr_schedule, asset, row, schedule_idx)
+
# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset life and value
if asset.flags.increase_in_asset_life:
return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / (
- date_diff(asset.to_date, asset.available_for_use_date) / 365
+ date_difference(asset.to_date, asset.available_for_use_date) / 365 # @dokos
)
# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset value
elif asset.flags.increase_in_asset_value_due_to_repair:
@@ -639,16 +661,89 @@ def get_straight_line_or_manual_depr_amount(
)
# if the Depreciation Schedule is being modified after Asset Value Adjustment due to decrease in asset value
elif asset.flags.decrease_in_asset_value_due_to_value_adjustment:
- return (
- flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
- ) / number_of_pending_depreciations
+ if row.daily_prorata_based:
+ amount = flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
+
+ return get_daily_prorata_based_straight_line_depr(
+ asset,
+ row,
+ schedule_idx,
+ number_of_pending_depreciations,
+ amount,
+ )
+ else:
+ return (
+ flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
+ ) / number_of_pending_depreciations
# if the Depreciation Schedule is being prepared for the first time
else:
+ if row.daily_prorata_based:
+ amount = (
+ flt(asset.gross_purchase_amount)
+ - flt(asset.opening_accumulated_depreciation)
+ - flt(row.expected_value_after_useful_life)
+ )
+ return get_daily_prorata_based_straight_line_depr(
+ asset, row, schedule_idx, number_of_pending_depreciations, amount
+ )
+ else:
+ return (
+ flt(asset.gross_purchase_amount)
+ - flt(asset.opening_accumulated_depreciation)
+ - flt(row.expected_value_after_useful_life)
+ ) / flt(row.total_number_of_depreciations - asset.opening_number_of_booked_depreciations)
+
+
+def get_daily_prorata_based_straight_line_depr(
+ asset, row, schedule_idx, number_of_pending_depreciations, amount
+):
+ total_years = flt(number_of_pending_depreciations * row.frequency_of_depreciation) / 12
+ every_year_depr = amount / total_years
+
+ year_start_date = add_years(
+ row.depreciation_start_date, (row.frequency_of_depreciation * schedule_idx) // 12
+ )
+ year_end_date = add_days(add_years(year_start_date, 1), -1)
+ daily_depr_amount = every_year_depr / (date_diff(year_end_date, year_start_date) + 1)
+ from_date, total_depreciable_days = _get_total_days(
+ row.depreciation_start_date, schedule_idx, row.frequency_of_depreciation
+ )
+ return daily_depr_amount * total_depreciable_days
+
+
+def get_shift_depr_amount(asset_depr_schedule, asset, row, schedule_idx):
+ if asset_depr_schedule.get("__islocal") and not asset.flags.shift_allocation:
return (
flt(asset.gross_purchase_amount)
- flt(asset.opening_accumulated_depreciation)
- flt(row.expected_value_after_useful_life)
- ) / flt(row.total_number_of_depreciations - asset.number_of_depreciations_booked)
+ ) / flt(row.total_number_of_depreciations - asset.opening_number_of_booked_depreciations)
+
+ asset_shift_factors_map = get_asset_shift_factors_map()
+ shift = (
+ asset_depr_schedule.schedules_before_clearing[schedule_idx].shift
+ if len(asset_depr_schedule.schedules_before_clearing) > schedule_idx
+ else None
+ )
+ shift_factor = asset_shift_factors_map.get(shift) if shift else 0
+
+ shift_factors_sum = sum(
+ flt(asset_shift_factors_map.get(schedule.shift))
+ for schedule in asset_depr_schedule.schedules_before_clearing
+ )
+
+ return (
+ (
+ flt(asset.gross_purchase_amount)
+ - flt(asset.opening_accumulated_depreciation)
+ - flt(row.expected_value_after_useful_life)
+ )
+ / flt(shift_factors_sum)
+ ) * shift_factor
+
+
+def get_asset_shift_factors_map():
+ return dict(frappe.db.get_all("Asset Shift Factor", ["shift_name", "shift_factor"], as_list=True))
@erpnext.allow_regional
@@ -661,6 +756,7 @@ def get_wdv_or_dd_depr_amount(
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
asset_depr_schedule,
+ prev_per_day_depr,
):
return get_default_wdv_or_dd_depr_amount(
asset,
@@ -670,6 +766,7 @@ def get_wdv_or_dd_depr_amount(
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
asset_depr_schedule,
+ prev_per_day_depr,
)
@@ -681,6 +778,39 @@ def get_default_wdv_or_dd_depr_amount(
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
asset_depr_schedule,
+ prev_per_day_depr,
+):
+ if not fb_row.daily_prorata_based or cint(fb_row.frequency_of_depreciation) == 12:
+ return _get_default_wdv_or_dd_depr_amount(
+ asset,
+ fb_row,
+ depreciable_value,
+ schedule_idx,
+ prev_depreciation_amount,
+ has_wdv_or_dd_non_yearly_pro_rata,
+ asset_depr_schedule,
+ ), None
+ else:
+ return _get_daily_prorata_based_default_wdv_or_dd_depr_amount(
+ asset,
+ fb_row,
+ depreciable_value,
+ schedule_idx,
+ prev_depreciation_amount,
+ has_wdv_or_dd_non_yearly_pro_rata,
+ asset_depr_schedule,
+ prev_per_day_depr,
+ )
+
+
+def _get_default_wdv_or_dd_depr_amount(
+ asset,
+ fb_row,
+ depreciable_value,
+ schedule_idx,
+ prev_depreciation_amount,
+ has_wdv_or_dd_non_yearly_pro_rata,
+ asset_depr_schedule,
):
if cint(fb_row.frequency_of_depreciation) == 12:
return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100)
@@ -707,6 +837,75 @@ def get_default_wdv_or_dd_depr_amount(
return prev_depreciation_amount
+def _get_daily_prorata_based_default_wdv_or_dd_depr_amount(
+ asset,
+ fb_row,
+ depreciable_value,
+ schedule_idx,
+ prev_depreciation_amount,
+ has_wdv_or_dd_non_yearly_pro_rata,
+ asset_depr_schedule,
+ prev_per_day_depr,
+):
+ if has_wdv_or_dd_non_yearly_pro_rata: # If applicable days for ther first month is less than full month
+ if schedule_idx == 0:
+ return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100), None
+
+ elif schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 1: # Year changes
+ return get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value)
+ else:
+ return get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, prev_per_day_depr)
+ else:
+ if schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 0: # year changes
+ return get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value)
+ else:
+ return get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, prev_per_day_depr)
+
+
+def get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value):
+ """ "
+ Returns monthly depreciation amount when year changes
+ 1. Calculate per day depr based on new year
+ 2. Calculate monthly amount based on new per day amount
+ """
+ from_date, days_in_month = _get_total_days(
+ fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation)
+ )
+ per_day_depr = get_per_day_depr(fb_row, depreciable_value, from_date)
+ return (per_day_depr * days_in_month), per_day_depr
+
+
+def get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, prev_per_day_depr):
+ """ "
+ Returns monthly depreciation amount based on prev per day depr
+ Calculate per day depr only for the first month
+ """
+ from_date, days_in_month = _get_total_days(
+ fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation)
+ )
+ return (prev_per_day_depr * days_in_month), prev_per_day_depr
+
+
+def get_per_day_depr(
+ fb_row,
+ depreciable_value,
+ from_date,
+):
+ to_date = add_days(add_years(from_date, 1), -1)
+ total_days = date_diff(to_date, from_date) + 1
+ per_day_depr = (flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100)) / total_days
+ return per_day_depr
+
+
+def _get_total_days(depreciation_start_date, schedule_idx, frequency_of_depreciation):
+ from_date = add_months(depreciation_start_date, (schedule_idx - 1) * frequency_of_depreciation)
+ to_date = add_months(from_date, frequency_of_depreciation)
+ if is_last_day_of_the_month(depreciation_start_date):
+ to_date = get_last_day(to_date)
+ from_date = add_days(get_last_day(from_date), 1)
+ return from_date, date_diff(to_date, from_date) + 1
+
+
def make_draft_asset_depr_schedules_if_not_present(asset_doc):
asset_depr_schedules_names = []
@@ -822,11 +1021,14 @@ def make_new_active_asset_depr_schedules_and_cancel_current_ones(
def get_temp_asset_depr_schedule_doc(
- asset_doc, row, date_of_disposal=None, date_of_return=None, update_asset_finance_book_row=False
+ asset_doc,
+ row,
+ date_of_disposal=None,
+ date_of_return=None,
+ update_asset_finance_book_row=False,
+ new_depr_schedule=None,
):
- current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(
- asset_doc.name, "Active", row.finance_book
- )
+ current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, "Active", row.finance_book)
if not current_asset_depr_schedule_doc:
frappe.throw(
@@ -837,6 +1039,21 @@ def get_temp_asset_depr_schedule_doc(
temp_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc)
+ if new_depr_schedule:
+ temp_asset_depr_schedule_doc.depreciation_schedule = []
+
+ for schedule in new_depr_schedule:
+ temp_asset_depr_schedule_doc.append(
+ "depreciation_schedule",
+ {
+ "schedule_date": schedule.schedule_date,
+ "depreciation_amount": schedule.depreciation_amount,
+ "accumulated_depreciation_amount": schedule.accumulated_depreciation_amount,
+ "journal_entry": schedule.journal_entry,
+ "shift": schedule.shift,
+ },
+ )
+
temp_asset_depr_schedule_doc.prepare_draft_asset_depr_schedule_data(
asset_doc,
row,
@@ -858,15 +1075,14 @@ def get_depr_schedule(asset_name, status, finance_book=None):
return asset_depr_schedule_doc.get("depreciation_schedule")
+@frappe.whitelist()
def get_asset_depr_schedule_doc(asset_name, status, finance_book=None):
asset_depr_schedule = get_asset_depr_schedule_name(asset_name, status, finance_book)
if not asset_depr_schedule:
return
- asset_depr_schedule_doc = frappe.get_doc(
- "Asset Depreciation Schedule", asset_depr_schedule[0].name
- )
+ asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule[0].name)
return asset_depr_schedule_doc
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
index 024121d39435a5f1fff7f8b148f0076af81770a6..6009ac1496cb67483ec24f29755a1c238acb9369 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
@@ -3,10 +3,15 @@
import frappe
from frappe.tests.utils import FrappeTestCase
+from frappe.utils import cstr
+from erpnext.assets.doctype.asset.depreciation import (
+ post_depreciation_entries,
+)
from erpnext.assets.doctype.asset.test_asset import create_asset, create_asset_data
from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
get_asset_depr_schedule_doc,
+ get_depr_schedule,
)
@@ -18,10 +23,175 @@ class TestAssetDepreciationSchedule(FrappeTestCase):
asset = create_asset(item_code="Macbook Pro", calculate_depreciation=1, submit=1)
first_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Active")
second_asset_depr_schedule = frappe.get_doc(
{"doctype": "Asset Depreciation Schedule", "asset": asset.name, "finance_book": None}
)
self.assertRaises(frappe.ValidationError, second_asset_depr_schedule.insert)
+
+ def test_daily_prorata_based_depr_on_sl_method(self):
+ asset = create_asset(
+ calculate_depreciation=1,
+ depreciation_method="Straight Line",
+ daily_prorata_based=1,
+ available_for_use_date="2020-01-01",
+ depreciation_start_date="2020-01-31",
+ frequency_of_depreciation=1,
+ total_number_of_depreciations=24,
+ )
+
+ expected_schedules = [
+ ["2020-01-31", 4234.97, 4234.97],
+ ["2020-02-29", 3961.75, 8196.72],
+ ["2020-03-31", 4234.97, 12431.69],
+ ["2020-04-30", 4098.36, 16530.05],
+ ["2020-05-31", 4234.97, 20765.02],
+ ["2020-06-30", 4098.36, 24863.38],
+ ["2020-07-31", 4234.97, 29098.35],
+ ["2020-08-31", 4234.97, 33333.32],
+ ["2020-09-30", 4098.36, 37431.68],
+ ["2020-10-31", 4234.97, 41666.65],
+ ["2020-11-30", 4098.36, 45765.01],
+ ["2020-12-31", 4234.97, 49999.98],
+ ["2021-01-31", 4246.58, 54246.56],
+ ["2021-02-28", 3835.62, 58082.18],
+ ["2021-03-31", 4246.58, 62328.76],
+ ["2021-04-30", 4109.59, 66438.35],
+ ["2021-05-31", 4246.58, 70684.93],
+ ["2021-06-30", 4109.59, 74794.52],
+ ["2021-07-31", 4246.58, 79041.1],
+ ["2021-08-31", 4246.58, 83287.68],
+ ["2021-09-30", 4109.59, 87397.27],
+ ["2021-10-31", 4246.58, 91643.85],
+ ["2021-11-30", 4109.59, 95753.44],
+ ["2021-12-31", 4246.56, 100000.0],
+ ]
+
+ schedules = [
+ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
+ for d in get_depr_schedule(asset.name, "Draft")
+ ]
+ self.assertEqual(schedules, expected_schedules)
+
+ # Test for Written Down Value Method
+ # Frequency of deprciation = 3
+ def test_for_daily_prorata_based_depreciation_wdv_method_frequency_3_months(self):
+ asset = create_asset(
+ item_code="Macbook Pro",
+ calculate_depreciation=1,
+ depreciation_method="Written Down Value",
+ daily_prorata_based=1,
+ available_for_use_date="2021-02-20",
+ depreciation_start_date="2021-03-31",
+ frequency_of_depreciation=3,
+ total_number_of_depreciations=6,
+ rate_of_depreciation=40,
+ )
+
+ expected_schedules = [
+ ["2021-03-31", 4383.56, 4383.56],
+ ["2021-06-30", 9535.45, 13919.01],
+ ["2021-09-30", 9640.23, 23559.24],
+ ["2021-12-31", 9640.23, 33199.47],
+ ["2022-03-31", 9430.66, 42630.13],
+ ["2022-06-30", 5721.27, 48351.4],
+ ["2022-08-20", 51648.6, 100000.0],
+ ]
+
+ schedules = [
+ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
+ for d in get_depr_schedule(asset.name, "Draft")
+ ]
+ self.assertEqual(schedules, expected_schedules)
+
+ # Frequency of deprciation = 6
+ def test_for_daily_prorata_based_depreciation_wdv_method_frequency_6_months(self):
+ asset = create_asset(
+ item_code="Macbook Pro",
+ calculate_depreciation=1,
+ depreciation_method="Written Down Value",
+ daily_prorata_based=1,
+ available_for_use_date="2020-02-20",
+ depreciation_start_date="2020-02-29",
+ frequency_of_depreciation=6,
+ total_number_of_depreciations=6,
+ rate_of_depreciation=40,
+ )
+
+ expected_schedules = [
+ ["2020-02-29", 1092.90, 1092.90],
+ ["2020-08-31", 19944.01, 21036.91],
+ ["2021-02-28", 19618.83, 40655.74],
+ ["2021-08-31", 11966.4, 52622.14],
+ ["2022-02-28", 11771.3, 64393.44],
+ ["2022-08-31", 7179.84, 71573.28],
+ ["2023-02-20", 28426.72, 100000.0],
+ ]
+
+ schedules = [
+ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
+ for d in get_depr_schedule(asset.name, "Draft")
+ ]
+ self.assertEqual(schedules, expected_schedules)
+
+ # Frequency of deprciation = 12
+ def test_for_daily_prorata_based_depreciation_wdv_method_frequency_12_months(self):
+ asset = create_asset(
+ item_code="Macbook Pro",
+ calculate_depreciation=1,
+ depreciation_method="Written Down Value",
+ daily_prorata_based=1,
+ available_for_use_date="2020-02-20",
+ depreciation_start_date="2020-03-31",
+ frequency_of_depreciation=12,
+ total_number_of_depreciations=4,
+ rate_of_depreciation=40,
+ )
+
+ expected_schedules = [
+ ["2020-03-31", 4480.87, 4480.87],
+ ["2021-03-31", 38207.65, 42688.52],
+ ["2022-03-31", 22924.59, 65613.11],
+ ["2023-03-31", 13754.76, 79367.87],
+ ["2024-02-20", 20632.13, 100000],
+ ]
+
+ schedules = [
+ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
+ for d in get_depr_schedule(asset.name, "Draft")
+ ]
+ self.assertEqual(schedules, expected_schedules)
+
+ def test_update_total_number_of_booked_depreciations(self):
+ # check if updates total number of booked depreciations when depreciation gets booked
+ asset = create_asset(
+ item_code="Macbook Pro",
+ calculate_depreciation=1,
+ opening_accumulated_depreciation=2000,
+ opening_number_of_booked_depreciations=2,
+ depreciation_method="Straight Line",
+ available_for_use_date="2020-03-01",
+ depreciation_start_date="2020-03-31",
+ frequency_of_depreciation=1,
+ total_number_of_depreciations=24,
+ submit=1,
+ )
+
+ post_depreciation_entries(date="2021-03-31")
+ asset.reload()
+ """
+ opening_number_of_booked_depreciations = 2
+ number_of_booked_depreciations till 2021-03-31 = 13
+ total_number_of_booked_depreciations = 15
+ """
+ self.assertEqual(asset.finance_books[0].total_number_of_booked_depreciations, 15)
+
+ # cancel depreciation entry
+ depr_entry = get_depr_schedule(asset.name, "Active")[0].journal_entry
+
+ frappe.get_doc("Journal Entry", depr_entry).cancel()
+ asset.reload()
+
+ self.assertEqual(asset.finance_books[0].total_number_of_booked_depreciations, 14)
diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
index e10257f87d2e214d84e74824f3210bcc286a0704..779749ee4eb0651e79418797f19faffb7712e9c9 100644
--- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
+++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
@@ -8,6 +8,9 @@
"finance_book",
"depreciation_method",
"total_number_of_depreciations",
+ "total_number_of_booked_depreciations",
+ "daily_prorata_based",
+ "shift_based",
"column_break_5",
"frequency_of_depreciation",
"depreciation_start_date",
@@ -18,6 +21,7 @@
],
"fields": [
{
+ "columns": 2,
"fieldname": "finance_book",
"fieldtype": "Link",
"in_list_view": 1,
@@ -33,6 +37,7 @@
"reqd": 1
},
{
+ "columns": 2,
"fieldname": "total_number_of_depreciations",
"fieldtype": "Int",
"in_list_view": 1,
@@ -44,6 +49,7 @@
"fieldtype": "Column Break"
},
{
+ "columns": 2,
"fieldname": "frequency_of_depreciation",
"fieldtype": "Int",
"in_list_view": 1,
@@ -58,6 +64,7 @@
"mandatory_depends_on": "eval:parent.doctype == 'Asset'"
},
{
+ "columns": 1,
"default": "0",
"depends_on": "eval:parent.doctype == 'Asset'",
"fieldname": "expected_value_after_useful_life",
@@ -79,26 +86,45 @@
"description": "In Percentage",
"fieldname": "rate_of_depreciation",
"fieldtype": "Percent",
- "label": "Rate of Depreciation",
- "precision": "4"
+ "label": "Rate of Depreciation"
},
{
"fieldname": "salvage_value_percentage",
"fieldtype": "Percent",
"label": "Salvage Value Percentage"
+ },
+ {
+ "default": "0",
+ "fieldname": "daily_prorata_based",
+ "fieldtype": "Check",
+ "label": "Depreciate based on daily pro-rata"
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:doc.depreciation_method == \"Straight Line\"",
+ "fieldname": "shift_based",
+ "fieldtype": "Check",
+ "label": "Depreciate based on shifts"
+ },
+ {
+ "default": "0",
+ "fieldname": "total_number_of_booked_depreciations",
+ "fieldtype": "Int",
+ "label": "Total Number of Booked Depreciations ",
+ "read_only": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2023-12-29 08:49:39.876439",
+ "modified": "2024-05-21 15:48:20.907250",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Finance Book",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py
index 56e4d4ff3d7471b95ff17972a7a01478aea11115..d06d6355ec34924efbb85cf044242a490ba8f504 100644
--- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py
+++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py
@@ -2,9 +2,35 @@
# For license information, please see license.txt
-import frappe
from frappe.model.document import Document
class AssetFinanceBook(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ daily_prorata_based: DF.Check
+ depreciation_method: DF.Literal[
+ "", "Straight Line", "Double Declining Balance", "Written Down Value", "Manual"
+ ]
+ depreciation_start_date: DF.Date | None
+ expected_value_after_useful_life: DF.Currency
+ finance_book: DF.Link | None
+ frequency_of_depreciation: DF.Int
+ parent: DF.Data
+ parentfield: DF.Data
+ parenttype: DF.Data
+ rate_of_depreciation: DF.Percent
+ salvage_value_percentage: DF.Percent
+ shift_based: DF.Check
+ total_number_of_booked_depreciations: DF.Int
+ total_number_of_depreciations: DF.Int
+ value_after_depreciation: DF.Currency
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
index 5c03b98873b626a00d873f0e3809719b1b407514..83dabab89357ec2f45bf6ec4fcb4eb2141efa601 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
@@ -1,49 +1,47 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Asset Maintenance', {
+frappe.ui.form.on("Asset Maintenance", {
setup: (frm) => {
- frm.set_query("assign_to", "asset_maintenance_tasks", function(doc) {
+ frm.set_query("assign_to", "asset_maintenance_tasks", function (doc) {
return {
query: "erpnext.assets.doctype.asset_maintenance.asset_maintenance.get_team_members",
filters: {
- maintenance_team: doc.maintenance_team
- }
+ maintenance_team: doc.maintenance_team,
+ },
};
});
- frm.set_indicator_formatter('maintenance_status',
- function(doc) {
- let indicator = 'blue';
- if (doc.maintenance_status == 'Overdue') {
- indicator = 'orange';
- }
- if (doc.maintenance_status == 'Cancelled') {
- indicator = 'red';
- }
- return indicator;
+ frm.set_indicator_formatter("maintenance_status", function (doc) {
+ let indicator = "blue";
+ if (doc.maintenance_status == "Overdue") {
+ indicator = "orange";
+ }
+ if (doc.maintenance_status == "Cancelled") {
+ indicator = "red";
}
- );
+ return indicator;
+ });
},
refresh: (frm) => {
- if(!frm.is_new()) {
- frm.trigger('make_dashboard');
+ if (!frm.is_new()) {
+ frm.trigger("make_dashboard");
}
},
make_dashboard: (frm) => {
- if(!frm.is_new()) {
+ if (!frm.is_new()) {
frappe.call({
- method: 'erpnext.assets.doctype.asset_maintenance.asset_maintenance.get_maintenance_log',
- args: {asset_name: frm.doc.asset_name},
+ method: "erpnext.assets.doctype.asset_maintenance.asset_maintenance.get_maintenance_log",
+ args: { asset_name: frm.doc.asset_name },
callback: (r) => {
- if(!r.message) {
+ if (!r.message) {
return;
}
- const section = frm.dashboard.add_section('', __("Maintenance Log"));
- var rows = $('