diff --git a/src/common/databases/migrations/20240417122422_rules_groups/migration.sql b/src/common/databases/migrations/20240417122422_rules_groups/migration.sql new file mode 100644 index 00000000..77df62a3 --- /dev/null +++ b/src/common/databases/migrations/20240417122422_rules_groups/migration.sql @@ -0,0 +1,30 @@ +-- CreateTable +CREATE TABLE "rules_groups" ( + "uid" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3), + + CONSTRAINT "rules_groups_pkey" PRIMARY KEY ("uid") +); + +-- CreateTable +CREATE TABLE "_RulesGroupsHasRules" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "rules_groups_uid_key" ON "rules_groups"("uid"); + +-- CreateIndex +CREATE UNIQUE INDEX "_RulesGroupsHasRules_AB_unique" ON "_RulesGroupsHasRules"("A", "B"); + +-- CreateIndex +CREATE INDEX "_RulesGroupsHasRules_B_index" ON "_RulesGroupsHasRules"("B"); + +-- AddForeignKey +ALTER TABLE "_RulesGroupsHasRules" ADD CONSTRAINT "_RulesGroupsHasRules_A_fkey" FOREIGN KEY ("A") REFERENCES "rules"("uid") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_RulesGroupsHasRules" ADD CONSTRAINT "_RulesGroupsHasRules_B_fkey" FOREIGN KEY ("B") REFERENCES "rules_groups"("uid") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/src/common/databases/schema.prisma b/src/common/databases/schema.prisma index 9f21c34d..3d813215 100644 --- a/src/common/databases/schema.prisma +++ b/src/common/databases/schema.prisma @@ -323,9 +323,19 @@ model Rules { role Roles[] @relation("RolesHasRules") office_roles OfficeRoles[] @relation("OfficeRolesHasRules") namespace String @db.VarChar(255) @default("notary") + groups RulesGroups[] @relation("RulesGroupsHasRules") @@map("rules") } +model RulesGroups { + uid String @id @unique @default(uuid()) + name String @db.VarChar(255) + created_at DateTime? @default(now()) + updated_at DateTime? @updatedAt + rules Rules[] @relation("RulesGroupsHasRules") + @@map("rules_groups") +} + model Emails { uid String @id @unique @default(uuid()) templateName String @db.VarChar(255) diff --git a/src/common/webhooks/stripeWebhooks.ts b/src/common/webhooks/stripeWebhooks.ts index 85fc45f7..5885b85c 100644 --- a/src/common/webhooks/stripeWebhooks.ts +++ b/src/common/webhooks/stripeWebhooks.ts @@ -24,10 +24,14 @@ export default class StripeWebhooks extends ApiController { const event = req.body; switch (event.type) { - case "invoice.payment_succeeded": - if (event.data.object.billing_reason !== "subscription_update") break; + //Manage plan switch + recurring payment + case "invoice.payment_succeeded": + if (event.data.object.billing_reason !== "subscription_update" && event.data.object.billing_reason !== "subscription_cycle") break; const stripeSubscription = await this.stripeService.getClient().subscriptions.retrieve(event.data.object.subscription); + if(stripeSubscription.metadata['env'] !== this.backendVariables.ENV) break; + const existingSubscription = await this.subscriptionsService.get({where : {stripe_subscription_id : stripeSubscription.id}}); + if(!existingSubscription[0]) break; const subscriptionUpdate: any = {}; @@ -42,19 +46,30 @@ export default class StripeWebhooks extends ApiController { subscriptionUpdate.type = "UNLIMITED"; } - const subscriptionEntityUpdate = Subscription.hydrate(subscriptionUpdate); + const subscriptionEntityUpdate = Subscription.hydrate(subscriptionUpdate); - await validateOrReject(subscriptionEntityUpdate, { groups: ["updateSubscription"], forbidUnknownValues: false }); + await validateOrReject(subscriptionEntityUpdate, { groups: ["updateSubscription"], forbidUnknownValues: false }); await this.subscriptionsService.update(existingSubscription[0].uid ,subscriptionEntityUpdate); - + + //Manage subscription creation and first payment case "checkout.session.completed": if (event.data.object.status !== "complete") break; const subscription = JSON.parse(event.data.object.metadata.subscription); + const env = event.data.object.metadata.env; + + if (env !== this.backendVariables.ENV) break; subscription.stripe_subscription_id = event.data.object.subscription; + await this.stripeService.getClient().subscriptions.update(subscription.stripe_subscription_id, { + metadata: { + env: env, + }, + } + ) + const subscriptionInfo = await this.stripeService .getClient() .subscriptions.retrieve(subscription.stripe_subscription_id); @@ -65,10 +80,14 @@ export default class StripeWebhooks extends ApiController { const subscriptionEntity = Subscription.hydrate(subscription); await validateOrReject(subscriptionEntity, { groups: ["createSubscription"], forbidUnknownValues: false }); + await this.subscriptionsService.create(subscriptionEntity); break; + //Manage plan expiration case "customer.subscription.deleted": + const currentSubscription = await this.stripeService.getClient().subscriptions.retrieve(event.data.object.id); + if(currentSubscription.metadata['env'] !== this.backendVariables.ENV) break; const subscriptionToDelete = await this.subscriptionsService.get({where : {stripe_subscription_id : event.data.object.id}}); if(!subscriptionToDelete[0]) break; await this.subscriptionsService.delete(subscriptionToDelete[0].uid); diff --git a/src/services/common/StripeService/StripeService.ts b/src/services/common/StripeService/StripeService.ts index e8e1ee8e..8087b5a5 100644 --- a/src/services/common/StripeService/StripeService.ts +++ b/src/services/common/StripeService/StripeService.ts @@ -30,6 +30,7 @@ export default class StripeService { cancel_url: this.variables.APP_HOST + "/subscription/error", metadata: { subscription: JSON.stringify(subscription), + env: this.variables.ENV, }, });