firts commit

This commit is contained in:
Mamadou Khoussa [028918 DSI/DAC/DIF/DS] 2025-10-22 03:03:37 +00:00
parent b409b81b18
commit df7ae8dbeb
12 changed files with 91 additions and 38 deletions

View File

@ -1,3 +1,10 @@
export class AuthController{
import { Controller, Get } from "@nestjs/common";
//todo
@Controller()
export class AuthController{
@Get()
getHello(): string {
return 'Hello World!';
}
}

View File

@ -84,10 +84,11 @@ export class NotificationsService {
channel: dto.channel,
recipient: recipient.contact,
subject: dto.subject,
content: await this.templateService.render(dto.templateId, {
...recipient.data,
...dto.variables,
}),
content:'{}',
//content: await this.templateService.render(dto.templateId, {
// ...recipient.data,
// ...dto.variables,
//}),
templateId: dto.templateId,
status: 'PENDING',
batchId: dto.batchId,
@ -138,16 +139,16 @@ export class NotificationsService {
message: notification.content,
userToken: notification.user?.userToken,
userAlias: notification.user?.userAlias,
from: notification.metadata?.from,
//from: notification.metadata?.from,
});
break;
case 'EMAIL':
result = await this.emailService.send({
to: notification.recipient,
subject: notification.subject,
// subject: notification.subject,
content: notification.content,
template: notification.templateId,
//template: notification.templateId,
message: ''
});
break;
@ -244,8 +245,8 @@ export class NotificationsService {
for (const user of users) {
recipients.push({
userId: user.id,
contact: dto.channel === 'SMS' ? user.msisdn : user.email,
data: { name: user.name, msisdn: user.msisdn },
contact: dto.channel === 'SMS' ? user.msisdn : user.msisdn,
data: { name: user.msisdn, msisdn: user.msisdn },
});
}
}
@ -278,7 +279,7 @@ export class NotificationsService {
users.push(...activeUsers.map(u => ({
userId: u.id,
contact: u.msisdn,
data: { name: u.name, msisdn: u.msisdn },
data: { name: u.msisdn, msisdn: u.msisdn },
})));
break;

View File

@ -63,7 +63,7 @@ export class WebhookService {
try {
const signature = this.generateSignature(
webhook.payload,
webhook.partner?.secretKey,
webhook.partner?.secretKey as string,
);
const response = await firstValueFrom(
@ -84,8 +84,8 @@ export class WebhookService {
data: {
status: 'SUCCESS',
response: response.data,
responseCode: response.status,
deliveredAt: new Date(),
//responseCode: response.status,
//deliveredAt: new Date(),
attempts: attempt,
},
});
@ -96,7 +96,7 @@ export class WebhookService {
where: { id: webhookId },
data: {
status: attempt >= 3 ? 'FAILED' : 'RETRYING',
lastError: error.message,
//lastError: error.message,
attempts: attempt,
lastAttempt: new Date(),
},

View File

@ -1,5 +1,11 @@
//todo
import { Controller, Get } from "@nestjs/common";
@Controller()
export class OperatorsController{
@Get()
getHello(): string {
return 'Hello World!';
}
}

View File

@ -4,6 +4,7 @@ import {
IsOptional,
IsObject,
MinLength,
IsUrl,
} from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
@ -73,4 +74,16 @@ export class UpdateCallbacksDto {
onSuccess?: string;
onFailure?: string;
};
@IsOptional()
@IsUrl()
success?: string;
@IsOptional()
@IsUrl()
cancel?: string;
@IsOptional()
@IsUrl()
webhook?: string;
}

View File

@ -1,4 +1,9 @@
//todoe
//todo
import { Controller, Get } from "@nestjs/common";
@Controller()
export class PartnersController{
@Get()
getHello(): string {
return 'Hello World!';
}
}

View File

@ -7,6 +7,7 @@ import { PrismaService } from '../../shared/services/prisma.service';
import * as bcrypt from 'bcrypt';
import * as crypto from 'crypto';
import { CreatePartnerDto, UpdateCallbacksDto } from './dto/partner.dto';
import { Prisma } from 'generated/prisma';
@Injectable()
export class PartnersService {
@ -65,7 +66,9 @@ export class PartnersService {
const updatedPartner = await this.prisma.partner.update({
where: { id: partnerId },
data: {
callbacks: dto,
//callbacks: dto as unknown as Prisma.JsonValue,
// ou
callbacks: JSON.parse(JSON.stringify(dto)),
},
});

View File

@ -45,7 +45,9 @@ export class PaymentsService {
// Créer la transaction dans la base
const payment = await this.prisma.payment.create({
data: {
partnerId:"",
userId: user.id,
amount: chargeDto.amount,
currency: chargeDto.currency,

View File

@ -73,7 +73,7 @@ export class SubscriptionScheduler {
},
data: {
status: 'EXPIRED',
expiredAt: new Date(),
//expiredAt: new Date(),
},
});

View File

@ -3,7 +3,6 @@ import { PrismaService } from '../../../shared/services/prisma.service';
import { CreatePlanDto, UpdatePlanDto } from '../dto/plan.dto';
import { Prisma } from 'generated/prisma';
@Injectable()
export class PlanService {
constructor(private readonly prisma: PrismaService) {}
@ -248,9 +247,9 @@ export class PlanService {
interval: plan.interval,
intervalCount: plan.intervalCount,
trialDays: plan.trialDays,
features: plan.features,
limits: plan.limits,
metadata: { ...plan.metadata, duplicatedFrom: plan.id },
//features: plan.features,
//limits: plan.limits,
metadata: {metadata:plan.metadata, duplicatedFrom: plan.id },
active: false, // Désactivé par défaut
},
});
@ -321,14 +320,14 @@ export class PlanService {
select: {
createdAt: true,
cancelledAt: true,
expiredAt: true,
suspendedAt: true,
},
});
if (subscriptions.length === 0) return 0;
const lifetimes = subscriptions.map(sub => {
const endDate = sub.cancelledAt || sub.expiredAt || new Date();
const endDate = sub.cancelledAt || sub.suspendedAt || new Date();
return endDate.getTime() - sub.createdAt.getTime();
});

View File

@ -9,9 +9,11 @@ import { BillingService } from './services/billing.service';
import { PrismaService } from '../../shared/services/prisma.service';
import { PaymentsModule } from '../payments/payments.module';
import { NotificationsModule } from '../notifications/notifications.module';
import { HttpModule } from '@nestjs/axios';
@Module({
imports: [
HttpModule,
BullModule.registerQueue({
name: 'subscriptions',
}),

View File

@ -86,8 +86,6 @@ export class SubscriptionsService {
currentPeriodEnd,
nextBillingDate,
trialEndsAt,
amount: plan.amount,
currency: plan.currency,
metadata: {
...dto.metadata,
userAlias: user.userAlias,
@ -234,6 +232,18 @@ export class SubscriptionsService {
where: { id: partnerId },
});
interface PartnerCallbacks {
subscription?: {
onCancel?: string;
onRenew?: string;
onExpire?: string;
};
payment?: {
onSuccess?: string;
onFailure?: string;
};
}
/*
if (partner?.callbacks?subscription?.onCancel) {
await this.subscriptionQueue.add('webhook-notification', {
url: partner.callbacks.subscription.onCancel,
@ -241,6 +251,7 @@ export class SubscriptionsService {
subscription: updatedSubscription,
});
}
*/
return updatedSubscription;
}
@ -293,29 +304,32 @@ export class SubscriptionsService {
currentPeriodEnd: this.calculatePeriodEnd(subscription.plan, subscription.currentPeriodEnd),
nextBillingDate: this.calculatePeriodEnd(subscription.plan, subscription.currentPeriodEnd),
lastPaymentId: payment.id,
lastPaymentDate: new Date(),
// lastPaymentDate: new Date(),
renewalCount: { increment: 1 },
failureCount: 0, // Reset failure count on success
},
});
// Programmer le prochain renouvellement
/* todo
const delay = subscription.nextBillingDate.getTime() - Date.now();
await this.billingQueue.add(
'process-renewal',
{ subscriptionId },
{ delay },
);
*/
// Notifier le succès
if (subscription.partner?.callbacks?.subscription?.onRenew) {
/* if (subscription.partner?.callbacks?.subscription?.onRenew) {
await this.subscriptionQueue.add('webhook-notification', {
url: subscription.partner.callbacks.subscription.onRenew,
event: 'SUBSCRIPTION_RENEWED',
subscription: subscription,
payment: payment,
});
}
}*/
} else {
await this.handleRenewalFailure(subscription);
}
@ -342,13 +356,14 @@ export class SubscriptionsService {
});
if (payment.status === 'SUCCESS') {
//todo
await this.prisma.subscription.update({
where: { id: subscription.id },
data: {
status: 'ACTIVE',
activatedAt: new Date(),
createdAt: new Date(),
lastPaymentId: payment.id,
lastPaymentDate: new Date(),
//lastPaymentDate: new Date(),
},
});
@ -364,7 +379,7 @@ export class SubscriptionsService {
where: { id: subscription.id },
data: {
status: 'FAILED',
failureReason: payment.failureReason,
//todo failureReason: payment.failureReason,
},
});
}
@ -373,7 +388,7 @@ export class SubscriptionsService {
where: { id: subscription.id },
data: {
status: 'FAILED',
failureReason: error.message,
//failureReason: error.message,
},
});
throw error;
@ -392,7 +407,7 @@ export class SubscriptionsService {
status: 'SUSPENDED',
failureCount,
suspendedAt: new Date(),
suspensionReason: `Payment failed ${maxRetries} times`,
//suspensionReason: `Payment failed ${maxRetries} times`,
},
});