fixed asset depreciation

This commit is contained in:
Nabin Hait 2016-03-09 12:40:56 +05:30
parent 3a15c92c5e
commit 4fdb05228d
22 changed files with 793 additions and 328 deletions

View File

@ -4,20 +4,37 @@
frappe.provide("erpnext.asset");
frappe.ui.form.on('Asset', {
refresh: function(frm) {
cur_frm.add_custom_button("Scrap", function() {
erpnext.asset.scrap_asset();
onload: function(frm) {
frm.set_query("item_code", function() {
return {
"filters": {
"is_stock_item": 0,
"is_fixed_asset": 1,
"disabled": 0
}
};
});
},
refresh: function(frm) {
if(frm.doc.docstatus==1 && frm.doc.status=='Available') {
cur_frm.add_custom_button("Scrap", function() {
erpnext.asset.scrap_asset(frm);
});
}
}
});
erpnext.asset.scrap_asset = function() {
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
},
method: "erpnext.accounts.doctype.asset.depreciation.scrap_asset"
method: "erpnext.accounts.doctype.asset.depreciation.scrap_asset",
callback: function(r) {
cur_frm.reload_doc();
}
})
})
}

View File

@ -60,6 +60,32 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "item_code",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Item Code",
"length": 0,
"no_copy": 0,
"options": "Item",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -74,13 +100,13 @@
"in_list_view": 0,
"label": "Status",
"length": 0,
"no_copy": 0,
"no_copy": 1,
"options": "Available\nSold\nScrapped",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
@ -162,6 +188,32 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "purchase_invoice",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Purchase Invoice",
"length": 0,
"no_copy": 1,
"options": "Purchase Invoice",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -216,7 +268,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "Straight Line",
"default": "",
"depends_on": "",
"fieldname": "depreciation_method",
"fieldtype": "Select",
@ -244,15 +296,14 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "The time period over which the company expects that the asset will be productive",
"fieldname": "useful_life",
"fieldname": "number_of_depreciations",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Useful Life (Years)",
"label": "Number of Depreciations",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@ -270,14 +321,14 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "start_depreciation_from_purchase_date",
"fieldtype": "Check",
"fieldname": "number_of_months_in_a_period",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Start Depreciation from Purchase Date",
"label": "Number of Months in a Period",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@ -291,6 +342,32 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"depends_on": "",
"fieldname": "next_depreciation_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Next Depreciation Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -319,16 +396,17 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "gross_value",
"fieldname": "gross_purchase_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Gross Value",
"label": "Gross Purchase Amount",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -344,17 +422,18 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "The estimated resale value of an asset at the end of its useful life",
"fieldname": "salvage_value",
"fieldtype": "Data",
"description": "",
"fieldname": "expected_value_after_useful_life",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Salvage Value",
"label": "Expected Value After Useful Life",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -369,7 +448,33 @@
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"collapsible": 0,
"fieldname": "current_value",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Current Value (After Depreciation)",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "section_break_14",
"fieldtype": "Section Break",
"hidden": 0,
@ -404,13 +509,38 @@
"in_list_view": 0,
"label": "Depreciation Schedules",
"length": 0,
"no_copy": 0,
"no_copy": 1,
"options": "Depreciation Schedule",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Amended From",
"length": 0,
"no_copy": 1,
"options": "Asset",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@ -423,11 +553,11 @@
"idx": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-03-03 17:34:00.991228",
"modified": "2016-03-09 12:22:05.223886",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Asset",
@ -437,7 +567,7 @@
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
@ -451,7 +581,7 @@
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"submit": 1,
"write": 1
}
],

View File

