mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-19 19:16:29 +08:00
refactor(server): saving past_due subscription in db (#10908)
close CLOUD-122
This commit is contained in:
@@ -107,7 +107,7 @@ export class UserFeatureModel extends BaseModel {
|
||||
}
|
||||
|
||||
async remove(userId: string, featureName: UserFeatureName) {
|
||||
await this.db.userFeature.updateMany({
|
||||
const { count } = await this.db.userFeature.updateMany({
|
||||
where: {
|
||||
userId,
|
||||
name: featureName,
|
||||
@@ -117,9 +117,11 @@ export class UserFeatureModel extends BaseModel {
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.verbose(
|
||||
`Feature ${featureName} deactivated for user ${userId}`
|
||||
);
|
||||
if (count > 0) {
|
||||
this.logger.verbose(
|
||||
`Feature ${featureName} deactivated for user ${userId}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional()
|
||||
|
||||
@@ -194,15 +194,17 @@ export class WorkspaceFeatureModel extends BaseModel {
|
||||
}
|
||||
|
||||
async remove(workspaceId: string, featureName: WorkspaceFeatureName) {
|
||||
await this.db.workspaceFeature.deleteMany({
|
||||
const { count } = await this.db.workspaceFeature.deleteMany({
|
||||
where: {
|
||||
workspaceId,
|
||||
name: featureName,
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.verbose(
|
||||
`Feature ${featureName} removed from workspace ${workspaceId}`
|
||||
);
|
||||
if (count > 0) {
|
||||
this.logger.verbose(
|
||||
`Feature ${featureName} removed from workspace ${workspaceId}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,14 +213,22 @@ export class UserSubscriptionManager extends SubscriptionManager {
|
||||
|
||||
// update features first, features modify are idempotent
|
||||
// so there is no need to skip if a subscription already exists.
|
||||
// TODO(@forehalo):
|
||||
// we should move the subscription feature updating logic back to payment module,
|
||||
// because quota or feature module themself should not be aware of what payment or subscription is.
|
||||
this.event.emit('user.subscription.activated', {
|
||||
userId,
|
||||
plan: lookupKey.plan,
|
||||
recurring: lookupKey.recurring,
|
||||
});
|
||||
if (
|
||||
stripeSubscription.status === SubscriptionStatus.Active ||
|
||||
stripeSubscription.status === SubscriptionStatus.Trialing
|
||||
) {
|
||||
this.event.emit('user.subscription.activated', {
|
||||
userId,
|
||||
plan: lookupKey.plan,
|
||||
recurring: lookupKey.recurring,
|
||||
});
|
||||
} else {
|
||||
this.event.emit('user.subscription.canceled', {
|
||||
userId,
|
||||
plan: lookupKey.plan,
|
||||
recurring: lookupKey.recurring,
|
||||
});
|
||||
}
|
||||
|
||||
const subscriptionData = this.transformSubscription(subscription);
|
||||
|
||||
@@ -247,20 +255,17 @@ export class UserSubscriptionManager extends SubscriptionManager {
|
||||
stripeSubscription,
|
||||
}: KnownStripeSubscription) {
|
||||
this.assertUserIdExists(userId);
|
||||
this.event.emit('user.subscription.canceled', {
|
||||
userId,
|
||||
plan: lookupKey.plan,
|
||||
recurring: lookupKey.recurring,
|
||||
});
|
||||
|
||||
const deleted = await this.db.subscription.deleteMany({
|
||||
await this.db.subscription.deleteMany({
|
||||
where: {
|
||||
stripeSubscriptionId: stripeSubscription.id,
|
||||
},
|
||||
});
|
||||
|
||||
if (deleted.count > 0) {
|
||||
this.event.emit('user.subscription.canceled', {
|
||||
userId,
|
||||
plan: lookupKey.plan,
|
||||
recurring: lookupKey.recurring,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async cancelSubscription(subscription: Subscription) {
|
||||
|
||||
@@ -137,12 +137,23 @@ export class WorkspaceSubscriptionManager extends SubscriptionManager {
|
||||
|
||||
const subscriptionData = this.transformSubscription(subscription);
|
||||
|
||||
this.event.emit('workspace.subscription.activated', {
|
||||
workspaceId,
|
||||
plan: lookupKey.plan,
|
||||
recurring: lookupKey.recurring,
|
||||
quantity: subscriptionData.quantity,
|
||||
});
|
||||
if (
|
||||
stripeSubscription.status === SubscriptionStatus.Active ||
|
||||
stripeSubscription.status === SubscriptionStatus.Trialing
|
||||
) {
|
||||
this.event.emit('workspace.subscription.activated', {
|
||||
workspaceId,
|
||||
plan: lookupKey.plan,
|
||||
recurring: lookupKey.recurring,
|
||||
quantity: subscriptionData.quantity,
|
||||
});
|
||||
} else {
|
||||
this.event.emit('workspace.subscription.canceled', {
|
||||
workspaceId,
|
||||
plan: lookupKey.plan,
|
||||
recurring: lookupKey.recurring,
|
||||
});
|
||||
}
|
||||
|
||||
return this.db.subscription.upsert({
|
||||
where: {
|
||||
@@ -176,17 +187,15 @@ export class WorkspaceSubscriptionManager extends SubscriptionManager {
|
||||
);
|
||||
}
|
||||
|
||||
const deleted = await this.db.subscription.deleteMany({
|
||||
where: { stripeSubscriptionId: stripeSubscription.id },
|
||||
this.event.emit('workspace.subscription.canceled', {
|
||||
workspaceId,
|
||||
plan: lookupKey.plan,
|
||||
recurring: lookupKey.recurring,
|
||||
});
|
||||
|
||||
if (deleted.count > 0) {
|
||||
this.event.emit('workspace.subscription.canceled', {
|
||||
workspaceId,
|
||||
plan: lookupKey.plan,
|
||||
recurring: lookupKey.recurring,
|
||||
});
|
||||
}
|
||||
await this.db.subscription.deleteMany({
|
||||
where: { stripeSubscriptionId: stripeSubscription.id },
|
||||
});
|
||||
}
|
||||
|
||||
getSubscription(identity: z.infer<typeof WorkspaceSubscriptionIdentity>) {
|
||||
|
||||
@@ -467,13 +467,17 @@ export class SubscriptionService implements OnApplicationBootstrap {
|
||||
throw new InternalServerError('Failed to parse stripe subscription.');
|
||||
}
|
||||
|
||||
const isPlanActive =
|
||||
const shouldSave =
|
||||
subscription.status === SubscriptionStatus.Active ||
|
||||
subscription.status === SubscriptionStatus.Trialing;
|
||||
subscription.status === SubscriptionStatus.Trialing ||
|
||||
// PastDue is a temporary status, it will be cancelled after all recurring payments retries failed.
|
||||
// Saved in db to let users be able to cancel further retries manually.
|
||||
subscription.status === SubscriptionStatus.PastDue;
|
||||
|
||||
const manager = this.select(knownSubscription.lookupKey.plan);
|
||||
|
||||
if (!isPlanActive) {
|
||||
// TODO(@forehalo): trigger 'subscription.status.changed' event to let strategy handle them. after migrated to Model
|
||||
if (!shouldSave) {
|
||||
await manager.deleteStripeSubscription(knownSubscription);
|
||||
} else {
|
||||
await manager.saveStripeSubscription(knownSubscription);
|
||||
|
||||
Reference in New Issue
Block a user