From b4141b9b5b3d81386f5d2fb60adf31f417d3e650 Mon Sep 17 00:00:00 2001 From: Gowtham M Date: Fri, 24 Jul 2026 11:48:07 +0530 Subject: [PATCH] assets list api changes --- docs/MODULE_DATA_FLOW.html | 83 ++++++++++++++++++++++-- docs/MODULE_DATA_FLOW.md | 97 ++++++++++++++++++++++++++-- src/docs/assets-routes.yaml | 3 + src/modules/assets/assets.service.js | 30 ++++++--- 4 files changed, 194 insertions(+), 19 deletions(-) diff --git a/docs/MODULE_DATA_FLOW.html b/docs/MODULE_DATA_FLOW.html index e7a2ac7..8197f48 100644 --- a/docs/MODULE_DATA_FLOW.html +++ b/docs/MODULE_DATA_FLOW.html @@ -892,7 +892,7 @@ flowchart TD end PREVIEW --> CALC[calculateDepreciation] - CREATE --> STORE[(assets: method, rate, cost, salvage, life, purchase_date)] + CREATE --> STORE[(assets: method, rate, cost, salvage, life, commencement/purchase date)] STORE --> READ["GET /assets/:id"] READ --> CALC @@ -903,19 +903,92 @@ flowchart TD OTHER --> CALC + +

Input fields used in calculation

- + - - - + + + + + + + +
MethodRate auto-calc?Formula concept
FieldMeaningRole in formula
SLMYes (if rate omitted)Equal yearly depreciation on original cost
WDVYes (if rate omitted)Depreciation on reducing book value year-by-year
OTHERNo — user must send depreciation_rateCustom % on cost
purchase_costAsset cost / amountStarting book value; base for rate & annual dep
salvage_valueResidual value at end of lifeFloor for book value; used in rate auto-calc
useful_life_yearsExpected life in yearsRate auto-calc + cap on years elapsed
commencement_dateUsage / put-to-use datePrimary start date for years elapsed
purchase_datePurchase dateFallback start date if commencement is null
depreciation_methodSLM / WDV / OTHERWhich formula path to run
depreciation_rate% per yearOptional for SLM/WDV (auto); required for OTHER
as_of_dateCalculate as of (preview only)Defaults to today
+ +

Date → years elapsed

+
depreciation_start_date = commencement_date || purchase_date
+years_elapsed           = (as_of_date − depreciation_start_date) / 365.25 days
+capped_years            = min(years_elapsed, useful_life_years)   // if life is set
+
+

Accumulated depreciation uses capped_years so it never exceeds useful life.

+ +

Method 1 — SLM (Straight Line)

+

Equal depreciation every year on original cost, never below salvage.

+

Auto rate (when depreciation_rate omitted):

+
depreciable_amount = max(purchase_cost − salvage_value, 0)
+depreciation_rate  = (depreciable_amount / purchase_cost / useful_life_years) × 100
+
+

Amounts:

+
annual_depreciation      = purchase_cost × rate / 100
+accumulated_depreciation = min(annual_depreciation × capped_years, purchase_cost − salvage_value)
+book_value               = max(purchase_cost − accumulated_depreciation, salvage_value)
+
+

Example: cost = ₹1,00,000 · salvage = ₹10,000 · life = 10 years · start = 1 year ago

+ + +

Method 2 — WDV (Written Down Value)

+

Depreciation each year on the reducing book value (not original cost). Book value never goes below salvage.

+

Auto rate (when depreciation_rate omitted; needs salvage > 0 and < cost):

+
depreciation_rate = (1 − (salvage_value / purchase_cost)^(1 / useful_life_years)) × 100
+
+

Amounts (year-by-year):

+
book_value = purchase_cost
+for each full year in capped_years:
+    year_dep   = book_value × rate / 100
+    book_value = max(book_value − year_dep, salvage_value)
+if fractional year remains:
+    year_dep   = (book_value × rate / 100) × fraction
+    book_value = max(book_value − year_dep, salvage_value)
+
+accumulated_depreciation = purchase_cost − book_value
+annual_depreciation      = book_value × rate / 100   // next year's dep on current WDV
+
+

Example: cost = ₹1,00,000 · salvage = ₹10,000 · life = 10 years · start = 1 year ago

+ + +

OTHER method

+

Same accumulation style as SLM, but depreciation_rate is mandatory (no auto-calc).

