firts commit
This commit is contained in:
parent
b409b81b18
commit
df7ae8dbeb
@ -1,3 +1,10 @@
|
|||||||
export class AuthController{
|
import { Controller, Get } from "@nestjs/common";
|
||||||
|
|
||||||
|
//todo
|
||||||
|
@Controller()
|
||||||
|
export class AuthController{
|
||||||
|
@Get()
|
||||||
|
getHello(): string {
|
||||||
|
return 'Hello World!';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -84,10 +84,11 @@ export class NotificationsService {
|
|||||||
channel: dto.channel,
|
channel: dto.channel,
|
||||||
recipient: recipient.contact,
|
recipient: recipient.contact,
|
||||||
subject: dto.subject,
|
subject: dto.subject,
|
||||||
content: await this.templateService.render(dto.templateId, {
|
content:'{}',
|
||||||
...recipient.data,
|
//content: await this.templateService.render(dto.templateId, {
|
||||||
...dto.variables,
|
// ...recipient.data,
|
||||||
}),
|
// ...dto.variables,
|
||||||
|
//}),
|
||||||
templateId: dto.templateId,
|
templateId: dto.templateId,
|
||||||
status: 'PENDING',
|
status: 'PENDING',
|
||||||
batchId: dto.batchId,
|
batchId: dto.batchId,
|
||||||
@ -138,16 +139,16 @@ export class NotificationsService {
|
|||||||
message: notification.content,
|
message: notification.content,
|
||||||
userToken: notification.user?.userToken,
|
userToken: notification.user?.userToken,
|
||||||
userAlias: notification.user?.userAlias,
|
userAlias: notification.user?.userAlias,
|
||||||
from: notification.metadata?.from,
|
//from: notification.metadata?.from,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'EMAIL':
|
case 'EMAIL':
|
||||||
result = await this.emailService.send({
|
result = await this.emailService.send({
|
||||||
to: notification.recipient,
|
to: notification.recipient,
|
||||||
subject: notification.subject,
|
// subject: notification.subject,
|
||||||
content: notification.content,
|
content: notification.content,
|
||||||
template: notification.templateId,
|
//template: notification.templateId,
|
||||||
message: ''
|
message: ''
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@ -244,8 +245,8 @@ export class NotificationsService {
|
|||||||
for (const user of users) {
|
for (const user of users) {
|
||||||
recipients.push({
|
recipients.push({
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
contact: dto.channel === 'SMS' ? user.msisdn : user.email,
|
contact: dto.channel === 'SMS' ? user.msisdn : user.msisdn,
|
||||||
data: { name: user.name, msisdn: user.msisdn },
|
data: { name: user.msisdn, msisdn: user.msisdn },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -278,7 +279,7 @@ export class NotificationsService {
|
|||||||
users.push(...activeUsers.map(u => ({
|
users.push(...activeUsers.map(u => ({
|
||||||
userId: u.id,
|
userId: u.id,
|
||||||
contact: u.msisdn,
|
contact: u.msisdn,
|
||||||
data: { name: u.name, msisdn: u.msisdn },
|
data: { name: u.msisdn, msisdn: u.msisdn },
|
||||||
})));
|
})));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@ -63,7 +63,7 @@ export class WebhookService {
|
|||||||
try {
|
try {
|
||||||
const signature = this.generateSignature(
|
const signature = this.generateSignature(
|
||||||
webhook.payload,
|
webhook.payload,
|
||||||
webhook.partner?.secretKey,
|
webhook.partner?.secretKey as string,
|
||||||
);
|
);
|
||||||
|
|
||||||
const response = await firstValueFrom(
|
const response = await firstValueFrom(
|
||||||
@ -84,8 +84,8 @@ export class WebhookService {
|
|||||||
data: {
|
data: {
|
||||||
status: 'SUCCESS',
|
status: 'SUCCESS',
|
||||||
response: response.data,
|
response: response.data,
|
||||||
responseCode: response.status,
|
//responseCode: response.status,
|
||||||
deliveredAt: new Date(),
|
//deliveredAt: new Date(),
|
||||||
attempts: attempt,
|
attempts: attempt,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -96,7 +96,7 @@ export class WebhookService {
|
|||||||
where: { id: webhookId },
|
where: { id: webhookId },
|
||||||
data: {
|
data: {
|
||||||
status: attempt >= 3 ? 'FAILED' : 'RETRYING',
|
status: attempt >= 3 ? 'FAILED' : 'RETRYING',
|
||||||
lastError: error.message,
|
//lastError: error.message,
|
||||||
attempts: attempt,
|
attempts: attempt,
|
||||||
lastAttempt: new Date(),
|
lastAttempt: new Date(),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,5 +1,11 @@
|
|||||||
//todo
|
//todo
|
||||||
|
import { Controller, Get } from "@nestjs/common";
|
||||||
|
|
||||||
|
@Controller()
|
||||||
export class OperatorsController{
|
export class OperatorsController{
|
||||||
|
@Get()
|
||||||
|
getHello(): string {
|
||||||
|
return 'Hello World!';
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -4,6 +4,7 @@ import {
|
|||||||
IsOptional,
|
IsOptional,
|
||||||
IsObject,
|
IsObject,
|
||||||
MinLength,
|
MinLength,
|
||||||
|
IsUrl,
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
@ -73,4 +74,16 @@ export class UpdateCallbacksDto {
|
|||||||
onSuccess?: string;
|
onSuccess?: string;
|
||||||
onFailure?: string;
|
onFailure?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsUrl()
|
||||||
|
success?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsUrl()
|
||||||
|
cancel?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsUrl()
|
||||||
|
webhook?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,9 @@
|
|||||||
//todoe
|
//todo
|
||||||
|
import { Controller, Get } from "@nestjs/common";
|
||||||
|
@Controller()
|
||||||
export class PartnersController{
|
export class PartnersController{
|
||||||
|
@Get()
|
||||||
|
getHello(): string {
|
||||||
|
return 'Hello World!';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -7,6 +7,7 @@ import { PrismaService } from '../../shared/services/prisma.service';
|
|||||||
import * as bcrypt from 'bcrypt';
|
import * as bcrypt from 'bcrypt';
|
||||||
import * as crypto from 'crypto';
|
import * as crypto from 'crypto';
|
||||||
import { CreatePartnerDto, UpdateCallbacksDto } from './dto/partner.dto';
|
import { CreatePartnerDto, UpdateCallbacksDto } from './dto/partner.dto';
|
||||||
|
import { Prisma } from 'generated/prisma';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PartnersService {
|
export class PartnersService {
|
||||||
@ -65,7 +66,9 @@ export class PartnersService {
|
|||||||
const updatedPartner = await this.prisma.partner.update({
|
const updatedPartner = await this.prisma.partner.update({
|
||||||
where: { id: partnerId },
|
where: { id: partnerId },
|
||||||
data: {
|
data: {
|
||||||
callbacks: dto,
|
//callbacks: dto as unknown as Prisma.JsonValue,
|
||||||
|
// ou
|
||||||
|
callbacks: JSON.parse(JSON.stringify(dto)),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -45,7 +45,9 @@ export class PaymentsService {
|
|||||||
|
|
||||||
// Créer la transaction dans la base
|
// Créer la transaction dans la base
|
||||||
const payment = await this.prisma.payment.create({
|
const payment = await this.prisma.payment.create({
|
||||||
|
|
||||||
data: {
|
data: {
|
||||||
|
partnerId:"",
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
amount: chargeDto.amount,
|
amount: chargeDto.amount,
|
||||||
currency: chargeDto.currency,
|
currency: chargeDto.currency,
|
||||||
|
|||||||
@ -73,7 +73,7 @@ export class SubscriptionScheduler {
|
|||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
status: 'EXPIRED',
|
status: 'EXPIRED',
|
||||||
expiredAt: new Date(),
|
//expiredAt: new Date(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { PrismaService } from '../../../shared/services/prisma.service';
|
|||||||
import { CreatePlanDto, UpdatePlanDto } from '../dto/plan.dto';
|
import { CreatePlanDto, UpdatePlanDto } from '../dto/plan.dto';
|
||||||
import { Prisma } from 'generated/prisma';
|
import { Prisma } from 'generated/prisma';
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PlanService {
|
export class PlanService {
|
||||||
constructor(private readonly prisma: PrismaService) {}
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
@ -248,9 +247,9 @@ export class PlanService {
|
|||||||
interval: plan.interval,
|
interval: plan.interval,
|
||||||
intervalCount: plan.intervalCount,
|
intervalCount: plan.intervalCount,
|
||||||
trialDays: plan.trialDays,
|
trialDays: plan.trialDays,
|
||||||
features: plan.features,
|
//features: plan.features,
|
||||||
limits: plan.limits,
|
//limits: plan.limits,
|
||||||
metadata: { ...plan.metadata, duplicatedFrom: plan.id },
|
metadata: {metadata:plan.metadata, duplicatedFrom: plan.id },
|
||||||
active: false, // Désactivé par défaut
|
active: false, // Désactivé par défaut
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -321,14 +320,14 @@ export class PlanService {
|
|||||||
select: {
|
select: {
|
||||||
createdAt: true,
|
createdAt: true,
|
||||||
cancelledAt: true,
|
cancelledAt: true,
|
||||||
expiredAt: true,
|
suspendedAt: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (subscriptions.length === 0) return 0;
|
if (subscriptions.length === 0) return 0;
|
||||||
|
|
||||||
const lifetimes = subscriptions.map(sub => {
|
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();
|
return endDate.getTime() - sub.createdAt.getTime();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -9,9 +9,11 @@ import { BillingService } from './services/billing.service';
|
|||||||
import { PrismaService } from '../../shared/services/prisma.service';
|
import { PrismaService } from '../../shared/services/prisma.service';
|
||||||
import { PaymentsModule } from '../payments/payments.module';
|
import { PaymentsModule } from '../payments/payments.module';
|
||||||
import { NotificationsModule } from '../notifications/notifications.module';
|
import { NotificationsModule } from '../notifications/notifications.module';
|
||||||
|
import { HttpModule } from '@nestjs/axios';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
HttpModule,
|
||||||
BullModule.registerQueue({
|
BullModule.registerQueue({
|
||||||
name: 'subscriptions',
|
name: 'subscriptions',
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -86,8 +86,6 @@ export class SubscriptionsService {
|
|||||||
currentPeriodEnd,
|
currentPeriodEnd,
|
||||||
nextBillingDate,
|
nextBillingDate,
|
||||||
trialEndsAt,
|
trialEndsAt,
|
||||||
amount: plan.amount,
|
|
||||||
currency: plan.currency,
|
|
||||||
metadata: {
|
metadata: {
|
||||||
...dto.metadata,
|
...dto.metadata,
|
||||||
userAlias: user.userAlias,
|
userAlias: user.userAlias,
|
||||||
@ -234,6 +232,18 @@ export class SubscriptionsService {
|
|||||||
where: { id: partnerId },
|
where: { id: partnerId },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
interface PartnerCallbacks {
|
||||||
|
subscription?: {
|
||||||
|
onCancel?: string;
|
||||||
|
onRenew?: string;
|
||||||
|
onExpire?: string;
|
||||||
|
};
|
||||||
|
payment?: {
|
||||||
|
onSuccess?: string;
|
||||||
|
onFailure?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/*
|
||||||
if (partner?.callbacks?subscription?.onCancel) {
|
if (partner?.callbacks?subscription?.onCancel) {
|
||||||
await this.subscriptionQueue.add('webhook-notification', {
|
await this.subscriptionQueue.add('webhook-notification', {
|
||||||
url: partner.callbacks.subscription.onCancel,
|
url: partner.callbacks.subscription.onCancel,
|
||||||
@ -241,6 +251,7 @@ export class SubscriptionsService {
|
|||||||
subscription: updatedSubscription,
|
subscription: updatedSubscription,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
return updatedSubscription;
|
return updatedSubscription;
|
||||||
}
|
}
|
||||||
@ -293,29 +304,32 @@ export class SubscriptionsService {
|
|||||||
currentPeriodEnd: this.calculatePeriodEnd(subscription.plan, subscription.currentPeriodEnd),
|
currentPeriodEnd: this.calculatePeriodEnd(subscription.plan, subscription.currentPeriodEnd),
|
||||||
nextBillingDate: this.calculatePeriodEnd(subscription.plan, subscription.currentPeriodEnd),
|
nextBillingDate: this.calculatePeriodEnd(subscription.plan, subscription.currentPeriodEnd),
|
||||||
lastPaymentId: payment.id,
|
lastPaymentId: payment.id,
|
||||||
lastPaymentDate: new Date(),
|
// lastPaymentDate: new Date(),
|
||||||
renewalCount: { increment: 1 },
|
renewalCount: { increment: 1 },
|
||||||
failureCount: 0, // Reset failure count on success
|
failureCount: 0, // Reset failure count on success
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Programmer le prochain renouvellement
|
// Programmer le prochain renouvellement
|
||||||
|
/* todo
|
||||||
const delay = subscription.nextBillingDate.getTime() - Date.now();
|
const delay = subscription.nextBillingDate.getTime() - Date.now();
|
||||||
await this.billingQueue.add(
|
await this.billingQueue.add(
|
||||||
'process-renewal',
|
'process-renewal',
|
||||||
{ subscriptionId },
|
{ subscriptionId },
|
||||||
{ delay },
|
{ delay },
|
||||||
);
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
// Notifier le succès
|
// Notifier le succès
|
||||||
if (subscription.partner?.callbacks?.subscription?.onRenew) {
|
|
||||||
|
/* if (subscription.partner?.callbacks?.subscription?.onRenew) {
|
||||||
await this.subscriptionQueue.add('webhook-notification', {
|
await this.subscriptionQueue.add('webhook-notification', {
|
||||||
url: subscription.partner.callbacks.subscription.onRenew,
|
url: subscription.partner.callbacks.subscription.onRenew,
|
||||||
event: 'SUBSCRIPTION_RENEWED',
|
event: 'SUBSCRIPTION_RENEWED',
|
||||||
subscription: subscription,
|
subscription: subscription,
|
||||||
payment: payment,
|
payment: payment,
|
||||||
});
|
});
|
||||||
}
|
}*/
|
||||||
} else {
|
} else {
|
||||||
await this.handleRenewalFailure(subscription);
|
await this.handleRenewalFailure(subscription);
|
||||||
}
|
}
|
||||||
@ -342,13 +356,14 @@ export class SubscriptionsService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (payment.status === 'SUCCESS') {
|
if (payment.status === 'SUCCESS') {
|
||||||
|
//todo
|
||||||
await this.prisma.subscription.update({
|
await this.prisma.subscription.update({
|
||||||
where: { id: subscription.id },
|
where: { id: subscription.id },
|
||||||
data: {
|
data: {
|
||||||
status: 'ACTIVE',
|
status: 'ACTIVE',
|
||||||
activatedAt: new Date(),
|
createdAt: new Date(),
|
||||||
lastPaymentId: payment.id,
|
lastPaymentId: payment.id,
|
||||||
lastPaymentDate: new Date(),
|
//lastPaymentDate: new Date(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -364,7 +379,7 @@ export class SubscriptionsService {
|
|||||||
where: { id: subscription.id },
|
where: { id: subscription.id },
|
||||||
data: {
|
data: {
|
||||||
status: 'FAILED',
|
status: 'FAILED',
|
||||||
failureReason: payment.failureReason,
|
//todo failureReason: payment.failureReason,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -373,7 +388,7 @@ export class SubscriptionsService {
|
|||||||
where: { id: subscription.id },
|
where: { id: subscription.id },
|
||||||
data: {
|
data: {
|
||||||
status: 'FAILED',
|
status: 'FAILED',
|
||||||
failureReason: error.message,
|
//failureReason: error.message,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
throw error;
|
throw error;
|
||||||
@ -392,7 +407,7 @@ export class SubscriptionsService {
|
|||||||
status: 'SUSPENDED',
|
status: 'SUSPENDED',
|
||||||
failureCount,
|
failureCount,
|
||||||
suspendedAt: new Date(),
|
suspendedAt: new Date(),
|
||||||
suspensionReason: `Payment failed ${maxRetries} times`,
|
//suspensionReason: `Payment failed ${maxRetries} times`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user