Skip to content

Commit 303c927

Browse files
authored
Merge pull request #489 from codex-team/master
Update prod
2 parents e91bd6e + fa97f7d commit 303c927

File tree

7 files changed

+82
-14
lines changed

7 files changed

+82
-14
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "hawk.api",
3-
"version": "1.1.19",
3+
"version": "1.1.20",
44
"main": "index.ts",
55
"license": "UNLICENSED",
66
"scripts": {

src/billing/cloudpayments.ts

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import {
2525
PlanDBScheme,
2626
PlanProlongationPayload
2727
} from '@hawk.so/types';
28-
import { PENNY_MULTIPLIER } from 'codex-accounting-sdk';
2928
import WorkspaceModel from '../models/workspace';
3029
import HawkCatcher from '@hawk.so/nodejs';
3130
import { publish } from '../rabbitmq';
@@ -45,6 +44,8 @@ import PlanModel from '../models/plan';
4544
import { ClientApi, ClientService, CustomerReceiptItem, ReceiptApi, ReceiptTypes, TaxationSystem } from 'cloudpayments';
4645
import { ComposePaymentPayload } from './types/composePaymentPayload';
4746

47+
const PENNY_MULTIPLIER = 100;
48+
4849
interface ComposePaymentRequest extends express.Request {
4950
query: ComposePaymentPayload & { [key: string]: any };
5051
context: import('../types/graphql').ResolverContextBase;
@@ -105,7 +106,12 @@ export default class CloudPaymentsWebhooks {
105106
const userId = req.context.user.id;
106107

107108
if (!workspaceId || !tariffPlanId || !userId) {
108-
this.sendError(res, 1, `[Billing / Compose payment] No workspace, tariff plan or user id in request body`, req.query);
109+
this.sendError(res, 1, `[Billing / Compose payment] No workspace, tariff plan or user id in request body
110+
Details:
111+
workspaceId: ${workspaceId}
112+
tariffPlanId: ${tariffPlanId}
113+
userId: ${userId}`
114+
, req.query);
109115

110116
return;
111117
}
@@ -137,18 +143,37 @@ export default class CloudPaymentsWebhooks {
137143

138144
const isCardLinkOperation = workspace.tariffPlanId.toString() === tariffPlanId && !workspace.isTariffPlanExpired();
139145

146+
// Calculate next payment date
147+
const lastChargeDate = new Date(workspace.lastChargeDate);
148+
const now = new Date();
149+
let nextPaymentDate: Date;
150+
151+
if (isCardLinkOperation) {
152+
nextPaymentDate = new Date(lastChargeDate);
153+
} else {
154+
nextPaymentDate = new Date(now);
155+
}
156+
157+
if (workspace.isDebug) {
158+
nextPaymentDate.setDate(nextPaymentDate.getDate() + 1);
159+
} else {
160+
nextPaymentDate.setMonth(nextPaymentDate.getMonth() + 1);
161+
}
162+
140163
let checksum;
141164

142165
try {
143166
const checksumData = isCardLinkOperation ? {
144167
isCardLinkOperation: true,
145168
workspaceId: workspace._id.toString(),
146169
userId: userId,
170+
nextPaymentDate: nextPaymentDate.toISOString(),
147171
} : {
148172
workspaceId: workspace._id.toString(),
149173
userId: userId,
150174
tariffPlanId: tariffPlan._id.toString(),
151175
shouldSaveCard: shouldSaveCard === 'true',
176+
nextPaymentDate: nextPaymentDate.toISOString(),
152177
};
153178

154179
checksum = await checksumService.generateChecksum(checksumData);
@@ -170,6 +195,7 @@ export default class CloudPaymentsWebhooks {
170195
isCardLinkOperation,
171196
currency: 'RUB',
172197
checksum,
198+
nextPaymentDate: nextPaymentDate.toISOString(),
173199
});
174200
}
175201

@@ -268,7 +294,7 @@ export default class CloudPaymentsWebhooks {
268294
status: BusinessOperationStatus.Pending,
269295
payload: {
270296
workspaceId: workspace._id,
271-
amount: +body.Amount * PENNY_MULTIPLIER,
297+
amount: +body.Amount,
272298
currency: body.Currency,
273299
userId: member._id,
274300
tariffPlanId: plan._id,
@@ -357,7 +383,6 @@ export default class CloudPaymentsWebhooks {
357383

358384
try {
359385
await businessOperation.setStatus(BusinessOperationStatus.Confirmed);
360-
await workspace.resetBillingPeriod();
361386
await workspace.changePlan(tariffPlan._id);
362387

363388
const subscriptionId = body.SubscriptionId;
@@ -427,7 +452,7 @@ export default class CloudPaymentsWebhooks {
427452

428453
try {
429454
await publish('cron-tasks', 'cron-tasks/limiter', JSON.stringify({
430-
type: 'check-single-workspace',
455+
type: 'unblock-workspace',
431456
workspaceId: data.workspaceId,
432457
}));
433458
} catch (e) {
@@ -479,8 +504,6 @@ export default class CloudPaymentsWebhooks {
479504
* Refund the money that were charged to link a card
480505
*/
481506
if (data.isCardLinkOperation) {
482-
this.handleSendingToTelegramError(telegram.sendMessage(`✅ [Billing / Pay] Recurrent payments activated for «${workspace.name}». 1 RUB charged`, TelegramBotURLs.Money));
483-
484507
await cloudPaymentsApi.cancelPayment(body.TransactionId);
485508

486509
const member = await this.getMember(data.userId, workspace);
@@ -503,7 +526,13 @@ export default class CloudPaymentsWebhooks {
503526
dtCreated: new Date(),
504527
});
505528

506-
this.handleSendingToTelegramError(telegram.sendMessage(`✅ [Billing / Pay] Recurrent payments activated for «${workspace.name}». 1 RUB returned`, TelegramBotURLs.Money));
529+
this.handleSendingToTelegramError(telegram.sendMessage(`✅ [Billing / Pay] Card linked
530+
531+
workspace id: ${workspace._id}
532+
date of operation: ${body.DateTime}
533+
first payment date: ${data.cloudPayments?.recurrent.startDate}
534+
sum: ${data.cloudPayments?.recurrent.amount}${body.Currency}`
535+
, TelegramBotURLs.Money));
507536
} else {
508537
/**
509538
* Russia code from ISO 3166-1
@@ -517,7 +546,14 @@ export default class CloudPaymentsWebhooks {
517546

518547
await this.sendReceipt(workspace, tariffPlan, userEmail);
519548

520-
this.handleSendingToTelegramError(telegram.sendMessage(`✅ [Billing / Pay] Payment passed successfully for «${workspace.name}»`, TelegramBotURLs.Money));
549+
this.handleSendingToTelegramError(telegram.sendMessage(`✅ [Billing / Pay] New payment
550+
551+
amount: ${+body.Amount} ${body.Currency}
552+
next payment date: ${data.cloudPayments?.recurrent.startDate}
553+
workspace id: ${workspace._id}
554+
date of operation: ${body.DateTime}
555+
subscription id: ${body.SubscriptionId}`
556+
, TelegramBotURLs.Money));
521557
}
522558
} catch (e) {
523559
const error = e as Error;
@@ -607,7 +643,7 @@ export default class CloudPaymentsWebhooks {
607643
return;
608644
}
609645

610-
this.handleSendingToTelegramError(telegram.sendMessage(` [Billing / Fail] Transaction failed for «${workspace.name}»`, TelegramBotURLs.Money));
646+
this.handleSendingToTelegramError(telegram.sendMessage(` [Billing / Fail] Transaction failed for «${workspace.name}»`, TelegramBotURLs.Money));
611647

612648
HawkCatcher.send(new Error('[Billing / Fail] Transaction failed'), body as any);
613649

@@ -629,7 +665,13 @@ export default class CloudPaymentsWebhooks {
629665

630666
console.log('💎 CloudPayments /recurrent request', body);
631667

632-
this.handleSendingToTelegramError(telegram.sendMessage(`[Billing / Recurrent] New recurrent event with ${body.Status} status`, TelegramBotURLs.Money));
668+
this.handleSendingToTelegramError(telegram.sendMessage(`✅ [Billing / Recurrent] New recurrent transaction
669+
670+
amount: ${+body.Amount} ${body.Currency}
671+
next payment date: ${body.NextTransactionDate}
672+
workspace id: ${body.AccountId}
673+
subscription id: ${body.Id}`
674+
, TelegramBotURLs.Money));
633675
HawkCatcher.send(new Error(`[Billing / Recurrent] New recurrent event with ${body.Status} status`), req.body);
634676

635677
switch (body.Status) {

src/models/workspace.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,6 @@ export default class WorkspaceModel extends AbstractModel<WorkspaceDBScheme> imp
302302
$set: {
303303
tariffPlanId: this.tariffPlanId,
304304
billingPeriodEventsCount: 0,
305-
isBlocked: false,
306305
lastChargeDate: new Date(),
307306
},
308307
}

src/utils/checksumService.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ interface PlanPurchaseChecksumData {
2020
* If true, we will save user card
2121
*/
2222
shouldSaveCard: boolean;
23+
/**
24+
* Next payment date
25+
*/
26+
nextPaymentDate: string;
2327
}
2428

2529
interface CardLinkChecksumData {
@@ -35,6 +39,10 @@ interface CardLinkChecksumData {
3539
* True if this is card linking operation – charging minimal amount of money to validate card info
3640
*/
3741
isCardLinkOperation: boolean;
42+
/**
43+
* Next payment date
44+
*/
45+
nextPaymentDate: string;
3846
}
3947

4048
/**
@@ -67,13 +75,15 @@ class ChecksumService {
6775
workspaceId: payload.workspaceId,
6876
userId: payload.userId,
6977
isCardLinkOperation: payload.isCardLinkOperation,
78+
nextPaymentDate: payload.nextPaymentDate,
7079
};
7180
} else {
7281
return {
7382
workspaceId: payload.workspaceId,
7483
userId: payload.userId,
7584
tariffPlanId: payload.tariffPlanId,
7685
shouldSaveCard: payload.shouldSaveCard,
86+
nextPaymentDate: payload.nextPaymentDate,
7787
};
7888
}
7989
}

test/integration/cases/billing/check.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ describe('Check webhook', () => {
151151
userId: admin._id.toString(),
152152
tariffPlanId: planToChange._id.toString(),
153153
shouldSaveCard: false,
154+
nextPaymentDate: new Date().toString(),
154155
}),
155156
}),
156157
};
@@ -172,6 +173,7 @@ describe('Check webhook', () => {
172173
userId: externalUser._id.toString(),
173174
tariffPlanId: planToChange._id.toString(),
174175
shouldSaveCard: false,
176+
nextPaymentDate: new Date().toString(),
175177
}),
176178
}),
177179
};
@@ -193,6 +195,7 @@ describe('Check webhook', () => {
193195
userId: member._id.toString(),
194196
tariffPlanId: planToChange._id.toString(),
195197
shouldSaveCard: false,
198+
nextPaymentDate: new Date().toString(),
196199
}),
197200
}),
198201
};
@@ -214,6 +217,7 @@ describe('Check webhook', () => {
214217
userId: admin._id.toString(),
215218
tariffPlanId: '5fe383b0126d28007780641b',
216219
shouldSaveCard: false,
220+
nextPaymentDate: new Date().toString(),
217221
}),
218222
}),
219223
};
@@ -236,6 +240,7 @@ describe('Check webhook', () => {
236240
userId: admin._id.toString(),
237241
tariffPlanId: planToChange._id.toString(),
238242
shouldSaveCard: false,
243+
nextPaymentDate: new Date().toString(),
239244
}),
240245
}),
241246
};
@@ -257,6 +262,7 @@ describe('Check webhook', () => {
257262
userId: admin._id.toString(),
258263
tariffPlanId: planToChange._id.toString(),
259264
shouldSaveCard: false,
265+
nextPaymentDate: new Date().toString(),
260266
}),
261267
}),
262268
};
@@ -283,6 +289,7 @@ describe('Check webhook', () => {
283289
userId: admin._id.toString(),
284290
tariffPlanId: planToChange._id.toString(),
285291
shouldSaveCard: false,
292+
nextPaymentDate: new Date().toString(),
286293
}),
287294
cloudPayments: {
288295
recurrent: {

test/integration/cases/billing/fail.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,12 @@ const tariffPlan: PlanDBScheme = {
5050
name: 'Test plan',
5151
};
5252

53-
const planProlongationPayload: PlanProlongationPayload = {
53+
const planProlongationPayload = {
5454
userId: user._id.toString(),
5555
workspaceId: workspace._id.toString(),
5656
tariffPlanId: tariffPlan._id.toString(),
5757
shouldSaveCard: false,
58+
nextPaymentDate: new Date().toString(),
5859
};
5960

6061
const validRequest: FailRequest = {
@@ -239,6 +240,7 @@ describe('Fail webhook', () => {
239240
workspaceId: workspace._id.toString(),
240241
tariffPlanId: tariffPlan._id.toString(),
241242
shouldSaveCard: false,
243+
nextPaymentDate: new Date().toString(),
242244
}),
243245
}),
244246
});

test/integration/cases/billing/pay.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ describe('Pay webhook', () => {
127127
checksum: await checksumService.generateChecksum({
128128
...paymentSuccessPayload,
129129
shouldSaveCard: false,
130+
nextPaymentDate: new Date().toString(),
130131
}),
131132
}),
132133
};
@@ -457,6 +458,7 @@ describe('Pay webhook', () => {
457458
checksum: await checksumService.generateChecksum({
458459
...paymentSuccessPayload,
459460
shouldSaveCard: true,
461+
nextPaymentDate: new Date().toString(),
460462
}),
461463
}),
462464
...cardDetails,
@@ -502,6 +504,7 @@ describe('Pay webhook', () => {
502504
workspaceId: '',
503505
tariffPlanId: planToChange._id.toString(),
504506
shouldSaveCard: false,
507+
nextPaymentDate: new Date().toString(),
505508
}),
506509
}),
507510
});
@@ -523,6 +526,7 @@ describe('Pay webhook', () => {
523526
workspaceId: workspace._id.toString(),
524527
tariffPlanId: planToChange._id.toString(),
525528
shouldSaveCard: false,
529+
nextPaymentDate: new Date().toString(),
526530
}),
527531
}),
528532
});
@@ -544,6 +548,7 @@ describe('Pay webhook', () => {
544548
workspaceId: workspace._id.toString(),
545549
tariffPlanId: '',
546550
shouldSaveCard: false,
551+
nextPaymentDate: new Date().toString(),
547552
}),
548553
}),
549554
});
@@ -565,6 +570,7 @@ describe('Pay webhook', () => {
565570
workspaceId: new ObjectId().toString(),
566571
tariffPlanId: planToChange._id.toString(),
567572
shouldSaveCard: false,
573+
nextPaymentDate: new Date().toString(),
568574
}),
569575
}),
570576
});
@@ -586,6 +592,7 @@ describe('Pay webhook', () => {
586592
workspaceId: workspace._id.toString(),
587593
tariffPlanId: new ObjectId().toString(),
588594
shouldSaveCard: false,
595+
nextPaymentDate: new Date().toString(),
589596
}),
590597
}),
591598
});
@@ -607,6 +614,7 @@ describe('Pay webhook', () => {
607614
workspaceId: workspace._id.toString(),
608615
tariffPlanId: planToChange._id.toString(),
609616
shouldSaveCard: false,
617+
nextPaymentDate: new Date().toString(),
610618
}),
611619
}),
612620
});

0 commit comments

Comments
 (0)