style: format code with black

This commit is contained in:
Ankush Menat
2022-03-28 18:52:46 +05:30
parent 21e00da3d6
commit 494bd9ef78
1395 changed files with 91704 additions and 62532 deletions

View File

@@ -18,30 +18,36 @@ def get_data():
if not fiscal_year:
return frappe._dict()
year_start_date = get_date_str(fiscal_year.get('year_start_date'))
year_end_date = get_date_str(fiscal_year.get('year_end_date'))
year_start_date = get_date_str(fiscal_year.get("year_start_date"))
year_end_date = get_date_str(fiscal_year.get("year_end_date"))
return frappe._dict(
{
"dashboards": get_dashboards(),
"charts": get_charts(fiscal_year, year_start_date, year_end_date),
"number_cards": get_number_cards(fiscal_year, year_start_date, year_end_date),
}
)
return frappe._dict({
"dashboards": get_dashboards(),
"charts": get_charts(fiscal_year, year_start_date, year_end_date),
"number_cards": get_number_cards(fiscal_year, year_start_date, year_end_date),
})
def get_dashboards():
return [{
"name": "Asset",
"dashboard_name": "Asset",
"charts": [
{ "chart": "Asset Value Analytics", "width": "Full" },
{ "chart": "Category-wise Asset Value", "width": "Half" },
{ "chart": "Location-wise Asset Value", "width": "Half" },
],
"cards": [
{"card": "Total Assets"},
{"card": "New Assets (This Year)"},
{"card": "Asset Value"}
]
}]
return [
{
"name": "Asset",
"dashboard_name": "Asset",
"charts": [
{"chart": "Asset Value Analytics", "width": "Full"},
{"chart": "Category-wise Asset Value", "width": "Half"},
{"chart": "Location-wise Asset Value", "width": "Half"},
],
"cards": [
{"card": "Total Assets"},
{"card": "New Assets (This Year)"},
{"card": "Asset Value"},
],
}
]
def get_charts(fiscal_year, year_start_date, year_end_date):
company = get_company_for_dashboards()
@@ -58,26 +64,30 @@ def get_charts(fiscal_year, year_start_date, year_end_date):
"timespan": "Last Year",
"time_interval": "Yearly",
"timeseries": 0,
"filters_json": json.dumps({
"company": company,
"status": "In Location",
"filter_based_on": "Fiscal Year",
"from_fiscal_year": fiscal_year.get('name'),
"to_fiscal_year": fiscal_year.get('name'),
"period_start_date": year_start_date,
"period_end_date": year_end_date,
"date_based_on": "Purchase Date",
"group_by": "--Select a group--"
}),
"filters_json": json.dumps(
{
"company": company,
"status": "In Location",
"filter_based_on": "Fiscal Year",
"from_fiscal_year": fiscal_year.get("name"),
"to_fiscal_year": fiscal_year.get("name"),
"period_start_date": year_start_date,
"period_end_date": year_end_date,
"date_based_on": "Purchase Date",
"group_by": "--Select a group--",
}
),
"type": "Bar",
"custom_options": json.dumps({
"type": "bar",
"barOptions": { "stacked": 1 },
"axisOptions": { "shortenYAxisNumbers": 1 },
"tooltipOptions": {}
}),
"custom_options": json.dumps(
{
"type": "bar",
"barOptions": {"stacked": 1},
"axisOptions": {"shortenYAxisNumbers": 1},
"tooltipOptions": {},
}
),
"doctype": "Dashboard Chart",
"y_axis": []
"y_axis": [],
},
{
"name": "Category-wise Asset Value",
@@ -86,12 +96,14 @@ def get_charts(fiscal_year, year_start_date, year_end_date):
"report_name": "Fixed Asset Register",
"x_field": "asset_category",
"timeseries": 0,
"filters_json": json.dumps({
"company": company,
"status":"In Location",
"group_by":"Asset Category",
"is_existing_asset":0
}),
"filters_json": json.dumps(
{
"company": company,
"status": "In Location",
"group_by": "Asset Category",
"is_existing_asset": 0,
}
),
"type": "Donut",
"doctype": "Dashboard Chart",
"y_axis": [
@@ -100,14 +112,12 @@ def get_charts(fiscal_year, year_start_date, year_end_date):
"parentfield": "y_axis",
"parenttype": "Dashboard Chart",
"y_field": "asset_value",
"doctype": "Dashboard Chart Field"
"doctype": "Dashboard Chart Field",
}
],
"custom_options": json.dumps({
"type": "donut",
"height": 300,
"axisOptions": {"shortenYAxisNumbers": 1}
})
"custom_options": json.dumps(
{"type": "donut", "height": 300, "axisOptions": {"shortenYAxisNumbers": 1}}
),
},
{
"name": "Location-wise Asset Value",
@@ -116,12 +126,9 @@ def get_charts(fiscal_year, year_start_date, year_end_date):
"report_name": "Fixed Asset Register",
"x_field": "location",
"timeseries": 0,
"filters_json": json.dumps({
"company": company,
"status":"In Location",
"group_by":"Location",
"is_existing_asset":0
}),
"filters_json": json.dumps(
{"company": company, "status": "In Location", "group_by": "Location", "is_existing_asset": 0}
),
"type": "Donut",
"doctype": "Dashboard Chart",
"y_axis": [
@@ -130,17 +137,16 @@ def get_charts(fiscal_year, year_start_date, year_end_date):
"parentfield": "y_axis",
"parenttype": "Dashboard Chart",
"y_field": "asset_value",
"doctype": "Dashboard Chart Field"
"doctype": "Dashboard Chart Field",
}
],
"custom_options": json.dumps({
"type": "donut",
"height": 300,
"axisOptions": {"shortenYAxisNumbers": 1}
})
}
"custom_options": json.dumps(
{"type": "donut", "height": 300, "axisOptions": {"shortenYAxisNumbers": 1}}
),
},
]
def get_number_cards(fiscal_year, year_start_date, year_end_date):
return [
{
@@ -162,9 +168,9 @@ def get_number_cards(fiscal_year, year_start_date, year_end_date):
"is_public": 1,
"show_percentage_stats": 1,
"stats_time_interval": "Monthly",
"filters_json": json.dumps([
['Asset', 'creation', 'between', [year_start_date, year_end_date]]
]),
"filters_json": json.dumps(
[["Asset", "creation", "between", [year_start_date, year_end_date]]]
),
"doctype": "Number Card",
},
{
@@ -177,6 +183,6 @@ def get_number_cards(fiscal_year, year_start_date, year_end_date):
"show_percentage_stats": 1,
"stats_time_interval": "Monthly",
"filters_json": "[]",
"doctype": "Number Card"
}
"doctype": "Number Card",
},
]

File diff suppressed because it is too large Load Diff

View File

@@ -3,13 +3,6 @@ from frappe import _
def get_data():
return {
'non_standard_fieldnames': {
'Asset Movement': 'asset'
},
'transactions': [
{
'label': _('Movement'),
'items': ['Asset Movement']
}
]
"non_standard_fieldnames": {"Asset Movement": "asset"},
"transactions": [{"label": _("Movement"), "items": ["Asset Movement"]}],
}

View File