@ -5,61 +5,90 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt, add_years
from frappe.utils import flt, add_months, cint
from frappe.model.document import Document
class Asset(Document):
def validate(self):
self.validate_mandatory()
self.validate_fixed_asset_item()
self.validate_asset_values()
self.set_depreciation_settings()
self.make_depreciation_schedule()
def validate_mandatory(self):
if not self.useful_life:
self.useful_life = frappe.db.get_value("Asset Category", self.asset_category, "useful_life")
if not self.useful_life:
frappe.throw(_("Useful Life is mandatory"))
def on_cancel(self):
self.validate_cancellation()
self.delete_depreciation_entries()
def validate_fixed_asset_item(self):
item = frappe.get_doc("Item", self.item_code)
if item.disabled:
frappe.throw(_("Item {0} has been disabled").format(self.item_code))
if item.is_stock_item:
frappe.throw(_("Item {0} must be a non-stock item").format(self.item_code))
def validate_asset_values(self):
if flt(self.expected_value_after_useful_life) >= flt(self.gross_purchase_amount):
frappe.throw(_("Expected Value After Useful Life must be less than Gross Purchase Amount"))
if not self.current_value:
self.current_value = flt(self.gross_purchase_amount)
else:
if flt(self.current_value) > flt(self.gross_purchase_amount):
frappe.throw(_("Current Value After Depreciation must be less than equal to {0}")
.format(flt(self.gross_purchase_amount)))
def set_depreciation_settings(self):
asset_category = frappe.get_doc("Asset Category", self.asset_category)
for field in ("depreciation_method", "number_of_depreciations", "number_of_months_in_a_period"):
if not self.get(field):
self.set(field, asset_category.get(field))
def make_depreciation_schedule(self):
self.schedules = []
if not self.get("schedules") and self.status == "Available":
depreciation_method = self.get_depreciation_method()
accumulated_depreciation = 0
value_after_depreciation = flt(self.gross_value)
for n in xrange(self.useful_life):
depreciation_date = add_years(self.purchase_date,
n if self.start_depreciation_from_purchase_date else n+1)
depreciation_amount = self.get_depreciation_amount(value_after_depreciation,
depreciation_method)
value_after_depreciation = flt(self.current_value)
for n in xrange(self.number_of_depreciations):
schedule_date = add_months(self.next_depreciation_date,
n * cint(self.number_of_months_in_a_period))
depreciation_amount = self.get_depreciation_amount(value_after_depreciation)
self.append("schedules", {
"depreciation_date": depreciation_date,
"schedule_date": schedule_date,
"depreciation_amount": depreciation_amount,
"accumulated_depreciation_amount": accumulated_depreciation + depreciation_amount
})
def get_depreciation_method(self):
depreciation_method = self.depreciation_method or \
frappe.db.get_value("Asset Category", self.asset_category, "depreciation_method") or \
frappe.db.get_value("Company", self.company, "depreciation_method")
if not depreciation_method:
frappe.throw(_("Please set Depreciation Method in Asset Category {0} or Company {1}")
.format(self.asset_category, self.company))
def get_depreciation_amount(self, depreciable_value, depreciation_method=None):
if not depreciation_method:
depreciation_method = self.get_depreciation_method()
if depreciation_method == "Straight Line":
depreciation_amount = (flt(self.gross_value) - flt(self.salvage_value)) / flt(self.useful_life)
accumulated_depreciation += flt(depreciation_amount)
value_after_depreciation -= flt(depreciation_amount)
def get_depreciation_amount(self, depreciable_value):
if self.depreciation_method == "Straight Line":
depreciation_amount = (flt(self.current_value) -
flt(self.expected_value_after_useful_life)) / cint(self.number_of_depreciations)
else:
factor = 200 / self.useful_life
factor = 200 / cint(self.number_of_depreciations)
depreciation_amount = depreciable_value * factor / 100
value_after_depreciation = flt(depreciable_value) - depreciation_amount
if value_after_depreciation < self.salvage_value:
depreciation_amount = flt(depreciable_value) - flt(self.salvage_value)
if value_after_depreciation < flt(self.expected_value_after_useful_life):
depreciation_amount = flt(depreciable_value) - flt(self.expected_value_after_useful_life)
return depreciation_amount
def validate_cancellation(self):
if self.status != "Available":
frappe.throw(_("Asset {0} cannot be cancelled, as it is already {1}")
.format(self.name, self.status))
def delete_depreciation_entries(self):
total_depreciation_amount = 0
for d in self.get("schedules"):
if d.journal_entry:
frappe.get_doc("Journal Entry", d.journal_entry).cancel()
d.db_set("journal_entry", None)
total_depreciation_amount += flt(d.depreciation_amount)
self.db_set("current_value", (self.current_value - total_depreciation_amount))

