add price and meter dynamically add foreign keys in billing (#9100)

**TLDR**
Solves: https://github.com/twentyhq/private-issues/issues/199
Partially solves: https://github.com/twentyhq/private-issues/issues/221
(more details below)

Updates the BillingMeter and BillingPrice tables while listening to the
events "price.created" and "price.updated" from the stripe webhook. Also
added the foreign keys, that couldn't be added to the BillingEntities.

**In Order To test**
Billing:

- Set IS_BILLING_ENABLED to true
- Add your BILLING_STRIPE_SECRET and BILLING_STRIPE_API_KEY
- Add your BILLING_STRIPE_BASE_PLAN_PRODUCT_ID (use the one in testMode
> Base Plan)

Authenticate with your account in the stripe CLI
Run the command: stripe listen --forward-to
http://localhost:3000/billing/webhooks

Run the twenty workker

Authenticate yourself on the app choose a plan and run the app normally.
In stripe and in posgress the customer table data should be added.

**Take Into Consideration**

In a previous migration the foreign key to workpaceId was taken down
this was due to the separation of the migrations if billing is enabled.
Because we want to separate in these two categories: we will be
polluting the Common Migrations with relations to tables that don't
exists. This will be addressed in a PR in the next sprint (perhaps a
decorator?)


**Doing**
Testing migrations, when we are in main and when billing is enabled.
This commit is contained in:
Ana Sofia Marin Alexandre
2024-12-17 15:54:56 -03:00
committed by GitHub
parent e492efb79e
commit 55dc5983a2
18 changed files with 348 additions and 30 deletions

View File

@ -0,0 +1,67 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddConstraintsOnBillingTables1734450749954
implements MigrationInterface
{
name = 'AddConstraintsOnBillingTables1734450749954';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."billingSubscriptionItem" DROP CONSTRAINT "IndexOnBillingSubscriptionIdAndStripeSubscriptionItemIdUnique"`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingCustomer" DROP CONSTRAINT "IndexOnWorkspaceIdAndStripeCustomerIdUnique"`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingSubscriptionItem" ADD CONSTRAINT "UQ_6a989264cab5ee2d4b424e78526" UNIQUE ("stripeSubscriptionItemId")`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingSubscriptionItem" DROP COLUMN "quantity"`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingSubscriptionItem" ADD "quantity" numeric`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingCustomer" ADD CONSTRAINT "UQ_53c2ef50e9611082f83d760897d" UNIQUE ("workspaceId")`,
);
await queryRunner.query(
`CREATE UNIQUE INDEX "IndexOnActiveSubscriptionPerWorkspace" ON "core"."billingSubscription" ("workspaceId") WHERE status IN ('trialing', 'active', 'past_due')`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingEntitlement" ADD CONSTRAINT "FK_766a1918aa3dbe0d67d3df62356" FOREIGN KEY ("stripeCustomerId") REFERENCES "core"."billingCustomer"("stripeCustomerId") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingSubscription" ADD CONSTRAINT "FK_9120b7586c3471463480b58d20a" FOREIGN KEY ("stripeCustomerId") REFERENCES "core"."billingCustomer"("stripeCustomerId") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."billingSubscription" DROP CONSTRAINT "FK_9120b7586c3471463480b58d20a"`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingEntitlement" DROP CONSTRAINT "FK_766a1918aa3dbe0d67d3df62356"`,
);
await queryRunner.query(
`DROP INDEX "core"."IndexOnActiveSubscriptionPerWorkspace"`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingCustomer" DROP CONSTRAINT "UQ_53c2ef50e9611082f83d760897d"`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingSubscriptionItem" DROP COLUMN "quantity"`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingSubscriptionItem" ADD "quantity" integer NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingSubscriptionItem" DROP CONSTRAINT "UQ_6a989264cab5ee2d4b424e78526"`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingCustomer" ADD CONSTRAINT "IndexOnWorkspaceIdAndStripeCustomerIdUnique" UNIQUE ("workspaceId", "stripeCustomerId")`,
);
await queryRunner.query(
`ALTER TABLE "core"."billingSubscriptionItem" ADD CONSTRAINT "IndexOnBillingSubscriptionIdAndStripeSubscriptionItemIdUnique" UNIQUE ("billingSubscriptionId", "stripeSubscriptionItemId")`,
);
}
}