Skip to content

Commit 4d7cfbb

Browse files
committed
adding support for appsumo codes
1 parent b4c0620 commit 4d7cfbb

File tree

5 files changed

+126
-2
lines changed

5 files changed

+126
-2
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { getPlanFromId } from "@data/PREMIUM";
2+
import StripeService from '~/server/services/StripeService';
3+
import { PREMIUM_PLAN } from "../../../../shared/data/PREMIUM";
4+
import { checkAppsumoCode, useAppsumoCode } from "~/server/services/AppsumoService";
5+
6+
7+
8+
function getPlanToActivate(current_plan_id: number) {
9+
if (current_plan_id === PREMIUM_PLAN.FREE.ID) {
10+
return PREMIUM_PLAN.APPSUMO_INCUBATION;
11+
}
12+
// if (current_plan_id === PREMIUM_PLAN.INCUBATION.ID) {
13+
// return PREMIUM_PLAN.APPSUMO_ACCELERATION;
14+
// }
15+
// if (current_plan_id === PREMIUM_PLAN.ACCELERATION.ID) {
16+
// return PREMIUM_PLAN.APPSUMO_GROWTH;
17+
// }
18+
if (current_plan_id === PREMIUM_PLAN.APPSUMO_INCUBATION.ID) {
19+
return PREMIUM_PLAN.APPSUMO_ACCELERATION;
20+
}
21+
if (current_plan_id === PREMIUM_PLAN.APPSUMO_ACCELERATION.ID) {
22+
return PREMIUM_PLAN.APPSUMO_GROWTH;
23+
}
24+
}
25+
26+
export default defineEventHandler(async event => {
27+
28+
const data = await getRequestData(event, { requireSchema: false, allowGuests: false, allowLitlyx: false });
29+
if (!data) return;
30+
31+
const { project, pid } = data;
32+
33+
const body = await readBody(event);
34+
35+
const { code } = body;
36+
37+
const valid = await checkAppsumoCode(code);
38+
39+
if (!valid) return setResponseStatus(event, 400, 'Current plan not found');
40+
41+
const currentPlan = getPlanFromId(project.premium_type);
42+
if (!currentPlan) return setResponseStatus(event, 400, 'Current plan not found');
43+
const planToActivate = getPlanToActivate(currentPlan.ID);
44+
if (!planToActivate) return setResponseStatus(event, 400, 'Cannot use code on current plan');
45+
46+
await StripeService.deleteSubscription(project.subscription_id);
47+
await StripeService.createSubscription(project.customer_id, planToActivate.ID);
48+
49+
await useAppsumoCode(code);
50+
51+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
3+
import { AppsumoCodeModel } from '@schema/AppsumoCode'
4+
5+
export async function checkAppsumoCode(code: string) {
6+
const target = await AppsumoCodeModel.exists({ code, used_at: { $exists: false } });
7+
return target;
8+
}
9+
10+
11+
export async function useAppsumoCode(code: string) {
12+
await AppsumoCodeModel.updateOne({ code }, { used_at: Date.now() });
13+
}

dashboard/server/services/StripeService.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,23 @@ class StripeService {
168168
return false;
169169
}
170170

171+
async createSubscription(customer_id: string, planId: number) {
172+
if (this.disabledMode) return;
173+
if (!this.stripe) throw Error('Stripe not initialized');
174+
175+
const PLAN = getPlanFromId(planId);
176+
if (!PLAN) throw Error('Plan not found');
177+
178+
const subscription = await this.stripe.subscriptions.create({
179+
customer: customer_id,
180+
items: [
181+
{ price: this.testMode ? PLAN.PRICE_TEST : PLAN.PRICE, quantity: 1 }
182+
],
183+
});
184+
185+
return subscription;
186+
}
187+
171188
async createOneTimeSubscriptionDummy(customer_id: string, planId: number) {
172189
if (this.disabledMode) return;
173190
if (!this.stripe) throw Error('Stripe not initialized');

shared/data/PREMIUM.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ export const PREMIUM_TAGS = [
1414
'SCALING',
1515
'UNICORN',
1616
'LIFETIME_GROWTH_ONETIME',
17-
'GROWTH_DUMMY'
17+
'GROWTH_DUMMY',
18+
'APPSUMO_INCUBATION',
19+
'APPSUMO_ACCELERATION',
20+
'APPSUMO_GROWTH',
1821
] as const;
1922

2023

@@ -123,7 +126,31 @@ export const PREMIUM_PLAN: Record<PREMIUM_TAG, PREMIUM_DATA> = {
123126
PRICE: 'price_1PvgoRB2lPUiVs9VC51YBT7J',
124127
PRICE_TEST: 'price_1PvgRTB2lPUiVs9V3kFSNC3G',
125128
COST: 0
126-
}
129+
},
130+
APPSUMO_INCUBATION: {
131+
ID: 6001,
132+
COUNT_LIMIT: 50_000,
133+
AI_MESSAGE_LIMIT: 30,
134+
PRICE: '',
135+
PRICE_TEST: '',
136+
COST: 0
137+
},
138+
APPSUMO_ACCELERATION: {
139+
ID: 6002,
140+
COUNT_LIMIT: 150_000,
141+
AI_MESSAGE_LIMIT: 100,
142+
PRICE: '',
143+
PRICE_TEST: '',
144+
COST: 0
145+
},
146+
APPSUMO_GROWTH: {
147+
ID: 6003,
148+
COUNT_LIMIT: 500_000,
149+
AI_MESSAGE_LIMIT: 3_000,
150+
PRICE: '',
151+
PRICE_TEST: '',
152+
COST: 0
153+
},
127154
}
128155

129156
try {

shared/schema/AppsumoCode.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { model, Schema, Types } from 'mongoose';
2+
3+
export type TAppsumoCode = {
4+
_id: Schema.Types.ObjectId,
5+
code: string,
6+
used_at: Date,
7+
created_at?: Date,
8+
}
9+
10+
const AppsumoCodeSchema = new Schema<TAppsumoCode>({
11+
code: { type: String, index: 1 },
12+
created_at: { type: Date, default: () => Date.now() },
13+
used_at: { type: Date, required: false },
14+
});
15+
16+
export const AppsumoCodeModel = model<TAppsumoCode>('appsumo_codes', AppsumoCodeSchema);

0 commit comments

Comments
 (0)