View File

@ -5,113 +5,140 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt, today
from frappe.utils import flt, today, getdate
# Depreciate
#------------
def post_depreciation_entries(self):
assets = get_depreciable_assets()
for asset in assets:
depreciate_asset(asset.asset_name, asset.depreciation_amount, asset.schedule_row)
def get_depreciable_assets(date=None):
def post_depreciation_entries(date=None):
if not date:
date = today()
return frappe.db.sql("""
select a.name as asset_name, ds.depreciation_amount, ds.name as schedule_row
for asset in get_depreciable_assets(date):
make_depreciation_entry(asset, date)
def get_depreciable_assets(date):
return frappe.db.sql_list("""select a.name
from tabAsset a, `tabDepreciation Schedule` ds
where
a.name = ds.parent and ds.depreciation_date=%s
and a.status = 'Available' and ds.posted=0 and a.docstatus < 2""", date, as_dict=1)
def depreciate_asset(asset_name, depreciation_amount, schedule_row):
asset = frappe.get_doc("Asset", asset_name)
accumulated_depreciation_account, depreciation_expense_account = get_depreciation_accounts(asset)
je = frappe.new_doc("Journal Entry")
je.voucher_type = "Depreciation Entry"
je.posting_date = today()
je.company = asset.company
je.remark = "Depreciation Entry against {0} worth {1}".format(asset_name, depreciation_amount)
je.append("accounts", {
"account": accumulated_depreciation_account,
"credit_in_account_currency": depreciation_amount,
"reference_type": "Asset",
"reference_name": asset.name
})
je.append("accounts", {
"account": depreciation_expense_account,
"debit_in_account_currency": depreciation_amount,
"reference_type": "Asset",
"reference_name": asset.name
})
je.flags.ignore_permissions = True
je.submit()
frappe.db.sql("""update `tabDepreciation Schedule`
set posted=1, journal_entry=%s, modified=now(), modified_by=%s where name=%s""",
(je.name, frappe.session.user, schedule_row))
where a.name = ds.parent and a.docstatus=1 and ds.schedule_date<=%s
and a.status = 'Available' and ifnull(ds.journal_entry, '')=''""", date)
def make_depreciation_entry(asset_name, date=None):
if not date:
date = today()
asset = frappe.get_doc("Asset", asset_name)
fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account = \
get_depreciation_accounts(asset)
for d in asset.get("schedules"):
if not d.journal_entry and getdate(d.schedule_date) <= getdate(date):
je = frappe.new_doc("Journal Entry")
je.voucher_type = "Depreciation Entry"
je.posting_date = d.schedule_date
je.company = asset.company
je.remark = "Depreciation Entry against {0} worth {1}".format(asset_name, d.depreciation_amount)
je.append("accounts", {
"account": accumulated_depreciation_account,
"credit_in_account_currency": d.depreciation_amount,
"reference_type": "Asset",
"reference_name": asset.name
})
je.append("accounts", {
"account": depreciation_expense_account,
"debit_in_account_currency": d.depreciation_amount,
"reference_type": "Asset",
"reference_name": asset.name
})
je.flags.ignore_permissions = True
je.submit()
d.db_set("journal_entry", je.name)
asset.current_value -= d.depreciation_amount
frappe.db.set_value("Asset", asset_name, "current_value", asset.current_value)
def get_depreciation_accounts(asset):
accumulated_depreciation_account, depreciation_expense_account = frappe.db.get_value("Asset Category",
asset.asset_category, ["accumulated_depreciation_account", "depreciation_expense_account"])
accounts = frappe.db.sql("""select fixed_asset_account, accumulated_depreciation_account,
depreciation_expense_account from `tabAsset Category Account`
where parent=%s and company=%s""", (asset.asset_category, asset.company), as_dict=1)[0]
fixed_asset_account = accounts.fixed_asset_account
accumulated_depreciation_account = accounts.accumulated_depreciation_account
depreciation_expense_account = accounts.depreciation_expense_account
if not accumulated_depreciation_account or not depreciation_expense_account:
accounts = frappe.db.get_value("Company", asset.company,
["accumulated_depreciation_account", "depreciation_expense_account"])
if not accumulated_depreciation_account:
accumulated_depreciation_account = accounts[0]
if not depreciation_expense_account:
depreciation_expense_account = accounts[1]
if 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.asset_category, asset.company))
return accumulated_depreciation_account, depreciation_expense_account
return fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account
# Scrap
#---------
@frappe.whitelist()
def scrap_asset(asset_name):
asset = frappe.get_doc("Asset", asset_name)
asset.status = "Scrapped"
accumulated_depr_amount = frappe.db.sql("""select accumulated_depreciation_amount
from `tabDepreciation Schedule`
where parent=%s and posted=1
order by depreciation_date desc limit 1""")
accumulated_depr_amount = flt(accumulated_depr_amount[0][0]) if accumulated_depr_amount else 0
net_value_after_depreciation = flt(asset.gross_value) - accumulated_depr_amount
if asset.docstatus != 1 or asset.status != 'Available':
frappe.throw(_("Asset {0} must be submitted and available").format(asset.name))
je = frappe.new_doc("Journal Entry")
je.voucher_type = "Depreciation Entry"
je.voucher_type = "Journal Entry"
je.posting_date = today()
je.company = asset.company
je.remark = "Disposal Entry for asset {0}".format(asset_name)
je.remark = "Scrap Entry for asset {0}".format(asset_name)
# je.append("accounts", {
# "account": accumulated_depreciation_account,
# "credit_in_account_currency": depreciation_amount,
# "reference_type": "Asset",
# "reference_name": asset.name
# })
#
# je.append("accounts", {
# "account": depreciation_expense_account,
# "debit_in_account_currency": depreciation_amount,
# "reference_type": "Asset",
# "reference_name": asset.name
# })
for entry in get_gl_entries_on_asset_disposal(asset):
entry.update({
"reference_type": "Asset",
"reference_name": asset_name
})
je.append("accounts", entry)
je.flags.ignore_permissions = True
je.submit()
je.submit()
frappe.db.set_value("Asset", asset_name, "status", "Scrapped")
@frappe.whitelist()
def get_gl_entries_on_asset_disposal(asset, selling_amount=0):
fixed_asset_account, accumulated_depr_account, depr_expense_account = get_depreciation_accounts(asset)
disposal_account, disposal_cost_center = get_disposal_account_and_cost_center(asset.company)
accumulated_depr_amount = flt(asset.gross_purchase_amount) - flt(asset.current_value)
gl_entries = [
{
"account": fixed_asset_account,
"credit_in_account_currency": asset.gross_purchase_amount,
"credit": asset.gross_purchase_amount
},
{
"account": accumulated_depr_account,
"debit_in_account_currency": accumulated_depr_amount,
"debit": accumulated_depr_amount
}
]
profit_amount = flt(selling_amount) - flt(asset.current_value)
if flt(asset.current_value) and profit_amount:
debit_or_credit = "debit" if profit_amount < 0 else "credit"
gl_entries.append({
"account": disposal_account,
"cost_center": disposal_cost_center,
debit_or_credit: abs(profit_amount),
debit_or_credit + "_in_account_currency": abs(profit_amount)
})
return gl_entries
def get_disposal_account_and_cost_center(company):
disposal_account, disposal_cost_center = frappe.db.get_value("Company", company,
["disposal_account", "disposal_cost_center"])
if not disposal_account or not disposal_cost_center:
frappe.throw(_("Please set 'Asset Disposal Account' and 'Asset Disposal Cost Center' in Company {0}").format(company))
return disposal_account, disposal_cost_center