@@ -13,7 +13,9 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
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")):
if not cint(
frappe.db.get_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically")
):
return
if not date:
@@ -22,26 +24,35 @@ def post_depreciation_entries(date=None):
make_depreciation_entry(asset, date)
frappe.db.commit()
def get_depreciable_assets(date):
return frappe.db.sql_list("""select distinct a.name
return frappe.db.sql_list(
"""select distinct a.name
from tabAsset a, `tabDepreciation Schedule` ds
where a.name = ds.parent and a.docstatus=1 and ds.schedule_date<=%s and a.calculate_depreciation = 1
and a.status in ('Submitted', 'Partially Depreciated')
and ifnull(ds.journal_entry, '')=''""", date)
and ifnull(ds.journal_entry, '')=''""",
date,
)
@frappe.whitelist()
def make_depreciation_entry(asset_name, date=None):
frappe.has_permission('Journal Entry', throw=True)
frappe.has_permission("Journal Entry", throw=True)
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)
(
fixed_asset_account,
accumulated_depreciation_account,
depreciation_expense_account,
) = get_depreciation_accounts(asset)
depreciation_cost_center, depreciation_series = frappe.get_cached_value('Company', asset.company,
["depreciation_cost_center", "series_for_depreciation_entry"])
depreciation_cost_center, depreciation_series = frappe.get_cached_value(
"Company", asset.company, ["depreciation_cost_center", "series_for_depreciation_entry"]
)
depreciation_cost_center = asset.cost_center or depreciation_cost_center
@@ -57,14 +68,16 @@ def make_depreciation_entry(asset_name, date=None):
je.finance_book = d.finance_book
je.remark = "Depreciation Entry against {0} worth {1}".format(asset_name, d.depreciation_amount)
credit_account, debit_account = get_credit_and_debit_accounts(accumulated_depreciation_account, depreciation_expense_account)
credit_account, debit_account = get_credit_and_debit_accounts(
accumulated_depreciation_account, depreciation_expense_account
)
credit_entry = {
"account": credit_account,
"credit_in_account_currency": d.depreciation_amount,
"reference_type": "Asset",
"reference_name": asset.name,
"cost_center": depreciation_cost_center
"cost_center": depreciation_cost_center,
}
debit_entry = {
@@ -72,19 +85,25 @@ def make_depreciation_entry(asset_name, date=None):
"debit_in_account_currency": d.depreciation_amount,
"reference_type": "Asset",
"reference_name": asset.name,
"cost_center": depreciation_cost_center
"cost_center": depreciation_cost_center,
}
for dimension in accounting_dimensions:
if (asset.get(dimension['fieldname']) or dimension.get('mandatory_for_bs')):
credit_entry.update({
dimension['fieldname']: asset.get(dimension['fieldname']) or dimension.get('default_dimension')
})
if asset.get(dimension["fieldname"]) or dimension.get("mandatory_for_bs"):
credit_entry.update(
{
dimension["fieldname"]: asset.get(dimension["fieldname"])
or dimension.get("default_dimension")
}
)
if (asset.get(dimension['fieldname']) or dimension.get('mandatory_for_pl')):
debit_entry.update({
dimension['fieldname']: asset.get(dimension['fieldname']) or dimension.get('default_dimension')
})
if asset.get(dimension["fieldname"]) or dimension.get("mandatory_for_pl"):
debit_entry.update(
{
dimension["fieldname"]: asset.get(dimension["fieldname"])
or dimension.get("default_dimension")
}
)
je.append("accounts", credit_entry)
@@ -98,7 +117,7 @@ def make_depreciation_entry(asset_name, date=None):
d.db_set("journal_entry", je.name)
idx = cint(d.finance_book_id)
finance_books = asset.get('finance_books')[idx - 1]
finance_books = asset.get("finance_books")[idx - 1]
finance_books.value_after_depreciation -= d.depreciation_amount
finance_books.db_update()
@@ -106,13 +125,20 @@ def make_depreciation_entry(asset_name, date=None):
return asset
def get_depreciation_accounts(asset):
fixed_asset_account = accumulated_depreciation_account = depreciation_expense_account = None
accounts = frappe.db.get_value("Asset Category Account",
filters={'parent': asset.asset_category, 'company_name': asset.company},
fieldname = ['fixed_asset_account', 'accumulated_depreciation_account',
'depreciation_expense_account'], as_dict=1)
accounts = frappe.db.get_value(
"Asset Category Account",
filters={"parent": asset.asset_category, "company_name": asset.company},
fieldname=[
"fixed_asset_account",
"accumulated_depreciation_account",
"depreciation_expense_account",
],
as_dict=1,
)
if accounts:
fixed_asset_account = accounts.fixed_asset_account
@@ -120,20 +146,29 @@ def get_depreciation_accounts(asset):
depreciation_expense_account = accounts.depreciation_expense_account
if not accumulated_depreciation_account or not depreciation_expense_account:
accounts = frappe.get_cached_value('Company', asset.company,
["accumulated_depreciation_account", "depreciation_expense_account"])
accounts = frappe.get_cached_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 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))
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 fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account
def get_credit_and_debit_accounts(accumulated_depreciation_account, depreciation_expense_account):
root_type = frappe.get_value("Account", depreciation_expense_account, "root_type")
@@ -148,6 +183,7 @@ def get_credit_and_debit_accounts(accumulated_depreciation_account, depreciation
return credit_account, debit_account
@frappe.whitelist()
def scrap_asset(asset_name):
asset = frappe.get_doc("Asset", asset_name)
@@ -155,9 +191,13 @@ 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"):
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)
)
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"
@@ -167,10 +207,7 @@ def scrap_asset(asset_name):
je.remark = "Scrap Entry for asset {0}".format(asset_name)
for entry in get_gl_entries_on_asset_disposal(asset):
entry.update({
"reference_type": "Asset",
"reference_name": asset_name
})
entry.update({"reference_type": "Asset", "reference_name": asset_name})
je.append("accounts", entry)
je.flags.ignore_permissions = True
@@ -182,6 +219,7 @@ def scrap_asset(asset_name):
frappe.msgprint(_("Asset scrapped via Journal Entry {0}").format(je.name))
@frappe.whitelist()
def restore_asset(asset_name):
asset = frappe.get_doc("Asset", asset_name)
@@ -195,23 +233,31 @@ def restore_asset(asset_name):
asset.set_status()
def get_gl_entries_on_asset_regain(asset, selling_amount=0, finance_book=None):
fixed_asset_account, asset, depreciation_cost_center, accumulated_depr_account, accumulated_depr_amount, disposal_account, value_after_depreciation = \
get_asset_details(asset, finance_book)
(
fixed_asset_account,
asset,
depreciation_cost_center,
accumulated_depr_account,
accumulated_depr_amount,
disposal_account,
value_after_depreciation,
) = get_asset_details(asset, finance_book)
gl_entries = [
{
"account": fixed_asset_account,
"debit_in_account_currency": asset.gross_purchase_amount,
"debit": asset.gross_purchase_amount,
"cost_center": depreciation_cost_center
"cost_center": depreciation_cost_center,
},
{
"account": accumulated_depr_account,
"credit_in_account_currency": accumulated_depr_amount,
"credit": accumulated_depr_amount,
"cost_center": depreciation_cost_center
}
"cost_center": depreciation_cost_center,
},
]
profit_amount = abs(flt(value_after_depreciation)) - abs(flt(selling_amount))
@@ -220,23 +266,31 @@ def get_gl_entries_on_asset_regain(asset, selling_amount=0, finance_book=None):
return gl_entries
def get_gl_entries_on_asset_disposal(asset, selling_amount=0, finance_book=None):
fixed_asset_account, asset, depreciation_cost_center, accumulated_depr_account, accumulated_depr_amount, disposal_account, value_after_depreciation = \
get_asset_details(asset, finance_book)
(
fixed_asset_account,
asset,
depreciation_cost_center,
accumulated_depr_account,
accumulated_depr_amount,
disposal_account,
value_after_depreciation,
) = get_asset_details(asset, finance_book)
gl_entries = [
{
"account": fixed_asset_account,
"credit_in_account_currency": asset.gross_purchase_amount,
"credit": asset.gross_purchase_amount,
"cost_center": depreciation_cost_center
"cost_center": depreciation_cost_center,
},
{
"account": accumulated_depr_account,
"debit_in_account_currency": accumulated_depr_amount,
"debit": accumulated_depr_amount,
"cost_center": depreciation_cost_center
}
"cost_center": depreciation_cost_center,
},
]
profit_amount = flt(selling_amount) - flt(value_after_depreciation)
@@ -245,8 +299,11 @@ def get_gl_entries_on_asset_disposal(asset, selling_amount=0, finance_book=None)
return gl_entries
def get_asset_details(asset, finance_book=None):
fixed_asset_account, accumulated_depr_account, depr_expense_account = get_depreciation_accounts(asset)
fixed_asset_account, accumulated_depr_account, depr_expense_account = get_depreciation_accounts(
asset
)
disposal_account, depreciation_cost_center = get_disposal_account_and_cost_center(asset.company)
depreciation_cost_center = asset.cost_center or depreciation_cost_center
@@ -257,28 +314,46 @@ def get_asset_details(asset, finance_book=None):
idx = d.idx
break
value_after_depreciation = (asset.finance_books[idx - 1].value_after_depreciation
if asset.calculate_depreciation else asset.value_after_depreciation)
value_after_depreciation = (
asset.finance_books[idx - 1].value_after_depreciation
if asset.calculate_depreciation
else asset.value_after_depreciation
)
accumulated_depr_amount = flt(asset.gross_purchase_amount) - flt(value_after_depreciation)
return fixed_asset_account, asset, depreciation_cost_center, accumulated_depr_account, accumulated_depr_amount, disposal_account, value_after_depreciation
return (
fixed_asset_account,
asset,
depreciation_cost_center,
accumulated_depr_account,
accumulated_depr_amount,
disposal_account,
value_after_depreciation,
)
def get_profit_gl_entries(profit_amount, gl_entries, disposal_account, depreciation_cost_center):
debit_or_credit = "debit" if profit_amount < 0 else "credit"
gl_entries.append({
"account": disposal_account,
"cost_center": depreciation_cost_center,
debit_or_credit: abs(profit_amount),
debit_or_credit + "_in_account_currency": abs(profit_amount)
})
gl_entries.append(
{
"account": disposal_account,
"cost_center": depreciation_cost_center,
debit_or_credit: abs(profit_amount),
debit_or_credit + "_in_account_currency": abs(profit_amount),
}
)
@frappe.whitelist()
def get_disposal_account_and_cost_center(company):
disposal_account, depreciation_cost_center = frappe.get_cached_value('Company', company,
["disposal_account", "depreciation_cost_center"])
disposal_account, depreciation_cost_center = frappe.get_cached_value(
"Company", company, ["disposal_account", "depreciation_cost_center"]
)
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))

File diff suppressed because it is too large Load Diff

View File

@@ -18,79 +18,104 @@ class AssetCategory(Document):
def validate_finance_books(self):
for d in self.finance_books:
for field in ("Total Number of Depreciations", "Frequency of Depreciation"):
if cint(d.get(frappe.scrub(field)))<1:
frappe.throw(_("Row {0}: {1} must be greater than 0").format(d.idx, field), frappe.MandatoryError)
if cint(d.get(frappe.scrub(field))) < 1:
frappe.throw(
_("Row {0}: {1} must be greater than 0").format(d.idx, field), frappe.MandatoryError
)
def validate_account_currency(self):
account_types = [
'fixed_asset_account', 'accumulated_depreciation_account', 'depreciation_expense_account', 'capital_work_in_progress_account'
"fixed_asset_account",
"accumulated_depreciation_account",
"depreciation_expense_account",
"capital_work_in_progress_account",
]
invalid_accounts = []
for d in self.accounts:
company_currency = frappe.get_value('Company', d.get('company_name'), 'default_currency')
company_currency = frappe.get_value("Company", d.get("company_name"), "default_currency")
for type_of_account in account_types:
if d.get(type_of_account):
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) }))
invalid_accounts.append(
frappe._dict({"type": type_of_account, "idx": d.idx, "account": d.get(type_of_account)})
)
for d in invalid_accounts:
frappe.throw(_("Row #{}: Currency of {} - {} doesn't matches company currency.")
.format(d.idx, frappe.bold(frappe.unscrub(d.type)), frappe.bold(d.account)),
title=_("Invalid Account"))
frappe.throw(
_("Row #{}: Currency of {} - {} doesn't matches company currency.").format(
d.idx, frappe.bold(frappe.unscrub(d.type)), frappe.bold(d.account)
),
title=_("Invalid Account"),
)
def validate_account_types(self):
account_type_map = {
'fixed_asset_account': {'account_type': ['Fixed Asset']},
'accumulated_depreciation_account': {'account_type': ['Accumulated Depreciation']},
'depreciation_expense_account': {'root_type': ['Expense', 'Income']},
'capital_work_in_progress_account': {'account_type': ['Capital Work in Progress']}
"fixed_asset_account": {"account_type": ["Fixed Asset"]},
"accumulated_depreciation_account": {"account_type": ["Accumulated Depreciation"]},
"depreciation_expense_account": {"root_type": ["Expense", "Income"]},
"capital_work_in_progress_account": {"account_type": ["Capital Work in Progress"]},
}
for d in self.accounts:
for fieldname in account_type_map.keys():
if d.get(fieldname):
selected_account = d.get(fieldname)
key_to_match = next(iter(account_type_map.get(fieldname))) # acount_type or root_type
selected_key_type = frappe.db.get_value('Account', selected_account, key_to_match)
key_to_match = next(iter(account_type_map.get(fieldname))) # acount_type or root_type
selected_key_type = frappe.db.get_value("Account", selected_account, key_to_match)
expected_key_types = account_type_map[fieldname][key_to_match]
if selected_key_type not in expected_key_types:
frappe.throw(_("Row #{}: {} of {} should be {}. Please modify the account or select a different account.")
.format(d.idx, frappe.unscrub(key_to_match), frappe.bold(selected_account), frappe.bold(expected_key_types)),
title=_("Invalid Account"))
frappe.throw(
_(
"Row #{}: {} of {} should be {}. Please modify the account or select a different account."
).format(
d.idx,
frappe.unscrub(key_to_match),
frappe.bold(selected_account),
frappe.bold(expected_key_types),
),
title=_("Invalid Account"),
)
def valide_cwip_account(self):
if self.enable_cwip_accounting:
missing_cwip_accounts_for_company = []
for d in self.accounts:
if (not d.capital_work_in_progress_account and
not frappe.db.get_value("Company", d.company_name, "capital_work_in_progress_account")):
if not d.capital_work_in_progress_account and not frappe.db.get_value(
"Company", d.company_name, "capital_work_in_progress_account"
):
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 += _("""you must select Capital Work in Progress Account in accounts table""")
msg += "<br><br>"
msg += _("You can also set default CWIP account in Company {}").format(", ".join(missing_cwip_accounts_for_company))
msg += _("You can also set default CWIP account in Company {}").format(
", ".join(missing_cwip_accounts_for_company)
)
frappe.throw(msg, title=_("Missing Account"))
@frappe.whitelist()
def get_asset_category_account(fieldname, item=None, asset=None, account=None, asset_category = None, company = None):
def get_asset_category_account(
fieldname, item=None, asset=None, account=None, asset_category=None, company=None
):
if item and frappe.db.get_value("Item", item, "is_fixed_asset"):
asset_category = frappe.db.get_value("Item", item, ["asset_category"])
elif not asset_category or not company:
if account:
if frappe.db.get_value("Account", account, "account_type") != "Fixed Asset":
account=None
account = None
if not account:
asset_details = frappe.db.get_value("Asset", asset, ["asset_category", "company"])
asset_category, company = asset_details or [None, None]
account = frappe.db.get_value("Asset Category Account",
filters={"parent": asset_category, "company_name": company}, fieldname=fieldname)
account = frappe.db.get_value(
"Asset Category Account",
filters={"parent": asset_category, "company_name": company},
fieldname=fieldname,
)
return account

View File

@@ -15,12 +15,15 @@ class TestAssetCategory(unittest.TestCase):
asset_category.total_number_of_depreciations = 3
asset_category.frequency_of_depreciation = 3
asset_category.append("accounts", {
"company_name": "_Test Company",
"fixed_asset_account": "_Test Fixed Asset - _TC",
"accumulated_depreciation_account": "_Test Accumulated Depreciations - _TC",
"depreciation_expense_account": "_Test Depreciations - _TC"
})
asset_category.append(
"accounts",
{
"company_name": "_Test Company",
"fixed_asset_account": "_Test Fixed Asset - _TC",
"accumulated_depreciation_account": "_Test Accumulated Depreciations - _TC",
"depreciation_expense_account": "_Test Depreciations - _TC",
},
)
try:
asset_category.insert(ignore_if_duplicate=True)
@@ -28,7 +31,9 @@ class TestAssetCategory(unittest.TestCase):
pass
def test_cwip_accounting(self):
company_cwip_acc = frappe.db.get_value("Company", "_Test Company", "capital_work_in_progress_account")
company_cwip_acc = 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")
@@ -37,11 +42,14 @@ class TestAssetCategory(unittest.TestCase):
asset_category.total_number_of_depreciations = 3
asset_category.frequency_of_depreciation = 3
asset_category.append("accounts", {
"company_name": "_Test Company",
"fixed_asset_account": "_Test Fixed Asset - _TC",
"accumulated_depreciation_account": "_Test Accumulated Depreciations - _TC",
"depreciation_expense_account": "_Test Depreciations - _TC"
})
asset_category.append(
"accounts",
{
"company_name": "_Test Company",
"fixed_asset_account": "_Test Fixed Asset - _TC",
"accumulated_depreciation_account": "_Test Accumulated Depreciations - _TC",
"depreciation_expense_account": "_Test Depreciations - _TC",
},
)
self.assertRaises(frappe.ValidationError, asset_category.insert)

