Skip to content

Commit d782e2b

Browse files
committed
refactor(billing): rename and restructure promo code application logic to improve clarity and remove deprecated methods
1 parent 7945cdb commit d782e2b

8 files changed

Lines changed: 286 additions & 555 deletions

File tree

src/models/promoCodeUsagesFactory.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,17 +84,4 @@ export default class PromoCodeUsagesFactory extends AbstractModelFactory<PromoCo
8484

8585
return new PromoCodeUsageModel(usage);
8686
}
87-
88-
/**
89-
* Deletes usage by id.
90-
*
91-
* Used only as compensation when promo benefit application fails after usage reservation.
92-
*
93-
* @param usageId - promo usage id
94-
*/
95-
public async deleteById(usageId: ObjectId): Promise<void> {
96-
await this.collection.deleteOne({
97-
_id: usageId,
98-
});
99-
}
10087
}

src/resolvers/billingNew.ts

Lines changed: 8 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ import { UserInputError } from 'apollo-server-express';
1414
import cloudPaymentsApi, { CloudPaymentsJsonData } from '../utils/cloudPaymentsApi';
1515
import * as telegram from '../utils/telegram';
1616
import { TelegramBotURLs } from '../utils/telegram';
17-
import PromoCodeService, { PromoCodeError, PromoCodeErrorCode, PromoCodePreviewResult, buildPaymentPromoData } from '../services/promoCodeService';
18-
import { publish } from '../rabbitmq';
17+
import PromoCodeService, { PromoCodeApplyResult, PromoCodeError, PromoCodeErrorCode, buildPaymentPromoData } from '../services/promoCodeService';
1918
import type { PaymentPromoData } from '../billing/types/paymentData';
2019
import { sanitizeUtmParams } from '../utils/utm/utm';
2120

@@ -39,13 +38,12 @@ interface ComposePaymentArgs {
3938
}
4039

4140
/**
42-
* Input data for promo code preview/apply mutation.
41+
* Input data for promo code apply mutation.
4342
*/
44-
interface PreviewPromoCodeArgs {
43+
interface ApplyPromoCodeArgs {
4544
input: {
4645
workspaceId: string;
4746
value: string;
48-
utm?: Utm;
4947
};
5048
}
5149

@@ -62,63 +60,6 @@ function throwPromoCodeGraphQLError(error: unknown): never {
6260
throw new UserInputError(PromoCodeErrorCode.ApplyFailed);
6361
}
6462

65-
/**
66-
* Sends task to limiter worker to unblock workspace after plan became valid again.
67-
* Same mechanism is used after successful payment or manual plan change.
68-
*
69-
* @param workspaceId - workspace id to unblock
70-
*/
71-
async function notifyLimiterToUnblockWorkspace(workspaceId: string): Promise<void> {
72-
await publish('cron-tasks', 'cron-tasks/limiter', JSON.stringify({
73-
type: 'unblock-workspace',
74-
workspaceId,
75-
}));
76-
}
77-
78-
/**
79-
* Validates promo code and either returns discount preview or applies grant_plan promo.
80-
*
81-
* Discount promos: returns recalculated plan prices with applied: false, no side effects.
82-
* Grant plan promo: applies plan immediately, stores usage, then unblocks workspace in limiter.
83-
* Unblock is not caused by preview itself — it runs only after grant_plan apply,
84-
* because workspace received a valid plan the same way as after paid plan change.
85-
*
86-
* @param promoCodeService - promo code service instance
87-
* @param input - promo code mutation input
88-
* @param userId - current user id
89-
* @param workspace - workspace model
90-
* @returns promo preview or apply result
91-
*/
92-
async function previewOrApplyPromoCode(
93-
promoCodeService: PromoCodeService,
94-
input: PreviewPromoCodeArgs['input'],
95-
userId: string,
96-
workspace: WorkspaceModel
97-
): Promise<PromoCodePreviewResult & { applied: boolean }> {
98-
const promoPreview = await promoCodeService.preview(input.value, userId, input.workspaceId);
99-
100-
if (promoPreview.benefitType !== 'grant_plan') {
101-
return {
102-
...promoPreview,
103-
applied: false,
104-
};
105-
}
106-
107-
await promoCodeService.applyGrantPlan(
108-
input.value,
109-
userId,
110-
workspace,
111-
sanitizeUtmParams(input.utm)
112-
);
113-
114-
await notifyLimiterToUnblockWorkspace(workspace._id.toString());
115-
116-
return {
117-
...promoPreview,
118-
applied: true,
119-
};
120-
}
121-
12263
/**
12364
* Data for processing payment with saved card
12465
*/
@@ -377,12 +318,7 @@ debug: ${Boolean(workspace.isDebug)}`
377318

378319
Mutation: {
379320
/**
380-
* Validates promo code for workspace and returns calculated prices.
381-
*
382-
* Preview here means a dry-run for discount promos: server recalculates prices
383-
* for all visible plans and returns them without creating promo usage.
384-
* For grant_plan promo preview becomes apply: workspace plan is changed immediately,
385-
* usage is stored, and response contains applied: true.
321+
* Validates promo code for workspace and returns benefit data for client-side pricing.
386322
*
387323
* Access check is handled by @requireAdmin on GraphQL schema.
388324
*
@@ -391,11 +327,11 @@ debug: ${Boolean(workspace.isDebug)}`
391327
* @param user - current authorized user
392328
* @param factories - factories for working with models
393329
*/
394-
async previewPromoCode(
330+
async applyPromoCode(
395331
_obj: undefined,
396-
{ input }: PreviewPromoCodeArgs,
332+
{ input }: ApplyPromoCodeArgs,
397333
{ user, factories }: ResolverContextWithUser
398-
): Promise<PromoCodePreviewResult & { applied: boolean }> {
334+
): Promise<PromoCodeApplyResult> {
399335
const workspace = await factories.workspacesFactory.findById(input.workspaceId);
400336

401337
if (!workspace) {
@@ -405,7 +341,7 @@ debug: ${Boolean(workspace.isDebug)}`
405341
const promoCodeService = new PromoCodeService(factories);
406342

407343
try {
408-
return await previewOrApplyPromoCode(promoCodeService, input, user.id, workspace);
344+
return await promoCodeService.applyPromoCode(input.value, user.id, input.workspaceId);
409345
} catch (error) {
410346
throwPromoCodeGraphQLError(error);
411347
}

0 commit comments

Comments
 (0)