mirror of
https://github.com/HamzaSha1/zod-backend.git
synced 2026-03-10 17:11:44 +00:00
feat(allowance): add delete API and configurable test intervals
- Add DELETE /guardians/me/allowances/:scheduleId endpoint - Add ALLOWANCE_TEST_MODE env variable for testing intervals: - true: DAILY=5min, WEEKLY=10min, MONTHLY=15min - false: DAILY=1day, WEEKLY=1week, MONTHLY=1month - Add deleteById to repository and deleteSchedule to service
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import { Body, Controller, Get, Param, Patch, Post, UseGuards } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Patch, Post, UseGuards } from '@nestjs/common';
|
||||
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||
import { Roles } from '~/auth/enums';
|
||||
import { IJwtPayload } from '~/auth/interfaces';
|
||||
@ -65,4 +65,14 @@ export class AllowanceController {
|
||||
const schedule = await this.allowanceService.updateSchedule(sub, scheduleId, body);
|
||||
return ResponseFactory.data(new AllowanceScheduleResponseDto(schedule));
|
||||
}
|
||||
|
||||
@Delete(':scheduleId')
|
||||
@HttpCode(HttpStatus.NO_CONTENT)
|
||||
@ApiOperation({ summary: 'Delete an allowance schedule' })
|
||||
async deleteSchedule(
|
||||
@AuthenticatedUser() { sub }: IJwtPayload,
|
||||
@Param('scheduleId') scheduleId: string,
|
||||
) {
|
||||
await this.allowanceService.deleteSchedule(sub, scheduleId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
export * from './create-allowance-schedule.request.dto';
|
||||
export * from './update-allowance-schedule.request.dto';
|
||||
export * from './update-allowance-schedule.request.dto';
|
||||
@ -89,4 +89,8 @@ export class AllowanceScheduleRepository {
|
||||
async updateSchedule(schedule: AllowanceSchedule): Promise<AllowanceSchedule> {
|
||||
return this.allowanceScheduleRepository.save(schedule);
|
||||
}
|
||||
|
||||
async deleteById(id: string): Promise<void> {
|
||||
await this.allowanceScheduleRepository.delete({ id });
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ export class AllowanceWorkerService implements OnModuleInit, OnModuleDestroy {
|
||||
private readonly queueName: string;
|
||||
private readonly rabbitUrl?: string;
|
||||
private readonly maxRetries: number;
|
||||
private readonly isTestMode: boolean;
|
||||
|
||||
constructor(
|
||||
private readonly configService: ConfigService,
|
||||
@ -31,6 +32,10 @@ export class AllowanceWorkerService implements OnModuleInit, OnModuleDestroy {
|
||||
this.queueName = this.configService.get<string>('ALLOWANCE_QUEUE_NAME') || ALLOWANCE_QUEUE_NAME;
|
||||
this.rabbitUrl = this.configService.get<string>('RABBITMQ_URL');
|
||||
this.maxRetries = Number(this.configService.get<string>('ALLOWANCE_MAX_RETRIES') || 5);
|
||||
this.isTestMode = this.configService.get<string>('ALLOWANCE_TEST_MODE') === 'true';
|
||||
if (this.isTestMode) {
|
||||
this.logger.warn('ALLOWANCE_TEST_MODE is enabled - using short intervals (5/10/15 min)');
|
||||
}
|
||||
}
|
||||
|
||||
async onModuleInit() {
|
||||
@ -142,6 +147,22 @@ export class AllowanceWorkerService implements OnModuleInit, OnModuleDestroy {
|
||||
|
||||
private computeNextRunAt(frequency: AllowanceFrequency): Date {
|
||||
const base = moment();
|
||||
|
||||
if (this.isTestMode) {
|
||||
// Test mode: DAILY=5min, WEEKLY=10min, MONTHLY=15min
|
||||
switch (frequency) {
|
||||
case AllowanceFrequency.DAILY:
|
||||
return base.add(5, 'minutes').toDate();
|
||||
case AllowanceFrequency.WEEKLY:
|
||||
return base.add(10, 'minutes').toDate();
|
||||
case AllowanceFrequency.MONTHLY:
|
||||
return base.add(15, 'minutes').toDate();
|
||||
default:
|
||||
return base.toDate();
|
||||
}
|
||||
}
|
||||
|
||||
// Production mode: real intervals
|
||||
switch (frequency) {
|
||||
case AllowanceFrequency.DAILY:
|
||||
return base.add(1, 'day').toDate();
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { BadRequestException, Injectable, Logger, NotFoundException } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import moment from 'moment';
|
||||
import { Junior } from '~/junior/entities';
|
||||
import { JuniorService } from '~/junior/services';
|
||||
@ -11,11 +12,18 @@ import { AllowanceScheduleRepository } from '../repositories';
|
||||
@Injectable()
|
||||
export class AllowanceService {
|
||||
private readonly logger = new Logger(AllowanceService.name);
|
||||
private readonly isTestMode: boolean;
|
||||
|
||||
constructor(
|
||||
private readonly allowanceScheduleRepository: AllowanceScheduleRepository,
|
||||
private readonly juniorService: JuniorService,
|
||||
) {}
|
||||
private readonly configService: ConfigService,
|
||||
) {
|
||||
this.isTestMode = this.configService.get<string>('ALLOWANCE_TEST_MODE') === 'true';
|
||||
if (this.isTestMode) {
|
||||
this.logger.warn('ALLOWANCE_TEST_MODE is enabled - using short intervals (5/10/15 min)');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all allowance schedules for a guardian, grouped by juniors with and without schedules.
|
||||
@ -104,6 +112,21 @@ export class AllowanceService {
|
||||
return base.toDate();
|
||||
}
|
||||
|
||||
if (this.isTestMode) {
|
||||
// Test mode: DAILY=5min, WEEKLY=10min, MONTHLY=15min
|
||||
switch (frequency) {
|
||||
case AllowanceFrequency.DAILY:
|
||||
return base.add(5, 'minutes').toDate();
|
||||
case AllowanceFrequency.WEEKLY:
|
||||
return base.add(10, 'minutes').toDate();
|
||||
case AllowanceFrequency.MONTHLY:
|
||||
return base.add(15, 'minutes').toDate();
|
||||
default:
|
||||
return base.toDate();
|
||||
}
|
||||
}
|
||||
|
||||
// Production mode: real intervals
|
||||
switch (frequency) {
|
||||
case AllowanceFrequency.DAILY:
|
||||
return base.add(1, 'day').toDate();
|
||||
@ -172,4 +195,19 @@ export class AllowanceService {
|
||||
|
||||
return { nextPaymentAt, monthlyTotal };
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an allowance schedule.
|
||||
*/
|
||||
async deleteSchedule(guardianId: string, scheduleId: string): Promise<void> {
|
||||
const schedule = await this.allowanceScheduleRepository.findByIdAndGuardian(scheduleId, guardianId);
|
||||
|
||||
if (!schedule) {
|
||||
this.logger.error(`Schedule ${scheduleId} not found for guardian ${guardianId}`);
|
||||
throw new NotFoundException('ALLOWANCE.NOT_FOUND');
|
||||
}
|
||||
|
||||
this.logger.log(`Deleting schedule ${scheduleId} for guardian ${guardianId}`);
|
||||
await this.allowanceScheduleRepository.deleteById(scheduleId);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user