@driveflux/api-functions 1.0.62 → 1.0.63
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.js +11 -9
- package/dist/reservation/fetch-or-create.js +54 -48
- package/dist/reservation/invoice.js +78 -70
- 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 +10 -10
|
@@ -3,27 +3,29 @@ import { makeProblem, PROBLEM_INTERNAL } 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:ensure-user-billing-address');
|
|
6
|
-
export const ensureUserBillingAddress = async (userOrBusiness, deliveryAddresses)=>{
|
|
6
|
+
export const ensureUserBillingAddress = async (userOrBusiness, deliveryAddresses) => {
|
|
7
7
|
if (userOrBusiness.addresses?.billing) {
|
|
8
8
|
return new Ok(userOrBusiness);
|
|
9
9
|
}
|
|
10
10
|
try {
|
|
11
11
|
const fullQuery = {
|
|
12
|
-
where: {
|
|
13
|
-
id: userOrBusiness.id
|
|
14
|
-
},
|
|
12
|
+
where: { id: userOrBusiness.id },
|
|
15
13
|
data: {
|
|
16
14
|
addresses: {
|
|
17
15
|
home: deliveryAddresses.home,
|
|
18
|
-
billing: deliveryAddresses.billing
|
|
19
|
-
}
|
|
20
|
-
}
|
|
16
|
+
billing: deliveryAddresses.billing,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
21
19
|
};
|
|
22
20
|
// Use the delivery addresses
|
|
23
|
-
const updatedUserOrBusiness = userOrBusiness.object === 'user'
|
|
21
|
+
const updatedUserOrBusiness = userOrBusiness.object === 'user'
|
|
22
|
+
? await prisma.user.update(fullQuery)
|
|
23
|
+
: await prisma.business.update(fullQuery);
|
|
24
24
|
return new Ok(updatedUserOrBusiness);
|
|
25
|
-
}
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
26
27
|
log.error(error, 'Failed to ensure user billing address');
|
|
27
28
|
return new Err(makeProblem(PROBLEM_INTERNAL, 'Failed to ensure user billing address'));
|
|
28
29
|
}
|
|
29
30
|
};
|
|
31
|
+
//# sourceMappingURL=ensure-user-billing-address.js.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { prisma } from '@driveflux/db';
|
|
1
|
+
import { prisma, } from '@driveflux/db';
|
|
2
2
|
import { generateId } from '@driveflux/db/id';
|
|
3
3
|
import { reportError } from '@driveflux/reporter';
|
|
4
4
|
import { Ok } from '@driveflux/result';
|
|
5
5
|
import { slackLater } from '../slack.js';
|
|
6
|
-
import { createReservationInvoice, updateReservationInvoiceIfNeeded } from './invoice.js';
|
|
7
|
-
export const fetchOrCreateReservation = async ({ vehicle, payer, body })=>{
|
|
8
|
-
const { subscribingUser, plan, mileagePackage, couponCode, referralCode, asBusiness, source, deliveryAddresses, deliveryDate, analytics, paymentIntentId, freeReservation, freeReservationReason } = body;
|
|
6
|
+
import { createReservationInvoice, updateReservationInvoiceIfNeeded, } from './invoice.js';
|
|
7
|
+
export const fetchOrCreateReservation = async ({ vehicle, payer, body, }) => {
|
|
8
|
+
const { subscribingUser, plan, mileagePackage, couponCode, referralCode, asBusiness, source, deliveryAddresses, deliveryDate, analytics, paymentIntentId, freeReservation, freeReservationReason, } = body;
|
|
9
9
|
try {
|
|
10
10
|
const previousReservation = await prisma.subscriptionReservation.findFirst({
|
|
11
11
|
where: {
|
|
@@ -19,14 +19,14 @@ export const fetchOrCreateReservation = async ({ vehicle, payer, body })=>{
|
|
|
19
19
|
source,
|
|
20
20
|
// If the subscription ID was populated, this means that this reservation was consumed into a subsription,
|
|
21
21
|
// so we shouldn't re-use it
|
|
22
|
-
subscription: null
|
|
22
|
+
subscription: null,
|
|
23
23
|
},
|
|
24
24
|
orderBy: {
|
|
25
|
-
updatedAt: 'desc'
|
|
25
|
+
updatedAt: 'desc',
|
|
26
26
|
},
|
|
27
27
|
include: {
|
|
28
|
-
invoice: true
|
|
29
|
-
}
|
|
28
|
+
invoice: true,
|
|
29
|
+
},
|
|
30
30
|
});
|
|
31
31
|
if (previousReservation) {
|
|
32
32
|
if (previousReservation.invoice.voided) {
|
|
@@ -39,7 +39,7 @@ export const fetchOrCreateReservation = async ({ vehicle, payer, body })=>{
|
|
|
39
39
|
'partiallyPaid',
|
|
40
40
|
'partiallyRefunded',
|
|
41
41
|
'refunded',
|
|
42
|
-
'pendingRefund'
|
|
42
|
+
'pendingRefund',
|
|
43
43
|
];
|
|
44
44
|
if (wrongStatuses.includes(previousReservation.invoice.status)) {
|
|
45
45
|
const updatedReservation = await recreateReservationInvoiceAndUpdateReservation(previousReservation, body, vehicle, payer);
|
|
@@ -52,16 +52,16 @@ export const fetchOrCreateReservation = async ({ vehicle, payer, body })=>{
|
|
|
52
52
|
text: {
|
|
53
53
|
type: 'plain_text',
|
|
54
54
|
text: '‼️ Reservation invoice in wrong status',
|
|
55
|
-
emoji: true
|
|
56
|
-
}
|
|
55
|
+
emoji: true,
|
|
56
|
+
},
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
59
|
type: 'section',
|
|
60
60
|
text: {
|
|
61
61
|
type: 'plain_text',
|
|
62
|
-
text: `The reservation invoice ${previousReservation.invoice.id} was in a wrong status (${previousReservation.invoice.status}), it was discarded and a new invoice (${updatedReservation.val.id}) was created, however, investigate the issue
|
|
63
|
-
}
|
|
64
|
-
}
|
|
62
|
+
text: `The reservation invoice ${previousReservation.invoice.id} was in a wrong status (${previousReservation.invoice.status}), it was discarded and a new invoice (${updatedReservation.val.id}) was created, however, investigate the issue.`,
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
65
|
]);
|
|
66
66
|
return updatedReservation;
|
|
67
67
|
}
|
|
@@ -73,7 +73,8 @@ export const fetchOrCreateReservation = async ({ vehicle, payer, body })=>{
|
|
|
73
73
|
// Otherwise, we need to create a new reservation
|
|
74
74
|
return new Ok(previousReservation);
|
|
75
75
|
}
|
|
76
|
-
}
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
77
78
|
// We couldn't fetch the reservation, so we create a new one and just log this
|
|
78
79
|
await reportError(error);
|
|
79
80
|
}
|
|
@@ -92,7 +93,7 @@ export const fetchOrCreateReservation = async ({ vehicle, payer, body })=>{
|
|
|
92
93
|
analytics,
|
|
93
94
|
vehicle,
|
|
94
95
|
payer,
|
|
95
|
-
subscribingUser
|
|
96
|
+
subscribingUser,
|
|
96
97
|
});
|
|
97
98
|
if (invoiceResult.err) {
|
|
98
99
|
return invoiceResult;
|
|
@@ -111,66 +112,70 @@ export const fetchOrCreateReservation = async ({ vehicle, payer, body })=>{
|
|
|
111
112
|
deliveryAddresses,
|
|
112
113
|
deliveryDate,
|
|
113
114
|
asBusiness,
|
|
114
|
-
source
|
|
115
|
+
source,
|
|
115
116
|
});
|
|
116
117
|
return new Ok(reservation);
|
|
117
118
|
};
|
|
118
|
-
const createReservation = async ({ reservationId, invoiceId, subscribingUserId, vehicleId, businessId, plan, mileagePackage, couponCode, referralCode, analytics, deliveryAddresses, deliveryDate, asBusiness, source })=>{
|
|
119
|
+
const createReservation = async ({ reservationId, invoiceId, subscribingUserId, vehicleId, businessId, plan, mileagePackage, couponCode, referralCode, analytics, deliveryAddresses, deliveryDate, asBusiness, source, }) => {
|
|
119
120
|
return await prisma.subscriptionReservation.create({
|
|
120
121
|
data: {
|
|
121
122
|
id: reservationId,
|
|
122
123
|
invoice: {
|
|
123
124
|
connect: {
|
|
124
|
-
id: invoiceId
|
|
125
|
-
}
|
|
125
|
+
id: invoiceId,
|
|
126
|
+
},
|
|
126
127
|
},
|
|
127
128
|
user: {
|
|
128
129
|
connect: {
|
|
129
|
-
id: subscribingUserId
|
|
130
|
-
}
|
|
130
|
+
id: subscribingUserId,
|
|
131
|
+
},
|
|
131
132
|
},
|
|
132
133
|
vehicle: {
|
|
133
134
|
connect: {
|
|
134
|
-
id: vehicleId
|
|
135
|
-
}
|
|
135
|
+
id: vehicleId,
|
|
136
|
+
},
|
|
136
137
|
},
|
|
137
|
-
...businessId
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
...(businessId
|
|
139
|
+
? {
|
|
140
|
+
business: {
|
|
141
|
+
connect: {
|
|
142
|
+
id: businessId,
|
|
143
|
+
},
|
|
144
|
+
},
|
|
142
145
|
}
|
|
143
|
-
|
|
146
|
+
: undefined),
|
|
144
147
|
plan,
|
|
145
148
|
mileagePackage,
|
|
146
149
|
couponCode: couponCode,
|
|
147
150
|
deliveryAddresses: deliveryAddresses,
|
|
148
151
|
deliveryDate: deliveryDate,
|
|
149
|
-
...referralCode
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
...(referralCode
|
|
153
|
+
? {
|
|
154
|
+
referral: {
|
|
155
|
+
connect: {
|
|
156
|
+
id: referralCode,
|
|
157
|
+
},
|
|
158
|
+
},
|
|
154
159
|
}
|
|
155
|
-
|
|
160
|
+
: undefined),
|
|
156
161
|
asBusiness: !!asBusiness,
|
|
157
162
|
source,
|
|
158
163
|
metadata: {
|
|
159
|
-
analytics
|
|
160
|
-
}
|
|
164
|
+
analytics,
|
|
165
|
+
},
|
|
161
166
|
},
|
|
162
167
|
include: {
|
|
163
|
-
invoice: true
|
|
164
|
-
}
|
|
168
|
+
invoice: true,
|
|
169
|
+
},
|
|
165
170
|
});
|
|
166
171
|
};
|
|
167
|
-
const recreateReservationInvoiceAndUpdateReservation = async (previousReservation, body, vehicle, payer)=>{
|
|
172
|
+
const recreateReservationInvoiceAndUpdateReservation = async (previousReservation, body, vehicle, payer) => {
|
|
168
173
|
const invoiceResult = await createReservationInvoice({
|
|
169
174
|
...body,
|
|
170
175
|
invoiceId: generateId('Invoice'),
|
|
171
176
|
reservationId: previousReservation.id,
|
|
172
177
|
vehicle,
|
|
173
|
-
payer
|
|
178
|
+
payer,
|
|
174
179
|
});
|
|
175
180
|
if (!invoiceResult.ok) {
|
|
176
181
|
return invoiceResult;
|
|
@@ -178,18 +183,19 @@ const recreateReservationInvoiceAndUpdateReservation = async (previousReservatio
|
|
|
178
183
|
const invoice = invoiceResult.val;
|
|
179
184
|
const updatedReservation = await prisma.subscriptionReservation.update({
|
|
180
185
|
where: {
|
|
181
|
-
id: previousReservation.id
|
|
186
|
+
id: previousReservation.id,
|
|
182
187
|
},
|
|
183
188
|
data: {
|
|
184
189
|
invoice: {
|
|
185
190
|
connect: {
|
|
186
|
-
id: invoice.id
|
|
187
|
-
}
|
|
188
|
-
}
|
|
191
|
+
id: invoice.id,
|
|
192
|
+
},
|
|
193
|
+
},
|
|
189
194
|
},
|
|
190
195
|
include: {
|
|
191
|
-
invoice: true
|
|
192
|
-
}
|
|
196
|
+
invoice: true,
|
|
197
|
+
},
|
|
193
198
|
});
|
|
194
199
|
return new Ok(updatedReservation);
|
|
195
200
|
};
|
|
201
|
+
//# sourceMappingURL=fetch-or-create.js.map
|
|
@@ -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,20 +142,18 @@ 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
|
-
log.debug({
|
|
145
|
-
finalCouponCode
|
|
146
|
-
}, 'Applying coupon code to invoice');
|
|
156
|
+
log.debug({ finalCouponCode }, 'Applying coupon code to invoice');
|
|
147
157
|
const withCoupon = await coupons.applyCouponToUnsavedInvoice(finalCouponCode, invoiceCreateDetails, 'reservationFee', {
|
|
148
158
|
subscriptionPlans: plan,
|
|
149
159
|
subscriptionMileagePackages: mileagePackage,
|
|
@@ -151,25 +161,24 @@ export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mi
|
|
|
151
161
|
vehicleMake: vehicle.make,
|
|
152
162
|
userId: subscribingUser.id,
|
|
153
163
|
businessId: payer.object === 'business' ? payer.id : undefined,
|
|
154
|
-
vehicleType: vehicle.type
|
|
164
|
+
vehicleType: vehicle.type,
|
|
155
165
|
});
|
|
156
|
-
if (withCoupon.err &&
|
|
166
|
+
if (withCoupon.err &&
|
|
167
|
+
withCoupon.val.code !== PROBLEM_APPLICABLE_NOT_FOUND) {
|
|
157
168
|
return withCoupon;
|
|
158
169
|
}
|
|
159
|
-
log.debug({
|
|
160
|
-
couponUpdates: withCoupon.val
|
|
161
|
-
}, 'Coupon applied to invoice');
|
|
170
|
+
log.debug({ couponUpdates: withCoupon.val }, 'Coupon applied to invoice');
|
|
162
171
|
if (withCoupon.ok) {
|
|
163
172
|
invoiceCreateDetails = {
|
|
164
173
|
...withCoupon.val,
|
|
165
174
|
metadata: {
|
|
166
175
|
...withCoupon.val.metadata,
|
|
167
|
-
couponCode: finalCouponCode
|
|
176
|
+
couponCode: finalCouponCode,
|
|
168
177
|
},
|
|
169
178
|
providerMetadata: {
|
|
170
179
|
...withCoupon.val.providerMetadata,
|
|
171
|
-
couponCode: finalCouponCode
|
|
172
|
-
}
|
|
180
|
+
couponCode: finalCouponCode,
|
|
181
|
+
},
|
|
173
182
|
};
|
|
174
183
|
}
|
|
175
184
|
}
|
|
@@ -177,15 +186,15 @@ export const createReservationInvoice = async ({ invoiceId, couponCode, plan, mi
|
|
|
177
186
|
...invoiceCreateDetails,
|
|
178
187
|
providerMetadata: {
|
|
179
188
|
...invoiceCreateDetails.providerMetadata,
|
|
180
|
-
invoiceId: invoiceCreateDetails.id
|
|
181
|
-
}
|
|
189
|
+
invoiceId: invoiceCreateDetails.id,
|
|
190
|
+
},
|
|
182
191
|
}));
|
|
183
192
|
if (result.err) {
|
|
184
193
|
return result;
|
|
185
194
|
}
|
|
186
195
|
return new Ok(result.val);
|
|
187
196
|
};
|
|
188
|
-
const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId, vehicle, plan, mileagePackage, couponCode, paymentIntentId, freeReservation, freeReservationReason, analytics, reservationId })=>{
|
|
197
|
+
const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId, vehicle, plan, mileagePackage, couponCode, paymentIntentId, freeReservation, freeReservationReason, analytics, reservationId, }) => {
|
|
189
198
|
return {
|
|
190
199
|
id: invoiceId || generateId('Invoice'),
|
|
191
200
|
taxPercentage: 0,
|
|
@@ -201,13 +210,15 @@ const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId
|
|
|
201
210
|
description: 'Reservation fee for a FLUX subscription',
|
|
202
211
|
footer: `Invoice for a FLUX subscription reservation. Due by ${format(date ?? new Date())}`,
|
|
203
212
|
invoiceUrl: `${config.appUrl}/invoice-preview/${invoiceId}`,
|
|
204
|
-
...reservationDiscountId
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
213
|
+
...(reservationDiscountId
|
|
214
|
+
? {
|
|
215
|
+
discounts: {
|
|
216
|
+
connect: {
|
|
217
|
+
id: reservationDiscountId,
|
|
218
|
+
},
|
|
219
|
+
},
|
|
209
220
|
}
|
|
210
|
-
|
|
221
|
+
: {}),
|
|
211
222
|
lines: [],
|
|
212
223
|
subscriptionDetails: {
|
|
213
224
|
vehicleId: vehicle.id,
|
|
@@ -216,7 +227,7 @@ const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId
|
|
|
216
227
|
variant: vehicle.variant,
|
|
217
228
|
year: vehicle.year,
|
|
218
229
|
plan: plan,
|
|
219
|
-
mileagePackage: mileagePackage
|
|
230
|
+
mileagePackage: mileagePackage,
|
|
220
231
|
},
|
|
221
232
|
// Legacy field:
|
|
222
233
|
stripePaymentIntentId: paymentIntentId,
|
|
@@ -226,18 +237,14 @@ const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId
|
|
|
226
237
|
mileagePackage,
|
|
227
238
|
vehicleId: vehicle.id,
|
|
228
239
|
vehicleName: vehicleName(vehicle),
|
|
229
|
-
...reservationId ? {
|
|
230
|
-
|
|
231
|
-
} : {},
|
|
232
|
-
...couponCode ? {
|
|
233
|
-
couponCode
|
|
234
|
-
} : {}
|
|
240
|
+
...(reservationId ? { reservationId } : {}),
|
|
241
|
+
...(couponCode ? { couponCode } : {}),
|
|
235
242
|
},
|
|
236
243
|
autoRetry: {
|
|
237
244
|
enabled: false,
|
|
238
245
|
interval: 0,
|
|
239
246
|
maxAttempts: 0,
|
|
240
|
-
attempts: 0
|
|
247
|
+
attempts: 0,
|
|
241
248
|
},
|
|
242
249
|
metadata: {
|
|
243
250
|
purpose: PURPOSE_RESERVATION,
|
|
@@ -246,10 +253,11 @@ const getInvoiceCreateDetails = ({ invoiceId, payer, date, reservationDiscountId
|
|
|
246
253
|
plan,
|
|
247
254
|
mileagePackage,
|
|
248
255
|
couponCode,
|
|
249
|
-
...freeReservation && freeReservationReason
|
|
250
|
-
freeReservationReason
|
|
251
|
-
|
|
252
|
-
analytics
|
|
253
|
-
}
|
|
256
|
+
...(freeReservation && freeReservationReason
|
|
257
|
+
? { freeReservationReason }
|
|
258
|
+
: {}),
|
|
259
|
+
analytics,
|
|
260
|
+
},
|
|
254
261
|
};
|
|
255
262
|
};
|
|
263
|
+
//# 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
|
body.subscribingUser = await handleAgreeToTerms(body);
|
|
@@ -45,7 +45,7 @@ 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
50
|
if (reservationResult.err) {
|
|
51
51
|
return reservationResult;
|
|
@@ -61,3 +61,4 @@ export const reserveVehicle = async (vehicleId, unprocessed)=>{
|
|
|
61
61
|
}
|
|
62
62
|
return new Ok(reservation);
|
|
63
63
|
};
|
|
64
|
+
//# sourceMappingURL=reserve.js.map
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {};
|
|
2
|
+
//# sourceMappingURL=types.js.map
|