diff --git a/package-lock.json b/package-lock.json index 7bc3bbb..03aa2e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,8 @@ "cache-manager-redis-store": "^3.0.1", "class-transformer": "^0.5.1", "class-validator": "^0.14.2", + "passport-headerapikey": "^1.2.2", + "passport-jwt": "^4.0.1", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1" }, @@ -9201,11 +9203,30 @@ "url": "https://github.com/sponsors/jaredhanson" } }, + "node_modules/passport-headerapikey": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/passport-headerapikey/-/passport-headerapikey-1.2.2.tgz", + "integrity": "sha512-4BvVJRrWsNJPrd3UoZfcnnl4zvUWYKEtfYkoDsaOKBsrWHYmzTApCjs7qUbncOLexE9ul0IRiYBFfBG0y9IVQA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.15", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "license": "MIT", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, "node_modules/passport-strategy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", - "peer": true, "engines": { "node": ">= 0.4.0" } diff --git a/package.json b/package.json index d5c4926..8fb5d56 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,8 @@ "cache-manager-redis-store": "^3.0.1", "class-transformer": "^0.5.1", "class-validator": "^0.14.2", + "passport-headerapikey": "^1.2.2", + "passport-jwt": "^4.0.1", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1" }, diff --git a/src/common/filters/prisma-exception.filter.ts b/src/common/filters/prisma-exception.filter.ts index b16eab9..fdc69c1 100644 --- a/src/common/filters/prisma-exception.filter.ts +++ b/src/common/filters/prisma-exception.filter.ts @@ -1,6 +1,6 @@ import { ExceptionFilter, Catch, ArgumentsHost, HttpStatus } from '@nestjs/common'; -import { Prisma } from '@prisma/client'; -import { Response } from 'express'; + import { Response } from 'express'; +import { Prisma } from 'generated/prisma'; @Catch(Prisma.PrismaClientKnownRequestError) export class PrismaExceptionFilter implements ExceptionFilter { diff --git a/src/common/guards/jwt-auth.guard.ts b/src/common/guards/jwt-auth.guard.ts index 64dfb27..2c94b5c 100644 --- a/src/common/guards/jwt-auth.guard.ts +++ b/src/common/guards/jwt-auth.guard.ts @@ -2,7 +2,7 @@ import { Injectable, ExecutionContext } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; import { Reflector } from '@nestjs/core'; import { IS_PUBLIC_KEY } from '../decorators/public.decorator'; - + @Injectable() export class JwtAuthGuard extends AuthGuard('jwt') { constructor(private reflector: Reflector) { diff --git a/src/common/guards/roles.guard.ts b/src/common/guards/roles.guard.ts index 2182c3d..373f775 100644 --- a/src/common/guards/roles.guard.ts +++ b/src/common/guards/roles.guard.ts @@ -1,7 +1,7 @@ import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { ROLES_KEY } from '../decorators/roles.decorator'; - + @Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {} diff --git a/src/config/app.config.ts b/src/config/app.config.ts index 7ef8656..e0bfb97 100644 --- a/src/config/app.config.ts +++ b/src/config/app.config.ts @@ -1,7 +1,7 @@ import { registerAs } from '@nestjs/config'; export default registerAs('app', () => ({ - port: parseInt(process.env.PORT, 10) || 3000, + port: parseInt(process.env.PORT ?? "3000", 10) || 3000, env: process.env.NODE_ENV || 'development', apiPrefix: process.env.API_PREFIX || 'v2', jwtSecret: process.env.JWT_SECRET || 'your-secret-key', @@ -11,6 +11,6 @@ export default registerAs('app', () => ({ }, redis: { host: process.env.REDIS_HOST || 'localhost', - port: parseInt(process.env.REDIS_PORT, 10) || 6379, + port: parseInt(process.env.REDIS_PORT?? "6379", 10) || 6379, }, })); diff --git a/src/modules/auth/auth.controller.ts b/src/modules/auth/auth.controller.ts new file mode 100644 index 0000000..2735892 --- /dev/null +++ b/src/modules/auth/auth.controller.ts @@ -0,0 +1,3 @@ +export class AuthController{ + +} \ No newline at end of file diff --git a/src/modules/auth/auth.module.ts b/src/modules/auth/auth.module.ts index b7b2501..50e178f 100644 --- a/src/modules/auth/auth.module.ts +++ b/src/modules/auth/auth.module.ts @@ -14,13 +14,23 @@ import { OperatorsModule } from '../operators/operators.module'; PassportModule.register({ defaultStrategy: 'jwt' }), JwtModule.registerAsync({ imports: [ConfigModule], + inject: [ConfigService], useFactory: async (configService: ConfigService) => ({ - secret: configService.get('app.jwtSecret'), + secret: configService.get('JWT_SECRET'), signOptions: { - expiresIn: configService.get('app.jwtExpiresIn'), + expiresIn: configService.get('JWT_EXPIRATION') || '1h', }, }), - inject: [ConfigService], + /*todo + useFactory: async (configService: ConfigService) => { + return { + secret: configService.get('JWT_SECRET'), + signOptions: { + expiresIn: configService.get('JWT_EXPIRATION') || '1h' + }, + }; + },*/ + }), OperatorsModule, ], diff --git a/src/modules/auth/strategies/api-key.strategy.ts b/src/modules/auth/strategies/api-key.strategy.ts index 1fdb18f..93d048a 100644 --- a/src/modules/auth/strategies/api-key.strategy.ts +++ b/src/modules/auth/strategies/api-key.strategy.ts @@ -8,10 +8,7 @@ export class ApiKeyStrategy extends PassportStrategy(HeaderAPIKeyStrategy, 'api- constructor(private readonly prisma: PrismaService) { super( { header: 'X-API-Key', prefix: '' }, - true, - async (apiKey, done) => { - return this.validate(apiKey, done); - }, + true ); } diff --git a/src/modules/notifications/notifications.controller.ts b/src/modules/notifications/notifications.controller.ts index a4a9539..e795fe6 100644 --- a/src/modules/notifications/notifications.controller.ts +++ b/src/modules/notifications/notifications.controller.ts @@ -2,8 +2,8 @@ import { Controller, Post, Get, Body, Param, Query, UseGuards, Request } from '@ import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'; import { NotificationsService } from './services/notifications.service'; import { SendNotificationDto, BulkNotificationDto } from './dto/notification.dto'; -import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard'; - +import { JwtAuthGuard } from 'src/common/guards/jwt-auth.guard'; + @ApiTags('notifications') @Controller('notifications') @UseGuards(JwtAuthGuard) diff --git a/src/modules/notifications/notifications.module.ts b/src/modules/notifications/notifications.module.ts index 4a52a9e..629bab5 100644 --- a/src/modules/notifications/notifications.module.ts +++ b/src/modules/notifications/notifications.module.ts @@ -2,7 +2,7 @@ import { Module } from '@nestjs/common'; import { BullModule } from '@nestjs/bull'; import { HttpModule } from '@nestjs/axios'; import { NotificationsController } from './notifications.controller'; -import { NotificationsService } from './notifications.service'; +import { NotificationsService } from './services/notifications.service'; import { SmsService } from './services/sms.service'; import { EmailService } from './services/email.service'; import { WebhookService } from './services/webhook.service'; diff --git a/src/modules/notifications/processors/notification.processor.ts b/src/modules/notifications/processors/notification.processor.ts index 1f55e25..d2d2570 100644 --- a/src/modules/notifications/processors/notification.processor.ts +++ b/src/modules/notifications/processors/notification.processor.ts @@ -1,6 +1,6 @@ import { Process, Processor } from '@nestjs/bull'; -import { Job } from 'bull'; -import { NotificationsService } from '../notifications.service'; +import bull from 'bull'; +import { NotificationsService } from '../services/notifications.service'; import { WebhookService } from '../services/webhook.service'; @Processor('notifications') @@ -10,7 +10,7 @@ export class NotificationProcessor { ) {} @Process('send-notification') - async handleSendNotification(job: Job) { + async handleSendNotification(job: bull.Job) { const { notificationId } = job.data; try { @@ -23,9 +23,9 @@ export class NotificationProcessor { } @Process('bulk-send') - async handleBulkSend(job: Job) { + async handleBulkSend(job: bull.Job) { const { notifications } = job.data; - const results = []; + const results:any = []; for (const notificationId of notifications) { try { @@ -47,7 +47,7 @@ export class WebhookProcessor { ) {} @Process('send-webhook') - async handleSendWebhook(job: Job) { + async handleSendWebhook(job: bull.Job) { const { webhookId, attempt } = job.data; return await this.webhookService.processWebhook(webhookId, attempt); diff --git a/src/modules/notifications/services/email.service.ts b/src/modules/notifications/services/email.service.ts new file mode 100644 index 0000000..439c01a --- /dev/null +++ b/src/modules/notifications/services/email.service.ts @@ -0,0 +1,98 @@ +import { Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { OperatorsService } from '../../operators/operators.service'; +import { PrismaService } from '../../../shared/services/prisma.service'; +//todo rewrite +@Injectable() +export class EmailService { + constructor( + private readonly operatorsService: OperatorsService, + private readonly prisma: PrismaService, + private readonly configService: ConfigService, + ) {} + + async send(params: { + to: string; + message: string; + subject?:string; + content?:string; + template?:string + userToken?: string; + userAlias?: string; + from?: string; + }) { + // Si on a un userToken, utiliser l'opérateur de l'utilisateur + if (params.userToken) { + const user = await this.prisma.user.findUnique({ + where: { userToken: params.userToken }, + include: { operator: true }, + }); + + if (user) { + const adapter = this.operatorsService.getAdapter( + user.operator.code, + user.country, + ); + + return await adapter.sendSms({ + to: params.to, + message: params.message, + userToken: params.userToken, + userAlias: params.userAlias, + from: params.from, + country: user.country, + }); + } + } + + // Sinon, détecter l'opérateur par le numéro + const operator = this.detectOperatorByNumber(params.to); + const adapter = this.operatorsService.getAdapter(operator.code, operator.country); + + return await adapter.sendSms({ + to: params.to, + message: params.message, + from: params.from, + country: operator.country, + }); + } + + async sendOtp(msisdn: string, code: string, template?: string) { + const message = template + ? template.replace('{code}', code) + : `Your verification code is: ${code}`; + + return this.send({ + to: msisdn, + message: message, + }); + } + + async sendTransactional(params: { + to: string; + template: string; + variables: Record; + userToken?: string; + }) { + // Remplacer les variables dans le template + let message = params.template; + for (const [key, value] of Object.entries(params.variables)) { + message = message.replace(new RegExp(`{${key}}`, 'g'), value); + } + + return this.send({ + to: params.to, + message: message, + userToken: params.userToken, + }); + } + + private detectOperatorByNumber(msisdn: string) { + // Logique de détection basée sur le préfixe + // Pour simplifier, on retourne Orange CI par défaut + return { + code: 'ORANGE', + country: 'CI', + }; + } +} \ No newline at end of file diff --git a/src/modules/notifications/services/notifications.service.ts b/src/modules/notifications/services/notifications.service.ts index 891f0d9..77a023c 100644 --- a/src/modules/notifications/services/notifications.service.ts +++ b/src/modules/notifications/services/notifications.service.ts @@ -1,12 +1,12 @@ import { Injectable, BadRequestException } from '@nestjs/common'; import { InjectQueue } from '@nestjs/bull'; -import { Queue } from 'bull'; -import { PrismaService } from '../../shared/services/prisma.service'; -import { SmsService } from './services/sms.service'; -import { EmailService } from './services/email.service'; -import { WebhookService } from './services/webhook.service'; -import { NotificationTemplateService } from './services/template.service'; -import { SendNotificationDto, BulkNotificationDto } from './dto/notification.dto'; +import bull from 'bull'; + import { SmsService } from './sms.service'; +import { EmailService } from './email.service'; +import { WebhookService } from './webhook.service'; +import { NotificationTemplateService } from './template.service'; +import { SendNotificationDto, BulkNotificationDto } from '../dto/notification.dto'; +import { PrismaService } from 'src/shared/services/prisma.service'; @Injectable() export class NotificationsService { @@ -16,12 +16,12 @@ export class NotificationsService { private readonly emailService: EmailService, private readonly webhookService: WebhookService, private readonly templateService: NotificationTemplateService, - @InjectQueue('notifications') private notificationQueue: Queue, + @InjectQueue('notifications') private notificationQueue: bull.Queue, ) {} async send(partnerId: string, dto: SendNotificationDto) { // Valider l'utilisateur si fourni - let user = null; + let user:any = null; if (dto.userToken) { user = await this.prisma.user.findFirst({ where: { @@ -70,13 +70,13 @@ export class NotificationsService { } async sendBulk(partnerId: string, dto: BulkNotificationDto) { - const notifications = []; + const notifications :any= []; // Récupérer les destinataires selon les critères - const recipients = await this.getRecipients(partnerId, dto); + const recipients:any = await this.getRecipients(partnerId, dto); for (const recipient of recipients) { - const notification = await this.prisma.notification.create({ + const notification:any = await this.prisma.notification.create({ data: { partnerId: partnerId, userId: recipient.userId, @@ -148,6 +148,7 @@ export class NotificationsService { subject: notification.subject, content: notification.content, template: notification.templateId, + message: '' }); break; @@ -230,7 +231,7 @@ export class NotificationsService { } private async getRecipients(partnerId: string, dto: BulkNotificationDto) { - const recipients = []; + const recipients:any = []; if (dto.userIds && dto.userIds.length > 0) { const users = await this.prisma.user.findMany({ @@ -259,7 +260,7 @@ export class NotificationsService { } private async getSegmentUsers(partnerId: string, segments: string[]) { - const users = []; + const users:any = []; for (const segment of segments) { switch (segment) { diff --git a/src/modules/notifications/services/template.service.ts b/src/modules/notifications/services/template.service.ts new file mode 100644 index 0000000..5a35d24 --- /dev/null +++ b/src/modules/notifications/services/template.service.ts @@ -0,0 +1,6 @@ +export class NotificationTemplateService{ + render(templateId: string | undefined, arg1: any) { + throw new Error('Method not implemented.'); + } + +} \ No newline at end of file diff --git a/src/modules/notifications/services/webhook.service.ts b/src/modules/notifications/services/webhook.service.ts index c8d7cca..774f2d4 100644 --- a/src/modules/notifications/services/webhook.service.ts +++ b/src/modules/notifications/services/webhook.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { HttpService } from '@nestjs/axios'; import { InjectQueue } from '@nestjs/bull'; -import { Queue } from 'bull'; +import bull from 'bull'; import { firstValueFrom } from 'rxjs'; import { PrismaService } from '../../../shared/services/prisma.service'; import * as crypto from 'crypto'; @@ -11,7 +11,7 @@ export class WebhookService { constructor( private readonly httpService: HttpService, private readonly prisma: PrismaService, - @InjectQueue('webhooks') private webhookQueue: Queue, + @InjectQueue('webhooks') private webhookQueue: bull.Queue, ) {} async send(params: { diff --git a/src/modules/operators/adapters/operator.adapter.interface.ts b/src/modules/operators/adapters/operator.adapter.interface.ts index c7269f9..c43bddb 100644 --- a/src/modules/operators/adapters/operator.adapter.interface.ts +++ b/src/modules/operators/adapters/operator.adapter.interface.ts @@ -1,3 +1,35 @@ + + +export interface AuthValidateParams{ + +} + +export interface AuthValidateResponse{ + +} + +export interface RefundParams{ + +} + +export interface SmsParams{ + +} + +export interface SmsResponse{ + +} + +export interface RefundResponse{ + +} + +export interface SubscriptionParams{ + +} +export interface SubscriptionResponse{ + +} export interface IOperatorAdapter { initializeAuth(params: AuthInitParams): Promise; validateAuth(params: AuthValidateParams): Promise; diff --git a/src/modules/operators/adapters/orange.adapter.ts b/src/modules/operators/adapters/orange.adapter.ts index af4580a..6fce7db 100644 --- a/src/modules/operators/adapters/orange.adapter.ts +++ b/src/modules/operators/adapters/orange.adapter.ts @@ -10,6 +10,7 @@ import { ChargeResponse, } from './operator.adapter.interface'; import { OrangeTransformer } from '../transformers/orange.transformer'; + @Injectable() export class OrangeAdapter implements IOperatorAdapter { @@ -21,8 +22,8 @@ export class OrangeAdapter implements IOperatorAdapter { private readonly httpService: HttpService, private readonly configService: ConfigService, ) { - this.baseUrl = this.configService.get('ORANGE_API_URL'); - this.accessToken = this.configService.get('ORANGE_ACCESS_TOKEN'); + this.baseUrl = this.configService.get('ORANGE_API_URL') as string; + this.accessToken = this.configService.get('ORANGE_ACCESS_TOKEN') as string; this.transformer = new OrangeTransformer(); } diff --git a/src/modules/operators/adapters/orange.transformer.ts b/src/modules/operators/adapters/orange.transformer.ts deleted file mode 100644 index 79e90d0..0000000 --- a/src/modules/operators/adapters/orange.transformer.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -@Injectable() -export class OrangeTransformer { - transformChargeResponse(bizaoResponse: any): any { - return { - paymentId: bizaoResponse.amountTransaction?.serverReferenceCode, - status: this.mapStatus( - bizaoResponse.amountTransaction?.transactionOperationStatus, - ), - operatorReference: bizaoResponse.amountTransaction?.serverReferenceCode, - amount: parseFloat( - bizaoResponse.amountTransaction?.paymentAmount?.totalAmountCharged, - ), - currency: - bizaoResponse.amountTransaction?.paymentAmount?.chargingInformation - ?.currency, - createdAt: new Date(), - }; - } - - private mapStatus(bizaoStatus: string): string { - const statusMap = { - Charged: 'SUCCESS', - Failed: 'FAILED', - Pending: 'PENDING', - }; - return statusMap[bizaoStatus] || 'PENDING'; - } -} diff --git a/src/modules/operators/transformers/orange.transformer.ts b/src/modules/operators/transformers/orange.transformer.ts index 84f3c33..79e90d0 100644 --- a/src/modules/operators/transformers/orange.transformer.ts +++ b/src/modules/operators/transformers/orange.transformer.ts @@ -1,3 +1,30 @@ -export class OrangeTransformer{ - -} \ No newline at end of file +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class OrangeTransformer { + transformChargeResponse(bizaoResponse: any): any { + return { + paymentId: bizaoResponse.amountTransaction?.serverReferenceCode, + status: this.mapStatus( + bizaoResponse.amountTransaction?.transactionOperationStatus, + ), + operatorReference: bizaoResponse.amountTransaction?.serverReferenceCode, + amount: parseFloat( + bizaoResponse.amountTransaction?.paymentAmount?.totalAmountCharged, + ), + currency: + bizaoResponse.amountTransaction?.paymentAmount?.chargingInformation + ?.currency, + createdAt: new Date(), + }; + } + + private mapStatus(bizaoStatus: string): string { + const statusMap = { + Charged: 'SUCCESS', + Failed: 'FAILED', + Pending: 'PENDING', + }; + return statusMap[bizaoStatus] || 'PENDING'; + } +} diff --git a/src/modules/partners/partners.controller.ts b/src/modules/partners/partners.controller.ts new file mode 100644 index 0000000..057af66 --- /dev/null +++ b/src/modules/partners/partners.controller.ts @@ -0,0 +1,4 @@ +//todoe +export class PartnersController{ + +} \ No newline at end of file diff --git a/src/modules/subscriptions/processors/subscription.processor.ts b/src/modules/subscriptions/processors/subscription.processor.ts index d28a490..7b0ea04 100644 --- a/src/modules/subscriptions/processors/subscription.processor.ts +++ b/src/modules/subscriptions/processors/subscription.processor.ts @@ -1,5 +1,5 @@ import { Process, Processor } from '@nestjs/bull'; -import { Job } from 'bull'; +import bull from 'bull'; import { SubscriptionsService } from '../subscriptions.service'; import { HttpService } from '@nestjs/axios'; import { firstValueFrom } from 'rxjs'; @@ -12,7 +12,7 @@ export class SubscriptionProcessor { ) {} @Process('webhook-notification') - async handleWebhookNotification(job: Job) { + async handleWebhookNotification(job: bull.Job) { const { url, event, subscription, payment } = job.data; try { @@ -50,13 +50,13 @@ export class BillingProcessor { ) {} @Process('process-renewal') - async handleRenewal(job: Job) { + async handleRenewal(job: bull.Job) { const { subscriptionId } = job.data; await this.subscriptionsService.processRenewal(subscriptionId); } @Process('trial-end') - async handleTrialEnd(job: Job) { + async handleTrialEnd(job: bull.Job) { const { subscriptionId } = job.data; // Convertir de TRIAL à ACTIVE et traiter le premier paiement @@ -64,7 +64,7 @@ export class BillingProcessor { } @Process('retry-renewal') - async handleRetryRenewal(job: Job) { + async handleRetryRenewal(job: bull.Job) { const { subscriptionId, attempt } = job.data; console.log(`Retrying renewal for subscription ${subscriptionId}, attempt ${attempt}`); diff --git a/src/modules/subscriptions/schedulers/subscription.scheduler.ts b/src/modules/subscriptions/schedulers/subscription.scheduler.ts index 2c1aa91..09cbca8 100644 --- a/src/modules/subscriptions/schedulers/subscription.scheduler.ts +++ b/src/modules/subscriptions/schedulers/subscription.scheduler.ts @@ -1,14 +1,14 @@ import { Injectable } from '@nestjs/common'; import { Cron, CronExpression } from '@nestjs/schedule'; import { InjectQueue } from '@nestjs/bull'; -import { Queue } from 'bull'; +import bull from 'bull'; import { PrismaService } from '../../../shared/services/prisma.service'; @Injectable() export class SubscriptionScheduler { constructor( private readonly prisma: PrismaService, - @InjectQueue('billing') private billingQueue: Queue, + @InjectQueue('billing') private billingQueue: bull.Queue, ) {} @Cron(CronExpression.EVERY_HOUR) diff --git a/src/modules/subscriptions/services/billing.service.ts b/src/modules/subscriptions/services/billing.service.ts index dc764b9..1908bb2 100644 --- a/src/modules/subscriptions/services/billing.service.ts +++ b/src/modules/subscriptions/services/billing.service.ts @@ -45,6 +45,7 @@ export class BillingService { end: subscription.currentPeriodEnd, }, }, + partnerId: '' }); // Mettre à jour la facture diff --git a/src/modules/subscriptions/services/plan.service.ts b/src/modules/subscriptions/services/plan.service.ts index cda973c..72e56c7 100644 --- a/src/modules/subscriptions/services/plan.service.ts +++ b/src/modules/subscriptions/services/plan.service.ts @@ -1,7 +1,8 @@ import { Injectable, BadRequestException, NotFoundException } from '@nestjs/common'; import { PrismaService } from '../../../shared/services/prisma.service'; import { CreatePlanDto, UpdatePlanDto } from '../dto/plan.dto'; -import { Prisma } from '@prisma/client'; +import { Prisma } from 'generated/prisma'; + @Injectable() export class PlanService { diff --git a/src/modules/subscriptions/subscriptions.service.ts b/src/modules/subscriptions/subscriptions.service.ts index 69997b1..08327f5 100644 --- a/src/modules/subscriptions/subscriptions.service.ts +++ b/src/modules/subscriptions/subscriptions.service.ts @@ -9,6 +9,15 @@ import { CreateSubscriptionDto, UpdateSubscriptionDto } from './dto/subscription @Injectable() export class SubscriptionsService { + get(id: string, partnerId: any) { + throw new Error('Method not implemented.'); + } + list(arg0: { partnerId: any; status: string | undefined; userId: string | undefined; page: number; limit: number; }) { + throw new Error('Method not implemented.'); + } + getInvoices(id: string, partnerId: any) { + throw new Error('Method not implemented.'); + } constructor( private readonly prisma: PrismaService, private readonly paymentsService: PaymentsService, @@ -141,7 +150,7 @@ export class SubscriptionsService { if (dto.status === 'PAUSED' && subscription.status === 'ACTIVE') { updateData.status = 'PAUSED'; updateData.pausedAt = new Date(); - } else if (dto.status === 'ACTIVE' && subscription.status === 'PAUSED') { + } else if (dto.status === 'ACTIVE' && subscription.status === 'SUSPENDED') { updateData.status = 'ACTIVE'; updateData.pausedAt = null; // Recalculer la prochaine date de facturation @@ -166,7 +175,7 @@ export class SubscriptionsService { } if (dto.metadata) { - updateData.metadata = { ...subscription.metadata, ...dto.metadata }; + updateData.metadata = { metadata:subscription.metadata, ...dto.metadata }; } const updatedSubscription = await this.prisma.subscription.update({ @@ -201,10 +210,8 @@ export class SubscriptionsService { where: { id: subscriptionId }, data: { status: 'CANCELLED', - cancelledAt: new Date(), - cancellationReason: reason, - metadata: { - ...subscription.metadata, + cancelledAt: new Date(), + metadata: { cancellationDetails: { reason, cancelledBy: 'partner', @@ -227,7 +234,7 @@ export class SubscriptionsService { where: { id: partnerId }, }); - if (partner?.callbacks?.subscription?.onCancel) { + if (partner?.callbacks?subscription?.onCancel) { await this.subscriptionQueue.add('webhook-notification', { url: partner.callbacks.subscription.onCancel, event: 'SUBSCRIPTION_CANCELLED', @@ -259,10 +266,11 @@ export class SubscriptionsService { try { // Créer le paiement de renouvellement + //todo const payment = await this.paymentsService.createCharge({ userToken: subscription.user.userToken, - amount: subscription.amount, - currency: subscription.currency, + amount: subscription.plan.amount, + currency: subscription.plan.currency, description: `Renewal: ${subscription.plan.name}`, reference: `REN-${subscription.id}-${Date.now()}`, metadata: { @@ -273,6 +281,7 @@ export class SubscriptionsService { end: this.calculatePeriodEnd(subscription.plan, subscription.currentPeriodEnd), }, }, + partnerId: '' }); if (payment.status === 'SUCCESS') { @@ -315,7 +324,7 @@ export class SubscriptionsService { await this.handleRenewalFailure(subscription); } } - +//todo private async processInitialPayment(subscription: any, callbackUrl?: string) { try { const payment = await this.paymentsService.createCharge({ @@ -329,6 +338,7 @@ export class SubscriptionsService { subscriptionId: subscription.id, type: 'initial', }, + partnerId:"" }); if (payment.status === 'SUCCESS') { diff --git a/src/shared/services/prisma.service.ts b/src/shared/services/prisma.service.ts index 1902de8..da108bc 100644 --- a/src/shared/services/prisma.service.ts +++ b/src/shared/services/prisma.service.ts @@ -1,6 +1,6 @@ import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common'; -import { PrismaClient } from '@prisma/client'; - +import { PrismaClient } from 'generated/prisma'; + @Injectable() export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy { constructor() {