fix: Modify depreciation schedule when increase_in_asset_life is not a multiple of frequency_of_depreciation)

This commit is contained in:
GangaManoj 2021-07-09 22:11:50 +05:30
parent 58bc967073
commit 42c70fba3c
13 changed files with 444 additions and 49 deletions

View File

@ -132,7 +132,6 @@ frappe.ui.form.on('Asset', {
}, __("Manage"));
}
frm.page.set_inner_btn_group_as_primary(__("Manage"));
frm.trigger("setup_chart");
}

View File

@ -23,6 +23,7 @@
"asset_name",
"asset_category",
"location",
"asset_value",
"custodian",
"department",
"disposal_date",
@ -53,6 +54,8 @@
"next_depreciation_date",
"section_break_14",
"schedules",
"to_date",
"edit_dates",
"insurance_details",
"policy_number",
"insurer",
@ -480,6 +483,24 @@
"fieldname": "section_break_36",
"fieldtype": "Section Break",
"label": "Finance Books"
},
{
"fieldname": "asset_value",
"fieldtype": "Currency",
"label": "Asset Value",
"read_only": 1
},
{
"fieldname": "to_date",
"fieldtype": "Date",
"hidden": 1,
"label": "To Date"
},
{
"fieldname": "edit_dates",
"fieldtype": "Data",
"hidden": 1,
"label": "Edit Dates"
}
],
"idx": 72,
@ -502,7 +523,7 @@
"link_fieldname": "asset"
}
],
"modified": "2021-01-22 12:38:59.091510",
"modified": "2021-05-21 12:05:29.424083",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",

View File