View File

@ -1,8 +1,36 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Asset Category', {
refresh: function(frm) {
cur_frm.fields_dict['accounts'].grid.get_field('fixed_asset_account').get_query = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
return {
"filters": {
"account_type": "Fixed Asset",
"root_type": "Asset",
"is_group": 0,
"company": d.company
}
};
}
}
});
cur_frm.fields_dict['accounts'].grid.get_field('accumulated_depreciation_account').get_query = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
return {
"filters": {
"root_type": "Asset",
"is_group": 0,
"company": d.company
}
};
}
cur_frm.fields_dict['accounts'].grid.get_field('depreciation_expense_account').get_query = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
return {
"filters": {
"root_type": "Expense",
"is_group": 0,
"company": d.company
}
};
}

View File

@ -34,30 +34,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "section_break_2",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -80,7 +56,7 @@
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@ -89,32 +65,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "useful_life",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Useful Life (Years)",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "column_break_5",
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
@ -138,17 +89,16 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "fixed_asset_account",
"fieldtype": "Link",
"fieldname": "number_of_depreciations",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Fixed Asset Account",
"label": "Number of Depreciations",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -164,17 +114,16 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "accumulated_depreciation_account",
"fieldtype": "Link",
"fieldname": "number_of_months_in_a_period",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Accumulated Depreciation Account",
"label": "Number of Months in a Period",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -190,24 +139,49 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "depreciation_expense_account",
"fieldtype": "Link",
"fieldname": "section_break_2",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Depreciation Expense Account",
"label": "Accounts",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "accounts",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Accounts",
"length": 0,
"no_copy": 0,
"options": "Asset Category Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@ -222,7 +196,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-03-03 15:17:44.877003",
"modified": "2016-03-07 19:01:19.265210",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Asset Category",