+ + + + + + + + +
MethodRate auto-calc?Depreciates onSalvage role
SLMYes (if rate omitted)Original purchase_cost every yearIn rate formula + book-value floor
WDVYes (if rate omitted)Reducing book value each yearIn rate formula + book-value floor
OTHERNo — send depreciation_rateOriginal cost × rate (like SLM)Book-value floor only
+

FE usage:

12. Alerts flow (cross-asset dashboards)

diff --git a/docs/MODULE_DATA_FLOW.md b/docs/MODULE_DATA_FLOW.md index fff00fe..6b4a66b 100644 --- a/docs/MODULE_DATA_FLOW.md +++ b/docs/MODULE_DATA_FLOW.md @@ -501,7 +501,7 @@ flowchart TD end PREVIEW --> CALC[calculateDepreciation] - CREATE --> STORE[(assets: method, rate, cost, salvage, life, purchase_date)] + CREATE --> STORE[(assets: method, rate, cost, salvage, life, commencement/purchase date)] STORE --> READ["GET /assets/:id"] READ --> CALC @@ -512,17 +512,104 @@ flowchart TD OTHER --> CALC ``` -| Method | Rate auto-calc? | Formula concept | +### Input fields used in calculation + +| Field | Meaning | Role in formula | |---|---|---| -| **SLM** | Yes (if rate omitted) | Equal yearly depreciation on original cost | -| **WDV** | Yes (if rate omitted) | Depreciation on reducing book value year-by-year | -| **OTHER** | No — user must send `depreciation_rate` | Custom % on cost | +| `purchase_cost` | Asset cost / amount | Starting book value; base for rate & annual dep | +| `salvage_value` | Residual value at end of life | Floor for book value; used in rate auto-calc | +| `useful_life_years` | Expected life in years | Rate auto-calc + cap on years elapsed | +| `commencement_date` | Usage / put-to-use date | **Primary** start date for years elapsed | +| `purchase_date` | Purchase date | Fallback start date if commencement is null | +| `depreciation_method` | `SLM` / `WDV` / `OTHER` | Which formula path to run | +| `depreciation_rate` | % per year | Optional for SLM/WDV (auto); required for OTHER | +| `as_of_date` | Calculate as of (preview only) | Defaults to today | + +### Date → years elapsed + +``` +depreciation_start_date = commencement_date || purchase_date +years_elapsed = (as_of_date − depreciation_start_date) / 365.25 days +capped_years = min(years_elapsed, useful_life_years) // if life is set +``` + +Accumulated depreciation uses `capped_years` so it never exceeds useful life. + +### Method 1 — SLM (Straight Line) + +Equal depreciation every year on **original cost**, never below salvage. + +**Auto rate** (when `depreciation_rate` omitted): + +``` +depreciable_amount = max(purchase_cost − salvage_value, 0) +depreciation_rate = (depreciable_amount / purchase_cost / useful_life_years) × 100 +``` + +**Amounts:** + +``` +annual_depreciation = purchase_cost × rate / 100 +accumulated_depreciation = min(annual_depreciation × capped_years, purchase_cost − salvage_value) +book_value = max(purchase_cost − accumulated_depreciation, salvage_value) +``` + +**Example:** cost = ₹1,00,000 · salvage = ₹10,000 · life = 10 years · start = 1 year ago + +- Rate = ((100000−10000)/100000/10)×100 = **9%** +- Annual = 100000 × 9% = **₹9,000** +- Accumulated (1 yr) = **₹9,000** +- Book value = **₹91,000** + +### Method 2 — WDV (Written Down Value) + +Depreciation each year on the **reducing book value**. Book value never goes below salvage. + +**Auto rate** (when `depreciation_rate` omitted; needs salvage > 0 and < cost): + +``` +depreciation_rate = (1 − (salvage_value / purchase_cost)^(1 / useful_life_years)) × 100 +``` + +**Amounts (year-by-year):** + +``` +book_value = purchase_cost +for each full year in capped_years: + year_dep = book_value × rate / 100 + book_value = max(book_value − year_dep, salvage_value) +if fractional year remains: + year_dep = (book_value × rate / 100) × fraction + book_value = max(book_value − year_dep, salvage_value) + +accumulated_depreciation = purchase_cost − book_value +annual_depreciation = book_value × rate / 100 // next year's dep on current WDV +``` + +**Example:** cost = ₹1,00,000 · salvage = ₹10,000 · life = 10 years · start = 1 year ago + +- Rate ≈ (1 − (10000/100000)^(1/10)) × 100 ≈ **20.57%** +- Year 1 dep ≈ 100000 × 20.57% ≈ **₹20,570** +- Book value ≈ **₹79,430** +- Accumulated ≈ **₹20,570** +- Next annual (on WDV) ≈ 79430 × 20.57% ≈ **₹16,340** + +### OTHER method + +Same accumulation style as SLM, but `depreciation_rate` is **mandatory** (no auto-calc). + +| Method | Rate auto-calc? | Depreciates on | Salvage role | +|---|---|---|---| +| **SLM** | Yes (if rate omitted) | Original `purchase_cost` every year | In rate formula + book-value floor | +| **WDV** | Yes (if rate omitted) | Reducing book value each year | In rate formula + book-value floor | +| **OTHER** | No — send `depreciation_rate` | Original cost × rate (like SLM) | Book-value floor only | **FE usage:** - **Live preview** → `POST /assets/depreciation/calculate` (no save) - **Saved asset view** → `GET /assets/:id` → `data.depreciation` object - **Method dropdown** → `GET /assets/depreciation-methods` +- Prefer sending `commencement_date`; backend falls back to `purchase_date` --- diff --git a/src/docs/assets-routes.yaml b/src/docs/assets-routes.yaml index 0a4ae31..8ed260d 100644 --- a/src/docs/assets-routes.yaml +++ b/src/docs/assets-routes.yaml @@ -509,6 +509,9 @@ paths: get: tags: [Assets] summary: List assets + description: > + Each item includes purchase_cost, current_value (book value after depreciation), + and a depreciation summary object (method, rate, annual, accumulated, book_value, years_elapsed). parameters: - { name: page, in: query, schema: { type: integer } } - { name: limit, in: query, schema: { type: integer } } diff --git a/src/modules/assets/assets.service.js b/src/modules/assets/assets.service.js index b610278..e97d60c 100644 --- a/src/modules/assets/assets.service.js +++ b/src/modules/assets/assets.service.js @@ -148,12 +148,24 @@ const sanitizeAsset = (asset) => { ? Number(rest.depreciation_rate) : null; + const depreciation = calculateDepreciation({ + depreciation_method: rest.depreciation_method, + depreciation_rate: depreciationRate, + purchase_cost: purchaseCost, + salvage_value: salvageValue, + useful_life_years: rest.useful_life_years, + commencement_date: rest.commencement_date, + purchase_date: rest.purchase_date, + }); + return { ...rest, maintenance_checklist_json: presentChecklistTemplate(rest.maintenance_checklist_json), purchase_cost: purchaseCost, salvage_value: salvageValue, depreciation_rate: depreciationRate, + // Current written-down / book value after depreciation (same as depreciation.book_value) + current_value: depreciation.book_value, item_category: item_categories || null, item_subcategory: item_subcategories || null, location: location || null, @@ -167,15 +179,10 @@ const sanitizeAsset = (asset) => { created_by_user: users_assets_created_byTousers || null, updated_by_user: users_assets_updated_byTousers || null, attachments: (asset_attachments || []).map(sanitizeAttachment), - depreciation: calculateDepreciation({ - depreciation_method: rest.depreciation_method, - depreciation_rate: depreciationRate, - purchase_cost: purchaseCost, - salvage_value: salvageValue, - useful_life_years: rest.useful_life_years, - commencement_date: rest.commencement_date, - purchase_date: rest.purchase_date, - }), + depreciation: { + ...depreciation, + current_value: depreciation.book_value, + }, item_categories: undefined, item_subcategories: undefined, departments: undefined, @@ -486,6 +493,11 @@ const exportAssets = async (query) => { { key: 'commencement_date', header: 'Commencement Date', type: 'date' }, { key: 'purchase_date', header: 'Purchase Date', type: 'date' }, { key: 'purchase_cost', header: 'Purchase Cost' }, + { key: 'current_value', header: 'Current Value' }, + { key: (row) => row.depreciation?.accumulated_depreciation ?? '', header: 'Accumulated Depreciation' }, + { key: (row) => row.depreciation?.annual_depreciation ?? '', header: 'Annual Depreciation' }, + { key: (row) => row.depreciation?.depreciation_method || '', header: 'Depreciation Method' }, + { key: (row) => row.depreciation?.depreciation_rate ?? '', header: 'Depreciation Rate %' }, { key: 'warranty_expiry_date', header: 'Warranty Expiry', type: 'date' }, { key: (row) => row.maintenance_incharge_user?.full_name || '',