View File

@@ -11,7 +11,7 @@ from frappe.utils import add_days, add_months, add_years, getdate, nowdate
class AssetMaintenance(Document):
def validate(self):
for task in self.get('asset_maintenance_tasks'):
for task in self.get("asset_maintenance_tasks"):
if task.end_date and (getdate(task.start_date) >= getdate(task.end_date)):
throw(_("Start date should be less than end date for task {0}").format(task.maintenance_task))
if getdate(task.next_due_date) < getdate(nowdate()):
@@ -20,83 +20,109 @@ class AssetMaintenance(Document):
throw(_("Row #{}: Please asign task to a member.").format(task.idx))
def on_update(self):
for task in self.get('asset_maintenance_tasks'):
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()
def sync_maintenance_tasks(self):
tasks_names = []
for task in self.get('asset_maintenance_tasks'):
for task in self.get("asset_maintenance_tasks"):
tasks_names.append(task.name)
update_maintenance_log(asset_maintenance = self.name, item_code = self.item_code, item_name = self.item_name, task = task)
asset_maintenance_logs = frappe.get_all("Asset Maintenance Log", fields=["name"], filters = {"asset_maintenance": self.name,
"task": ("not in", tasks_names)})
update_maintenance_log(
asset_maintenance=self.name, item_code=self.item_code, item_name=self.item_name, task=task
)
asset_maintenance_logs = frappe.get_all(
"Asset Maintenance Log",
fields=["name"],
filters={"asset_maintenance": self.name, "task": ("not in", tasks_names)},
)
if asset_maintenance_logs:
for asset_maintenance_log in asset_maintenance_logs:
maintenance_log = frappe.get_doc('Asset Maintenance Log', asset_maintenance_log.name)
maintenance_log.db_set('maintenance_status', 'Cancelled')
maintenance_log = frappe.get_doc("Asset Maintenance Log", asset_maintenance_log.name)
maintenance_log.db_set("maintenance_status", "Cancelled")
@frappe.whitelist()
def assign_tasks(asset_maintenance_name, assign_to_member, maintenance_task, next_due_date):
team_member = frappe.db.get_value('User', assign_to_member, "email")
team_member = frappe.db.get_value("User", assign_to_member, "email")
args = {
'doctype' : 'Asset Maintenance',
'assign_to' : [team_member],
'name' : asset_maintenance_name,
'description' : maintenance_task,
'date' : next_due_date
"doctype": "Asset Maintenance",
"assign_to": [team_member],
"name": asset_maintenance_name,
"description": maintenance_task,
"date": next_due_date,
}
if not frappe.db.sql("""select owner from `tabToDo`
if not frappe.db.sql(
"""select owner from `tabToDo`
where reference_type=%(doctype)s and reference_name=%(name)s and status="Open"
and owner=%(assign_to)s""", args):
and owner=%(assign_to)s""",
args,
):
assign_to.add(args)
@frappe.whitelist()
def calculate_next_due_date(periodicity, start_date = None, end_date = None, last_completion_date = None, next_due_date = None):
def calculate_next_due_date(
periodicity, start_date=None, end_date=None, last_completion_date=None, next_due_date=None
):
if not start_date and not last_completion_date:
start_date = frappe.utils.now()
if last_completion_date and ((start_date and last_completion_date > start_date) or not start_date):
if last_completion_date and (
(start_date and last_completion_date > start_date) or not start_date
):
start_date = last_completion_date
if periodicity == 'Daily':
if periodicity == "Daily":
next_due_date = add_days(start_date, 1)
if periodicity == 'Weekly':
if periodicity == "Weekly":
next_due_date = add_days(start_date, 7)
if periodicity == 'Monthly':
if periodicity == "Monthly":
next_due_date = add_months(start_date, 1)
if periodicity == 'Yearly':
if periodicity == "Yearly":
next_due_date = add_years(start_date, 1)
if periodicity == '2 Yearly':
if periodicity == "2 Yearly":
next_due_date = add_years(start_date, 2)
if periodicity == 'Quarterly':
if periodicity == "Quarterly":
next_due_date = add_months(start_date, 3)
if end_date and ((start_date and start_date >= end_date) or (last_completion_date and last_completion_date >= end_date) or next_due_date):
if end_date and (
(start_date and start_date >= end_date)
or (last_completion_date and last_completion_date >= end_date)
or next_due_date
):
next_due_date = ""
return next_due_date
def update_maintenance_log(asset_maintenance, item_code, item_name, task):
asset_maintenance_log = frappe.get_value("Asset Maintenance Log", {"asset_maintenance": asset_maintenance,
"task": task.name, "maintenance_status": ('in',['Planned','Overdue'])})
asset_maintenance_log = frappe.get_value(
"Asset Maintenance Log",
{
"asset_maintenance": asset_maintenance,
"task": task.name,
"maintenance_status": ("in", ["Planned", "Overdue"]),
},
)
if not asset_maintenance_log:
asset_maintenance_log = frappe.get_doc({
"doctype": "Asset Maintenance Log",
"asset_maintenance": asset_maintenance,
"asset_name": asset_maintenance,
"item_code": item_code,
"item_name": item_name,
"task": task.name,
"has_certificate": task.certificate_required,
"description": task.description,
"assign_to_name": task.assign_to_name,
"periodicity": str(task.periodicity),
"maintenance_type": task.maintenance_type,
"due_date": task.next_due_date
})
asset_maintenance_log = frappe.get_doc(
{
"doctype": "Asset Maintenance Log",
"asset_maintenance": asset_maintenance,
"asset_name": asset_maintenance,
"item_code": item_code,
"item_name": item_name,
"task": task.name,
"has_certificate": task.certificate_required,
"description": task.description,
"assign_to_name": task.assign_to_name,
"periodicity": str(task.periodicity),
"maintenance_type": task.maintenance_type,
"due_date": task.next_due_date,
}
)
asset_maintenance_log.insert()
else:
maintenance_log = frappe.get_doc('Asset Maintenance Log', asset_maintenance_log)
maintenance_log = frappe.get_doc("Asset Maintenance Log", asset_maintenance_log)
maintenance_log.assign_to_name = task.assign_to_name
maintenance_log.has_certificate = task.certificate_required
maintenance_log.description = task.description
@@ -105,15 +131,22 @@ def update_maintenance_log(asset_maintenance, item_code, item_name, task):
maintenance_log.due_date = task.next_due_date
maintenance_log.save()
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_team_members(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.get_values('Maintenance Team Member', { 'parent': filters.get("maintenance_team") }, "team_member")
return frappe.db.get_values(
"Maintenance Team Member", {"parent": filters.get("maintenance_team")}, "team_member"
)
@frappe.whitelist()
def get_maintenance_log(asset_name):
return frappe.db.sql("""
return frappe.db.sql(
"""
select maintenance_status, count(asset_name) as count, asset_name
from `tabAsset Maintenance Log`
where asset_name=%s group by maintenance_status""",
(asset_name), as_dict=1)
(asset_name),
as_dict=1,
)

View File

@@ -17,11 +17,12 @@ class TestAssetMaintenance(unittest.TestCase):
create_maintenance_team()
def test_create_asset_maintenance(self):
pr = make_purchase_receipt(item_code="Photocopier",
qty=1, rate=100000.0, location="Test Location")
pr = make_purchase_receipt(
item_code="Photocopier", qty=1, rate=100000.0, location="Test Location"
)
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset_doc = frappe.get_doc('Asset', asset_name)
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, "name")
asset_doc = frappe.get_doc("Asset", asset_name)
month_end_date = get_last_day(nowdate())
purchase_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15)
@@ -30,66 +31,74 @@ class TestAssetMaintenance(unittest.TestCase):
asset_doc.purchase_date = purchase_date
asset_doc.calculate_depreciation = 1
asset_doc.append("finance_books", {
"expected_value_after_useful_life": 200,
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
"frequency_of_depreciation": 10,
"depreciation_start_date": month_end_date
})
asset_doc.append(
"finance_books",
{
"expected_value_after_useful_life": 200,
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
"frequency_of_depreciation": 10,
"depreciation_start_date": month_end_date,
},
)
asset_doc.save()
if not frappe.db.exists("Asset Maintenance", "Photocopier"):
asset_maintenance = frappe.get_doc({
asset_maintenance = frappe.get_doc(
{
"doctype": "Asset Maintenance",
"asset_name": "Photocopier",
"maintenance_team": "Team Awesome",
"company": "_Test Company",
"asset_maintenance_tasks": get_maintenance_tasks()
}).insert()
"asset_maintenance_tasks": get_maintenance_tasks(),
}
).insert()
next_due_date = calculate_next_due_date(nowdate(), "Monthly")
self.assertEqual(asset_maintenance.asset_maintenance_tasks[0].next_due_date, next_due_date)
def test_create_asset_maintenance_log(self):
if not frappe.db.exists("Asset Maintenance Log", "Photocopier"):
asset_maintenance_log = frappe.get_doc({
asset_maintenance_log = frappe.get_doc(
{
"doctype": "Asset Maintenance Log",
"asset_maintenance": "Photocopier",
"task": "Change Oil",
"completion_date": add_days(nowdate(), 2),
"maintenance_status": "Completed"
}).insert()
"maintenance_status": "Completed",
}
).insert()
asset_maintenance = frappe.get_doc("Asset Maintenance", "Photocopier")
next_due_date = calculate_next_due_date(asset_maintenance_log.completion_date, "Monthly")
self.assertEqual(asset_maintenance.asset_maintenance_tasks[0].next_due_date, next_due_date)
def create_asset_data():
if not frappe.db.exists("Asset Category", "Equipment"):
create_asset_category()
if not frappe.db.exists("Location", "Test Location"):
frappe.get_doc({
'doctype': 'Location',
'location_name': 'Test Location'
}).insert()
frappe.get_doc({"doctype": "Location", "location_name": "Test Location"}).insert()
if not frappe.db.exists("Item", "Photocopier"):
meta = frappe.get_meta('Asset')
meta = frappe.get_meta("Asset")
naming_series = meta.get_field("naming_series").options
frappe.get_doc({
"doctype": "Item",
"item_code": "Photocopier",
"item_name": "Photocopier",
"item_group": "All Item Groups",
"company": "_Test Company",
"is_fixed_asset": 1,
"is_stock_item": 0,
"asset_category": "Equipment",
"auto_create_assets": 1,
"asset_naming_series": naming_series
}).insert()
frappe.get_doc(
{
"doctype": "Item",
"item_code": "Photocopier",
"item_name": "Photocopier",
"item_group": "All Item Groups",
"company": "_Test Company",
"is_fixed_asset": 1,
"is_stock_item": 0,
"asset_category": "Equipment",
"auto_create_assets": 1,
"asset_naming_series": naming_series,
}
).insert()
def create_maintenance_team():
user_list = ["marcus@abc.com", "thalia@abc.com", "mathias@abc.com"]
@@ -97,60 +106,73 @@ def create_maintenance_team():
frappe.get_doc({"doctype": "Role", "role_name": "Technician"}).insert()
for user in user_list:
if not frappe.db.get_value("User", user):
frappe.get_doc({
"doctype": "User",
"email": user,
"first_name": user,
"new_password": "password",
"roles": [{"doctype": "Has Role", "role": "Technician"}]
}).insert()
frappe.get_doc(
{
"doctype": "User",
"email": user,
"first_name": user,
"new_password": "password",
"roles": [{"doctype": "Has Role", "role": "Technician"}],
}
).insert()
if not frappe.db.exists("Asset Maintenance Team", "Team Awesome"):
frappe.get_doc({
"doctype": "Asset Maintenance Team",
"maintenance_manager": "marcus@abc.com",
"maintenance_team_name": "Team Awesome",
"company": "_Test Company",
"maintenance_team_members": get_maintenance_team(user_list)
}).insert()
frappe.get_doc(
{
"doctype": "Asset Maintenance Team",
"maintenance_manager": "marcus@abc.com",
"maintenance_team_name": "Team Awesome",
"company": "_Test Company",
"maintenance_team_members": get_maintenance_team(user_list),
}
).insert()
def get_maintenance_team(user_list):
return [{"team_member": user,
"full_name": user,
"maintenance_role": "Technician"
}
for user in user_list[1:]]
return [
{"team_member": user, "full_name": user, "maintenance_role": "Technician"}
for user in user_list[1:]
]
def get_maintenance_tasks():
return [{"maintenance_task": "Change Oil",
return [
{
"maintenance_task": "Change Oil",
"start_date": nowdate(),
"periodicity": "Monthly",
"maintenance_type": "Preventive Maintenance",
"maintenance_status": "Planned",
"assign_to": "marcus@abc.com"
},
{"maintenance_task": "Check Gears",
"assign_to": "marcus@abc.com",
},
{
"maintenance_task": "Check Gears",
"start_date": nowdate(),
"periodicity": "Yearly",
"maintenance_type": "Calibration",
"maintenance_status": "Planned",
"assign_to": "thalia@abc.com"
}
]
"assign_to": "thalia@abc.com",
},
]
def create_asset_category():
asset_category = frappe.new_doc("Asset Category")
asset_category.asset_category_name = "Equipment"
asset_category.total_number_of_depreciations = 3
asset_category.frequency_of_depreciation = 3
asset_category.append("accounts", {
"company_name": "_Test Company",
"fixed_asset_account": "_Test Fixed Asset - _TC",
"accumulated_depreciation_account": "_Test Accumulated Depreciations - _TC",
"depreciation_expense_account": "_Test Depreciations - _TC"
})
asset_category.append(
"accounts",
{
"company_name": "_Test Company",
"fixed_asset_account": "_Test Fixed Asset - _TC",
"accumulated_depreciation_account": "_Test Accumulated Depreciations - _TC",
"depreciation_expense_account": "_Test Depreciations - _TC",
},
)
asset_category.insert()
def set_depreciation_settings_in_company():
company = frappe.get_doc("Company", "_Test Company")
company.accumulated_depreciation_account = "_Test Accumulated Depreciations - _TC"

View File

@@ -12,7 +12,10 @@ from erpnext.assets.doctype.asset_maintenance.asset_maintenance import calculate
class AssetMaintenanceLog(Document):
def validate(self):
if getdate(self.due_date) < getdate(nowdate()) and self.maintenance_status not in ["Completed", "Cancelled"]:
if getdate(self.due_date) < getdate(nowdate()) and self.maintenance_status not in [
"Completed",
"Cancelled",
]:
self.maintenance_status = "Overdue"
if self.maintenance_status == "Completed" and not self.completion_date:
@@ -22,15 +25,17 @@ class AssetMaintenanceLog(Document):
frappe.throw(_("Please select Maintenance Status as Completed or remove Completion Date"))
def on_submit(self):
if self.maintenance_status not in ['Completed', 'Cancelled']:
if self.maintenance_status not in ["Completed", "Cancelled"]:
frappe.throw(_("Maintenance Status has to be Cancelled or Completed to Submit"))
self.update_maintenance_task()
def update_maintenance_task(self):
asset_maintenance_doc = frappe.get_doc('Asset Maintenance Task', self.task)
asset_maintenance_doc = frappe.get_doc("Asset Maintenance Task", self.task)
if self.maintenance_status == "Completed":
if asset_maintenance_doc.last_completion_date != self.completion_date:
next_due_date = calculate_next_due_date(periodicity = self.periodicity, last_completion_date = self.completion_date)
next_due_date = calculate_next_due_date(
periodicity=self.periodicity, last_completion_date=self.completion_date
)
asset_maintenance_doc.last_completion_date = self.completion_date
asset_maintenance_doc.next_due_date = next_due_date
asset_maintenance_doc.maintenance_status = "Planned"
@@ -38,11 +43,14 @@ class AssetMaintenanceLog(Document):
if self.maintenance_status == "Cancelled":
asset_maintenance_doc.maintenance_status = "Cancelled"
asset_maintenance_doc.save()
asset_maintenance_doc = frappe.get_doc('Asset Maintenance', self.asset_maintenance)
asset_maintenance_doc = frappe.get_doc("Asset Maintenance", self.asset_maintenance)
asset_maintenance_doc.save()
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_maintenance_tasks(doctype, txt, searchfield, start, page_len, filters):
asset_maintenance_tasks = frappe.db.get_values('Asset Maintenance Task', {'parent':filters.get("asset_maintenance")}, 'maintenance_task')
asset_maintenance_tasks = frappe.db.get_values(
"Asset Maintenance Task", {"parent": filters.get("asset_maintenance")}, "maintenance_task"
)
return asset_maintenance_tasks

View File

@@ -16,7 +16,7 @@ class AssetMovement(Document):
def validate_asset(self):
for d in self.assets:
status, company = frappe.db.get_value("Asset", d.asset, ["status", "company"])
if self.purpose == 'Transfer' and status in ("Draft", "Scrapped", "Sold"):
if self.purpose == "Transfer" and status in ("Draft", "Scrapped", "Sold"):
frappe.throw(_("{0} asset cannot be transferred").format(status))
if company != self.company:
@@ -27,7 +27,7 @@ class AssetMovement(Document):
def validate_location(self):
for d in self.assets:
if self.purpose in ['Transfer', 'Issue']:
if self.purpose in ["Transfer", "Issue"]:
if not d.source_location:
d.source_location = frappe.db.get_value("Asset", d.asset, "location")
@@ -38,52 +38,76 @@ class AssetMovement(Document):
current_location = frappe.db.get_value("Asset", d.asset, "location")
if current_location != d.source_location:
frappe.throw(_("Asset {0} does not belongs to the location {1}").
format(d.asset, d.source_location))
frappe.throw(
_("Asset {0} does not belongs to the location {1}").format(d.asset, d.source_location)
)
if self.purpose == 'Issue':
if self.purpose == "Issue":
if d.target_location:
frappe.throw(_("Issuing cannot be done to a location. \
Please enter employee who has issued Asset {0}").format(d.asset), title="Incorrect Movement Purpose")
frappe.throw(
_(
"Issuing cannot be done to a location. \
Please enter employee who has issued Asset {0}"
).format(d.asset),
title="Incorrect Movement Purpose",
)
if not d.to_employee:
frappe.throw(_("Employee is required while issuing Asset {0}").format(d.asset))
if self.purpose == 'Transfer':
if self.purpose == "Transfer":
if d.to_employee:
frappe.throw(_("Transferring cannot be done to an Employee. \
Please enter location where Asset {0} has to be transferred").format(
d.asset), title="Incorrect Movement Purpose")
frappe.throw(
_(
"Transferring cannot be done to an Employee. \
Please enter location where Asset {0} has to be transferred"
).format(d.asset),
title="Incorrect Movement Purpose",
)
if not d.target_location:
frappe.throw(_("Target Location is required while transferring Asset {0}").format(d.asset))
if d.source_location == d.target_location:
frappe.throw(_("Source and Target Location cannot be same"))
if self.purpose == 'Receipt':
if self.purpose == "Receipt":
# only when asset is bought and first entry is made
if not d.source_location and not (d.target_location or d.to_employee):
frappe.throw(_("Target Location or To Employee is required while receiving Asset {0}").format(d.asset))
frappe.throw(
_("Target Location or To Employee is required while receiving Asset {0}").format(d.asset)
)
elif d.source_location:
# when asset is received from an employee
if d.target_location and not d.from_employee:
frappe.throw(_("From employee is required while receiving Asset {0} to a target location").format(d.asset))
frappe.throw(
_("From employee is required while receiving Asset {0} to a target location").format(
d.asset
)
)
if d.from_employee and not d.target_location:
frappe.throw(_("Target Location is required while receiving Asset {0} from an employee").format(d.asset))
frappe.throw(
_("Target Location is required while receiving Asset {0} from an employee").format(d.asset)
)
if d.to_employee and d.target_location:
frappe.throw(_("Asset {0} cannot be received at a location and \
given to employee in a single movement").format(d.asset))
frappe.throw(
_(
"Asset {0} cannot be received at a location and \
given to employee in a single movement"
).format(d.asset)
)
def validate_employee(self):
for d in self.assets:
if d.from_employee:
current_custodian = frappe.db.get_value("Asset", d.asset, "custodian")
current_custodian = frappe.db.get_value("Asset", d.asset, "custodian")
if current_custodian != d.from_employee:
frappe.throw(_("Asset {0} does not belongs to the custodian {1}").
format(d.asset, d.from_employee))
if current_custodian != d.from_employee:
frappe.throw(
_("Asset {0} does not belongs to the custodian {1}").format(d.asset, d.from_employee)
)
if d.to_employee and frappe.db.get_value("Employee", d.to_employee, "company") != self.company:
frappe.throw(_("Employee {0} does not belongs to the company {1}").
format(d.to_employee, self.company))
frappe.throw(
_("Employee {0} does not belongs to the company {1}").format(d.to_employee, self.company)
)
def on_submit(self):
self.set_latest_location_in_asset()
@@ -92,14 +116,11 @@ class AssetMovement(Document):
self.set_latest_location_in_asset()
def set_latest_location_in_asset(self):
current_location, current_employee = '', ''
current_location, current_employee = "", ""
cond = "1=1"
for d in self.assets:
args = {
'asset': d.asset,
'company': self.company
}
args = {"asset": d.asset, "company": self.company}
# latest entry corresponds to current document's location, employee when transaction date > previous dates
# In case of cancellation it corresponds to previous latest document's location, employee
@@ -114,10 +135,14 @@ class AssetMovement(Document):
asm.docstatus=1 and {0}
ORDER BY
asm.transaction_date desc limit 1
""".format(cond), args)
""".format(
cond
),
args,
)
if latest_movement_entry:
current_location = latest_movement_entry[0][0]
current_employee = latest_movement_entry[0][1]
frappe.db.set_value('Asset', d.asset, 'location', current_location)
frappe.db.set_value('Asset', d.asset, 'custodian', current_employee)
frappe.db.set_value("Asset", d.asset, "location", current_location)
frappe.db.set_value("Asset", d.asset, "custodian", current_employee)

View File

@@ -13,95 +13,122 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_pu
class TestAssetMovement(unittest.TestCase):
def setUp(self):
frappe.db.set_value("Company", "_Test Company", "capital_work_in_progress_account", "CWIP Account - _TC")
frappe.db.set_value(
"Company", "_Test Company", "capital_work_in_progress_account", "CWIP Account - _TC"
)
create_asset_data()
make_location()
def test_movement(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)
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, "name")
asset = frappe.get_doc("Asset", asset_name)
asset.calculate_depreciation = 1
asset.available_for_use_date = '2020-06-06'
asset.purchase_date = '2020-06-06'
asset.append("finance_books", {
"expected_value_after_useful_life": 10000,
"next_depreciation_date": "2020-12-31",
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
"frequency_of_depreciation": 10
})
asset.available_for_use_date = "2020-06-06"
asset.purchase_date = "2020-06-06"
asset.append(
"finance_books",
{
"expected_value_after_useful_life": 10000,
"next_depreciation_date": "2020-12-31",
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
"frequency_of_depreciation": 10,
},
)
if asset.docstatus == 0:
asset.submit()
# check asset movement is created
if not frappe.db.exists("Location", "Test Location 2"):
frappe.get_doc({
'doctype': 'Location',
'location_name': 'Test Location 2'
}).insert()
frappe.get_doc({"doctype": "Location", "location_name": "Test Location 2"}).insert()
movement1 = create_asset_movement(purpose = 'Transfer', company = asset.company,
assets = [{ 'asset': asset.name , 'source_location': 'Test Location', 'target_location': 'Test Location 2'}],
reference_doctype = 'Purchase Receipt', reference_name = pr.name)
movement1 = create_asset_movement(
purpose="Transfer",
company=asset.company,
assets=[
{"asset": asset.name, "source_location": "Test Location", "target_location": "Test Location 2"}
],
reference_doctype="Purchase Receipt",
reference_name=pr.name,
)
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location 2")
create_asset_movement(purpose = 'Transfer', company = asset.company,
assets = [{ 'asset': asset.name , 'source_location': 'Test Location 2', 'target_location': 'Test Location'}],
reference_doctype = 'Purchase Receipt', reference_name = pr.name)
create_asset_movement(
purpose="Transfer",
company=asset.company,
assets=[
{"asset": asset.name, "source_location": "Test Location 2", "target_location": "Test Location"}
],
reference_doctype="Purchase Receipt",
reference_name=pr.name,
)
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
movement1.cancel()
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
employee = make_employee("testassetmovemp@example.com", company="_Test Company")
create_asset_movement(purpose = 'Issue', company = asset.company,
assets = [{ 'asset': asset.name , 'source_location': 'Test Location', 'to_employee': employee}],
reference_doctype = 'Purchase Receipt', reference_name = pr.name)
create_asset_movement(
purpose="Issue",
company=asset.company,
assets=[{"asset": asset.name, "source_location": "Test Location", "to_employee": employee}],
reference_doctype="Purchase Receipt",
reference_name=pr.name,
)
# after issuing asset should belong to an employee not at a location
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), None)
self.assertEqual(frappe.db.get_value("Asset", asset.name, "custodian"), employee)
def test_last_movement_cancellation(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)
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, "name")
asset = frappe.get_doc("Asset", asset_name)
asset.calculate_depreciation = 1
asset.available_for_use_date = '2020-06-06'
asset.purchase_date = '2020-06-06'
asset.append("finance_books", {
"expected_value_after_useful_life": 10000,
"next_depreciation_date": "2020-12-31",
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
"frequency_of_depreciation": 10
})
asset.available_for_use_date = "2020-06-06"
asset.purchase_date = "2020-06-06"
asset.append(
"finance_books",
{
"expected_value_after_useful_life": 10000,
"next_depreciation_date": "2020-12-31",
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
"frequency_of_depreciation": 10,
},
)
if asset.docstatus == 0:
asset.submit()
if not frappe.db.exists("Location", "Test Location 2"):
frappe.get_doc({
'doctype': 'Location',
'location_name': 'Test Location 2'
}).insert()
frappe.get_doc({"doctype": "Location", "location_name": "Test Location 2"}).insert()
movement = frappe.get_doc({'doctype': 'Asset Movement', 'reference_name': pr.name })
movement = frappe.get_doc({"doctype": "Asset Movement", "reference_name": pr.name})
self.assertRaises(frappe.ValidationError, movement.cancel)
movement1 = create_asset_movement(purpose = 'Transfer', company = asset.company,
assets = [{ 'asset': asset.name , 'source_location': 'Test Location', 'target_location': 'Test Location 2'}],
reference_doctype = 'Purchase Receipt', reference_name = pr.name)
movement1 = create_asset_movement(
purpose="Transfer",
company=asset.company,
assets=[
{"asset": asset.name, "source_location": "Test Location", "target_location": "Test Location 2"}
],
reference_doctype="Purchase Receipt",
reference_name=pr.name,
)
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location 2")
movement1.cancel()
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
def create_asset_movement(**args):
args = frappe._dict(args)
@@ -109,24 +136,26 @@ def create_asset_movement(**args):
args.transaction_date = now()
movement = frappe.new_doc("Asset Movement")
movement.update({
"assets": args.assets,
"transaction_date": args.transaction_date,
"company": args.company,
'purpose': args.purpose or 'Receipt',
'reference_doctype': args.reference_doctype,
'reference_name': args.reference_name
})
movement.update(
{
"assets": args.assets,
"transaction_date": args.transaction_date,
"company": args.company,
"purpose": args.purpose or "Receipt",
"reference_doctype": args.reference_doctype,
"reference_name": args.reference_name,
}
)
movement.insert()
movement.submit()
return movement
def make_location():
for location in ['Pune', 'Mumbai', 'Nagpur']:
if not frappe.db.exists('Location', location):
frappe.get_doc({
'doctype': 'Location',
'location_name': location
}).insert(ignore_permissions = True)
for location in ["Pune", "Mumbai", "Nagpur"]:
if not frappe.db.exists("Location", location):
frappe.get_doc({"doctype": "Location", "location_name": location}).insert(
ignore_permissions=True
)

View File

@@ -13,21 +13,21 @@ from erpnext.controllers.accounts_controller import AccountsController
class AssetRepair(AccountsController):
def validate(self):
self.asset_doc = frappe.get_doc('Asset', self.asset)
self.asset_doc = frappe.get_doc("Asset", self.asset)
self.update_status()
if self.get('stock_items'):
if self.get("stock_items"):
self.set_total_value()
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')
if self.repair_status == "Pending":
frappe.db.set_value("Asset", self.asset, "status", "Out of Order")
else:
self.asset_doc.set_status()
def set_total_value(self):
for item in self.get('stock_items'):
for item in self.get("stock_items"):
item.total_value = flt(item.valuation_rate) * flt(item.consumed_quantity)
def calculate_total_repair_cost(self):
@@ -39,14 +39,17 @@ class AssetRepair(AccountsController):
def before_submit(self):
self.check_repair_status()
if self.get('stock_consumption') or self.get('capitalize_repair_cost'):
if self.get("stock_consumption") or self.get("capitalize_repair_cost"):
self.increase_asset_value()
if self.get('stock_consumption'):
if self.get("stock_consumption"):
self.check_for_stock_items_and_warehouse()
self.decrease_stock_quantity()
if self.get('capitalize_repair_cost'):
if self.get("capitalize_repair_cost"):
self.make_gl_entries()
if frappe.db.get_value('Asset', self.asset, 'calculate_depreciation') and self.increase_in_asset_life:
if (
frappe.db.get_value("Asset", self.asset, "calculate_depreciation")
and self.increase_in_asset_life
):
self.modify_depreciation_schedule()
self.asset_doc.flags.ignore_validate_update_after_submit = True
@@ -54,16 +57,19 @@ class AssetRepair(AccountsController):
self.asset_doc.save()
def before_cancel(self):
self.asset_doc = frappe.get_doc('Asset', self.asset)
self.asset_doc = frappe.get_doc("Asset", self.asset)
if self.get('stock_consumption') or self.get('capitalize_repair_cost'):
if self.get("stock_consumption") or self.get("capitalize_repair_cost"):
self.decrease_asset_value()
if self.get('stock_consumption'):
if self.get("stock_consumption"):
self.increase_stock_quantity()
if self.get('capitalize_repair_cost'):
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
if self.get("capitalize_repair_cost"):
self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry")
self.make_gl_entries(cancel=True)
if frappe.db.get_value('Asset', self.asset, 'calculate_depreciation') and self.increase_in_asset_life:
if (
frappe.db.get_value("Asset", self.asset, "calculate_depreciation")
and self.increase_in_asset_life
):
self.revert_depreciation_schedule_on_cancellation()
self.asset_doc.flags.ignore_validate_update_after_submit = True
@@ -75,10 +81,15 @@ class AssetRepair(AccountsController):
frappe.throw(_("Please update Repair Status."))
def check_for_stock_items_and_warehouse(self):
if not self.get('stock_items'):
frappe.throw(_("Please enter Stock Items consumed during the Repair."), title=_("Missing Items"))
if not self.get("stock_items"):
frappe.throw(
_("Please enter Stock Items consumed during the Repair."), title=_("Missing Items")
)
if not self.warehouse:
frappe.throw(_("Please enter Warehouse from which Stock Items consumed during the Repair were taken."), title=_("Missing Warehouse"))
frappe.throw(
_("Please enter Warehouse from which Stock Items consumed during the Repair were taken."),
title=_("Missing Warehouse"),
)
def increase_asset_value(self):
total_value_of_stock_consumed = self.get_total_value_of_stock_consumed()
@@ -102,35 +113,36 @@ class AssetRepair(AccountsController):
def get_total_value_of_stock_consumed(self):
total_value_of_stock_consumed = 0
if self.get('stock_consumption'):
for item in self.get('stock_items'):
if self.get("stock_consumption"):
for item in self.get("stock_items"):
total_value_of_stock_consumed += item.total_value
return total_value_of_stock_consumed
def decrease_stock_quantity(self):
stock_entry = frappe.get_doc({
"doctype": "Stock Entry",
"stock_entry_type": "Material Issue",
"company": self.company
})
stock_entry = frappe.get_doc(
{"doctype": "Stock Entry", "stock_entry_type": "Material Issue", "company": self.company}
)
for stock_item in self.get('stock_items'):
stock_entry.append('items', {
"s_warehouse": self.warehouse,
"item_code": stock_item.item_code,
"qty": stock_item.consumed_quantity,
"basic_rate": stock_item.valuation_rate,
"serial_no": stock_item.serial_no
})
for stock_item in self.get("stock_items"):
stock_entry.append(
"items",
{
"s_warehouse": self.warehouse,
"item_code": stock_item.item_code,
"qty": stock_item.consumed_quantity,
"basic_rate": stock_item.valuation_rate,
"serial_no": stock_item.serial_no,
},
)
stock_entry.insert()
stock_entry.submit()
self.db_set('stock_entry', stock_entry.name)
self.db_set("stock_entry", stock_entry.name)
def increase_stock_quantity(self):
stock_entry = frappe.get_doc('Stock Entry', self.stock_entry)
stock_entry = frappe.get_doc("Stock Entry", self.stock_entry)
stock_entry.flags.ignore_links = True
stock_entry.cancel()
@@ -141,63 +153,78 @@ class AssetRepair(AccountsController):
def get_gl_entries(self):
gl_entries = []
repair_and_maintenance_account = frappe.db.get_value('Company', self.company, 'repair_and_maintenance_account')
fixed_asset_account = get_asset_account("fixed_asset_account", asset=self.asset, company=self.company)
expense_account = frappe.get_doc('Purchase Invoice', self.purchase_invoice).items[0].expense_account
gl_entries.append(
self.get_gl_dict({
"account": expense_account,
"credit": self.repair_cost,
"credit_in_account_currency": self.repair_cost,
"against": repair_and_maintenance_account,
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
"posting_date": getdate(),
"company": self.company
}, item=self)
repair_and_maintenance_account = frappe.db.get_value(
"Company", self.company, "repair_and_maintenance_account"
)
fixed_asset_account = get_asset_account(
"fixed_asset_account", asset=self.asset, company=self.company
)
expense_account = (
frappe.get_doc("Purchase Invoice", self.purchase_invoice).items[0].expense_account
)
if self.get('stock_consumption'):
gl_entries.append(
self.get_gl_dict(
{
"account": expense_account,
"credit": self.repair_cost,
"credit_in_account_currency": self.repair_cost,
"against": repair_and_maintenance_account,
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
"posting_date": getdate(),
"company": self.company,
},
item=self,
)
)
if self.get("stock_consumption"):
# creating GL Entries for each row in Stock Items based on the Stock Entry created for it
stock_entry = frappe.get_doc('Stock Entry', self.stock_entry)
stock_entry = frappe.get_doc("Stock Entry", self.stock_entry)
for item in stock_entry.items:
gl_entries.append(
self.get_gl_dict({
"account": item.expense_account,
"credit": item.amount,
"credit_in_account_currency": item.amount,
"against": repair_and_maintenance_account,
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
"posting_date": getdate(),
"company": self.company
}, item=self)
self.get_gl_dict(
{
"account": item.expense_account,
"credit": item.amount,
"credit_in_account_currency": item.amount,
"against": repair_and_maintenance_account,
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
"posting_date": getdate(),
"company": self.company,
},
item=self,
)
)
gl_entries.append(
self.get_gl_dict({
"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,
"company": self.company
}, item=self)
self.get_gl_dict(
{
"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,
"company": self.company,
},
item=self,
)
)
return gl_entries
def modify_depreciation_schedule(self):
for row in self.asset_doc.finance_books:
row.total_number_of_depreciations += self.increase_in_asset_life/row.frequency_of_depreciation
row.total_number_of_depreciations += self.increase_in_asset_life / row.frequency_of_depreciation
self.asset_doc.flags.increase_in_asset_life = False
extra_months = self.increase_in_asset_life % row.frequency_of_depreciation
@@ -207,26 +234,29 @@ class AssetRepair(AccountsController):
# 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.flags.increase_in_asset_life = True
number_of_pending_depreciations = cint(row.total_number_of_depreciations) - \
cint(asset.number_of_depreciations_booked)
number_of_pending_depreciations = cint(row.total_number_of_depreciations) - cint(
asset.number_of_depreciations_booked
)
# the Schedule Date in the final row of the old Depreciation Schedule
last_schedule_date = asset.schedules[len(asset.schedules)-1].schedule_date
last_schedule_date = asset.schedules[len(asset.schedules) - 1].schedule_date
# the Schedule Date in the final row of the new Depreciation Schedule
asset.to_date = add_months(last_schedule_date, extra_months)
# the latest possible date at which the depreciation can occur, without increasing the Total Number of Depreciations
# if depreciations happen yearly and the Depreciation Posting Date is 01-01-2020, this could be 01-01-2021, 01-01-2022...
schedule_date = add_months(row.depreciation_start_date,
number_of_pending_depreciations * cint(row.frequency_of_depreciation))
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
def revert_depreciation_schedule_on_cancellation(self):
for row in self.asset_doc.finance_books:
row.total_number_of_depreciations -= self.increase_in_asset_life/row.frequency_of_depreciation
row.total_number_of_depreciations -= self.increase_in_asset_life / row.frequency_of_depreciation
self.asset_doc.flags.increase_in_asset_life = False
extra_months = self.increase_in_asset_life % row.frequency_of_depreciation
@@ -235,23 +265,27 @@ class AssetRepair(AccountsController):
def calculate_last_schedule_date_before_modification(self, asset, row, extra_months):
asset.flags.increase_in_asset_life = True
number_of_pending_depreciations = cint(row.total_number_of_depreciations) - \
cint(asset.number_of_depreciations_booked)
number_of_pending_depreciations = cint(row.total_number_of_depreciations) - cint(
asset.number_of_depreciations_booked
)
# the Schedule Date in the final row of the modified Depreciation Schedule
last_schedule_date = asset.schedules[len(asset.schedules)-1].schedule_date
last_schedule_date = asset.schedules[len(asset.schedules) - 1].schedule_date
# the Schedule Date in the final row of the original Depreciation Schedule
asset.to_date = add_months(last_schedule_date, -extra_months)
# the latest possible date at which the depreciation can occur, without decreasing the Total Number of Depreciations
# if depreciations happen yearly and the Depreciation Posting Date is 01-01-2020, this could be 01-01-2021, 01-01-2022...
schedule_date = add_months(row.depreciation_start_date,
(number_of_pending_depreciations - 1) * cint(row.frequency_of_depreciation))
schedule_date = add_months(
row.depreciation_start_date,
(number_of_pending_depreciations - 1) * 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

@@ -25,7 +25,7 @@ class TestAssetRepair(unittest.TestCase):
def test_update_status(self):
asset = create_asset(submit=1)
initial_status = asset.status
asset_repair = create_asset_repair(asset = asset)
asset_repair = create_asset_repair(asset=asset)
if asset_repair.repair_status == "Pending":
asset.reload()
@@ -37,14 +37,14 @@ class TestAssetRepair(unittest.TestCase):
self.assertEqual(asset_status, initial_status)
def test_stock_item_total_value(self):
asset_repair = create_asset_repair(stock_consumption = 1)
asset_repair = create_asset_repair(stock_consumption=1)
for item in asset_repair.stock_items:
total_value = flt(item.valuation_rate) * flt(item.consumed_quantity)
self.assertEqual(item.total_value, total_value)
def test_total_repair_cost(self):
asset_repair = create_asset_repair(stock_consumption = 1)
asset_repair = create_asset_repair(stock_consumption=1)
total_repair_cost = asset_repair.repair_cost
self.assertEqual(total_repair_cost, asset_repair.repair_cost)
@@ -54,22 +54,22 @@ class TestAssetRepair(unittest.TestCase):
self.assertEqual(total_repair_cost, asset_repair.total_repair_cost)
def test_repair_status_after_submit(self):
asset_repair = create_asset_repair(submit = 1)
asset_repair = create_asset_repair(submit=1)
self.assertNotEqual(asset_repair.repair_status, "Pending")
def test_stock_items(self):
asset_repair = create_asset_repair(stock_consumption = 1)
asset_repair = create_asset_repair(stock_consumption=1)
self.assertTrue(asset_repair.stock_consumption)
self.assertTrue(asset_repair.stock_items)
def test_warehouse(self):
asset_repair = create_asset_repair(stock_consumption = 1)
asset_repair = create_asset_repair(stock_consumption=1)
self.assertTrue(asset_repair.stock_consumption)
self.assertTrue(asset_repair.warehouse)
def test_decrease_stock_quantity(self):
asset_repair = create_asset_repair(stock_consumption = 1, submit = 1)
stock_entry = frappe.get_last_doc('Stock Entry')
asset_repair = create_asset_repair(stock_consumption=1, submit=1)
stock_entry = frappe.get_last_doc("Stock Entry")
self.assertEqual(stock_entry.stock_entry_type, "Material Issue")
self.assertEqual(stock_entry.items[0].s_warehouse, asset_repair.warehouse)
@@ -85,58 +85,72 @@ class TestAssetRepair(unittest.TestCase):
serial_no = serial_nos.split("\n")[0]
# should not raise any error
create_asset_repair(stock_consumption = 1, item_code = stock_entry.get("items")[0].item_code,
warehouse = "_Test Warehouse - _TC", serial_no = serial_no, submit = 1)
create_asset_repair(
stock_consumption=1,
item_code=stock_entry.get("items")[0].item_code,
warehouse="_Test Warehouse - _TC",
serial_no=serial_no,
submit=1,
)
# should raise error
asset_repair = create_asset_repair(stock_consumption = 1, warehouse = "_Test Warehouse - _TC",
item_code = stock_entry.get("items")[0].item_code)
asset_repair = create_asset_repair(
stock_consumption=1,
warehouse="_Test Warehouse - _TC",
item_code=stock_entry.get("items")[0].item_code,
)
asset_repair.repair_status = "Completed"
self.assertRaises(SerialNoRequiredError, asset_repair.submit)
def test_increase_in_asset_value_due_to_stock_consumption(self):
asset = create_asset(calculate_depreciation = 1, submit=1)
asset = create_asset(calculate_depreciation=1, submit=1)
initial_asset_value = get_asset_value(asset)
asset_repair = create_asset_repair(asset= asset, stock_consumption = 1, submit = 1)
asset_repair = create_asset_repair(asset=asset, stock_consumption=1, submit=1)
asset.reload()
increase_in_asset_value = get_asset_value(asset) - initial_asset_value
self.assertEqual(asset_repair.stock_items[0].total_value, increase_in_asset_value)
def test_increase_in_asset_value_due_to_repair_cost_capitalisation(self):
asset = create_asset(calculate_depreciation = 1, submit=1)
asset = create_asset(calculate_depreciation=1, submit=1)
initial_asset_value = get_asset_value(asset)
asset_repair = create_asset_repair(asset= asset, capitalize_repair_cost = 1, submit = 1)
asset_repair = create_asset_repair(asset=asset, capitalize_repair_cost=1, submit=1)
asset.reload()
increase_in_asset_value = get_asset_value(asset) - initial_asset_value
self.assertEqual(asset_repair.repair_cost, increase_in_asset_value)
def test_purchase_invoice(self):
asset_repair = create_asset_repair(capitalize_repair_cost = 1, submit = 1)
asset_repair = create_asset_repair(capitalize_repair_cost=1, submit=1)
self.assertTrue(asset_repair.purchase_invoice)
def test_gl_entries(self):
asset_repair = create_asset_repair(capitalize_repair_cost = 1, submit = 1)
gl_entry = frappe.get_last_doc('GL Entry')
asset_repair = create_asset_repair(capitalize_repair_cost=1, submit=1)
gl_entry = frappe.get_last_doc("GL Entry")
self.assertEqual(asset_repair.name, gl_entry.voucher_no)
def test_increase_in_asset_life(self):
asset = create_asset(calculate_depreciation = 1, submit=1)
asset = create_asset(calculate_depreciation=1, submit=1)
initial_num_of_depreciations = num_of_depreciations(asset)
create_asset_repair(asset= asset, capitalize_repair_cost = 1, submit = 1)
create_asset_repair(asset=asset, capitalize_repair_cost=1, submit=1)
asset.reload()
self.assertEqual((initial_num_of_depreciations + 1), num_of_depreciations(asset))
self.assertEqual(asset.schedules[-1].accumulated_depreciation_amount, asset.finance_books[0].value_after_depreciation)
self.assertEqual(
asset.schedules[-1].accumulated_depreciation_amount,
asset.finance_books[0].value_after_depreciation,
)
def get_asset_value(asset):
return asset.finance_books[0].value_after_depreciation
def num_of_depreciations(asset):
return asset.finance_books[0].total_number_of_depreciations
def create_asset_repair(**args):
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
@@ -146,26 +160,33 @@ def create_asset_repair(**args):
if args.asset:
asset = args.asset
else:
asset = create_asset(is_existing_asset = 1, submit=1)
asset = create_asset(is_existing_asset=1, submit=1)
asset_repair = frappe.new_doc("Asset Repair")
asset_repair.update({
"asset": asset.name,
"asset_name": asset.asset_name,
"failure_date": nowdate(),
"description": "Test Description",
"repair_cost": 0,
"company": asset.company
})
asset_repair.update(
{
"asset": asset.name,
"asset_name": asset.asset_name,
"failure_date": nowdate(),
"description": "Test Description",
"repair_cost": 0,
"company": asset.company,
}
)
if args.stock_consumption:
asset_repair.stock_consumption = 1
asset_repair.warehouse = args.warehouse or create_warehouse("Test Warehouse", company = asset.company)
asset_repair.append("stock_items", {
"item_code": args.item_code or "_Test Stock Item",
"valuation_rate": args.rate if args.get("rate") is not None else 100,
"consumed_quantity": args.qty or 1,
"serial_no": args.serial_no
})
asset_repair.warehouse = args.warehouse or create_warehouse(
"Test Warehouse", company=asset.company
)
asset_repair.append(
"stock_items",
{
"item_code": args.item_code or "_Test Stock Item",
"valuation_rate": args.rate if args.get("rate") is not None else 100,
"consumed_quantity": args.qty or 1,
"serial_no": args.serial_no,
},
)
asset_repair.insert(ignore_if_duplicate=True)
@@ -174,16 +195,17 @@ def create_asset_repair(**args):
asset_repair.cost_center = "_Test Cost Center - _TC"
if args.stock_consumption:
stock_entry = frappe.get_doc({
"doctype": "Stock Entry",
"stock_entry_type": "Material Receipt",
"company": asset.company
})
stock_entry.append('items', {
"t_warehouse": asset_repair.warehouse,
"item_code": asset_repair.stock_items[0].item_code,
"qty": asset_repair.stock_items[0].consumed_quantity
})
stock_entry = frappe.get_doc(
{"doctype": "Stock Entry", "stock_entry_type": "Material Receipt", "company": asset.company}
)
stock_entry.append(
"items",
{
"t_warehouse": asset_repair.warehouse,
"item_code": asset_repair.stock_items[0].item_code,
"qty": asset_repair.stock_items[0].consumed_quantity,
},
)
stock_entry.submit()
if args.capitalize_repair_cost:

View File

@@ -31,10 +31,14 @@ class AssetValueAdjustment(Document):
self.reschedule_depreciations(self.current_asset_value)
def validate_date(self):
asset_purchase_date = frappe.db.get_value('Asset', self.asset, 'purchase_date')
asset_purchase_date = frappe.db.get_value("Asset", self.asset, "purchase_date")
if getdate(self.date) < getdate(asset_purchase_date):
frappe.throw(_("Asset Value Adjustment cannot be posted before Asset's purchase date <b>{0}</b>.")
.format(formatdate(asset_purchase_date)), title="Incorrect Date")
frappe.throw(
_("Asset Value Adjustment cannot be posted before Asset's purchase date <b>{0}</b>.").format(
formatdate(asset_purchase_date)
),
title="Incorrect Date",
)
def set_difference_amount(self):
self.difference_amount = flt(self.current_asset_value - self.new_asset_value)
@@ -45,11 +49,15 @@ class AssetValueAdjustment(Document):
def make_depreciation_entry(self):
asset = frappe.get_doc("Asset", self.asset)
fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account = \
get_depreciation_accounts(asset)
(
fixed_asset_account,
accumulated_depreciation_account,
depreciation_expense_account,
) = get_depreciation_accounts(asset)
depreciation_cost_center, depreciation_series = frappe.get_cached_value('Company', asset.company,
["depreciation_cost_center", "series_for_depreciation_entry"])
depreciation_cost_center, depreciation_series = frappe.get_cached_value(
"Company", asset.company, ["depreciation_cost_center", "series_for_depreciation_entry"]
)
je = frappe.new_doc("Journal Entry")
je.voucher_type = "Depreciation Entry"
@@ -62,27 +70,33 @@ class AssetValueAdjustment(Document):
credit_entry = {
"account": accumulated_depreciation_account,
"credit_in_account_currency": self.difference_amount,
"cost_center": depreciation_cost_center or self.cost_center
"cost_center": depreciation_cost_center or self.cost_center,
}
debit_entry = {
"account": depreciation_expense_account,
"debit_in_account_currency": self.difference_amount,
"cost_center": depreciation_cost_center or self.cost_center
"cost_center": depreciation_cost_center or self.cost_center,
}
accounting_dimensions = get_checks_for_pl_and_bs_accounts()
for dimension in accounting_dimensions:
if dimension.get('mandatory_for_bs'):
credit_entry.update({
dimension['fieldname']: self.get(dimension['fieldname']) or dimension.get('default_dimension')
})
if dimension.get("mandatory_for_bs"):
credit_entry.update(
{
dimension["fieldname"]: self.get(dimension["fieldname"])
or dimension.get("default_dimension")
}
)
if dimension.get('mandatory_for_pl'):
debit_entry.update({
dimension['fieldname']: self.get(dimension['fieldname']) or dimension.get('default_dimension')
})
if dimension.get("mandatory_for_pl"):
debit_entry.update(
{
dimension["fieldname"]: self.get(dimension["fieldname"])
or dimension.get("default_dimension")
}
)
je.append("accounts", credit_entry)
je.append("accounts", debit_entry)
@@ -93,8 +107,8 @@ class AssetValueAdjustment(Document):
self.db_set("journal_entry", je.name)
def reschedule_depreciations(self, asset_value):
asset = frappe.get_doc('Asset', self.asset)
country = frappe.get_value('Company', self.company, 'country')
asset = frappe.get_doc("Asset", self.asset)
country = frappe.get_value("Company", self.company, "country")
for d in asset.finance_books:
d.value_after_depreciation = asset_value
@@ -105,8 +119,11 @@ class AssetValueAdjustment(Document):
rate_per_day = flt(d.value_after_depreciation) / flt(total_days)
from_date = self.date
else:
no_of_depreciations = len([s.name for s in asset.schedules
if (cint(s.finance_book_id) == d.idx and not s.journal_entry)])
no_of_depreciations = len(
[
s.name for s in asset.schedules if (cint(s.finance_book_id) == d.idx and not s.journal_entry)
]
)
value_after_depreciation = d.value_after_depreciation
for data in asset.schedules:
@@ -132,10 +149,11 @@ class AssetValueAdjustment(Document):
if not asset_data.journal_entry:
asset_data.db_update()
@frappe.whitelist()
def get_current_asset_value(asset, finance_book=None):
cond = {'parent': asset, 'parenttype': 'Asset'}
cond = {"parent": asset, "parenttype": "Asset"}
if finance_book:
cond.update({'finance_book': finance_book})
cond.update({"finance_book": finance_book})
return frappe.db.get_value('Asset Finance Book', cond, 'value_after_depreciation')
return frappe.db.get_value("Asset Finance Book", cond, "value_after_depreciation")

View File

@@ -18,11 +18,12 @@ class TestAssetValueAdjustment(unittest.TestCase):
create_asset_data()
def test_current_asset_value(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_doc = frappe.get_doc('Asset', asset_name)
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, "name")
asset_doc = frappe.get_doc("Asset", asset_name)
month_end_date = get_last_day(nowdate())
purchase_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15)
@@ -30,24 +31,28 @@ class TestAssetValueAdjustment(unittest.TestCase):
asset_doc.available_for_use_date = purchase_date
asset_doc.purchase_date = purchase_date
asset_doc.calculate_depreciation = 1
asset_doc.append("finance_books", {
"expected_value_after_useful_life": 200,
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
"frequency_of_depreciation": 10,
"depreciation_start_date": month_end_date
})
asset_doc.append(
"finance_books",
{
"expected_value_after_useful_life": 200,
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
"frequency_of_depreciation": 10,
"depreciation_start_date": month_end_date,
},
)
asset_doc.submit()
current_value = get_current_asset_value(asset_doc.name)
self.assertEqual(current_value, 100000.0)
def test_asset_depreciation_value_adjustment(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_doc = frappe.get_doc('Asset', asset_name)
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, "name")
asset_doc = frappe.get_doc("Asset", asset_name)
asset_doc.calculate_depreciation = 1
month_end_date = get_last_day(nowdate())
@@ -56,42 +61,52 @@ class TestAssetValueAdjustment(unittest.TestCase):
asset_doc.available_for_use_date = purchase_date
asset_doc.purchase_date = purchase_date
asset_doc.calculate_depreciation = 1
asset_doc.append("finance_books", {
"expected_value_after_useful_life": 200,
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
"frequency_of_depreciation": 10,
"depreciation_start_date": month_end_date
})
asset_doc.append(
"finance_books",
{
"expected_value_after_useful_life": 200,
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
"frequency_of_depreciation": 10,
"depreciation_start_date": month_end_date,
},
)
asset_doc.submit()
current_value = get_current_asset_value(asset_doc.name)
adj_doc = make_asset_value_adjustment(asset = asset_doc.name,
current_asset_value = current_value, new_asset_value = 50000.0)
adj_doc = make_asset_value_adjustment(
asset=asset_doc.name, current_asset_value=current_value, new_asset_value=50000.0
)
adj_doc.submit()
expected_gle = (
("_Test Accumulated Depreciations - _TC", 0.0, 50000.0),
("_Test Depreciations - _TC", 50000.0, 0.0)
("_Test Depreciations - _TC", 50000.0, 0.0),
)
gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
gle = frappe.db.sql(
"""select account, debit, credit from `tabGL Entry`
where voucher_type='Journal Entry' and voucher_no = %s
order by account""", adj_doc.journal_entry)
order by account""",
adj_doc.journal_entry,
)
self.assertEqual(gle, expected_gle)
def make_asset_value_adjustment(**args):
args = frappe._dict(args)
doc = frappe.get_doc({
"doctype": "Asset Value Adjustment",
"company": args.company or "_Test Company",
"asset": args.asset,
"date": args.date or nowdate(),
"new_asset_value": args.new_asset_value,
"current_asset_value": args.current_asset_value,
"cost_center": args.cost_center or "Main - _TC"
}).insert()
doc = frappe.get_doc(
{
"doctype": "Asset Value Adjustment",
"company": args.company or "_Test Company",
"asset": args.asset,
"date": args.date or nowdate(),
"new_asset_value": args.new_asset_value,
"current_asset_value": args.current_asset_value,
"cost_center": args.cost_center or "Main - _TC",
}
).insert()
return doc

