179 lines
6.7 KiB
TypeScript
179 lines
6.7 KiB
TypeScript
import {
|
|
Body,
|
|
Controller,
|
|
Delete,
|
|
Get,
|
|
HttpCode,
|
|
HttpStatus,
|
|
Param,
|
|
Patch,
|
|
Post,
|
|
Query,
|
|
} from '@nestjs/common';
|
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
|
import { FinanceService, FinancialEntryResponse } from './finance.service';
|
|
import { RecurringTransactionService, RecurringTransactionResponse } from './recurring-transaction.service';
|
|
import { BudgetTargetService, BudgetTargetResponse } from './budget-target.service';
|
|
import { FinanceSummaryService } from './finance-summary.service';
|
|
import { BillableService } from './billable.service';
|
|
import { BillableEntry } from './entities/billable-entry.entity';
|
|
import { CreateFinancialEntryDto } from './dto/create-financial-entry.dto';
|
|
import { UpdateFinancialEntryDto } from './dto/update-financial-entry.dto';
|
|
import { QueryFinancialEntryDto, FinanceSummaryQueryDto } from './dto/query-financial-entry.dto';
|
|
import { CreateRecurringTransactionDto } from './dto/create-recurring-transaction.dto';
|
|
import { UpdateRecurringTransactionDto } from './dto/update-recurring-transaction.dto';
|
|
import { CreateBudgetTargetDto } from './dto/create-budget-target.dto';
|
|
import { UpdateBudgetTargetDto } from './dto/update-budget-target.dto';
|
|
import { CreateBillableDto } from './dto/create-billable.dto';
|
|
import { UpdateBillableDto } from './dto/update-billable.dto';
|
|
import { QueryBillableDto } from './dto/query-billable.dto';
|
|
import { PaginatedResponse } from '@common/pagination.dto';
|
|
import type { FinanceSummary } from '@life-platform/shared';
|
|
|
|
@ApiTags('Finance')
|
|
@Controller('finance')
|
|
export class FinanceController {
|
|
constructor(
|
|
private readonly financeService: FinanceService,
|
|
private readonly recurringService: RecurringTransactionService,
|
|
private readonly budgetTargetService: BudgetTargetService,
|
|
private readonly summaryService: FinanceSummaryService,
|
|
private readonly billableService: BillableService,
|
|
) {}
|
|
|
|
// ── Summary & Projections ──
|
|
|
|
@Get('summary')
|
|
@ApiOperation({ summary: 'Get unified finance summary for a month' })
|
|
getSummary(@Query() query: FinanceSummaryQueryDto): Promise<FinanceSummary> {
|
|
return this.summaryService.getSummary(query.month, query.domainId);
|
|
}
|
|
|
|
@Get('projection')
|
|
@ApiOperation({ summary: 'Get cash flow projection' })
|
|
getProjection(@Query('months') months?: string) {
|
|
return this.summaryService.getMonthlyTrend(parseInt(months ?? '3', 10));
|
|
}
|
|
|
|
@Get('trend')
|
|
@ApiOperation({ summary: 'Get monthly trend data' })
|
|
getTrend(@Query('months') months?: string) {
|
|
return this.summaryService.getMonthlyTrend(parseInt(months ?? '6', 10));
|
|
}
|
|
|
|
// ── Financial Entries ──
|
|
|
|
@Get('entries')
|
|
@ApiOperation({ summary: 'List financial entries (paginated)' })
|
|
findAllEntries(@Query() query: QueryFinancialEntryDto): Promise<PaginatedResponse<FinancialEntryResponse>> {
|
|
return this.financeService.findAll(query);
|
|
}
|
|
|
|
@Post('entries')
|
|
@ApiOperation({ summary: 'Create financial entry' })
|
|
createEntry(@Body() dto: CreateFinancialEntryDto): Promise<FinancialEntryResponse> {
|
|
return this.financeService.create(dto);
|
|
}
|
|
|
|
@Patch('entries/:id')
|
|
@ApiOperation({ summary: 'Update financial entry' })
|
|
updateEntry(@Param('id') id: string, @Body() dto: UpdateFinancialEntryDto): Promise<FinancialEntryResponse> {
|
|
return this.financeService.update(id, dto);
|
|
}
|
|
|
|
@Delete('entries/:id')
|
|
@HttpCode(HttpStatus.NO_CONTENT)
|
|
@ApiOperation({ summary: 'Delete financial entry' })
|
|
removeEntry(@Param('id') id: string): Promise<void> {
|
|
return this.financeService.remove(id);
|
|
}
|
|
|
|
// ── Recurring Transactions ──
|
|
|
|
@Get('recurring')
|
|
@ApiOperation({ summary: 'List recurring transactions' })
|
|
findAllRecurring(@Query('type') type?: string): Promise<RecurringTransactionResponse[]> {
|
|
return this.recurringService.findAll(type);
|
|
}
|
|
|
|
@Post('recurring')
|
|
@ApiOperation({ summary: 'Create recurring transaction' })
|
|
createRecurring(@Body() dto: CreateRecurringTransactionDto): Promise<RecurringTransactionResponse> {
|
|
return this.recurringService.create(dto);
|
|
}
|
|
|
|
@Patch('recurring/:id')
|
|
@ApiOperation({ summary: 'Update recurring transaction' })
|
|
updateRecurring(@Param('id') id: string, @Body() dto: UpdateRecurringTransactionDto): Promise<RecurringTransactionResponse> {
|
|
return this.recurringService.update(id, dto);
|
|
}
|
|
|
|
@Delete('recurring/:id')
|
|
@HttpCode(HttpStatus.NO_CONTENT)
|
|
@ApiOperation({ summary: 'Delete recurring transaction' })
|
|
removeRecurring(@Param('id') id: string): Promise<void> {
|
|
return this.recurringService.remove(id);
|
|
}
|
|
|
|
@Post('recurring/:id/mark-paid')
|
|
@ApiOperation({ summary: 'Create entry from recurring for given month' })
|
|
markPaid(@Param('id') id: string, @Body('month') month: string): Promise<void> {
|
|
return this.recurringService.markPaid(id, month);
|
|
}
|
|
|
|
// ── Budget Targets ──
|
|
|
|
@Get('targets')
|
|
@ApiOperation({ summary: 'List budget targets' })
|
|
findAllTargets(@Query('month') month?: string): Promise<BudgetTargetResponse[]> {
|
|
return month
|
|
? this.budgetTargetService.getTargetsForMonth(month)
|
|
: this.budgetTargetService.findAll();
|
|
}
|
|
|
|
@Post('targets')
|
|
@ApiOperation({ summary: 'Create budget target' })
|
|
createTarget(@Body() dto: CreateBudgetTargetDto): Promise<BudgetTargetResponse> {
|
|
return this.budgetTargetService.create(dto);
|
|
}
|
|
|
|
@Patch('targets/:id')
|
|
@ApiOperation({ summary: 'Update budget target' })
|
|
updateTarget(@Param('id') id: string, @Body() dto: UpdateBudgetTargetDto): Promise<BudgetTargetResponse> {
|
|
return this.budgetTargetService.update(id, dto);
|
|
}
|
|
|
|
@Delete('targets/:id')
|
|
@HttpCode(HttpStatus.NO_CONTENT)
|
|
@ApiOperation({ summary: 'Delete budget target' })
|
|
removeTarget(@Param('id') id: string): Promise<void> {
|
|
return this.budgetTargetService.remove(id);
|
|
}
|
|
|
|
// ── Billable Entries (moved from income) ──
|
|
|
|
@Get('billable')
|
|
@ApiOperation({ summary: 'List billable entries' })
|
|
findAllBillable(@Query() query: QueryBillableDto): Promise<PaginatedResponse<BillableEntry>> {
|
|
return this.billableService.findAll(query as QueryBillableDto & Record<string, unknown>);
|
|
}
|
|
|
|
@Post('billable')
|
|
@ApiOperation({ summary: 'Create billable entry' })
|
|
createBillable(@Body() dto: CreateBillableDto): Promise<BillableEntry> {
|
|
return this.billableService.createBillable(dto);
|
|
}
|
|
|
|
@Patch('billable/:id')
|
|
@ApiOperation({ summary: 'Update billable entry' })
|
|
updateBillable(@Param('id') id: string, @Body() dto: UpdateBillableDto): Promise<BillableEntry> {
|
|
return this.billableService.updateBillable(id, dto);
|
|
}
|
|
|
|
@Delete('billable/:id')
|
|
@HttpCode(HttpStatus.NO_CONTENT)
|
|
@ApiOperation({ summary: 'Delete billable entry' })
|
|
deleteBillable(@Param('id') id: string): Promise<void> {
|
|
return this.billableService.remove(id);
|
|
}
|
|
}
|