@ -96,6 +96,9 @@ class Asset(AccountsController):
finance_books = get_item_details(self.item_code, self.asset_category)
self.set('finance_books', finance_books)
if not(self.asset_value):
self.asset_value = self.gross_purchase_amount
def validate_asset_values(self):
if not self.asset_category:
self.asset_category = frappe.get_cached_value("Item", self.item_code, "asset_category")
@ -168,15 +171,23 @@ class Asset(AccountsController):
d.precision("rate_of_depreciation"))
def make_depreciation_schedule(self):
if 'Manual' not in [d.depreciation_method for d in self.finance_books]:
if 'Manual' not in [d.depreciation_method for d in self.finance_books] and not self.schedules:
self.schedules = []
if self.get("schedules") or not self.available_for_use_date:
if not self.available_for_use_date:
return
for d in self.get('finance_books'):
self.validate_asset_finance_books(d)
start = 0
for n in range (len(self.schedules)):
if not self.schedules[n].journal_entry:
print("*"*100)
del self.schedules[n:]
start = n
break
value_after_depreciation = (flt(self.gross_purchase_amount) -
flt(self.opening_accumulated_depreciation))
@ -189,9 +200,9 @@ class Asset(AccountsController):
if has_pro_rata:
number_of_pending_depreciations += 1
skip_row = False
for n in range(number_of_pending_depreciations):
for n in range(start, number_of_pending_depreciations):
# If depreciation is already completed (for double declining balance)
if skip_row: continue
@ -216,11 +227,12 @@ class Asset(AccountsController):
# For last row
elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1:
to_date = add_months(self.available_for_use_date,
n * cint(d.frequency_of_depreciation))
if not self.edit_dates:
self.to_date = add_months(self.available_for_use_date,
n * cint(d.frequency_of_depreciation))
depreciation_amount, days, months = self.get_pro_rata_amt(d,
depreciation_amount, schedule_date, to_date)
depreciation_amount, days, months = get_pro_rata_amt(d,
depreciation_amount, schedule_date, self.to_date)
monthly_schedule_date = add_months(schedule_date, 1)
@ -346,11 +358,12 @@ class Asset(AccountsController):
if d.finance_book_id not in finance_books:
accumulated_depreciation = flt(self.opening_accumulated_depreciation)
value_after_depreciation = flt(self.get_value_after_depreciation(d.finance_book_id))
finance_books.append(d.finance_book_id)
finance_books.append(int(d.finance_book_id))
depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount"))
value_after_depreciation -= flt(depreciation_amount)
# for the last row, if depreciation method = Straight Line
if straight_line_idx and i == max(straight_line_idx) - 1:
book = self.get('finance_books')[cint(d.finance_book_id) - 1]
depreciation_amount += flt(value_after_depreciation -

View File

@ -30,7 +30,10 @@ frappe.ui.form.on('Asset Maintenance', {
if(!frm.is_new()) {
frm.trigger('make_dashboard');
}
frm.toggle_display(['stock_consumption_details_section'], frm.doc.stock_consumption)
},
make_dashboard: (frm) => {
if(!frm.is_new()) {
frappe.call({

View File

@ -12,13 +12,17 @@
"column_break_3",
"item_code",
"item_name",
"stock_consumption",
"section_break_6",
"maintenance_team",
"column_break_9",
"maintenance_manager",
"maintenance_manager_name",
"section_break_8",
"asset_maintenance_tasks"
"asset_maintenance_tasks",
"stock_consumption_details_section",
"warehouse",
"stock_items"
],
"fields": [
{
@ -100,10 +104,33 @@
"label": "Maintenance Tasks",
"options": "Asset Maintenance Task",
"reqd": 1
},
{
"default": "0",
"fieldname": "stock_consumption",
"fieldtype": "Check",
"label": "Stock Consumed During Maintenance"
},
{
"fieldname": "stock_consumption_details_section",
"fieldtype": "Section Break",
"label": "Stock Consumption Details"
},
{
"fieldname": "warehouse",
"fieldtype": "Link",
"label": "Warehouse",
"options": "Warehouse"
},
{
"fieldname": "stock_items",
"fieldtype": "Table",
"label": "Stock Items",
"options": "Stock Item"
}
],
"links": [],
"modified": "2020-05-28 20:28:32.993823",
"modified": "2021-05-13 05:24:58.480132",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Maintenance",

View File

@ -19,10 +19,45 @@ class AssetMaintenance(Document):
if not task.assign_to and self.docstatus == 0:
throw(_("Row #{}: Please asign task to a member.").format(task.idx))
if self.stock_consumption:
self.check_for_stock_items_and_warehouse()
self.increase_asset_value()
self.decrease_stock_quantity()
def on_update(self):
for task in self.get('asset_maintenance_tasks'):
assign_tasks(self.name, task.assign_to, task.maintenance_task, task.next_due_date)
self.sync_maintenance_tasks()
self.sync_maintenance_tasks()
def check_for_stock_items_and_warehouse(self):
if self.stock_consumption:
if not self.stock_items:
frappe.throw(_("Please enter Stock Items consumed during Asset Maintenance."))
if not self.warehouse:
frappe.throw(_("Please enter Warehouse from which Stock Items consumed during Asset Maintenance were taken."))
def increase_asset_value(self):
asset_value = frappe.db.get_value('Asset', self.asset_name, 'asset_value')
for item in self.stock_items:
asset_value += item.total_value
frappe.db.set_value('Asset', self.asset_name, 'asset_value', asset_value)
def decrease_stock_quantity(self):
stock_entry = frappe.get_doc({
"doctype": "Stock Entry",
"stock_entry_type": "Material Issue"
})
for stock_item in self.stock_items:
stock_entry.append('items', {
"s_warehouse": self.warehouse,
"item_code": stock_item.item,
"qty": stock_item.consumed_quantity
})
stock_entry.insert()
stock_entry.submit()
def sync_maintenance_tasks(self):
tasks_names = []

View File

@ -3,7 +3,16 @@
frappe.ui.form.on('Asset Repair', {
refresh: function(frm) {
frm.toggle_display(['completion_date', 'repair_status'], !(frm.doc.__islocal));
frm.toggle_display(['completion_date', 'repair_status', 'accounting_details', 'accounting_dimensions_section'], !(frm.doc.__islocal));
if (frm.doc.docstatus) {
frm.add_custom_button("View General Ledger", function() {
frappe.route_options = {
"voucher_no": frm.doc.name
};
frappe.set_route("query-report", "General Ledger");
});
}
},
repair_status: (frm) => {

View File

@ -13,20 +13,30 @@
"asset_name",
"section_break_5",
"failure_date",
"assign_to",
"assign_to_name",
"repair_status",
"column_break_6",
"completion_date",
"repair_status",
"section_break_7",
"accounting_dimensions_section",
"cost_center",
"column_break_14",
"project",
"accounting_details",
"repair_cost",
"capitalize_repair_cost",
"stock_consumption",
"column_break_8",
"payable_account",
"total_repair_cost",
"purchase_invoice",
"stock_consumption_details_section",
"warehouse",
"stock_items",
"asset_depreciation_details_section",
"increase_in_asset_life",
"section_break_9",
"description",
"column_break_9",
"actions_performed",
"section_break_17",
"section_break_23",
"downtime",
"column_break_19",
"amended_from"
@ -55,20 +65,6 @@
"label": "Failure Date",
"reqd": 1
},
{
"allow_on_submit": 1,
"fieldname": "assign_to",
"fieldtype": "Link",
"label": "Assign To",
"options": "User"
},
{
"allow_on_submit": 1,
"fetch_from": "assign_to.full_name",
"fieldname": "assign_to_name",
"fieldtype": "Read Only",
"label": "Assign To Name"
},
{
"fieldname": "column_break_6",
"fieldtype": "Column Break"
@ -110,10 +106,6 @@
"fieldtype": "Long Text",
"label": "Actions performed"
},
{
"fieldname": "section_break_17",
"fieldtype": "Section Break"
},
{
"allow_on_submit": 1,
"fieldname": "downtime",
@ -151,30 +143,103 @@
"reqd": 1
},
{
"fetch_from": "asset.asset_name",
"fieldname": "asset_name",
"fieldtype": "Read Only",
"label": "Asset Name"
},
{
"fieldname": "payable_account",
"fieldtype": "Link",
"label": "Payable Account",
"options": "Account"
"fieldname": "column_break_8",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_7",
"default": "0",
"fieldname": "capitalize_repair_cost",
"fieldtype": "Check",
"label": "Capitalize Repair Cost"
},
{
"fieldname": "accounting_details",
"fieldtype": "Section Break",
"label": "Accounting Details"
},
{
"fieldname": "column_break_8",
"fieldname": "stock_items",
"fieldtype": "Table",
"label": "Stock Items",
"options": "Stock Item"
},
{
"fieldname": "section_break_23",
"fieldtype": "Section Break"
},
{
"fieldname": "accounting_dimensions_section",
"fieldtype": "Section Break",
"label": "Accounting Dimensions"
},
{
"fieldname": "cost_center",
"fieldtype": "Link",
"label": "Cost Center",
"options": "Cost Center"
},
{
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
},
{
"fieldname": "column_break_14",
"fieldtype": "Column Break"
},
{
"default": "0",
"fieldname": "stock_consumption",
"fieldtype": "Check",
"label": "Stock Consumed During Repair"
},
{
"depends_on": "stock_consumption",
"fieldname": "stock_consumption_details_section",
"fieldtype": "Section Break",
"label": "Stock Consumption Details"
},
{
"depends_on": "stock_consumption",
"fieldname": "total_repair_cost",
"fieldtype": "Currency",
"label": "Total Repair Cost"
},
{
"fieldname": "warehouse",
"fieldtype": "Link",
"label": "Warehouse",
"options": "Warehouse"
},
{
"depends_on": "capitalize_repair_cost",
"fieldname": "asset_depreciation_details_section",
"fieldtype": "Section Break",
"label": "Asset Depreciation Details"
},
{
"fieldname": "increase_in_asset_life",
"fieldtype": "Int",
"label": "Increase In Asset Life(Months)"
},
{
"fieldname": "purchase_invoice",
"fieldtype": "Link",
"label": "Purchase Invoice",
"options": "Purchase Invoice"
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2021-05-11 05:11:58.330860",
"modified": "2021-05-21 10:37:35.002238",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",

View File

@ -5,19 +5,172 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import time_diff_in_hours
from frappe.utils import time_diff_in_hours, getdate, add_days, date_diff, add_months, flt, cint
from frappe.model.document import Document
from erpnext.accounts.general_ledger import make_gl_entries
class AssetRepair(Document):
def validate(self):
if self.repair_status == "Completed" and not self.completion_date:
frappe.throw(_("Please select Completion Date for Completed Repair"))
self.update_status()
self.set_total_value() # change later
self.calculate_total_repair_cost()
def update_status(self):
if self.repair_status == 'Pending':
frappe.db.set_value('Asset', self.asset, 'status', 'Out of Order')
else:
frappe.db.set_value('Asset', self.asset, 'status', 'Submitted')
asset = frappe.get_doc('Asset', self.asset)
asset.set_status()
def set_total_value(self):
for item in self.stock_items:
item.total_value = flt(item.valuation_rate) * flt(item.consumed_quantity)
def calculate_total_repair_cost(self):
self.total_repair_cost = self.repair_cost
if self.stock_consumption:
for item in self.stock_items:
self.total_repair_cost += item.total_value
def on_submit(self):
self.check_repair_status()
self.check_for_cost_center()
if self.stock_consumption or self.capitalize_repair_cost:
self.increase_asset_value()
if self.stock_consumption:
self.check_for_stock_items_and_warehouse()
self.decrease_stock_quantity()
if self.capitalize_repair_cost:
self.check_for_purchase_invoice()
self.make_gl_entries()
self.modify_depreciation_schedule()
def check_repair_status(self):
if self.repair_status == "Pending":
frappe.throw(_("Please update Repair Status."))
def check_for_stock_items_and_warehouse(self):
if not self.stock_items:
frappe.throw(_("Please enter Stock Items consumed during Asset Repair."))
if not self.warehouse:
frappe.throw(_("Please enter Warehouse from which Stock Items consumed during Asset Repair were taken."))
def check_for_cost_center(self):
if not self.cost_center:
frappe.throw(_("Please enter Cost Center."))
def increase_asset_value(self):
asset_value = frappe.db.get_value('Asset', self.asset, 'asset_value')
for item in self.stock_items:
asset_value += item.total_value
if self.capitalize_repair_cost:
asset_value += self.repair_cost
frappe.db.set_value('Asset', self.asset, 'asset_value', asset_value)
def decrease_stock_quantity(self):
stock_entry = frappe.get_doc({
"doctype": "Stock Entry",
"stock_entry_type": "Material Issue"
})
for stock_item in self.stock_items:
stock_entry.append('items', {
"s_warehouse": self.warehouse,
"item_code": stock_item.item,
"qty": stock_item.consumed_quantity
})
stock_entry.insert()
stock_entry.submit()
def check_for_purchase_invoice(self):
if not self.purchase_invoice:
frappe.throw(_("Please link Purchase Invoice."))
def on_cancel(self):
self.make_gl_entries(cancel=True)
def make_gl_entries(self, cancel=False):
if flt(self.repair_cost) > 0:
gl_entries = self.get_gl_entries()
make_gl_entries(gl_entries, cancel)
def get_gl_entries(self):
gl_entry = []
company = frappe.db.get_value('Asset', self.asset, 'company')
repair_and_maintenance_account = frappe.db.get_value('Company', company, 'repair_and_maintenance_account')
fixed_asset_account = self.get_fixed_asset_account()
expense_account = frappe.get_doc('Purchase Invoice', self.purchase_invoice).items[0].expense_account
gl_entry = frappe.get_doc({
"doctype": "GL Entry",
"account": expense_account,
"credit": self.total_repair_cost,
"credit_in_account_currency": self.total_repair_cost,
"against": repair_and_maintenance_account,
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
"posting_date": getdate()
})
gl_entry.insert()
gl_entry = frappe.get_doc({
"doctype": "GL Entry",
"account": fixed_asset_account,
"debit": self.total_repair_cost,
"debit_in_account_currency": self.total_repair_cost,
"against": expense_account,
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
"posting_date": getdate(),
"against_voucher_type": "Purchase Invoice",
"against_voucher": self.purchase_invoice
})
gl_entry.insert()
def get_fixed_asset_account(self):
asset_category = frappe.get_doc('Asset Category', frappe.db.get_value('Asset', self.asset, 'asset_category'))
company = frappe.db.get_value('Asset', self.asset, 'company')
for account in asset_category.accounts:
if account.company_name == company:
return account.fixed_asset_account
def modify_depreciation_schedule(self):
if self.increase_in_asset_life:
asset = frappe.get_doc('Asset', self.asset)
asset.flags.ignore_validate_update_after_submit = True
for row in asset.finance_books:
row.total_number_of_depreciations += self.increase_in_asset_life/row.frequency_of_depreciation
asset.edit_dates = ""
extra_months = self.increase_in_asset_life % row.frequency_of_depreciation
if extra_months != 0:
self.calculate_last_schedule_date(asset, row, extra_months)
# fix depreciation amount
asset.prepare_depreciation_data()
asset.save()
# to help modify depreciation schedule when increase_in_asset_life is not a multiple of frequency_of_depreciation
def calculate_last_schedule_date(self, asset, row, extra_months):
asset.edit_dates = "Don't Edit"
number_of_pending_depreciations = cint(row.total_number_of_depreciations) - \
cint(asset.number_of_depreciations_booked)
last_schedule_date = asset.schedules[len(asset.schedules)-1].schedule_date
asset.to_date = add_months(last_schedule_date, extra_months)
schedule_date = add_months(row.depreciation_start_date,
number_of_pending_depreciations * cint(row.frequency_of_depreciation))
if asset.to_date > schedule_date:
row.total_number_of_depreciations += 1
@frappe.whitelist()
def get_downtime(failure_date, completion_date):
downtime = time_diff_in_hours(completion_date, failure_date)

View File

@ -0,0 +1,55 @@
{
"actions": [],
"creation": "2021-05-12 02:41:54.161024",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"item",
"valuation_rate",
"consumed_quantity",
"total_value"
],
"fields": [
{
"fieldname": "item",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Item",
"options": "Item"
},
{
"fetch_from": "item.valuation_rate",
"fieldname": "valuation_rate",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Valuation Rate",
"read_only": 1
},
{
"fieldname": "consumed_quantity",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Consumed Quantity"
},
{
"fieldname": "total_value",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Total Value",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-05-12 03:19:55.006300",
"modified_by": "Administrator",
"module": "Assets",
"name": "Stock Item",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -0,0 +1,8 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class StockItem(Document):
pass

View File

@ -83,6 +83,7 @@
"disposal_account",
"depreciation_cost_center",
"capital_work_in_progress_account",
"repair_and_maintenance_account",
"asset_received_but_not_billed",
"budget_detail",
"exception_budget_approver_role",
@ -734,6 +735,12 @@
"fieldname": "fixed_asset_defaults",
"fieldtype": "Section Break",
"label": "Fixed Asset Defaults"
},
{
"fieldname": "repair_and_maintenance_account",
"fieldtype": "Link",
"label": "Repair and Maintenance Account",
"options": "Account"
}
],
"icon": "fa fa-building",
@ -741,7 +748,7 @@
"image_field": "company_logo",
"is_tree": 1,
"links": [],
"modified": "2021-05-11 21:45:22.803065",
"modified": "2021-05-12 16:51:08.187233",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",