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