View File

@ -4,7 +4,12 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
class AssetCategory(Document):
pass
def validate(self):
for field in ("depreciation_method", "number_of_depreciations",
"number_of_months_in_a_period", "accounts"):
if not self.get(field):
frappe.throw(_("{0} is mandatory").format(self.meta.get_label(field)))

View File

@ -0,0 +1,136 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"creation": "2016-03-07 15:55:18.806409",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "fixed_asset_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"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,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "accumulated_depreciation_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"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,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "depreciation_expense_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"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,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2016-03-07 19:02:09.879979",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Asset Category Account",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class AssetCategoryAccount(Document):
pass

View File

@ -13,21 +13,21 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "depreciation_date",
"fieldname": "schedule_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Depreciation Date",
"label": "Schedule Date",
"length": 0,
"no_copy": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
@ -47,6 +47,31 @@
"in_list_view": 1,
"label": "Depreciation Amount",
"length": 0,
"no_copy": 1,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
@ -54,7 +79,7 @@
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@ -72,43 +97,19 @@
"in_list_view": 1,
"label": "Accumulated Depreciation Amount",
"length": 0,
"no_copy": 0,
"no_copy": 1,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "posted",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Posted",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -119,16 +120,16 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_list_view": 1,
"label": "Journal Entry",
"length": 0,
"no_copy": 0,
"no_copy": 1,
"options": "Journal Entry",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@ -145,7 +146,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2016-03-03 14:50:39.794061",
"modified": "2016-03-09 12:21:27.938215",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Depreciation Schedule",

View File

