fix pagination et filter
This commit is contained in:
parent
0af15e26fc
commit
e4c4383ceb
31
src/common/dto/pagination.dto.ts
Normal file
31
src/common/dto/pagination.dto.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import { IsInt, IsOptional, Min, Max } from 'class-validator';
|
||||
|
||||
export class PaginationDto {
|
||||
@ApiProperty({
|
||||
description: 'Page number',
|
||||
minimum: 1,
|
||||
default: 1,
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
page?: number = 1;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Number of items per page',
|
||||
minimum: 1,
|
||||
maximum: 100,
|
||||
default: 10,
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
@Max(100)
|
||||
limit?: number = 10;
|
||||
}
|
||||
11
src/common/interfaces/paginated-response.interface.ts
Normal file
11
src/common/interfaces/paginated-response.interface.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export interface PaginatedResponse<T> {
|
||||
data: T[];
|
||||
meta: {
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
totalPages: number;
|
||||
hasNextPage: boolean;
|
||||
hasPreviousPage: boolean;
|
||||
};
|
||||
}
|
||||
@ -7,9 +7,12 @@ import {
|
||||
IsEnum,
|
||||
IsDateString,
|
||||
isNumber,
|
||||
IsInt,
|
||||
} from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import { PaymentType, TransactionStatus } from 'generated/prisma';
|
||||
import { PaginationDto } from 'src/common/dto/pagination.dto';
|
||||
|
||||
export class ChargeDto {
|
||||
@ApiProperty({ description: 'User token from authentication' })
|
||||
@ -77,46 +80,6 @@ export class RefundDto {
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
export class PaymentQueryDto {
|
||||
@ApiProperty({ required: false, enum: ['PENDING', 'SUCCESS', 'FAILED', 'REFUNDED'] })
|
||||
@IsOptional()
|
||||
@IsEnum(['PENDING', 'SUCCESS', 'FAILED', 'REFUNDED'])
|
||||
status?: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
userId?: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
subscriptionId?: number;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
startDate?: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
endDate?: string;
|
||||
|
||||
@ApiProperty({ required: false, default: 1 })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsNumber()
|
||||
@Min(1)
|
||||
page?: number = 1;
|
||||
|
||||
@ApiProperty({ required: false, default: 20 })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsNumber()
|
||||
@Min(1)
|
||||
limit?: number = 20;
|
||||
}
|
||||
|
||||
export class PaymentResponseDto {
|
||||
@ApiProperty()
|
||||
@ -168,3 +131,156 @@ export class PaymentListResponseDto {
|
||||
totalPages: number;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export class PaymentQueryDto extends PaginationDto {
|
||||
@ApiProperty({
|
||||
description: 'Filter by payment type',
|
||||
enum: PaymentType,
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsEnum(PaymentType)
|
||||
type?: PaymentType;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter by transaction status',
|
||||
enum: TransactionStatus,
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsEnum(TransactionStatus)
|
||||
status?: TransactionStatus;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter by merchant partner ID',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
merchantPartnerId?: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter by customer ID',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
customerId?: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter by subscription ID',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
subscriptionId?: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Search by external reference',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
externalReference?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Search by payment reference',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
reference?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter by currency code (e.g., XOF, XAF, EUR)',
|
||||
example: 'XOF',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
currency?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter payments with amount greater than or equal to this value',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
amountMin?: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter payments with amount less than or equal to this value',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
amountMax?: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter payments created from this date (ISO format)',
|
||||
example: '2024-01-01T00:00:00Z',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
createdFrom?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter payments created until this date (ISO format)',
|
||||
example: '2024-12-31T23:59:59Z',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
createdTo?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter payments completed from this date (ISO format)',
|
||||
example: '2024-01-01T00:00:00Z',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
completedFrom?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter payments completed until this date (ISO format)',
|
||||
example: '2024-12-31T23:59:59Z',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
completedTo?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter only failed payments (with failure reason)',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@Type(() => Boolean)
|
||||
hasFailureReason?: boolean;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Sort field',
|
||||
enum: ['createdAt', 'completedAt', 'amount'],
|
||||
default: 'createdAt',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
sortBy?: 'createdAt' | 'completedAt' | 'amount' = 'createdAt';
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Sort order',
|
||||
enum: ['asc', 'desc'],
|
||||
default: 'desc',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsEnum(['asc', 'desc'])
|
||||
sortOrder?: 'asc' | 'desc' = 'desc';
|
||||
}
|
||||
@ -125,23 +125,32 @@ export class PaymentsController {
|
||||
|
||||
|
||||
@Get('/')
|
||||
@ApiOperation({
|
||||
summary: 'Get payment list with pagination and filters',
|
||||
description: 'Retrieve payments with optional filters on status, type, dates, amounts, etc.'
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Paginated list of payments',
|
||||
})
|
||||
@ApiOperation({ summary: 'Get payments list' })
|
||||
async getAll(@Request() req) {
|
||||
return this.paymentsService.findAll();
|
||||
async getAll(@Request() req, @Query() paymentQueryDto: PaymentQueryDto) {
|
||||
return this.paymentsService.findAll(paymentQueryDto);
|
||||
}
|
||||
|
||||
@Get('merchant/:merchantId')
|
||||
@ApiOperation({ summary: 'Get payments list by merchant' })
|
||||
async getAllByPaymentByMerchant(@Request() req, @Param('merchantId', ParseIntPipe) merchantId: number) {
|
||||
return this.paymentsService.findAllByMerchant(merchantId);
|
||||
async getAllByPaymentByMerchant(@Request() req, @Param('merchantId', ParseIntPipe) merchantId: number, @Query() queryDto: Omit<PaymentQueryDto, 'merchantPartnerId'>,) {
|
||||
return this.paymentsService.findAll({ ...queryDto, merchantPartnerId: merchantId });
|
||||
}
|
||||
|
||||
@Get('merchant/:merchantId/subscription/:subscriptionId')
|
||||
@ApiOperation({ summary: 'Get payments list by merchant' })
|
||||
async getAllBySubscription(@Request() req,
|
||||
@Param('merchantId', ParseIntPipe) merchantId: number,
|
||||
@Param('subscriptionId', ParseIntPipe) subscriptionId: number) {
|
||||
return this.paymentsService.findAllByMerchantSubscription(merchantId,subscriptionId);
|
||||
@Param('subscriptionId', ParseIntPipe) subscriptionId: number,
|
||||
@Query() queryDto: Omit<PaymentQueryDto, 'merchantPartnerId' | 'subscriptionId'>,) {
|
||||
return this.paymentsService.findAll({ ...queryDto, merchantPartnerId: merchantId, subscriptionId: subscriptionId });
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -2,9 +2,10 @@ import { Injectable, BadRequestException, Logger } from '@nestjs/common';
|
||||
import { OperatorsService } from '../operators/operators.service';
|
||||
import { PrismaService } from '../../shared/services/prisma.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { ChargeDto } from './dto/payment.dto';
|
||||
import { ChargeDto, PaymentQueryDto } from './dto/payment.dto';
|
||||
import { RefundDto } from './dto/payment.dto';
|
||||
import { PaymentType, TransactionStatus } from 'generated/prisma';
|
||||
import { Payment, PaymentType, Prisma, TransactionStatus } from 'generated/prisma';
|
||||
import { PaginatedResponse } from 'src/common/interfaces/paginated-response.interface';
|
||||
|
||||
@Injectable()
|
||||
export class PaymentsService {
|
||||
@ -64,17 +65,149 @@ export class PaymentsService {
|
||||
});
|
||||
}
|
||||
|
||||
async findAll(): Promise<any[]> {
|
||||
// Check if merchant exists
|
||||
return this.prisma.payment.findMany({
|
||||
// where: { merchantPartnerId: merchantId },
|
||||
async findAll(
|
||||
queryDto: PaymentQueryDto,
|
||||
): Promise<PaginatedResponse<Payment>> {
|
||||
const {
|
||||
page = 1,
|
||||
limit = 10,
|
||||
sortBy = 'createdAt',
|
||||
sortOrder = 'desc',
|
||||
} = queryDto;
|
||||
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
});
|
||||
const skip = (page - 1) * limit;
|
||||
const where = this.buildWhereClause(queryDto);
|
||||
|
||||
// Construction du orderBy dynamique
|
||||
const orderBy: Prisma.PaymentOrderByWithRelationInput = {
|
||||
[sortBy]: sortOrder,
|
||||
};
|
||||
|
||||
// Exécuter les requêtes en parallèle
|
||||
const [payments, total] = await Promise.all([
|
||||
this.prisma.payment.findMany({
|
||||
where,
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy,
|
||||
// Optionnel: inclure les relations
|
||||
// include: {
|
||||
// merchantPartner: true,
|
||||
// subscription: true,
|
||||
// reversementRequests: true,
|
||||
// },
|
||||
}),
|
||||
this.prisma.payment.count({ where }),
|
||||
]);
|
||||
|
||||
const totalPages = Math.ceil(total / limit);
|
||||
|
||||
return {
|
||||
data: payments,
|
||||
meta: {
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
totalPages,
|
||||
hasNextPage: page < totalPages,
|
||||
hasPreviousPage: page > 1,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private buildWhereClause(
|
||||
filters: Partial<PaymentQueryDto>
|
||||
): Prisma.PaymentWhereInput {
|
||||
const {
|
||||
type,
|
||||
status,
|
||||
merchantPartnerId,
|
||||
customerId,
|
||||
subscriptionId,
|
||||
externalReference,
|
||||
reference,
|
||||
currency,
|
||||
amountMin,
|
||||
amountMax,
|
||||
createdFrom,
|
||||
createdTo,
|
||||
completedFrom,
|
||||
completedTo,
|
||||
hasFailureReason,
|
||||
} = filters;
|
||||
|
||||
const where: Prisma.PaymentWhereInput = {};
|
||||
|
||||
// Filtres simples
|
||||
if (type) where.type = type;
|
||||
if (status) where.status = status;
|
||||
if (merchantPartnerId) where.merchantPartnerId = merchantPartnerId;
|
||||
if (customerId) where.customerId = customerId;
|
||||
if (subscriptionId) where.subscriptionId = subscriptionId;
|
||||
if (currency) where.currency = currency;
|
||||
|
||||
// Filtres de recherche par référence
|
||||
if (externalReference) {
|
||||
where.externalReference = {
|
||||
contains: externalReference,
|
||||
mode: 'insensitive',
|
||||
};
|
||||
}
|
||||
|
||||
if (reference) {
|
||||
where.reference = {
|
||||
contains: reference,
|
||||
mode: 'insensitive',
|
||||
};
|
||||
}
|
||||
|
||||
// Filtre sur les montants
|
||||
if (amountMin !== undefined || amountMax !== undefined) {
|
||||
where.amount = {};
|
||||
if (amountMin !== undefined) {
|
||||
where.amount.gte = amountMin;
|
||||
}
|
||||
if (amountMax !== undefined) {
|
||||
where.amount.lte = amountMax;
|
||||
}
|
||||
}
|
||||
|
||||
// Filtres sur createdAt
|
||||
if (createdFrom || createdTo) {
|
||||
where.createdAt = {};
|
||||
if (createdFrom) {
|
||||
where.createdAt.gte = new Date(createdFrom);
|
||||
}
|
||||
if (createdTo) {
|
||||
where.createdAt.lte = new Date(createdTo);
|
||||
}
|
||||
}
|
||||
|
||||
// Filtres sur completedAt
|
||||
if (completedFrom || completedTo) {
|
||||
where.completedAt = {};
|
||||
if (completedFrom) {
|
||||
where.completedAt.gte = new Date(completedFrom);
|
||||
}
|
||||
if (completedTo) {
|
||||
where.completedAt.lte = new Date(completedTo);
|
||||
}
|
||||
}
|
||||
|
||||
// Filtre sur les paiements échoués
|
||||
if (hasFailureReason !== undefined) {
|
||||
if (hasFailureReason) {
|
||||
where.failureReason = { not: null };
|
||||
} else {
|
||||
where.failureReason = null;
|
||||
}
|
||||
}
|
||||
|
||||
return where;
|
||||
}
|
||||
|
||||
|
||||
refundPayment(paymentId: string, partnerId: any, refundDto: RefundDto) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import { IsString, IsOptional, IsNumber, IsEnum, IsBoolean, Min } from 'class-validator';
|
||||
import { IsString, IsOptional, IsNumber, IsEnum,IsDateString, IsBoolean, Min, IsInt } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { PaginationDto } from 'src/common/dto/pagination.dto';
|
||||
import { Type } from 'class-transformer';
|
||||
import { Periodicity, SubscriptionStatus } from 'generated/prisma';
|
||||
|
||||
export class CreateSubscriptionDto {
|
||||
@ApiProperty()
|
||||
@ -45,3 +48,122 @@ export class UpdateSubscriptionDto {
|
||||
@IsOptional()
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
export class SubscriptionQueryDto extends PaginationDto {
|
||||
@ApiProperty({
|
||||
description: 'Filter by merchant partner ID',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
merchantPartnerId?: number;
|
||||
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter by subscription status',
|
||||
enum: SubscriptionStatus,
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsEnum(SubscriptionStatus)
|
||||
status?: SubscriptionStatus;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter by periodicity',
|
||||
enum: Periodicity,
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsEnum(Periodicity)
|
||||
periodicity?: Periodicity;
|
||||
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter by service ID',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
serviceId?: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter subscriptions starting from this date (ISO format)',
|
||||
example: '2024-01-01',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
startDateFrom?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter subscriptions starting until this date (ISO format)',
|
||||
example: '2024-12-31',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
startDateTo?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter subscriptions ending from this date (ISO format)',
|
||||
example: '2024-01-01',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
endDateFrom?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter subscriptions ending until this date (ISO format)',
|
||||
example: '2024-12-31',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
endDateTo?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter subscriptions created from this date (ISO format)',
|
||||
example: '2024-01-01T00:00:00Z',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
createdFrom?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter subscriptions created until this date (ISO format)',
|
||||
example: '2024-12-31T23:59:59Z',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
createdTo?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter subscriptions with next payment from this date',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
nextPaymentFrom?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter subscriptions with next payment until this date',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
nextPaymentTo?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Filter by customer ID',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
customerId?: number;
|
||||
}
|
||||
@ -13,10 +13,11 @@ import {
|
||||
Logger,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { ApiTags, ApiOperation, ApiQuery,ApiBearerAuth, ApiResponse } from '@nestjs/swagger';
|
||||
import { SubscriptionsService } from './subscriptions.service';
|
||||
import { CreateSubscriptionDto, UpdateSubscriptionDto } from './dto/subscription.dto';
|
||||
import { CreateSubscriptionDto, SubscriptionQueryDto, UpdateSubscriptionDto } from './dto/subscription.dto';
|
||||
import { JwtAuthGuard } from 'src/common/guards/jwt-auth.guard';
|
||||
import { PaginationDto } from 'src/common/dto/pagination.dto';
|
||||
|
||||
@ApiTags('subscriptions')
|
||||
@Controller('subscriptions')
|
||||
@ -41,15 +42,21 @@ export class SubscriptionsController {
|
||||
}
|
||||
|
||||
@Get('/')
|
||||
@ApiOperation({ summary: 'Get subscription list' })
|
||||
async getAll(@Request() req) {
|
||||
return this.subscriptionsService.findAll();
|
||||
@ApiOperation({ summary: 'Get subscription list with pagination' })
|
||||
@ApiQuery({ type: PaginationDto })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Paginated list of subscriptions',
|
||||
})
|
||||
async getAll(@Request() req, @Query() paginationDto: SubscriptionQueryDto,) {
|
||||
return this.subscriptionsService.findAll(paginationDto);
|
||||
}
|
||||
|
||||
@Get('merchant/:merchantId')
|
||||
@ApiOperation({ summary: 'Get subscription list by merchant' })
|
||||
async getAllByMErchant(@Request() req, @Param('merchantId', ParseIntPipe) merchantId: number) {
|
||||
return this.subscriptionsService.findAllByMerchant(merchantId);
|
||||
async getAllByMErchant(@Request() req, @Param('merchantId', ParseIntPipe,) merchantId: number, paginationDto: Omit<SubscriptionQueryDto, 'merchantPartnerId'> ,) {
|
||||
const page = {...paginationDto, merchantPartnerId: merchantId};
|
||||
return this.subscriptionsService.findAll(page);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -3,9 +3,11 @@ import { InjectQueue } from '@nestjs/bull';
|
||||
import bull from 'bull';
|
||||
import { PrismaService } from '../../shared/services/prisma.service';
|
||||
import { PaymentsService } from '../payments/payments.service';
|
||||
import { CreateSubscriptionDto, UpdateSubscriptionDto } from './dto/subscription.dto';
|
||||
import { Subscription } from 'generated/prisma';
|
||||
import { CreateSubscriptionDto, SubscriptionQueryDto, UpdateSubscriptionDto } from './dto/subscription.dto';
|
||||
import { Prisma, Subscription } from 'generated/prisma';
|
||||
import { OperatorsService } from '../operators/operators.service';
|
||||
import { PaginationDto } from 'src/common/dto/pagination.dto';
|
||||
import { PaginatedResponse } from 'src/common/interfaces/paginated-response.interface';
|
||||
//import { SubscriptionStatus } from '@prisma/client';
|
||||
//import { SubscriptionStatus, Prisma } from '@prisma/client';
|
||||
|
||||
@ -46,16 +48,122 @@ export class SubscriptionsService {
|
||||
});
|
||||
}
|
||||
|
||||
async findAll(): Promise<Subscription[]> {
|
||||
async findAll( paginationDto: SubscriptionQueryDto,): Promise<PaginatedResponse<Subscription>> {
|
||||
const { page = 1, limit = 10, status,
|
||||
periodicity,
|
||||
merchantPartnerId,
|
||||
customerId,
|
||||
serviceId,
|
||||
startDateFrom,
|
||||
startDateTo,
|
||||
endDateFrom,
|
||||
endDateTo,
|
||||
createdFrom,
|
||||
createdTo,
|
||||
nextPaymentFrom,
|
||||
nextPaymentTo, } = paginationDto;
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
// Construction du where clause dynamique
|
||||
const where: Prisma.SubscriptionWhereInput = {};
|
||||
|
||||
// Filtre par status
|
||||
if (status) {
|
||||
where.status = status;
|
||||
}
|
||||
|
||||
// Filtre par periodicity
|
||||
if (periodicity) {
|
||||
where.periodicity = periodicity;
|
||||
}
|
||||
|
||||
// Filtre par IDs
|
||||
if (merchantPartnerId) {
|
||||
where.merchantPartnerId = merchantPartnerId;
|
||||
}
|
||||
|
||||
if (customerId) {
|
||||
where.customerId = customerId;
|
||||
}
|
||||
|
||||
if (serviceId) {
|
||||
where.serviceId = serviceId;
|
||||
}
|
||||
|
||||
// Filtres sur startDate
|
||||
if (startDateFrom || startDateTo) {
|
||||
where.startDate = {};
|
||||
if (startDateFrom) {
|
||||
where.startDate.gte = new Date(startDateFrom);
|
||||
}
|
||||
if (startDateTo) {
|
||||
where.startDate.lte = new Date(startDateTo);
|
||||
}
|
||||
}
|
||||
|
||||
// Filtres sur endDate
|
||||
if (endDateFrom || endDateTo) {
|
||||
where.endDate = {};
|
||||
if (endDateFrom) {
|
||||
where.endDate.gte = new Date(endDateFrom);
|
||||
}
|
||||
if (endDateTo) {
|
||||
where.endDate.lte = new Date(endDateTo);
|
||||
}
|
||||
}
|
||||
|
||||
// Filtres sur createdAt
|
||||
if (createdFrom || createdTo) {
|
||||
where.createdAt = {};
|
||||
if (createdFrom) {
|
||||
where.createdAt.gte = new Date(createdFrom);
|
||||
}
|
||||
if (createdTo) {
|
||||
where.createdAt.lte = new Date(createdTo);
|
||||
}
|
||||
}
|
||||
|
||||
// Filtres sur nextPaymentDate
|
||||
if (nextPaymentFrom || nextPaymentTo) {
|
||||
where.nextPaymentDate = {};
|
||||
if (nextPaymentFrom) {
|
||||
where.nextPaymentDate.gte = new Date(nextPaymentFrom);
|
||||
}
|
||||
if (nextPaymentTo) {
|
||||
where.nextPaymentDate.lte = new Date(nextPaymentTo);
|
||||
}
|
||||
}
|
||||
// Check if merchant exists
|
||||
const [subscriptions, total] = await Promise.all([
|
||||
this.prisma.subscription.findMany({
|
||||
where,
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
// Vous pouvez inclure des relations si nécessaire
|
||||
// include: {
|
||||
// merchantPartner: true,
|
||||
// service: true,
|
||||
// },
|
||||
}),
|
||||
this.prisma.subscription.count(),
|
||||
]);
|
||||
|
||||
return this.prisma.subscription.findMany({
|
||||
// where: { merchantPartnerId: merchantId },
|
||||
const totalPages = Math.ceil(total / limit);
|
||||
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
return {
|
||||
data: subscriptions,
|
||||
meta: {
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
totalPages,
|
||||
hasNextPage: page < totalPages,
|
||||
hasPreviousPage: page > 1,
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
getInvoices(id: string, partnerId: any) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user