Introduces a capability layer on top of existing roles that controls feature visibility and access. Capabilities follow an area.feature.action taxonomy (~35 capabilities) with sensible defaults per role. Tenant admins can customize via grant/revoke overrides stored in org settings JSONB. Key changes: - Add vice_president role to DB schema - Backend: capability constants, resolution logic, CapabilityGuard (global), @RequireCapability decorator on all 16 tenant controllers - Frontend: permission hooks (useCanEdit, useHasCapability), CapabilityGate component, sidebar filtering by capability, all 17 pages migrated from useIsReadOnly to capability-based checks - New admin UI: /settings/permissions matrix page for per-tenant role customization with grant/revoke delta model - GET /organizations/my-capabilities endpoint for capability refresh - Validation of permissionOverrides in settings updates Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
98 lines
3.4 KiB
TypeScript
98 lines
3.4 KiB
TypeScript
import {
|
|
Controller, Get, Post, Put, Body, Param, Query, UseGuards,
|
|
} from '@nestjs/common';
|
|
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
|
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
|
|
import { RequireCapability } from '../../common/decorators/capability.decorator';
|
|
import { AccountsService } from './accounts.service';
|
|
import { CreateAccountDto } from './dto/create-account.dto';
|
|
import { UpdateAccountDto } from './dto/update-account.dto';
|
|
|
|
@ApiTags('accounts')
|
|
@Controller('accounts')
|
|
@ApiBearerAuth()
|
|
@UseGuards(JwtAuthGuard)
|
|
export class AccountsController {
|
|
constructor(private accountsService: AccountsService) {}
|
|
|
|
@Get()
|
|
@ApiOperation({ summary: 'List all accounts' })
|
|
@RequireCapability('financials.accounts.view')
|
|
findAll(@Query('fundType') fundType?: string, @Query('includeArchived') includeArchived?: string) {
|
|
return this.accountsService.findAll(fundType, includeArchived === 'true');
|
|
}
|
|
|
|
@Get('trial-balance')
|
|
@ApiOperation({ summary: 'Get trial balance' })
|
|
@RequireCapability('financials.accounts.view')
|
|
getTrialBalance(@Query('asOfDate') asOfDate?: string) {
|
|
return this.accountsService.getTrialBalance(asOfDate);
|
|
}
|
|
|
|
@Put(':id/set-primary')
|
|
@ApiOperation({ summary: 'Set account as primary for its fund type' })
|
|
@RequireCapability('financials.accounts.edit')
|
|
setPrimary(@Param('id') id: string) {
|
|
return this.accountsService.setPrimary(id);
|
|
}
|
|
|
|
@Post('bulk-opening-balances')
|
|
@ApiOperation({ summary: 'Set opening balances for multiple accounts' })
|
|
@RequireCapability('financials.accounts.edit')
|
|
bulkSetOpeningBalances(
|
|
@Body() dto: { asOfDate: string; entries: { accountId: string; targetBalance: number }[] },
|
|
) {
|
|
return this.accountsService.bulkSetOpeningBalances(dto);
|
|
}
|
|
|
|
@Post(':id/opening-balance')
|
|
@ApiOperation({ summary: 'Set opening balance for an account at a specific date' })
|
|
@RequireCapability('financials.accounts.edit')
|
|
setOpeningBalance(
|
|
@Param('id') id: string,
|
|
@Body() dto: { targetBalance: number; asOfDate: string; memo?: string },
|
|
) {
|
|
return this.accountsService.setOpeningBalance(id, dto);
|
|
}
|
|
|
|
@Post(':id/adjust-balance')
|
|
@ApiOperation({ summary: 'Adjust account balance to a target amount' })
|
|
@RequireCapability('financials.accounts.edit')
|
|
adjustBalance(
|
|
@Param('id') id: string,
|
|
@Body() dto: { targetBalance: number; asOfDate: string; memo?: string },
|
|
) {
|
|
return this.accountsService.adjustBalance(id, dto);
|
|
}
|
|
|
|
@Post('transfer')
|
|
@ApiOperation({ summary: 'Transfer funds between asset accounts' })
|
|
@RequireCapability('financials.accounts.edit')
|
|
transferFunds(
|
|
@Body() dto: { fromAccountId: string; toAccountId: string; amount: number; transferDate: string; memo?: string },
|
|
) {
|
|
return this.accountsService.transferFunds(dto);
|
|
}
|
|
|
|
@Get(':id')
|
|
@ApiOperation({ summary: 'Get account by ID' })
|
|
@RequireCapability('financials.accounts.view')
|
|
findOne(@Param('id') id: string) {
|
|
return this.accountsService.findOne(id);
|
|
}
|
|
|
|
@Post()
|
|
@ApiOperation({ summary: 'Create a new account' })
|
|
@RequireCapability('financials.accounts.edit')
|
|
create(@Body() dto: CreateAccountDto) {
|
|
return this.accountsService.create(dto);
|
|
}
|
|
|
|
@Put(':id')
|
|
@ApiOperation({ summary: 'Update an account' })
|
|
@RequireCapability('financials.accounts.edit')
|
|
update(@Param('id') id: string, @Body() dto: UpdateAccountDto) {
|
|
return this.accountsService.update(id, dto);
|
|
}
|
|
}
|