View File

@@ -13,12 +13,12 @@ EARTH_RADIUS = 6378137
class Location(NestedSet):
nsm_parent_field = 'parent_location'
nsm_parent_field = "parent_location"
def validate(self):
self.calculate_location_area()
if not self.is_new() and self.get('parent_location'):
if not self.is_new() and self.get("parent_location"):
self.update_ancestor_location_features()
def on_update(self):
@@ -42,7 +42,7 @@ class Location(NestedSet):
if not self.location:
return []
features = json.loads(self.location).get('features')
features = json.loads(self.location).get("features")
if not isinstance(features, list):
features = json.loads(features)
@@ -54,15 +54,15 @@ class Location(NestedSet):
self.location = '{"type":"FeatureCollection","features":[]}'
location = json.loads(self.location)
location['features'] = features
location["features"] = features
self.db_set('location', json.dumps(location), commit=True)
self.db_set("location", json.dumps(location), commit=True)
def update_ancestor_location_features(self):
self_features = set(self.add_child_property())
for ancestor in self.get_ancestors():
ancestor_doc = frappe.get_doc('Location', ancestor)
ancestor_doc = frappe.get_doc("Location", ancestor)
child_features, ancestor_features = ancestor_doc.feature_seperator(child_feature=self.name)
ancestor_features = list(set(ancestor_features))
@@ -84,25 +84,27 @@ class Location(NestedSet):
ancestor_features[index] = json.loads(feature)
ancestor_doc.set_location_features(features=ancestor_features)
ancestor_doc.db_set('area', ancestor_doc.area + self.area_difference, commit=True)
ancestor_doc.db_set("area", ancestor_doc.area + self.area_difference, commit=True)
def remove_ancestor_location_features(self):
for ancestor in self.get_ancestors():
ancestor_doc = frappe.get_doc('Location', ancestor)
ancestor_doc = frappe.get_doc("Location", ancestor)
child_features, ancestor_features = ancestor_doc.feature_seperator(child_feature=self.name)
for index, feature in enumerate(ancestor_features):
ancestor_features[index] = json.loads(feature)
ancestor_doc.set_location_features(features=ancestor_features)
ancestor_doc.db_set('area', ancestor_doc.area - self.area, commit=True)
ancestor_doc.db_set("area", ancestor_doc.area - self.area, commit=True)
def add_child_property(self):
features = self.get_location_features()
filter_features = [feature for feature in features if not feature.get('properties').get('child_feature')]
filter_features = [
feature for feature in features if not feature.get("properties").get("child_feature")
]
for index, feature in enumerate(filter_features):
feature['properties'].update({'child_feature': True, 'feature_of': self.location_name})
feature["properties"].update({"child_feature": True, "feature_of": self.location_name})
filter_features[index] = json.dumps(filter_features[index])
return filter_features
@@ -112,7 +114,7 @@ class Location(NestedSet):
features = self.get_location_features()
for feature in features:
if feature.get('properties').get('feature_of') == child_feature:
if feature.get("properties").get("feature_of") == child_feature:
child_features.extend([json.dumps(feature)])
else:
non_child_features.extend([json.dumps(feature)])
@@ -126,22 +128,22 @@ def compute_area(features):
Reference from https://github.com/scisco/area.
Args:
`features` (list of dict): Features marked on the map as
GeoJSON data
`features` (list of dict): Features marked on the map as
GeoJSON data
Returns:
float: The approximate signed geodesic area (in sq. meters)
float: The approximate signed geodesic area (in sq. meters)
"""
layer_area = 0.0
for feature in features:
feature_type = feature.get('geometry', {}).get('type')
feature_type = feature.get("geometry", {}).get("type")
if feature_type == 'Polygon':
layer_area += _polygon_area(coords=feature.get('geometry').get('coordinates'))
elif feature_type == 'Point' and feature.get('properties').get('point_type') == 'circle':
layer_area += math.pi * math.pow(feature.get('properties').get('radius'), 2)
if feature_type == "Polygon":
layer_area += _polygon_area(coords=feature.get("geometry").get("coordinates"))
elif feature_type == "Point" and feature.get("properties").get("point_type") == "circle":
layer_area += math.pi * math.pow(feature.get("properties").get("radius"), 2)
return layer_area
@@ -192,7 +194,8 @@ def get_children(doctype, parent=None, location=None, is_root=False):
if parent is None or parent == "All Locations":
parent = ""
return frappe.db.sql("""
return frappe.db.sql(
"""
select
name as value,
is_group as expandable
@@ -201,17 +204,20 @@ def get_children(doctype, parent=None, location=None, is_root=False):
where
ifnull(parent_location, "")={parent}
""".format(
doctype=doctype,
parent=frappe.db.escape(parent)
), as_dict=1)
doctype=doctype, parent=frappe.db.escape(parent)
),
as_dict=1,
)
@frappe.whitelist()
def add_node():
from frappe.desk.treeview import make_tree_args
args = frappe.form_dict
args = make_tree_args(**args)
if args.parent_location == 'All Locations':
if args.parent_location == "All Locations":
args.parent_location = None
frappe.get_doc(args).insert()

