@driveflux/api-functions 1.0.116 → 1.0.118
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/dist/auth/confirm.js +24 -24
- package/dist/auth/consent.js +27 -22
- package/dist/auth/emails.js +13 -12
- package/dist/auth/formatter.js +5 -5
- package/dist/auth/otp.js +50 -66
- package/dist/auth/register.js +35 -48
- package/dist/auth/tokens.js +55 -58
- package/dist/auth/verifications.js +52 -53
- package/dist/constants.js +1 -0
- package/dist/create-logger.js +2 -1
- package/dist/mailjet/calls/manage-contacts-in-list.js +6 -5
- package/dist/mailjet/calls/manage-subscription-status.js +5 -4
- package/dist/mailjet/calls/request-service.js +6 -7
- package/dist/mailjet/refresh-email-preferences.js +12 -11
- package/dist/mailjet/set-contact.js +12 -11
- package/dist/mailjet/types.js +2 -1
- package/dist/mailjet/utils/convert-to-array.js +6 -8
- package/dist/mailjet/utils/extract-email-preferences.js +15 -14
- package/dist/mailjet/utils/lists.js +8 -7
- package/dist/mailjet/utils/update-email-references.js +15 -16
- package/dist/notion/client.js +19 -22
- package/dist/notion/helpful.js +9 -6
- package/dist/notion/schemas/block.js +48 -42
- package/dist/notion/schemas/common.js +14 -9
- package/dist/notion/schemas/database.js +60 -62
- package/dist/notion/schemas/emoji.js +2 -1
- package/dist/notion/schemas/file.js +9 -9
- package/dist/notion/schemas/kb.js +6 -5
- package/dist/notion/schemas/page.js +61 -72
- package/dist/notion/schemas/parent.js +5 -4
- package/dist/notion/schemas/user.js +19 -18
- package/dist/reservation/agree.js +3 -2
- package/dist/reservation/checks.js +4 -3
- package/dist/reservation/display-vehicle.d.ts +4 -0
- package/dist/reservation/display-vehicle.d.ts.map +1 -1
- package/dist/reservation/display-vehicle.js +83 -73
- package/dist/reservation/ensure-user-billing-address.js +11 -9
- package/dist/reservation/fetch-or-create.js +56 -49
- package/dist/reservation/invoice.js +88 -77
- package/dist/reservation/payer.js +6 -5
- package/dist/reservation/payment-intent-sync.js +6 -4
- package/dist/reservation/reserve.js +4 -3
- package/dist/reservation/types.js +2 -1
- package/dist/reservation/vehicle.js +16 -13
- package/dist/slack.js +29 -24
- package/dist/validation.js +79 -77
- package/dist/vehicle/vehicle-pricing/constants.js +19 -22
- package/dist/vehicle/vehicle-pricing/index.js +42 -28
- package/dist/vehicle/vehicle-pricing/types.js +2 -1
- package/package.json +8 -8
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { config } from '@driveflux/config/backend';
|
|
2
2
|
import { loadCoupon, PROBLEM_APPLICABLE_NOT_FOUND } from '@driveflux/coupon';
|
|
3
|
-
import { prisma } from '@driveflux/db';
|
|
3
|
+
import { prisma, } from '@driveflux/db';
|
|
4
4
|
import { generateId } from '@driveflux/db/id';
|
|
5
5
|
import { EMPTY_BILLING_ADDRESS } from '@driveflux/db/models/other';
|
|
6
|
-
import { INVOICE_LINE_CYCLE, INVOICE_LINE_DEPOSIT, INVOICE_LINE_OTHER, INVOICE_LINE_RESERVATION_FEE, PURPOSE_FULL_BOOKING, PURPOSE_RESERVATION } from '@driveflux/db/models/subscription';
|
|
6
|
+
import { INVOICE_LINE_CYCLE, INVOICE_LINE_DEPOSIT, INVOICE_LINE_OTHER, INVOICE_LINE_RESERVATION_FEE, PURPOSE_FULL_BOOKING, PURPOSE_RESERVATION, } from '@driveflux/db/models/subscription';
|
|
7
7
|
import { userName } from '@driveflux/db/models/user';
|
|
8
8
|
import { vehicleName } from '@driveflux/db/models/vehicle';
|
|
9
9
|
import { biller, coupons } from '@driveflux/engine';
|
|
@@ -16,15 +16,16 @@ import { isAfter } from 'date-fns/isAfter';
|
|
|
16
16
|
import { subMinutes } from 'date-fns/subMinutes';
|
|
17
17
|
import { createScopedLogger } from '../create-logger.js';
|
|
18
18
|
const log = createScopedLogger('reservation:invoice');
|
|
19
|
-
export const updateReservationInvoiceIfNeeded = async (oldReservationInvoice, newParams)=>{
|
|
19
|
+
export const updateReservationInvoiceIfNeeded = async (oldReservationInvoice, newParams) => {
|
|
20
20
|
const couponIsDifferent = oldReservationInvoice.couponCode !== newParams.couponCode;
|
|
21
|
-
if (!couponIsDifferent &&
|
|
21
|
+
if (!couponIsDifferent &&
|
|
22
|
+
oldReservationInvoice.stripePaymentIntentId === newParams.paymentIntentId) {
|
|
22
23
|
return new Ok(oldReservationInvoice);
|
|
23
24
|
}
|
|
24
25
|
// If the coupon or payment intent are differnt we should update the invoice
|
|
25
26
|
let update = {
|
|
26
27
|
stripePaymentIntentId: newParams.paymentIntentId,
|
|
27
|
-
couponCode: newParams.couponCode
|
|
28
|
+
couponCode: newParams.couponCode,
|
|
28
29
|
};
|
|
29
30
|
// If the coupon is different, we need to apply the coupon to the invoice
|
|
30
31
|
if (couponIsDifferent) {
|
|
@@ -32,56 +33,63 @@ export const updateReservationInvoiceIfNeeded = async (oldReservationInvoice, ne
|
|
|
32
33
|
const result = await coupons.applyCouponToUnsavedInvoice(newParams.couponCode, oldReservationInvoice);
|
|
33
34
|
if (result.ok) {
|
|
34
35
|
const { discounts, ...rest } = result.val;
|
|
35
|
-
const toDisconnect = discounts
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
const toDisconnect = discounts
|
|
37
|
+
? oldReservationInvoice.discountIds?.filter((id) => !discounts.connect?.some((d) => d.id === id))
|
|
38
|
+
: undefined;
|
|
39
|
+
const disconnectClauses = toDisconnect?.length
|
|
40
|
+
? {
|
|
41
|
+
disconnect: toDisconnect.map((id) => ({ id })),
|
|
42
|
+
}
|
|
43
|
+
: undefined;
|
|
41
44
|
update = {
|
|
42
45
|
...update,
|
|
43
46
|
...rest,
|
|
44
|
-
...discounts || disconnectClauses
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
...(discounts || disconnectClauses
|
|
48
|
+
? {
|
|
49
|
+
discounts: {
|
|
50
|
+
...(discounts || {}),
|
|
51
|
+
...(disconnectClauses || {}),
|
|
52
|
+
},
|
|
48
53
|
}
|
|
49
|
-
|
|
54
|
+
: {}),
|
|
50
55
|
metadata: {
|
|
51
56
|
...update.metadata,
|
|
52
|
-
couponCode: newParams.couponCode
|
|
57
|
+
couponCode: newParams.couponCode,
|
|
53
58
|
},
|
|
54
59
|
providerMetadata: {
|
|
55
60
|
...update.providerMetadata,
|
|
56
|
-
couponCode: newParams.couponCode
|
|
57
|
-
}
|
|
61
|
+
couponCode: newParams.couponCode,
|
|
62
|
+
},
|
|
58
63
|
};
|
|
59
64
|
}
|
|
60
65
|
if (result.err && result.val.code !== PROBLEM_APPLICABLE_NOT_FOUND) {
|
|
61
66
|
return result;
|
|
62
67
|
}
|
|
63
|
-
}
|
|
68
|
+
}
|
|
69
|
+
else if (oldReservationInvoice.discountIds.length) {
|
|
64
70
|
// No discounts, so we disconnect all of them
|
|
65
71
|
update = {
|
|
66
72
|
discounts: {
|
|
67
|
-
disconnect: oldReservationInvoice.discountIds.map((id)=>({
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
73
|
+
disconnect: oldReservationInvoice.discountIds.map((id) => ({
|
|
74
|
+
id,
|
|
75
|
+
})),
|
|
76
|
+
},
|
|
71
77
|
};
|
|
72
78
|
}
|
|
73
79
|
}
|
|
74
80
|
let updated = await wrapInResult(biller.updateInvoice(oldReservationInvoice.id, update));
|
|
75
81
|
// If the invoice was locked due to pending status and we're more than 1 minute old, we unlock it
|
|
76
82
|
if (updated.err && updated.val.code === 'invoice_pending') {
|
|
77
|
-
if (oldReservationInvoice.lockedAt &&
|
|
83
|
+
if ((oldReservationInvoice.lockedAt &&
|
|
84
|
+
isAfter(oldReservationInvoice.lockedAt, subMinutes(new Date(), 1))) ||
|
|
85
|
+
!oldReservationInvoice.lockedAt) {
|
|
78
86
|
updated = await wrapInResult(biller.updateInvoice(oldReservationInvoice.id, {
|
|
79
87
|
...update,
|
|
80
88
|
locked: false,
|
|
81
89
|
lockedAt: null,
|
|
82
90
|
lockReason: null,
|
|
83
91
|
unlockAt: null,
|
|
84
|
-
status: 'draft'
|
|
92
|
+
status: 'draft',
|
|
85
93
|
}));
|
|
86
94
|
}
|
|
87
95
|
}
|
|
@@ -90,7 +98,7 @@ export const updateReservationInvoiceIfNeeded = async (oldReservationInvoice, ne
|
|
|
90
98
|
}
|
|
91
99
|
return new Ok(updated.val);
|
|
92
100
|
};
|
|
93
|
-
export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mileagePackage, referralCode, reservationId, paymentIntentId, freeReservation, freeReservationReason, analytics, vehicle, payer, subscribingUser, fullBooking })=>{
|
|
101
|
+
export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mileagePackage, referralCode, reservationId, paymentIntentId, freeReservation, freeReservationReason, analytics, vehicle, payer, subscribingUser, fullBooking, }) => {
|
|
94
102
|
if (freeReservation && !fullBooking) {
|
|
95
103
|
// It's a free reservation, so we don't need to add a coupon code
|
|
96
104
|
return await wrapInResult(biller.createInvoice(getInvoiceCreateDetails({
|
|
@@ -102,17 +110,21 @@ export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mi
|
|
|
102
110
|
freeReservation,
|
|
103
111
|
freeReservationReason,
|
|
104
112
|
analytics,
|
|
105
|
-
reservationId
|
|
113
|
+
reservationId,
|
|
106
114
|
})));
|
|
107
115
|
}
|
|
108
116
|
let finalCouponCode = couponCode;
|
|
109
117
|
// If we don't have a reservation coupon ID, we apply the referral discount if any
|
|
110
|
-
const referral = referralCode &&
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
118
|
+
const referral = referralCode &&
|
|
119
|
+
(await prisma.referral.findUnique({
|
|
120
|
+
where: {
|
|
121
|
+
id: referralCode,
|
|
122
|
+
},
|
|
123
|
+
}));
|
|
124
|
+
if (!finalCouponCode &&
|
|
125
|
+
referral &&
|
|
126
|
+
referral.discountToReceiverCouponId &&
|
|
127
|
+
referral.discountToReceiverCouponApplicationName === 'reservationFee') {
|
|
116
128
|
const referralCoupon = await loadCoupon(referral.discountToReceiverCouponId);
|
|
117
129
|
if (referralCoupon) {
|
|
118
130
|
finalCouponCode = referralCoupon.code;
|
|
@@ -131,8 +143,8 @@ export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mi
|
|
|
131
143
|
freeReservation,
|
|
132
144
|
freeReservationReason,
|
|
133
145
|
analytics,
|
|
134
|
-
reservationId
|
|
135
|
-
})
|
|
146
|
+
reservationId,
|
|
147
|
+
}),
|
|
136
148
|
};
|
|
137
149
|
if (fullBooking) {
|
|
138
150
|
invoiceCreateDetails.subscriptionPurpose = PURPOSE_FULL_BOOKING;
|
|
@@ -144,32 +156,31 @@ export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mi
|
|
|
144
156
|
{
|
|
145
157
|
amount: vehiclePrice,
|
|
146
158
|
chargingFor: INVOICE_LINE_CYCLE,
|
|
147
|
-
description: `First payment for ${vehicleName(vehicle)}
|
|
159
|
+
description: `First payment for ${vehicleName(vehicle)}`,
|
|
148
160
|
},
|
|
149
161
|
{
|
|
150
162
|
amount: vehiclePrice * config.taxRate,
|
|
151
163
|
chargingFor: INVOICE_LINE_OTHER,
|
|
152
|
-
description: `Processing fee for ${vehicleName(vehicle)}
|
|
164
|
+
description: `Processing fee for ${vehicleName(vehicle)}`,
|
|
153
165
|
},
|
|
154
166
|
{
|
|
155
167
|
amount: vehiclePrice,
|
|
156
168
|
description: `Deposit for ${vehicleName(vehicle)}`,
|
|
157
|
-
chargingFor: INVOICE_LINE_DEPOSIT
|
|
158
|
-
}
|
|
169
|
+
chargingFor: INVOICE_LINE_DEPOSIT,
|
|
170
|
+
},
|
|
159
171
|
];
|
|
160
|
-
}
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
161
174
|
invoiceCreateDetails.lines = [
|
|
162
175
|
{
|
|
163
176
|
amount: reservationAmount,
|
|
164
177
|
description: `Reservation fee for ${vehicleName(vehicle)}`,
|
|
165
|
-
chargingFor: INVOICE_LINE_RESERVATION_FEE
|
|
166
|
-
}
|
|
178
|
+
chargingFor: INVOICE_LINE_RESERVATION_FEE,
|
|
179
|
+
},
|
|
167
180
|
];
|
|
168
181
|
}
|
|
169
182
|
if (finalCouponCode) {
|
|
170
|
-
log.debug({
|
|
171
|
-
finalCouponCode
|
|
172
|
-
}, 'Applying coupon code to invoice');
|
|
183
|
+
log.debug({ finalCouponCode }, 'Applying coupon code to invoice');
|
|
173
184
|
const withCoupon = await coupons.applyCouponToUnsavedInvoice(finalCouponCode, invoiceCreateDetails, 'reservationFee', {
|
|
174
185
|
subscriptionPlans: plan,
|
|
175
186
|
subscriptionMileagePackages: mileagePackage,
|
|
@@ -177,25 +188,24 @@ export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mi
|
|
|
177
188
|
vehicleMake: vehicle.make,
|
|
178
189
|
userId: subscribingUser.id,
|
|
179
190
|
businessId: payer.object === 'business' ? payer.id : undefined,
|
|
180
|
-
vehicleType: vehicle.type
|
|
191
|
+
vehicleType: vehicle.type,
|
|
181
192
|
});
|
|
182
|
-
if (withCoupon.err &&
|
|
193
|
+
if (withCoupon.err &&
|
|
194
|
+
withCoupon.val.code !== PROBLEM_APPLICABLE_NOT_FOUND) {
|
|
183
195
|
return withCoupon;
|
|
184
196
|
}
|
|
185
|
-
log.debug({
|
|
186
|
-
couponUpdates: withCoupon.val
|
|
187
|
-
}, 'Coupon applied to invoice');
|
|
197
|
+
log.debug({ couponUpdates: withCoupon.val }, 'Coupon applied to invoice');
|
|
188
198
|
if (withCoupon.ok) {
|
|
189
199
|
invoiceCreateDetails = {
|
|
190
200
|
...withCoupon.val,
|
|
191
201
|
metadata: {
|
|
192
202
|
...withCoupon.val.metadata,
|
|
193
|
-
couponCode: finalCouponCode
|
|
203
|
+
couponCode: finalCouponCode,
|
|
194
204
|
},
|
|
195
205
|
providerMetadata: {
|
|
196
206
|
...withCoupon.val.providerMetadata,
|
|
197
|
-
couponCode: finalCouponCode
|
|
198
|
-
}
|
|
207
|
+
couponCode: finalCouponCode,
|
|
208
|
+
},
|
|
199
209
|
};
|
|
200
210
|
}
|
|
201
211
|
}
|
|
@@ -207,7 +217,9 @@ export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mi
|
|
|
207
217
|
if (paymentIntentResult.err) {
|
|
208
218
|
return new Err(makeProblem(PROBLEM_EXTERNAL, 'Payment intent not found'));
|
|
209
219
|
}
|
|
210
|
-
if (paymentIntentResult.val.amount !==
|
|
220
|
+
if (paymentIntentResult.val.amount !==
|
|
221
|
+
currency(biller.getCorrectedInvoiceData(invoiceCreateDetails).total)
|
|
222
|
+
.intValue) {
|
|
211
223
|
return new Err(makeProblem(PROBLEM_EXTERNAL, 'Payment intent amount does not match invoice amount'));
|
|
212
224
|
}
|
|
213
225
|
}
|
|
@@ -215,15 +227,15 @@ export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mi
|
|
|
215
227
|
...invoiceCreateDetails,
|
|
216
228
|
providerMetadata: {
|
|
217
229
|
...invoiceCreateDetails.providerMetadata,
|
|
218
|
-
invoiceId: invoiceCreateDetails.id
|
|
219
|
-
}
|
|
230
|
+
invoiceId: invoiceCreateDetails.id,
|
|
231
|
+
},
|
|
220
232
|
}));
|
|
221
233
|
if (result.err) {
|
|
222
234
|
return result;
|
|
223
235
|
}
|
|
224
236
|
return new Ok(result.val);
|
|
225
237
|
};
|
|
226
|
-
const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId, vehicle, plan, mileagePackage, couponCode, paymentIntentId, freeReservation, freeReservationReason, analytics, reservationId })=>{
|
|
238
|
+
const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId, vehicle, plan, mileagePackage, couponCode, paymentIntentId, freeReservation, freeReservationReason, analytics, reservationId, }) => {
|
|
227
239
|
return {
|
|
228
240
|
id: invoiceId || generateId('Invoice'),
|
|
229
241
|
taxPercentage: 0,
|
|
@@ -239,13 +251,15 @@ const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId
|
|
|
239
251
|
description: 'Reservation fee for a FLUX subscription',
|
|
240
252
|
footer: `Invoice for a FLUX subscription reservation. Due by ${format(date ?? new Date())}`,
|
|
241
253
|
invoiceUrl: `${config.appUrl}/invoice-preview/${invoiceId}`,
|
|
242
|
-
...reservationDiscountId
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
254
|
+
...(reservationDiscountId
|
|
255
|
+
? {
|
|
256
|
+
discounts: {
|
|
257
|
+
connect: {
|
|
258
|
+
id: reservationDiscountId,
|
|
259
|
+
},
|
|
260
|
+
},
|
|
247
261
|
}
|
|
248
|
-
|
|
262
|
+
: {}),
|
|
249
263
|
lines: [],
|
|
250
264
|
subscriptionDetails: {
|
|
251
265
|
vehicleId: vehicle.id,
|
|
@@ -254,7 +268,7 @@ const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId
|
|
|
254
268
|
variant: vehicle.variant,
|
|
255
269
|
year: vehicle.year,
|
|
256
270
|
plan: plan,
|
|
257
|
-
mileagePackage: mileagePackage
|
|
271
|
+
mileagePackage: mileagePackage,
|
|
258
272
|
},
|
|
259
273
|
// Legacy field:
|
|
260
274
|
stripePaymentIntentId: paymentIntentId,
|
|
@@ -264,18 +278,14 @@ const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId
|
|
|
264
278
|
mileagePackage,
|
|
265
279
|
vehicleId: vehicle.id,
|
|
266
280
|
vehicleName: vehicleName(vehicle),
|
|
267
|
-
...reservationId ? {
|
|
268
|
-
|
|
269
|
-
} : {},
|
|
270
|
-
...couponCode ? {
|
|
271
|
-
couponCode
|
|
272
|
-
} : {}
|
|
281
|
+
...(reservationId ? { reservationId } : {}),
|
|
282
|
+
...(couponCode ? { couponCode } : {}),
|
|
273
283
|
},
|
|
274
284
|
autoRetry: {
|
|
275
285
|
enabled: false,
|
|
276
286
|
interval: 0,
|
|
277
287
|
maxAttempts: 0,
|
|
278
|
-
attempts: 0
|
|
288
|
+
attempts: 0,
|
|
279
289
|
},
|
|
280
290
|
metadata: {
|
|
281
291
|
purpose: PURPOSE_RESERVATION,
|
|
@@ -284,10 +294,11 @@ const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId
|
|
|
284
294
|
plan,
|
|
285
295
|
mileagePackage,
|
|
286
296
|
couponCode,
|
|
287
|
-
...freeReservation && freeReservationReason
|
|
288
|
-
freeReservationReason
|
|
289
|
-
|
|
290
|
-
analytics
|
|
291
|
-
}
|
|
297
|
+
...(freeReservation && freeReservationReason
|
|
298
|
+
? { freeReservationReason }
|
|
299
|
+
: {}),
|
|
300
|
+
analytics,
|
|
301
|
+
},
|
|
292
302
|
};
|
|
293
303
|
};
|
|
304
|
+
//# sourceMappingURL=invoice.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { prisma } from '@driveflux/db';
|
|
2
|
-
import { makeProblem, PROBLEM_CONDITION_FAILED, PROBLEM_NOT_FOUND } from '@driveflux/problem';
|
|
2
|
+
import { makeProblem, PROBLEM_CONDITION_FAILED, PROBLEM_NOT_FOUND, } from '@driveflux/problem';
|
|
3
3
|
import { Err, Ok } from '@driveflux/result';
|
|
4
|
-
export const getPayer = async ({ subscribingUser, asBusiness })=>{
|
|
4
|
+
export const getPayer = async ({ subscribingUser, asBusiness, }) => {
|
|
5
5
|
let business = null;
|
|
6
6
|
let payer = subscribingUser;
|
|
7
7
|
if (asBusiness) {
|
|
@@ -11,8 +11,8 @@ export const getPayer = async ({ subscribingUser, asBusiness })=>{
|
|
|
11
11
|
// load business
|
|
12
12
|
business = await prisma.business.findUnique({
|
|
13
13
|
where: {
|
|
14
|
-
id: subscribingUser.businessId
|
|
15
|
-
}
|
|
14
|
+
id: subscribingUser.businessId,
|
|
15
|
+
},
|
|
16
16
|
});
|
|
17
17
|
if (!business) {
|
|
18
18
|
return new Err(makeProblem(PROBLEM_NOT_FOUND, `The business ${subscribingUser.businessId} was not found.`));
|
|
@@ -26,7 +26,7 @@ export const getPayer = async ({ subscribingUser, asBusiness })=>{
|
|
|
26
26
|
}
|
|
27
27
|
return new Ok(payer);
|
|
28
28
|
};
|
|
29
|
-
const checkPayerObjectSanity = (subscriber)=>{
|
|
29
|
+
const checkPayerObjectSanity = (subscriber) => {
|
|
30
30
|
if (!subscriber.email) {
|
|
31
31
|
return new Err(makeProblem(PROBLEM_CONDITION_FAILED, `Subscriber ${subscriber.id} has no email. Please add a verified email first.`));
|
|
32
32
|
}
|
|
@@ -35,3 +35,4 @@ const checkPayerObjectSanity = (subscriber)=>{
|
|
|
35
35
|
}
|
|
36
36
|
return new Ok(true);
|
|
37
37
|
};
|
|
38
|
+
//# sourceMappingURL=payer.js.map
|
|
@@ -3,18 +3,20 @@ import { makeProblem, PROBLEM_EXTERNAL } from '@driveflux/problem';
|
|
|
3
3
|
import { Err, Ok } from '@driveflux/result';
|
|
4
4
|
import { createScopedLogger } from '../create-logger.js';
|
|
5
5
|
const log = createScopedLogger('reservation:payment-intent-sync');
|
|
6
|
-
export const ensurePaymentIntentIdIsSynced = async (invoice, paymentIntentId)=>{
|
|
6
|
+
export const ensurePaymentIntentIdIsSynced = async (invoice, paymentIntentId) => {
|
|
7
7
|
const stripe = biller.getPaymentProvider('stripe').getStripe();
|
|
8
8
|
try {
|
|
9
9
|
await stripe.paymentIntents.update(paymentIntentId, {
|
|
10
10
|
metadata: {
|
|
11
11
|
...invoice.providerMetadata,
|
|
12
|
-
invoiceId: invoice.id
|
|
13
|
-
}
|
|
12
|
+
invoiceId: invoice.id,
|
|
13
|
+
},
|
|
14
14
|
});
|
|
15
15
|
return new Ok(true);
|
|
16
|
-
}
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
17
18
|
log.error(error, 'Error updating payment intent metadata');
|
|
18
19
|
return new Err(makeProblem(PROBLEM_EXTERNAL, 'Error updating payment intent metadata'));
|
|
19
20
|
}
|
|
20
21
|
};
|
|
22
|
+
//# sourceMappingURL=payment-intent-sync.js.map
|
|
@@ -7,14 +7,14 @@ import { fetchOrCreateReservation } from './fetch-or-create.js';
|
|
|
7
7
|
import { getPayer } from './payer.js';
|
|
8
8
|
import { ensurePaymentIntentIdIsSynced } from './payment-intent-sync.js';
|
|
9
9
|
import { getVehicle } from './vehicle.js';
|
|
10
|
-
const processBody = (body)=>{
|
|
10
|
+
const processBody = (body) => {
|
|
11
11
|
// Switch mileage package
|
|
12
12
|
if (body.plan === 'plan1' || body.plan === 'planWeekly') {
|
|
13
13
|
body.mileagePackage = 'unlimited';
|
|
14
14
|
}
|
|
15
15
|
return body;
|
|
16
16
|
};
|
|
17
|
-
export const reserveVehicle = async (vehicleId, unprocessed)=>{
|
|
17
|
+
export const reserveVehicle = async (vehicleId, unprocessed) => {
|
|
18
18
|
const body = processBody(unprocessed);
|
|
19
19
|
// Agree to terms if not done yet
|
|
20
20
|
const agreeToTermsResult = await handleAgreeToTerms(body);
|
|
@@ -49,7 +49,7 @@ export const reserveVehicle = async (vehicleId, unprocessed)=>{
|
|
|
49
49
|
const reservationResult = await fetchOrCreateReservation({
|
|
50
50
|
vehicle,
|
|
51
51
|
payer,
|
|
52
|
-
body
|
|
52
|
+
body,
|
|
53
53
|
});
|
|
54
54
|
if (reservationResult.err) {
|
|
55
55
|
return reservationResult;
|
|
@@ -65,3 +65,4 @@ export const reserveVehicle = async (vehicleId, unprocessed)=>{
|
|
|
65
65
|
}
|
|
66
66
|
return new Ok(reservation);
|
|
67
67
|
};
|
|
68
|
+
//# sourceMappingURL=reserve.js.map
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {};
|
|
2
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -4,19 +4,21 @@ import { makeProblem, PROBLEM_NOT_FOUND } from '@driveflux/problem';
|
|
|
4
4
|
import { Err, Ok } from '@driveflux/result';
|
|
5
5
|
import { checkIfVehicleIsAvailableForReservation } from './checks.js';
|
|
6
6
|
import { createVehicleFromDisplayVehicle } from './display-vehicle.js';
|
|
7
|
-
export const getVehicle = async (id, { selectedColor, plan, requestUser }, requesterAbility)=>{
|
|
8
|
-
const vehicle = id.startsWith('DV_')
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
export const getVehicle = async (id, { selectedColor, plan, requestUser, }, requesterAbility) => {
|
|
8
|
+
const vehicle = id.startsWith('DV_')
|
|
9
|
+
? await createVehicleFromDisplayVehicle(id, selectedColor || undefined)
|
|
10
|
+
: await prisma.vehicle.findUnique({
|
|
11
|
+
where: {
|
|
12
|
+
id,
|
|
13
|
+
},
|
|
14
|
+
include: {
|
|
15
|
+
host: {
|
|
16
|
+
select: {
|
|
17
|
+
id: true,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
});
|
|
20
22
|
if (!vehicle) {
|
|
21
23
|
return new Err(makeProblem(PROBLEM_NOT_FOUND, 'Vehicle not found'));
|
|
22
24
|
}
|
|
@@ -27,3 +29,4 @@ export const getVehicle = async (id, { selectedColor, plan, requestUser }, reque
|
|
|
27
29
|
}
|
|
28
30
|
return new Ok(vehicle);
|
|
29
31
|
};
|
|
32
|
+
//# sourceMappingURL=vehicle.js.map
|
package/dist/slack.js
CHANGED
|
@@ -10,11 +10,12 @@ const slackBlocks = global.__slackBlocks;
|
|
|
10
10
|
/**
|
|
11
11
|
*
|
|
12
12
|
* @deprecated Use slackLater instead and commitSlack to commit
|
|
13
|
-
*/
|
|
13
|
+
*/
|
|
14
|
+
export const slack = async (message, channel = config.slack.defaultChannelId) => {
|
|
14
15
|
return await enhancedFetch('https://slack.com/api/chat.postMessage', {
|
|
15
16
|
method: 'POST',
|
|
16
17
|
headers: {
|
|
17
|
-
Authorization: `Bearer ${config.slack.token}
|
|
18
|
+
Authorization: `Bearer ${config.slack.token}`,
|
|
18
19
|
},
|
|
19
20
|
body: JSON.stringify({
|
|
20
21
|
channel,
|
|
@@ -23,20 +24,23 @@ const slackBlocks = global.__slackBlocks;
|
|
|
23
24
|
type: 'section',
|
|
24
25
|
text: {
|
|
25
26
|
type: 'mrkdwn',
|
|
26
|
-
text: message
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
]
|
|
30
|
-
})
|
|
27
|
+
text: message,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
}),
|
|
31
32
|
});
|
|
32
33
|
};
|
|
33
|
-
export const getSlackBlocks = (channel)=>channel ? slackBlocks.get(channel) : slackBlocks;
|
|
34
|
+
export const getSlackBlocks = (channel) => channel ? slackBlocks.get(channel) : slackBlocks;
|
|
34
35
|
/**
|
|
35
36
|
* Naive implementation, however, for now (uncrowded serverless env), this works
|
|
36
37
|
* @param blocks
|
|
37
38
|
* @param channel
|
|
38
|
-
*/
|
|
39
|
-
|
|
39
|
+
*/
|
|
40
|
+
export function slackLater(blocks, channel) {
|
|
41
|
+
const targetChannel = (config.appEnv === 'production'
|
|
42
|
+
? channel
|
|
43
|
+
: config.slack.defaultChannelId) || config.slack.defaultChannelId;
|
|
40
44
|
if (!targetChannel || !blocks) {
|
|
41
45
|
return;
|
|
42
46
|
}
|
|
@@ -46,13 +50,15 @@ export const getSlackBlocks = (channel)=>channel ? slackBlocks.get(channel) : sl
|
|
|
46
50
|
type: 'section',
|
|
47
51
|
text: {
|
|
48
52
|
type: 'mrkdwn',
|
|
49
|
-
text: blocks
|
|
50
|
-
}
|
|
53
|
+
text: blocks,
|
|
54
|
+
},
|
|
51
55
|
});
|
|
52
|
-
}
|
|
56
|
+
}
|
|
57
|
+
else if (!Array.isArray(blocks)) {
|
|
53
58
|
messages.add(blocks);
|
|
54
|
-
}
|
|
55
|
-
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
for (const b of blocks) {
|
|
56
62
|
messages.add(b);
|
|
57
63
|
}
|
|
58
64
|
}
|
|
@@ -63,22 +69,22 @@ export async function sendSlackMessages(channel, blocks) {
|
|
|
63
69
|
return await enhancedFetch('https://slack.com/api/chat.postMessage', {
|
|
64
70
|
method: 'POST',
|
|
65
71
|
headers: {
|
|
66
|
-
Authorization: `Bearer ${config.slack.token}
|
|
72
|
+
Authorization: `Bearer ${config.slack.token}`,
|
|
67
73
|
},
|
|
68
74
|
body: JSON.stringify({
|
|
69
75
|
channel: targetChannel,
|
|
70
|
-
blocks: Array.from(blocks)
|
|
71
|
-
})
|
|
76
|
+
blocks: Array.from(blocks),
|
|
77
|
+
}),
|
|
72
78
|
});
|
|
73
79
|
}
|
|
74
|
-
export const commitSlack = ()=>{
|
|
80
|
+
export const commitSlack = () => {
|
|
75
81
|
if (!slackBlocks.size) {
|
|
76
82
|
return;
|
|
77
83
|
}
|
|
78
84
|
const channels = slackBlocks.keys();
|
|
79
85
|
let i = 1;
|
|
80
86
|
const baseUrl = config.appEnv === 'development' ? config.tunnelUrl : config.appUrl;
|
|
81
|
-
for (const channel of channels){
|
|
87
|
+
for (const channel of channels) {
|
|
82
88
|
const blocks = slackBlocks.get(channel);
|
|
83
89
|
if (!blocks?.size) {
|
|
84
90
|
continue;
|
|
@@ -88,13 +94,12 @@ export const commitSlack = ()=>{
|
|
|
88
94
|
name: TASK_COMMIT_SLACK_CHANNEL,
|
|
89
95
|
metadata: {
|
|
90
96
|
channel,
|
|
91
|
-
blocks: [
|
|
92
|
-
...blocks
|
|
93
|
-
]
|
|
97
|
+
blocks: [...blocks],
|
|
94
98
|
},
|
|
95
99
|
taskHandlerUrl: `${baseUrl || config.appUrl}/api/hooks/slack-pipeline`,
|
|
96
|
-
scheduledAt: addSeconds(new Date(), i++)
|
|
100
|
+
scheduledAt: addSeconds(new Date(), i++),
|
|
97
101
|
});
|
|
98
102
|
}
|
|
99
103
|
slackBlocks.clear();
|
|
100
104
|
};
|
|
105
|
+
//# sourceMappingURL=slack.js.map
|