@ -16,6 +16,7 @@
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_list_view": 1,
"label": "Account",
@ -44,6 +45,7 @@
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Account Type",
@ -68,6 +70,7 @@
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Account Balance",
@ -96,6 +99,7 @@
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_list_view": 0,
"label": "Cost Center",
@ -124,6 +128,7 @@
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
@ -146,6 +151,7 @@
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Party Type",
@ -170,6 +176,7 @@
"fieldtype": "Dynamic Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Party",
@ -194,6 +201,7 @@
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Party Balance",
@ -221,6 +229,7 @@
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Currency",
@ -245,6 +254,7 @@
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Account Currency",
@ -270,6 +280,7 @@
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
@ -293,6 +304,7 @@
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Exchange Rate",
@ -317,6 +329,7 @@
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Amount",
@ -340,6 +353,7 @@
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Debit",
@ -365,6 +379,7 @@
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Debit in Company Currency",
@ -392,6 +407,7 @@
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
@ -414,6 +430,7 @@
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Credit",
@ -439,6 +456,7 @@
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Credit in Company Currency",
@ -466,6 +484,7 @@
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference",
@ -489,12 +508,13 @@
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference Type",
"length": 0,
"no_copy": 0,
"options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim",
"options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -514,6 +534,7 @@
"fieldtype": "Dynamic Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Reference Name",
@ -539,6 +560,7 @@
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
@ -561,6 +583,7 @@
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Is Advance",
@ -587,6 +610,7 @@
"fieldtype": "Text",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Against Account",
@ -614,12 +638,13 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2015-12-02 04:14:37.571883",
"modified": "2016-03-07 19:10:27.135795",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Account",
"owner": "Administrator",
"permissions": [],
"read_only": 0,
"read_only_onload": 0
"read_only_onload": 0,
"sort_order": "DESC"
}

View File

@ -210,6 +210,18 @@ cur_frm.set_query("expense_account", "items", function(doc) {
}
});
cur_frm.set_query("asset", "items", function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
return {
filters: {
'item_code': d.item_code,
'docstatus': 1,
'company': doc.company,
'status': 'Available'
}
}
});
cur_frm.cscript.expense_account = function(doc, cdt, cdn){
var d = locals[cdt][cdn];
if(d.idx == 1 && d.expense_account){

View File

@ -253,19 +253,28 @@ class PurchaseInvoice(BuyingController):
self.update_project()
def post_asset_depreciation(self):
from erpnext.accounts.doctype.asset.asset import depreciate_asset
for d in self.get("items"):
if frappe.db.get_value("Item", d.item_code, "is_fixed_asset"):
if not d.asset:
frappe.throw(_("Row #{0}: Asset is mandatory against a Fixed Asset Item").format(d.idx))
else:
asset = frappe.get_doc("Asset", d.asset)
if asset.start_depreciation_from_purchase_date:
for schedule in asset.get("schedules"):
if schedule.depreciation_date == asset.purchase_date:
depreciate_asset(asset.name, schedule.depreciation_amount, schedule.name)
break
self.validate_asset(asset, d)
frappe.db.set_value("Asset", asset.name, "purchase_invoice",
(self.name if self.docstatus==1 else None))
def validate_asset(self, asset, item_row):
super(PurchaseInvoice, self).validate_asset(asset, item_row)
if getdate(asset.purchase_date) != getdate(self.posting_date):
frappe.throw(_("Purchase Date of asset {0} does not match with Purchase Invoice date")
.format(item_row.asset))
if asset.supplier != self.supplier:
frappe.throw(_("Supplier of asset {0} does not match with the supplier in the Purchase Invoice")
.format(item_row.asset))
def make_gl_entries(self):
auto_accounting_for_stock = \
cint(frappe.defaults.get_global_default("auto_accounting_for_stock"))
@ -432,6 +441,7 @@ class PurchaseInvoice(BuyingController):
self.make_gl_entries_on_cancel()
self.update_project()
self.post_asset_depreciation()
def update_project(self):
project_list = []

View File

@ -471,3 +471,15 @@ cur_frm.set_query("debit_to", function(doc) {
}
}
});
cur_frm.set_query("asset", "items", function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
return {
filters: {
'item_code': d.item_code,
'docstatus': 1,
'company': doc.company,
'status': 'Available'
}
}
});

View File