View File

@@ -6,29 +6,34 @@ import unittest
import frappe
test_records = frappe.get_test_records('Location')
test_records = frappe.get_test_records("Location")
class TestLocation(unittest.TestCase):
def runTest(self):
locations = ['Basil Farm', 'Division 1', 'Field 1', 'Block 1']
locations = ["Basil Farm", "Division 1", "Field 1", "Block 1"]
area = 0
formatted_locations = []
for location in locations:
doc = frappe.get_doc('Location', location)
doc = frappe.get_doc("Location", location)
doc.save()
area += doc.area
temp = json.loads(doc.location)
temp['features'][0]['properties']['child_feature'] = True
temp['features'][0]['properties']['feature_of'] = location
formatted_locations.extend(temp['features'])
temp["features"][0]["properties"]["child_feature"] = True
temp["features"][0]["properties"]["feature_of"] = location
formatted_locations.extend(temp["features"])
test_location = frappe.get_doc('Location', 'Test Location Area')
test_location = frappe.get_doc("Location", "Test Location Area")
test_location.save()
test_location_features = json.loads(test_location.get('location'))['features']
ordered_test_location_features = sorted(test_location_features, key=lambda x: x['properties']['feature_of'])
ordered_formatted_locations = sorted(formatted_locations, key=lambda x: x['properties']['feature_of'])
test_location_features = json.loads(test_location.get("location"))["features"]
ordered_test_location_features = sorted(
test_location_features, key=lambda x: x["properties"]["feature_of"]
)
ordered_formatted_locations = sorted(
formatted_locations, key=lambda x: x["properties"]["feature_of"]
)
self.assertEqual(ordered_formatted_locations, ordered_test_location_features)
self.assertEqual(area, test_location.get('area'))
self.assertEqual(area, test_location.get("area"))

