mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 02:30:55 +00:00
235 lines
9.2 KiB
TypeScript
235 lines
9.2 KiB
TypeScript
import { Body, Controller, Get, Post, Put, Delete, Param, UseGuards, Request, Query } from '@nestjs/common';
|
|
import { ApiTags, ApiBearerAuth, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/swagger';
|
|
import { ConfigurableFareService } from './configurable-fare.service';
|
|
import {
|
|
CreateFareConfigurationDto,
|
|
UpdateFareConfigurationDto,
|
|
FareTestScenarioDto,
|
|
FareCalculationResultDto,
|
|
MigrateLegacyDto,
|
|
CreateNewFormulaDto,
|
|
ToggleFeatureDto
|
|
} from './configurable-fare.dto';
|
|
import { IamGuard } from '../../common/iam-adapter';
|
|
import { Roles } from '../../common/roles.decorator';
|
|
|
|
@ApiTags('Configurable Fares')
|
|
@Controller('admin/fare-configurations')
|
|
@ApiBearerAuth('IAM-auth')
|
|
@UseGuards(IamGuard)
|
|
@Roles('ADMIN')
|
|
export class ConfigurableFareController {
|
|
constructor(private service: ConfigurableFareService) {}
|
|
|
|
@Get()
|
|
@ApiOperation({ summary: 'List all fare configurations' })
|
|
@ApiResponse({ status: 200, description: 'List of all configurations with summary counts' })
|
|
async getAllConfigurations() {
|
|
return this.service.getAllConfigurations();
|
|
}
|
|
|
|
@Post()
|
|
@ApiOperation({ summary: 'Create new fare configuration' })
|
|
@ApiResponse({ status: 201, description: 'Configuration created successfully' })
|
|
@ApiResponse({ status: 400, description: 'Invalid configuration data' })
|
|
async createConfiguration(
|
|
@Body() dto: CreateFareConfigurationDto,
|
|
@Request() req: any
|
|
) {
|
|
const createdBy = req.user?.id || req.user?.sub;
|
|
return this.service.createConfiguration(dto, createdBy);
|
|
}
|
|
|
|
@Get(':id')
|
|
@ApiOperation({ summary: 'Get configuration details' })
|
|
@ApiParam({ name: 'id', description: 'Configuration ID' })
|
|
@ApiResponse({ status: 200, description: 'Configuration details with all rules' })
|
|
@ApiResponse({ status: 404, description: 'Configuration not found' })
|
|
async getConfigurationById(@Param('id') id: string) {
|
|
return this.service.getConfigurationById(id);
|
|
}
|
|
|
|
@Put(':id')
|
|
@ApiOperation({ summary: 'Update configuration' })
|
|
@ApiParam({ name: 'id', description: 'Configuration ID' })
|
|
@ApiResponse({ status: 200, description: 'Configuration updated successfully' })
|
|
@ApiResponse({ status: 404, description: 'Configuration not found' })
|
|
async updateConfiguration(
|
|
@Param('id') id: string,
|
|
@Body() dto: UpdateFareConfigurationDto,
|
|
@Request() req: any
|
|
) {
|
|
const updatedBy = req.user?.id || req.user?.sub;
|
|
return this.service.updateConfiguration(id, dto, updatedBy);
|
|
}
|
|
|
|
@Post(':id/activate')
|
|
@ApiOperation({ summary: 'Activate configuration' })
|
|
@ApiParam({ name: 'id', description: 'Configuration ID' })
|
|
@ApiResponse({ status: 200, description: 'Configuration activated successfully' })
|
|
@ApiResponse({ status: 404, description: 'Configuration not found' })
|
|
async activateConfiguration(@Param('id') id: string, @Request() req: any) {
|
|
const activatedBy = req.user?.id || req.user?.sub;
|
|
return this.service.activateConfiguration(id, activatedBy);
|
|
}
|
|
|
|
@Delete(':id')
|
|
@ApiOperation({ summary: 'Delete configuration' })
|
|
@ApiParam({ name: 'id', description: 'Configuration ID' })
|
|
@ApiResponse({ status: 200, description: 'Configuration deleted successfully' })
|
|
@ApiResponse({ status: 404, description: 'Configuration not found' })
|
|
@ApiResponse({ status: 409, description: 'Cannot delete active configuration' })
|
|
async deleteConfiguration(@Param('id') id: string, @Request() req: any) {
|
|
const deletedBy = req.user?.id || req.user?.sub;
|
|
return this.service.deleteConfiguration(id, deletedBy);
|
|
}
|
|
|
|
@Post(':id/test')
|
|
@ApiOperation({ summary: 'Test fare calculation with configuration' })
|
|
@ApiParam({ name: 'id', description: 'Configuration ID' })
|
|
@ApiResponse({ status: 200, type: FareCalculationResultDto, description: 'Fare calculation result' })
|
|
@ApiResponse({ status: 400, description: 'Invalid test scenario or missing rate rules' })
|
|
async testConfiguration(
|
|
@Param('id') id: string,
|
|
@Body() scenario: FareTestScenarioDto
|
|
): Promise<FareCalculationResultDto> {
|
|
return this.service.testConfiguration(id, scenario);
|
|
}
|
|
|
|
@Get(':id/audit')
|
|
@ApiOperation({ summary: 'Get configuration audit trail' })
|
|
@ApiParam({ name: 'id', description: 'Configuration ID' })
|
|
@ApiResponse({ status: 200, description: 'Audit trail entries' })
|
|
async getAuditTrail(@Param('id') id: string) {
|
|
return this.service.getAuditTrail(id);
|
|
}
|
|
}
|
|
|
|
@ApiTags('Configurable Fares')
|
|
@Controller('admin/fare-migration')
|
|
@ApiBearerAuth('IAM-auth')
|
|
@UseGuards(IamGuard)
|
|
@Roles('ADMIN')
|
|
export class FareMigrationController {
|
|
constructor(private service: ConfigurableFareService) {}
|
|
|
|
@Post('migrate-legacy')
|
|
@ApiOperation({ summary: 'Migrate existing fare rules to configurable system' })
|
|
@ApiResponse({ status: 200, description: 'Migration completed successfully' })
|
|
@ApiResponse({ status: 400, description: 'Migration failed' })
|
|
async migrateLegacySystem(@Body() dto: MigrateLegacyDto) {
|
|
return this.service.migrateLegacySystem(dto);
|
|
}
|
|
|
|
@Post('create-new-formula')
|
|
@ApiOperation({ summary: 'Create new formula configuration with defaults' })
|
|
@ApiResponse({ status: 201, description: 'New formula configuration created' })
|
|
async createNewFormulaConfiguration(@Body() dto: CreateNewFormulaDto) {
|
|
return this.service.createNewFormulaConfiguration(dto);
|
|
}
|
|
|
|
@Post('complete-setup')
|
|
@ApiOperation({
|
|
summary: 'Complete system setup (migrate + create + activate)',
|
|
description: 'Performs full system migration and setup in one operation'
|
|
})
|
|
@ApiResponse({ status: 200, description: 'System setup completed successfully' })
|
|
async completeSetup(@Body() body: { activateNewFormula?: boolean; enableFeature?: boolean }) {
|
|
// Step 1: Migrate legacy system
|
|
const migrationResult = await this.service.migrateLegacySystem({ dryRun: false });
|
|
|
|
// Step 2: Create new formula configuration
|
|
const newConfig = await this.service.createNewFormulaConfiguration({
|
|
name: 'Default System Configuration',
|
|
description: 'System-generated configuration with optimal defaults',
|
|
activateImmediately: body.activateNewFormula !== false
|
|
});
|
|
|
|
// Step 3: Enable feature flag if requested
|
|
if (body.enableFeature) {
|
|
await this.service.toggleFeature({
|
|
featureName: 'USE_CONFIGURABLE_FARES',
|
|
enabled: true,
|
|
config: { rollout_percentage: 100 }
|
|
});
|
|
}
|
|
|
|
return {
|
|
migration: migrationResult,
|
|
newConfiguration: newConfig,
|
|
featureEnabled: body.enableFeature || false,
|
|
message: 'System setup completed successfully'
|
|
};
|
|
}
|
|
|
|
@Get('status')
|
|
@ApiOperation({ summary: 'Get migration and setup status' })
|
|
@ApiResponse({ status: 200, description: 'Current system status' })
|
|
async getStatus() {
|
|
const featureStatus = await this.service.getFeatureStatus('USE_CONFIGURABLE_FARES');
|
|
const configurations = await this.service.getAllConfigurations();
|
|
|
|
const activeConfig = (configurations as any[]).find(config => config.is_active);
|
|
|
|
return {
|
|
configurableFaresEnabled: featureStatus.enabled,
|
|
rolloutPercentage: featureStatus.config?.rollout_percentage || 0,
|
|
totalConfigurations: (configurations as any[]).length,
|
|
activeConfiguration: activeConfig?.id || null,
|
|
activeConfigurationName: activeConfig?.name || null,
|
|
systemReady: featureStatus.enabled && !!activeConfig
|
|
};
|
|
}
|
|
}
|
|
|
|
@ApiTags('Configurable Fares')
|
|
@Controller('admin/fare-configurations/system')
|
|
@ApiBearerAuth('IAM-auth')
|
|
@UseGuards(IamGuard)
|
|
@Roles('ADMIN')
|
|
export class FareSystemController {
|
|
constructor(private service: ConfigurableFareService) {}
|
|
|
|
@Get('feature-status')
|
|
@ApiOperation({ summary: 'Check configurable fares feature status' })
|
|
@ApiQuery({ name: 'feature', required: false, description: 'Feature name (defaults to USE_CONFIGURABLE_FARES)' })
|
|
@ApiResponse({ status: 200, description: 'Feature status retrieved' })
|
|
async getFeatureStatus(@Query('feature') featureName = 'USE_CONFIGURABLE_FARES') {
|
|
return this.service.getFeatureStatus(featureName);
|
|
}
|
|
|
|
@Post('toggle-feature')
|
|
@ApiOperation({ summary: 'Enable or disable configurable fares system' })
|
|
@ApiResponse({ status: 200, description: 'Feature toggled successfully' })
|
|
async toggleFeature(@Body() dto: ToggleFeatureDto) {
|
|
return this.service.toggleFeature(dto);
|
|
}
|
|
|
|
@Post('enable-configurable-fares')
|
|
@ApiOperation({
|
|
summary: 'Enable configurable fares with rollout percentage',
|
|
description: 'Quick endpoint to enable the configurable fares feature'
|
|
})
|
|
@ApiResponse({ status: 200, description: 'Configurable fares enabled successfully' })
|
|
async enableConfigurableFares(@Body() body: { rolloutPercentage?: number }) {
|
|
return this.service.toggleFeature({
|
|
featureName: 'USE_CONFIGURABLE_FARES',
|
|
enabled: true,
|
|
config: { rollout_percentage: body.rolloutPercentage || 100 }
|
|
});
|
|
}
|
|
|
|
@Post('disable-configurable-fares')
|
|
@ApiOperation({
|
|
summary: 'Disable configurable fares (fallback to legacy system)',
|
|
description: 'Disables the configurable fares feature and falls back to legacy fare calculation'
|
|
})
|
|
@ApiResponse({ status: 200, description: 'Configurable fares disabled successfully' })
|
|
async disableConfigurableFares() {
|
|
return this.service.toggleFeature({
|
|
featureName: 'USE_CONFIGURABLE_FARES',
|
|
enabled: false,
|
|
config: { rollout_percentage: 0 }
|
|
});
|
|
}
|
|
} |