mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
60423edc17
Summary: - Reading plans from Stripe, and allowing Stripe to define custom plans. - Storing product features (aka limits) in Stripe, that override those in db. - Adding hierarchical data in Stripe. All features are defined at Product level but can be overwritten on Price levels. - New options for Support user to -- Override product for team site (if he is added as a billing manager) -- Override subscription and customer id for a team site -- Attach an "offer", an custom plan configured in stripe that a team site can use -- Enabling wire transfer for subscription by allowing subscription to be created without a payment method (which is customizable) Test Plan: Updated and new. Reviewers: georgegevoian Reviewed By: georgegevoian Differential Revision: https://phab.getgrist.com/D4201
95 lines
3.6 KiB
TypeScript
95 lines
3.6 KiB
TypeScript
import {BaseEntity, Column, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn} from 'typeorm';
|
|
import {BillingAccountManager} from 'app/gen-server/entity/BillingAccountManager';
|
|
import {Organization} from 'app/gen-server/entity/Organization';
|
|
import {Product} from 'app/gen-server/entity/Product';
|
|
import {nativeValues} from 'app/gen-server/lib/values';
|
|
import {Limit} from 'app/gen-server/entity/Limit';
|
|
import {Features, mergedFeatures} from 'app/common/Features';
|
|
|
|
// This type is for billing account status information. Intended for stuff
|
|
// like "free trial running out in N days".
|
|
export interface BillingAccountStatus {
|
|
stripeStatus?: string;
|
|
currentPeriodEnd?: string;
|
|
message?: string;
|
|
}
|
|
|
|
// A structure for billing options relevant to an external authority, for sites
|
|
// created outside of Grist's regular billing flow.
|
|
export interface ExternalBillingOptions {
|
|
authority: string; // The name of the external authority.
|
|
invoiceId?: string; // An id of an invoice or other external billing context.
|
|
}
|
|
|
|
/**
|
|
* This relates organizations to products. It holds any stripe information
|
|
* needed to be able to update and pay for the product that applies to the
|
|
* organization. It has a list of managers detailing which users have the
|
|
* right to view and edit these settings.
|
|
*/
|
|
@Entity({name: 'billing_accounts'})
|
|
export class BillingAccount extends BaseEntity {
|
|
@PrimaryGeneratedColumn()
|
|
public id: number;
|
|
|
|
@ManyToOne(type => Product)
|
|
@JoinColumn({name: 'product_id'})
|
|
public product: Product;
|
|
|
|
@Column({type: nativeValues.jsonEntityType, nullable: true})
|
|
public features: Features|null;
|
|
|
|
@Column({type: Boolean})
|
|
public individual: boolean;
|
|
|
|
// A flag for when all is well with the user's subscription.
|
|
// Probably shouldn't use this to drive whether service is provided or not.
|
|
// Strip recommends updating an end-of-service datetime every time payment
|
|
// is received, adding on a grace period of some days.
|
|
@Column({name: 'in_good_standing', type: Boolean, default: nativeValues.trueValue})
|
|
public inGoodStanding: boolean;
|
|
|
|
@Column({type: nativeValues.jsonEntityType, nullable: true})
|
|
public status: BillingAccountStatus;
|
|
|
|
@Column({name: 'stripe_customer_id', type: String, nullable: true})
|
|
public stripeCustomerId: string | null;
|
|
|
|
@Column({name: 'stripe_subscription_id', type: String, nullable: true})
|
|
public stripeSubscriptionId: string | null;
|
|
|
|
@Column({name: 'stripe_plan_id', type: String, nullable: true})
|
|
public stripePlanId: string | null;
|
|
|
|
@Column({name: 'payment_link', type: String, nullable: true})
|
|
public paymentLink: string | null;
|
|
|
|
@Column({name: 'external_id', type: String, nullable: true})
|
|
public externalId: string | null;
|
|
|
|
@Column({name: 'external_options', type: nativeValues.jsonEntityType, nullable: true})
|
|
public externalOptions: ExternalBillingOptions | null;
|
|
|
|
@OneToMany(type => BillingAccountManager, manager => manager.billingAccount)
|
|
public managers: BillingAccountManager[];
|
|
|
|
// Only one billing account per organization.
|
|
@OneToMany(type => Organization, org => org.billingAccount)
|
|
public orgs: Organization[];
|
|
|
|
@OneToMany(type => Limit, limit => limit.billingAccount)
|
|
public limits: Limit[];
|
|
|
|
// A calculated column that is true if it looks like there is a paid plan.
|
|
@Column({name: 'paid', type: 'boolean', insert: false, select: false})
|
|
public paid?: boolean;
|
|
|
|
// A calculated column summarizing whether active user is a manager of the billing account.
|
|
// (No @Column needed since calculation is done in javascript not sql)
|
|
public isManager?: boolean;
|
|
|
|
public getFeatures(): Features {
|
|
return mergedFeatures(this.features, this.product.features) ?? {};
|
|
}
|
|
}
|