@ -13,6 +13,7 @@ from frappe.model.mapper import get_mapped_doc
from erpnext.controllers.selling_controller import SellingController
from erpnext.accounts.utils import get_account_currency
from erpnext.stock.doctype.delivery_note.delivery_note import update_billed_amount_based_on_so
from erpnext.accounts.doctype.asset.depreciation import get_gl_entries_on_asset_disposal
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@ -59,6 +60,7 @@ class SalesInvoice(SellingController):
self.validate_advance_jv("Sales Order")
self.add_remarks()
self.validate_write_off_account()
self.set_income_account_for_fixed_assets()
if cint(self.is_pos):
self.validate_pos()
@ -447,6 +449,17 @@ class SalesInvoice(SellingController):
msgprint(_("POS Profile required to make POS Entry"), raise_exception=True)
return warehouse
def set_income_account_for_fixed_assets(self):
disposal_account = None
for d in self.get("items"):
if frappe.db.get_value("Item", d.item_code, "is_fixed_asset"):
if not disposal_account:
disposal_account = frappe.db.get_value("Company", self.company, "disposal_account")
if not disposal_account:
frappe.throw(_("Please mention 'Gain/Loss Account on Asset Disposal' in Company"))
d.income_account = disposal_account
def on_update(self):
if cint(self.is_pos) == 1:
@ -557,17 +570,31 @@ class SalesInvoice(SellingController):
# income account gl entries
for item in self.get("items"):
if flt(item.base_net_amount):
account_currency = get_account_currency(item.income_account)
gl_entries.append(
self.get_gl_dict({
"account": item.income_account,
"against": self.customer,
"credit": item.base_net_amount,
"credit_in_account_currency": item.base_net_amount \
if account_currency==self.company_currency else item.net_amount,
"cost_center": item.cost_center
}, account_currency)
)
if frappe.db.get_value("Item", item.item_code, "is_fixed_asset"):
if not item.asset:
frappe.throw(_("Row #{0}: Asset is mandatory against a Fixed Asset Item")
.format(item.idx))
else:
asset = frappe.get_doc("Asset", item.asset)
self.validate_asset(asset, item)
fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(asset, item.base_net_amount)
for gle in fixed_asset_gl_entries:
gl_entries.append(self.get_gl_dict(gle))
frappe.db.set_value("Asset", asset.name, "status", "Sold")
else:
account_currency = get_account_currency(item.income_account)
gl_entries.append(
self.get_gl_dict({
"account": item.income_account,
"against": self.customer,
"credit": item.base_net_amount,
"credit_in_account_currency": item.base_net_amount \
if account_currency==self.company_currency else item.net_amount,
"cost_center": item.cost_center
}, account_currency)
)
# expense account gl entries
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) \

View File

@ -458,7 +458,20 @@ class AccountsController(TransactionBase):
# Note: not validating with gle account because we don't have the account
# at quotation / sales order level and we shouldn't stop someone
# from creating a sales invoice if sales order is already created
def validate_asset(self, asset, item_row):
if asset.company != self.company:
frappe.throw(_("Row #{0}: Asset {1} does not belong to company {2}")
.format(item_row.idx, item_row.asset, self.company))
elif asset.item_code != item_row.item_code:
frappe.throw(_("Row #{0}: Asset {1} does not linked to Item {2}")
.format(item_row.idx, item_row.asset, item_row.item_code))
elif asset.docstatus != 1:
frappe.throw(_("Row #{0}: Asset {1} must be submitted").format(item_row.idx, item_row.asset))
elif item_row.qty > 1:
frappe.throw(_("Row #{0}: Qty must be 1, as item is linked to an asset").format(item_row.idx))
@frappe.whitelist()
def get_tax_rate(account_head):
return frappe.db.get_value("Account", account_head, "tax_rate")

View File

@ -137,7 +137,8 @@ scheduler_events = {
"erpnext.support.doctype.issue.issue.auto_close_tickets",
"erpnext.accounts.doctype.fiscal_year.fiscal_year.auto_create_fiscal_year",
"erpnext.hr.doctype.employee.employee.send_birthday_reminders",
"erpnext.projects.doctype.task.task.set_tasks_as_overdue"
"erpnext.projects.doctype.task.task.set_tasks_as_overdue",
"erpnext.accounts.doctype.asset.depreciation.post_depreciation_entries"
]
}

