@driveflux/api-functions 1.0.31 → 1.0.33
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 +29 -24
- 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 +34 -42
- 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 +7 -6
- package/dist/reservation/checks.js +4 -3
- package/dist/reservation/display-vehicle.js +71 -65
- package/dist/reservation/ensure-user-billing-address.d.ts +5 -0
- package/dist/reservation/ensure-user-billing-address.d.ts.map +1 -0
- package/dist/reservation/ensure-user-billing-address.js +31 -0
- package/dist/reservation/ensure-user-billing-address.js.map +1 -0
- package/dist/reservation/fetch-or-create.js +54 -48
- package/dist/reservation/invoice.js +76 -64
- package/dist/reservation/payer.js +6 -5
- package/dist/reservation/payment-intent-sync.js +6 -4
- package/dist/reservation/reserve.d.ts.map +1 -1
- package/dist/reservation/reserve.js +12 -4
- package/dist/reservation/reserve.js.map +1 -1
- package/dist/reservation/types.d.ts +1 -1
- package/dist/reservation/types.d.ts.map +1 -1
- 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 +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
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
6
|
import { PURPOSE_RESERVATION } from '@driveflux/db/models/subscription';
|
|
@@ -14,15 +14,16 @@ import { isAfter } from 'date-fns/isAfter';
|
|
|
14
14
|
import { subMinutes } from 'date-fns/subMinutes';
|
|
15
15
|
import { createScopedLogger } from '../create-logger.js';
|
|
16
16
|
const _log = createScopedLogger('reservation:invoice');
|
|
17
|
-
export const updateReservationInvoiceIfNeeded = async (oldReservationInvoice, newParams)=>{
|
|
17
|
+
export const updateReservationInvoiceIfNeeded = async (oldReservationInvoice, newParams) => {
|
|
18
18
|
const couponIsDifferent = oldReservationInvoice.couponCode !== newParams.couponCode;
|
|
19
|
-
if (!couponIsDifferent &&
|
|
19
|
+
if (!couponIsDifferent &&
|
|
20
|
+
oldReservationInvoice.stripePaymentIntentId === newParams.paymentIntentId) {
|
|
20
21
|
return new Ok(oldReservationInvoice);
|
|
21
22
|
}
|
|
22
23
|
// If the coupon or payment intent are differnt we should update the invoice
|
|
23
24
|
let update = {
|
|
24
25
|
stripePaymentIntentId: newParams.paymentIntentId,
|
|
25
|
-
couponCode: newParams.couponCode
|
|
26
|
+
couponCode: newParams.couponCode,
|
|
26
27
|
};
|
|
27
28
|
// If the coupon is different, we need to apply the coupon to the invoice
|
|
28
29
|
if (couponIsDifferent) {
|
|
@@ -30,56 +31,63 @@ export const updateReservationInvoiceIfNeeded = async (oldReservationInvoice, ne
|
|
|
30
31
|
const result = await coupons.applyCouponToUnsavedInvoice(newParams.couponCode, oldReservationInvoice);
|
|
31
32
|
if (result.ok) {
|
|
32
33
|
const { discounts, ...rest } = result.val;
|
|
33
|
-
const toDisconnect = discounts
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
const toDisconnect = discounts
|
|
35
|
+
? oldReservationInvoice.discountIds?.filter((id) => !discounts.connect?.some((d) => d.id === id))
|
|
36
|
+
: undefined;
|
|
37
|
+
const disconnectClauses = toDisconnect?.length
|
|
38
|
+
? {
|
|
39
|
+
disconnect: toDisconnect.map((id) => ({ id })),
|
|
40
|
+
}
|
|
41
|
+
: undefined;
|
|
39
42
|
update = {
|
|
40
43
|
...update,
|
|
41
44
|
...rest,
|
|
42
|
-
...discounts || disconnectClauses
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
...(discounts || disconnectClauses
|
|
46
|
+
? {
|
|
47
|
+
discounts: {
|
|
48
|
+
...(discounts || {}),
|
|
49
|
+
...(disconnectClauses || {}),
|
|
50
|
+
},
|
|
46
51
|
}
|
|
47
|
-
|
|
52
|
+
: {}),
|
|
48
53
|
metadata: {
|
|
49
54
|
...update.metadata,
|
|
50
|
-
couponCode: newParams.couponCode
|
|
55
|
+
couponCode: newParams.couponCode,
|
|
51
56
|
},
|
|
52
57
|
providerMetadata: {
|
|
53
58
|
...update.providerMetadata,
|
|
54
|
-
couponCode: newParams.couponCode
|
|
55
|
-
}
|
|
59
|
+
couponCode: newParams.couponCode,
|
|
60
|
+
},
|
|
56
61
|
};
|
|
57
62
|
}
|
|
58
63
|
if (result.err && result.val.code !== PROBLEM_APPLICABLE_NOT_FOUND) {
|
|
59
64
|
return result;
|
|
60
65
|
}
|
|
61
|
-
}
|
|
66
|
+
}
|
|
67
|
+
else if (oldReservationInvoice.discountIds.length) {
|
|
62
68
|
// No discounts, so we disconnect all of them
|
|
63
69
|
update = {
|
|
64
70
|
discounts: {
|
|
65
|
-
disconnect: oldReservationInvoice.discountIds.map((id)=>({
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
71
|
+
disconnect: oldReservationInvoice.discountIds.map((id) => ({
|
|
72
|
+
id,
|
|
73
|
+
})),
|
|
74
|
+
},
|
|
69
75
|
};
|
|
70
76
|
}
|
|
71
77
|
}
|
|
72
78
|
let updated = await wrapInResult(biller.updateInvoice(oldReservationInvoice.id, update));
|
|
73
79
|
// If the invoice was locked due to pending status and we're more than 1 minute old, we unlock it
|
|
74
80
|
if (updated.err && updated.val.code === 'invoice_pending') {
|
|
75
|
-
if (oldReservationInvoice.lockedAt &&
|
|
81
|
+
if ((oldReservationInvoice.lockedAt &&
|
|
82
|
+
isAfter(oldReservationInvoice.lockedAt, subMinutes(new Date(), 1))) ||
|
|
83
|
+
!oldReservationInvoice.lockedAt) {
|
|
76
84
|
updated = await wrapInResult(biller.updateInvoice(oldReservationInvoice.id, {
|
|
77
85
|
...update,
|
|
78
86
|
locked: false,
|
|
79
87
|
lockedAt: null,
|
|
80
88
|
lockReason: null,
|
|
81
89
|
unlockAt: null,
|
|
82
|
-
status: 'draft'
|
|
90
|
+
status: 'draft',
|
|
83
91
|
}));
|
|
84
92
|
}
|
|
85
93
|
}
|
|
@@ -88,7 +96,7 @@ export const updateReservationInvoiceIfNeeded = async (oldReservationInvoice, ne
|
|
|
88
96
|
}
|
|
89
97
|
return new Ok(updated.val);
|
|
90
98
|
};
|
|
91
|
-
export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mileagePackage, referralCode, reservationId, paymentIntentId, freeReservation, freeReservationReason, analytics, vehicle, payer, subscribingUser })=>{
|
|
99
|
+
export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mileagePackage, referralCode, reservationId, paymentIntentId, freeReservation, freeReservationReason, analytics, vehicle, payer, subscribingUser, }) => {
|
|
92
100
|
if (freeReservation) {
|
|
93
101
|
// It's a free reservation, so we don't need to add a coupon code
|
|
94
102
|
return await wrapInResult(biller.createInvoice(getInvoiceCreateDetails({
|
|
@@ -101,17 +109,21 @@ export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mi
|
|
|
101
109
|
freeReservation,
|
|
102
110
|
freeReservationReason,
|
|
103
111
|
analytics,
|
|
104
|
-
reservationId
|
|
112
|
+
reservationId,
|
|
105
113
|
})));
|
|
106
114
|
}
|
|
107
115
|
let finalCouponCode = couponCode;
|
|
108
116
|
// If we don't have a reservation coupon ID, we apply the referral discount if any
|
|
109
|
-
const referral = referralCode &&
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
117
|
+
const referral = referralCode &&
|
|
118
|
+
(await prisma.referral.findUnique({
|
|
119
|
+
where: {
|
|
120
|
+
id: referralCode,
|
|
121
|
+
},
|
|
122
|
+
}));
|
|
123
|
+
if (!finalCouponCode &&
|
|
124
|
+
referral &&
|
|
125
|
+
referral.discountToReceiverCouponId &&
|
|
126
|
+
referral.discountToReceiverCouponApplicationName === 'reservationFee') {
|
|
115
127
|
const referralCoupon = await loadCoupon(referral.discountToReceiverCouponId);
|
|
116
128
|
if (referralCoupon) {
|
|
117
129
|
finalCouponCode = referralCoupon.code;
|
|
@@ -130,15 +142,15 @@ export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mi
|
|
|
130
142
|
freeReservation,
|
|
131
143
|
freeReservationReason,
|
|
132
144
|
analytics,
|
|
133
|
-
reservationId
|
|
145
|
+
reservationId,
|
|
134
146
|
}),
|
|
135
147
|
lines: [
|
|
136
148
|
{
|
|
137
149
|
amount: reservationAmount,
|
|
138
150
|
description: `Reservation fee for ${vehicleName(vehicle)}`,
|
|
139
|
-
chargingFor: 'reservationFee'
|
|
140
|
-
}
|
|
141
|
-
]
|
|
151
|
+
chargingFor: 'reservationFee',
|
|
152
|
+
},
|
|
153
|
+
],
|
|
142
154
|
};
|
|
143
155
|
if (finalCouponCode) {
|
|
144
156
|
const withCoupon = await coupons.applyCouponToUnsavedInvoice(finalCouponCode, invoiceCreateDetails, 'reservationFee', {
|
|
@@ -148,9 +160,10 @@ export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mi
|
|
|
148
160
|
vehicleMake: vehicle.make,
|
|
149
161
|
userId: subscribingUser.id,
|
|
150
162
|
businessId: payer.object === 'business' ? payer.id : undefined,
|
|
151
|
-
vehicleType: vehicle.type
|
|
163
|
+
vehicleType: vehicle.type,
|
|
152
164
|
});
|
|
153
|
-
if (withCoupon.err &&
|
|
165
|
+
if (withCoupon.err &&
|
|
166
|
+
withCoupon.val.code !== PROBLEM_APPLICABLE_NOT_FOUND) {
|
|
154
167
|
return withCoupon;
|
|
155
168
|
}
|
|
156
169
|
if (withCoupon.ok) {
|
|
@@ -158,12 +171,12 @@ export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mi
|
|
|
158
171
|
...withCoupon.val,
|
|
159
172
|
metadata: {
|
|
160
173
|
...withCoupon.val.metadata,
|
|
161
|
-
couponCode: finalCouponCode
|
|
174
|
+
couponCode: finalCouponCode,
|
|
162
175
|
},
|
|
163
176
|
providerMetadata: {
|
|
164
177
|
...withCoupon.val.providerMetadata,
|
|
165
|
-
couponCode: finalCouponCode
|
|
166
|
-
}
|
|
178
|
+
couponCode: finalCouponCode,
|
|
179
|
+
},
|
|
167
180
|
};
|
|
168
181
|
}
|
|
169
182
|
}
|
|
@@ -171,15 +184,15 @@ export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mi
|
|
|
171
184
|
...invoiceCreateDetails,
|
|
172
185
|
providerMetadata: {
|
|
173
186
|
...invoiceCreateDetails.providerMetadata,
|
|
174
|
-
invoiceId: invoiceCreateDetails.id
|
|
175
|
-
}
|
|
187
|
+
invoiceId: invoiceCreateDetails.id,
|
|
188
|
+
},
|
|
176
189
|
}));
|
|
177
190
|
if (result.err) {
|
|
178
191
|
return result;
|
|
179
192
|
}
|
|
180
193
|
return new Ok(result.val);
|
|
181
194
|
};
|
|
182
|
-
const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId, vehicle, plan, mileagePackage, couponCode, paymentIntentId, freeReservation, freeReservationReason, analytics, reservationId })=>{
|
|
195
|
+
const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId, vehicle, plan, mileagePackage, couponCode, paymentIntentId, freeReservation, freeReservationReason, analytics, reservationId, }) => {
|
|
183
196
|
return {
|
|
184
197
|
id: invoiceId || generateId('Invoice'),
|
|
185
198
|
taxPercentage: 0,
|
|
@@ -195,13 +208,15 @@ const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId
|
|
|
195
208
|
description: 'Reservation fee for a FLUX subscription',
|
|
196
209
|
footer: `Invoice for a FLUX subscription reservation. Due by ${format(date ?? new Date())}`,
|
|
197
210
|
invoiceUrl: `${config.appUrl}/invoice-preview/${invoiceId}`,
|
|
198
|
-
...reservationDiscountId
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
211
|
+
...(reservationDiscountId
|
|
212
|
+
? {
|
|
213
|
+
discounts: {
|
|
214
|
+
connect: {
|
|
215
|
+
id: reservationDiscountId,
|
|
216
|
+
},
|
|
217
|
+
},
|
|
203
218
|
}
|
|
204
|
-
|
|
219
|
+
: {}),
|
|
205
220
|
lines: [],
|
|
206
221
|
subscriptionDetails: {
|
|
207
222
|
vehicleId: vehicle.id,
|
|
@@ -210,7 +225,7 @@ const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId
|
|
|
210
225
|
variant: vehicle.variant,
|
|
211
226
|
year: vehicle.year,
|
|
212
227
|
plan: plan,
|
|
213
|
-
mileagePackage: mileagePackage
|
|
228
|
+
mileagePackage: mileagePackage,
|
|
214
229
|
},
|
|
215
230
|
// Legacy field:
|
|
216
231
|
stripePaymentIntentId: paymentIntentId,
|
|
@@ -220,18 +235,14 @@ const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId
|
|
|
220
235
|
mileagePackage,
|
|
221
236
|
vehicleId: vehicle.id,
|
|
222
237
|
vehicleName: vehicleName(vehicle),
|
|
223
|
-
...reservationId ? {
|
|
224
|
-
|
|
225
|
-
} : {},
|
|
226
|
-
...couponCode ? {
|
|
227
|
-
couponCode
|
|
228
|
-
} : {}
|
|
238
|
+
...(reservationId ? { reservationId } : {}),
|
|
239
|
+
...(couponCode ? { couponCode } : {}),
|
|
229
240
|
},
|
|
230
241
|
autoRetry: {
|
|
231
242
|
enabled: false,
|
|
232
243
|
interval: 0,
|
|
233
244
|
maxAttempts: 0,
|
|
234
|
-
attempts: 0
|
|
245
|
+
attempts: 0,
|
|
235
246
|
},
|
|
236
247
|
metadata: {
|
|
237
248
|
purpose: PURPOSE_RESERVATION,
|
|
@@ -240,10 +251,11 @@ const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId
|
|
|
240
251
|
plan,
|
|
241
252
|
mileagePackage,
|
|
242
253
|
couponCode,
|
|
243
|
-
...freeReservation && freeReservationReason
|
|
244
|
-
freeReservationReason
|
|
245
|
-
|
|
246
|
-
analytics
|
|
247
|
-
}
|
|
254
|
+
...(freeReservation && freeReservationReason
|
|
255
|
+
? { freeReservationReason }
|
|
256
|
+
: {}),
|
|
257
|
+
analytics,
|
|
258
|
+
},
|
|
248
259
|
};
|
|
249
260
|
};
|
|
261
|
+
//# 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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reserve.d.ts","sourceRoot":"","sources":["../../src/reservation/reserve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAA;AAC5D,OAAO,EAAM,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"reserve.d.ts","sourceRoot":"","sources":["../../src/reservation/reserve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAA;AAC5D,OAAO,EAAM,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAO3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAYtD,eAAO,MAAM,cAAc,GAC1B,WAAW,MAAM,EACjB,aAAa,oBAAoB,KAC/B,cAAc,CAAC,uBAAuB,CAwDxC,CAAA"}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { Ok } from '@driveflux/result';
|
|
2
2
|
import { handleAgreeToTerms } from './agree.js';
|
|
3
3
|
import { checkIfUserCanReserve } from './checks.js';
|
|
4
|
+
import { ensureUserBillingAddress } from './ensure-user-billing-address.js';
|
|
4
5
|
import { fetchOrCreateReservation } from './fetch-or-create.js';
|
|
5
6
|
import { getPayer } from './payer.js';
|
|
6
7
|
import { ensurePaymentIntentIdIsSynced } from './payment-intent-sync.js';
|
|
7
8
|
import { getVehicle } from './vehicle.js';
|
|
8
|
-
const processBody = (body)=>{
|
|
9
|
+
const processBody = (body) => {
|
|
9
10
|
// Switch mileage package
|
|
10
11
|
if (body.plan === 'plan1' || body.plan === 'planWeekly') {
|
|
11
12
|
body.mileagePackage = 'unlimited';
|
|
12
13
|
}
|
|
13
14
|
return body;
|
|
14
15
|
};
|
|
15
|
-
export const reserveVehicle = async (vehicleId, unprocessed)=>{
|
|
16
|
+
export const reserveVehicle = async (vehicleId, unprocessed) => {
|
|
16
17
|
const body = processBody(unprocessed);
|
|
17
18
|
// Agree to terms if not done yet
|
|
18
19
|
await handleAgreeToTerms(body);
|
|
@@ -23,7 +24,13 @@ export const reserveVehicle = async (vehicleId, unprocessed)=>{
|
|
|
23
24
|
if (payerResult.err) {
|
|
24
25
|
return payerResult;
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
+
let payer = payerResult.val;
|
|
28
|
+
// Make sure the user has a billing address
|
|
29
|
+
const updatedPayerResult = await ensureUserBillingAddress(payer, body.deliveryAddresses);
|
|
30
|
+
if (updatedPayerResult.err) {
|
|
31
|
+
return updatedPayerResult;
|
|
32
|
+
}
|
|
33
|
+
payer = updatedPayerResult.val;
|
|
27
34
|
// Vehicle
|
|
28
35
|
const vehicleResult = await getVehicle(vehicleId, body, requesterAbility);
|
|
29
36
|
if (vehicleResult.err) {
|
|
@@ -34,7 +41,7 @@ export const reserveVehicle = async (vehicleId, unprocessed)=>{
|
|
|
34
41
|
const reservationResult = await fetchOrCreateReservation({
|
|
35
42
|
vehicle,
|
|
36
43
|
payer,
|
|
37
|
-
body
|
|
44
|
+
body,
|
|
38
45
|
});
|
|
39
46
|
if (reservationResult.err) {
|
|
40
47
|
return reservationResult;
|
|
@@ -50,3 +57,4 @@ export const reserveVehicle = async (vehicleId, unprocessed)=>{
|
|
|
50
57
|
}
|
|
51
58
|
return new Ok(reservation);
|
|
52
59
|
};
|
|
60
|
+
//# sourceMappingURL=reserve.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reserve.js","sourceRoot":"","sources":["../../src/reservation/reserve.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAuB,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAA;AAExE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,MAAM,WAAW,GAAG,CAAC,IAA0B,EAAwB,EAAE;IACxE,yBAAyB;IACzB,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACzD,IAAI,CAAC,cAAc,GAAG,WAAW,CAAA;IAClC,CAAC;IAED,OAAO,IAAI,CAAA;AACZ,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EAClC,SAAiB,EACjB,WAAiC,EACS,EAAE;IAC5C,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,CAAC,CAAA;IAErC,iCAAiC;IACjC,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAA;IAE9B,gCAAgC;IAChC,MAAM,gBAAgB,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAA;IAE1D,QAAQ;IACR,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAA;IACxC,IAAI,WAAW,CAAC,GAAG,EAAE,CAAC;QACrB,OAAO,WAAW,CAAA;IACnB,CAAC;IACD,
|
|
1
|
+
{"version":3,"file":"reserve.js","sourceRoot":"","sources":["../../src/reservation/reserve.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAuB,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAA;AAC3E,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAA;AAExE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,MAAM,WAAW,GAAG,CAAC,IAA0B,EAAwB,EAAE;IACxE,yBAAyB;IACzB,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACzD,IAAI,CAAC,cAAc,GAAG,WAAW,CAAA;IAClC,CAAC;IAED,OAAO,IAAI,CAAA;AACZ,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EAClC,SAAiB,EACjB,WAAiC,EACS,EAAE;IAC5C,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,CAAC,CAAA;IAErC,iCAAiC;IACjC,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAA;IAE9B,gCAAgC;IAChC,MAAM,gBAAgB,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAA;IAE1D,QAAQ;IACR,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAA;IACxC,IAAI,WAAW,CAAC,GAAG,EAAE,CAAC;QACrB,OAAO,WAAW,CAAA;IACnB,CAAC;IACD,IAAI,KAAK,GAAG,WAAW,CAAC,GAAG,CAAA;IAE3B,2CAA2C;IAC3C,MAAM,kBAAkB,GAAG,MAAM,wBAAwB,CACxD,KAAK,EACL,IAAI,CAAC,iBAAiB,CACtB,CAAA;IACD,IAAI,kBAAkB,CAAC,GAAG,EAAE,CAAC;QAC5B,OAAO,kBAAkB,CAAA;IAC1B,CAAC;IACD,KAAK,GAAG,kBAAkB,CAAC,GAAG,CAAA;IAE9B,UAAU;IACV,MAAM,aAAa,GAAG,MAAM,UAAU,CAAC,SAAS,EAAE,IAAI,EAAE,gBAAgB,CAAC,CAAA;IACzE,IAAI,aAAa,CAAC,GAAG,EAAE,CAAC;QACvB,OAAO,aAAa,CAAA;IACrB,CAAC;IACD,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAA;IACjC,gCAAgC;IAChC,MAAM,iBAAiB,GAAG,MAAM,wBAAwB,CAAC;QACxD,OAAO;QACP,KAAK;QACL,IAAI;KACJ,CAAC,CAAA;IACF,IAAI,iBAAiB,CAAC,GAAG,EAAE,CAAC;QAC3B,OAAO,iBAAiB,CAAA;IACzB,CAAC;IACD,MAAM,WAAW,GAAG,iBAAiB,CAAC,GAAG,CAAA;IAEzC,oFAAoF;IACpF,+CAA+C;IAC/C,IAAI,WAAW,CAAC,OAAO,CAAC,2BAA2B,EAAE,CAAC;QACrD,MAAM,oBAAoB,GAAG,MAAM,6BAA6B,CAC/D,WAAW,CAAC,OAAO,EACnB,WAAW,CAAC,OAAO,CAAC,2BAA2B,CAC/C,CAAA;QACD,IAAI,oBAAoB,CAAC,GAAG,EAAE,CAAC;YAC9B,OAAO,oBAAoB,CAAA;QAC5B,CAAC;IACF,CAAC;IAED,OAAO,IAAI,EAAE,CAAC,WAAW,CAAC,CAAA;AAC3B,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/reservation/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,cAAc,EACd,QAAQ,EACR,iBAAiB,EACjB,IAAI,EACJ,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AAE1D,MAAM,MAAM,oBAAoB,GAAG;IAClC,IAAI,EAAE,QAAQ,CAAA;IACd,cAAc,EAAE,cAAc,CAAA;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE;QACX,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,WAAW,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;IACD,iBAAiB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/reservation/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,cAAc,EACd,QAAQ,EACR,iBAAiB,EACjB,IAAI,EACJ,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AAE1D,MAAM,MAAM,oBAAoB,GAAG;IAClC,IAAI,EAAE,QAAQ,CAAA;IACd,cAAc,EAAE,cAAc,CAAA;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE;QACX,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,WAAW,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;IACD,iBAAiB,EAAE;QAClB,IAAI,EAAE,OAAO,CAAA;QACb,OAAO,EAAE,OAAO,CAAA;KAChB,CAAA;IACD,YAAY,CAAC,EAAE,IAAI,CAAA;IACnB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,MAAM,EAAE,iBAAiB,CAAA;IACzB,eAAe,EAAE,IAAI,CAAA;IACrB,WAAW,EAAE,IAAI,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,OAAO,CAAA;CACvB,CAAA"}
|
|
@@ -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
|