shufflecom-calculations 1.12.18 → 1.12.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/games/dice.js +1 -1
- package/lib/games/dice.js.map +1 -1
- package/lib/games/hilo.js +2 -2
- package/lib/games/hilo.js.map +1 -1
- package/lib/games/mines.js +1 -1
- package/lib/games/mines.js.map +1 -1
- package/lib/games/tower.js +1 -1
- package/lib/games/tower.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/utils/derive-vip-bonus.js +7 -9
- package/lib/utils/derive-vip-bonus.js.map +1 -1
- package/lib/utils/validate-cashout-avaliable.d.ts +3 -7
- package/lib/utils/validate-cashout-avaliable.js +36 -37
- package/lib/utils/validate-cashout-avaliable.js.map +1 -1
- package/lib/utils/vip-bonus.type.d.ts +2 -1
- package/lib/utils/vip-bonus.type.js.map +1 -1
- package/package.json +2 -2
- package/src/games/dice.ts +1 -1
- package/src/games/hilo.ts +2 -3
- package/src/games/mines.ts +1 -1
- package/src/games/tower.ts +1 -2
- package/src/utils/derive-vip-bonus.spec.ts +221 -117
- package/src/utils/derive-vip-bonus.ts +26 -14
- package/src/utils/validate-cashout-avaliable.ts +50 -46
- package/src/utils/vip-bonus.type.ts +2 -1
|
@@ -18,7 +18,7 @@ describe('VipBonusUtils', () => {
|
|
|
18
18
|
const expiryPerOccurrence = 5 * 60;
|
|
19
19
|
const firstOccurrenceActivationPeriod = 5;
|
|
20
20
|
const occurrence = 4;
|
|
21
|
-
const bonusClaims: VipBonusIssuanceModel[] = []
|
|
21
|
+
const bonusClaims: VipBonusIssuanceModel[] = [];
|
|
22
22
|
|
|
23
23
|
const vipBonus: VipBonusPartial = {
|
|
24
24
|
type: VipBonusType.RELOADED,
|
|
@@ -28,56 +28,63 @@ describe('VipBonusUtils', () => {
|
|
|
28
28
|
occurrence,
|
|
29
29
|
cancelledAt: null,
|
|
30
30
|
createdAt: startDate.toISOString(),
|
|
31
|
-
endAt: startDate
|
|
31
|
+
endAt: startDate
|
|
32
|
+
.add(firstOccurrenceActivationPeriod, 'hours')
|
|
33
|
+
.add(expiryPerOccurrence * occurrence, 'seconds')
|
|
34
|
+
.toISOString(),
|
|
32
35
|
bonusClaims,
|
|
33
36
|
firstOccurrenceActivationPeriod,
|
|
34
37
|
expiryPerOccurrence,
|
|
35
|
-
}
|
|
38
|
+
};
|
|
36
39
|
|
|
37
|
-
let timeNow = startDate
|
|
40
|
+
let timeNow = startDate;
|
|
38
41
|
mockdatetime(timeNow.toDate());
|
|
39
42
|
|
|
40
|
-
let issuances = deriveBonusIssuances(vipBonus)
|
|
43
|
+
let issuances = deriveBonusIssuances(vipBonus);
|
|
41
44
|
|
|
42
|
-
let firstIssuance = issuances[0]
|
|
43
|
-
expect(firstIssuance.expiryDate).toEqual(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
expect(secondIssuance.expiryDate).toBeUndefined()
|
|
49
|
-
expect(secondIssuance.availableDate).toBeUndefined()
|
|
50
|
-
expect(secondIssuance.status).toEqual(VipBonusIssuanceStatus.SCHEDULED)
|
|
45
|
+
let firstIssuance = issuances[0];
|
|
46
|
+
expect(firstIssuance.expiryDate).toEqual(
|
|
47
|
+
startDate.add(firstOccurrenceActivationPeriod, 'hours').add(expiryPerOccurrence, 'seconds').toISOString(),
|
|
48
|
+
);
|
|
49
|
+
expect(firstIssuance.availableDate).toEqual(startDate.toISOString());
|
|
50
|
+
expect(firstIssuance.status).toEqual(VipBonusIssuanceStatus.PENDING_CLAIM);
|
|
51
51
|
|
|
52
|
+
let secondIssuance = issuances[1];
|
|
53
|
+
expect(secondIssuance.expiryDate).toBeUndefined();
|
|
54
|
+
expect(secondIssuance.availableDate).toBeUndefined();
|
|
55
|
+
expect(secondIssuance.status).toEqual(VipBonusIssuanceStatus.SCHEDULED);
|
|
52
56
|
|
|
53
57
|
// first claim before the activation period ends
|
|
54
|
-
timeNow = startDate.add(firstOccurrenceActivationPeriod / 2, 'hours')
|
|
55
|
-
mockdatetime(timeNow.toDate())
|
|
58
|
+
timeNow = startDate.add(firstOccurrenceActivationPeriod / 2, 'hours');
|
|
59
|
+
mockdatetime(timeNow.toDate());
|
|
56
60
|
|
|
57
61
|
bonusClaims.push({
|
|
58
62
|
currency: Currency.BTC,
|
|
63
|
+
amount: '10',
|
|
59
64
|
bonusAmountUsd: BigNumber(bonusAmountUsd).dividedBy(occurrence).toString(),
|
|
60
65
|
occurrenceIndex: 1,
|
|
61
66
|
createdAt: timeNow.toISOString(),
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
vipBonus.bonusClaims = bonusClaims
|
|
67
|
+
});
|
|
65
68
|
|
|
66
|
-
|
|
69
|
+
vipBonus.bonusClaims = bonusClaims;
|
|
67
70
|
|
|
68
|
-
|
|
69
|
-
expect(firstIssuance.expiryDate).toEqual(startDate.add(firstOccurrenceActivationPeriod, 'hours').add(expiryPerOccurrence, 'seconds').toISOString())
|
|
70
|
-
expect(firstIssuance.availableDate).toEqual(startDate.toISOString())
|
|
71
|
-
expect(firstIssuance.status).toEqual(VipBonusIssuanceStatus.CLAIMED)
|
|
71
|
+
issuances = deriveBonusIssuances(vipBonus);
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
expect(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
expect(
|
|
73
|
+
firstIssuance = issuances[0];
|
|
74
|
+
expect(firstIssuance.expiryDate).toEqual(
|
|
75
|
+
startDate.add(firstOccurrenceActivationPeriod, 'hours').add(expiryPerOccurrence, 'seconds').toISOString(),
|
|
76
|
+
);
|
|
77
|
+
expect(firstIssuance.availableDate).toEqual(startDate.toISOString());
|
|
78
|
+
expect(firstIssuance.status).toEqual(VipBonusIssuanceStatus.CLAIMED);
|
|
79
|
+
expect(firstIssuance.amount).toEqual('10');
|
|
78
80
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
secondIssuance = issuances[1];
|
|
82
|
+
expect(secondIssuance.expiryDate).toEqual(timeNow.add(cadence + expiryPerOccurrence, 'seconds').toISOString());
|
|
83
|
+
expect(secondIssuance.availableDate).toEqual(timeNow.add(cadence, 'seconds').toISOString());
|
|
84
|
+
expect(secondIssuance.status).toEqual(VipBonusIssuanceStatus.SCHEDULED);
|
|
85
|
+
expect(secondIssuance.currency).toEqual(Currency.BTC);
|
|
86
|
+
expect(secondIssuance.amount).toEqual(undefined);
|
|
87
|
+
});
|
|
81
88
|
|
|
82
89
|
it('should derive bonus issuance status correctly (first claim after activation period)', () => {
|
|
83
90
|
const bonusAmountUsd = '100';
|
|
@@ -86,7 +93,7 @@ describe('VipBonusUtils', () => {
|
|
|
86
93
|
const expiryPerOccurrence = 20 * 60;
|
|
87
94
|
const firstOccurrenceActivationPeriod = 5;
|
|
88
95
|
const occurrence = 4;
|
|
89
|
-
const bonusClaims: VipBonusIssuanceModel[] = []
|
|
96
|
+
const bonusClaims: VipBonusIssuanceModel[] = [];
|
|
90
97
|
|
|
91
98
|
const vipBonus: VipBonusPartial = {
|
|
92
99
|
type: VipBonusType.RELOADED,
|
|
@@ -96,54 +103,85 @@ describe('VipBonusUtils', () => {
|
|
|
96
103
|
occurrence,
|
|
97
104
|
cancelledAt: null,
|
|
98
105
|
createdAt: startDate.toISOString(),
|
|
99
|
-
endAt: startDate
|
|
106
|
+
endAt: startDate
|
|
107
|
+
.add(firstOccurrenceActivationPeriod, 'hours')
|
|
108
|
+
.add(expiryPerOccurrence * occurrence, 'seconds')
|
|
109
|
+
.toISOString(),
|
|
100
110
|
bonusClaims,
|
|
101
111
|
firstOccurrenceActivationPeriod,
|
|
102
112
|
expiryPerOccurrence,
|
|
103
|
-
}
|
|
113
|
+
};
|
|
104
114
|
|
|
105
|
-
let timeNow = startDate
|
|
115
|
+
let timeNow = startDate;
|
|
106
116
|
mockdatetime(timeNow.toDate());
|
|
107
117
|
|
|
108
|
-
let issuances = deriveBonusIssuances(vipBonus)
|
|
118
|
+
let issuances = deriveBonusIssuances(vipBonus);
|
|
109
119
|
|
|
110
|
-
let firstIssuance = issuances[0]
|
|
111
|
-
expect(firstIssuance.expiryDate).toEqual(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
expect(secondIssuance.expiryDate).toBeUndefined()
|
|
117
|
-
expect(secondIssuance.availableDate).toBeUndefined()
|
|
118
|
-
expect(secondIssuance.status).toEqual(VipBonusIssuanceStatus.SCHEDULED)
|
|
120
|
+
let firstIssuance = issuances[0];
|
|
121
|
+
expect(firstIssuance.expiryDate).toEqual(
|
|
122
|
+
startDate.add(firstOccurrenceActivationPeriod, 'hours').add(expiryPerOccurrence, 'seconds').toISOString(),
|
|
123
|
+
);
|
|
124
|
+
expect(firstIssuance.availableDate).toEqual(startDate.toISOString());
|
|
125
|
+
expect(firstIssuance.status).toEqual(VipBonusIssuanceStatus.PENDING_CLAIM);
|
|
119
126
|
|
|
127
|
+
let secondIssuance = issuances[1];
|
|
128
|
+
expect(secondIssuance.expiryDate).toBeUndefined();
|
|
129
|
+
expect(secondIssuance.availableDate).toBeUndefined();
|
|
130
|
+
expect(secondIssuance.status).toEqual(VipBonusIssuanceStatus.SCHEDULED);
|
|
120
131
|
|
|
121
132
|
// first claim after the activation period ends
|
|
122
|
-
timeNow = startDate.add(firstOccurrenceActivationPeriod, 'hours').add(expiryPerOccurrence / 2, 'seconds')
|
|
123
|
-
const activationTime = startDate.add(firstOccurrenceActivationPeriod, 'hours')
|
|
124
|
-
mockdatetime(timeNow.toDate())
|
|
133
|
+
timeNow = startDate.add(firstOccurrenceActivationPeriod, 'hours').add(expiryPerOccurrence / 2, 'seconds');
|
|
134
|
+
const activationTime = startDate.add(firstOccurrenceActivationPeriod, 'hours');
|
|
135
|
+
mockdatetime(timeNow.toDate());
|
|
125
136
|
|
|
126
137
|
bonusClaims.push({
|
|
127
138
|
currency: Currency.BTC,
|
|
139
|
+
amount: '10',
|
|
128
140
|
bonusAmountUsd: BigNumber(bonusAmountUsd).dividedBy(occurrence).toString(),
|
|
129
141
|
occurrenceIndex: 1,
|
|
130
142
|
createdAt: timeNow.toISOString(),
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
vipBonus.bonusClaims = bonusClaims
|
|
134
|
-
|
|
135
|
-
issuances = deriveBonusIssuances(vipBonus)
|
|
136
|
-
firstIssuance = issuances[0]
|
|
137
|
-
expect(firstIssuance.expiryDate).toEqual(startDate.add(firstOccurrenceActivationPeriod, 'hours').add(expiryPerOccurrence, 'seconds').toISOString())
|
|
138
|
-
expect(firstIssuance.availableDate).toEqual(startDate.toISOString())
|
|
139
|
-
expect(firstIssuance.status).toEqual(VipBonusIssuanceStatus.CLAIMED)
|
|
143
|
+
});
|
|
140
144
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
expect(
|
|
146
|
-
|
|
145
|
+
vipBonus.bonusClaims = bonusClaims;
|
|
146
|
+
|
|
147
|
+
issuances = deriveBonusIssuances(vipBonus);
|
|
148
|
+
firstIssuance = issuances[0];
|
|
149
|
+
expect(firstIssuance.expiryDate).toEqual(
|
|
150
|
+
startDate.add(firstOccurrenceActivationPeriod, 'hours').add(expiryPerOccurrence, 'seconds').toISOString(),
|
|
151
|
+
);
|
|
152
|
+
expect(firstIssuance.availableDate).toEqual(startDate.toISOString());
|
|
153
|
+
expect(firstIssuance.status).toEqual(VipBonusIssuanceStatus.CLAIMED);
|
|
154
|
+
expect(firstIssuance.amount).toEqual('10');
|
|
155
|
+
|
|
156
|
+
secondIssuance = issuances[1];
|
|
157
|
+
expect(secondIssuance.expiryDate).toEqual(activationTime.add(cadence + expiryPerOccurrence, 'seconds').toISOString());
|
|
158
|
+
expect(secondIssuance.availableDate).toEqual(activationTime.add(cadence, 'seconds').toISOString());
|
|
159
|
+
expect(secondIssuance.status).toEqual(VipBonusIssuanceStatus.PENDING_CLAIM);
|
|
160
|
+
expect(secondIssuance.currency).toEqual(Currency.BTC);
|
|
161
|
+
expect(secondIssuance.amount).toEqual(undefined);
|
|
162
|
+
|
|
163
|
+
timeNow = startDate.add(firstOccurrenceActivationPeriod, 'hours').add(cadence + 1, 'seconds');
|
|
164
|
+
mockdatetime(timeNow.toDate());
|
|
165
|
+
const bonusClaimNotInOrder = [
|
|
166
|
+
{
|
|
167
|
+
currency: Currency.BTC,
|
|
168
|
+
bonusAmountUsd: BigNumber(bonusAmountUsd).dividedBy(occurrence).toString(),
|
|
169
|
+
occurrenceIndex: 2,
|
|
170
|
+
createdAt: timeNow.toISOString(),
|
|
171
|
+
},
|
|
172
|
+
bonusClaims[0],
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
vipBonus.bonusClaims = bonusClaimNotInOrder;
|
|
176
|
+
issuances = deriveBonusIssuances(vipBonus);
|
|
177
|
+
firstIssuance = issuances[0];
|
|
178
|
+
expect(firstIssuance.createdAt).toEqual(
|
|
179
|
+
startDate
|
|
180
|
+
.add(firstOccurrenceActivationPeriod, 'hours')
|
|
181
|
+
.add(expiryPerOccurrence / 2, 'seconds')
|
|
182
|
+
.toISOString(),
|
|
183
|
+
);
|
|
184
|
+
});
|
|
147
185
|
|
|
148
186
|
it('should update bonus issuance status correctly sequential vip reload', () => {
|
|
149
187
|
const vipBonusId = uuidv4();
|
|
@@ -156,15 +194,22 @@ describe('VipBonusUtils', () => {
|
|
|
156
194
|
const firstOccurrenceActivationPeriod = 0;
|
|
157
195
|
const occurrence = 10;
|
|
158
196
|
const claimed = [2, 3];
|
|
159
|
-
const activationTime = dayjs(startDate)
|
|
197
|
+
const activationTime = dayjs(startDate);
|
|
160
198
|
|
|
161
|
-
const issuances = range(1, occurrence + 1).map(
|
|
199
|
+
const issuances = range(1, occurrence + 1).map(occurrenceIndex => ({
|
|
162
200
|
vipBonusId,
|
|
163
201
|
userId,
|
|
164
202
|
currency,
|
|
165
203
|
bonusAmountUsd,
|
|
166
204
|
occurrenceIndex,
|
|
167
|
-
expiryDate: getReloadExpiryDate(
|
|
205
|
+
expiryDate: getReloadExpiryDate(
|
|
206
|
+
activationTime,
|
|
207
|
+
cadence,
|
|
208
|
+
expiryPerOccurrence,
|
|
209
|
+
occurrenceIndex,
|
|
210
|
+
startDate,
|
|
211
|
+
firstOccurrenceActivationPeriod,
|
|
212
|
+
)?.toISOString(),
|
|
168
213
|
availableDate: getReloadAvailableDate(activationTime, cadence, occurrenceIndex, startDate)?.toISOString(),
|
|
169
214
|
status: claimed.includes(occurrenceIndex) ? VipBonusIssuanceStatus.CLAIMED : null,
|
|
170
215
|
createdAt: startDate.toISOString(),
|
|
@@ -175,7 +220,7 @@ describe('VipBonusUtils', () => {
|
|
|
175
220
|
|
|
176
221
|
// fast forward into reward 3 claiming interval
|
|
177
222
|
mockdatetime(startDate.add(cadence * fastForward + 1, 'seconds').toDate());
|
|
178
|
-
let updatedStatusList = issuances.map(
|
|
223
|
+
let updatedStatusList = issuances.map(issuance => updateBonusIssuanceStatus(issuance, null, dayjs()));
|
|
179
224
|
|
|
180
225
|
updatedStatusList.forEach((issuance, index) => {
|
|
181
226
|
if (claimed.includes(index + 1)) {
|
|
@@ -190,7 +235,7 @@ describe('VipBonusUtils', () => {
|
|
|
190
235
|
// fast forward into reward 6 claiming interval
|
|
191
236
|
fastForward = 5;
|
|
192
237
|
mockdatetime(startDate.add(cadence * fastForward, 'seconds').toDate());
|
|
193
|
-
updatedStatusList = issuances.map(
|
|
238
|
+
updatedStatusList = issuances.map(issuance => updateBonusIssuanceStatus(issuance, null, dayjs()));
|
|
194
239
|
|
|
195
240
|
updatedStatusList.forEach((issuance, index) => {
|
|
196
241
|
if (claimed.includes(index + 1)) {
|
|
@@ -216,27 +261,41 @@ describe('VipBonusUtils', () => {
|
|
|
216
261
|
const firstOccurrenceActivationPeriod = 10;
|
|
217
262
|
const occurrence = 10;
|
|
218
263
|
let activationTime: Dayjs | null = null; // first one not claimed yet
|
|
219
|
-
|
|
220
|
-
let issuances = range(1, occurrence + 1).map(
|
|
264
|
+
|
|
265
|
+
let issuances = range(1, occurrence + 1).map(occurrenceIndex => ({
|
|
221
266
|
vipBonusId,
|
|
222
267
|
userId,
|
|
223
268
|
currency,
|
|
224
269
|
bonusAmountUsd,
|
|
225
270
|
occurrenceIndex,
|
|
226
|
-
expiryDate: getReloadExpiryDate(
|
|
271
|
+
expiryDate: getReloadExpiryDate(
|
|
272
|
+
activationTime,
|
|
273
|
+
cadence,
|
|
274
|
+
expiryPerOccurrence,
|
|
275
|
+
occurrenceIndex,
|
|
276
|
+
startDate,
|
|
277
|
+
firstOccurrenceActivationPeriod,
|
|
278
|
+
)?.toISOString(),
|
|
227
279
|
availableDate: getReloadAvailableDate(activationTime, cadence, occurrenceIndex, startDate)?.toISOString(),
|
|
228
280
|
status: null as VipBonusIssuanceStatus | null,
|
|
229
281
|
createdAt: startDate.toISOString(),
|
|
230
282
|
expiryPerOccurrence,
|
|
231
283
|
firstOccurrenceActivationPeriod,
|
|
232
|
-
}))
|
|
284
|
+
}));
|
|
233
285
|
|
|
234
286
|
// fast forward within first occurrence activation period
|
|
235
287
|
mockdatetime(startDate.add(firstOccurrenceActivationPeriod / 2, 'hours').toDate());
|
|
236
288
|
// first issuance has to recalculate based on current time
|
|
237
|
-
issuances[0].expiryDate = getReloadExpiryDate(
|
|
289
|
+
issuances[0].expiryDate = getReloadExpiryDate(
|
|
290
|
+
activationTime,
|
|
291
|
+
cadence,
|
|
292
|
+
expiryPerOccurrence,
|
|
293
|
+
1,
|
|
294
|
+
startDate,
|
|
295
|
+
firstOccurrenceActivationPeriod,
|
|
296
|
+
)?.toISOString();
|
|
238
297
|
|
|
239
|
-
let updatedStatusList = issuances.map(
|
|
298
|
+
let updatedStatusList = issuances.map(issuance => updateBonusIssuanceStatus(issuance, null, dayjs()));
|
|
240
299
|
|
|
241
300
|
updatedStatusList.forEach((issuance, index) => {
|
|
242
301
|
if (index + 1 === 1) {
|
|
@@ -244,39 +303,63 @@ describe('VipBonusUtils', () => {
|
|
|
244
303
|
} else {
|
|
245
304
|
expect(issuance.status).toEqual(VipBonusIssuanceStatus.SCHEDULED);
|
|
246
305
|
}
|
|
247
|
-
})
|
|
306
|
+
});
|
|
248
307
|
|
|
249
308
|
// fast forward after first occurrence activation period
|
|
250
|
-
mockdatetime(
|
|
251
|
-
|
|
252
|
-
|
|
309
|
+
mockdatetime(
|
|
310
|
+
startDate
|
|
311
|
+
.add(firstOccurrenceActivationPeriod, 'hours')
|
|
312
|
+
.add(expiryPerOccurrence / 2, 'seconds')
|
|
313
|
+
.toDate(),
|
|
314
|
+
);
|
|
315
|
+
issuances[0].expiryDate = getReloadExpiryDate(
|
|
316
|
+
activationTime,
|
|
317
|
+
cadence,
|
|
318
|
+
expiryPerOccurrence,
|
|
319
|
+
1,
|
|
320
|
+
startDate,
|
|
321
|
+
firstOccurrenceActivationPeriod,
|
|
322
|
+
)?.toISOString();
|
|
323
|
+
updatedStatusList = issuances.map(issuance => updateBonusIssuanceStatus(issuance, null, dayjs()));
|
|
253
324
|
|
|
254
325
|
updatedStatusList.forEach((issuance, index) => {
|
|
255
|
-
if (index + 1 === 1) {
|
|
326
|
+
if (index + 1 === 1) {
|
|
256
327
|
expect(issuance.status).toEqual(VipBonusIssuanceStatus.PENDING_CLAIM);
|
|
257
328
|
} else {
|
|
258
329
|
expect(issuance.status).toEqual(VipBonusIssuanceStatus.SCHEDULED);
|
|
259
330
|
}
|
|
260
|
-
})
|
|
331
|
+
});
|
|
261
332
|
|
|
262
333
|
// fast forward after expiry
|
|
263
|
-
mockdatetime(
|
|
264
|
-
|
|
265
|
-
|
|
334
|
+
mockdatetime(
|
|
335
|
+
startDate
|
|
336
|
+
.add(firstOccurrenceActivationPeriod, 'hours')
|
|
337
|
+
.add(expiryPerOccurrence + 1, 'seconds')
|
|
338
|
+
.toDate(),
|
|
339
|
+
);
|
|
340
|
+
activationTime = dayjs(startDate).add(firstOccurrenceActivationPeriod, 'hours');
|
|
341
|
+
issuances = range(1, occurrence + 1).map(occurrenceIndex => ({
|
|
266
342
|
vipBonusId,
|
|
267
343
|
userId,
|
|
268
344
|
currency,
|
|
269
345
|
bonusAmountUsd,
|
|
270
346
|
occurrenceIndex,
|
|
271
|
-
expiryDate: getReloadExpiryDate(
|
|
347
|
+
expiryDate: getReloadExpiryDate(
|
|
348
|
+
activationTime,
|
|
349
|
+
cadence,
|
|
350
|
+
expiryPerOccurrence,
|
|
351
|
+
occurrenceIndex,
|
|
352
|
+
startDate,
|
|
353
|
+
firstOccurrenceActivationPeriod,
|
|
354
|
+
)?.toISOString(),
|
|
272
355
|
availableDate: getReloadAvailableDate(activationTime, cadence, occurrenceIndex, startDate)?.toISOString(),
|
|
273
356
|
status: null as VipBonusIssuanceStatus | null,
|
|
274
357
|
createdAt: startDate.toISOString(),
|
|
275
358
|
expiryPerOccurrence,
|
|
276
359
|
firstOccurrenceActivationPeriod,
|
|
277
|
-
}))
|
|
360
|
+
}));
|
|
278
361
|
|
|
279
|
-
updatedStatusList = issuances.map(
|
|
362
|
+
updatedStatusList = issuances.map(issuance => updateBonusIssuanceStatus(issuance, null, dayjs()));
|
|
280
363
|
|
|
281
364
|
updatedStatusList.forEach((issuance, index) => {
|
|
282
365
|
if (index + 1 === 1) {
|
|
@@ -284,8 +367,8 @@ describe('VipBonusUtils', () => {
|
|
|
284
367
|
} else {
|
|
285
368
|
expect(issuance.status).toEqual(VipBonusIssuanceStatus.SCHEDULED);
|
|
286
369
|
}
|
|
287
|
-
})
|
|
288
|
-
})
|
|
370
|
+
});
|
|
371
|
+
});
|
|
289
372
|
|
|
290
373
|
it('should update bonus issuance status correctly for independent vip reload (overlapping vip reloads)', () => {
|
|
291
374
|
const vipBonusId = uuidv4();
|
|
@@ -298,15 +381,22 @@ describe('VipBonusUtils', () => {
|
|
|
298
381
|
const firstOccurrenceActivationPeriod = 10;
|
|
299
382
|
const occurrence = 10;
|
|
300
383
|
const claimed = [1];
|
|
301
|
-
const activationTime = dayjs(startDate).add(5, 'hours') // user claimed within first occurrence activation period
|
|
384
|
+
const activationTime = dayjs(startDate).add(5, 'hours'); // user claimed within first occurrence activation period
|
|
302
385
|
|
|
303
|
-
const issuances = range(1, occurrence + 1).map(
|
|
386
|
+
const issuances = range(1, occurrence + 1).map(occurrenceIndex => ({
|
|
304
387
|
vipBonusId,
|
|
305
388
|
userId,
|
|
306
389
|
currency,
|
|
307
390
|
bonusAmountUsd,
|
|
308
391
|
occurrenceIndex,
|
|
309
|
-
expiryDate: getReloadExpiryDate(
|
|
392
|
+
expiryDate: getReloadExpiryDate(
|
|
393
|
+
activationTime,
|
|
394
|
+
cadence,
|
|
395
|
+
expiryPerOccurrence,
|
|
396
|
+
occurrenceIndex,
|
|
397
|
+
startDate,
|
|
398
|
+
firstOccurrenceActivationPeriod,
|
|
399
|
+
)?.toISOString(),
|
|
310
400
|
availableDate: getReloadAvailableDate(activationTime, cadence, occurrenceIndex, startDate)?.toISOString(),
|
|
311
401
|
status: claimed.includes(occurrenceIndex) ? VipBonusIssuanceStatus.CLAIMED : null,
|
|
312
402
|
createdAt: startDate.toISOString(),
|
|
@@ -318,9 +408,9 @@ describe('VipBonusUtils', () => {
|
|
|
318
408
|
|
|
319
409
|
// fast forward into reward 3 claiming interval
|
|
320
410
|
mockdatetime(activationTime.add(cadence * fastForward + 1, 'seconds').toDate());
|
|
321
|
-
let updatedStatusList = issuances.map(
|
|
411
|
+
let updatedStatusList = issuances.map(issuance => updateBonusIssuanceStatus(issuance, null, dayjs()));
|
|
322
412
|
|
|
323
|
-
let pendingClaims = [2, 3]
|
|
413
|
+
let pendingClaims = [2, 3];
|
|
324
414
|
updatedStatusList.forEach((issuance, index) => {
|
|
325
415
|
if (claimed.includes(index + 1)) {
|
|
326
416
|
expect(issuance.status).toEqual(VipBonusIssuanceStatus.CLAIMED);
|
|
@@ -331,14 +421,14 @@ describe('VipBonusUtils', () => {
|
|
|
331
421
|
}
|
|
332
422
|
});
|
|
333
423
|
|
|
334
|
-
fastForward = 7
|
|
424
|
+
fastForward = 7;
|
|
335
425
|
|
|
336
426
|
// fast forward into reward 8 just after expiry
|
|
337
427
|
mockdatetime(activationTime.add(cadence * fastForward + expiryPerOccurrence + 1, 'seconds').toDate());
|
|
338
|
-
updatedStatusList = issuances.map(
|
|
428
|
+
updatedStatusList = issuances.map(issuance => updateBonusIssuanceStatus(issuance, null, dayjs()));
|
|
339
429
|
|
|
340
|
-
pendingClaims = [9, 10]
|
|
341
|
-
|
|
430
|
+
pendingClaims = [9, 10];
|
|
431
|
+
const expired = [2, 3, 4, 5, 6, 7, 8];
|
|
342
432
|
updatedStatusList.forEach((issuance, index) => {
|
|
343
433
|
if (claimed.includes(index + 1)) {
|
|
344
434
|
expect(issuance.status).toEqual(VipBonusIssuanceStatus.CLAIMED);
|
|
@@ -349,8 +439,8 @@ describe('VipBonusUtils', () => {
|
|
|
349
439
|
} else {
|
|
350
440
|
expect(issuance.status).toEqual(VipBonusIssuanceStatus.SCHEDULED);
|
|
351
441
|
}
|
|
352
|
-
})
|
|
353
|
-
})
|
|
442
|
+
});
|
|
443
|
+
});
|
|
354
444
|
|
|
355
445
|
it('should update bonus issuance status correctly for independent vip reload (no overlapping vip reloads', () => {
|
|
356
446
|
const vipBonusId = uuidv4();
|
|
@@ -364,26 +454,33 @@ describe('VipBonusUtils', () => {
|
|
|
364
454
|
const occurrence = 10;
|
|
365
455
|
const claimed = [2, 3];
|
|
366
456
|
const activationTime = dayjs(startDate).add(firstOccurrenceActivationPeriod, 'hours');
|
|
367
|
-
|
|
368
|
-
const issuances = range(1, occurrence + 1).map(
|
|
457
|
+
|
|
458
|
+
const issuances = range(1, occurrence + 1).map(occurrenceIndex => ({
|
|
369
459
|
vipBonusId,
|
|
370
460
|
userId,
|
|
371
461
|
currency,
|
|
372
462
|
bonusAmountUsd,
|
|
373
463
|
occurrenceIndex,
|
|
374
|
-
expiryDate: getReloadExpiryDate(
|
|
464
|
+
expiryDate: getReloadExpiryDate(
|
|
465
|
+
activationTime,
|
|
466
|
+
cadence,
|
|
467
|
+
expiryPerOccurrence,
|
|
468
|
+
occurrenceIndex,
|
|
469
|
+
startDate,
|
|
470
|
+
firstOccurrenceActivationPeriod,
|
|
471
|
+
)?.toISOString(),
|
|
375
472
|
availableDate: getReloadAvailableDate(activationTime, cadence, occurrenceIndex, startDate)?.toISOString(),
|
|
376
473
|
status: claimed.includes(occurrenceIndex) ? VipBonusIssuanceStatus.CLAIMED : null,
|
|
377
474
|
createdAt: startDate.toISOString(),
|
|
378
475
|
expiryPerOccurrence,
|
|
379
476
|
firstOccurrenceActivationPeriod,
|
|
380
|
-
}))
|
|
477
|
+
}));
|
|
381
478
|
|
|
382
479
|
let fastForward = 2;
|
|
383
|
-
let pendingClaims = [4, 5, 6, 7, 8, 9, 10]
|
|
480
|
+
let pendingClaims = [4, 5, 6, 7, 8, 9, 10];
|
|
384
481
|
// fast forward into reward 3 claiming interval
|
|
385
482
|
mockdatetime(activationTime.add(cadence * fastForward + 1, 'seconds').toDate());
|
|
386
|
-
let updatedStatusList = issuances.map(
|
|
483
|
+
let updatedStatusList = issuances.map(issuance => updateBonusIssuanceStatus(issuance, null, dayjs()));
|
|
387
484
|
|
|
388
485
|
updatedStatusList.forEach((issuance, index) => {
|
|
389
486
|
if (claimed.includes(index + 1)) {
|
|
@@ -393,14 +490,14 @@ describe('VipBonusUtils', () => {
|
|
|
393
490
|
} else {
|
|
394
491
|
expect(issuance.status).toEqual(VipBonusIssuanceStatus.EXPIRED);
|
|
395
492
|
}
|
|
396
|
-
})
|
|
493
|
+
});
|
|
397
494
|
|
|
398
|
-
fastForward = 7
|
|
399
|
-
pendingClaims = [9, 10]
|
|
495
|
+
fastForward = 7;
|
|
496
|
+
pendingClaims = [9, 10];
|
|
400
497
|
|
|
401
498
|
// fast forward into reward 8 just after expiry
|
|
402
499
|
mockdatetime(activationTime.add(cadence * fastForward + expiryPerOccurrence + 1, 'seconds').toDate());
|
|
403
|
-
updatedStatusList = issuances.map(
|
|
500
|
+
updatedStatusList = issuances.map(issuance => updateBonusIssuanceStatus(issuance, null, dayjs()));
|
|
404
501
|
|
|
405
502
|
updatedStatusList.forEach((issuance, index) => {
|
|
406
503
|
if (claimed.includes(index + 1)) {
|
|
@@ -410,9 +507,9 @@ describe('VipBonusUtils', () => {
|
|
|
410
507
|
} else {
|
|
411
508
|
expect(issuance.status).toEqual(VipBonusIssuanceStatus.EXPIRED);
|
|
412
509
|
}
|
|
413
|
-
})
|
|
414
|
-
})
|
|
415
|
-
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
|
|
416
513
|
it('should update bonus issuance status correctly with cancelledAt', () => {
|
|
417
514
|
const vipBonusId = uuidv4();
|
|
418
515
|
const userId = uuidv4();
|
|
@@ -428,15 +525,22 @@ describe('VipBonusUtils', () => {
|
|
|
428
525
|
const cancelledAt = dayjs(startDate)
|
|
429
526
|
.add(cadence * (cancelledIndex - 1), 'seconds')
|
|
430
527
|
.toDate();
|
|
431
|
-
const activationTime = dayjs(startDate)
|
|
528
|
+
const activationTime = dayjs(startDate);
|
|
432
529
|
|
|
433
|
-
const issuances = range(1, occurrence + 1).map(
|
|
530
|
+
const issuances = range(1, occurrence + 1).map(occurrenceIndex => ({
|
|
434
531
|
vipBonusId,
|
|
435
532
|
userId,
|
|
436
533
|
currency,
|
|
437
534
|
bonusAmountUsd,
|
|
438
535
|
occurrenceIndex,
|
|
439
|
-
expiryDate: getReloadExpiryDate(
|
|
536
|
+
expiryDate: getReloadExpiryDate(
|
|
537
|
+
activationTime,
|
|
538
|
+
cadence,
|
|
539
|
+
expiryPerOccurrence,
|
|
540
|
+
occurrenceIndex,
|
|
541
|
+
startDate,
|
|
542
|
+
firstOccurrenceActivationPeriod,
|
|
543
|
+
)?.toISOString(),
|
|
440
544
|
availableDate: getReloadAvailableDate(activationTime, cadence, occurrenceIndex, startDate)?.toISOString(),
|
|
441
545
|
status: claimed.includes(occurrenceIndex) ? VipBonusIssuanceStatus.CLAIMED : null,
|
|
442
546
|
createdAt: startDate.toISOString(),
|
|
@@ -447,7 +551,7 @@ describe('VipBonusUtils', () => {
|
|
|
447
551
|
// fast forward into reward 7 claiming interval
|
|
448
552
|
let fastForward = 6;
|
|
449
553
|
mockdatetime(startDate.add(cadence * fastForward, 'seconds').toDate());
|
|
450
|
-
let updatedStatusList = issuances.map(
|
|
554
|
+
let updatedStatusList = issuances.map(issuance => updateBonusIssuanceStatus(issuance, cancelledAt, dayjs()));
|
|
451
555
|
|
|
452
556
|
updatedStatusList.forEach((issuance, index) => {
|
|
453
557
|
if (claimed.includes(index + 1)) {
|
|
@@ -464,7 +568,7 @@ describe('VipBonusUtils', () => {
|
|
|
464
568
|
// fast forward into reward 8 claiming interval
|
|
465
569
|
fastForward = 7;
|
|
466
570
|
mockdatetime(startDate.add(cadence * fastForward, 'seconds').toDate());
|
|
467
|
-
updatedStatusList = issuances.map(
|
|
571
|
+
updatedStatusList = issuances.map(issuance => updateBonusIssuanceStatus(issuance, cancelledAt, dayjs()));
|
|
468
572
|
|
|
469
573
|
updatedStatusList.forEach((issuance, index) => {
|
|
470
574
|
if (claimed.includes(index + 1)) {
|
|
@@ -21,19 +21,26 @@ export function getReloadAvailableDate(activationTime: Dayjs | null, cadence: nu
|
|
|
21
21
|
return activationTime.add(cadence * (index - 1), 'second').toDate();
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export function getReloadExpiryDate(
|
|
24
|
+
export function getReloadExpiryDate(
|
|
25
|
+
activationTime: Dayjs | null,
|
|
26
|
+
cadence: number,
|
|
27
|
+
expiryPerOccurrence: number,
|
|
28
|
+
index: number,
|
|
29
|
+
createdAt: Dayjs,
|
|
30
|
+
firstOccurrenceActivationPeriod: number,
|
|
31
|
+
) {
|
|
25
32
|
const availableDate = getReloadAvailableDate(activationTime, cadence, index, createdAt);
|
|
26
33
|
|
|
27
34
|
if (index === 1) {
|
|
28
35
|
return dayjs(createdAt).add(firstOccurrenceActivationPeriod, 'hours').add(expiryPerOccurrence, 'second').toDate();
|
|
29
36
|
}
|
|
30
|
-
|
|
37
|
+
|
|
31
38
|
if (!availableDate) {
|
|
32
|
-
return null
|
|
39
|
+
return null;
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
const result = dayjs(availableDate).add(expiryPerOccurrence, 'second').toDate();
|
|
36
|
-
return result
|
|
43
|
+
return result;
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
export function deriveBonusIssuances(vipBonus: VipBonusPartial) {
|
|
@@ -42,7 +49,7 @@ export function deriveBonusIssuances(vipBonus: VipBonusPartial) {
|
|
|
42
49
|
const bonusCreatedAt = dayjs(vipBonus.createdAt);
|
|
43
50
|
const now = dayjs();
|
|
44
51
|
|
|
45
|
-
const firstClaim = claims?.find(
|
|
52
|
+
const firstClaim = claims?.find(claim => claim.occurrenceIndex == 1);
|
|
46
53
|
let activationTime: Dayjs | null = null;
|
|
47
54
|
const maxBonusActivationTime = bonusCreatedAt.add(vipBonus.firstOccurrenceActivationPeriod ?? 0, 'hours');
|
|
48
55
|
|
|
@@ -52,11 +59,18 @@ export function deriveBonusIssuances(vipBonus: VipBonusPartial) {
|
|
|
52
59
|
activationTime = maxBonusActivationTime;
|
|
53
60
|
}
|
|
54
61
|
|
|
55
|
-
return range(1, vipBonus.occurrence + 1).map(
|
|
56
|
-
const claim = claims?.find(
|
|
62
|
+
return range(1, vipBonus.occurrence + 1).map(occurrenceIndex => {
|
|
63
|
+
const claim = claims?.find(claim => claim.occurrenceIndex == occurrenceIndex);
|
|
57
64
|
const expiryDate =
|
|
58
65
|
vipBonus.type === VipBonusType.RELOADED
|
|
59
|
-
? getReloadExpiryDate(
|
|
66
|
+
? getReloadExpiryDate(
|
|
67
|
+
activationTime,
|
|
68
|
+
vipBonus.cadence!,
|
|
69
|
+
vipBonus.expiryPerOccurrence ?? 0,
|
|
70
|
+
occurrenceIndex,
|
|
71
|
+
bonusCreatedAt,
|
|
72
|
+
vipBonus.firstOccurrenceActivationPeriod ?? 0,
|
|
73
|
+
)?.toISOString()
|
|
60
74
|
: vipBonus.endAt;
|
|
61
75
|
const availableDate =
|
|
62
76
|
vipBonus.type === VipBonusType.RELOADED
|
|
@@ -65,18 +79,16 @@ export function deriveBonusIssuances(vipBonus: VipBonusPartial) {
|
|
|
65
79
|
return updateBonusIssuanceStatus(
|
|
66
80
|
{
|
|
67
81
|
currency,
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
.decimalPlaces(8, BigNumber.ROUND_DOWN)
|
|
71
|
-
.toFixed(),
|
|
82
|
+
amount: claim?.amount,
|
|
83
|
+
bonusAmountUsd: new BigNumber(vipBonus.bonusAmountUsd).dividedBy(vipBonus.occurrence).decimalPlaces(8, BigNumber.ROUND_DOWN).toFixed(),
|
|
72
84
|
occurrenceIndex,
|
|
73
85
|
expiryDate,
|
|
74
86
|
availableDate,
|
|
75
87
|
status: claim ? VipBonusIssuanceStatus.CLAIMED : null,
|
|
76
|
-
createdAt:
|
|
88
|
+
createdAt: claim?.createdAt,
|
|
77
89
|
},
|
|
78
90
|
vipBonus.cancelledAt ? new Date(vipBonus.cancelledAt) : null,
|
|
79
|
-
now
|
|
91
|
+
now,
|
|
80
92
|
);
|
|
81
93
|
});
|
|
82
94
|
}
|