(core) Billing for formula assistant

Summary:
Adding limits for AI calls and connecting those limits with a Stripe Account.

- New table in homedb called `limits`
- All calls to the AI are not routed through DocApi and measured.
- All products now contain a special key `assistantLimit`, with a default value 0
- Limit is reset every time the subscription has changed its period
- The billing page is updated with two new options that describe the AI plan
- There is a new popup that allows the user to upgrade to a higher plan
- Tiers are read directly from the Stripe product with a volume pricing model

Test Plan: Updated and added

Reviewers: georgegevoian, paulfitz

Reviewed By: georgegevoian

Subscribers: dsagal

Differential Revision: https://phab.getgrist.com/D3907
This commit is contained in:
Jarosław Sadziński
2023-07-05 17:36:45 +02:00
parent 75d979abdb
commit d13b9b9019
26 changed files with 501 additions and 106 deletions

View File

@@ -0,0 +1,82 @@
import * as sqlUtils from "app/gen-server/sqlUtils";
import {MigrationInterface, QueryRunner, Table, TableIndex} from 'typeorm';
export class AssistantLimit1685343047786 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
const dbType = queryRunner.connection.driver.options.type;
const datetime = sqlUtils.datetime(dbType);
const now = sqlUtils.now(dbType);
await queryRunner.createTable(
new Table({
name: 'limits',
columns: [
{
name: 'id',
type: 'integer',
isPrimary: true,
isGenerated: true,
generationStrategy: 'increment',
},
{
name: 'type',
type: 'varchar',
},
{
name: 'billing_account_id',
type: 'integer',
},
{
name: 'limit',
type: 'integer',
default: 0,
},
{
name: 'usage',
type: 'integer',
default: 0,
},
{
name: "created_at",
type: datetime,
default: now
},
{
name: "changed_at", // When the limit was last changed
type: datetime,
isNullable: true
},
{
name: "used_at", // When the usage was last increased
type: datetime,
isNullable: true
},
{
name: "reset_at", // When the usage was last reset.
type: datetime,
isNullable: true
},
],
foreignKeys: [
{
columnNames: ['billing_account_id'],
referencedTableName: 'billing_accounts',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
},
],
})
);
await queryRunner.createIndex(
'limits',
new TableIndex({
name: 'limits_billing_account_id',
columnNames: ['billing_account_id'],
})
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('limits');
}
}