From bae61760112baa78ad346934f0c792e21855494e Mon Sep 17 00:00:00 2001
From: Khushi Rawat <142375893+khushi8112@users.noreply.github.com>
Date: Tue, 28 May 2024 20:37:52 +0530
Subject: [PATCH 1/5] =?UTF-8?q?refactor:=20renamed=20number=20of=20depreci?=
=?UTF-8?q?ations=20booked=20to=20opening=20booked=20de=E2=80=A6=20(#41515?=
=?UTF-8?q?)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* refactor: renamed number of depreciations booked to opening booked depreciations
* feat: introduced new field for showing total number of booked depreciations
---
.../doctype/journal_entry/journal_entry.py | 25 ++-
erpnext/assets/doctype/asset/asset.json | 16 +-
erpnext/assets/doctype/asset/asset.py | 27 ++-
erpnext/assets/doctype/asset/depreciation.py | 1 +
erpnext/assets/doctype/asset/test_asset.py | 26 +--
.../asset_depreciation_schedule.json | 6 +-
.../asset_depreciation_schedule.py | 64 +++++--
.../test_asset_depreciation_schedule.py | 168 ++++++++++++++++++
.../asset_finance_book.json | 25 ++-
.../asset_finance_book/asset_finance_book.py | 27 +++
.../doctype/asset_repair/asset_repair.py | 4 +-
erpnext/patches.txt | 1 +
...sset_depreciation_schedules_from_assets.py | 2 +-
..._booked_to_opening_booked_depreciations.py | 7 +
.../update_gpa_and_ndb_for_assdeprsch.py | 24 +--
15 files changed, 362 insertions(+), 61 deletions(-)
create mode 100644 erpnext/patches/v15_0/rename_number_of_depreciations_booked_to_opening_booked_depreciations.py
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 436b2c3907..be0b585ff7 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -197,7 +197,7 @@ class JournalEntry(AccountsController):
self.update_asset_value()
self.update_inter_company_jv()
self.update_invoice_discounting()
- self.update_unreconciled_amount()
+ self.update_booked_depreciation()
def on_update_after_submit(self):
if hasattr(self, "repost_required"):
@@ -231,6 +231,7 @@ class JournalEntry(AccountsController):
self.unlink_inter_company_jv()
self.unlink_asset_adjustment_entry()
self.update_invoice_discounting()
+ self.update_booked_depreciation()
def get_title(self):
return self.pay_to_recd_from or self.accounts[0].account
@@ -443,6 +444,28 @@ class JournalEntry(AccountsController):
if status:
inv_disc_doc.set_status(status=status)
+ def update_booked_depreciation(self):
+ for d in self.get("accounts"):
+ if (
+ self.voucher_type == "Depreciation Entry"
+ and d.reference_type == "Asset"
+ and d.reference_name
+ and frappe.get_cached_value("Account", d.account, "root_type") == "Expense"
+ and d.debit
+ ):
+ asset = frappe.get_doc("Asset", d.reference_name)
+ for fb_row in asset.get("finance_books"):
+ if fb_row.finance_book == self.finance_book:
+ depr_schedule = get_depr_schedule(asset.name, "Active", fb_row.finance_book)
+ total_number_of_booked_depreciations = asset.opening_number_of_booked_depreciations
+ for je in depr_schedule:
+ if je.journal_entry:
+ total_number_of_booked_depreciations += 1
+ fb_row.db_set(
+ "total_number_of_booked_depreciations", total_number_of_booked_depreciations
+ )
+ break
+
def unlink_advance_entry_reference(self):
for d in self.get("accounts"):
if d.is_advance == "Yes" and d.reference_type in ("Sales Invoice", "Purchase Invoice"):
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index 3a2a942bdf..99a430cbb4 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -45,7 +45,7 @@
"calculate_depreciation",
"column_break_33",
"opening_accumulated_depreciation",
- "number_of_depreciations_booked",
+ "opening_number_of_booked_depreciations",
"is_fully_depreciated",
"section_break_36",
"finance_books",
@@ -257,12 +257,6 @@
"label": "Opening Accumulated Depreciation",
"options": "Company:company:default_currency"
},
- {
- "depends_on": "eval:(doc.is_existing_asset)",
- "fieldname": "number_of_depreciations_booked",
- "fieldtype": "Int",
- "label": "Number of Depreciations Booked"
- },
{
"collapsible": 1,
"collapsible_depends_on": "eval:doc.calculate_depreciation || doc.is_existing_asset",
@@ -546,6 +540,12 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "depends_on": "eval:(doc.is_existing_asset)",
+ "fieldname": "opening_number_of_booked_depreciations",
+ "fieldtype": "Int",
+ "label": "Opening Number of Booked Depreciations"
}
],
"idx": 72,
@@ -589,7 +589,7 @@
"link_fieldname": "target_asset"
}
],
- "modified": "2024-04-18 16:45:47.306032",
+ "modified": "2024-05-21 13:46:21.066483",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 57a8eb0eef..77cbb90ea8 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -89,8 +89,8 @@ class Asset(AccountsController):
maintenance_required: DF.Check
naming_series: DF.Literal["ACC-ASS-.YYYY.-"]
next_depreciation_date: DF.Date | None
- number_of_depreciations_booked: DF.Int
opening_accumulated_depreciation: DF.Currency
+ opening_number_of_booked_depreciations: DF.Int
policy_number: DF.Data | None
purchase_amount: DF.Currency
purchase_date: DF.Date | None
@@ -145,7 +145,7 @@ class Asset(AccountsController):
"Asset Depreciation Schedules created:
{0}
Please check, edit if needed, and submit the Asset."
).format(asset_depr_schedules_links)
)
-
+ self.set_total_booked_depreciations()
self.total_asset_cost = self.gross_purchase_amount
self.status = self.get_status()
@@ -422,7 +422,7 @@ class Asset(AccountsController):
if not self.is_existing_asset:
self.opening_accumulated_depreciation = 0
- self.number_of_depreciations_booked = 0
+ self.opening_number_of_booked_depreciations = 0
else:
depreciable_amount = flt(self.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
if flt(self.opening_accumulated_depreciation) > depreciable_amount:
@@ -433,15 +433,15 @@ class Asset(AccountsController):
)
if self.opening_accumulated_depreciation:
- if not self.number_of_depreciations_booked:
- frappe.throw(_("Please set Number of Depreciations Booked"))
+ if not self.opening_number_of_booked_depreciations:
+ frappe.throw(_("Please set Opening Number of Booked Depreciations"))
else:
- self.number_of_depreciations_booked = 0
+ self.opening_number_of_booked_depreciations = 0
- if flt(row.total_number_of_depreciations) <= cint(self.number_of_depreciations_booked):
+ if flt(row.total_number_of_depreciations) <= cint(self.opening_number_of_booked_depreciations):
frappe.throw(
_(
- "Row {0}: Total Number of Depreciations cannot be less than or equal to Number of Depreciations Booked"
+ "Row {0}: Total Number of Depreciations cannot be less than or equal to Opening Number of Booked Depreciations"
).format(row.idx),
title=_("Invalid Schedule"),
)
@@ -464,6 +464,17 @@ class Asset(AccountsController):
).format(row.idx)
)
+ def set_total_booked_depreciations(self):
+ # set value of total number of booked depreciations field
+ for fb_row in self.get("finance_books"):
+ total_number_of_booked_depreciations = self.opening_number_of_booked_depreciations
+ depr_schedule = get_depr_schedule(self.name, "Active", fb_row.finance_book)
+ if depr_schedule:
+ for je in depr_schedule:
+ if je.journal_entry:
+ total_number_of_booked_depreciations += 1
+ fb_row.db_set("total_number_of_booked_depreciations", total_number_of_booked_depreciations)
+
def validate_expected_value_after_useful_life(self):
for row in self.get("finance_books"):
depr_schedule = get_depr_schedule(self.name, "Draft", row.finance_book)
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index b968736cee..6af057d642 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -326,6 +326,7 @@ def _make_journal_entry_for_depreciation(
if not je.meta.get_workflow():
je.submit()
+ asset.reload()
idx = cint(asset_depr_schedule_doc.finance_book_id)
row = asset.get("finance_books")[idx - 1]
row.value_after_depreciation -= depr_schedule.depreciation_amount
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index c0ded4b2a5..bb6b102b62 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -352,7 +352,7 @@ class TestAsset(AssetSetup):
purchase_date="2020-04-01",
expected_value_after_useful_life=0,
total_number_of_depreciations=5,
- number_of_depreciations_booked=2,
+ opening_number_of_booked_depreciations=2,
frequency_of_depreciation=12,
depreciation_start_date="2023-03-31",
opening_accumulated_depreciation=24000,
@@ -450,7 +450,7 @@ class TestAsset(AssetSetup):
purchase_date="2020-01-01",
expected_value_after_useful_life=0,
total_number_of_depreciations=6,
- number_of_depreciations_booked=1,
+ opening_number_of_booked_depreciations=1,
frequency_of_depreciation=10,
depreciation_start_date="2021-01-01",
opening_accumulated_depreciation=20000,
@@ -707,7 +707,7 @@ class TestDepreciationMethods(AssetSetup):
calculate_depreciation=1,
available_for_use_date="2030-06-06",
is_existing_asset=1,
- number_of_depreciations_booked=2,
+ opening_number_of_booked_depreciations=2,
opening_accumulated_depreciation=47095.89,
expected_value_after_useful_life=10000,
depreciation_start_date="2032-12-31",
@@ -757,7 +757,7 @@ class TestDepreciationMethods(AssetSetup):
available_for_use_date="2030-01-01",
is_existing_asset=1,
depreciation_method="Double Declining Balance",
- number_of_depreciations_booked=1,
+ opening_number_of_booked_depreciations=1,
opening_accumulated_depreciation=50000,
expected_value_after_useful_life=10000,
depreciation_start_date="2031-12-31",
@@ -1091,8 +1091,8 @@ class TestDepreciationBasics(AssetSetup):
self.assertRaises(frappe.ValidationError, asset.save)
- def test_number_of_depreciations_booked(self):
- """Tests if an error is raised when number_of_depreciations_booked is not specified when opening_accumulated_depreciation is."""
+ def test_opening_booked_depreciations(self):
+ """Tests if an error is raised when opening_number_of_booked_depreciations is not specified when opening_accumulated_depreciation is."""
asset = create_asset(
item_code="Macbook Pro",
@@ -1108,9 +1108,9 @@ class TestDepreciationBasics(AssetSetup):
self.assertRaises(frappe.ValidationError, asset.save)
def test_number_of_depreciations(self):
- """Tests if an error is raised when number_of_depreciations_booked >= total_number_of_depreciations."""
+ """Tests if an error is raised when opening_number_of_booked_depreciations >= total_number_of_depreciations."""
- # number_of_depreciations_booked > total_number_of_depreciations
+ # opening_number_of_booked_depreciations > total_number_of_depreciations
asset = create_asset(
item_code="Macbook Pro",
calculate_depreciation=1,
@@ -1119,13 +1119,13 @@ class TestDepreciationBasics(AssetSetup):
expected_value_after_useful_life=10000,
depreciation_start_date="2020-07-01",
opening_accumulated_depreciation=10000,
- number_of_depreciations_booked=5,
+ opening_number_of_booked_depreciations=5,
do_not_save=1,
)
self.assertRaises(frappe.ValidationError, asset.save)
- # number_of_depreciations_booked = total_number_of_depreciations
+ # opening_number_of_booked_depreciations = total_number_of_depreciations
asset_2 = create_asset(
item_code="Macbook Pro",
calculate_depreciation=1,
@@ -1134,7 +1134,7 @@ class TestDepreciationBasics(AssetSetup):
expected_value_after_useful_life=10000,
depreciation_start_date="2020-07-01",
opening_accumulated_depreciation=10000,
- number_of_depreciations_booked=5,
+ opening_number_of_booked_depreciations=5,
do_not_save=1,
)
@@ -1482,7 +1482,7 @@ class TestDepreciationBasics(AssetSetup):
asset = create_asset(calculate_depreciation=1)
asset.opening_accumulated_depreciation = 2000
- asset.number_of_depreciations_booked = 1
+ asset.opening_number_of_booked_depreciations = 1
asset.finance_books[0].expected_value_after_useful_life = 100
asset.save()
@@ -1676,7 +1676,7 @@ def create_asset(**args):
"purchase_date": args.purchase_date or "2015-01-01",
"calculate_depreciation": args.calculate_depreciation or 0,
"opening_accumulated_depreciation": args.opening_accumulated_depreciation or 0,
- "number_of_depreciations_booked": args.number_of_depreciations_booked or 0,
+ "opening_number_of_booked_depreciations": args.opening_number_of_booked_depreciations or 0,
"gross_purchase_amount": args.gross_purchase_amount or 100000,
"purchase_amount": args.purchase_amount or 100000,
"maintenance_required": args.maintenance_required or 0,
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json
index 5487cded84..01c0ea7fc7 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json
@@ -13,7 +13,7 @@
"column_break_2",
"gross_purchase_amount",
"opening_accumulated_depreciation",
- "number_of_depreciations_booked",
+ "opening_number_of_booked_depreciations",
"finance_book",
"finance_book_id",
"depreciation_details_section",
@@ -169,10 +169,10 @@
"read_only": 1
},
{
- "fieldname": "number_of_depreciations_booked",
+ "fieldname": "opening_number_of_booked_depreciations",
"fieldtype": "Int",
"hidden": 1,
- "label": "Number of Depreciations Booked",
+ "label": "Opening Number of Booked Depreciations",
"print_hide": 1,
"read_only": 1
},
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
index 448c34f36c..0b07015391 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
@@ -50,7 +50,7 @@ class AssetDepreciationSchedule(Document):
gross_purchase_amount: DF.Currency
naming_series: DF.Literal["ACC-ADS-.YYYY.-"]
notes: DF.SmallText | None
- number_of_depreciations_booked: DF.Int
+ opening_number_of_booked_depreciations: DF.Int
opening_accumulated_depreciation: DF.Currency
rate_of_depreciation: DF.Percent
shift_based: DF.Check
@@ -150,7 +150,7 @@ class AssetDepreciationSchedule(Document):
return (
asset_doc.gross_purchase_amount != self.gross_purchase_amount
or asset_doc.opening_accumulated_depreciation != self.opening_accumulated_depreciation
- or asset_doc.number_of_depreciations_booked != self.number_of_depreciations_booked
+ or asset_doc.opening_number_of_booked_depreciations != self.opening_number_of_booked_depreciations
)
def not_manual_depr_or_have_manual_depr_details_been_modified(self, row):
@@ -183,7 +183,7 @@ class AssetDepreciationSchedule(Document):
self.finance_book = row.finance_book
self.finance_book_id = row.idx
self.opening_accumulated_depreciation = asset_doc.opening_accumulated_depreciation or 0
- self.number_of_depreciations_booked = asset_doc.number_of_depreciations_booked or 0
+ self.opening_number_of_booked_depreciations = asset_doc.opening_number_of_booked_depreciations or 0
self.gross_purchase_amount = asset_doc.gross_purchase_amount
self.depreciation_method = row.depreciation_method
self.total_number_of_depreciations = row.total_number_of_depreciations
@@ -248,7 +248,7 @@ class AssetDepreciationSchedule(Document):
row.db_update()
final_number_of_depreciations = cint(row.total_number_of_depreciations) - cint(
- self.number_of_depreciations_booked
+ self.opening_number_of_booked_depreciations
)
has_pro_rata = _check_is_pro_rata(asset_doc, row)
@@ -315,7 +315,7 @@ class AssetDepreciationSchedule(Document):
if date_of_disposal and getdate(schedule_date) >= getdate(date_of_disposal):
from_date = add_months(
getdate(asset_doc.available_for_use_date),
- (asset_doc.number_of_depreciations_booked * row.frequency_of_depreciation),
+ (asset_doc.opening_number_of_booked_depreciations * row.frequency_of_depreciation),
)
if self.depreciation_schedule:
@@ -369,13 +369,16 @@ class AssetDepreciationSchedule(Document):
from_date = get_last_day(
add_months(
getdate(asset_doc.available_for_use_date),
- ((self.number_of_depreciations_booked - 1) * row.frequency_of_depreciation),
+ (
+ (self.opening_number_of_booked_depreciations - 1)
+ * row.frequency_of_depreciation
+ ),
)
)
else:
from_date = add_months(
getdate(add_days(asset_doc.available_for_use_date, -1)),
- (self.number_of_depreciations_booked * row.frequency_of_depreciation),
+ (self.opening_number_of_booked_depreciations * row.frequency_of_depreciation),
)
depreciation_amount, days, months = _get_pro_rata_amt(
row,
@@ -391,7 +394,8 @@ class AssetDepreciationSchedule(Document):
# In case of increase_in_asset_life, the asset.to_date is already set on asset_repair submission
asset_doc.to_date = add_months(
asset_doc.available_for_use_date,
- (n + self.number_of_depreciations_booked) * cint(row.frequency_of_depreciation),
+ (n + self.opening_number_of_booked_depreciations)
+ * cint(row.frequency_of_depreciation),
)
depreciation_amount_without_pro_rata = depreciation_amount
@@ -533,7 +537,7 @@ def _check_is_pro_rata(asset_doc, row, wdv_or_dd_non_yearly=False):
has_pro_rata = False
# if not existing asset, from_date = available_for_use_date
- # otherwise, if number_of_depreciations_booked = 2, available_for_use_date = 01/01/2020 and frequency_of_depreciation = 12
+ # otherwise, if opening_number_of_booked_depreciations = 2, available_for_use_date = 01/01/2020 and frequency_of_depreciation = 12
# from_date = 01/01/2022
from_date = _get_modified_available_for_use_date(asset_doc, row, wdv_or_dd_non_yearly)
days = date_diff(row.depreciation_start_date, from_date) + 1
@@ -557,12 +561,12 @@ def _get_modified_available_for_use_date(asset_doc, row, wdv_or_dd_non_yearly=Fa
if wdv_or_dd_non_yearly:
return add_months(
asset_doc.available_for_use_date,
- (asset_doc.number_of_depreciations_booked * 12),
+ (asset_doc.opening_number_of_booked_depreciations * 12),
)
else:
return add_months(
asset_doc.available_for_use_date,
- (asset_doc.number_of_depreciations_booked * row.frequency_of_depreciation),
+ (asset_doc.opening_number_of_booked_depreciations * row.frequency_of_depreciation),
)
@@ -644,11 +648,47 @@ def get_straight_line_or_manual_depr_amount(
) / number_of_pending_depreciations
# if the Depreciation Schedule is being prepared for the first time
else:
+ if row.daily_prorata_based:
+ amount = (
+ flt(asset.gross_purchase_amount)
+ - flt(asset.opening_accumulated_depreciation)
+ - flt(row.expected_value_after_useful_life)
+ )
+ return get_daily_prorata_based_straight_line_depr(
+ asset, row, schedule_idx, number_of_pending_depreciations, amount
+ )
+ else:
+ return (
+ flt(asset.gross_purchase_amount)
+ - flt(asset.opening_accumulated_depreciation)
+ - flt(row.expected_value_after_useful_life)
+ ) / flt(row.total_number_of_depreciations - asset.opening_number_of_booked_depreciations)
+
+
+def get_daily_prorata_based_straight_line_depr(
+ asset, row, schedule_idx, number_of_pending_depreciations, amount
+):
+ total_years = flt(number_of_pending_depreciations * row.frequency_of_depreciation) / 12
+ every_year_depr = amount / total_years
+
+ year_start_date = add_years(
+ row.depreciation_start_date, (row.frequency_of_depreciation * schedule_idx) // 12
+ )
+ year_end_date = add_days(add_years(year_start_date, 1), -1)
+ daily_depr_amount = every_year_depr / (date_diff(year_end_date, year_start_date) + 1)
+ from_date, total_depreciable_days = _get_total_days(
+ row.depreciation_start_date, schedule_idx, row.frequency_of_depreciation
+ )
+ return daily_depr_amount * total_depreciable_days
+
+
+def get_shift_depr_amount(asset_depr_schedule, asset, row, schedule_idx):
+ if asset_depr_schedule.get("__islocal") and not asset.flags.shift_allocation:
return (
flt(asset.gross_purchase_amount)
- flt(asset.opening_accumulated_depreciation)
- flt(row.expected_value_after_useful_life)
- ) / flt(row.total_number_of_depreciations - asset.number_of_depreciations_booked)
+ ) / flt(row.total_number_of_depreciations - asset.opening_number_of_booked_depreciations)
@erpnext.allow_regional
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
index 024121d394..217b036590 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
@@ -4,6 +4,9 @@
import frappe
from frappe.tests.utils import FrappeTestCase
+from erpnext.assets.doctype.asset.depreciation import (
+ post_depreciation_entries,
+)
from erpnext.assets.doctype.asset.test_asset import create_asset, create_asset_data
from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
get_asset_depr_schedule_doc,
@@ -25,3 +28,168 @@ class TestAssetDepreciationSchedule(FrappeTestCase):
)
self.assertRaises(frappe.ValidationError, second_asset_depr_schedule.insert)
+
+ def test_daily_prorata_based_depr_on_sl_method(self):
+ asset = create_asset(
+ calculate_depreciation=1,
+ depreciation_method="Straight Line",
+ daily_prorata_based=1,
+ available_for_use_date="2020-01-01",
+ depreciation_start_date="2020-01-31",
+ frequency_of_depreciation=1,
+ total_number_of_depreciations=24,
+ )
+
+ expected_schedules = [
+ ["2020-01-31", 4234.97, 4234.97],
+ ["2020-02-29", 3961.75, 8196.72],
+ ["2020-03-31", 4234.97, 12431.69],
+ ["2020-04-30", 4098.36, 16530.05],
+ ["2020-05-31", 4234.97, 20765.02],
+ ["2020-06-30", 4098.36, 24863.38],
+ ["2020-07-31", 4234.97, 29098.35],
+ ["2020-08-31", 4234.97, 33333.32],
+ ["2020-09-30", 4098.36, 37431.68],
+ ["2020-10-31", 4234.97, 41666.65],
+ ["2020-11-30", 4098.36, 45765.01],
+ ["2020-12-31", 4234.97, 49999.98],
+ ["2021-01-31", 4246.58, 54246.56],
+ ["2021-02-28", 3835.62, 58082.18],
+ ["2021-03-31", 4246.58, 62328.76],
+ ["2021-04-30", 4109.59, 66438.35],
+ ["2021-05-31", 4246.58, 70684.93],
+ ["2021-06-30", 4109.59, 74794.52],
+ ["2021-07-31", 4246.58, 79041.1],
+ ["2021-08-31", 4246.58, 83287.68],
+ ["2021-09-30", 4109.59, 87397.27],
+ ["2021-10-31", 4246.58, 91643.85],
+ ["2021-11-30", 4109.59, 95753.44],
+ ["2021-12-31", 4246.56, 100000.0],
+ ]
+
+ schedules = [
+ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
+ for d in get_depr_schedule(asset.name, "Draft")
+ ]
+ self.assertEqual(schedules, expected_schedules)
+
+ # Test for Written Down Value Method
+ # Frequency of deprciation = 3
+ def test_for_daily_prorata_based_depreciation_wdv_method_frequency_3_months(self):
+ asset = create_asset(
+ item_code="Macbook Pro",
+ calculate_depreciation=1,
+ depreciation_method="Written Down Value",
+ daily_prorata_based=1,
+ available_for_use_date="2021-02-20",
+ depreciation_start_date="2021-03-31",
+ frequency_of_depreciation=3,
+ total_number_of_depreciations=6,
+ rate_of_depreciation=40,
+ )
+
+ expected_schedules = [
+ ["2021-03-31", 4383.56, 4383.56],
+ ["2021-06-30", 9535.45, 13919.01],
+ ["2021-09-30", 9640.23, 23559.24],
+ ["2021-12-31", 9640.23, 33199.47],
+ ["2022-03-31", 9430.66, 42630.13],
+ ["2022-06-30", 5721.27, 48351.4],
+ ["2022-08-20", 51648.6, 100000.0],
+ ]
+
+ schedules = [
+ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
+ for d in get_depr_schedule(asset.name, "Draft")
+ ]
+ self.assertEqual(schedules, expected_schedules)
+
+ # Frequency of deprciation = 6
+ def test_for_daily_prorata_based_depreciation_wdv_method_frequency_6_months(self):
+ asset = create_asset(
+ item_code="Macbook Pro",
+ calculate_depreciation=1,
+ depreciation_method="Written Down Value",
+ daily_prorata_based=1,
+ available_for_use_date="2020-02-20",
+ depreciation_start_date="2020-02-29",
+ frequency_of_depreciation=6,
+ total_number_of_depreciations=6,
+ rate_of_depreciation=40,
+ )
+
+ expected_schedules = [
+ ["2020-02-29", 1092.90, 1092.90],
+ ["2020-08-31", 19944.01, 21036.91],
+ ["2021-02-28", 19618.83, 40655.74],
+ ["2021-08-31", 11966.4, 52622.14],
+ ["2022-02-28", 11771.3, 64393.44],
+ ["2022-08-31", 7179.84, 71573.28],
+ ["2023-02-20", 28426.72, 100000.0],
+ ]
+
+ schedules = [
+ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
+ for d in get_depr_schedule(asset.name, "Draft")
+ ]
+ self.assertEqual(schedules, expected_schedules)
+
+ # Frequency of deprciation = 12
+ def test_for_daily_prorata_based_depreciation_wdv_method_frequency_12_months(self):
+ asset = create_asset(
+ item_code="Macbook Pro",
+ calculate_depreciation=1,
+ depreciation_method="Written Down Value",
+ daily_prorata_based=1,
+ available_for_use_date="2020-02-20",
+ depreciation_start_date="2020-03-31",
+ frequency_of_depreciation=12,
+ total_number_of_depreciations=4,
+ rate_of_depreciation=40,
+ )
+
+ expected_schedules = [
+ ["2020-03-31", 4480.87, 4480.87],
+ ["2021-03-31", 38207.65, 42688.52],
+ ["2022-03-31", 22924.59, 65613.11],
+ ["2023-03-31", 13754.76, 79367.87],
+ ["2024-02-20", 20632.13, 100000],
+ ]
+
+ schedules = [
+ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
+ for d in get_depr_schedule(asset.name, "Draft")
+ ]
+ self.assertEqual(schedules, expected_schedules)
+
+ def test_update_total_number_of_booked_depreciations(self):
+ # check if updates total number of booked depreciations when depreciation gets booked
+ asset = create_asset(
+ item_code="Macbook Pro",
+ calculate_depreciation=1,
+ opening_accumulated_depreciation=2000,
+ opening_number_of_booked_depreciations=2,
+ depreciation_method="Straight Line",
+ available_for_use_date="2020-03-01",
+ depreciation_start_date="2020-03-31",
+ frequency_of_depreciation=1,
+ total_number_of_depreciations=24,
+ submit=1,
+ )
+
+ post_depreciation_entries(date="2021-03-31")
+ asset.reload()
+ """
+ opening_number_of_booked_depreciations = 2
+ number_of_booked_depreciations till 2021-03-31 = 13
+ total_number_of_booked_depreciations = 15
+ """
+ self.assertEqual(asset.finance_books[0].total_number_of_booked_depreciations, 15)
+
+ # cancel depreciation entry
+ depr_entry = get_depr_schedule(asset.name, "Active")[0].journal_entry
+
+ frappe.get_doc("Journal Entry", depr_entry).cancel()
+ asset.reload()
+
+ self.assertEqual(asset.finance_books[0].total_number_of_booked_depreciations, 14)
diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
index e10257f87d..a6a7d81de7 100644
--- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
+++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
@@ -8,6 +8,9 @@
"finance_book",
"depreciation_method",
"total_number_of_depreciations",
+ "total_number_of_booked_depreciations",
+ "daily_prorata_based",
+ "shift_based",
"column_break_5",
"frequency_of_depreciation",
"depreciation_start_date",
@@ -86,12 +89,32 @@
"fieldname": "salvage_value_percentage",
"fieldtype": "Percent",
"label": "Salvage Value Percentage"
+ },
+ {
+ "default": "0",
+ "fieldname": "daily_prorata_based",
+ "fieldtype": "Check",
+ "label": "Depreciate based on daily pro-rata"
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:doc.depreciation_method == \"Straight Line\"",
+ "fieldname": "shift_based",
+ "fieldtype": "Check",
+ "label": "Depreciate based on shifts"
+ },
+ {
+ "default": "0",
+ "fieldname": "total_number_of_booked_depreciations",
+ "fieldtype": "Int",
+ "label": "Total Number of Booked Depreciations ",
+ "read_only": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2023-12-29 08:49:39.876439",
+ "modified": "2024-05-21 15:48:20.907250",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Finance Book",
diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py
index 56e4d4ff3d..ab01956625 100644
--- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py
+++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py
@@ -7,4 +7,31 @@ from frappe.model.document import Document
class AssetFinanceBook(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ daily_prorata_based: DF.Check
+ depreciation_method: DF.Literal[
+ "", "Straight Line", "Double Declining Balance", "Written Down Value", "Manual"
+ ]
+ depreciation_start_date: DF.Date | None
+ expected_value_after_useful_life: DF.Currency
+ finance_book: DF.Link | None
+ frequency_of_depreciation: DF.Int
+ parent: DF.Data
+ parentfield: DF.Data
+ parenttype: DF.Data
+ rate_of_depreciation: DF.Percent
+ salvage_value_percentage: DF.Percent
+ shift_based: DF.Check
+ total_number_of_booked_depreciations: DF.Int
+ total_number_of_depreciations: DF.Int
+ value_after_depreciation: DF.Currency
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 81a97ed10b..0b8450614c 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -345,7 +345,7 @@ class AssetRepair(AccountsController):
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
+ asset.opening_number_of_booked_depreciations
)
depr_schedule = get_depr_schedule(asset.name, "Active", row.finance_book)
@@ -378,7 +378,7 @@ 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
+ asset.opening_number_of_booked_depreciations
)
depr_schedule = get_depr_schedule(asset.name, "Active", row.finance_book)
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 8f663fc009..dfcd258c6e 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -395,3 +395,4 @@ erpnext.patches.v14_0.set_maintain_stock_for_bom_item
erpnext.patches.v15_0.fix_debit_credit_in_transaction_currency
erpnext.patches.v15_0.rename_purchase_receipt_amount_to_purchase_amount
erpnext.patches.v14_0.enable_set_priority_for_pricing_rules #1
+erpnext.patches.v15_0.rename_number_of_depreciations_booked_to_opening_booked_depreciations
diff --git a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py
index bc0fd2871a..3087ff0209 100644
--- a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py
+++ b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py
@@ -43,7 +43,7 @@ def get_details_of_draft_or_submitted_depreciable_assets():
asset.name,
asset.opening_accumulated_depreciation,
asset.gross_purchase_amount,
- asset.number_of_depreciations_booked,
+ asset.opening_number_of_booked_depreciations,
asset.docstatus,
)
.where(asset.calculate_depreciation == 1)
diff --git a/erpnext/patches/v15_0/rename_number_of_depreciations_booked_to_opening_booked_depreciations.py b/erpnext/patches/v15_0/rename_number_of_depreciations_booked_to_opening_booked_depreciations.py
new file mode 100644
index 0000000000..1818337455
--- /dev/null
+++ b/erpnext/patches/v15_0/rename_number_of_depreciations_booked_to_opening_booked_depreciations.py
@@ -0,0 +1,7 @@
+import frappe
+from frappe.model.utils.rename_field import rename_field
+
+
+def execute():
+ if frappe.db.has_column("Asset", "number_of_depreciations_booked"):
+ rename_field("Asset", "number_of_depreciations_booked", "opening_number_of_booked_depreciations")
diff --git a/erpnext/patches/v15_0/update_gpa_and_ndb_for_assdeprsch.py b/erpnext/patches/v15_0/update_gpa_and_ndb_for_assdeprsch.py
index 2198be73d8..4399a95fda 100644
--- a/erpnext/patches/v15_0/update_gpa_and_ndb_for_assdeprsch.py
+++ b/erpnext/patches/v15_0/update_gpa_and_ndb_for_assdeprsch.py
@@ -5,16 +5,16 @@ def execute():
# not using frappe.qb because https://github.com/frappe/frappe/issues/20292
frappe.db.sql(
"""UPDATE `tabAsset Depreciation Schedule`
- JOIN `tabAsset`
- ON `tabAsset Depreciation Schedule`.`asset`=`tabAsset`.`name`
- SET
- `tabAsset Depreciation Schedule`.`gross_purchase_amount`=`tabAsset`.`gross_purchase_amount`,
- `tabAsset Depreciation Schedule`.`number_of_depreciations_booked`=`tabAsset`.`number_of_depreciations_booked`
- WHERE
- (
- `tabAsset Depreciation Schedule`.`gross_purchase_amount`<>`tabAsset`.`gross_purchase_amount`
- OR
- `tabAsset Depreciation Schedule`.`number_of_depreciations_booked`<>`tabAsset`.`number_of_depreciations_booked`
- )
- AND `tabAsset Depreciation Schedule`.`docstatus`<2"""
+ JOIN `tabAsset`
+ ON `tabAsset Depreciation Schedule`.`asset`=`tabAsset`.`name`
+ SET
+ `tabAsset Depreciation Schedule`.`gross_purchase_amount`=`tabAsset`.`gross_purchase_amount`,
+ `tabAsset Depreciation Schedule`.`opening_number_of_booked_depreciations`=`tabAsset`.`opening_number_of_booked_depreciations`
+ WHERE
+ (
+ `tabAsset Depreciation Schedule`.`gross_purchase_amount`<>`tabAsset`.`gross_purchase_amount`
+ OR
+ `tabAsset Depreciation Schedule`.`opening_number_of_booked_depreciations`<>`tabAsset`.`opening_number_of_booked_depreciations`
+ )
+ AND `tabAsset Depreciation Schedule`.`docstatus`<2"""
)
--
GitLab
From e33956bdc6e11403ce6a963375227cda2eddf492 Mon Sep 17 00:00:00 2001
From: Charles-Henri Decultot
Date: Wed, 29 May 2024 06:36:29 +0000
Subject: [PATCH 2/5] fix: merge conflict
---
erpnext/accounts/doctype/journal_entry/journal_entry.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index be0b585ff7..24b82b29cb 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -197,6 +197,7 @@ class JournalEntry(AccountsController):
self.update_asset_value()
self.update_inter_company_jv()
self.update_invoice_discounting()
+ self.update_unreconciled_amount() # @dokos
self.update_booked_depreciation()
def on_update_after_submit(self):
--
GitLab
From 5ab8ff5011a8f3ca9c354a6c002da6985e7dab96 Mon Sep 17 00:00:00 2001
From: Charles-Henri Decultot
Date: Wed, 29 May 2024 16:23:30 +0000
Subject: [PATCH 3/5] fix: missing dependency
---
.../test_asset_depreciation_schedule.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
index 217b036590..4399774c7a 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
@@ -10,6 +10,7 @@ from erpnext.assets.doctype.asset.depreciation import (
from erpnext.assets.doctype.asset.test_asset import create_asset, create_asset_data
from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
get_asset_depr_schedule_doc,
+ get_depr_schedule
)
--
GitLab
From 3fa5f3faa27501a97a446bca073d911ef5a192e9 Mon Sep 17 00:00:00 2001
From: Charles-Henri Decultot
Date: Wed, 29 May 2024 19:54:09 +0000
Subject: [PATCH 4/5] fix: missing utils import
---
.../test_asset_depreciation_schedule.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
index 4399774c7a..ec0f40c842 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
@@ -3,6 +3,7 @@
import frappe
from frappe.tests.utils import FrappeTestCase
+from frappe.utils import cstr
from erpnext.assets.doctype.asset.depreciation import (
post_depreciation_entries,
--
GitLab
From 90c5894d9507f3bb57a290e47b9cefe4a41339c6 Mon Sep 17 00:00:00 2001
From: Charles-Henri Decultot
Date: Thu, 30 May 2024 08:45:10 +0200
Subject: [PATCH 5/5] chore: rebase assets module
---
erpnext/assets/doctype/asset/asset.js | 701 ++++++++++--------
erpnext/assets/doctype/asset/asset.py | 93 +--
erpnext/assets/doctype/asset/asset_list.js | 32 +-
erpnext/assets/doctype/asset/depreciation.py | 47 +-
erpnext/assets/doctype/asset/test_asset.py | 170 +++--
.../asset_activity/asset_activity.json | 4 +-
.../doctype/asset_activity/asset_activity.py | 14 +
.../asset_capitalization.js | 183 +++--
.../asset_capitalization.json | 4 +-
.../asset_capitalization.py | 57 ++
.../test_asset_capitalization.py | 22 +-
.../asset_capitalization_asset_item.json | 7 +-
.../asset_capitalization_asset_item.py | 22 +
.../asset_capitalization_service_item.json | 4 +-
.../asset_capitalization_service_item.py | 21 +
.../asset_capitalization_stock_item.json | 4 +-
.../doctype/asset_category/asset_category.js | 71 +-
.../asset_category/asset_category.json | 8 +-
.../doctype/asset_category/asset_category.py | 26 +-
.../asset_category/test_asset_category.py | 7 +-
.../asset_category_account.json | 251 ++-----
.../asset_category_account.py | 19 +-
.../asset_depreciation_schedule.js | 59 +-
.../asset_depreciation_schedule.json | 25 +-
.../asset_depreciation_schedule.py | 280 +++++--
.../test_asset_depreciation_schedule.py | 4 +-
.../asset_finance_book.json | 9 +-
.../asset_finance_book/asset_finance_book.py | 1 -
.../asset_maintenance/asset_maintenance.js | 73 +-
.../asset_maintenance/asset_maintenance.json | 279 +++----
.../asset_maintenance/asset_maintenance.py | 33 +-
.../asset_maintenance_log.js | 12 +-
.../asset_maintenance_log.json | 402 +++++-----
.../asset_maintenance_log.py | 28 +
.../asset_maintenance_log_calendar.js | 24 +-
.../asset_maintenance_log_list.js | 15 +-
.../test_asset_maintenance_log.py | 1 -
.../asset_maintenance_task.json | 7 +-
.../asset_maintenance_task.py | 28 +-
.../asset_maintenance_team.js | 6 +-
.../asset_maintenance_team.json | 173 ++---
.../asset_maintenance_team.py | 20 +-
.../test_asset_maintenance_team.py | 1 -
.../doctype/asset_movement/asset_movement.js | 97 +--
.../asset_movement/asset_movement.json | 4 +-
.../doctype/asset_movement/asset_movement.py | 47 +-
.../asset_movement/test_asset_movement.py | 30 +-
.../asset_movement_item.json | 9 +-
.../asset_movement_item.py | 20 +
.../doctype/asset_repair/asset_repair.js | 96 +--
.../doctype/asset_repair/asset_repair.json | 6 +-
.../doctype/asset_repair/asset_repair.py | 44 +-
.../doctype/asset_repair/asset_repair_list.js | 12 +-
.../doctype/asset_repair/test_asset_repair.py | 16 +-
.../asset_repair_consumed_item.json | 4 +-
.../asset_repair_consumed_item.py | 19 +
.../asset_shift_allocation/__init__.py | 0
.../asset_shift_allocation.js | 14 +
.../asset_shift_allocation.json | 111 +++
.../asset_shift_allocation.py | 273 +++++++
.../test_asset_shift_allocation.py | 113 +++
.../doctype/asset_shift_factor/__init__.py | 0
.../asset_shift_factor/asset_shift_factor.js | 8 +
.../asset_shift_factor.json | 74 ++
.../asset_shift_factor/asset_shift_factor.py | 35 +
.../test_asset_shift_factor.py | 9 +
.../asset_value_adjustment.js | 42 +-
.../asset_value_adjustment.json | 369 ++++-----
.../asset_value_adjustment.py | 4 +-
.../test_asset_value_adjustment.py | 14 +-
.../depreciation_schedule.json | 11 +-
.../depreciation_schedule.py | 18 +
.../linked_location/linked_location.json | 99 +--
.../linked_location/linked_location.py | 15 +-
erpnext/assets/doctype/location/location.js | 15 +-
erpnext/assets/doctype/location/location.json | 26 +-
erpnext/assets/doctype/location/location.py | 29 +-
.../assets/doctype/location/location_tree.js | 16 +-
.../assets/doctype/location/test_location.py | 5 +-
.../maintenance_team_member.js | 6 +-
.../maintenance_team_member.json | 183 ++---
.../maintenance_team_member.py | 17 +-
.../test_maintenance_team_member.py | 1 -
erpnext/regional/france/assets.py | 33 +-
84 files changed, 3169 insertions(+), 2022 deletions(-)
create mode 100644 erpnext/assets/doctype/asset_shift_allocation/__init__.py
create mode 100644 erpnext/assets/doctype/asset_shift_allocation/asset_shift_allocation.js
create mode 100644 erpnext/assets/doctype/asset_shift_allocation/asset_shift_allocation.json
create mode 100644 erpnext/assets/doctype/asset_shift_allocation/asset_shift_allocation.py
create mode 100644 erpnext/assets/doctype/asset_shift_allocation/test_asset_shift_allocation.py
create mode 100644 erpnext/assets/doctype/asset_shift_factor/__init__.py
create mode 100644 erpnext/assets/doctype/asset_shift_factor/asset_shift_factor.js
create mode 100644 erpnext/assets/doctype/asset_shift_factor/asset_shift_factor.json
create mode 100644 erpnext/assets/doctype/asset_shift_factor/asset_shift_factor.py
create mode 100644 erpnext/assets/doctype/asset_shift_factor/test_asset_shift_factor.py
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index cb3ce813b9..46dbe07420 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -4,77 +4,77 @@
frappe.provide("erpnext.asset");
frappe.provide("erpnext.accounts.dimensions");
-frappe.ui.form.on('Asset', {
- onload: function(frm) {
- frm.set_query("item_code", function() {
+frappe.ui.form.on("Asset", {
+ onload: function (frm) {
+ frm.set_query("item_code", function () {
return {
- "filters": {
- "is_fixed_asset": 1,
- "is_stock_item": 0
- }
+ filters: {
+ is_fixed_asset: 1,
+ is_stock_item: 0,
+ },
};
});
- frm.set_query("warehouse", function() {
+ frm.set_query("warehouse", function () {
return {
- "filters": {
- "company": frm.doc.company,
- "is_group": 0
- }
+ filters: {
+ company: frm.doc.company,
+ is_group: 0,
+ },
};
});
- frm.set_query("department", function() {
+ frm.set_query("department", function () {
return {
- "filters": {
- "company": frm.doc.company,
- }
+ filters: {
+ company: frm.doc.company,
+ },
};
});
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
- company: function(frm) {
+ company: function (frm) {
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
- setup: function(frm) {
- frm.ignore_doctypes_on_cancel_all = ['Journal Entry'];
+ setup: function (frm) {
+ frm.ignore_doctypes_on_cancel_all = ["Journal Entry"];
frm.make_methods = {
- 'Asset Movement': () => {
+ "Asset Movement": () => {
frappe.call({
- method: "erpnext.assets.doctype.asset.asset.make_asset_movement",
- freeze: true,
- args:{
- "assets": [{ name: cur_frm.doc.name }]
- },
- callback: function (r) {
- if (r.message) {
- var doc = frappe.model.sync(r.message)[0];
- frappe.set_route("Form", doc.doctype, doc.name);
- }
- }
- });
+ method: "erpnext.assets.doctype.asset.asset.make_asset_movement",
+ freeze: true,
+ args: {
+ assets: [{ name: frm.doc.name }],
+ },
+ callback: function (r) {
+ if (r.message) {
+ var doc = frappe.model.sync(r.message)[0];
+ frappe.set_route("Form", doc.doctype, doc.name);
+ }
+ },
+ });
},
- }
+ };
frm.set_query("purchase_receipt", (doc) => {
return {
query: "erpnext.controllers.queries.get_purchase_receipts",
- filters: { item_code: doc.item_code }
- }
+ filters: { item_code: doc.item_code },
+ };
});
frm.set_query("purchase_invoice", (doc) => {
return {
query: "erpnext.controllers.queries.get_purchase_invoices",
- filters: { item_code: doc.item_code }
- }
+ filters: { item_code: doc.item_code },
+ };
});
},
- refresh: function(frm) {
+ refresh: function (frm) {
frappe.ui.form.trigger("Asset", "is_existing_asset");
frm.toggle_display("next_depreciation_date", frm.doc.docstatus < 1);
@@ -114,41 +114,65 @@ frappe.ui.form.on('Asset', {
}
if (frm.doc.maintenance_required && !frm.doc.maintenance_schedule) {
- frm.add_custom_button(__("Maintain Asset"), function() {
- frm.trigger("create_asset_maintenance");
- }, __("Manage"));
+ frm.add_custom_button(
+ __("Maintain Asset"),
+ function () {
+ frm.trigger("create_asset_maintenance");
+ },
+ __("Manage")
+ );
}
- frm.add_custom_button(__("Repair Asset"), function() {
- frm.trigger("create_asset_repair");
- }, __("Manage"));
+ frm.add_custom_button(
+ __("Repair Asset"),
+ function () {
+ frm.trigger("create_asset_repair");
+ },
+ __("Manage")
+ );
- frm.add_custom_button(__("Split Asset"), function() {
- frm.trigger("split_asset");
- }, __("Manage"));
+ frm.add_custom_button(
+ __("Split Asset"),
+ function () {
+ frm.trigger("split_asset");
+ },
+ __("Manage")
+ );
- if (frm.doc.status != 'Fully Depreciated') {
- frm.add_custom_button(__("Adjust Asset Value"), function() {
- frm.trigger("create_asset_value_adjustment");
- }, __("Manage"));
+ if (frm.doc.status != "Fully Depreciated") {
+ frm.add_custom_button(
+ __("Adjust Asset Value"),
+ function () {
+ frm.trigger("create_asset_value_adjustment");
+ },
+ __("Manage")
+ );
}
if (!frm.doc.calculate_depreciation) {
- frm.add_custom_button(__("Create Depreciation Entry"), function() {
- frm.trigger("make_journal_entry");
- }, __("Manage"));
+ frm.add_custom_button(
+ __("Create Depreciation Entry"),
+ function () {
+ frm.trigger("make_journal_entry");
+ },
+ __("Manage")
+ );
}
if (frm.doc.purchase_receipt || !frm.doc.is_existing_asset) {
- frm.add_custom_button(__("View General Ledger"), function() {
- frappe.route_options = {
- "voucher_no": frm.doc.name,
- "from_date": frm.doc.available_for_use_date,
- "to_date": frm.doc.available_for_use_date,
- "company": frm.doc.company
- };
- frappe.set_route("query-report", "General Ledger");
- }, __("Manage"));
+ frm.add_custom_button(
+ __("View General Ledger"),
+ function () {
+ frappe.route_options = {
+ voucher_no: frm.doc.name,
+ from_date: frm.doc.available_for_use_date,
+ to_date: frm.doc.available_for_use_date,
+ company: frm.doc.company,
+ };
+ frappe.set_route("query-report", "General Ledger");
+ },
+ __("Manage")
+ );
}
if (frm.doc.depr_entry_posting_status === "Failed") {
@@ -164,21 +188,26 @@ frappe.ui.form.on('Asset', {
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
if (frm.doc.is_composite_asset && !frm.doc.capitalized_in) {
- $('.primary-action').prop('hidden', true);
- $('.form-message').text('Capitalize this asset to confirm');
+ $(".primary-action").prop("hidden", true);
+ $(".form-message").text("Capitalize this asset to confirm");
- frm.add_custom_button(__("Capitalize Asset"), function() {
+ frm.add_custom_button(__("Capitalize Asset"), function () {
frm.trigger("create_asset_capitalization");
});
}
}
if (frm.doc.docstatus === 1) {
- frm.add_custom_button(__('Accounting Journal Adjustment'), () => {
+ frm.add_custom_button(
+ __("Accounting Journal Adjustment"),
+ () => {
frappe.require("assets/erpnext/js/accounting_journal_adjustment.js", () => {
- new erpnext.journalAdjustment({doctype: frm.doctype, docnames: [frm.docname]})
+ new erpnext.journalAdjustment({ doctype: frm.doctype, docnames: [frm.docname] });
});
- }, __('Create'), true);
+ },
+ __("Create"),
+ true
+ );
}
},
@@ -195,146 +224,192 @@ frappe.ui.form.on('Asset', {
frm.dashboard.set_headline_alert(alert);
},
- toggle_reference_doc: function(frm) {
+ toggle_reference_doc: function (frm) {
if (frm.doc.purchase_receipt && frm.doc.purchase_invoice && frm.doc.docstatus === 1) {
- frm.set_df_property('purchase_invoice', 'read_only', 1);
- frm.set_df_property('purchase_receipt', 'read_only', 1);
- }
- else if (frm.doc.is_existing_asset || frm.doc.is_composite_asset) {
- frm.toggle_reqd('purchase_receipt', 0);
- frm.toggle_reqd('purchase_invoice', 0);
- }
- else if (frm.doc.purchase_receipt) {
+ frm.set_df_property("purchase_invoice", "read_only", 1);
+ frm.set_df_property("purchase_receipt", "read_only", 1);
+ } else if (frm.doc.is_existing_asset || frm.doc.is_composite_asset) {
+ frm.toggle_reqd("purchase_receipt", 0);
+ frm.toggle_reqd("purchase_invoice", 0);
+ } else if (frm.doc.purchase_receipt) {
// if purchase receipt link is set then set PI disabled
- frm.toggle_reqd('purchase_invoice', 0);
- frm.set_df_property('purchase_invoice', 'read_only', 1);
- }
- else if (frm.doc.purchase_invoice) {
+ frm.toggle_reqd("purchase_invoice", 0);
+ frm.set_df_property("purchase_invoice", "read_only", 1);
+ } else if (frm.doc.purchase_invoice) {
// if purchase invoice link is set then set PR disabled
- frm.toggle_reqd('purchase_receipt', 0);
- frm.set_df_property('purchase_receipt', 'read_only', 1);
- }
- else {
- frm.toggle_reqd('purchase_receipt', 1);
- frm.set_df_property('purchase_receipt', 'read_only', 0);
- frm.toggle_reqd('purchase_invoice', 1);
- frm.set_df_property('purchase_invoice', 'read_only', 0);
+ frm.toggle_reqd("purchase_receipt", 0);
+ frm.set_df_property("purchase_receipt", "read_only", 1);
+ } else {
+ frm.toggle_reqd("purchase_receipt", 1);
+ frm.set_df_property("purchase_receipt", "read_only", 0);
+ frm.toggle_reqd("purchase_invoice", 1);
+ frm.set_df_property("purchase_invoice", "read_only", 0);
}
},
- make_journal_entry: function(frm) {
+ make_journal_entry: function (frm) {
frappe.call({
method: "erpnext.assets.doctype.asset.asset.make_journal_entry",
args: {
- asset_name: frm.doc.name
+ asset_name: frm.doc.name,
},
- callback: function(r) {
+ callback: function (r) {
if (r.message) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
}
- }
- })
+ },
+ });
},
- render_depreciation_schedule_view: function(frm, depr_schedule) {
+ render_depreciation_schedule_view: function (frm, asset_depr_schedule_doc) {
let wrapper = $(frm.fields_dict["depreciation_schedule_view"].wrapper).empty();
let data = [];
- depr_schedule.forEach((sch) => {
+ asset_depr_schedule_doc.depreciation_schedule.forEach((sch) => {
const row = [
- sch['idx'],
- frappe.format(sch['schedule_date'], { fieldtype: 'Date' }),
- frappe.format(sch['depreciation_amount'], { fieldtype: 'Currency' }),
- frappe.format(sch['accumulated_depreciation_amount'], { fieldtype: 'Currency' }),
- sch['journal_entry'] || ''
+ sch["idx"],
+ frappe.format(sch["schedule_date"], { fieldtype: "Date" }),
+ frappe.format(sch["depreciation_amount"], { fieldtype: "Currency" }),
+ frappe.format(sch["accumulated_depreciation_amount"], { fieldtype: "Currency" }),
+ sch["journal_entry"] || "",
];
+
+ if (asset_depr_schedule_doc.shift_based) {
+ row.push(sch["shift"]);
+ }
+
data.push(row);
});
+ let columns = [
+ { name: __("No."), editable: false, resizable: false, format: (value) => value, width: 60 },
+ { name: __("Schedule Date"), editable: false, resizable: false, width: 270 },
+ { name: __("Depreciation Amount"), editable: false, resizable: false, width: 164 },
+ { name: __("Accumulated Depreciation Amount"), editable: false, resizable: false, width: 164 },
+ ];
+
+ if (asset_depr_schedule_doc.shift_based) {
+ columns.push({
+ name: __("Journal Entry"),
+ editable: false,
+ resizable: false,
+ format: (value) => `${value}`,
+ width: 245,
+ });
+ columns.push({ name: __("Shift"), editable: false, resizable: false, width: 59 });
+ } else {
+ columns.push({
+ name: __("Journal Entry"),
+ editable: false,
+ resizable: false,
+ format: (value) => `${value}`,
+ width: 304,
+ });
+ }
+
let datatable = new frappe.DataTable(wrapper.get(0), {
- columns: [
- {name: __("No."), editable: false, resizable: false, format: value => value, width: 60},
- {name: __("Schedule Date"), editable: false, resizable: false, width: 270},
- {name: __("Depreciation Amount"), editable: false, resizable: false, width: 164},
- {name: __("Accumulated Depreciation Amount"), editable: false, resizable: false, width: 164},
- {name: __("Journal Entry"), editable: false, resizable: false, format: value => `${value}`, width: 304}
- ],
+ columns: columns,
data: data,
layout: "fluid",
serialNoColumn: false,
checkboxColumn: true,
- cellHeight: 35
+ cellHeight: 35,
});
- datatable.style.setStyle(`.dt-scrollable`, {'font-size': '0.75rem', 'margin-bottom': '1rem', 'margin-left': '0.35rem', 'margin-right': '0.35rem'});
- datatable.style.setStyle(`.dt-header`, {'margin-left': '0.35rem', 'margin-right': '0.35rem'});
- datatable.style.setStyle(`.dt-cell--header .dt-cell__content`, {'color': 'var(--gray-600)', 'font-size': 'var(--text-sm)'});
- datatable.style.setStyle(`.dt-cell`, {'color': 'var(--text-color)'});
- datatable.style.setStyle(`.dt-cell--col-1`, {'text-align': 'center'});
- datatable.style.setStyle(`.dt-cell--col-2`, {'font-weight': 600});
- datatable.style.setStyle(`.dt-cell--col-3`, {'font-weight': 600});
+ datatable.style.setStyle(`.dt-scrollable`, {
+ "font-size": "0.75rem",
+ "margin-bottom": "1rem",
+ "margin-left": "0.35rem",
+ "margin-right": "0.35rem",
+ });
+ datatable.style.setStyle(`.dt-header`, { "margin-left": "0.35rem", "margin-right": "0.35rem" });
+ datatable.style.setStyle(`.dt-cell--header .dt-cell__content`, {
+ color: "var(--gray-600)",
+ "font-size": "var(--text-sm)",
+ });
+ datatable.style.setStyle(`.dt-cell`, { color: "var(--text-color)" });
+ datatable.style.setStyle(`.dt-cell--col-1`, { "text-align": "center" });
+ datatable.style.setStyle(`.dt-cell--col-2`, { "font-weight": 600 });
+ datatable.style.setStyle(`.dt-cell--col-3`, { "font-weight": 600 });
},
- setup_chart_and_depr_schedule_view: async function(frm) {
- if(frm.doc.finance_books.length > 1) {
- return
+ setup_chart_and_depr_schedule_view: async function (frm) {
+ if (frm.doc.finance_books.length > 1) {
+ return;
}
- var x_intervals = [frappe.format(frm.doc.purchase_date, { fieldtype: 'Date' })];
+ var x_intervals = [frappe.format(frm.doc.purchase_date, { fieldtype: "Date" })];
var asset_values = [frm.doc.gross_purchase_amount];
- if(frm.doc.calculate_depreciation) {
- if(frm.doc.opening_accumulated_depreciation) {
+ if (frm.doc.calculate_depreciation) {
+ if (frm.doc.opening_accumulated_depreciation) {
var depreciation_date = frappe.datetime.add_months(
frm.doc.finance_books[0].depreciation_start_date,
-1 * frm.doc.finance_books[0].frequency_of_depreciation
);
- x_intervals.push(frappe.format(depreciation_date, { fieldtype: 'Date' }));
- asset_values.push(flt(frm.doc.gross_purchase_amount - frm.doc.opening_accumulated_depreciation, precision('gross_purchase_amount')));
+ x_intervals.push(frappe.format(depreciation_date, { fieldtype: "Date" }));
+ asset_values.push(
+ flt(
+ frm.doc.gross_purchase_amount - frm.doc.opening_accumulated_depreciation,
+ precision("gross_purchase_amount")
+ )
+ );
}
- let depr_schedule = (await frappe.call(
- "erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule.get_depr_schedule",
- {
- asset_name: frm.doc.name,
- status: "Active",
- finance_book: frm.doc.finance_books[0].finance_book || null
- }
- )).message;
-
- $.each(depr_schedule || [], function(i, v) {
- x_intervals.push(frappe.format(v.schedule_date, { fieldtype: 'Date' }));
- var asset_value = flt(frm.doc.gross_purchase_amount - v.accumulated_depreciation_amount, precision('gross_purchase_amount'));
- if(v.journal_entry) {
+ let asset_depr_schedule_doc = (
+ await frappe.call(
+ "erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule.get_asset_depr_schedule_doc",
+ {
+ asset_name: frm.doc.name,
+ status: "Active",
+ finance_book: frm.doc.finance_books[0].finance_book || null,
+ }
+ )
+ ).message;
+
+ $.each(asset_depr_schedule_doc.depreciation_schedule || [], function (i, v) {
+ x_intervals.push(frappe.format(v.schedule_date, { fieldtype: "Date" }));
+ var asset_value = flt(
+ frm.doc.gross_purchase_amount - v.accumulated_depreciation_amount,
+ precision("gross_purchase_amount")
+ );
+ if (v.journal_entry) {
asset_values.push(asset_value);
} else {
if (["Scrapped", "Sold"].includes(frm.doc.status)) {
asset_values.push(null);
} else {
- asset_values.push(asset_value)
+ asset_values.push(asset_value);
}
}
});
frm.toggle_display(["depreciation_schedule_view"], 1);
- frm.events.render_depreciation_schedule_view(frm, depr_schedule);
+ frm.events.render_depreciation_schedule_view(frm, asset_depr_schedule_doc);
} else {
- if(frm.doc.opening_accumulated_depreciation) {
- x_intervals.push(frappe.format(frm.doc.creation.split(" ")[0], { fieldtype: 'Date' }));
- asset_values.push(flt(frm.doc.gross_purchase_amount - frm.doc.opening_accumulated_depreciation, precision('gross_purchase_amount')));
+ if (frm.doc.opening_accumulated_depreciation) {
+ x_intervals.push(frappe.format(frm.doc.creation.split(" ")[0], { fieldtype: "Date" }));
+ asset_values.push(
+ flt(
+ frm.doc.gross_purchase_amount - frm.doc.opening_accumulated_depreciation,
+ precision("gross_purchase_amount")
+ )
+ );
}
- let depr_entries = (await frappe.call({
- method: "get_manual_depreciation_entries",
- doc: frm.doc,
- })).message;
-
- $.each(depr_entries || [], function(i, v) {
- x_intervals.push(frappe.format(v.posting_date, { fieldtype: 'Date' }));
- let last_asset_value = asset_values[asset_values.length - 1]
- asset_values.push(flt(last_asset_value - v.value, precision('gross_purchase_amount')));
+ let depr_entries = (
+ await frappe.call({
+ method: "get_manual_depreciation_entries",
+ doc: frm.doc,
+ })
+ ).message;
+
+ $.each(depr_entries || [], function (i, v) {
+ x_intervals.push(frappe.format(v.posting_date, { fieldtype: "Date" }));
+ let last_asset_value = asset_values[asset_values.length - 1];
+ asset_values.push(flt(last_asset_value - v.value, precision("gross_purchase_amount")));
});
}
@@ -347,145 +422,146 @@ frappe.ui.form.on('Asset', {
title: "Asset Value",
data: {
labels: x_intervals,
- datasets: [{
- color: 'green',
- values: asset_values,
- formatted: asset_values.map(d => d?.toFixed(2))
- }]
+ datasets: [
+ {
+ color: "green",
+ values: asset_values,
+ formatted: asset_values.map((d) => d?.toFixed(2)),
+ },
+ ],
},
- type: 'line'
+ type: "line",
});
},
-
- item_code: function(frm) {
- if(frm.doc.item_code && frm.doc.calculate_depreciation && frm.doc.gross_purchase_amount) {
- frm.trigger('set_finance_book');
+ item_code: function (frm) {
+ if (frm.doc.item_code && frm.doc.calculate_depreciation && frm.doc.gross_purchase_amount) {
+ frm.trigger("set_finance_book");
} else {
- frm.set_value('finance_books', []);
+ frm.set_value("finance_books", []);
}
},
- set_finance_book: function(frm) {
+ set_finance_book: function (frm) {
frappe.call({
method: "erpnext.assets.doctype.asset.asset.get_item_details",
args: {
item_code: frm.doc.item_code,
asset_category: frm.doc.asset_category,
- gross_purchase_amount: frm.doc.gross_purchase_amount
+ gross_purchase_amount: frm.doc.gross_purchase_amount,
},
- callback: function(r, rt) {
- if(r.message) {
- frm.set_value('finance_books', r.message);
+ callback: function (r, rt) {
+ if (r.message) {
+ frm.set_value("finance_books", r.message);
}
- }
- })
+ },
+ });
},
- is_existing_asset: function(frm) {
+ is_existing_asset: function (frm) {
frm.trigger("toggle_reference_doc");
},
- is_composite_asset: function(frm) {
- if(frm.doc.is_composite_asset) {
- frm.set_value('gross_purchase_amount', 0);
- frm.set_df_property('gross_purchase_amount', 'read_only', 1);
+ is_composite_asset: function (frm) {
+ if (frm.doc.is_composite_asset) {
+ frm.set_value("gross_purchase_amount", 0);
+ frm.set_df_property("gross_purchase_amount", "read_only", 1);
} else {
- frm.set_df_property('gross_purchase_amount', 'read_only', 0);
+ frm.set_df_property("gross_purchase_amount", "read_only", 0);
}
frm.trigger("toggle_reference_doc");
},
- make_sales_invoice: function(frm) {
+ make_sales_invoice: function (frm) {
frappe.call({
args: {
- "asset": frm.doc.name,
- "item_code": frm.doc.item_code,
- "company": frm.doc.company,
- "serial_no": frm.doc.serial_no
+ asset: frm.doc.name,
+ item_code: frm.doc.item_code,
+ company: frm.doc.company,
+ serial_no: frm.doc.serial_no,
},
method: "erpnext.assets.doctype.asset.asset.make_sales_invoice",
- callback: function(r) {
+ callback: function (r) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
- })
+ },
+ });
},
- create_asset_maintenance: function(frm) {
+ create_asset_maintenance: function (frm) {
frappe.call({
args: {
- "asset": frm.doc.name,
- "item_code": frm.doc.item_code,
- "item_name": frm.doc.item_name,
- "asset_category": frm.doc.asset_category,
- "company": frm.doc.company
+ asset: frm.doc.name,
+ item_code: frm.doc.item_code,
+ item_name: frm.doc.item_name,
+ asset_category: frm.doc.asset_category,
+ company: frm.doc.company,
},
method: "erpnext.assets.doctype.asset.asset.create_asset_maintenance",
- callback: function(r) {
+ callback: function (r) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
- })
+ },
+ });
},
- create_asset_repair: function(frm) {
+ create_asset_repair: function (frm) {
frappe.call({
args: {
- "asset": frm.doc.name,
- "asset_name": frm.doc.asset_name
+ asset: frm.doc.name,
+ asset_name: frm.doc.asset_name,
},
method: "erpnext.assets.doctype.asset.asset.create_asset_repair",
- callback: function(r) {
+ callback: function (r) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
+ },
});
},
- create_asset_capitalization: function(frm) {
+ create_asset_capitalization: function (frm) {
frappe.call({
args: {
- "asset": frm.doc.name,
+ asset: frm.doc.name,
},
method: "erpnext.assets.doctype.asset.asset.create_asset_capitalization",
- callback: function(r) {
+ callback: function (r) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
+ },
});
},
- split_asset: function(frm) {
- const title = __('Split Asset');
+ split_asset: function (frm) {
+ const title = __("Split Asset");
const fields = [
{
- fieldname: 'split_qty',
- fieldtype: 'Int',
- label: __('Split Qty'),
- reqd: 1
- }
+ fieldname: "split_qty",
+ fieldtype: "Int",
+ label: __("Split Qty"),
+ reqd: 1,
+ },
];
let dialog = new frappe.ui.Dialog({
title: title,
- fields: fields
+ fields: fields,
});
- dialog.set_primary_action(__('Split'), function() {
+ dialog.set_primary_action(__("Split"), function () {
const dialog_data = dialog.get_values();
frappe.call({
args: {
- "asset_name": frm.doc.name,
- "split_qty": cint(dialog_data.split_qty)
+ asset_name: frm.doc.name,
+ split_qty: cint(dialog_data.split_qty),
},
method: "erpnext.assets.doctype.asset.asset.split_asset",
- callback: function(r) {
+ callback: function (r) {
let doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
+ },
});
dialog.hide();
@@ -494,23 +570,23 @@ frappe.ui.form.on('Asset', {
dialog.show();
},
- create_asset_value_adjustment: function(frm) {
+ create_asset_value_adjustment: function (frm) {
frappe.call({
args: {
- "asset": frm.doc.name,
- "asset_category": frm.doc.asset_category,
- "company": frm.doc.company
+ asset: frm.doc.name,
+ asset_category: frm.doc.asset_category,
+ company: frm.doc.company,
},
method: "erpnext.assets.doctype.asset.asset.create_asset_value_adjustment",
freeze: 1,
- callback: function(r) {
+ callback: function (r) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
- })
+ },
+ });
},
- calculate_depreciation: function(frm) {
+ calculate_depreciation: function (frm) {
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
if (frm.doc.item_code && frm.doc.calculate_depreciation && frm.doc.gross_purchase_amount) {
frm.trigger("set_finance_book");
@@ -519,69 +595,69 @@ frappe.ui.form.on('Asset', {
}
},
- gross_purchase_amount: function(frm) {
+ gross_purchase_amount: function (frm) {
if (frm.doc.finance_books) {
- frm.doc.finance_books.forEach(d => {
+ frm.doc.finance_books.forEach((d) => {
frm.events.set_depreciation_rate(frm, d);
- })
+ });
}
},
purchase_receipt: (frm) => {
- frm.trigger('toggle_reference_doc');
+ frm.trigger("toggle_reference_doc");
if (frm.doc.purchase_receipt) {
if (frm.doc.item_code) {
- frappe.db.get_doc('Purchase Receipt', frm.doc.purchase_receipt).then(pr_doc => {
- frm.events.set_values_from_purchase_doc(frm, 'Purchase Receipt', pr_doc)
+ frappe.db.get_doc("Purchase Receipt", frm.doc.purchase_receipt).then((pr_doc) => {
+ frm.events.set_values_from_purchase_doc(frm, "Purchase Receipt", pr_doc);
});
} else {
- frm.set_value('purchase_receipt', '');
+ frm.set_value("purchase_receipt", "");
frappe.msgprint({
- title: __('Not Allowed'),
- message: __("Please select Item Code first")
+ title: __("Not Allowed"),
+ message: __("Please select Item Code first"),
});
}
}
},
purchase_invoice: (frm) => {
- frm.trigger('toggle_reference_doc');
+ frm.trigger("toggle_reference_doc");
if (frm.doc.purchase_invoice) {
if (frm.doc.item_code) {
- frappe.db.get_doc('Purchase Invoice', frm.doc.purchase_invoice).then(pi_doc => {
- frm.events.set_values_from_purchase_doc(frm, 'Purchase Invoice', pi_doc)
+ frappe.db.get_doc("Purchase Invoice", frm.doc.purchase_invoice).then((pi_doc) => {
+ frm.events.set_values_from_purchase_doc(frm, "Purchase Invoice", pi_doc);
});
} else {
- frm.set_value('purchase_invoice', '');
+ frm.set_value("purchase_invoice", "");
frappe.msgprint({
- title: __('Not Allowed'),
- message: __("Please select Item Code first")
+ title: __("Not Allowed"),
+ message: __("Please select Item Code first"),
});
}
}
},
- set_values_from_purchase_doc: function(frm, doctype, purchase_doc) {
- frm.set_value('company', purchase_doc.company);
+ set_values_from_purchase_doc: function (frm, doctype, purchase_doc) {
+ frm.set_value("company", purchase_doc.company);
if (purchase_doc.bill_date) {
- frm.set_value('purchase_date', purchase_doc.bill_date);
+ frm.set_value("purchase_date", purchase_doc.bill_date);
} else {
- frm.set_value('purchase_date', purchase_doc.posting_date);
+ frm.set_value("purchase_date", purchase_doc.posting_date);
}
if (!frm.doc.is_existing_asset && !frm.doc.available_for_use_date) {
- frm.set_value('available_for_use_date', frm.doc.purchase_date);
+ frm.set_value("available_for_use_date", frm.doc.purchase_date);
}
- const item = purchase_doc.items.find(item => item.item_code === frm.doc.item_code);
+ const item = purchase_doc.items.find((item) => item.item_code === frm.doc.item_code);
if (!item) {
- let doctype_field = frappe.scrub(doctype)
- frm.set_value(doctype_field, '');
+ let doctype_field = frappe.scrub(doctype);
+ frm.set_value(doctype_field, "");
frappe.msgprint({
- title: __('Invalid {0}', [__(doctype)]),
- message: __('The selected {0} does not contain the selected Asset Item.', [__(doctype)]),
- indicator: 'red'
+ title: __("Invalid {0}", [__(doctype)]),
+ message: __("The selected {0} does not contain the selected Asset Item.", [__(doctype)]),
+ indicator: "red",
});
}
- frappe.db.get_value('Item', item.item_code, 'is_grouped_asset', (r) => {
+ frappe.db.get_value("Item", item.item_code, "is_grouped_asset", (r) => {
var asset_quantity = r.is_grouped_asset ? item.qty : 1;
var purchase_amount = flt(
item.valuation_rate * asset_quantity,
@@ -598,129 +674,166 @@ frappe.ui.form.on('Asset', {
});
},
- set_depreciation_rate: function(frm, row) {
- if (row.total_number_of_depreciations && row.frequency_of_depreciation
- && row.expected_value_after_useful_life) {
+ set_depreciation_rate: function (frm, row) {
+ if (
+ row.total_number_of_depreciations &&
+ row.frequency_of_depreciation &&
+ row.expected_value_after_useful_life
+ ) {
frappe.call({
method: "get_depreciation_rate",
doc: frm.doc,
args: row,
- callback: function(r) {
+ callback: function (r) {
if (r.message) {
frappe.flags.dont_change_rate = true;
- frappe.model.set_value(row.doctype, row.name,
- "rate_of_depreciation", flt(r.message, precision("rate_of_depreciation", row)));
+ frappe.model.set_value(
+ row.doctype,
+ row.name,
+ "rate_of_depreciation",
+ flt(r.message, precision("rate_of_depreciation", row))
+ );
}
- }
+ },
});
}
},
- set_salvage_value_percentage_or_expected_value_after_useful_life: function(frm, row, salvage_value_percentage_changed, expected_value_after_useful_life_changed) {
+ set_salvage_value_percentage_or_expected_value_after_useful_life: function (
+ frm,
+ row,
+ salvage_value_percentage_changed,
+ expected_value_after_useful_life_changed
+ ) {
if (expected_value_after_useful_life_changed) {
frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life = true;
- const new_salvage_value_percentage = flt((row.expected_value_after_useful_life * 100) / frm.doc.gross_purchase_amount, precision("salvage_value_percentage", row));
- frappe.model.set_value(row.doctype, row.name, "salvage_value_percentage", new_salvage_value_percentage);
+ const new_salvage_value_percentage = flt(
+ (row.expected_value_after_useful_life * 100) / frm.doc.gross_purchase_amount,
+ precision("salvage_value_percentage", row)
+ );
+ frappe.model.set_value(
+ row.doctype,
+ row.name,
+ "salvage_value_percentage",
+ new_salvage_value_percentage
+ );
frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life = false;
} else if (salvage_value_percentage_changed) {
frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life = true;
- const new_expected_value_after_useful_life = flt(frm.doc.gross_purchase_amount * (row.salvage_value_percentage / 100), precision('gross_purchase_amount'));
- frappe.model.set_value(row.doctype, row.name, "expected_value_after_useful_life", new_expected_value_after_useful_life);
+ const new_expected_value_after_useful_life = flt(
+ frm.doc.gross_purchase_amount * (row.salvage_value_percentage / 100),
+ precision("gross_purchase_amount")
+ );
+ frappe.model.set_value(
+ row.doctype,
+ row.name,
+ "expected_value_after_useful_life",
+ new_expected_value_after_useful_life
+ );
frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life = false;
}
},
});
-frappe.ui.form.on('Asset Finance Book', {
- depreciation_method: function(frm, cdt, cdn) {
+frappe.ui.form.on("Asset Finance Book", {
+ depreciation_method: function (frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
},
- expected_value_after_useful_life: function(frm, cdt, cdn) {
+ expected_value_after_useful_life: function (frm, cdt, cdn) {
const row = locals[cdt][cdn];
if (!frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life) {
- frm.events.set_salvage_value_percentage_or_expected_value_after_useful_life(frm, row, false, true);
+ frm.events.set_salvage_value_percentage_or_expected_value_after_useful_life(
+ frm,
+ row,
+ false,
+ true
+ );
}
frm.events.set_depreciation_rate(frm, row);
},
- salvage_value_percentage: function(frm, cdt, cdn) {
+ salvage_value_percentage: function (frm, cdt, cdn) {
const row = locals[cdt][cdn];
if (!frappe.flags.from_set_salvage_value_percentage_or_expected_value_after_useful_life) {
- frm.events.set_salvage_value_percentage_or_expected_value_after_useful_life(frm, row, true, false);
+ frm.events.set_salvage_value_percentage_or_expected_value_after_useful_life(
+ frm,
+ row,
+ true,
+ false
+ );
}
},
- frequency_of_depreciation: function(frm, cdt, cdn) {
+ frequency_of_depreciation: function (frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
},
- total_number_of_depreciations: function(frm, cdt, cdn) {
+ total_number_of_depreciations: function (frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
},
- rate_of_depreciation: function(frm, cdt, cdn) {
- if(!frappe.flags.dont_change_rate) {
+ rate_of_depreciation: function (frm, cdt, cdn) {
+ if (!frappe.flags.dont_change_rate) {
frappe.model.set_value(cdt, cdn, "expected_value_after_useful_life", 0);
}
frappe.flags.dont_change_rate = false;
},
- depreciation_start_date: function(frm, cdt, cdn) {
+ depreciation_start_date: function (frm, cdt, cdn) {
const book = locals[cdt][cdn];
- if (frm.doc.available_for_use_date && book.depreciation_start_date == frm.doc.available_for_use_date) {
+ if (
+ frm.doc.available_for_use_date &&
+ book.depreciation_start_date == frm.doc.available_for_use_date
+ ) {
frappe.msgprint(__("Depreciation Posting Date should not be equal to Available for Use Date."));
book.depreciation_start_date = "";
frm.refresh_field("finance_books");
}
- }
+ },
});
-erpnext.asset.scrap_asset = function(frm) {
+erpnext.asset.scrap_asset = function (frm) {
frappe.confirm(__("Do you really want to scrap this asset?"), function () {
frappe.call({
args: {
- "asset_name": frm.doc.name
+ asset_name: frm.doc.name,
},
method: "erpnext.assets.doctype.asset.depreciation.scrap_asset",
- callback: function(r) {
- cur_frm.reload_doc();
- }
- })
- })
+ callback: (r) => frm.reload_doc(),
+ });
+ });
};
-erpnext.asset.restore_asset = function(frm) {
+erpnext.asset.restore_asset = function (frm) {
frappe.confirm(__("Do you really want to restore this scrapped asset?"), function () {
frappe.call({
args: {
- "asset_name": frm.doc.name
+ asset_name: frm.doc.name,
},
method: "erpnext.assets.doctype.asset.depreciation.restore_asset",
- callback: function(r) {
- cur_frm.reload_doc();
- }
- })
- })
+ callback: (r) => frm.reload_doc(),
+ });
+ });
};
-erpnext.asset.transfer_asset = function() {
+erpnext.asset.transfer_asset = function (frm) {
frappe.call({
method: "erpnext.assets.doctype.asset.asset.make_asset_movement",
freeze: true,
- args:{
- "assets": [{ name: cur_frm.doc.name }],
- "purpose": "Transfer"
+ args: {
+ assets: [{ name: frm.doc.name }],
+ purpose: "Transfer",
},
callback: function (r) {
if (r.message) {
var doc = frappe.model.sync(r.message)[0];
frappe.set_route("Form", doc.doctype, doc.name);
}
- }
+ },
});
};
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 77cbb90ea8..d31348d158 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -211,9 +211,7 @@ class Asset(AccountsController):
)
if self.is_existing_asset and self.purchase_invoice:
- frappe.throw(
- _("Purchase Invoice cannot be made against an existing asset {0}").format(self.name)
- )
+ frappe.throw(_("Purchase Invoice cannot be made against an existing asset {0}").format(self.name))
def prepare_depreciation_data(self):
if self.calculate_depreciation:
@@ -274,9 +272,9 @@ class Asset(AccountsController):
for d in self.finance_books:
if d.depreciation_start_date == self.available_for_use_date:
frappe.throw(
- _("Row #{}: Depreciation Posting Date should not be equal to Available for Use Date.").format(
- d.idx
- ),
+ _(
+ "Row #{}: Depreciation Posting Date should not be equal to Available for Use Date."
+ ).format(d.idx),
title=_("Incorrect Date"),
)
@@ -285,9 +283,7 @@ class Asset(AccountsController):
self.asset_category = frappe.get_cached_value("Item", self.item_code, "asset_category")
if self.item_code and not self.get("finance_books"):
- finance_books = get_item_details(
- self.item_code, self.asset_category, self.gross_purchase_amount
- )
+ finance_books = get_item_details(self.item_code, self.asset_category, self.gross_purchase_amount)
self.set("finance_books", finance_books)
def validate_finance_books(self):
@@ -337,7 +333,9 @@ class Asset(AccountsController):
and not frappe.db.get_value("Purchase Invoice", self.purchase_invoice, "update_stock")
):
frappe.throw(
- _("Update stock must be enabled for the purchase invoice {0}").format(self.purchase_invoice)
+ _("Update stock must be enabled for the purchase invoice {0}").format(
+ self.purchase_invoice
+ )
)
if not self.calculate_depreciation:
@@ -351,9 +349,7 @@ class Asset(AccountsController):
if self.is_existing_asset:
return
- if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(
- self.purchase_date
- ):
+ if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(self.purchase_date):
frappe.throw(_("Available-for-use Date should be after purchase date"))
def validate_gross_and_purchase_amount(self):
@@ -376,7 +372,7 @@ class Asset(AccountsController):
posting_date, posting_time = frappe.db.get_value(
reference_doctype, reference_docname, ["posting_date", "posting_time"]
)
- transaction_date = get_datetime("{} {}".format(posting_date, posting_time))
+ transaction_date = get_datetime(f"{posting_date} {posting_time}")
assets = [
{
"asset": self.name,
@@ -416,7 +412,8 @@ class Asset(AccountsController):
if not row.depreciation_start_date:
if not self.available_for_use_date:
frappe.throw(
- _("Row {0}: Depreciation Start Date is required").format(row.idx), title=_("Invalid Schedule")
+ _("Row {0}: Depreciation Start Date is required").format(row.idx),
+ title=_("Invalid Schedule"),
)
row.depreciation_start_date = get_last_day(self.available_for_use_date)
@@ -446,9 +443,7 @@ class Asset(AccountsController):
title=_("Invalid Schedule"),
)
- if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(
- self.purchase_date
- ):
+ if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(self.purchase_date):
frappe.throw(
_("Depreciation Row {0}: Next Depreciation Date cannot be before Purchase Date").format(
row.idx
@@ -578,11 +573,14 @@ class Asset(AccountsController):
if self.calculate_depreciation:
idx = self.get_default_finance_book_idx() or 0
- expected_value_after_useful_life = self.finance_books[idx].expected_value_after_useful_life
+ expected_value_after_useful_life = self.finance_books[
+ idx
+ ].expected_value_after_useful_life
value_after_depreciation = self.finance_books[idx].value_after_depreciation
if (
- flt(value_after_depreciation) <= expected_value_after_useful_life or self.is_fully_depreciated
+ flt(value_after_depreciation) <= expected_value_after_useful_life
+ or self.is_fully_depreciated
):
status = "Fully Depreciated"
elif flt(value_after_depreciation) < flt(self.gross_purchase_amount):
@@ -615,9 +613,7 @@ class Asset(AccountsController):
@frappe.whitelist()
def get_manual_depreciation_entries(self):
- (_, _, depreciation_expense_account) = get_depreciation_accounts(
- self.asset_category, self.company
- )
+ (_, _, depreciation_expense_account) = get_depreciation_accounts(self.asset_category, self.company)
gle = frappe.qb.DocType("GL Entry")
@@ -757,7 +753,8 @@ class Asset(AccountsController):
if args.get("depreciation_method") == "Double Declining Balance":
return 200.0 / (
(
- flt(args.get("total_number_of_depreciations"), 2) * flt(args.get("frequency_of_depreciation"))
+ flt(args.get("total_number_of_depreciations"), 2)
+ * flt(args.get("frequency_of_depreciation"))
)
/ 12
)
@@ -801,9 +798,7 @@ def update_maintenance_status():
asset = frappe.get_doc("Asset", asset.name)
if frappe.db.exists("Asset Repair", {"asset_name": asset.name, "repair_status": "Pending"}):
asset.set_status("Out of Order")
- elif frappe.db.exists(
- "Asset Maintenance Task", {"parent": asset.name, "next_due_date": today()}
- ):
+ elif frappe.db.exists("Asset Maintenance Task", {"parent": asset.name, "next_due_date": today()}):
asset.set_status("In Maintenance")
else:
asset.set_status()
@@ -887,9 +882,7 @@ def create_asset_capitalization(asset):
@frappe.whitelist()
def create_asset_value_adjustment(asset, asset_category, company):
asset_value_adjustment = frappe.new_doc("Asset Value Adjustment")
- asset_value_adjustment.update(
- {"asset": asset, "company": company, "asset_category": asset_category}
- )
+ asset_value_adjustment.update({"asset": asset, "company": company, "asset_category": asset_category})
return asset_value_adjustment
@@ -925,6 +918,8 @@ def get_item_details(item_code, asset_category, gross_purchase_amount):
"depreciation_method": d.depreciation_method,
"total_number_of_depreciations": d.total_number_of_depreciations,
"frequency_of_depreciation": d.frequency_of_depreciation,
+ "daily_prorata_based": d.daily_prorata_based,
+ "shift_based": d.shift_based,
"salvage_value_percentage": d.salvage_value_percentage,
"expected_value_after_useful_life": flt(gross_purchase_amount)
* flt(d.salvage_value_percentage / 100),
@@ -944,18 +939,14 @@ def get_asset_account(account_name, asset=None, asset_category=None, company=Non
)
if not asset and not account:
- account = get_asset_category_account(
- account_name, asset_category=asset_category, company=company
- )
+ account = get_asset_category_account(account_name, asset_category=asset_category, company=company)
if not account:
account = frappe.get_cached_value("Company", company, account_name)
if not account:
if not asset_category:
- frappe.throw(
- _("Set {0} in company {1}").format(account_name.replace("_", " ").title(), company)
- )
+ frappe.throw(_("Set {0} in company {1}").format(account_name.replace("_", " ").title(), company))
else:
frappe.throw(
_("Set {0} in asset category {1} or company {2}").format(
@@ -1055,7 +1046,7 @@ def split_asset(asset_name, split_qty):
split_qty = cint(split_qty)
if split_qty >= asset.asset_quantity:
- frappe.throw(_("Split qty cannot be greater than or equal to asset qty"))
+ frappe.throw(_("Split qty cannot be grater than or equal to asset qty"))
remaining_qty = asset.asset_quantity - split_qty
@@ -1085,15 +1076,11 @@ def update_existing_asset(asset, remaining_qty, new_asset_name):
add_asset_activity(
asset.name,
- _("Asset updated after being split into Asset {0}").format(
- get_link_to_form("Asset", new_asset_name)
- ),
+ _("Asset updated after being split into Asset {0}").format(get_link_to_form("Asset", new_asset_name)),
)
for row in asset.get("finance_books"):
- value_after_depreciation = flt(
- (row.value_after_depreciation * remaining_qty) / asset.asset_quantity
- )
+ value_after_depreciation = flt((row.value_after_depreciation * remaining_qty) / asset.asset_quantity)
expected_value_after_useful_life = flt(
(row.expected_value_after_useful_life * remaining_qty) / asset.asset_quantity
)
@@ -1107,9 +1094,7 @@ def update_existing_asset(asset, remaining_qty, new_asset_name):
expected_value_after_useful_life,
)
- current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(
- asset.name, "Active", row.finance_book
- )
+ current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, "Active", row.finance_book)
new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc)
new_asset_depr_schedule_doc.set_draft_asset_depr_schedule_details(asset, row)
@@ -1124,9 +1109,7 @@ def update_existing_asset(asset, remaining_qty, new_asset_name):
notes = _(
"This schedule was created when Asset {0} was updated after being split into new Asset {1}."
- ).format(
- get_link_to_form(asset.doctype, asset.name), get_link_to_form(asset.doctype, new_asset_name)
- )
+ ).format(get_link_to_form(asset.doctype, asset.name), get_link_to_form(asset.doctype, new_asset_name))
new_asset_depr_schedule_doc.notes = notes
current_asset_depr_schedule_doc.flags.should_not_cancel_depreciation_entries = True
@@ -1150,9 +1133,7 @@ def create_new_asset_after_split(asset, split_qty):
new_asset.split_from = asset.name
for row in new_asset.get("finance_books"):
- row.value_after_depreciation = flt(
- (row.value_after_depreciation * split_qty) / asset.asset_quantity
- )
+ row.value_after_depreciation = flt((row.value_after_depreciation * split_qty) / asset.asset_quantity)
row.expected_value_after_useful_life = flt(
(row.expected_value_after_useful_life * split_qty) / asset.asset_quantity
)
@@ -1161,18 +1142,14 @@ def create_new_asset_after_split(asset, split_qty):
add_asset_activity(
new_asset.name,
- _("Asset created after being split from Asset {0}").format(
- get_link_to_form("Asset", asset.name)
- ),
+ _("Asset created after being split from Asset {0}").format(get_link_to_form("Asset", asset.name)),
)
new_asset.submit()
new_asset.set_status()
for row in new_asset.get("finance_books"):
- current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(
- asset.name, "Active", row.finance_book
- )
+ current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, "Active", row.finance_book)
new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc)
new_asset_depr_schedule_doc.set_draft_asset_depr_schedule_details(new_asset, row)
diff --git a/erpnext/assets/doctype/asset/asset_list.js b/erpnext/assets/doctype/asset/asset_list.js
index e587e1dc71..712958adcf 100644
--- a/erpnext/assets/doctype/asset/asset_list.js
+++ b/erpnext/assets/doctype/asset/asset_list.js
@@ -1,56 +1,46 @@
-frappe.listview_settings['Asset'] = {
- add_fields: ['status'],
+frappe.listview_settings["Asset"] = {
+ add_fields: ["status"],
get_indicator: function (doc) {
if (doc.status === "Fully Depreciated") {
return [__("Fully Depreciated"), "green", "status,=,Fully Depreciated"];
-
} else if (doc.status === "Partially Depreciated") {
- return [__("Partially Depreciated"), "gray", "status,=,Partially Depreciated"];
-
+ return [__("Partially Depreciated"), "grey", "status,=,Partially Depreciated"];
} else if (doc.status === "Sold") {
return [__("Sold"), "green", "status,=,Sold"];
-
} else if (["Capitalized", "Decapitalized"].includes(doc.status)) {
return [__(doc.status), "grey", "status,=," + doc.status];
-
} else if (doc.status === "Scrapped") {
- return [__("Scrapped"), "gray", "status,=,Scrapped"];
-
+ return [__("Scrapped"), "grey", "status,=,Scrapped"];
} else if (doc.status === "In Maintenance") {
return [__("In Maintenance"), "orange", "status,=,In Maintenance"];
-
} else if (doc.status === "Out of Order") {
- return [__("Out of Order"), "gray", "status,=,Out of Order"];
-
+ return [__("Out of Order"), "grey", "status,=,Out of Order"];
} else if (doc.status === "Issue") {
return [__("Issue"), "orange", "status,=,Issue"];
-
} else if (doc.status === "Receipt") {
return [__("Receipt"), "green", "status,=,Receipt"];
-
} else if (doc.status === "Submitted") {
return [__("Submitted"), "blue", "status,=,Submitted"];
-
} else if (doc.status === "Draft") {
return [__("Draft"), "red", "status,=,Draft"];
}
},
- onload: function(me) {
- me.page.add_action_item(__('Make Asset Movement'), function() {
+ onload: function (me) {
+ me.page.add_action_item(__("Make Asset Movement"), function () {
const assets = me.get_checked_items();
frappe.call({
method: "erpnext.assets.doctype.asset.asset.make_asset_movement",
freeze: true,
- args:{
- "assets": assets
+ args: {
+ assets: assets,
},
callback: function (r) {
if (r.message) {
var doc = frappe.model.sync(r.message)[0];
frappe.set_route("Form", doc.doctype, doc.name);
}
- }
+ },
});
});
},
-}
\ No newline at end of file
+};
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index 6af057d642..93f32b43b4 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -36,7 +36,7 @@ from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_sched
def post_depreciation_entries(date=None):
# Return if automatic booking of asset depreciation is disabled
if not cint(
- frappe.db.get_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically")
+ frappe.db.get_single_value("Accounts Settings", "book_asset_depreciation_entry_automatically")
):
return
@@ -71,7 +71,10 @@ def post_depreciation_entries(date=None):
) not in credit_and_debit_accounts_for_asset_category_and_company:
credit_and_debit_accounts_for_asset_category_and_company.update(
{
- (asset_category, asset_company): get_credit_and_debit_accounts_for_asset_category_and_company(
+ (
+ asset_category,
+ asset_company,
+ ): get_credit_and_debit_accounts_for_asset_category_and_company(
asset_category, asset_company
),
}
@@ -135,9 +138,7 @@ def get_depreciable_asset_depr_schedules_data(date):
def make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date=None):
for row in asset_doc.get("finance_books"):
- asset_depr_schedule_name = get_asset_depr_schedule_name(
- asset_doc.name, "Active", row.finance_book
- )
+ asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, "Active", row.finance_book)
make_depreciation_entry(asset_depr_schedule_name, date)
@@ -147,9 +148,7 @@ def get_acc_frozen_upto():
if not acc_frozen_upto:
return
- frozen_accounts_modifier = frappe.db.get_single_value(
- "Accounts Settings", "frozen_accounts_modifier"
- )
+ frozen_accounts_modifier = frappe.db.get_single_value("Accounts Settings", "frozen_accounts_modifier")
if frozen_accounts_modifier not in frappe.get_roles() or frappe.session.user == "Administrator":
return getdate(acc_frozen_upto)
@@ -278,7 +277,7 @@ def _make_journal_entry_for_depreciation(
je.posting_date = depr_schedule.schedule_date
je.company = asset.company
je.finance_book = asset_depr_schedule_doc.finance_book
- je.remark = "Depreciation Entry against {0} worth {1}".format(
+ je.remark = frappe._("Depreciation Entry against {} worth {}").format(
asset.name, depr_schedule.depreciation_amount
)
@@ -362,11 +361,7 @@ def get_depreciation_accounts(asset_category, company):
if not depreciation_expense_account:
depreciation_expense_account = accounts[1]
- if (
- not fixed_asset_account
- or not accumulated_depreciation_account
- or not depreciation_expense_account
- ):
+ if not fixed_asset_account or not accumulated_depreciation_account or not depreciation_expense_account:
frappe.throw(
_("Please set Depreciation related Accounts in Asset Category {0} or Company {1}").format(
asset_category, company
@@ -444,9 +439,7 @@ def scrap_asset(asset_name):
if asset.docstatus != 1:
frappe.throw(_("Asset {0} must be submitted").format(asset.name))
elif asset.status in ("Cancelled", "Sold", "Scrapped", "Capitalized", "Decapitalized"):
- frappe.throw(
- _("Asset {0} cannot be scrapped, as it is already {1}").format(asset.name, asset.status)
- )
+ frappe.throw(_("Asset {0} cannot be scrapped, as it is already {1}").format(asset.name, asset.status))
date = today()
@@ -457,16 +450,14 @@ def scrap_asset(asset_name):
depreciate_asset(asset, date, notes)
asset.reload()
- depreciation_series = frappe.get_cached_value(
- "Company", asset.company, "series_for_depreciation_entry"
- )
+ depreciation_series = frappe.get_cached_value("Company", asset.company, "series_for_depreciation_entry")
je = frappe.new_doc("Journal Entry")
je.voucher_type = "Journal Entry"
je.naming_series = depreciation_series
je.posting_date = date
je.company = asset.company
- je.remark = "Scrap Entry for asset {0}".format(asset_name)
+ je.remark = f"Scrap Entry for asset {asset_name}"
for entry in get_gl_entries_on_asset_disposal(asset, date):
entry.update({"reference_type": "Asset", "reference_name": asset_name})
@@ -514,9 +505,7 @@ def depreciate_asset(asset_doc, date, notes):
asset_doc.flags.ignore_validate_update_after_submit = True
- make_new_active_asset_depr_schedules_and_cancel_current_ones(
- asset_doc, notes, date_of_disposal=date
- )
+ make_new_active_asset_depr_schedules_and_cancel_current_ones(asset_doc, notes, date_of_disposal=date)
asset_doc.save()
@@ -537,9 +526,7 @@ def reset_depreciation_schedule(asset_doc, date, notes):
asset_doc.flags.ignore_validate_update_after_submit = True
- make_new_active_asset_depr_schedules_and_cancel_current_ones(
- asset_doc, notes, date_of_return=date
- )
+ make_new_active_asset_depr_schedules_and_cancel_current_ones(asset_doc, notes, date_of_return=date)
modify_depreciation_schedule_for_asset_repairs(asset_doc, notes)
@@ -782,9 +769,7 @@ def get_disposal_account_and_cost_center(company):
)
if not disposal_account:
- frappe.throw(
- _("Please set 'Gain/Loss Account on Asset Disposal' in Company {0}").format(company)
- )
+ frappe.throw(_("Please set 'Gain/Loss Account on Asset Disposal' in Company {0}").format(company))
if not depreciation_cost_center:
frappe.throw(_("Please set 'Asset Depreciation Cost Center' in Company {0}").format(company))
@@ -797,7 +782,7 @@ def get_value_after_depreciation_on_disposal_date(asset, disposal_date, finance_
if asset_doc.available_for_use_date > getdate(disposal_date):
frappe.throw(
- "Disposal date {0} cannot be before available for use date {1} of the asset.".format(
+ "Disposal date {} cannot be before available for use date {} of the asset.".format(
disposal_date, asset_doc.available_for_use_date
)
)
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index bb6b102b62..a634550089 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -49,10 +49,12 @@ class AssetSetup(unittest.TestCase):
enable_cwip_accounting("Computers")
make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location")
frappe.db.sql("delete from `tabTax Rule`")
+ set_system_settings(3) # @dokos
@classmethod
def tearDownClass(cls):
frappe.db.rollback()
+ set_system_settings() # @dokos
class TestAsset(AssetSetup):
@@ -109,9 +111,7 @@ class TestAsset(AssetSetup):
self.assertRaises(frappe.ValidationError, asset.save)
def test_purchase_asset(self):
- pr = make_purchase_receipt(
- item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location"
- )
+ pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location")
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, "name")
asset = frappe.get_doc("Asset", asset_name)
@@ -211,7 +211,7 @@ class TestAsset(AssetSetup):
)
first_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Active")
post_depreciation_entries(date=add_months(purchase_date, 2))
asset.load_from_db()
@@ -220,25 +220,29 @@ class TestAsset(AssetSetup):
asset.gross_purchase_amount - asset.finance_books[0].value_after_depreciation,
asset.precision("gross_purchase_amount"),
)
- self.assertEquals(accumulated_depr_amount, 18000.0)
+ self.assertEqual(accumulated_depr_amount, 18000.0)
scrap_asset(asset.name)
asset.load_from_db()
first_asset_depr_schedule.load_from_db()
second_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(second_asset_depr_schedule.status, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
+ self.assertEqual(second_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Cancelled")
accumulated_depr_amount = flt(
asset.gross_purchase_amount - asset.finance_books[0].value_after_depreciation,
asset.precision("gross_purchase_amount"),
)
pro_rata_amount, _, _ = _get_pro_rata_amt(
- asset.finance_books[0], 9000, get_last_day(add_months(purchase_date, 1)), date
+ asset.finance_books[0],
+ 9000,
+ get_last_day(add_months(purchase_date, 1)),
+ date,
+ original_schedule_date=get_last_day(nowdate()),
)
pro_rata_amount = flt(pro_rata_amount, asset.precision("gross_purchase_amount"))
- self.assertEquals(
+ self.assertEqual(
accumulated_depr_amount,
flt(18000.0 + pro_rata_amount, asset.precision("gross_purchase_amount")),
)
@@ -267,8 +271,8 @@ class TestAsset(AssetSetup):
second_asset_depr_schedule.load_from_db()
third_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(third_asset_depr_schedule.status, "Active")
- self.assertEquals(second_asset_depr_schedule.status, "Cancelled")
+ self.assertEqual(third_asset_depr_schedule.status, "Active")
+ self.assertEqual(second_asset_depr_schedule.status, "Cancelled")
asset.load_from_db()
self.assertFalse(asset.journal_entry_for_scrap)
@@ -280,7 +284,7 @@ class TestAsset(AssetSetup):
)
this_month_depr_amount = 9000.0 if is_last_day_of_the_month(date) else 0
- self.assertEquals(accumulated_depr_amount, 18000.0 + this_month_depr_amount)
+ self.assertEqual(accumulated_depr_amount, 18000.0 + this_month_depr_amount)
def test_gle_made_by_asset_sale(self):
date = nowdate()
@@ -297,7 +301,7 @@ class TestAsset(AssetSetup):
)
first_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Active")
post_depreciation_entries(date=add_months(purchase_date, 2))
@@ -313,11 +317,15 @@ class TestAsset(AssetSetup):
first_asset_depr_schedule.load_from_db()
second_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(second_asset_depr_schedule.status, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
+ self.assertEqual(second_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Cancelled")
pro_rata_amount, _, _ = _get_pro_rata_amt(
- asset.finance_books[0], 9000, get_last_day(add_months(purchase_date, 1)), date
+ asset.finance_books[0],
+ 9000,
+ get_last_day(add_months(purchase_date, 1)),
+ date,
+ original_schedule_date=get_last_day(nowdate()),
)
pro_rata_amount = flt(pro_rata_amount, asset.precision("gross_purchase_amount"))
@@ -335,7 +343,6 @@ class TestAsset(AssetSetup):
),
("Debtors - _TC", 25000.0, 0.0),
)
-
gle = get_gl_entries("Sales Invoice", si.name)
self.assertSequenceEqual(gle, expected_gle)
@@ -382,7 +389,7 @@ class TestAsset(AssetSetup):
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Sold")
- expected_values = [["2023-03-31", 12000, 36000], ["2023-05-23", 1742.47, 37742.47]]
+ expected_values = [["2023-03-31", 12000, 36000], ["2023-05-23", 1737.7, 37737.7]]
second_asset_depr_schedule = get_depr_schedule(asset.name, "Active")
@@ -395,7 +402,7 @@ class TestAsset(AssetSetup):
expected_gle = (
(
"_Test Accumulated Depreciations - _TC",
- 37742.47,
+ 37737.7,
0.0,
),
(
@@ -406,7 +413,7 @@ class TestAsset(AssetSetup):
(
"_Test Gain/Loss on Asset Disposal - _TC",
0.0,
- 17742.47,
+ 17737.7,
),
("Debtors - _TC", 40000.0, 0.0),
)
@@ -459,7 +466,7 @@ class TestAsset(AssetSetup):
)
first_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Active")
post_depreciation_entries(date="2021-01-01")
@@ -473,9 +480,9 @@ class TestAsset(AssetSetup):
second_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
first_asset_depr_schedule_of_new_asset = get_asset_depr_schedule_doc(new_asset.name, "Active")
- self.assertEquals(second_asset_depr_schedule.status, "Active")
- self.assertEquals(first_asset_depr_schedule_of_new_asset.status, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
+ self.assertEqual(second_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule_of_new_asset.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Cancelled")
depr_schedule_of_asset = second_asset_depr_schedule.get("depreciation_schedule")
depr_schedule_of_new_asset = first_asset_depr_schedule_of_new_asset.get("depreciation_schedule")
@@ -507,9 +514,7 @@ class TestAsset(AssetSetup):
self.assertEqual(jv.accounts[3].reference_name, new_asset.name)
def test_expense_head(self):
- pr = make_purchase_receipt(
- item_code="Macbook Pro", qty=2, rate=200000.0, location="Test Location"
- )
+ pr = make_purchase_receipt(item_code="Macbook Pro", qty=2, rate=200000.0, location="Test Location")
doc = make_invoice(pr.name)
self.assertEqual("Asset Received But Not Billed - _TC", doc.items[0].expense_account)
@@ -619,9 +624,7 @@ class TestAsset(AssetSetup):
self.assertFalse(gle)
# case 1 -- PR with cwip disabled, Asset with cwip enabled
- pr = make_purchase_receipt(
- item_code="Macbook Pro", qty=1, rate=200000.0, location="Test Location"
- )
+ pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=200000.0, location="Test Location")
frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", 1)
frappe.db.set_value("Asset Category Account", name, "capital_work_in_progress_account", cwip_acc)
asset = frappe.db.get_value("Asset", {"purchase_receipt": pr.name, "docstatus": 0}, "name")
@@ -633,9 +636,7 @@ class TestAsset(AssetSetup):
self.assertFalse(gle)
# case 2 -- PR with cwip enabled, Asset with cwip disabled
- pr = make_purchase_receipt(
- item_code="Macbook Pro", qty=1, rate=200000.0, location="Test Location"
- )
+ pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=200000.0, location="Test Location")
frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", 0)
asset = frappe.db.get_value("Asset", {"purchase_receipt": pr.name, "docstatus": 0}, "name")
asset_doc = frappe.get_doc("Asset", asset)
@@ -702,6 +703,41 @@ class TestDepreciationMethods(AssetSetup):
self.assertEqual(schedules, expected_schedules)
+ def test_schedule_for_straight_line_method_with_daily_prorata_based(
+ self,
+ ):
+ asset = create_asset(
+ calculate_depreciation=1,
+ available_for_use_date="2023-01-01",
+ purchase_date="2023-01-01",
+ gross_purchase_amount=12000,
+ depreciation_start_date="2023-01-31",
+ total_number_of_depreciations=12,
+ frequency_of_depreciation=1,
+ daily_prorata_based=1,
+ )
+
+ expected_schedules = [
+ ["2023-01-31", 1019.18, 1019.18],
+ ["2023-02-28", 920.55, 1939.73],
+ ["2023-03-31", 1019.18, 2958.91],
+ ["2023-04-30", 986.3, 3945.21],
+ ["2023-05-31", 1019.18, 4964.39],
+ ["2023-06-30", 986.3, 5950.69],
+ ["2023-07-31", 1019.18, 6969.87],
+ ["2023-08-31", 1019.18, 7989.05],
+ ["2023-09-30", 986.3, 8975.35],
+ ["2023-10-31", 1019.18, 9994.53],
+ ["2023-11-30", 986.3, 10980.83],
+ ["2023-12-31", 1019.17, 12000.0],
+ ]
+
+ schedules = [
+ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
+ for d in get_depr_schedule(asset.name, "Draft")
+ ]
+ self.assertEqual(schedules, expected_schedules)
+
def test_schedule_for_straight_line_method_for_existing_asset(self):
asset = create_asset(
calculate_depreciation=1,
@@ -739,9 +775,9 @@ class TestDepreciationMethods(AssetSetup):
self.assertEqual(asset.status, "Draft")
expected_schedules = [
- ["2030-12-31", 66666.70, 66666.70],
- ["2031-12-31", 22222.21, 88888.91],
- ["2032-12-31", 1111.09, 90000.0],
+ ["2030-12-31", 66667.00, 66667.00],
+ ["2031-12-31", 22222.11, 88889.11],
+ ["2032-12-31", 1110.89, 90000.0],
]
schedules = [
@@ -767,7 +803,7 @@ class TestDepreciationMethods(AssetSetup):
self.assertEqual(asset.status, "Draft")
- expected_schedules = [["2031-12-31", 33333.35, 83333.35], ["2032-12-31", 6666.65, 90000.0]]
+ expected_schedules = [["2031-12-31", 33333.50, 83333.50], ["2032-12-31", 6666.50, 90000.0]]
schedules = [
[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
@@ -885,12 +921,12 @@ class TestDepreciationMethods(AssetSetup):
)
expected_schedules = [
- ["2022-02-28", 310.88, 310.88],
- ["2022-03-31", 654.42, 965.30],
- ["2022-04-30", 654.42, 1619.72],
- ["2022-05-31", 654.42, 2274.14],
- ["2022-06-30", 654.42, 2928.56],
- ["2022-07-15", 2071.44, 5000.0],
+ ["2022-02-28", 310.89, 310.89],
+ ["2022-03-31", 654.45, 965.34],
+ ["2022-04-30", 654.45, 1619.79],
+ ["2022-05-31", 654.45, 2274.24],
+ ["2022-06-30", 654.45, 2928.69],
+ ["2022-07-15", 2071.31, 5000.0],
]
schedules = [
@@ -968,7 +1004,7 @@ class TestDepreciationBasics(AssetSetup):
asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, "Active")
- depreciation_amount = get_depreciation_amount(
+ depreciation_amount, prev_per_day_depr = get_depreciation_amount(
asset_depr_schedule_doc, asset, 100000, 100000, asset.finance_books[0]
)
self.assertEqual(depreciation_amount, 30000)
@@ -1214,8 +1250,7 @@ class TestDepreciationBasics(AssetSetup):
je = frappe.get_doc("Journal Entry", get_depr_schedule(asset.name, "Active")[0].journal_entry)
accounting_entries = [
- {"account": entry.account, "debit": entry.debit, "credit": entry.credit}
- for entry in je.accounts
+ {"account": entry.account, "debit": entry.debit, "credit": entry.credit} for entry in je.accounts
]
for entry in accounting_entries:
@@ -1250,8 +1285,7 @@ class TestDepreciationBasics(AssetSetup):
je = frappe.get_doc("Journal Entry", get_depr_schedule(asset.name, "Active")[0].journal_entry)
accounting_entries = [
- {"account": entry.account, "debit": entry.debit, "credit": entry.credit}
- for entry in je.accounts
+ {"account": entry.account, "debit": entry.debit, "credit": entry.credit} for entry in je.accounts
]
for entry in accounting_entries:
@@ -1332,21 +1366,15 @@ class TestDepreciationBasics(AssetSetup):
post_depreciation_entries(date="2020-04-01")
asset.load_from_db()
- asset_depr_schedule_doc_1 = get_asset_depr_schedule_doc(
- asset.name, "Active", "Test Finance Book 1"
- )
+ asset_depr_schedule_doc_1 = get_asset_depr_schedule_doc(asset.name, "Active", "Test Finance Book 1")
asset_depr_schedule_doc_1.clear_depr_schedule()
self.assertEqual(len(asset_depr_schedule_doc_1.get("depreciation_schedule")), 3)
- asset_depr_schedule_doc_2 = get_asset_depr_schedule_doc(
- asset.name, "Active", "Test Finance Book 2"
- )
+ asset_depr_schedule_doc_2 = get_asset_depr_schedule_doc(asset.name, "Active", "Test Finance Book 2")
asset_depr_schedule_doc_2.clear_depr_schedule()
self.assertEqual(len(asset_depr_schedule_doc_2.get("depreciation_schedule")), 3)
- asset_depr_schedule_doc_3 = get_asset_depr_schedule_doc(
- asset.name, "Active", "Test Finance Book 3"
- )
+ asset_depr_schedule_doc_3 = get_asset_depr_schedule_doc(asset.name, "Active", "Test Finance Book 3")
asset_depr_schedule_doc_3.clear_depr_schedule()
self.assertEqual(len(asset_depr_schedule_doc_3.get("depreciation_schedule")), 0)
@@ -1378,14 +1406,10 @@ class TestDepreciationBasics(AssetSetup):
)
asset.save()
- asset_depr_schedule_doc_1 = get_asset_depr_schedule_doc(
- asset.name, "Draft", "Test Finance Book 1"
- )
+ asset_depr_schedule_doc_1 = get_asset_depr_schedule_doc(asset.name, "Draft", "Test Finance Book 1")
self.assertEqual(len(asset_depr_schedule_doc_1.get("depreciation_schedule")), 3)
- asset_depr_schedule_doc_2 = get_asset_depr_schedule_doc(
- asset.name, "Draft", "Test Finance Book 2"
- )
+ asset_depr_schedule_doc_2 = get_asset_depr_schedule_doc(asset.name, "Draft", "Test Finance Book 2")
self.assertEqual(len(asset_depr_schedule_doc_2.get("depreciation_schedule")), 6)
def test_depreciation_entry_cancellation(self):
@@ -1487,13 +1511,13 @@ class TestDepreciationBasics(AssetSetup):
asset.finance_books[0].expected_value_after_useful_life = 100
asset.save()
asset.reload()
- self.assertEquals(asset.finance_books[0].value_after_depreciation, 98000.0)
+ self.assertEqual(asset.finance_books[0].value_after_depreciation, 98000.0)
# changing expected_value_after_useful_life shouldn't affect value_after_depreciation
asset.finance_books[0].expected_value_after_useful_life = 200
asset.save()
asset.reload()
- self.assertEquals(asset.finance_books[0].value_after_depreciation, 98000.0)
+ self.assertEqual(asset.finance_books[0].value_after_depreciation, 98000.0)
def test_asset_cost_center(self):
asset = create_asset(is_existing_asset=1, do_not_save=1)
@@ -1630,6 +1654,15 @@ class TestDepreciationBasics(AssetSetup):
self.assertTrue(get_gl_entries("Purchase Receipt", pr.name))
+def set_system_settings(float_precision=2, currency_precision=2):
+ # @dokos set number and currency precision to match tests calculation results
+ system_settings = frappe.get_doc("System Settings")
+ system_settings.float_precision = float_precision
+ system_settings.currency_precision = currency_precision
+ system_settings.rounding_method = "Banker's Rounding"
+ system_settings.save()
+
+
def get_gl_entries(doctype, docname):
gl_entry = frappe.qb.DocType("GL Entry")
return (
@@ -1701,6 +1734,9 @@ def create_asset(**args):
"total_number_of_depreciations": args.total_number_of_depreciations or 5,
"expected_value_after_useful_life": args.expected_value_after_useful_life or 0,
"depreciation_start_date": args.depreciation_start_date,
+ "daily_prorata_based": args.daily_prorata_based or 0,
+ "shift_based": args.shift_based or 0,
+ "rate_of_depreciation": args.rate_of_depreciation or 0,
},
)
@@ -1716,12 +1752,12 @@ def create_asset(**args):
return asset
-def create_asset_category():
+def create_asset_category(enable_cwip=1):
asset_category = frappe.new_doc("Asset Category")
asset_category.asset_category_name = "Computers"
asset_category.total_number_of_depreciations = 3
asset_category.frequency_of_depreciation = 3
- asset_category.enable_cwip_accounting = 1
+ asset_category.enable_cwip_accounting = enable_cwip
asset_category.append(
"accounts",
{
diff --git a/erpnext/assets/doctype/asset_activity/asset_activity.json b/erpnext/assets/doctype/asset_activity/asset_activity.json
index 2c883a0b21..96110611d0 100644
--- a/erpnext/assets/doctype/asset_activity/asset_activity.json
+++ b/erpnext/assets/doctype/asset_activity/asset_activity.json
@@ -75,7 +75,7 @@
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2023-09-29 15:56:17.608643",
+ "modified": "2024-03-27 13:06:32.933603",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Activity",
@@ -106,7 +106,7 @@
"share": 1
}
],
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": []
}
diff --git a/erpnext/assets/doctype/asset_activity/asset_activity.py b/erpnext/assets/doctype/asset_activity/asset_activity.py
index 0b3c313879..7177223b4f 100644
--- a/erpnext/assets/doctype/asset_activity/asset_activity.py
+++ b/erpnext/assets/doctype/asset_activity/asset_activity.py
@@ -7,6 +7,20 @@ from frappe.utils import now_datetime
class AssetActivity(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ asset: DF.Link
+ date: DF.Datetime
+ subject: DF.SmallText
+ user: DF.Link
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js
index 110f2c4f2a..651b75d0a7 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js
@@ -3,10 +3,9 @@
frappe.provide("erpnext.assets");
-
erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.stock.StockController {
setup() {
- this.frm.ignore_doctypes_on_cancel_all = ['Serial and Batch Bundle', 'Asset Movement'];
+ this.frm.ignore_doctypes_on_cancel_all = ["Serial and Batch Bundle", "Asset Movement"];
this.setup_posting_date_time_check();
}
@@ -17,7 +16,10 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
refresh() {
this.show_general_ledger();
- if ((this.frm.doc.stock_items && this.frm.doc.stock_items.length) || !this.frm.doc.target_is_fixed_asset) {
+ if (
+ (this.frm.doc.stock_items && this.frm.doc.stock_items.length) ||
+ !this.frm.doc.target_is_fixed_asset
+ ) {
this.show_stock_ledger();
}
@@ -32,32 +34,32 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
me.setup_warehouse_query();
- me.frm.set_query("target_item_code", function() {
+ me.frm.set_query("target_item_code", function () {
if (me.frm.doc.entry_type == "Capitalization") {
- return erpnext.queries.item({"is_stock_item": 0, "is_fixed_asset": 1});
+ return erpnext.queries.item({ is_stock_item: 0, is_fixed_asset: 1 });
} else {
- return erpnext.queries.item({"is_stock_item": 1, "is_fixed_asset": 0});
+ return erpnext.queries.item({ is_stock_item: 1, is_fixed_asset: 0 });
}
});
- me.frm.set_query("target_asset", function() {
+ me.frm.set_query("target_asset", function () {
return {
- filters: {'is_composite_asset': 1, 'docstatus': 0 }
- }
+ filters: { is_composite_asset: 1, docstatus: 0 },
+ };
});
- me.frm.set_query("asset", "asset_items", function() {
+ me.frm.set_query("asset", "asset_items", function () {
var filters = {
- 'status': ["not in", ["Draft", "Scrapped", "Sold", "Capitalized", "Decapitalized"]],
- 'docstatus': 1
+ status: ["not in", ["Draft", "Scrapped", "Sold", "Capitalized", "Decapitalized"]],
+ docstatus: 1,
};
if (me.frm.doc.target_asset) {
- filters['name'] = ['!=', me.frm.doc.target_asset];
+ filters["name"] = ["!=", me.frm.doc.target_asset];
}
return {
- filters: filters
+ filters: filters,
};
});
@@ -65,58 +67,67 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
let row = locals[cdt][cdn];
return {
filters: {
- 'item_code': row.item_code,
- 'voucher_type': doc.doctype,
- 'voucher_no': ["in", [doc.name, ""]],
- 'is_cancelled': 0,
- }
- }
+ item_code: row.item_code,
+ voucher_type: doc.doctype,
+ voucher_no: ["in", [doc.name, ""]],
+ is_cancelled: 0,
+ },
+ };
});
- me.frm.set_query("item_code", "stock_items", function() {
- return erpnext.queries.item({"is_stock_item": 1});
+ me.frm.set_query("item_code", "stock_items", function () {
+ return erpnext.queries.item({ is_stock_item: 1 });
});
- me.frm.set_query("item_code", "service_items", function() {
- return erpnext.queries.item({"is_stock_item": 0, "is_fixed_asset": 0});
+ me.frm.set_query("item_code", "service_items", function () {
+ return erpnext.queries.item({ is_stock_item: 0, is_fixed_asset: 0 });
});
- me.frm.set_query('batch_no', 'stock_items', function(doc, cdt, cdn) {
+ me.frm.set_query("batch_no", "stock_items", function (doc, cdt, cdn) {
var item = locals[cdt][cdn];
if (!item.item_code) {
frappe.throw(__("Please enter Item Code to get Batch Number"));
} else {
var filters = {
- 'item_code': item.item_code,
- 'posting_date': me.frm.doc.posting_date || frappe.datetime.nowdate(),
- 'warehouse': item.warehouse
+ item_code: item.item_code,
+ posting_date: me.frm.doc.posting_date || frappe.datetime.nowdate(),
+ warehouse: item.warehouse,
};
return {
query: "erpnext.controllers.queries.get_batch_no",
- filters: filters
+ filters: filters,
};
}
});
- me.frm.set_query('expense_account', 'service_items', function() {
+ me.frm.set_query("expense_account", "service_items", function () {
return {
filters: {
- "account_type": ['in', ["Tax", "Expense Account", "Income Account", "Expenses Included In Valuation", "Expenses Included In Asset Valuation"]],
- "is_group": 0,
- "company": me.frm.doc.company
- }
+ account_type: [
+ "in",
+ [
+ "Tax",
+ "Expense Account",
+ "Income Account",
+ "Expenses Included In Valuation",
+ "Expenses Included In Asset Valuation",
+ ],
+ ],
+ is_group: 0,
+ company: me.frm.doc.company,
+ },
};
});
- let sbb_field = me.frm.get_docfield('stock_items', 'serial_and_batch_bundle');
+ let sbb_field = me.frm.get_docfield("stock_items", "serial_and_batch_bundle");
if (sbb_field) {
sbb_field.get_route_options_for_new_doc = (row) => {
return {
- 'item_code': row.doc.item_code,
- 'warehouse': row.doc.warehouse,
- 'voucher_type': me.frm.doc.doctype,
- }
+ item_code: row.doc.item_code,
+ warehouse: row.doc.warehouse,
+ voucher_type: me.frm.doc.doctype,
+ };
};
}
}
@@ -126,7 +137,10 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
}
target_asset() {
- if (this.frm.doc.target_asset && this.frm.doc.capitalization_method === "Choose a WIP composite asset") {
+ if (
+ this.frm.doc.target_asset &&
+ this.frm.doc.capitalization_method === "Choose a WIP composite asset"
+ ) {
this.set_consumed_stock_items_tagged_to_wip_composite_asset(this.frm.doc.target_asset);
this.get_target_asset_details();
}
@@ -143,7 +157,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
},
callback: function (r) {
if (!r.exc && r.message) {
- if(r.message[0] && r.message[0].length) {
+ if (r.message[0] && r.message[0].length) {
me.frm.clear_table("stock_items");
for (let item of r.message[0]) {
me.frm.add_child("stock_items", item);
@@ -160,7 +174,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
me.calculate_totals();
}
- }
+ },
});
}
}
@@ -192,7 +206,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
if (this.frm.doc.posting_date) {
frappe.run_serially([
() => this.get_all_item_warehouse_details(),
- () => this.get_all_asset_values()
+ () => this.get_all_asset_values(),
]);
}
}
@@ -248,15 +262,15 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
}
stock_items_add(doc, cdt, cdn) {
- erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, 'stock_items');
+ erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, "stock_items");
}
asset_items_add(doc, cdt, cdn) {
- erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, 'asset_items');
+ erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, "asset_items");
}
serivce_items_add(doc, cdt, cdn) {
- erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, 'service_items');
+ erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, "service_items");
}
get_target_item_details() {
@@ -274,7 +288,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
if (!r.exc) {
me.frm.refresh_fields();
}
- }
+ },
});
}
}
@@ -294,7 +308,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
if (!r.exc) {
me.frm.refresh_fields();
}
- }
+ },
});
}
}
@@ -316,13 +330,13 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
company: me.frm.doc.company,
posting_date: me.frm.doc.posting_date,
posting_time: me.frm.doc.posting_time,
- }
+ },
},
callback: function (r) {
if (!r.exc) {
me.calculate_totals();
}
- }
+ },
});
}
}
@@ -343,13 +357,13 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
finance_book: row.finance_book || me.frm.doc.finance_book,
posting_date: me.frm.doc.posting_date,
posting_time: me.frm.doc.posting_time,
- }
+ },
},
callback: function (r) {
if (!r.exc) {
me.calculate_totals();
}
- }
+ },
});
}
}
@@ -367,13 +381,13 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
qty: flt(row.qty),
expense_account: row.expense_account,
company: me.frm.doc.company,
- }
+ },
},
callback: function (r) {
if (!r.exc) {
me.calculate_totals();
}
- }
+ },
});
}
}
@@ -386,23 +400,23 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
child: item,
args: {
args: {
- 'item_code': item.item_code,
- 'warehouse': cstr(item.warehouse),
- 'qty': flt(item.stock_qty),
- 'serial_no': item.serial_no,
- 'posting_date': me.frm.doc.posting_date,
- 'posting_time': me.frm.doc.posting_time,
- 'company': me.frm.doc.company,
- 'voucher_type': me.frm.doc.doctype,
- 'voucher_no': me.frm.doc.name,
- 'allow_zero_valuation': 1
- }
+ item_code: item.item_code,
+ warehouse: cstr(item.warehouse),
+ qty: flt(item.stock_qty),
+ serial_no: item.serial_no,
+ posting_date: me.frm.doc.posting_date,
+ posting_time: me.frm.doc.posting_time,
+ company: me.frm.doc.company,
+ voucher_type: me.frm.doc.doctype,
+ voucher_no: me.frm.doc.name,
+ allow_zero_valuation: 1,
+ },
},
- callback: function(r) {
+ callback: function (r) {
if (!r.exc) {
me.calculate_totals();
}
- }
+ },
});
}
}
@@ -412,11 +426,11 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
return me.frm.call({
method: "set_warehouse_details",
doc: me.frm.doc,
- callback: function(r) {
+ callback: function (r) {
if (!r.exc) {
me.calculate_totals();
}
- }
+ },
});
}
@@ -425,11 +439,11 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
return me.frm.call({
method: "set_asset_values",
doc: me.frm.doc,
- callback: function(r) {
+ callback: function (r) {
if (!r.exc) {
me.calculate_totals();
}
- }
+ },
});
}
@@ -441,33 +455,38 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
me.frm.doc.service_items_total = 0;
$.each(me.frm.doc.stock_items || [], function (i, d) {
- d.amount = flt(flt(d.stock_qty) * flt(d.valuation_rate), precision('amount', d));
+ d.amount = flt(flt(d.stock_qty) * flt(d.valuation_rate), precision("amount", d));
me.frm.doc.stock_items_total += d.amount;
});
$.each(me.frm.doc.asset_items || [], function (i, d) {
- d.asset_value = flt(flt(d.asset_value), precision('asset_value', d));
+ d.asset_value = flt(flt(d.asset_value), precision("asset_value", d));
me.frm.doc.asset_items_total += d.asset_value;
});
$.each(me.frm.doc.service_items || [], function (i, d) {
- d.amount = flt(flt(d.qty) * flt(d.rate), precision('amount', d));
+ d.amount = flt(flt(d.qty) * flt(d.rate), precision("amount", d));
me.frm.doc.service_items_total += d.amount;
});
- me.frm.doc.stock_items_total = flt(me.frm.doc.stock_items_total, precision('stock_items_total'));
- me.frm.doc.asset_items_total = flt(me.frm.doc.asset_items_total, precision('asset_items_total'));
- me.frm.doc.service_items_total = flt(me.frm.doc.service_items_total, precision('service_items_total'));
+ me.frm.doc.stock_items_total = flt(me.frm.doc.stock_items_total, precision("stock_items_total"));
+ me.frm.doc.asset_items_total = flt(me.frm.doc.asset_items_total, precision("asset_items_total"));
+ me.frm.doc.service_items_total = flt(
+ me.frm.doc.service_items_total,
+ precision("service_items_total")
+ );
- me.frm.doc.total_value = me.frm.doc.stock_items_total + me.frm.doc.asset_items_total + me.frm.doc.service_items_total;
- me.frm.doc.total_value = flt(me.frm.doc.total_value, precision('total_value'));
+ me.frm.doc.total_value =
+ me.frm.doc.stock_items_total + me.frm.doc.asset_items_total + me.frm.doc.service_items_total;
+ me.frm.doc.total_value = flt(me.frm.doc.total_value, precision("total_value"));
- me.frm.doc.target_qty = flt(me.frm.doc.target_qty, precision('target_qty'));
- me.frm.doc.target_incoming_rate = me.frm.doc.target_qty ? me.frm.doc.total_value / flt(me.frm.doc.target_qty)
+ me.frm.doc.target_qty = flt(me.frm.doc.target_qty, precision("target_qty"));
+ me.frm.doc.target_incoming_rate = me.frm.doc.target_qty
+ ? me.frm.doc.total_value / flt(me.frm.doc.target_qty)
: me.frm.doc.total_value;
me.frm.refresh_fields();
}
};
-cur_frm.cscript = new erpnext.assets.AssetCapitalization({frm: cur_frm});
+cur_frm.cscript = new erpnext.assets.AssetCapitalization({ frm: cur_frm });
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json
index 000ec65c45..4e7ac3ee8b 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json
@@ -356,7 +356,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2023-10-03 22:55:59.461456",
+ "modified": "2024-03-27 13:06:33.080441",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Capitalization",
@@ -394,7 +394,7 @@
"write": 1
}
],
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": [],
"title_field": "title",
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
index e6eaba5dd6..9e9176f592 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
@@ -49,6 +49,59 @@ force_fields = [
class AssetCapitalization(StockController):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ from erpnext.assets.doctype.asset_capitalization_asset_item.asset_capitalization_asset_item import (
+ AssetCapitalizationAssetItem,
+ )
+ from erpnext.assets.doctype.asset_capitalization_service_item.asset_capitalization_service_item import (
+ AssetCapitalizationServiceItem,
+ )
+ from erpnext.assets.doctype.asset_capitalization_stock_item.asset_capitalization_stock_item import (
+ AssetCapitalizationStockItem,
+ )
+
+ amended_from: DF.Link | None
+ asset_items: DF.Table[AssetCapitalizationAssetItem]
+ asset_items_total: DF.Currency
+ capitalization_method: DF.Literal["", "Create a new composite asset", "Choose a WIP composite asset"]
+ company: DF.Link
+ cost_center: DF.Link | None
+ entry_type: DF.Literal["Capitalization", "Decapitalization"]
+ finance_book: DF.Link | None
+ naming_series: DF.Literal["ACC-ASC-.YYYY.-"]
+ posting_date: DF.Date
+ posting_time: DF.Time
+ service_items: DF.Table[AssetCapitalizationServiceItem]
+ service_items_total: DF.Currency
+ set_posting_time: DF.Check
+ stock_items: DF.Table[AssetCapitalizationStockItem]
+ stock_items_total: DF.Currency
+ target_asset: DF.Link | None
+ target_asset_location: DF.Link | None
+ target_asset_name: DF.Data | None
+ target_batch_no: DF.Link | None
+ target_fixed_asset_account: DF.Link | None
+ target_has_batch_no: DF.Check
+ target_has_serial_no: DF.Check
+ target_incoming_rate: DF.Currency
+ target_is_fixed_asset: DF.Check
+ target_item_code: DF.Link | None
+ target_item_name: DF.Data | None
+ target_qty: DF.Float
+ target_serial_no: DF.SmallText | None
+ target_stock_uom: DF.Link | None
+ target_warehouse: DF.Link | None
+ title: DF.Data | None
+ total_value: DF.Currency
+ # end: auto-generated types
+
def validate(self):
self.validate_posting_time()
self.set_missing_values(for_validate=True)
@@ -90,6 +143,10 @@ class AssetCapitalization(StockController):
self.make_gl_entries()
self.restore_consumed_asset_items()
+ def on_trash(self):
+ frappe.db.set_value("Asset", self.target_asset, "capitalized_in", None)
+ super().on_trash()
+
def cancel_target_asset(self):
if self.entry_type == "Capitalization" and self.target_asset:
asset_doc = frappe.get_doc("Asset", self.target_asset)
diff --git a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py
index 32c6122609..31723ef3be 100644
--- a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py
+++ b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py
@@ -321,7 +321,7 @@ class TestAssetCapitalization(unittest.TestCase):
)
first_asset_depr_schedule = get_asset_depr_schedule_doc(consumed_asset.name, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Active")
# Create and submit Asset Captitalization
asset_capitalization = create_asset_capitalization(
@@ -355,8 +355,8 @@ class TestAssetCapitalization(unittest.TestCase):
first_asset_depr_schedule.load_from_db()
second_asset_depr_schedule = get_asset_depr_schedule_doc(consumed_asset.name, "Active")
- self.assertEquals(second_asset_depr_schedule.status, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
+ self.assertEqual(second_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Cancelled")
depr_schedule_of_consumed_asset = second_asset_depr_schedule.get("depreciation_schedule")
@@ -365,9 +365,7 @@ class TestAssetCapitalization(unittest.TestCase):
for d in depr_schedule_of_consumed_asset
if getdate(d.schedule_date) == getdate(capitalization_date)
]
- self.assertTrue(
- consumed_depreciation_schedule and consumed_depreciation_schedule[0].journal_entry
- )
+ self.assertTrue(consumed_depreciation_schedule and consumed_depreciation_schedule[0].journal_entry)
self.assertEqual(
consumed_depreciation_schedule[0].depreciation_amount, depreciation_before_disposal_amount
)
@@ -390,15 +388,9 @@ class TestAssetCapitalization(unittest.TestCase):
def create_asset_capitalization_data():
- create_item(
- "Capitalization Target Stock Item", is_stock_item=1, is_fixed_asset=0, is_purchase_item=0
- )
- create_item(
- "Capitalization Source Stock Item", is_stock_item=1, is_fixed_asset=0, is_purchase_item=0
- )
- create_item(
- "Capitalization Source Service Item", is_stock_item=0, is_fixed_asset=0, is_purchase_item=0
- )
+ create_item("Capitalization Target Stock Item", is_stock_item=1, is_fixed_asset=0, is_purchase_item=0)
+ create_item("Capitalization Source Stock Item", is_stock_item=1, is_fixed_asset=0, is_purchase_item=0)
+ create_item("Capitalization Source Service Item", is_stock_item=0, is_fixed_asset=0, is_purchase_item=0)
def create_asset_capitalization(**args):
diff --git a/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.json b/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.json
index ebaaffbad1..9a6b02e544 100644
--- a/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.json
+++ b/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.json
@@ -116,13 +116,14 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-09-12 14:30:02.915132",
+ "modified": "2024-03-27 13:06:33.350191",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Capitalization Asset Item",
"owner": "Administrator",
"permissions": [],
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
+ "states": [],
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.py b/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.py
index ba356d6b9f..003973f94d 100644
--- a/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.py
+++ b/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.py
@@ -6,4 +6,26 @@ from frappe.model.document import Document
class AssetCapitalizationAssetItem(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ asset: DF.Link
+ asset_name: DF.Data | None
+ asset_value: DF.Currency
+ cost_center: DF.Link | None
+ current_asset_value: DF.Currency
+ finance_book: DF.Link | None
+ fixed_asset_account: DF.Link | None
+ item_code: DF.Link
+ item_name: DF.Data | None
+ parent: DF.Data
+ parentfield: DF.Data
+ parenttype: DF.Data
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.json b/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.json
index 75691eaf9d..6d74e873e5 100644
--- a/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.json
+++ b/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.json
@@ -110,13 +110,13 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2024-03-05 11:23:40.766844",
+ "modified": "2024-03-27 13:06:33.503815",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Capitalization Service Item",
"owner": "Administrator",
"permissions": [],
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
diff --git a/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.py b/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.py
index 28d018ee39..93457f8785 100644
--- a/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.py
+++ b/erpnext/assets/doctype/asset_capitalization_service_item/asset_capitalization_service_item.py
@@ -6,4 +6,25 @@ from frappe.model.document import Document
class AssetCapitalizationServiceItem(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ amount: DF.Currency
+ cost_center: DF.Link | None
+ expense_account: DF.Link
+ item_code: DF.Link | None
+ item_name: DF.Data | None
+ parent: DF.Data
+ parentfield: DF.Data
+ parenttype: DF.Data
+ qty: DF.Float
+ rate: DF.Currency
+ uom: DF.Link | None
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json b/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json
index 2874aedd87..e863298fbf 100644
--- a/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json
+++ b/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json
@@ -178,13 +178,13 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2024-03-05 11:22:57.346889",
+ "modified": "2024-03-27 13:06:33.664691",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Capitalization Stock Item",
"owner": "Administrator",
"permissions": [],
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
diff --git a/erpnext/assets/doctype/asset_category/asset_category.js b/erpnext/assets/doctype/asset_category/asset_category.js
index 7dde14ea0e..046b62f244 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.js
+++ b/erpnext/assets/doctype/asset_category/asset_category.js
@@ -1,56 +1,55 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Asset Category', {
- onload: function(frm) {
- frm.add_fetch('company_name', 'accumulated_depreciation_account', 'accumulated_depreciation_account');
- frm.add_fetch('company_name', 'depreciation_expense_account', 'depreciation_expense_account');
+frappe.ui.form.on("Asset Category", {
+ onload: function (frm) {
+ frm.add_fetch("company_name", "accumulated_depreciation_account", "accumulated_depreciation_account");
+ frm.add_fetch("company_name", "depreciation_expense_account", "depreciation_expense_account");
- frm.set_query('fixed_asset_account', 'accounts', function(doc, cdt, cdn) {
- var d = locals[cdt][cdn];
+ frm.set_query("fixed_asset_account", "accounts", function (doc, cdt, cdn) {
+ var d = locals[cdt][cdn];
return {
- "filters": {
- "account_type": "Fixed Asset",
- "root_type": "Asset",
- "is_group": 0,
- "company": d.company_name
- }
+ filters: {
+ account_type: "Fixed Asset",
+ root_type: "Asset",
+ is_group: 0,
+ company: d.company_name,
+ },
};
});
- frm.set_query('accumulated_depreciation_account', 'accounts', function(doc, cdt, cdn) {
- var d = locals[cdt][cdn];
+ frm.set_query("accumulated_depreciation_account", "accounts", function (doc, cdt, cdn) {
+ var d = locals[cdt][cdn];
return {
- "filters": {
- "account_type": "Accumulated Depreciation",
- "is_group": 0,
- "company": d.company_name
- }
+ filters: {
+ account_type: "Accumulated Depreciation",
+ is_group: 0,
+ company: d.company_name,
+ },
};
});
- frm.set_query('depreciation_expense_account', 'accounts', function(doc, cdt, cdn) {
- var d = locals[cdt][cdn];
+ frm.set_query("depreciation_expense_account", "accounts", function (doc, cdt, cdn) {
+ var d = locals[cdt][cdn];
return {
- "filters": {
- "account_type": "Depreciation",
- "root_type": ["in", ["Expense", "Income"]],
- "is_group": 0,
- "company": d.company_name
- }
+ filters: {
+ account_type: "Depreciation",
+ root_type: ["in", ["Expense", "Income"]],
+ is_group: 0,
+ company: d.company_name,
+ },
};
});
- frm.set_query('capital_work_in_progress_account', 'accounts', function(doc, cdt, cdn) {
- var d = locals[cdt][cdn];
+ frm.set_query("capital_work_in_progress_account", "accounts", function (doc, cdt, cdn) {
+ var d = locals[cdt][cdn];
return {
- "filters": {
- "account_type": "Capital Work in Progress",
- "is_group": 0,
- "company": d.company_name
- }
+ filters: {
+ account_type: "Capital Work in Progress",
+ is_group: 0,
+ company: d.company_name,
+ },
};
});
-
- }
+ },
});
diff --git a/erpnext/assets/doctype/asset_category/asset_category.json b/erpnext/assets/doctype/asset_category/asset_category.json
index 0283f095ff..e58e9c0676 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.json
+++ b/erpnext/assets/doctype/asset_category/asset_category.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:asset_category_name",
@@ -65,7 +66,7 @@
}
],
"links": [],
- "modified": "2021-01-22 12:31:14.425319",
+ "modified": "2024-03-27 13:06:33.840414",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Category",
@@ -111,7 +112,8 @@
}
],
"show_name_in_global_search": 1,
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
+ "states": [],
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py
index 9cf3bf35b3..8c2d301a89 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.py
+++ b/erpnext/assets/doctype/asset_category/asset_category.py
@@ -9,6 +9,25 @@ from frappe.utils import cint, get_link_to_form
class AssetCategory(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ from erpnext.assets.doctype.asset_category_account.asset_category_account import (
+ AssetCategoryAccount,
+ )
+ from erpnext.assets.doctype.asset_finance_book.asset_finance_book import AssetFinanceBook
+
+ accounts: DF.Table[AssetCategoryAccount]
+ asset_category_name: DF.Data
+ enable_cwip_accounting: DF.Check
+ finance_books: DF.Table[AssetFinanceBook]
+ # end: auto-generated types
+
def validate(self):
self.validate_finance_books()
self.validate_account_types()
@@ -38,7 +57,9 @@ class AssetCategory(Document):
account_currency = frappe.get_value("Account", d.get(type_of_account), "account_currency")
if account_currency != company_currency:
invalid_accounts.append(
- frappe._dict({"type": type_of_account, "idx": d.idx, "account": d.get(type_of_account)})
+ frappe._dict(
+ {"type": type_of_account, "idx": d.idx, "account": d.get(type_of_account)}
+ )
)
for d in invalid_accounts:
@@ -87,8 +108,7 @@ class AssetCategory(Document):
missing_cwip_accounts_for_company.append(get_link_to_form("Company", d.company_name))
if missing_cwip_accounts_for_company:
- msg = _("""To enable Capital Work in Progress Accounting,""")
- msg += " "
+ msg = _("""To enable Capital Work in Progress Accounting,""") + " "
msg += _("""you must select Capital Work in Progress Account in accounts table""")
msg += "
"
msg += _("You can also set default CWIP account in Company {}").format(
diff --git a/erpnext/assets/doctype/asset_category/test_asset_category.py b/erpnext/assets/doctype/asset_category/test_asset_category.py
index 31aeeec5d7..516e27e00f 100644
--- a/erpnext/assets/doctype/asset_category/test_asset_category.py
+++ b/erpnext/assets/doctype/asset_category/test_asset_category.py
@@ -1,7 +1,6 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
-
import unittest
import frappe
@@ -27,14 +26,12 @@ class TestAssetCategory(unittest.TestCase):
)
try:
- asset_category.insert()
+ asset_category.insert(ignore_if_duplicate=True)
except frappe.DuplicateEntryError:
pass
def test_cwip_accounting(self):
- company_cwip_acc = frappe.db.get_value(
- "Company", "_Test Company", "capital_work_in_progress_account"
- )
+ frappe.db.get_value("Company", "_Test Company", "capital_work_in_progress_account")
frappe.db.set_value("Company", "_Test Company", "capital_work_in_progress_account", "")
asset_category = frappe.new_doc("Asset Category")
diff --git a/erpnext/assets/doctype/asset_category_account/asset_category_account.json b/erpnext/assets/doctype/asset_category_account/asset_category_account.json
index b7df557552..8fa7488458 100644
--- a/erpnext/assets/doctype/asset_category_account/asset_category_account.json
+++ b/erpnext/assets/doctype/asset_category_account/asset_category_account.json
@@ -1,196 +1,71 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2016-03-07 15:55:18.806409",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "creation": "2016-03-07 15:55:18.806409",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company_name",
+ "fixed_asset_account",
+ "accumulated_depreciation_account",
+ "depreciation_expense_account",
+ "capital_work_in_progress_account"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "company_name",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "company_name",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "fixed_asset_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Fixed Asset Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "fixed_asset_account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Fixed Asset Account",
+ "options": "Account",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "accumulated_depreciation_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Accumulated Depreciation Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "accumulated_depreciation_account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Accumulated Depreciation Account",
+ "options": "Account"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "depreciation_expense_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Depreciation Expense Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "depreciation_expense_account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Depreciation Expense Account",
+ "options": "Account"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "capital_work_in_progress_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Capital Work In Progress Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
+ "columns": 2,
+ "fieldname": "capital_work_in_progress_account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Capital Work In Progress Account",
+ "options": "Account"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2018-05-10 17:06:48.839347",
- "modified_by": "Administrator",
- "module": "Assets",
- "name": "Asset Category Account",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2024-03-27 13:06:34.012854",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset Category Account",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "states": [],
+ "track_changes": 1
+}
diff --git a/erpnext/assets/doctype/asset_category_account/asset_category_account.py b/erpnext/assets/doctype/asset_category_account/asset_category_account.py
index cce22734f9..2798f1cd6b 100644
--- a/erpnext/assets/doctype/asset_category_account/asset_category_account.py
+++ b/erpnext/assets/doctype/asset_category_account/asset_category_account.py
@@ -2,9 +2,26 @@
# For license information, please see license.txt
-import frappe
from frappe.model.document import Document
class AssetCategoryAccount(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ accumulated_depreciation_account: DF.Link | None
+ capital_work_in_progress_account: DF.Link | None
+ company_name: DF.Link
+ depreciation_expense_account: DF.Link | None
+ fixed_asset_account: DF.Link
+ parent: DF.Data
+ parentfield: DF.Data
+ parenttype: DF.Data
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js
index 3d2dff179a..83b5c376ac 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js
@@ -2,50 +2,63 @@
// For license information, please see license.txt
frappe.provide("erpnext.asset");
-frappe.ui.form.on('Asset Depreciation Schedule', {
- onload: function(frm) {
+frappe.ui.form.on("Asset Depreciation Schedule", {
+ onload: function (frm) {
frm.events.make_schedules_editable(frm);
},
- make_schedules_editable: function(frm) {
- var is_editable = frm.doc.depreciation_method == "Manual" ? true : false;
+ make_schedules_editable: function (frm) {
+ var is_manual_hence_editable = frm.doc.depreciation_method === "Manual" ? true : false;
+ var is_shift_hence_editable = frm.doc.shift_based ? true : false;
- frm.toggle_enable("depreciation_schedule", is_editable);
- frm.fields_dict["depreciation_schedule"].grid.toggle_enable("schedule_date", is_editable);
- frm.fields_dict["depreciation_schedule"].grid.toggle_enable("depreciation_amount", is_editable);
- }
+ frm.toggle_enable("depreciation_schedule", is_manual_hence_editable || is_shift_hence_editable);
+ frm.fields_dict["depreciation_schedule"].grid.toggle_enable(
+ "schedule_date",
+ is_manual_hence_editable
+ );
+ frm.fields_dict["depreciation_schedule"].grid.toggle_enable(
+ "depreciation_amount",
+ is_manual_hence_editable
+ );
+ frm.fields_dict["depreciation_schedule"].grid.toggle_enable("shift", is_shift_hence_editable);
+ },
});
-frappe.ui.form.on('Depreciation Schedule', {
- make_depreciation_entry: function(frm, cdt, cdn) {
+frappe.ui.form.on("Depreciation Schedule", {
+ make_depreciation_entry: function (frm, cdt, cdn) {
var row = locals[cdt][cdn];
if (!row.journal_entry) {
frappe.call({
method: "erpnext.assets.doctype.asset.depreciation.make_depreciation_entry",
args: {
- "asset_depr_schedule_name": frm.doc.name,
- "date": row.schedule_date
+ asset_depr_schedule_name: frm.doc.name,
+ date: row.schedule_date,
},
- callback: function(r) {
+ callback: function (r) {
frappe.model.sync(r.message);
frm.refresh();
- }
- })
+ },
+ });
}
},
- depreciation_amount: function(frm, cdt, cdn) {
+ depreciation_amount: function (frm, cdt, cdn) {
erpnext.asset.set_accumulated_depreciation(frm);
- }
+ },
});
-erpnext.asset.set_accumulated_depreciation = function(frm) {
- if(frm.doc.depreciation_method != "Manual") return;
+erpnext.asset.set_accumulated_depreciation = function (frm) {
+ if (frm.doc.depreciation_method != "Manual") return;
var accumulated_depreciation = flt(frm.doc.opening_accumulated_depreciation);
- $.each(frm.doc.depreciation_schedule || [], function(i, row) {
- accumulated_depreciation += flt(row.depreciation_amount);
- frappe.model.set_value(row.doctype, row.name, "accumulated_depreciation_amount", accumulated_depreciation);
- })
+ $.each(frm.doc.depreciation_schedule || [], function (i, row) {
+ accumulated_depreciation += flt(row.depreciation_amount);
+ frappe.model.set_value(
+ row.doctype,
+ row.name,
+ "accumulated_depreciation_amount",
+ accumulated_depreciation
+ );
+ });
};
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json
index 01c0ea7fc7..3a540d82d0 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json
@@ -20,6 +20,8 @@
"depreciation_method",
"total_number_of_depreciations",
"rate_of_depreciation",
+ "daily_prorata_based",
+ "shift_based",
"column_break_8",
"frequency_of_depreciation",
"expected_value_after_useful_life",
@@ -177,11 +179,20 @@
"read_only": 1
},
{
- "fetch_from": "asset.company",
- "fieldname": "company",
- "fieldtype": "Link",
- "label": "Company",
- "options": "Company",
+ "default": "0",
+ "depends_on": "eval:doc.depreciation_method == \"Straight Line\" || doc.depreciation_method == \"Manual\"",
+ "fieldname": "daily_prorata_based",
+ "fieldtype": "Check",
+ "label": "Depreciate based on daily pro-rata",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:doc.depreciation_method == \"Straight Line\"",
+ "fieldname": "shift_based",
+ "fieldtype": "Check",
+ "label": "Depreciate based on shifts",
"read_only": 1
},
{
@@ -196,7 +207,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2024-01-08 16:31:04.533928",
+ "modified": "2024-03-27 13:06:34.135004",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Depreciation Schedule",
@@ -233,7 +244,7 @@
"write": 1
}
],
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": []
}
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
index 0b07015391..eb0135033b 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
@@ -63,6 +63,7 @@ class AssetDepreciationSchedule(Document):
self.prepare_draft_asset_depr_schedule_data_from_asset_name_and_fb_name(
self.asset, self.finance_book
)
+ self.update_shift_depr_schedule()
def validate(self):
self.validate_another_asset_depr_schedule_does_not_exist()
@@ -110,6 +111,16 @@ class AssetDepreciationSchedule(Document):
def on_cancel(self):
self.db_set("status", "Cancelled")
+ def update_shift_depr_schedule(self):
+ if not self.shift_based or self.docstatus != 0:
+ return
+
+ asset_doc = frappe.get_doc("Asset", self.asset)
+ fb_row = asset_doc.finance_books[self.finance_book_id - 1]
+
+ self.make_depr_schedule(asset_doc, fb_row)
+ self.set_accumulated_depreciation(asset_doc, fb_row)
+
def prepare_draft_asset_depr_schedule_data_from_asset_name_and_fb_name(self, asset_name, fb_name):
asset_doc = frappe.get_doc("Asset", asset_name)
@@ -190,13 +201,15 @@ class AssetDepreciationSchedule(Document):
self.frequency_of_depreciation = row.frequency_of_depreciation
self.rate_of_depreciation = row.rate_of_depreciation
self.expected_value_after_useful_life = row.expected_value_after_useful_life
+ self.daily_prorata_based = row.daily_prorata_based
+ self.shift_based = row.shift_based
self.status = "Draft"
def make_depr_schedule(
self,
asset_doc,
row,
- date_of_disposal,
+ date_of_disposal=None,
update_asset_finance_book_row=True,
value_after_depreciation=None,
):
@@ -217,6 +230,8 @@ class AssetDepreciationSchedule(Document):
num_of_depreciations_completed = 0
depr_schedule = []
+ self.schedules_before_clearing = self.get("depreciation_schedule")
+
for schedule in self.get("depreciation_schedule"):
if schedule.journal_entry:
num_of_depreciations_completed += 1
@@ -260,9 +275,7 @@ class AssetDepreciationSchedule(Document):
row.depreciation_method in ("Written Down Value", "Double Declining Balance")
and cint(row.frequency_of_depreciation) != 12
):
- has_wdv_or_dd_non_yearly_pro_rata = _check_is_pro_rata(
- asset_doc, row, wdv_or_dd_non_yearly=True
- )
+ has_wdv_or_dd_non_yearly_pro_rata = _check_is_pro_rata(asset_doc, row, wdv_or_dd_non_yearly=True)
skip_row = False
should_get_last_day = is_last_day_of_the_month(row.depreciation_start_date)
@@ -272,6 +285,7 @@ class AssetDepreciationSchedule(Document):
number_of_pending_depreciations = final_number_of_depreciations - start
yearly_opening_wdv = value_after_depreciation
current_fiscal_year_end_date = None
+ prev_per_day_depr = True
for n in range(start, final_number_of_depreciations):
# If depreciation is already completed (for double declining balance)
if skip_row:
@@ -288,8 +302,7 @@ class AssetDepreciationSchedule(Document):
prev_depreciation_amount = self.get("depreciation_schedule")[n - 1].depreciation_amount
else:
prev_depreciation_amount = 0
-
- depreciation_amount = get_depreciation_amount(
+ depreciation_amount, prev_per_day_depr = get_depreciation_amount(
self,
asset_doc,
value_after_depreciation,
@@ -299,8 +312,8 @@ class AssetDepreciationSchedule(Document):
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
number_of_pending_depreciations,
+ prev_per_day_depr,
)
-
if not has_pro_rata or (
n < (cint(final_number_of_depreciations) - 1) or final_number_of_depreciations == 2
):
@@ -317,7 +330,6 @@ class AssetDepreciationSchedule(Document):
getdate(asset_doc.available_for_use_date),
(asset_doc.opening_number_of_booked_depreciations * row.frequency_of_depreciation),
)
-
if self.depreciation_schedule:
from_date = self.depreciation_schedule[-1].schedule_date
@@ -326,13 +338,11 @@ class AssetDepreciationSchedule(Document):
depreciation_amount,
from_date,
date_of_disposal,
+ original_schedule_date=schedule_date,
)
if depreciation_amount > 0:
- self.add_depr_schedule_row(
- date_of_disposal,
- depreciation_amount,
- )
+ self.add_depr_schedule_row(date_of_disposal, depreciation_amount, n)
break
@@ -346,7 +356,6 @@ class AssetDepreciationSchedule(Document):
from_date = add_days(
asset_doc.available_for_use_date, -1
) # needed to calc depr amount for available_for_use_date too
-
depreciation_amount, days, months = _get_pro_rata_amt(
row,
depreciation_amount,
@@ -412,7 +421,7 @@ class AssetDepreciationSchedule(Document):
depreciation_amount_without_pro_rata, depreciation_amount
)
- schedule_date = asset_doc.to_date # @dokos
+ schedule_date = add_days(schedule_date, days)
if not depreciation_amount:
continue
@@ -432,10 +441,7 @@ class AssetDepreciationSchedule(Document):
skip_row = True
if flt(depreciation_amount, asset_doc.precision("gross_purchase_amount")) > 0:
- self.add_depr_schedule_row(
- schedule_date,
- depreciation_amount,
- )
+ self.add_depr_schedule_row(schedule_date, depreciation_amount, n)
# to ensure that final accumulated depreciation amount is accurate
def get_adjusted_depreciation_amount(
@@ -457,16 +463,22 @@ class AssetDepreciationSchedule(Document):
def get_depreciation_amount_for_first_row(self):
return self.get("depreciation_schedule")[0].depreciation_amount
- def add_depr_schedule_row(
- self,
- schedule_date,
- depreciation_amount,
- ):
+ def add_depr_schedule_row(self, schedule_date, depreciation_amount, schedule_idx):
+ if self.shift_based:
+ shift = (
+ self.schedules_before_clearing[schedule_idx].shift
+ if self.schedules_before_clearing and len(self.schedules_before_clearing) > schedule_idx
+ else frappe.get_cached_value("Asset Shift Factor", {"default": 1}, "shift_name")
+ )
+ else:
+ shift = None
+
self.append(
"depreciation_schedule",
{
"schedule_date": schedule_date,
"depreciation_amount": depreciation_amount,
+ "shift": shift,
},
)
@@ -508,6 +520,7 @@ class AssetDepreciationSchedule(Document):
and i == max(straight_line_idx) - 1
and not date_of_disposal
and not date_of_return
+ and not row.shift_based
):
depreciation_amount += flt(
value_after_depreciation - flt(row.expected_value_after_useful_life),
@@ -551,9 +564,6 @@ def _check_is_pro_rata(asset_doc, row, wdv_or_dd_non_yearly=False):
if days < total_days:
has_pro_rata = True
- if row.depreciation_start_date == from_date:
- has_pro_rata = False # @dokos
-
return has_pro_rata
@@ -571,34 +581,38 @@ def _get_modified_available_for_use_date(asset_doc, row, wdv_or_dd_non_yearly=Fa
def _get_pro_rata_amt(
- row, depreciation_amount, from_date, to_date, has_wdv_or_dd_non_yearly_pro_rata=False
+ row,
+ depreciation_amount,
+ from_date,
+ to_date,
+ has_wdv_or_dd_non_yearly_pro_rata=False,
+ original_schedule_date=None,
):
- days = date_difference(to_date, from_date) # @dokos
+ days = date_diff(to_date, from_date)
months = month_diff(to_date, from_date)
if has_wdv_or_dd_non_yearly_pro_rata:
- total_days = get_total_days(to_date, 12)
+ total_days = get_total_days(original_schedule_date or to_date, 12)
else:
- total_days = get_total_days(to_date, row.frequency_of_depreciation)
+ total_days = get_total_days(original_schedule_date or to_date, row.frequency_of_depreciation)
- return (depreciation_amount * flt(days)) / flt(total_days), days, months
+ depreciation_days = date_difference(to_date, from_date) # @dokos
+ return (depreciation_amount * flt(depreciation_days)) / flt(total_days), days, months
-@erpnext.allow_regional
+@erpnext.allow_regional # @dokos
def get_total_days(date, frequency):
period_start_date = add_months(date, cint(frequency) * -1)
-
if is_last_day_of_the_month(date):
period_start_date = get_last_day(period_start_date)
+ return date_difference(date, period_start_date) # @dokos
- return date_difference(date, period_start_date)
-
-@erpnext.allow_regional
+@erpnext.allow_regional # @dokos
def date_difference(to_date, from_date):
return date_diff(to_date, from_date)
-@erpnext.allow_regional
+@erpnext.allow_regional # @dokos
def get_depreciation_amount(
asset_depr_schedule,
asset,
@@ -609,12 +623,12 @@ def get_depreciation_amount(
prev_depreciation_amount=0,
has_wdv_or_dd_non_yearly_pro_rata=False,
number_of_pending_depreciations=0,
+ prev_per_day_depr=0,
):
if fb_row.depreciation_method in ("Straight Line", "Manual"):
return get_straight_line_or_manual_depr_amount(
- asset, fb_row, schedule_idx, number_of_pending_depreciations
- )
-
+ asset_depr_schedule, asset, fb_row, schedule_idx, number_of_pending_depreciations
+ ), None
else:
return get_wdv_or_dd_depr_amount(
asset,
@@ -625,16 +639,20 @@ def get_depreciation_amount(
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
asset_depr_schedule,
+ prev_per_day_depr,
)
def get_straight_line_or_manual_depr_amount(
- asset, row, schedule_idx, number_of_pending_depreciations
+ asset_depr_schedule, asset, row, schedule_idx, number_of_pending_depreciations
):
+ if row.shift_based:
+ return get_shift_depr_amount(asset_depr_schedule, asset, row, schedule_idx)
+
# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset life and value
if asset.flags.increase_in_asset_life:
return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / (
- date_diff(asset.to_date, asset.available_for_use_date) / 365
+ date_difference(asset.to_date, asset.available_for_use_date) / 365 # @dokos
)
# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset value
elif asset.flags.increase_in_asset_value_due_to_repair:
@@ -643,9 +661,20 @@ def get_straight_line_or_manual_depr_amount(
)
# if the Depreciation Schedule is being modified after Asset Value Adjustment due to decrease in asset value
elif asset.flags.decrease_in_asset_value_due_to_value_adjustment:
- return (
- flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
- ) / number_of_pending_depreciations
+ if row.daily_prorata_based:
+ amount = flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
+
+ return get_daily_prorata_based_straight_line_depr(
+ asset,
+ row,
+ schedule_idx,
+ number_of_pending_depreciations,
+ amount,
+ )
+ else:
+ return (
+ flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
+ ) / number_of_pending_depreciations
# if the Depreciation Schedule is being prepared for the first time
else:
if row.daily_prorata_based:
@@ -690,6 +719,32 @@ def get_shift_depr_amount(asset_depr_schedule, asset, row, schedule_idx):
- flt(row.expected_value_after_useful_life)
) / flt(row.total_number_of_depreciations - asset.opening_number_of_booked_depreciations)
+ asset_shift_factors_map = get_asset_shift_factors_map()
+ shift = (
+ asset_depr_schedule.schedules_before_clearing[schedule_idx].shift
+ if len(asset_depr_schedule.schedules_before_clearing) > schedule_idx
+ else None
+ )
+ shift_factor = asset_shift_factors_map.get(shift) if shift else 0
+
+ shift_factors_sum = sum(
+ flt(asset_shift_factors_map.get(schedule.shift))
+ for schedule in asset_depr_schedule.schedules_before_clearing
+ )
+
+ return (
+ (
+ flt(asset.gross_purchase_amount)
+ - flt(asset.opening_accumulated_depreciation)
+ - flt(row.expected_value_after_useful_life)
+ )
+ / flt(shift_factors_sum)
+ ) * shift_factor
+
+
+def get_asset_shift_factors_map():
+ return dict(frappe.db.get_all("Asset Shift Factor", ["shift_name", "shift_factor"], as_list=True))
+
@erpnext.allow_regional
def get_wdv_or_dd_depr_amount(
@@ -701,6 +756,7 @@ def get_wdv_or_dd_depr_amount(
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
asset_depr_schedule,
+ prev_per_day_depr,
):
return get_default_wdv_or_dd_depr_amount(
asset,
@@ -710,6 +766,7 @@ def get_wdv_or_dd_depr_amount(
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
asset_depr_schedule,
+ prev_per_day_depr,
)
@@ -721,6 +778,39 @@ def get_default_wdv_or_dd_depr_amount(
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
asset_depr_schedule,
+ prev_per_day_depr,
+):
+ if not fb_row.daily_prorata_based or cint(fb_row.frequency_of_depreciation) == 12:
+ return _get_default_wdv_or_dd_depr_amount(
+ asset,
+ fb_row,
+ depreciable_value,
+ schedule_idx,
+ prev_depreciation_amount,
+ has_wdv_or_dd_non_yearly_pro_rata,
+ asset_depr_schedule,
+ ), None
+ else:
+ return _get_daily_prorata_based_default_wdv_or_dd_depr_amount(
+ asset,
+ fb_row,
+ depreciable_value,
+ schedule_idx,
+ prev_depreciation_amount,
+ has_wdv_or_dd_non_yearly_pro_rata,
+ asset_depr_schedule,
+ prev_per_day_depr,
+ )
+
+
+def _get_default_wdv_or_dd_depr_amount(
+ asset,
+ fb_row,
+ depreciable_value,
+ schedule_idx,
+ prev_depreciation_amount,
+ has_wdv_or_dd_non_yearly_pro_rata,
+ asset_depr_schedule,
):
if cint(fb_row.frequency_of_depreciation) == 12:
return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100)
@@ -747,6 +837,75 @@ def get_default_wdv_or_dd_depr_amount(
return prev_depreciation_amount
+def _get_daily_prorata_based_default_wdv_or_dd_depr_amount(
+ asset,
+ fb_row,
+ depreciable_value,
+ schedule_idx,
+ prev_depreciation_amount,
+ has_wdv_or_dd_non_yearly_pro_rata,
+ asset_depr_schedule,
+ prev_per_day_depr,
+):
+ if has_wdv_or_dd_non_yearly_pro_rata: # If applicable days for ther first month is less than full month
+ if schedule_idx == 0:
+ return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100), None
+
+ elif schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 1: # Year changes
+ return get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value)
+ else:
+ return get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, prev_per_day_depr)
+ else:
+ if schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 0: # year changes
+ return get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value)
+ else:
+ return get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, prev_per_day_depr)
+
+
+def get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value):
+ """ "
+ Returns monthly depreciation amount when year changes
+ 1. Calculate per day depr based on new year
+ 2. Calculate monthly amount based on new per day amount
+ """
+ from_date, days_in_month = _get_total_days(
+ fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation)
+ )
+ per_day_depr = get_per_day_depr(fb_row, depreciable_value, from_date)
+ return (per_day_depr * days_in_month), per_day_depr
+
+
+def get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, prev_per_day_depr):
+ """ "
+ Returns monthly depreciation amount based on prev per day depr
+ Calculate per day depr only for the first month
+ """
+ from_date, days_in_month = _get_total_days(
+ fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation)
+ )
+ return (prev_per_day_depr * days_in_month), prev_per_day_depr
+
+
+def get_per_day_depr(
+ fb_row,
+ depreciable_value,
+ from_date,
+):
+ to_date = add_days(add_years(from_date, 1), -1)
+ total_days = date_diff(to_date, from_date) + 1
+ per_day_depr = (flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100)) / total_days
+ return per_day_depr
+
+
+def _get_total_days(depreciation_start_date, schedule_idx, frequency_of_depreciation):
+ from_date = add_months(depreciation_start_date, (schedule_idx - 1) * frequency_of_depreciation)
+ to_date = add_months(from_date, frequency_of_depreciation)
+ if is_last_day_of_the_month(depreciation_start_date):
+ to_date = get_last_day(to_date)
+ from_date = add_days(get_last_day(from_date), 1)
+ return from_date, date_diff(to_date, from_date) + 1
+
+
def make_draft_asset_depr_schedules_if_not_present(asset_doc):
asset_depr_schedules_names = []
@@ -862,11 +1021,14 @@ def make_new_active_asset_depr_schedules_and_cancel_current_ones(
def get_temp_asset_depr_schedule_doc(
- asset_doc, row, date_of_disposal=None, date_of_return=None, update_asset_finance_book_row=False
+ asset_doc,
+ row,
+ date_of_disposal=None,
+ date_of_return=None,
+ update_asset_finance_book_row=False,
+ new_depr_schedule=None,
):
- current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(
- asset_doc.name, "Active", row.finance_book
- )
+ current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, "Active", row.finance_book)
if not current_asset_depr_schedule_doc:
frappe.throw(
@@ -877,6 +1039,21 @@ def get_temp_asset_depr_schedule_doc(
temp_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc)
+ if new_depr_schedule:
+ temp_asset_depr_schedule_doc.depreciation_schedule = []
+
+ for schedule in new_depr_schedule:
+ temp_asset_depr_schedule_doc.append(
+ "depreciation_schedule",
+ {
+ "schedule_date": schedule.schedule_date,
+ "depreciation_amount": schedule.depreciation_amount,
+ "accumulated_depreciation_amount": schedule.accumulated_depreciation_amount,
+ "journal_entry": schedule.journal_entry,
+ "shift": schedule.shift,
+ },
+ )
+
temp_asset_depr_schedule_doc.prepare_draft_asset_depr_schedule_data(
asset_doc,
row,
@@ -898,15 +1075,14 @@ def get_depr_schedule(asset_name, status, finance_book=None):
return asset_depr_schedule_doc.get("depreciation_schedule")
+@frappe.whitelist()
def get_asset_depr_schedule_doc(asset_name, status, finance_book=None):
asset_depr_schedule = get_asset_depr_schedule_name(asset_name, status, finance_book)
if not asset_depr_schedule:
return
- asset_depr_schedule_doc = frappe.get_doc(
- "Asset Depreciation Schedule", asset_depr_schedule[0].name
- )
+ asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule[0].name)
return asset_depr_schedule_doc
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
index ec0f40c842..6009ac1496 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
@@ -11,7 +11,7 @@ from erpnext.assets.doctype.asset.depreciation import (
from erpnext.assets.doctype.asset.test_asset import create_asset, create_asset_data
from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
get_asset_depr_schedule_doc,
- get_depr_schedule
+ get_depr_schedule,
)
@@ -23,7 +23,7 @@ class TestAssetDepreciationSchedule(FrappeTestCase):
asset = create_asset(item_code="Macbook Pro", calculate_depreciation=1, submit=1)
first_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Active")
second_asset_depr_schedule = frappe.get_doc(
{"doctype": "Asset Depreciation Schedule", "asset": asset.name, "finance_book": None}
diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
index a6a7d81de7..779749ee4e 100644
--- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
+++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
@@ -21,6 +21,7 @@
],
"fields": [
{
+ "columns": 2,
"fieldname": "finance_book",
"fieldtype": "Link",
"in_list_view": 1,
@@ -36,6 +37,7 @@
"reqd": 1
},
{
+ "columns": 2,
"fieldname": "total_number_of_depreciations",
"fieldtype": "Int",
"in_list_view": 1,
@@ -47,6 +49,7 @@
"fieldtype": "Column Break"
},
{
+ "columns": 2,
"fieldname": "frequency_of_depreciation",
"fieldtype": "Int",
"in_list_view": 1,
@@ -61,6 +64,7 @@
"mandatory_depends_on": "eval:parent.doctype == 'Asset'"
},
{
+ "columns": 1,
"default": "0",
"depends_on": "eval:parent.doctype == 'Asset'",
"fieldname": "expected_value_after_useful_life",
@@ -82,8 +86,7 @@
"description": "In Percentage",
"fieldname": "rate_of_depreciation",
"fieldtype": "Percent",
- "label": "Rate of Depreciation",
- "precision": "4"
+ "label": "Rate of Depreciation"
},
{
"fieldname": "salvage_value_percentage",
@@ -121,7 +124,7 @@
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py
index ab01956625..d06d6355ec 100644
--- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py
+++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py
@@ -2,7 +2,6 @@
# For license information, please see license.txt
-import frappe
from frappe.model.document import Document
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
index 5c03b98873..83dabab893 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js
@@ -1,49 +1,47 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Asset Maintenance', {
+frappe.ui.form.on("Asset Maintenance", {
setup: (frm) => {
- frm.set_query("assign_to", "asset_maintenance_tasks", function(doc) {
+ frm.set_query("assign_to", "asset_maintenance_tasks", function (doc) {
return {
query: "erpnext.assets.doctype.asset_maintenance.asset_maintenance.get_team_members",
filters: {
- maintenance_team: doc.maintenance_team
- }
+ maintenance_team: doc.maintenance_team,
+ },
};
});
- frm.set_indicator_formatter('maintenance_status',
- function(doc) {
- let indicator = 'blue';
- if (doc.maintenance_status == 'Overdue') {
- indicator = 'orange';
- }
- if (doc.maintenance_status == 'Cancelled') {
- indicator = 'red';
- }
- return indicator;
+ frm.set_indicator_formatter("maintenance_status", function (doc) {
+ let indicator = "blue";
+ if (doc.maintenance_status == "Overdue") {
+ indicator = "orange";
+ }
+ if (doc.maintenance_status == "Cancelled") {
+ indicator = "red";
}
- );
+ return indicator;
+ });
},
refresh: (frm) => {
- if(!frm.is_new()) {
- frm.trigger('make_dashboard');
+ if (!frm.is_new()) {
+ frm.trigger("make_dashboard");
}
},
make_dashboard: (frm) => {
- if(!frm.is_new()) {
+ if (!frm.is_new()) {
frappe.call({
- method: 'erpnext.assets.doctype.asset_maintenance.asset_maintenance.get_maintenance_log',
- args: {asset_name: frm.doc.asset_name},
+ method: "erpnext.assets.doctype.asset_maintenance.asset_maintenance.get_maintenance_log",
+ args: { asset_name: frm.doc.asset_name },
callback: (r) => {
- if(!r.message) {
+ if (!r.message) {
return;
}
- const section = frm.dashboard.add_section('', __("Maintenance Log"));
- var rows = $('').appendTo(section);
+ const section = frm.dashboard.add_section("", __("Maintenance Log"));
+ var rows = $("").appendTo(section);
// show
- (r.message || []).forEach(function(d) {
+ (r.message || []).forEach(function (d) {
$(`
{
get_next_due_date(frm, cdt, cdn);
},
- periodicity: (frm, cdt, cdn) => {
+ periodicity: (frm, cdt, cdn) => {
get_next_due_date(frm, cdt, cdn);
},
- last_completion_date: (frm, cdt, cdn) => {
+ last_completion_date: (frm, cdt, cdn) => {
get_next_due_date(frm, cdt, cdn);
},
- end_date: (frm, cdt, cdn) => {
+ end_date: (frm, cdt, cdn) => {
get_next_due_date(frm, cdt, cdn);
- }
+ },
});
var get_next_due_date = function (frm, cdt, cdn) {
var d = locals[cdt][cdn];
if (d.start_date && d.periodicity) {
return frappe.call({
- method: 'erpnext.assets.doctype.asset_maintenance.asset_maintenance.calculate_next_due_date',
+ method: "erpnext.assets.doctype.asset_maintenance.asset_maintenance.calculate_next_due_date",
args: {
start_date: d.start_date,
periodicity: d.periodicity,
end_date: d.end_date,
last_completion_date: d.last_completion_date,
- next_due_date: d.next_due_date
+ next_due_date: d.next_due_date,
},
- callback: function(r) {
+ callback: function (r) {
if (r.message) {
frappe.model.set_value(cdt, cdn, "next_due_date", r.message);
- }
- else {
+ } else {
frappe.model.set_value(cdt, cdn, "next_due_date", "");
}
- }
+ },
});
}
};
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json
index c8a504cad8..5287f643bd 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json
@@ -1,140 +1,141 @@
{
- "actions": [],
- "autoname": "field:asset_name",
- "creation": "2017-10-19 16:50:22.879545",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "asset_name",
- "asset_category",
- "company",
- "column_break_3",
- "item_code",
- "item_name",
- "section_break_6",
- "maintenance_team",
- "column_break_9",
- "maintenance_manager",
- "maintenance_manager_name",
- "section_break_8",
- "asset_maintenance_tasks"
- ],
- "fields": [
- {
- "fieldname": "asset_name",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Asset Name",
- "options": "Asset",
- "reqd": 1,
- "unique": 1
- },
- {
- "fetch_from": "asset_name.asset_category",
- "fieldname": "asset_category",
- "fieldtype": "Read Only",
- "label": "Asset Category"
- },
- {
- "fetch_from": "asset_name.item_code",
- "fieldname": "item_code",
- "fieldtype": "Read Only",
- "label": "Item Code"
- },
- {
- "fetch_from": "asset_name.item_name",
- "fieldname": "item_name",
- "fieldtype": "Read Only",
- "label": "Item Name"
- },
- {
- "fieldname": "column_break_3",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "label": "Company",
- "options": "Company",
- "reqd": 1
- },
- {
- "fieldname": "section_break_6",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "maintenance_team",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Maintenance Team",
- "options": "Asset Maintenance Team",
- "reqd": 1
- },
- {
- "fieldname": "column_break_9",
- "fieldtype": "Column Break"
- },
- {
- "fetch_from": "maintenance_team.maintenance_manager",
- "fieldname": "maintenance_manager",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Maintenance Manager",
- "read_only": 1
- },
- {
- "fetch_from": "maintenance_team.maintenance_manager_name",
- "fieldname": "maintenance_manager_name",
- "fieldtype": "Read Only",
- "label": "Maintenance Manager Name"
- },
- {
- "fieldname": "section_break_8",
- "fieldtype": "Section Break",
- "label": "Tasks"
- },
- {
- "fieldname": "asset_maintenance_tasks",
- "fieldtype": "Table",
- "label": "Maintenance Tasks",
- "options": "Asset Maintenance Task",
- "reqd": 1
- }
- ],
- "links": [],
- "modified": "2020-05-28 20:28:32.993823",
- "modified_by": "Administrator",
- "module": "Assets",
- "name": "Asset Maintenance",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Quality Manager",
- "share": 1,
- "write": 1
- },
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Manufacturing User",
- "share": 1,
- "write": 1
- }
- ],
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
- }
\ No newline at end of file
+ "actions": [],
+ "autoname": "field:asset_name",
+ "creation": "2017-10-19 16:50:22.879545",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "asset_name",
+ "asset_category",
+ "company",
+ "column_break_3",
+ "item_code",
+ "item_name",
+ "section_break_6",
+ "maintenance_team",
+ "column_break_9",
+ "maintenance_manager",
+ "maintenance_manager_name",
+ "section_break_8",
+ "asset_maintenance_tasks"
+ ],
+ "fields": [
+ {
+ "fieldname": "asset_name",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Asset Name",
+ "options": "Asset",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fetch_from": "asset_name.asset_category",
+ "fieldname": "asset_category",
+ "fieldtype": "Read Only",
+ "label": "Asset Category"
+ },
+ {
+ "fetch_from": "asset_name.item_code",
+ "fieldname": "item_code",
+ "fieldtype": "Read Only",
+ "label": "Item Code"
+ },
+ {
+ "fetch_from": "asset_name.item_name",
+ "fieldname": "item_name",
+ "fieldtype": "Read Only",
+ "label": "Item Name"
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
+ {
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "maintenance_team",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Maintenance Team",
+ "options": "Asset Maintenance Team",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_9",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fetch_from": "maintenance_team.maintenance_manager",
+ "fieldname": "maintenance_manager",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Maintenance Manager",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "maintenance_team.maintenance_manager_name",
+ "fieldname": "maintenance_manager_name",
+ "fieldtype": "Read Only",
+ "label": "Maintenance Manager Name"
+ },
+ {
+ "fieldname": "section_break_8",
+ "fieldtype": "Section Break",
+ "label": "Tasks"
+ },
+ {
+ "fieldname": "asset_maintenance_tasks",
+ "fieldtype": "Table",
+ "label": "Maintenance Tasks",
+ "options": "Asset Maintenance Task",
+ "reqd": 1
+ }
+ ],
+ "links": [],
+ "modified": "2024-03-27 13:06:34.491299",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset Maintenance",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Quality Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing User",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "states": [],
+ "track_changes": 1
+}
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
index 7cb826fe96..99829df28e 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
@@ -10,6 +10,29 @@ from frappe.utils import add_days, add_months, add_years, getdate, nowdate
class AssetMaintenance(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ from erpnext.assets.doctype.asset_maintenance_task.asset_maintenance_task import (
+ AssetMaintenanceTask,
+ )
+
+ asset_category: DF.ReadOnly | None
+ asset_maintenance_tasks: DF.Table[AssetMaintenanceTask]
+ asset_name: DF.Link
+ company: DF.Link
+ item_code: DF.ReadOnly | None
+ item_name: DF.ReadOnly | None
+ maintenance_manager: DF.Data | None
+ maintenance_manager_name: DF.ReadOnly | None
+ maintenance_team: DF.Link
+ # end: auto-generated types
+
def validate(self):
for task in self.get("asset_maintenance_tasks"):
if task.end_date and (getdate(task.start_date) >= getdate(task.end_date)):
@@ -69,9 +92,7 @@ def calculate_next_due_date(
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":
next_due_date = add_days(start_date, 1)
@@ -149,9 +170,9 @@ def get_team_members(doctype, txt, searchfield, start, page_len, filters):
def get_maintenance_log(asset_name):
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""",
+ 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,
)
diff --git a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.js b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.js
index c5db90ad37..47a2128c37 100644
--- a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.js
+++ b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.js
@@ -1,15 +1,15 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Asset Maintenance Log', {
+frappe.ui.form.on("Asset Maintenance Log", {
asset_maintenance: (frm) => {
- frm.set_query('task', function(doc) {
+ frm.set_query("task", function (doc) {
return {
query: "erpnext.assets.doctype.asset_maintenance_log.asset_maintenance_log.get_maintenance_tasks",
filters: {
- 'asset_maintenance': doc.asset_maintenance
- }
+ asset_maintenance: doc.asset_maintenance,
+ },
};
});
- }
-});
\ No newline at end of file
+ },
+});
diff --git a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.json b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.json
index 2619229980..c641d48075 100644
--- a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.json
+++ b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.json
@@ -1,201 +1,203 @@
{
- "actions": [],
- "autoname": "naming_series:",
- "creation": "2017-10-23 16:58:44.424309",
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "asset_maintenance",
- "naming_series",
- "asset_name",
- "column_break_2",
- "item_code",
- "item_name",
- "section_break_5",
- "task",
- "task_name",
- "maintenance_type",
- "periodicity",
- "has_certificate",
- "certificate_attachement",
- "column_break_6",
- "maintenance_status",
- "assign_to_name",
- "due_date",
- "completion_date",
- "description",
- "column_break_9",
- "actions_performed",
- "amended_from"
- ],
- "fields": [
- {
- "fieldname": "asset_maintenance",
- "fieldtype": "Link",
- "label": "Asset Maintenance",
- "options": "Asset Maintenance"
- },
- {
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "label": "Series",
- "options": "ACC-AML-.YYYY.-",
- "reqd": 1
- },
- {
- "fetch_from": "asset_maintenance.asset_name",
- "fieldname": "asset_name",
- "fieldtype": "Read Only",
- "label": "Asset Name"
- },
- {
- "fieldname": "column_break_2",
- "fieldtype": "Column Break"
- },
- {
- "fetch_from": "asset_maintenance.item_code",
- "fieldname": "item_code",
- "fieldtype": "Read Only",
- "label": "Item Code"
- },
- {
- "fetch_from": "asset_maintenance.item_name",
- "fieldname": "item_name",
- "fieldtype": "Read Only",
- "label": "Item Name"
- },
- {
- "fieldname": "section_break_5",
- "fieldtype": "Section Break",
- "label": "Maintenance Details"
- },
- {
- "fieldname": "task",
- "fieldtype": "Link",
- "label": "Task",
- "options": "Asset Maintenance Task"
- },
- {
- "fetch_from": "task.maintenance_type",
- "fieldname": "maintenance_type",
- "fieldtype": "Read Only",
- "label": "Maintenance Type"
- },
- {
- "fetch_from": "task.periodicity",
- "fieldname": "periodicity",
- "fieldtype": "Data",
- "label": "Periodicity",
- "read_only": 1
- },
- {
- "fetch_from": "task.assign_to_name",
- "fieldname": "assign_to_name",
- "fieldtype": "Read Only",
- "label": "Assign To"
- },
- {
- "fieldname": "column_break_6",
- "fieldtype": "Column Break"
- },
- {
- "fetch_from": "task.next_due_date",
- "fieldname": "due_date",
- "fieldtype": "Date",
- "in_list_view": 1,
- "label": "Due Date",
- "read_only": 1
- },
- {
- "fieldname": "completion_date",
- "fieldtype": "Date",
- "in_list_view": 1,
- "label": "Completion Date"
- },
- {
- "fieldname": "maintenance_status",
- "fieldtype": "Select",
- "in_standard_filter": 1,
- "label": "Maintenance Status",
- "options": "Planned\nCompleted\nCancelled\nOverdue",
- "reqd": 1
- },
- {
- "default": "0",
- "fetch_from": "task.certificate_required",
- "fieldname": "has_certificate",
- "fieldtype": "Check",
- "label": "Has Certificate "
- },
- {
- "depends_on": "eval:doc.has_certificate",
- "fieldname": "certificate_attachement",
- "fieldtype": "Attach",
- "label": "Certificate"
- },
- {
- "fetch_from": "task.description",
- "fieldname": "description",
- "fieldtype": "Read Only",
- "label": "Description",
- "read_only": 1
- },
- {
- "fieldname": "column_break_9",
- "fieldtype": "Section Break"
- },
- {
- "allow_on_submit": 1,
- "fieldname": "actions_performed",
- "fieldtype": "Text Editor",
- "label": "Actions performed"
- },
- {
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "label": "Amended From",
- "no_copy": 1,
- "options": "Asset Maintenance Log",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fetch_from": "task.maintenance_task",
- "fieldname": "task_name",
- "fieldtype": "Data",
- "in_preview": 1,
- "label": "Task Name",
- "read_only": 1
- }
- ],
- "is_submittable": 1,
- "links": [],
- "modified": "2021-01-22 12:33:45.888124",
- "modified_by": "Administrator",
- "module": "Assets",
- "name": "Asset Maintenance Log",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Manufacturing User",
- "share": 1,
- "submit": 1,
- "write": 1
- }
- ],
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 1
- }
\ No newline at end of file
+ "actions": [],
+ "autoname": "naming_series:",
+ "creation": "2017-10-23 16:58:44.424309",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "asset_maintenance",
+ "naming_series",
+ "asset_name",
+ "column_break_2",
+ "item_code",
+ "item_name",
+ "section_break_5",
+ "task",
+ "task_name",
+ "maintenance_type",
+ "periodicity",
+ "has_certificate",
+ "certificate_attachement",
+ "column_break_6",
+ "maintenance_status",
+ "assign_to_name",
+ "due_date",
+ "completion_date",
+ "description",
+ "column_break_9",
+ "actions_performed",
+ "amended_from"
+ ],
+ "fields": [
+ {
+ "fieldname": "asset_maintenance",
+ "fieldtype": "Link",
+ "label": "Asset Maintenance",
+ "options": "Asset Maintenance"
+ },
+ {
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "options": "ACC-AML-.YYYY.-",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "asset_maintenance.asset_name",
+ "fieldname": "asset_name",
+ "fieldtype": "Read Only",
+ "label": "Asset Name"
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fetch_from": "asset_maintenance.item_code",
+ "fieldname": "item_code",
+ "fieldtype": "Read Only",
+ "label": "Item Code"
+ },
+ {
+ "fetch_from": "asset_maintenance.item_name",
+ "fieldname": "item_name",
+ "fieldtype": "Read Only",
+ "label": "Item Name"
+ },
+ {
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break",
+ "label": "Maintenance Details"
+ },
+ {
+ "fieldname": "task",
+ "fieldtype": "Link",
+ "label": "Task",
+ "options": "Asset Maintenance Task"
+ },
+ {
+ "fetch_from": "task.maintenance_type",
+ "fieldname": "maintenance_type",
+ "fieldtype": "Read Only",
+ "label": "Maintenance Type"
+ },
+ {
+ "fetch_from": "task.periodicity",
+ "fieldname": "periodicity",
+ "fieldtype": "Data",
+ "label": "Periodicity",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "task.assign_to_name",
+ "fieldname": "assign_to_name",
+ "fieldtype": "Read Only",
+ "label": "Assign To"
+ },
+ {
+ "fieldname": "column_break_6",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fetch_from": "task.next_due_date",
+ "fieldname": "due_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Due Date",
+ "read_only": 1
+ },
+ {
+ "fieldname": "completion_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Completion Date"
+ },
+ {
+ "fieldname": "maintenance_status",
+ "fieldtype": "Select",
+ "in_standard_filter": 1,
+ "label": "Maintenance Status",
+ "options": "Planned\nCompleted\nCancelled\nOverdue",
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "fetch_from": "task.certificate_required",
+ "fieldname": "has_certificate",
+ "fieldtype": "Check",
+ "label": "Has Certificate "
+ },
+ {
+ "depends_on": "eval:doc.has_certificate",
+ "fieldname": "certificate_attachement",
+ "fieldtype": "Attach",
+ "label": "Certificate"
+ },
+ {
+ "fetch_from": "task.description",
+ "fieldname": "description",
+ "fieldtype": "Read Only",
+ "label": "Description",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_9",
+ "fieldtype": "Section Break"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "actions_performed",
+ "fieldtype": "Text Editor",
+ "label": "Actions performed"
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Asset Maintenance Log",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fetch_from": "task.maintenance_task",
+ "fieldname": "task_name",
+ "fieldtype": "Data",
+ "in_preview": 1,
+ "label": "Task Name",
+ "read_only": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2024-03-27 13:06:34.654633",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset Maintenance Log",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "states": [],
+ "track_changes": 1,
+ "track_seen": 1
+}
diff --git a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.py b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.py
index ff791b2754..009bcc3e69 100644
--- a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.py
+++ b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.py
@@ -11,6 +11,34 @@ from erpnext.assets.doctype.asset_maintenance.asset_maintenance import calculate
class AssetMaintenanceLog(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ actions_performed: DF.TextEditor | None
+ amended_from: DF.Link | None
+ asset_maintenance: DF.Link | None
+ asset_name: DF.ReadOnly | None
+ assign_to_name: DF.ReadOnly | None
+ certificate_attachement: DF.Attach | None
+ completion_date: DF.Date | None
+ description: DF.ReadOnly | None
+ due_date: DF.Date | None
+ has_certificate: DF.Check
+ item_code: DF.ReadOnly | None
+ item_name: DF.ReadOnly | None
+ maintenance_status: DF.Literal["Planned", "Completed", "Cancelled", "Overdue"]
+ maintenance_type: DF.ReadOnly | None
+ naming_series: DF.Literal["ACC-AML-.YYYY.-"]
+ periodicity: DF.Data | None
+ task: DF.Link | None
+ task_name: DF.Data | None
+ # end: auto-generated types
+
def validate(self):
if getdate(self.due_date) < getdate(nowdate()) and self.maintenance_status not in [
"Completed",
diff --git a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log_calendar.js b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log_calendar.js
index c804b31e90..7b7b508536 100644
--- a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log_calendar.js
+++ b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log_calendar.js
@@ -3,20 +3,20 @@
frappe.views.calendar["Asset Maintenance Log"] = {
field_map: {
- "start": "due_date",
- "end": "due_date",
- "id": "name",
- "title": "task",
- "allDay": "allDay",
- "progress": "progress"
+ start: "due_date",
+ end: "due_date",
+ id: "name",
+ title: "task",
+ allDay: "allDay",
+ progress: "progress",
},
filters: [
{
- "fieldtype": "Link",
- "fieldname": "asset_name",
- "options": "Asset Maintenance",
- "label": __("Asset Maintenance")
- }
+ fieldtype: "Link",
+ fieldname: "asset_name",
+ options: "Asset Maintenance",
+ label: __("Asset Maintenance"),
+ },
],
- get_events_method: "frappe.desk.calendar.get_events"
+ get_events_method: "frappe.desk.calendar.get_events",
};
diff --git a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log_list.js b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log_list.js
index 23100bc2ec..13f2444742 100644
--- a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log_list.js
+++ b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log_list.js
@@ -1,14 +1,15 @@
-frappe.listview_settings['Asset Maintenance Log'] = {
+frappe.listview_settings["Asset Maintenance Log"] = {
add_fields: ["maintenance_status"],
- get_indicator: function(doc) {
- if (doc.maintenance_status=="Planned") {
+ has_indicator_for_draft: 1,
+ get_indicator: function (doc) {
+ if (doc.maintenance_status == "Planned") {
return [__(doc.maintenance_status), "orange", "status,=," + doc.maintenance_status];
- } else if (doc.maintenance_status=="Completed") {
+ } else if (doc.maintenance_status == "Completed") {
return [__(doc.maintenance_status), "green", "status,=," + doc.maintenance_status];
- } else if (doc.maintenance_status=="Cancelled") {
+ } else if (doc.maintenance_status == "Cancelled") {
return [__(doc.maintenance_status), "red", "status,=," + doc.maintenance_status];
- } else if (doc.maintenance_status=="Overdue") {
+ } else if (doc.maintenance_status == "Overdue") {
return [__(doc.maintenance_status), "red", "status,=," + doc.maintenance_status];
}
- }
+ },
};
diff --git a/erpnext/assets/doctype/asset_maintenance_log/test_asset_maintenance_log.py b/erpnext/assets/doctype/asset_maintenance_log/test_asset_maintenance_log.py
index 8766079934..9980ff31f6 100644
--- a/erpnext/assets/doctype/asset_maintenance_log/test_asset_maintenance_log.py
+++ b/erpnext/assets/doctype/asset_maintenance_log/test_asset_maintenance_log.py
@@ -1,7 +1,6 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
-
import unittest
diff --git a/erpnext/assets/doctype/asset_maintenance_task/asset_maintenance_task.json b/erpnext/assets/doctype/asset_maintenance_task/asset_maintenance_task.json
index 80d90c6347..f8f9d4db29 100644
--- a/erpnext/assets/doctype/asset_maintenance_task/asset_maintenance_task.json
+++ b/erpnext/assets/doctype/asset_maintenance_task/asset_maintenance_task.json
@@ -144,13 +144,14 @@
],
"istable": 1,
"links": [],
- "modified": "2023-03-23 07:03:07.113452",
+ "modified": "2024-03-27 13:06:34.835687",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Maintenance Task",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC"
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "states": []
}
diff --git a/erpnext/assets/doctype/asset_maintenance_task/asset_maintenance_task.py b/erpnext/assets/doctype/asset_maintenance_task/asset_maintenance_task.py
index 65b0e36171..f3a21b59ca 100644
--- a/erpnext/assets/doctype/asset_maintenance_task/asset_maintenance_task.py
+++ b/erpnext/assets/doctype/asset_maintenance_task/asset_maintenance_task.py
@@ -2,9 +2,35 @@
# For license information, please see license.txt
-import frappe
from frappe.model.document import Document
class AssetMaintenanceTask(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ assign_to: DF.Link | None
+ assign_to_name: DF.ReadOnly | None
+ certificate_required: DF.Check
+ description: DF.TextEditor | None
+ end_date: DF.Date | None
+ last_completion_date: DF.Date | None
+ maintenance_status: DF.Literal["Planned", "Overdue", "Cancelled"]
+ maintenance_task: DF.Data
+ maintenance_type: DF.Literal["Preventive Maintenance", "Calibration"]
+ next_due_date: DF.Date | None
+ parent: DF.Data
+ parentfield: DF.Data
+ parenttype: DF.Data
+ periodicity: DF.Literal[
+ "", "Daily", "Weekly", "Monthly", "Quarterly", "Half-yearly", "Yearly", "2 Yearly", "3 Yearly"
+ ]
+ start_date: DF.Date
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.js b/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.js
index c94e3dbc3c..8598765190 100644
--- a/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.js
+++ b/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.js
@@ -1,8 +1,6 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Asset Maintenance Team', {
- refresh: function() {
-
- }
+frappe.ui.form.on("Asset Maintenance Team", {
+ refresh: function () {},
});
diff --git a/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.json b/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.json
index 6adc2de8b9..e2bfdc20dd 100644
--- a/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.json
+++ b/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.json
@@ -1,87 +1,88 @@
{
- "actions": [],
- "autoname": "field:maintenance_team_name",
- "creation": "2017-10-20 11:43:47.712616",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "maintenance_team_name",
- "maintenance_manager",
- "maintenance_manager_name",
- "column_break_2",
- "company",
- "section_break_2",
- "maintenance_team_members"
- ],
- "fields": [
- {
- "fieldname": "maintenance_team_name",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Maintenance Team Name",
- "reqd": 1,
- "unique": 1
- },
- {
- "fieldname": "maintenance_manager",
- "fieldtype": "Link",
- "label": "Maintenance Manager",
- "options": "User"
- },
- {
- "fetch_from": "maintenance_manager.full_name",
- "fieldname": "maintenance_manager_name",
- "fieldtype": "Read Only",
- "label": "Maintenance Manager Name"
- },
- {
- "fieldname": "column_break_2",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "label": "Company",
- "options": "Company",
- "reqd": 1
- },
- {
- "fieldname": "section_break_2",
- "fieldtype": "Section Break",
- "label": "Team"
- },
- {
- "fieldname": "maintenance_team_members",
- "fieldtype": "Table",
- "label": "Maintenance Team Members",
- "options": "Maintenance Team Member",
- "reqd": 1
- }
- ],
- "index_web_pages_for_search": 1,
- "links": [],
- "modified": "2021-01-22 15:09:03.347345",
- "modified_by": "Administrator",
- "module": "Assets",
- "name": "Asset Maintenance Team",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Manufacturing User",
- "share": 1,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
- }
\ No newline at end of file
+ "actions": [],
+ "autoname": "field:maintenance_team_name",
+ "creation": "2017-10-20 11:43:47.712616",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "maintenance_team_name",
+ "maintenance_manager",
+ "maintenance_manager_name",
+ "column_break_2",
+ "company",
+ "section_break_2",
+ "maintenance_team_members"
+ ],
+ "fields": [
+ {
+ "fieldname": "maintenance_team_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Maintenance Team Name",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "maintenance_manager",
+ "fieldtype": "Link",
+ "label": "Maintenance Manager",
+ "options": "User"
+ },
+ {
+ "fetch_from": "maintenance_manager.full_name",
+ "fieldname": "maintenance_manager_name",
+ "fieldtype": "Read Only",
+ "label": "Maintenance Manager Name"
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
+ {
+ "fieldname": "section_break_2",
+ "fieldtype": "Section Break",
+ "label": "Team"
+ },
+ {
+ "fieldname": "maintenance_team_members",
+ "fieldtype": "Table",
+ "label": "Maintenance Team Members",
+ "options": "Maintenance Team Member",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2024-03-27 13:06:34.976117",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset Maintenance Team",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing User",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "states": [],
+ "track_changes": 1
+}
diff --git a/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.py b/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.py
index 22015d63ed..b2219f0ae0 100644
--- a/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.py
+++ b/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.py
@@ -2,9 +2,27 @@
# For license information, please see license.txt
-import frappe
from frappe.model.document import Document
class AssetMaintenanceTeam(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ from erpnext.assets.doctype.maintenance_team_member.maintenance_team_member import (
+ MaintenanceTeamMember,
+ )
+
+ company: DF.Link
+ maintenance_manager: DF.Link | None
+ maintenance_manager_name: DF.ReadOnly | None
+ maintenance_team_members: DF.Table[MaintenanceTeamMember]
+ maintenance_team_name: DF.Data
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/asset_maintenance_team/test_asset_maintenance_team.py b/erpnext/assets/doctype/asset_maintenance_team/test_asset_maintenance_team.py
index 173864f6a5..732ab4ae48 100644
--- a/erpnext/assets/doctype/asset_maintenance_team/test_asset_maintenance_team.py
+++ b/erpnext/assets/doctype/asset_maintenance_team/test_asset_maintenance_team.py
@@ -1,7 +1,6 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
-
import unittest
diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.js b/erpnext/assets/doctype/asset_movement/asset_movement.js
index 1482639f4c..e445c90f30 100644
--- a/erpnext/assets/doctype/asset_movement/asset_movement.js
+++ b/erpnext/assets/doctype/asset_movement/asset_movement.js
@@ -1,104 +1,107 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Asset Movement', {
+frappe.ui.form.on("Asset Movement", {
setup: (frm) => {
frm.set_query("to_employee", "assets", (doc) => {
return {
filters: {
- company: doc.company
- }
+ company: doc.company,
+ },
};
- })
+ });
frm.set_query("from_employee", "assets", (doc) => {
return {
filters: {
- company: doc.company
- }
+ company: doc.company,
+ },
};
- })
+ });
frm.set_query("reference_name", (doc) => {
return {
filters: {
company: doc.company,
- docstatus: 1
- }
+ docstatus: 1,
+ },
};
- })
+ });
frm.set_query("reference_doctype", () => {
return {
filters: {
- name: ["in", ["Purchase Receipt", "Purchase Invoice"]]
- }
+ name: ["in", ["Purchase Receipt", "Purchase Invoice"]],
+ },
};
}),
- frm.set_query("asset", "assets", () => {
- return {
- filters: {
- status: ["not in", ["Draft"]]
- }
- }
- })
+ frm.set_query("asset", "assets", () => {
+ return {
+ filters: {
+ status: ["not in", ["Draft"]],
+ },
+ };
+ });
},
onload: (frm) => {
- frm.trigger('set_required_fields');
+ frm.trigger("set_required_fields");
},
purpose: (frm) => {
- frm.trigger('set_required_fields');
+ frm.trigger("set_required_fields");
},
set_required_fields: (frm, cdt, cdn) => {
let fieldnames_to_be_altered;
- if (frm.doc.purpose === 'Transfer') {
+ if (frm.doc.purpose === "Transfer") {
fieldnames_to_be_altered = {
target_location: { read_only: 0, reqd: 1 },
- source_location: { read_only: 1, reqd: 0 },
+ source_location: { read_only: 1, reqd: 1 },
from_employee: { read_only: 1, reqd: 0 },
- to_employee: { read_only: 1, reqd: 0 }
+ to_employee: { read_only: 1, reqd: 0 },
};
- }
- else if (frm.doc.purpose === 'Receipt') {
+ } else if (frm.doc.purpose === "Receipt") {
fieldnames_to_be_altered = {
target_location: { read_only: 0, reqd: 1 },
source_location: { read_only: 1, reqd: 0 },
from_employee: { read_only: 0, reqd: 0 },
- to_employee: { read_only: 1, reqd: 0 }
+ to_employee: { read_only: 1, reqd: 0 },
};
- }
- else if (frm.doc.purpose === 'Issue') {
+ } else if (frm.doc.purpose === "Issue") {
fieldnames_to_be_altered = {
target_location: { read_only: 1, reqd: 0 },
- source_location: { read_only: 1, reqd: 1 },
+ source_location: { read_only: 1, reqd: 0 },
from_employee: { read_only: 1, reqd: 0 },
- to_employee: { read_only: 0, reqd: 1 }
+ to_employee: { read_only: 0, reqd: 1 },
};
}
if (fieldnames_to_be_altered) {
- Object.keys(fieldnames_to_be_altered).forEach(fieldname => {
+ Object.keys(fieldnames_to_be_altered).forEach((fieldname) => {
let property_to_be_altered = fieldnames_to_be_altered[fieldname];
- Object.keys(property_to_be_altered).forEach(property => {
+ Object.keys(property_to_be_altered).forEach((property) => {
let value = property_to_be_altered[property];
- frm.fields_dict['assets'].grid.update_docfield_property(fieldname, property, value);
+ frm.fields_dict["assets"].grid.update_docfield_property(fieldname, property, value);
});
});
- frm.refresh_field('assets');
+ frm.refresh_field("assets");
}
- }
+ },
});
-frappe.ui.form.on('Asset Movement Item', {
- asset: function(frm, cdt, cdn) {
+frappe.ui.form.on("Asset Movement Item", {
+ asset: function (frm, cdt, cdn) {
// on manual entry of an asset auto sets their source location / employee
const asset_name = locals[cdt][cdn].asset;
- if (asset_name){
- frappe.db.get_doc('Asset', asset_name).then((asset_doc) => {
- if(asset_doc.location) frappe.model.set_value(cdt, cdn, 'source_location', asset_doc.location);
- if(asset_doc.custodian) frappe.model.set_value(cdt, cdn, 'from_employee', asset_doc.custodian);
- }).catch((err) => {
- console.log(err); // eslint-disable-line
- });
+ if (asset_name) {
+ frappe.db
+ .get_doc("Asset", asset_name)
+ .then((asset_doc) => {
+ if (asset_doc.location)
+ frappe.model.set_value(cdt, cdn, "source_location", asset_doc.location);
+ if (asset_doc.custodian)
+ frappe.model.set_value(cdt, cdn, "from_employee", asset_doc.custodian);
+ })
+ .catch((err) => {
+ console.log(err); // eslint-disable-line
+ });
}
- }
-});
\ No newline at end of file
+ },
+});
diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.json b/erpnext/assets/doctype/asset_movement/asset_movement.json
index 7515dc03c5..6e0dee6c5d 100644
--- a/erpnext/assets/doctype/asset_movement/asset_movement.json
+++ b/erpnext/assets/doctype/asset_movement/asset_movement.json
@@ -96,7 +96,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2023-06-28 16:54:26.571083",
+ "modified": "2024-03-27 13:06:35.116228",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Movement",
@@ -149,7 +149,7 @@
"write": 1
}
],
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": []
}
diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.py b/erpnext/assets/doctype/asset_movement/asset_movement.py
index 267fe6f259..29c8b3c39e 100644
--- a/erpnext/assets/doctype/asset_movement/asset_movement.py
+++ b/erpnext/assets/doctype/asset_movement/asset_movement.py
@@ -11,6 +11,25 @@ from erpnext.assets.doctype.asset_activity.asset_activity import add_asset_activ
class AssetMovement(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ from erpnext.assets.doctype.asset_movement_item.asset_movement_item import AssetMovementItem
+
+ amended_from: DF.Link | None
+ assets: DF.Table[AssetMovementItem]
+ company: DF.Link
+ purpose: DF.Literal["", "Issue", "Receipt", "Transfer"]
+ reference_doctype: DF.Link | None
+ reference_name: DF.DynamicLink | None
+ transaction_date: DF.Datetime
+ # end: auto-generated types
+
def validate(self):
self.validate_asset()
self.validate_location()
@@ -35,7 +54,9 @@ class AssetMovement(Document):
if d.source_location:
if current_location != d.source_location:
frappe.throw(
- _("Asset {0} does not belongs to the location {1}").format(d.asset, d.source_location)
+ _("Asset {0} does not belongs to the location {1}").format(
+ d.asset, d.source_location
+ )
)
else:
d.source_location = current_location
@@ -60,19 +81,25 @@ class AssetMovement(Document):
title=_("Incorrect Movement Purpose"),
)
if not d.target_location:
- frappe.throw(_("Target Location is required while transferring Asset {0}").format(d.asset))
+ 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 not (d.source_location) and not d.target_location and not d.to_employee:
frappe.throw(
- _("Target Location or To Employee is required while receiving Asset {0}").format(d.asset)
+ _("Target Location or To Employee is required while receiving Asset {0}").format(
+ d.asset
+ )
)
elif d.source_location:
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)
+ _(
+ "Target Location is required while receiving Asset {0} from an employee"
+ ).format(d.asset)
)
elif d.to_employee and d.target_location:
frappe.throw(
@@ -112,19 +139,17 @@ class AssetMovement(Document):
# 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
latest_movement_entry = frappe.db.sql(
- """
+ f"""
SELECT asm_item.target_location, asm_item.to_employee
FROM `tabAsset Movement Item` asm_item, `tabAsset Movement` asm
WHERE
asm_item.parent=asm.name and
asm_item.asset=%(asset)s and
asm.company=%(company)s and
- asm.docstatus=1 and {0}
+ asm.docstatus=1 and {cond}
ORDER BY
asm.transaction_date desc limit 1
- """.format(
- cond
- ),
+ """,
args,
)
if latest_movement_entry:
@@ -145,7 +170,9 @@ class AssetMovement(Document):
elif current_location:
add_asset_activity(
d.asset,
- _("Asset transferred to Location {0}").format(get_link_to_form("Location", current_location)),
+ _("Asset transferred to Location {0}").format(
+ get_link_to_form("Location", current_location)
+ ),
)
elif current_employee:
add_asset_activity(
diff --git a/erpnext/assets/doctype/asset_movement/test_asset_movement.py b/erpnext/assets/doctype/asset_movement/test_asset_movement.py
index 27e7e557f1..52590d2ba8 100644
--- a/erpnext/assets/doctype/asset_movement/test_asset_movement.py
+++ b/erpnext/assets/doctype/asset_movement/test_asset_movement.py
@@ -20,9 +20,7 @@ class TestAssetMovement(unittest.TestCase):
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)
@@ -51,7 +49,11 @@ class TestAssetMovement(unittest.TestCase):
purpose="Transfer",
company=asset.company,
assets=[
- {"asset": asset.name, "source_location": "Test Location", "target_location": "Test Location 2"}
+ {
+ "asset": asset.name,
+ "source_location": "Test Location",
+ "target_location": "Test Location 2",
+ }
],
reference_doctype="Purchase Receipt",
reference_name=pr.name,
@@ -62,7 +64,11 @@ class TestAssetMovement(unittest.TestCase):
purpose="Transfer",
company=asset.company,
assets=[
- {"asset": asset.name, "source_location": "Test Location 2", "target_location": "Test Location"}
+ {
+ "asset": asset.name,
+ "source_location": "Test Location 2",
+ "target_location": "Test Location",
+ }
],
reference_doctype="Purchase Receipt",
reference_name=pr.name,
@@ -97,9 +103,7 @@ class TestAssetMovement(unittest.TestCase):
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
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)
@@ -129,7 +133,11 @@ class TestAssetMovement(unittest.TestCase):
purpose="Transfer",
company=asset.company,
assets=[
- {"asset": asset.name, "source_location": "Test Location", "target_location": "Test Location 2"}
+ {
+ "asset": asset.name,
+ "source_location": "Test Location",
+ "target_location": "Test Location 2",
+ }
],
reference_doctype="Purchase Receipt",
reference_name=pr.name,
@@ -167,6 +175,4 @@ def create_asset_movement(**args):
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
- )
+ frappe.get_doc({"doctype": "Location", "location_name": location}).insert(ignore_permissions=True)
diff --git a/erpnext/assets/doctype/asset_movement_item/asset_movement_item.json b/erpnext/assets/doctype/asset_movement_item/asset_movement_item.json
index 994c3c0989..084b736f8a 100644
--- a/erpnext/assets/doctype/asset_movement_item/asset_movement_item.json
+++ b/erpnext/assets/doctype/asset_movement_item/asset_movement_item.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2019-10-07 18:49:00.737806",
"doctype": "DocType",
"editable_grid": 1,
@@ -73,14 +74,16 @@
}
],
"istable": 1,
- "modified": "2019-10-09 15:59:08.265141",
+ "links": [],
+ "modified": "2024-03-27 13:06:35.272015",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Movement Item",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
+ "states": [],
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/assets/doctype/asset_movement_item/asset_movement_item.py b/erpnext/assets/doctype/asset_movement_item/asset_movement_item.py
index e25226d580..1a5302b9d8 100644
--- a/erpnext/assets/doctype/asset_movement_item/asset_movement_item.py
+++ b/erpnext/assets/doctype/asset_movement_item/asset_movement_item.py
@@ -7,4 +7,24 @@ from frappe.model.document import Document
class AssetMovementItem(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ asset: DF.Link
+ asset_name: DF.Data | None
+ company: DF.Link | None
+ from_employee: DF.Link | None
+ parent: DF.Data
+ parentfield: DF.Data
+ parenttype: DF.Data
+ source_location: DF.Link | None
+ target_location: DF.Link | None
+ to_employee: DF.Link | None
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.js b/erpnext/assets/doctype/asset_repair/asset_repair.js
index 03afcb9442..27a4eb6e99 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.js
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.js
@@ -1,31 +1,31 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Asset Repair', {
- setup: function(frm) {
- frm.fields_dict.cost_center.get_query = function(doc) {
+frappe.ui.form.on("Asset Repair", {
+ setup: function (frm) {
+ frm.fields_dict.cost_center.get_query = function (doc) {
return {
filters: {
- 'is_group': 0,
- 'company': doc.company
- }
+ is_group: 0,
+ company: doc.company,
+ },
};
};
- frm.fields_dict.project.get_query = function(doc) {
+ frm.fields_dict.project.get_query = function (doc) {
return {
filters: {
- 'company': doc.company
- }
+ company: doc.company,
+ },
};
};
- frm.fields_dict.warehouse.get_query = function(doc) {
+ frm.fields_dict.warehouse.get_query = function (doc) {
return {
filters: {
- 'is_group': 0,
- 'company': doc.company
- }
+ is_group: 0,
+ company: doc.company,
+ },
};
};
@@ -33,87 +33,87 @@ frappe.ui.form.on('Asset Repair', {
let row = locals[cdt][cdn];
return {
filters: {
- 'item_code': row.item_code,
- 'voucher_type': doc.doctype,
- 'voucher_no': ["in", [doc.name, ""]],
- 'is_cancelled': 0,
- }
- }
+ item_code: row.item_code,
+ voucher_type: doc.doctype,
+ voucher_no: ["in", [doc.name, ""]],
+ is_cancelled: 0,
+ },
+ };
});
},
- refresh: function(frm) {
+ refresh: function (frm) {
if (frm.doc.docstatus) {
- frm.add_custom_button(__("View General Ledger"), function() {
+ frm.add_custom_button(__("View General Ledger"), function () {
frappe.route_options = {
- "voucher_no": frm.doc.name
+ voucher_no: frm.doc.name,
};
frappe.set_route("query-report", "General Ledger");
});
}
- let sbb_field = frm.get_docfield('stock_items', 'serial_and_batch_bundle');
+ let sbb_field = frm.get_docfield("stock_items", "serial_and_batch_bundle");
if (sbb_field) {
sbb_field.get_route_options_for_new_doc = (row) => {
return {
- 'item_code': row.doc.item_code,
- 'voucher_type': frm.doc.doctype,
- }
+ item_code: row.doc.item_code,
+ voucher_type: frm.doc.doctype,
+ };
};
}
},
repair_status: (frm) => {
if (frm.doc.completion_date && frm.doc.repair_status == "Completed") {
- frappe.call ({
+ frappe.call({
method: "erpnext.assets.doctype.asset_repair.asset_repair.get_downtime",
args: {
- "failure_date":frm.doc.failure_date,
- "completion_date":frm.doc.completion_date
+ failure_date: frm.doc.failure_date,
+ completion_date: frm.doc.completion_date,
},
- callback: function(r) {
- if(r.message) {
+ callback: function (r) {
+ if (r.message) {
frm.set_value("downtime", r.message + " Hrs");
}
- }
+ },
});
}
if (frm.doc.repair_status == "Completed") {
- frm.set_value('completion_date', frappe.datetime.now_datetime());
+ frm.set_value("completion_date", frappe.datetime.now_datetime());
}
},
stock_items_on_form_rendered() {
erpnext.setup_serial_or_batch_no();
- }
+ },
});
-frappe.ui.form.on('Asset Repair Consumed Item', {
- item_code: function(frm, cdt, cdn) {
+frappe.ui.form.on("Asset Repair Consumed Item", {
+ item_code: function (frm, cdt, cdn) {
var item = locals[cdt][cdn];
let item_args = {
- 'item_code': item.item_code,
- 'warehouse': frm.doc.warehouse,
- 'qty': item.consumed_quantity,
- 'serial_no': item.serial_no,
- 'company': frm.doc.company,
+ item_code: item.item_code,
+ warehouse: frm.doc.warehouse,
+ qty: item.consumed_quantity,
+ serial_no: item.serial_no,
+ company: frm.doc.company,
};
frappe.call({
- method: 'erpnext.stock.utils.get_incoming_rate',
+ method: "erpnext.stock.utils.get_incoming_rate",
args: {
- args: item_args
+ args: item_args,
+ },
+ callback: function (r) {
+ frappe.model.set_value(cdt, cdn, "valuation_rate", r.message);
},
- callback: function(r) {
- frappe.model.set_value(cdt, cdn, 'valuation_rate', r.message);
- }
});
},
- consumed_quantity: function(frm, cdt, cdn) {
+ consumed_quantity: function (frm, cdt, cdn) {
var row = locals[cdt][cdn];
- frappe.model.set_value(cdt, cdn, 'total_value', row.consumed_quantity * row.valuation_rate);
+ frappe.model.set_value(cdt, cdn, "total_value", row.consumed_quantity * row.valuation_rate);
},
});
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json
index accb5bf54b..218ff45ce7 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.json
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.json
@@ -264,7 +264,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2022-08-16 15:55:25.023471",
+ "modified": "2024-03-27 13:06:35.397626",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair",
@@ -302,10 +302,10 @@
"write": 1
}
],
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": [],
"title_field": "asset_name",
"track_changes": 1,
"track_seen": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 0b8450614c..ccde836fe0 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -17,6 +17,42 @@ from erpnext.controllers.accounts_controller import AccountsController
class AssetRepair(AccountsController):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ from erpnext.assets.doctype.asset_repair_consumed_item.asset_repair_consumed_item import (
+ AssetRepairConsumedItem,
+ )
+
+ actions_performed: DF.LongText | None
+ amended_from: DF.Link | None
+ asset: DF.Link
+ asset_name: DF.ReadOnly | None
+ capitalize_repair_cost: DF.Check
+ company: DF.Link | None
+ completion_date: DF.Datetime | None
+ cost_center: DF.Link | None
+ description: DF.LongText | None
+ downtime: DF.Data | None
+ failure_date: DF.Datetime
+ increase_in_asset_life: DF.Int
+ naming_series: DF.Literal["ACC-ASR-.YYYY.-"]
+ project: DF.Link | None
+ purchase_invoice: DF.Link | None
+ repair_cost: DF.Currency
+ repair_status: DF.Literal["Pending", "Completed", "Cancelled"]
+ stock_consumption: DF.Check
+ stock_entry: DF.Link | None
+ stock_items: DF.Table[AssetRepairConsumedItem]
+ total_repair_cost: DF.Currency
+ warehouse: DF.Link | None
+ # end: auto-generated types
+
def validate(self):
self.asset_doc = frappe.get_doc("Asset", self.asset)
self.update_status()
@@ -133,9 +169,7 @@ class AssetRepair(AccountsController):
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")
- )
+ 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."),
@@ -227,9 +261,7 @@ class AssetRepair(AccountsController):
def get_gl_entries(self):
gl_entries = []
- fixed_asset_account = get_asset_account(
- "fixed_asset_account", asset=self.asset, company=self.company
- )
+ fixed_asset_account = get_asset_account("fixed_asset_account", asset=self.asset, company=self.company)
self.get_gl_entries_for_repair_cost(gl_entries, fixed_asset_account)
self.get_gl_entries_for_consumed_items(gl_entries, fixed_asset_account)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair_list.js b/erpnext/assets/doctype/asset_repair/asset_repair_list.js
index 86376f4004..633c39ba77 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair_list.js
+++ b/erpnext/assets/doctype/asset_repair/asset_repair_list.js
@@ -1,12 +1,12 @@
-frappe.listview_settings['Asset Repair'] = {
+frappe.listview_settings["Asset Repair"] = {
add_fields: ["repair_status"],
- get_indicator: function(doc) {
- if(doc.repair_status=="Pending") {
+ get_indicator: function (doc) {
+ if (doc.repair_status == "Pending") {
return [__("Pending"), "orange"];
- } else if(doc.repair_status=="Completed") {
+ } else if (doc.repair_status == "Completed") {
return [__("Completed"), "green"];
- } else if(doc.repair_status=="Cancelled") {
+ } else if (doc.repair_status == "Cancelled") {
return [__("Cancelled"), "red"];
}
- }
+ },
};
diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
index 6d75871a35..d59c057df9 100644
--- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
@@ -199,9 +199,9 @@ class TestAssetRepair(unittest.TestCase):
self.assertEqual(expected_values[d.account][1], d.credit)
def test_gl_entries_with_periodical_inventory(self):
- frappe.db.set_value(
- "Company", "_Test Company", "default_expense_account", "Cost of Goods Sold - _TC"
- )
+ frappe.db.set_value("Company", "_Test Company", "default_expense_account", "Cost of Goods Sold - _TC")
+ frappe.db.set_value("Company", "_Test Company", "stock_adjustment_account", None) # @dokos
+
asset_repair = create_asset_repair(
capitalize_repair_cost=1,
stock_consumption=1,
@@ -244,7 +244,7 @@ class TestAssetRepair(unittest.TestCase):
asset = create_asset(calculate_depreciation=1, submit=1)
first_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Active")
initial_num_of_depreciations = num_of_depreciations(asset)
create_asset_repair(asset=asset, capitalize_repair_cost=1, submit=1)
@@ -253,8 +253,8 @@ class TestAssetRepair(unittest.TestCase):
first_asset_depr_schedule.load_from_db()
second_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
- self.assertEquals(second_asset_depr_schedule.status, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
+ self.assertEqual(second_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Cancelled")
self.assertEqual((initial_num_of_depreciations + 1), num_of_depreciations(asset))
self.assertEqual(
@@ -291,9 +291,7 @@ def create_asset_repair(**args):
if args.stock_consumption:
asset_repair.stock_consumption = 1
- asset_repair.warehouse = args.warehouse or create_warehouse(
- "Test Warehouse", company=asset.company
- )
+ asset_repair.warehouse = args.warehouse or create_warehouse("Test Warehouse", company=asset.company)
bundle = None
if args.serial_no:
diff --git a/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json b/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json
index 5fed16888c..f15b5a8667 100644
--- a/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json
+++ b/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json
@@ -56,13 +56,13 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2023-04-06 02:24:20.375870",
+ "modified": "2024-03-27 13:06:35.608355",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Repair Consumed Item",
"owner": "Administrator",
"permissions": [],
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
diff --git a/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.py b/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.py
index 2a8d64ef49..ab43cfe62a 100644
--- a/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.py
+++ b/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.py
@@ -6,4 +6,23 @@ from frappe.model.document import Document
class AssetRepairConsumedItem(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ consumed_quantity: DF.Data | None
+ item_code: DF.Link | None
+ parent: DF.Data
+ parentfield: DF.Data
+ parenttype: DF.Data
+ serial_and_batch_bundle: DF.Link | None
+ serial_no: DF.SmallText | None
+ total_value: DF.Currency
+ valuation_rate: DF.Currency
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/asset_shift_allocation/__init__.py b/erpnext/assets/doctype/asset_shift_allocation/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/assets/doctype/asset_shift_allocation/asset_shift_allocation.js b/erpnext/assets/doctype/asset_shift_allocation/asset_shift_allocation.js
new file mode 100644
index 0000000000..c22feb0545
--- /dev/null
+++ b/erpnext/assets/doctype/asset_shift_allocation/asset_shift_allocation.js
@@ -0,0 +1,14 @@
+// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+frappe.ui.form.on("Asset Shift Allocation", {
+ onload: function (frm) {
+ frm.events.make_schedules_editable(frm);
+ },
+
+ make_schedules_editable: function (frm) {
+ frm.toggle_enable("depreciation_schedule", true);
+ frm.fields_dict["depreciation_schedule"].grid.toggle_enable("schedule_date", false);
+ frm.fields_dict["depreciation_schedule"].grid.toggle_enable("depreciation_amount", false);
+ frm.fields_dict["depreciation_schedule"].grid.toggle_enable("shift", true);
+ },
+});
diff --git a/erpnext/assets/doctype/asset_shift_allocation/asset_shift_allocation.json b/erpnext/assets/doctype/asset_shift_allocation/asset_shift_allocation.json
new file mode 100644
index 0000000000..925f3b4b63
--- /dev/null
+++ b/erpnext/assets/doctype/asset_shift_allocation/asset_shift_allocation.json
@@ -0,0 +1,111 @@
+{
+ "actions": [],
+ "autoname": "naming_series:",
+ "creation": "2023-11-24 15:07:44.652133",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+ "section_break_esaa",
+ "asset",
+ "naming_series",
+ "column_break_tdae",
+ "finance_book",
+ "amended_from",
+ "depreciation_schedule_section",
+ "depreciation_schedule"
+ ],
+ "fields": [
+ {
+ "fieldname": "section_break_esaa",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Asset Shift Allocation",
+ "print_hide": 1,
+ "read_only": 1,
+ "search_index": 1
+ },
+ {
+ "fieldname": "asset",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Asset",
+ "options": "Asset",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_tdae",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "finance_book",
+ "fieldtype": "Link",
+ "label": "Finance Book",
+ "options": "Finance Book"
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "depreciation_schedule_section",
+ "fieldtype": "Section Break",
+ "label": "Depreciation Schedule"
+ },
+ {
+ "fieldname": "depreciation_schedule",
+ "fieldtype": "Table",
+ "label": "Depreciation Schedule",
+ "options": "Depreciation Schedule"
+ },
+ {
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Naming Series",
+ "options": "ACC-ASA-.YYYY.-",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2024-03-27 13:06:35.732191",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset Shift Allocation",
+ "naming_rule": "By \"Naming Series\" field",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "states": []
+}
diff --git a/erpnext/assets/doctype/asset_shift_allocation/asset_shift_allocation.py b/erpnext/assets/doctype/asset_shift_allocation/asset_shift_allocation.py
new file mode 100644
index 0000000000..323cb73fb8
--- /dev/null
+++ b/erpnext/assets/doctype/asset_shift_allocation/asset_shift_allocation.py
@@ -0,0 +1,273 @@
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe import _
+from frappe.model.document import Document
+from frappe.utils import (
+ add_months,
+ cint,
+ flt,
+ get_last_day,
+ get_link_to_form,
+ is_last_day_of_the_month,
+)
+
+from erpnext.assets.doctype.asset_activity.asset_activity import add_asset_activity
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+ get_asset_depr_schedule_doc,
+ get_asset_shift_factors_map,
+ get_temp_asset_depr_schedule_doc,
+)
+
+
+class AssetShiftAllocation(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ from erpnext.assets.doctype.depreciation_schedule.depreciation_schedule import (
+ DepreciationSchedule,
+ )
+
+ amended_from: DF.Link | None
+ asset: DF.Link
+ depreciation_schedule: DF.Table[DepreciationSchedule]
+ finance_book: DF.Link | None
+ naming_series: DF.Literal["ACC-ASA-.YYYY.-"]
+ # end: auto-generated types
+
+ def after_insert(self):
+ self.fetch_and_set_depr_schedule()
+
+ def validate(self):
+ self.asset_depr_schedule_doc = get_asset_depr_schedule_doc(self.asset, "Active", self.finance_book)
+
+ self.validate_invalid_shift_change()
+ self.update_depr_schedule()
+
+ def on_submit(self):
+ self.create_new_asset_depr_schedule()
+
+ def fetch_and_set_depr_schedule(self):
+ if self.asset_depr_schedule_doc:
+ if self.asset_depr_schedule_doc.shift_based:
+ for schedule in self.asset_depr_schedule_doc.get("depreciation_schedule"):
+ self.append(
+ "depreciation_schedule",
+ {
+ "schedule_date": schedule.schedule_date,
+ "depreciation_amount": schedule.depreciation_amount,
+ "accumulated_depreciation_amount": schedule.accumulated_depreciation_amount,
+ "journal_entry": schedule.journal_entry,
+ "shift": schedule.shift,
+ },
+ )
+
+ self.flags.ignore_validate = True
+ self.save()
+ else:
+ frappe.throw(
+ _(
+ "Asset Depreciation Schedule for Asset {0} and Finance Book {1} is not using shift based depreciation"
+ ).format(self.asset, self.finance_book)
+ )
+ else:
+ frappe.throw(
+ _("Asset Depreciation Schedule not found for Asset {0} and Finance Book {1}").format(
+ self.asset, self.finance_book
+ )
+ )
+
+ def validate_invalid_shift_change(self):
+ if not self.get("depreciation_schedule") or self.docstatus == 1:
+ return
+
+ for i, sch in enumerate(self.depreciation_schedule):
+ if sch.journal_entry and self.asset_depr_schedule_doc.depreciation_schedule[i].shift != sch.shift:
+ frappe.throw(
+ _(
+ "Row {0}: Shift cannot be changed since the depreciation has already been processed"
+ ).format(i)
+ )
+
+ def update_depr_schedule(self):
+ if not self.get("depreciation_schedule") or self.docstatus == 1:
+ return
+
+ self.allocate_shift_diff_in_depr_schedule()
+
+ asset_doc = frappe.get_doc("Asset", self.asset)
+ fb_row = asset_doc.finance_books[self.asset_depr_schedule_doc.finance_book_id - 1]
+
+ asset_doc.flags.shift_allocation = True
+
+ temp_depr_schedule = get_temp_asset_depr_schedule_doc(
+ asset_doc, fb_row, new_depr_schedule=self.depreciation_schedule
+ ).get("depreciation_schedule")
+
+ self.depreciation_schedule = []
+
+ for schedule in temp_depr_schedule:
+ self.append(
+ "depreciation_schedule",
+ {
+ "schedule_date": schedule.schedule_date,
+ "depreciation_amount": schedule.depreciation_amount,
+ "accumulated_depreciation_amount": schedule.accumulated_depreciation_amount,
+ "journal_entry": schedule.journal_entry,
+ "shift": schedule.shift,
+ },
+ )
+
+ def allocate_shift_diff_in_depr_schedule(self):
+ asset_shift_factors_map = get_asset_shift_factors_map()
+ reverse_asset_shift_factors_map = {asset_shift_factors_map[k]: k for k in asset_shift_factors_map}
+
+ original_shift_factors_sum = sum(
+ flt(asset_shift_factors_map.get(schedule.shift))
+ for schedule in self.asset_depr_schedule_doc.depreciation_schedule
+ )
+
+ new_shift_factors_sum = sum(
+ flt(asset_shift_factors_map.get(schedule.shift)) for schedule in self.depreciation_schedule
+ )
+
+ diff = new_shift_factors_sum - original_shift_factors_sum
+
+ if diff > 0:
+ for i, schedule in reversed(list(enumerate(self.depreciation_schedule))):
+ if diff <= 0:
+ break
+
+ shift_factor = flt(asset_shift_factors_map.get(schedule.shift))
+
+ if shift_factor <= diff:
+ self.depreciation_schedule.pop()
+ diff -= shift_factor
+ else:
+ try:
+ self.depreciation_schedule[i].shift = reverse_asset_shift_factors_map.get(
+ shift_factor - diff
+ )
+ diff = 0
+ except Exception:
+ frappe.throw(
+ _("Could not auto update shifts. Shift with shift factor {0} needed.")
+ ).format(shift_factor - diff)
+ elif diff < 0:
+ shift_factors = list(asset_shift_factors_map.values())
+ desc_shift_factors = sorted(shift_factors, reverse=True)
+ depr_schedule_len_diff = self.asset_depr_schedule_doc.total_number_of_depreciations - len(
+ self.depreciation_schedule
+ )
+ subsets_result = []
+
+ if depr_schedule_len_diff > 0:
+ num_rows_to_add = depr_schedule_len_diff
+
+ while not subsets_result and num_rows_to_add > 0:
+ find_subsets_with_sum(shift_factors, num_rows_to_add, abs(diff), [], subsets_result)
+ if subsets_result:
+ break
+ num_rows_to_add -= 1
+
+ if subsets_result:
+ for i in range(num_rows_to_add):
+ schedule_date = add_months(
+ self.depreciation_schedule[-1].schedule_date,
+ cint(self.asset_depr_schedule_doc.frequency_of_depreciation),
+ )
+
+ if is_last_day_of_the_month(self.depreciation_schedule[-1].schedule_date):
+ schedule_date = get_last_day(schedule_date)
+
+ self.append(
+ "depreciation_schedule",
+ {
+ "schedule_date": schedule_date,
+ "shift": reverse_asset_shift_factors_map.get(subsets_result[0][i]),
+ },
+ )
+
+ if depr_schedule_len_diff <= 0 or not subsets_result:
+ for i, schedule in reversed(list(enumerate(self.depreciation_schedule))):
+ diff = abs(diff)
+
+ if diff <= 0:
+ break
+
+ shift_factor = flt(asset_shift_factors_map.get(schedule.shift))
+
+ if shift_factor <= diff:
+ for sf in desc_shift_factors:
+ if sf - shift_factor <= diff:
+ self.depreciation_schedule[i].shift = reverse_asset_shift_factors_map.get(sf)
+ diff -= sf - shift_factor
+ break
+ else:
+ try:
+ self.depreciation_schedule[i].shift = reverse_asset_shift_factors_map.get(
+ shift_factor + diff
+ )
+ diff = 0
+ except Exception:
+ frappe.throw(
+ _("Could not auto update shifts. Shift with shift factor {0} needed.")
+ ).format(shift_factor + diff)
+
+ def create_new_asset_depr_schedule(self):
+ new_asset_depr_schedule_doc = frappe.copy_doc(self.asset_depr_schedule_doc)
+
+ new_asset_depr_schedule_doc.depreciation_schedule = []
+
+ for schedule in self.depreciation_schedule:
+ new_asset_depr_schedule_doc.append(
+ "depreciation_schedule",
+ {
+ "schedule_date": schedule.schedule_date,
+ "depreciation_amount": schedule.depreciation_amount,
+ "accumulated_depreciation_amount": schedule.accumulated_depreciation_amount,
+ "journal_entry": schedule.journal_entry,
+ "shift": schedule.shift,
+ },
+ )
+
+ notes = _(
+ "This schedule was created when Asset {0}'s shifts were adjusted through Asset Shift Allocation {1}."
+ ).format(
+ get_link_to_form("Asset", self.asset),
+ get_link_to_form(self.doctype, self.name),
+ )
+
+ new_asset_depr_schedule_doc.notes = notes
+
+ self.asset_depr_schedule_doc.flags.should_not_cancel_depreciation_entries = True
+ self.asset_depr_schedule_doc.cancel()
+
+ new_asset_depr_schedule_doc.submit()
+
+ add_asset_activity(
+ self.asset,
+ _("Asset's depreciation schedule updated after Asset Shift Allocation {0}").format(
+ get_link_to_form(self.doctype, self.name)
+ ),
+ )
+
+
+def find_subsets_with_sum(numbers, k, target_sum, current_subset, result):
+ if k == 0 and target_sum == 0:
+ result.append(current_subset.copy())
+ return
+ if k <= 0 or target_sum <= 0 or not numbers:
+ return
+
+ # Include the current number in the subset
+ find_subsets_with_sum(numbers, k - 1, target_sum - numbers[0], [*current_subset, numbers[0]], result)
+
+ # Exclude the current number from the subset
+ find_subsets_with_sum(numbers[1:], k, target_sum, current_subset, result)
diff --git a/erpnext/assets/doctype/asset_shift_allocation/test_asset_shift_allocation.py b/erpnext/assets/doctype/asset_shift_allocation/test_asset_shift_allocation.py
new file mode 100644
index 0000000000..8d00a24f6b
--- /dev/null
+++ b/erpnext/assets/doctype/asset_shift_allocation/test_asset_shift_allocation.py
@@ -0,0 +1,113 @@
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+import frappe
+from frappe.tests.utils import FrappeTestCase
+from frappe.utils import cstr
+
+from erpnext.assets.doctype.asset.test_asset import create_asset
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+ get_depr_schedule,
+)
+
+
+class TestAssetShiftAllocation(FrappeTestCase):
+ @classmethod
+ def setUpClass(cls):
+ create_asset_shift_factors()
+
+ @classmethod
+ def tearDownClass(cls):
+ frappe.db.rollback()
+
+ def test_asset_shift_allocation(self):
+ asset = create_asset(
+ calculate_depreciation=1,
+ available_for_use_date="2023-01-01",
+ purchase_date="2023-01-01",
+ gross_purchase_amount=120000,
+ depreciation_start_date="2023-01-31",
+ total_number_of_depreciations=12,
+ frequency_of_depreciation=1,
+ shift_based=1,
+ submit=1,
+ )
+
+ expected_schedules = [
+ ["2023-01-31", 10000.0, 10000.0, "Single"],
+ ["2023-02-28", 10000.0, 20000.0, "Single"],
+ ["2023-03-31", 10000.0, 30000.0, "Single"],
+ ["2023-04-30", 10000.0, 40000.0, "Single"],
+ ["2023-05-31", 10000.0, 50000.0, "Single"],
+ ["2023-06-30", 10000.0, 60000.0, "Single"],
+ ["2023-07-31", 10000.0, 70000.0, "Single"],
+ ["2023-08-31", 10000.0, 80000.0, "Single"],
+ ["2023-09-30", 10000.0, 90000.0, "Single"],
+ ["2023-10-31", 10000.0, 100000.0, "Single"],
+ ["2023-11-30", 10000.0, 110000.0, "Single"],
+ ["2023-12-31", 10000.0, 120000.0, "Single"],
+ ]
+
+ schedules = [
+ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount, d.shift]
+ for d in get_depr_schedule(asset.name, "Active")
+ ]
+
+ self.assertEqual(schedules, expected_schedules)
+
+ asset_shift_allocation = frappe.get_doc(
+ {"doctype": "Asset Shift Allocation", "asset": asset.name}
+ ).insert()
+
+ schedules = [
+ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount, d.shift]
+ for d in asset_shift_allocation.get("depreciation_schedule")
+ ]
+
+ self.assertEqual(schedules, expected_schedules)
+
+ asset_shift_allocation = frappe.get_doc("Asset Shift Allocation", asset_shift_allocation.name)
+ asset_shift_allocation.depreciation_schedule[4].shift = "Triple"
+ asset_shift_allocation.save()
+
+ schedules = [
+ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount, d.shift]
+ for d in asset_shift_allocation.get("depreciation_schedule")
+ ]
+
+ expected_schedules = [
+ ["2023-01-31", 10000.0, 10000.0, "Single"],
+ ["2023-02-28", 10000.0, 20000.0, "Single"],
+ ["2023-03-31", 10000.0, 30000.0, "Single"],
+ ["2023-04-30", 10000.0, 40000.0, "Single"],
+ ["2023-05-31", 20000.0, 60000.0, "Triple"],
+ ["2023-06-30", 10000.0, 70000.0, "Single"],
+ ["2023-07-31", 10000.0, 80000.0, "Single"],
+ ["2023-08-31", 10000.0, 90000.0, "Single"],
+ ["2023-09-30", 10000.0, 100000.0, "Single"],
+ ["2023-10-31", 10000.0, 110000.0, "Single"],
+ ["2023-11-30", 10000.0, 120000.0, "Single"],
+ ]
+
+ self.assertEqual(schedules, expected_schedules)
+
+ asset_shift_allocation.submit()
+
+ schedules = [
+ [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount, d.shift]
+ for d in get_depr_schedule(asset.name, "Active")
+ ]
+
+ self.assertEqual(schedules, expected_schedules)
+
+
+def create_asset_shift_factors():
+ shifts = [
+ {"doctype": "Asset Shift Factor", "shift_name": "Half", "shift_factor": 0.5, "default": 0},
+ {"doctype": "Asset Shift Factor", "shift_name": "Single", "shift_factor": 1, "default": 1},
+ {"doctype": "Asset Shift Factor", "shift_name": "Double", "shift_factor": 1.5, "default": 0},
+ {"doctype": "Asset Shift Factor", "shift_name": "Triple", "shift_factor": 2, "default": 0},
+ ]
+
+ for s in shifts:
+ frappe.get_doc(s).insert()
diff --git a/erpnext/assets/doctype/asset_shift_factor/__init__.py b/erpnext/assets/doctype/asset_shift_factor/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/assets/doctype/asset_shift_factor/asset_shift_factor.js b/erpnext/assets/doctype/asset_shift_factor/asset_shift_factor.js
new file mode 100644
index 0000000000..88887fea87
--- /dev/null
+++ b/erpnext/assets/doctype/asset_shift_factor/asset_shift_factor.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+// frappe.ui.form.on("Asset Shift Factor", {
+// refresh(frm) {
+
+// },
+// });
diff --git a/erpnext/assets/doctype/asset_shift_factor/asset_shift_factor.json b/erpnext/assets/doctype/asset_shift_factor/asset_shift_factor.json
new file mode 100644
index 0000000000..98757fa66b
--- /dev/null
+++ b/erpnext/assets/doctype/asset_shift_factor/asset_shift_factor.json
@@ -0,0 +1,74 @@
+{
+ "actions": [],
+ "allow_rename": 1,
+ "autoname": "field:shift_name",
+ "creation": "2023-11-27 18:16:03.980086",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+ "shift_name",
+ "shift_factor",
+ "default"
+ ],
+ "fields": [
+ {
+ "fieldname": "shift_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Shift Name",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "shift_factor",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Shift Factor",
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "default",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Default"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2024-03-27 13:06:35.869900",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset Shift Factor",
+ "naming_rule": "By fieldname",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "states": []
+}
diff --git a/erpnext/assets/doctype/asset_shift_factor/asset_shift_factor.py b/erpnext/assets/doctype/asset_shift_factor/asset_shift_factor.py
new file mode 100644
index 0000000000..4af7067f28
--- /dev/null
+++ b/erpnext/assets/doctype/asset_shift_factor/asset_shift_factor.py
@@ -0,0 +1,35 @@
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe import _
+from frappe.model.document import Document
+
+
+class AssetShiftFactor(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ default: DF.Check
+ shift_factor: DF.Float
+ shift_name: DF.Data
+ # end: auto-generated types
+
+ def validate(self):
+ self.validate_default()
+
+ def validate_default(self):
+ if self.default:
+ existing_default_shift_factor = frappe.db.get_value("Asset Shift Factor", {"default": 1}, "name")
+
+ if existing_default_shift_factor:
+ frappe.throw(
+ _("Asset Shift Factor {0} is set as default currently. Please change it first.").format(
+ frappe.bold(existing_default_shift_factor)
+ )
+ )
diff --git a/erpnext/assets/doctype/asset_shift_factor/test_asset_shift_factor.py b/erpnext/assets/doctype/asset_shift_factor/test_asset_shift_factor.py
new file mode 100644
index 0000000000..75073673c0
--- /dev/null
+++ b/erpnext/assets/doctype/asset_shift_factor/test_asset_shift_factor.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+from frappe.tests.utils import FrappeTestCase
+
+
+class TestAssetShiftFactor(FrappeTestCase):
+ pass
diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js
index 3620049ba0..917c678be3 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js
+++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js
@@ -3,57 +3,57 @@
frappe.provide("erpnext.accounts.dimensions");
-frappe.ui.form.on('Asset Value Adjustment', {
- setup: function(frm) {
- frm.add_fetch('company', 'cost_center', 'cost_center');
- frm.set_query('cost_center', function() {
+frappe.ui.form.on("Asset Value Adjustment", {
+ setup: function (frm) {
+ frm.add_fetch("company", "cost_center", "cost_center");
+ frm.set_query("cost_center", function () {
return {
filters: {
company: frm.doc.company,
- is_group: 0
- }
- }
+ is_group: 0,
+ },
+ };
});
- frm.set_query('asset', function() {
+ frm.set_query("asset", function () {
return {
filters: {
calculate_depreciation: 1,
- docstatus: 1
- }
+ docstatus: 1,
+ },
};
});
},
- onload: function(frm) {
- if(frm.is_new() && frm.doc.asset) {
+ onload: function (frm) {
+ if (frm.is_new() && frm.doc.asset) {
frm.trigger("set_current_asset_value");
}
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
- company: function(frm) {
+ company: function (frm) {
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
- asset: function(frm) {
+ asset: function (frm) {
frm.trigger("set_current_asset_value");
},
- finance_book: function(frm) {
+ finance_book: function (frm) {
frm.trigger("set_current_asset_value");
},
- set_current_asset_value: function(frm) {
+ set_current_asset_value: function (frm) {
if (frm.doc.asset) {
frm.call({
method: "erpnext.assets.doctype.asset.asset.get_asset_value_after_depreciation",
args: {
asset_name: frm.doc.asset,
- finance_book: frm.doc.finance_book
+ finance_book: frm.doc.finance_book,
},
- callback: function(r) {
+ callback: function (r) {
if (r.message) {
- frm.set_value('current_asset_value', r.message);
+ frm.set_value("current_asset_value", r.message);
}
- }
+ },
});
}
- }
+ },
});
diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json
index a255825a7f..743e2a61c8 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json
+++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json
@@ -1,185 +1,186 @@
{
- "actions": [],
- "creation": "2018-05-11 00:22:43.695151",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "company",
- "asset",
- "asset_category",
- "column_break_4",
- "date",
- "finance_book",
- "amended_from",
- "value_details_section",
- "current_asset_value",
- "new_asset_value",
- "column_break_11",
- "difference_amount",
- "journal_entry",
- "accounting_dimensions_section",
- "cost_center",
- "dimension_col_break"
- ],
- "fields": [
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "label": "Company",
- "options": "Company"
- },
- {
- "fieldname": "asset",
- "fieldtype": "Link",
- "label": "Asset",
- "options": "Asset",
- "reqd": 1
- },
- {
- "fetch_from": "asset.asset_category",
- "fieldname": "asset_category",
- "fieldtype": "Read Only",
- "label": "Asset Category"
- },
- {
- "fieldname": "finance_book",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Finance Book",
- "options": "Finance Book"
- },
- {
- "fieldname": "journal_entry",
- "fieldtype": "Link",
- "label": "Journal Entry",
- "options": "Journal Entry",
- "read_only": 1
- },
- {
- "fieldname": "column_break_4",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "date",
- "fieldtype": "Date",
- "label": "Date",
- "reqd": 1
- },
- {
- "fieldname": "current_asset_value",
- "fieldtype": "Currency",
- "in_list_view": 1,
- "label": "Current Asset Value",
- "read_only": 1,
- "reqd": 1
- },
- {
- "fieldname": "new_asset_value",
- "fieldtype": "Currency",
- "in_list_view": 1,
- "label": "New Asset Value",
- "reqd": 1
- },
- {
- "fieldname": "difference_amount",
- "fieldtype": "Currency",
- "label": "Difference Amount",
- "no_copy": 1,
- "read_only": 1
- },
- {
- "fieldname": "cost_center",
- "fieldtype": "Link",
- "label": "Cost Center",
- "options": "Cost Center"
- },
- {
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "label": "Amended From",
- "no_copy": 1,
- "options": "Asset Value Adjustment",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "accounting_dimensions_section",
- "fieldtype": "Section Break",
- "label": "Accounting Dimensions"
- },
- {
- "fieldname": "dimension_col_break",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "value_details_section",
- "fieldtype": "Section Break",
- "label": "Value Details"
- },
- {
- "fieldname": "column_break_11",
- "fieldtype": "Column Break"
- }
- ],
- "index_web_pages_for_search": 1,
- "is_submittable": 1,
- "links": [],
- "modified": "2021-01-22 14:10:23.085181",
- "modified_by": "Administrator",
- "module": "Assets",
- "name": "Asset Value Adjustment",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts User",
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts Manager",
- "share": 1,
- "submit": 1,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "asset",
- "track_changes": 1
- }
\ No newline at end of file
+ "actions": [],
+ "creation": "2018-05-11 00:22:43.695151",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company",
+ "asset",
+ "asset_category",
+ "column_break_4",
+ "date",
+ "finance_book",
+ "amended_from",
+ "value_details_section",
+ "current_asset_value",
+ "new_asset_value",
+ "column_break_11",
+ "difference_amount",
+ "journal_entry",
+ "accounting_dimensions_section",
+ "cost_center",
+ "dimension_col_break"
+ ],
+ "fields": [
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company"
+ },
+ {
+ "fieldname": "asset",
+ "fieldtype": "Link",
+ "label": "Asset",
+ "options": "Asset",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "asset.asset_category",
+ "fieldname": "asset_category",
+ "fieldtype": "Read Only",
+ "label": "Asset Category"
+ },
+ {
+ "fieldname": "finance_book",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Finance Book",
+ "options": "Finance Book"
+ },
+ {
+ "fieldname": "journal_entry",
+ "fieldtype": "Link",
+ "label": "Journal Entry",
+ "options": "Journal Entry",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "date",
+ "fieldtype": "Date",
+ "label": "Date",
+ "reqd": 1
+ },
+ {
+ "fieldname": "current_asset_value",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Current Asset Value",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "new_asset_value",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "New Asset Value",
+ "reqd": 1
+ },
+ {
+ "fieldname": "difference_amount",
+ "fieldtype": "Currency",
+ "label": "Difference Amount",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "cost_center",
+ "fieldtype": "Link",
+ "label": "Cost Center",
+ "options": "Cost Center"
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Asset Value Adjustment",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "accounting_dimensions_section",
+ "fieldtype": "Section Break",
+ "label": "Accounting Dimensions"
+ },
+ {
+ "fieldname": "dimension_col_break",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "value_details_section",
+ "fieldtype": "Section Break",
+ "label": "Value Details"
+ },
+ {
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2024-03-27 13:06:36.004049",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset Value Adjustment",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "states": [],
+ "title_field": "asset",
+ "track_changes": 1
+}
diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
index 9be7243602..eaf7ef3332 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
+++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
@@ -77,7 +77,9 @@ class AssetValueAdjustment(Document):
je.naming_series = depreciation_series
je.posting_date = self.date
je.company = self.company
- je.remark = "Depreciation Entry against {0} worth {1}".format(self.asset, self.difference_amount)
+ je.remark = frappe._("Depreciation Entry against {} worth {}").format(
+ self.asset, self.difference_amount
+ )
je.finance_book = self.finance_book
credit_entry = {
diff --git a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py
index 2c97baece5..634ed41377 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py
+++ b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py
@@ -23,9 +23,7 @@ class TestAssetValueAdjustment(unittest.TestCase):
)
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)
@@ -52,9 +50,7 @@ class TestAssetValueAdjustment(unittest.TestCase):
self.assertEqual(current_value, 100000.0)
def test_asset_depreciation_value_adjustment(self):
- pr = make_purchase_receipt(
- item_code="Macbook Pro", qty=1, rate=120000.0, location="Test Location"
- )
+ pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=120000.0, location="Test Location")
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, "name")
asset_doc = frappe.get_doc("Asset", asset_name)
@@ -75,7 +71,7 @@ class TestAssetValueAdjustment(unittest.TestCase):
asset_doc.submit()
first_asset_depr_schedule = get_asset_depr_schedule_doc(asset_doc.name, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Active")
post_depreciation_entries(getdate("2023-08-21"))
@@ -92,8 +88,8 @@ class TestAssetValueAdjustment(unittest.TestCase):
first_asset_depr_schedule.load_from_db()
second_asset_depr_schedule = get_asset_depr_schedule_doc(asset_doc.name, "Active")
- self.assertEquals(second_asset_depr_schedule.status, "Active")
- self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
+ self.assertEqual(second_asset_depr_schedule.status, "Active")
+ self.assertEqual(first_asset_depr_schedule.status, "Cancelled")
expected_gle = (
("_Test Accumulated Depreciations - _TC", 0.0, 4625.29),
diff --git a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json
index 3c5e5ced35..ad09c36948 100644
--- a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json
+++ b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json
@@ -12,6 +12,7 @@
"column_break_3",
"accumulated_depreciation_amount",
"journal_entry",
+ "shift",
"make_depreciation_entry"
],
"fields": [
@@ -57,18 +58,24 @@
"fieldname": "make_depreciation_entry",
"fieldtype": "Button",
"label": "Make Depreciation Entry"
+ },
+ {
+ "fieldname": "shift",
+ "fieldtype": "Link",
+ "label": "Shift",
+ "options": "Asset Shift Factor"
}
],
"istable": 1,
"links": [],
- "modified": "2023-07-26 12:56:48.718736",
+ "modified": "2024-03-27 13:06:51.227001",
"modified_by": "Administrator",
"module": "Assets",
"name": "Depreciation Schedule",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": []
}
diff --git a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.py b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.py
index b597c58752..41aade6591 100644
--- a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.py
+++ b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.py
@@ -6,4 +6,22 @@ from frappe.model.document import Document
class DepreciationSchedule(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ accumulated_depreciation_amount: DF.Currency
+ depreciation_amount: DF.Currency
+ journal_entry: DF.Link | None
+ parent: DF.Data
+ parentfield: DF.Data
+ parenttype: DF.Data
+ schedule_date: DF.Date
+ shift: DF.Link | None
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/linked_location/linked_location.json b/erpnext/assets/doctype/linked_location/linked_location.json
index f04a79e593..455ef61629 100644
--- a/erpnext/assets/doctype/linked_location/linked_location.json
+++ b/erpnext/assets/doctype/linked_location/linked_location.json
@@ -1,74 +1,33 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2017-11-22 14:34:59.461273",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "creation": "2017-11-22 14:34:59.461273",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "location"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "location",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Location",
- "length": 0,
- "no_copy": 0,
- "options": "Location",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "location",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Location",
+ "options": "Location",
+ "reqd": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2018-06-20 04:35:59.514281",
- "modified_by": "Administrator",
- "module": "Assets",
- "name": "Linked Location",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2024-03-27 13:10:02.464102",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Linked Location",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "states": [],
+ "track_changes": 1
+}
diff --git a/erpnext/assets/doctype/linked_location/linked_location.py b/erpnext/assets/doctype/linked_location/linked_location.py
index 5acba70505..35e6d8b41d 100644
--- a/erpnext/assets/doctype/linked_location/linked_location.py
+++ b/erpnext/assets/doctype/linked_location/linked_location.py
@@ -2,9 +2,22 @@
# For license information, please see license.txt
-import frappe
from frappe.model.document import Document
class LinkedLocation(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ location: DF.Link
+ parent: DF.Data
+ parentfield: DF.Data
+ parenttype: DF.Data
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/location/location.js b/erpnext/assets/doctype/location/location.js
index 0f069b2fd8..97d7239158 100644
--- a/erpnext/assets/doctype/location/location.js
+++ b/erpnext/assets/doctype/location/location.js
@@ -1,13 +1,13 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Location', {
+frappe.ui.form.on("Location", {
setup: function (frm) {
frm.set_query("parent_location", function () {
return {
- "filters": {
- "is_group": 1
- }
+ filters: {
+ is_group: 1,
+ },
};
});
},
@@ -15,10 +15,9 @@ frappe.ui.form.on('Location', {
onload_post_render(frm) {
if (!frm.doc.location && frm.doc.latitude && frm.doc.longitude) {
frm.fields_dict.location.map.setView([frm.doc.latitude, frm.doc.longitude], 13);
- }
- else {
- frm.doc.latitude = frm.fields_dict.location.map.getCenter()['lat'];
- frm.doc.longitude = frm.fields_dict.location.map.getCenter()['lng'];
+ } else {
+ frm.doc.latitude = frm.fields_dict.location.map.getCenter()["lat"];
+ frm.doc.longitude = frm.fields_dict.location.map.getCenter()["lng"];
}
},
});
diff --git a/erpnext/assets/doctype/location/location.json b/erpnext/assets/doctype/location/location.json
index 47dd7784c7..64fc4f52e4 100644
--- a/erpnext/assets/doctype/location/location.json
+++ b/erpnext/assets/doctype/location/location.json
@@ -142,7 +142,7 @@
],
"is_tree": 1,
"links": [],
- "modified": "2023-08-29 12:49:33.290527",
+ "modified": "2024-03-27 13:10:02.572355",
"modified_by": "Administrator",
"module": "Assets",
"name": "Location",
@@ -197,11 +197,33 @@
"role": "Stock Manager",
"share": 1,
"write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Agriculture Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Agriculture User",
+ "share": 1,
+ "write": 1
}
],
"quick_entry": 1,
"show_name_in_global_search": 1,
- "sort_field": "modified",
+ "sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
diff --git a/erpnext/assets/doctype/location/location.py b/erpnext/assets/doctype/location/location.py
index 5bff3dd8c9..03d0980b03 100644
--- a/erpnext/assets/doctype/location/location.py
+++ b/erpnext/assets/doctype/location/location.py
@@ -13,6 +13,27 @@ EARTH_RADIUS = 6378137
class Location(NestedSet):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ area: DF.Float
+ area_uom: DF.Link | None
+ is_container: DF.Check
+ is_group: DF.Check
+ latitude: DF.Float
+ lft: DF.Int
+ location_name: DF.Data
+ longitude: DF.Float
+ old_parent: DF.Data | None
+ parent_location: DF.Link | None
+ rgt: DF.Int
+ # end: auto-generated types
+
nsm_parent_field = "parent_location"
def validate(self):
@@ -195,17 +216,15 @@ def get_children(doctype, parent=None, location=None, is_root=False):
parent = ""
return frappe.db.sql(
- """
+ f"""
select
name as value,
is_group as expandable
from
`tabLocation` comp
where
- ifnull(parent_location, "")={parent}
- """.format(
- parent=frappe.db.escape(parent)
- ),
+ ifnull(parent_location, "")={frappe.db.escape(parent)}
+ """,
as_dict=1,
)
diff --git a/erpnext/assets/doctype/location/location_tree.js b/erpnext/assets/doctype/location/location_tree.js
index b405afd1dd..c3484c2469 100644
--- a/erpnext/assets/doctype/location/location_tree.js
+++ b/erpnext/assets/doctype/location/location_tree.js
@@ -1,7 +1,7 @@
frappe.treeview_settings["Location"] = {
ignore_fields: ["parent_location"],
- get_tree_nodes: 'erpnext.assets.doctype.location.location.get_children',
- add_tree_node: 'erpnext.assets.doctype.location.location.add_node',
+ get_tree_nodes: "erpnext.assets.doctype.location.location.get_children",
+ add_tree_node: "erpnext.assets.doctype.location.location.add_node",
filters: [
{
fieldname: "location",
@@ -10,9 +10,9 @@ frappe.treeview_settings["Location"] = {
label: __("Location"),
get_query: function () {
return {
- filters: [["Location", "is_group", "=", 1]]
+ filters: [["Location", "is_group", "=", 1]],
};
- }
+ },
},
],
breadcrumb: "Assets",
@@ -24,10 +24,10 @@ frappe.treeview_settings["Location"] = {
action: function () {
frappe.new_doc("Location", true);
},
- condition: 'frappe.boot.user.can_create.indexOf("Location") !== -1'
- }
+ condition: 'frappe.boot.user.can_create.indexOf("Location") !== -1',
+ },
],
onload: function (treeview) {
treeview.make_tree();
- }
-};
\ No newline at end of file
+ },
+};
diff --git a/erpnext/assets/doctype/location/test_location.py b/erpnext/assets/doctype/location/test_location.py
index 27ba6345fb..3b5af61fd4 100644
--- a/erpnext/assets/doctype/location/test_location.py
+++ b/erpnext/assets/doctype/location/test_location.py
@@ -1,7 +1,6 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
-
import json
import unittest
@@ -32,9 +31,7 @@ class TestLocation(unittest.TestCase):
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"]
- )
+ 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"))
diff --git a/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.js b/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.js
index 2db712546c..6f3521ffd8 100644
--- a/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.js
+++ b/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.js
@@ -1,8 +1,6 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Maintenance Team Member', {
- refresh: function() {
-
- }
+frappe.ui.form.on("Maintenance Team Member", {
+ refresh: function () {},
});
diff --git a/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.json b/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.json
index 5155b0b426..f13bbbbf17 100644
--- a/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.json
+++ b/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.json
@@ -1,140 +1,57 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "field:team_member",
- "beta": 0,
- "creation": "2016-10-26 10:56:04.534717",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "autoname": "field:team_member",
+ "creation": "2016-10-26 10:56:04.534717",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "team_member",
+ "full_name",
+ "maintenance_role"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "team_member",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Team Member",
- "length": 0,
- "no_copy": 0,
- "options": "User",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "team_member",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Team Member",
+ "options": "User",
+ "reqd": 1,
+ "unique": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
"fetch_from": "team_member.full_name",
- "fieldname": "full_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Full Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "full_name",
+ "fieldtype": "Data",
+ "in_filter": 1,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Full Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "maintenance_role",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Maintenance Role",
- "length": 0,
- "no_copy": 0,
- "options": "Role",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "maintenance_role",
+ "fieldtype": "Link",
+ "in_filter": 1,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Maintenance Role",
+ "options": "Role",
+ "reqd": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2018-05-16 22:43:15.255185",
- "modified_by": "Administrator",
- "module": "Assets",
- "name": "Maintenance Team Member",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0
-}
\ No newline at end of file
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2024-03-27 13:10:04.127108",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Maintenance Team Member",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "states": []
+}
diff --git a/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.py b/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.py
index 670731fb55..80a6a563b8 100644
--- a/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.py
+++ b/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.py
@@ -2,9 +2,24 @@
# For license information, please see license.txt
-import frappe
from frappe.model.document import Document
class MaintenanceTeamMember(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ full_name: DF.Data | None
+ maintenance_role: DF.Link
+ parent: DF.Data
+ parentfield: DF.Data
+ parenttype: DF.Data
+ team_member: DF.Link
+ # end: auto-generated types
+
pass
diff --git a/erpnext/assets/doctype/maintenance_team_member/test_maintenance_team_member.py b/erpnext/assets/doctype/maintenance_team_member/test_maintenance_team_member.py
index a955b38567..911a6544e9 100644
--- a/erpnext/assets/doctype/maintenance_team_member/test_maintenance_team_member.py
+++ b/erpnext/assets/doctype/maintenance_team_member/test_maintenance_team_member.py
@@ -1,7 +1,6 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
-
import unittest
diff --git a/erpnext/regional/france/assets.py b/erpnext/regional/france/assets.py
index 2a17b42877..74215922fc 100644
--- a/erpnext/regional/france/assets.py
+++ b/erpnext/regional/france/assets.py
@@ -1,25 +1,34 @@
from frappe.utils import add_months, cint, date_diff, flt, get_last_day, getdate
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+ get_straight_line_or_manual_depr_amount,
+)
+
def get_depreciation_amount(
- asset_depr_schedule, asset, depreciable_value, yearly_opening_wdv, row, *args, **kwargs
+ asset_depr_schedule,
+ asset,
+ depreciable_value,
+ yearly_opening_wdv,
+ fb_row,
+ schedule_idx=0,
+ prev_depreciation_amount=0,
+ has_wdv_or_dd_non_yearly_pro_rata=False,
+ number_of_pending_depreciations=0,
+ prev_per_day_depr=0,
):
- if row.depreciation_method in ("Straight Line", "Manual"):
+ if fb_row.depreciation_method in ("Straight Line", "Manual"):
# if the Depreciation Schedule is being prepared for the first time
if not asset.flags.increase_in_asset_life:
depreciation_amount = (
- flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
- ) / flt(row.total_number_of_depreciations)
+ flt(asset.gross_purchase_amount) - flt(fb_row.expected_value_after_useful_life)
+ ) / flt(fb_row.total_number_of_depreciations)
- # if the Depreciation Schedule is being modified after Asset Repair
- else:
- depreciation_amount = (
- flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
- ) / (date_diff(asset.to_date, asset.available_for_use_date) / 365)
- else:
- depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100))
+ return depreciation_amount, None
- return depreciation_amount
+ return get_straight_line_or_manual_depr_amount(
+ asset_depr_schedule, asset, fb_row, schedule_idx, number_of_pending_depreciations
+ ), None
def get_total_days(date, frequency):
--
GitLab