1
0
Files
bigcapital/packages/server/src/modules/Assets/repositories/AssetDepreciationEntry.repository.ts
T
Ahmed Bouhuolia b6a2c97f9f feat(assets): implement asset management with depreciation
Add comprehensive asset management system with depreciation tracking similar to Xero.

Features:
- Create and manage fixed assets with purchase details
- Calculate depreciation using straight-line and declining balance methods
- Track asset book value and accumulated depreciation
- Dispose/sell assets with gain/loss calculations
- Automatic depreciation schedule generation
- Integration with chart of accounts for depreciation entries

Database:
- Add assets table with purchase and depreciation fields
- Add asset_depreciation_entries table for schedule tracking
- Add accumulated depreciation account to seed data

Server-side:
- Assets module with CRUD operations
- Depreciation calculation service
- Asset disposal service with gain/loss tracking
- REST API endpoints with permission guards

Frontend:
- Assets list page with data table
- Asset form with purchase and depreciation sections
- React Query hooks for API integration
- Sidebar navigation under Accounting

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 20:09:14 +02:00

90 lines
2.5 KiB
TypeScript

import { Injectable, Scope } from '@nestjs/common';
import { Knex } from 'knex';
import { Inject } from '@nestjs/common';
import { TenantRepository } from '@/modules/Tenancy/TenancyDB/TenantRepository';
import { TENANCY_DB_CONNECTION } from '@/modules/Tenancy/TenancyDB/TenancyDB.constants';
import { AssetDepreciationEntry } from '../models/AssetDepreciationEntry.model';
@Injectable({ scope: Scope.REQUEST })
export class AssetDepreciationEntryRepository extends TenantRepository {
constructor(
@Inject(TENANCY_DB_CONNECTION)
private readonly tenantDBKnex: () => Knex,
) {
super();
}
get model(): typeof AssetDepreciationEntry {
return AssetDepreciationEntry.bindKnex(this.tenantDBKnex());
}
/**
* Find entries by asset ID.
*/
async findByAssetId(assetId: number): Promise<AssetDepreciationEntry[]> {
return this.model
.query()
.where('assetId', assetId)
.orderBy(['periodYear', 'periodMonth']);
}
/**
* Find unposted entries by period.
*/
async findUnpostedByPeriod(year: number, month: number): Promise<AssetDepreciationEntry[]> {
return this.model
.query()
.where('periodYear', year)
.where('periodMonth', month)
.where('isPosted', false);
}
/**
* Find entries by asset and period.
*/
async findByPeriod(assetId: number, year: number, month: number): Promise<AssetDepreciationEntry[]> {
return this.model
.query()
.where('assetId', assetId)
.where('periodYear', year)
.where('periodMonth', month);
}
/**
* Delete unposted entries for an asset.
*/
async deleteUnpostedEntries(assetId: number): Promise<void> {
await this.model
.query()
.where('assetId', assetId)
.where('isPosted', false)
.delete();
}
/**
* Create a depreciation entry.
*/
async create(data: Partial<AssetDepreciationEntry>): Promise<AssetDepreciationEntry> {
return this.model.query().insert(data);
}
/**
* Update a depreciation entry.
*/
async update(id: number, data: Partial<AssetDepreciationEntry>): Promise<AssetDepreciationEntry> {
return this.model.query().patchAndFetchById(id, data);
}
/**
* Get the last posted entry for an asset.
*/
async getLastPostedEntry(assetId: number): Promise<AssetDepreciationEntry | undefined> {
return this.model
.query()
.where('assetId', assetId)
.where('isPosted', true)
.orderBy(['periodYear', 'periodMonth'], 'desc')
.first();
}
}