Skip to content

Commit db86b6b

Browse files
committed
Add isCardLinkOperation
1 parent 4a7d7a6 commit db86b6b

4 files changed

Lines changed: 96 additions & 13 deletions

File tree

src/billing/cloudpayments.ts

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,13 @@ import { PaymentData } from './types/paymentData';
4343
import cloudPaymentsApi from '../utils/cloudPaymentsApi';
4444
import PlanModel from '../models/plan';
4545
import { ClientApi, ClientService, CustomerReceiptItem, ReceiptApi, ReceiptTypes, TaxationSystem } from 'cloudpayments';
46+
import { ComposePaymentPayload } from './types/composePaymentPayload';
4647

47-
/**
48-
* Custom data of the plan prolongation request
49-
*/
50-
type PlanProlongationData = PlanProlongationPayload & PaymentData;
48+
49+
interface ComposePaymentRequest extends express.Request {
50+
query: ComposePaymentPayload & { [key: string]: any };
51+
context: import('../types/graphql').ResolverContextBase
52+
};
5153

5254
/**
5355
* Class for describing the logic of payment routes
@@ -99,8 +101,8 @@ export default class CloudPaymentsWebhooks {
99101
* @param req — Express request object
100102
* @param res - Express response object
101103
*/
102-
private async composePayment(req: express.Request, res: express.Response): Promise<void> {
103-
const { workspaceId, tariffPlanId, shouldSaveCard } = req.query as Record<string, string>;
104+
private async composePayment(req: ComposePaymentRequest, res: express.Response): Promise<void> {
105+
const { workspaceId, tariffPlanId, shouldSaveCard, isCardLinkOperation } = req.query;
104106
const userId = req.context.user.id;
105107

106108
if (!workspaceId || !tariffPlanId || !userId) {
@@ -142,6 +144,7 @@ export default class CloudPaymentsWebhooks {
142144
userId: userId,
143145
tariffPlanId: tariffPlan._id.toString(),
144146
shouldSaveCard: shouldSaveCard === 'true',
147+
isCardLinkOperation: isCardLinkOperation === 'true',
145148
});
146149
} catch (e) {
147150
const error = e as Error;
@@ -201,7 +204,7 @@ export default class CloudPaymentsWebhooks {
201204
let member: ConfirmedMemberDBScheme;
202205
let plan: PlanDBScheme;
203206

204-
if (!data.workspaceId || !data.tariffPlanId || !data.userId) {
207+
if (!data.workspaceId || !data.tariffPlanId || !data.userId || data.isCardLinkOperation === undefined) {
205208
this.sendError(res, CheckCodes.PAYMENT_COULD_NOT_BE_ACCEPTED, '[Billing / Check] There is no necessary data in the request', body);
206209

207210
return;
@@ -235,6 +238,18 @@ export default class CloudPaymentsWebhooks {
235238
return;
236239
}
237240

241+
if (data.isCardLinkOperation) {
242+
telegram
243+
.sendMessage(`✅ [Billing / Check] Card linked for subscription workspace «${workspace.name}»`, TelegramBotURLs.Money)
244+
.catch(e => console.error('Error while sending message to Telegram: ' + e));
245+
246+
res.json({
247+
code: CheckCodes.SUCCESS,
248+
} as CheckResponse);
249+
250+
return;
251+
}
252+
238253
/**
239254
* Create business operation about creation of subscription
240255
*/
@@ -266,6 +281,7 @@ export default class CloudPaymentsWebhooks {
266281

267282
telegram.sendMessage(`✅ [Billing / Check] All checks passed successfully «${workspace.name}»`, TelegramBotURLs.Money)
268283
.catch(e => console.error('Error while sending message to Telegram: ' + e));
284+
269285
HawkCatcher.send(new Error('[Billing / Check] All checks passed successfully'), body as any);
270286

271287
res.json({
@@ -720,9 +736,9 @@ export default class CloudPaymentsWebhooks {
720736
*
721737
* @param req - request with necessary data
722738
*/
723-
private async getDataFromRequest(req: express.Request): Promise<PlanProlongationData> {
739+
private async getDataFromRequest(req: express.Request): Promise<PaymentData> {
724740
const context = req.context;
725-
const body: CheckRequest = req.body;
741+
const body: CheckRequest | PayRequest | FailRequest = req.body;
726742

727743
/**
728744
* If Data is not presented in body means there is a recurring payment
@@ -752,6 +768,7 @@ export default class CloudPaymentsWebhooks {
752768
tariffPlanId: workspace.tariffPlanId.toString(),
753769
userId,
754770
shouldSaveCard: false,
771+
isCardLinkOperation: false
755772
};
756773
}
757774

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export interface ComposePaymentPayload {
2+
/**
3+
* Workspace Identifier
4+
*/
5+
workspaceId: string;
6+
/**
7+
* Id of the user making the payment
8+
*/
9+
userId: string;
10+
/**
11+
* Workspace current plan id or plan id to change
12+
*/
13+
tariffPlanId: string;
14+
/**
15+
* If true, we will save user card
16+
*/
17+
shouldSaveCard: 'true' | 'false';
18+
/**
19+
* True if this is card linking operation – charging minimal amount of money to validate card info
20+
*/
21+
isCardLinkOperation: 'true' | 'false';
22+
}

src/billing/types/paymentData.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,24 @@ export interface PaymentData {
4040
* Data for Cloudpayments needs
4141
*/
4242
cloudPayments?: CloudPaymentsSettings;
43+
/**
44+
* Workspace Identifier
45+
*/
46+
workspaceId: string;
47+
/**
48+
* Id of the user making the payment
49+
*/
50+
userId: string;
51+
/**
52+
* Workspace current plan id or plan id to change
53+
*/
54+
tariffPlanId: string;
55+
/**
56+
* If true, we will save user card
57+
*/
58+
shouldSaveCard: boolean;
59+
/**
60+
* True if this is card linking operation – charging minimal amount of money to validate card info
61+
*/
62+
isCardLinkOperation: boolean;
4363
}

src/utils/checksumService.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,29 @@
11
import { PlanProlongationPayload } from '@hawk.so/types';
22
import jwt, { Secret } from 'jsonwebtoken';
33

4+
interface ChecksumData {
5+
/**
6+
* Workspace Identifier
7+
*/
8+
workspaceId: string;
9+
/**
10+
* Id of the user making the payment
11+
*/
12+
userId: string;
13+
/**
14+
* Workspace current plan id or plan id to change
15+
*/
16+
tariffPlanId: string;
17+
/**
18+
* If true, we will save user card
19+
*/
20+
shouldSaveCard: boolean;
21+
/**
22+
* True if this is card linking operation – charging minimal amount of money to validate card info
23+
*/
24+
isCardLinkOperation: boolean;
25+
}
26+
427
/**
528
* Helper class for working with checksums
629
*/
@@ -10,7 +33,7 @@ class ChecksumService {
1033
*
1134
* @param data - data for processing billing request
1235
*/
13-
public async generateChecksum(data: PlanProlongationPayload): Promise<string> {
36+
public async generateChecksum(data: ChecksumData): Promise<string> {
1437
return jwt.sign(
1538
data,
1639
process.env.JWT_SECRET_BILLING_CHECKSUM as Secret,
@@ -23,19 +46,20 @@ class ChecksumService {
2346
*
2447
* @param checksum - checksum to parse
2548
*/
26-
public parseAndVerifyChecksum(checksum: string): PlanProlongationPayload {
27-
const payload = jwt.verify(checksum, process.env.JWT_SECRET_BILLING_CHECKSUM as Secret) as PlanProlongationPayload;
49+
public parseAndVerifyChecksum(checksum: string): ChecksumData {
50+
const payload = jwt.verify(checksum, process.env.JWT_SECRET_BILLING_CHECKSUM as Secret) as ChecksumData;
2851

2952
/**
3053
* Filter unnecessary fields from JWT payload (e.g. "iat")
3154
*/
32-
const { tariffPlanId, workspaceId, userId, shouldSaveCard } = payload;
55+
const { tariffPlanId, workspaceId, userId, shouldSaveCard, isCardLinkOperation } = payload;
3356

3457
return {
3558
tariffPlanId,
3659
workspaceId,
3760
userId,
3861
shouldSaveCard,
62+
isCardLinkOperation
3963
};
4064
}
4165
}

0 commit comments

Comments
 (0)