View File

@@ -17,16 +17,21 @@ def execute(filters=None):
filters = frappe._dict(filters or {})
columns = get_columns(filters)
data = get_data(filters)
chart = prepare_chart_data(data, filters) if filters.get("group_by") not in ("Asset Category", "Location") else {}
chart = (
prepare_chart_data(data, filters)
if filters.get("group_by") not in ("Asset Category", "Location")
else {}
)
return columns, data, None, chart
def get_conditions(filters):
conditions = { 'docstatus': 1 }
conditions = {"docstatus": 1}
status = filters.status
date_field = frappe.scrub(filters.date_based_on or "Purchase Date")
if filters.get('company'):
if filters.get("company"):
conditions["company"] = filters.company
if filters.filter_based_on == "Date Range":
conditions[date_field] = ["between", [filters.from_date, filters.to_date]]
@@ -37,23 +42,24 @@ def get_conditions(filters):
filters.year_end_date = getdate(fiscal_year.year_end_date)
conditions[date_field] = ["between", [filters.year_start_date, filters.year_end_date]]
if filters.get('is_existing_asset'):
conditions["is_existing_asset"] = filters.get('is_existing_asset')
if filters.get('asset_category'):
conditions["asset_category"] = filters.get('asset_category')
if filters.get('cost_center'):
conditions["cost_center"] = filters.get('cost_center')
if filters.get("is_existing_asset"):
conditions["is_existing_asset"] = filters.get("is_existing_asset")
if filters.get("asset_category"):
conditions["asset_category"] = filters.get("asset_category")
if filters.get("cost_center"):
conditions["cost_center"] = filters.get("cost_center")
if status:
# In Store assets are those that are not sold or scrapped
operand = 'not in'
if status not in 'In Location':
operand = 'in'
operand = "not in"
if status not in "In Location":
operand = "in"
conditions['status'] = (operand, ['Sold', 'Scrapped'])
conditions["status"] = (operand, ["Sold", "Scrapped"])
return conditions
def get_data(filters):
data = []
@@ -74,21 +80,37 @@ def get_data(filters):
assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields, group_by=group_by)
else:
fields = ["name as asset_id", "asset_name", "status", "department", "cost_center", "purchase_receipt",
"asset_category", "purchase_date", "gross_purchase_amount", "location",
"available_for_use_date", "purchase_invoice", "opening_accumulated_depreciation"]
fields = [
"name as asset_id",
"asset_name",
"status",
"department",
"cost_center",
"purchase_receipt",
"asset_category",
"purchase_date",
"gross_purchase_amount",
"location",
"available_for_use_date",
"purchase_invoice",
"opening_accumulated_depreciation",
]
assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields)
for asset in assets_record:
asset_value = asset.gross_purchase_amount - flt(asset.opening_accumulated_depreciation) \
asset_value = (
asset.gross_purchase_amount
- flt(asset.opening_accumulated_depreciation)
- flt(depreciation_amount_map.get(asset.name))
)
row = {
"asset_id": asset.asset_id,
"asset_name": asset.asset_name,
"status": asset.status,
"department": asset.department,
"cost_center": asset.cost_center,
"vendor_name": pr_supplier_map.get(asset.purchase_receipt) or pi_supplier_map.get(asset.purchase_invoice),
"vendor_name": pr_supplier_map.get(asset.purchase_receipt)
or pi_supplier_map.get(asset.purchase_invoice),
"gross_purchase_amount": asset.gross_purchase_amount,
"opening_accumulated_depreciation": asset.opening_accumulated_depreciation,
"depreciated_amount": depreciation_amount_map.get(asset.asset_id) or 0.0,
@@ -96,21 +118,31 @@ def get_data(filters):
"location": asset.location,
"asset_category": asset.asset_category,
"purchase_date": asset.purchase_date,
"asset_value": asset_value
"asset_value": asset_value,
}
data.append(row)
return data
def prepare_chart_data(data, filters):
labels_values_map = {}
date_field = frappe.scrub(filters.date_based_on)
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
filters.from_date, filters.to_date, filters.filter_based_on, "Monthly", company=filters.company)
period_list = get_period_list(
filters.from_fiscal_year,
filters.to_fiscal_year,
filters.from_date,
filters.to_date,
filters.filter_based_on,
"Monthly",
company=filters.company,
)
for d in period_list:
labels_values_map.setdefault(d.get('label'), frappe._dict({'asset_value': 0, 'depreciated_amount': 0}))
labels_values_map.setdefault(
d.get("label"), frappe._dict({"asset_value": 0, "depreciated_amount": 0})
)
for d in data:
date = d.get(date_field)
@@ -120,23 +152,30 @@ def prepare_chart_data(data, filters):
labels_values_map[belongs_to_month].depreciated_amount += d.get("depreciated_amount")
return {
"data" : {
"data": {
"labels": labels_values_map.keys(),
"datasets": [
{ 'name': _('Asset Value'), 'values': [d.get("asset_value") for d in labels_values_map.values()] },
{ 'name': _('Depreciatied Amount'), 'values': [d.get("depreciated_amount") for d in labels_values_map.values()] }
]
{
"name": _("Asset Value"),
"values": [d.get("asset_value") for d in labels_values_map.values()],
},
{
"name": _("Depreciatied Amount"),
"values": [d.get("depreciated_amount") for d in labels_values_map.values()],
},
],
},
"type": "bar",
"barOptions": {
"stacked": 1
},
"barOptions": {"stacked": 1},
}
def get_finance_book_value_map(filters):
date = filters.to_date if filters.filter_based_on == "Date Range" else filters.year_end_date
return frappe._dict(frappe.db.sql(''' Select
return frappe._dict(
frappe.db.sql(
""" Select
parent, SUM(depreciation_amount)
FROM `tabDepreciation Schedule`
WHERE
@@ -144,27 +183,41 @@ def get_finance_book_value_map(filters):
AND schedule_date<=%s
AND journal_entry IS NOT NULL
AND ifnull(finance_book, '')=%s
GROUP BY parent''', (date, cstr(filters.finance_book or ''))))
GROUP BY parent""",
(date, cstr(filters.finance_book or "")),
)
)
def get_purchase_receipt_supplier_map():
return frappe._dict(frappe.db.sql(''' Select
return frappe._dict(
frappe.db.sql(
""" Select
pr.name, pr.supplier
FROM `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pri
WHERE
pri.parent = pr.name
AND pri.is_fixed_asset=1
AND pr.docstatus=1
AND pr.is_return=0'''))
AND pr.is_return=0"""
)
)
def get_purchase_invoice_supplier_map():
return frappe._dict(frappe.db.sql(''' Select
return frappe._dict(
frappe.db.sql(
""" Select
pi.name, pi.supplier
FROM `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pii
WHERE
pii.parent = pi.name
AND pii.is_fixed_asset=1
AND pi.docstatus=1
AND pi.is_return=0'''))
AND pi.is_return=0"""
)
)
def get_columns(filters):
if filters.get("group_by") in ["Asset Category", "Location"]:
@@ -174,36 +227,36 @@ def get_columns(filters):
"fieldtype": "Link",
"fieldname": frappe.scrub(filters.get("group_by")),
"options": filters.get("group_by"),
"width": 120
"width": 120,
},
{
"label": _("Gross Purchase Amount"),
"fieldname": "gross_purchase_amount",
"fieldtype": "Currency",
"options": "company:currency",
"width": 100
"width": 100,
},
{
"label": _("Opening Accumulated Depreciation"),
"fieldname": "opening_accumulated_depreciation",
"fieldtype": "Currency",
"options": "company:currency",
"width": 90
"width": 90,
},
{
"label": _("Depreciated Amount"),
"fieldname": "depreciated_amount",
"fieldtype": "Currency",
"options": "company:currency",
"width": 100
"width": 100,
},
{
"label": _("Asset Value"),
"fieldname": "asset_value",
"fieldtype": "Currency",
"options": "company:currency",
"width": 100
}
"width": 100,
},
]
return [
@@ -212,92 +265,72 @@ def get_columns(filters):
"fieldtype": "Link",
"fieldname": "asset_id",
"options": "Asset",
"width": 60
},
{
"label": _("Asset Name"),
"fieldtype": "Data",
"fieldname": "asset_name",
"width": 140
"width": 60,
},
{"label": _("Asset Name"), "fieldtype": "Data", "fieldname": "asset_name", "width": 140},
{
"label": _("Asset Category"),
"fieldtype": "Link",
"fieldname": "asset_category",
"options": "Asset Category",
"width": 100
},
{
"label": _("Status"),
"fieldtype": "Data",
"fieldname": "status",
"width": 80
},
{
"label": _("Purchase Date"),
"fieldtype": "Date",
"fieldname": "purchase_date",
"width": 90
"width": 100,
},
{"label": _("Status"), "fieldtype": "Data", "fieldname": "status", "width": 80},
{"label": _("Purchase Date"), "fieldtype": "Date", "fieldname": "purchase_date", "width": 90},
{
"label": _("Available For Use Date"),
"fieldtype": "Date",
"fieldname": "available_for_use_date",
"width": 90
"width": 90,
},
{
"label": _("Gross Purchase Amount"),
"fieldname": "gross_purchase_amount",
"fieldtype": "Currency",
"options": "company:currency",
"width": 100
"width": 100,
},
{
"label": _("Asset Value"),
"fieldname": "asset_value",
"fieldtype": "Currency",
"options": "company:currency",
"width": 100
"width": 100,
},
{
"label": _("Opening Accumulated Depreciation"),
"fieldname": "opening_accumulated_depreciation",
"fieldtype": "Currency",
"options": "company:currency",
"width": 90
"width": 90,
},
{
"label": _("Depreciated Amount"),
"fieldname": "depreciated_amount",
"fieldtype": "Currency",
"options": "company:currency",
"width": 100
"width": 100,
},
{
"label": _("Cost Center"),
"fieldtype": "Link",
"fieldname": "cost_center",
"options": "Cost Center",
"width": 100
"width": 100,
},
{
"label": _("Department"),
"fieldtype": "Link",
"fieldname": "department",
"options": "Department",
"width": 100
},
{
"label": _("Vendor Name"),
"fieldtype": "Data",
"fieldname": "vendor_name",
"width": 100
"width": 100,
},
{"label": _("Vendor Name"), "fieldtype": "Data", "fieldname": "vendor_name", "width": 100},
{
"label": _("Location"),
"fieldtype": "Link",
"fieldname": "location",
"options": "Location",
"width": 100
"width": 100,
},
]