View File

@ -136,8 +136,12 @@ erpnext.company.setup_queries = function(frm) {
["default_expense_account", {"root_type": "Expense"}],
["default_income_account", {"root_type": "Income"}],
["round_off_account", {"root_type": "Expense"}],
["accumulated_depreciation_account", {"root_type": "Asset"}],
["depreciation_expense_account", {"root_type": "Expense"}],
["disposal_account", {"report_type": "Profit and Loss"}],
["cost_center", {}],
["round_off_cost_center", {}]
["round_off_cost_center", {}],
["disposal_cost_center", {}]
], function(i, v) {
erpnext.company.set_custom_query(frm, v);
});

View File

@ -253,12 +253,11 @@
"no_copy": 0,
"options": "Terms and Conditions",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@ -990,18 +989,17 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "Straight Line",
"fieldname": "depreciation_method",
"fieldtype": "Select",
"fieldname": "accumulated_depreciation_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Depreciation Method",
"label": "Accumulated Depreciation Account",
"length": 0,
"no_copy": 0,
"options": "Straight Line\nDouble Declining Balance",
"no_copy": 1,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -1017,16 +1015,16 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "accumulated_depreciation_account",
"fieldname": "depreciation_expense_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Accumulated Depreciation Account",
"label": "Depreciation Expense Account",
"length": 0,
"no_copy": 0,
"no_copy": 1,
"options": "Account",
"permlevel": 0,
"precision": "",
@ -1067,16 +1065,16 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "depreciation_expense_account",
"fieldname": "disposal_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Depreciation Expense Account",
"label": "Gain/Loss Account on Asset Disposal",
"length": 0,
"no_copy": 0,
"no_copy": 1,
"options": "Account",
"permlevel": 0,
"precision": "",
@ -1093,17 +1091,17 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "gain_loss_account",
"fieldname": "disposal_cost_center",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Gain/Loss Account on Asset Sale/Disposal",
"label": "Asset Disposal Cost Center",
"length": 0,
"no_copy": 0,
"options": "Account",
"no_copy": 1,
"options": "Cost Center",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -1389,7 +1387,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2016-03-08 20:21:46.331870",
"modified": "2016-03-09 12:06:12.189968",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",

View File

@ -251,6 +251,36 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "",
"depends_on": "",
"description": "",
"fieldname": "is_fixed_asset",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Is Fixed Asset",
"length": 0,
"no_copy": 0,
"oldfieldname": "is_asset_item",
"oldfieldtype": "Select",
"options": "",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -600,36 +630,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "",
"depends_on": "eval:doc.is_stock_item",
"description": "",
"fieldname": "is_fixed_asset",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Is Fixed Asset",
"length": 0,
"no_copy": 0,
"oldfieldname": "is_asset_item",
"oldfieldtype": "Select",
"options": "",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,

View File

@ -80,10 +80,12 @@ class Item(WebsiteGenerator):
self.validate_variant_attributes()
self.validate_website_image()
self.make_thumbnail()
self.validate_fixed_asset_item()
if not self.get("__islocal"):
self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group")
self.old_website_item_groups = frappe.db.sql_list("""select item_group from `tabWebsite Item Group`
self.old_website_item_groups = frappe.db.sql_list("""select item_group
from `tabWebsite Item Group`
where parentfield='website_item_groups' and parenttype='Item' and parent=%s""", self.name)
def on_update(self):
@ -566,6 +568,10 @@ class Item(WebsiteGenerator):
if variant:
frappe.throw(_("Item variant {0} exists with same attributes")
.format(variant), ItemVariantExistsError)
def validate_fixed_asset_item(self):
if self.is_fixed_asset and self.is_stock_item:
frappe.throw(_("Fixed Asset Item must be a non-stock item"))
def validate_end_of_life(item_code, end_of_life=None, disabled=None, verbose=1):
if (not end_of_life) or (disabled is None):