@driveflux/api-functions 1.0.136 → 1.0.138
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/tokens.d.ts +3 -3
- package/dist/notion/schemas/database.d.ts +3 -3
- package/dist/notion/schemas/file.d.ts +1 -1
- package/dist/notion/schemas/kb.d.ts +4 -4
- package/dist/notion/schemas/page.d.ts +4 -4
- package/dist/reservation/display-vehicle.d.ts +17 -17
- package/dist/reservation/invoice.js +88 -77
- package/dist/reservation/payment-intent-sync.js +6 -4
- package/package.json +4 -4
package/dist/auth/tokens.d.ts
CHANGED
|
@@ -13,8 +13,8 @@ export declare const createToken: (userId: string | null, type: "email" | "phone
|
|
|
13
13
|
metadata: PrismaJson.AnyMetadata | null;
|
|
14
14
|
createdAt: Date;
|
|
15
15
|
updatedAt: Date;
|
|
16
|
-
value: string | null;
|
|
17
16
|
userId: string | null;
|
|
17
|
+
value: string | null;
|
|
18
18
|
client: string | null;
|
|
19
19
|
identifier: string | null;
|
|
20
20
|
expiresAt: Date | null;
|
|
@@ -29,8 +29,8 @@ export declare const createEmailToken: (userId: string, email: string) => Promis
|
|
|
29
29
|
metadata: PrismaJson.AnyMetadata | null;
|
|
30
30
|
createdAt: Date;
|
|
31
31
|
updatedAt: Date;
|
|
32
|
-
value: string | null;
|
|
33
32
|
userId: string | null;
|
|
33
|
+
value: string | null;
|
|
34
34
|
client: string | null;
|
|
35
35
|
identifier: string | null;
|
|
36
36
|
expiresAt: Date | null;
|
|
@@ -45,8 +45,8 @@ export declare const createSMSToken: (userId: string | null, phoneNumber: string
|
|
|
45
45
|
metadata: PrismaJson.AnyMetadata | null;
|
|
46
46
|
createdAt: Date;
|
|
47
47
|
updatedAt: Date;
|
|
48
|
-
value: string | null;
|
|
49
48
|
userId: string | null;
|
|
49
|
+
value: string | null;
|
|
50
50
|
client: string | null;
|
|
51
51
|
identifier: string | null;
|
|
52
52
|
expiresAt: Date | null;
|
|
@@ -190,8 +190,8 @@ export declare const notionDatabasePropertyRollupSchema: ZodObject<{
|
|
|
190
190
|
type: z.ZodEnum<{
|
|
191
191
|
number: "number";
|
|
192
192
|
date: "date";
|
|
193
|
-
array: "array";
|
|
194
193
|
incomplete: "incomplete";
|
|
194
|
+
array: "array";
|
|
195
195
|
unsupported: "unsupported";
|
|
196
196
|
}>;
|
|
197
197
|
}, z.core.$strip>;
|
|
@@ -475,8 +475,8 @@ export declare const notionDatabaseSchema: <T extends ZodObject<any>>(properties
|
|
|
475
475
|
}, z.core.$strip>>;
|
|
476
476
|
icon: z.ZodUnion<[ZodObject<{
|
|
477
477
|
type: z.ZodEnum<{
|
|
478
|
-
file: "file";
|
|
479
478
|
external: "external";
|
|
479
|
+
file: "file";
|
|
480
480
|
}>;
|
|
481
481
|
name: z.ZodOptional<z.ZodString>;
|
|
482
482
|
file: z.ZodOptional<ZodObject<{
|
|
@@ -492,8 +492,8 @@ export declare const notionDatabaseSchema: <T extends ZodObject<any>>(properties
|
|
|
492
492
|
}, z.core.$strip>]>;
|
|
493
493
|
cover: z.ZodNullable<ZodObject<{
|
|
494
494
|
type: z.ZodEnum<{
|
|
495
|
-
file: "file";
|
|
496
495
|
external: "external";
|
|
496
|
+
file: "file";
|
|
497
497
|
}>;
|
|
498
498
|
name: z.ZodOptional<z.ZodString>;
|
|
499
499
|
file: z.ZodOptional<ZodObject<{
|
|
@@ -188,8 +188,8 @@ export declare const knowledgeBaseRetrieveDatabaseSchema: z.ZodObject<{
|
|
|
188
188
|
}, z.core.$strip>>;
|
|
189
189
|
icon: z.ZodUnion<[z.ZodObject<{
|
|
190
190
|
type: z.ZodEnum<{
|
|
191
|
-
file: "file";
|
|
192
191
|
external: "external";
|
|
192
|
+
file: "file";
|
|
193
193
|
}>;
|
|
194
194
|
name: z.ZodOptional<z.ZodString>;
|
|
195
195
|
file: z.ZodOptional<z.ZodObject<{
|
|
@@ -205,8 +205,8 @@ export declare const knowledgeBaseRetrieveDatabaseSchema: z.ZodObject<{
|
|
|
205
205
|
}, z.core.$strip>]>;
|
|
206
206
|
cover: z.ZodNullable<z.ZodObject<{
|
|
207
207
|
type: z.ZodEnum<{
|
|
208
|
-
file: "file";
|
|
209
208
|
external: "external";
|
|
209
|
+
file: "file";
|
|
210
210
|
}>;
|
|
211
211
|
name: z.ZodOptional<z.ZodString>;
|
|
212
212
|
file: z.ZodOptional<z.ZodObject<{
|
|
@@ -611,8 +611,8 @@ export declare const knowledgeBaseRetrievePageSchema: z.ZodObject<{
|
|
|
611
611
|
archived: z.ZodBoolean;
|
|
612
612
|
icon: z.ZodNullable<z.ZodUnion<[z.ZodObject<{
|
|
613
613
|
type: z.ZodEnum<{
|
|
614
|
-
file: "file";
|
|
615
614
|
external: "external";
|
|
615
|
+
file: "file";
|
|
616
616
|
}>;
|
|
617
617
|
name: z.ZodOptional<z.ZodString>;
|
|
618
618
|
file: z.ZodOptional<z.ZodObject<{
|
|
@@ -1123,8 +1123,8 @@ export declare const knowledgeBaseQueryDatabaseSchema: z.ZodObject<{
|
|
|
1123
1123
|
archived: z.ZodBoolean;
|
|
1124
1124
|
icon: z.ZodNullable<z.ZodUnion<[z.ZodObject<{
|
|
1125
1125
|
type: z.ZodEnum<{
|
|
1126
|
-
file: "file";
|
|
1127
1126
|
external: "external";
|
|
1127
|
+
file: "file";
|
|
1128
1128
|
}>;
|
|
1129
1129
|
name: z.ZodOptional<z.ZodString>;
|
|
1130
1130
|
file: z.ZodOptional<z.ZodObject<{
|
|
@@ -58,8 +58,8 @@ export declare const notionPagePropertyEmailSchema: ZodObject<{
|
|
|
58
58
|
export declare const notionPagePropertyFilesSchema: ZodObject<{
|
|
59
59
|
files: z.ZodArray<ZodObject<{
|
|
60
60
|
type: z.ZodEnum<{
|
|
61
|
-
file: "file";
|
|
62
61
|
external: "external";
|
|
62
|
+
file: "file";
|
|
63
63
|
}>;
|
|
64
64
|
name: z.ZodOptional<z.ZodString>;
|
|
65
65
|
file: z.ZodOptional<ZodObject<{
|
|
@@ -231,8 +231,8 @@ export declare const notionPagePropertyRollupSchema: ZodObject<{
|
|
|
231
231
|
type: z.ZodEnum<{
|
|
232
232
|
number: "number";
|
|
233
233
|
date: "date";
|
|
234
|
-
array: "array";
|
|
235
234
|
incomplete: "incomplete";
|
|
235
|
+
array: "array";
|
|
236
236
|
unsupported: "unsupported";
|
|
237
237
|
}>;
|
|
238
238
|
}, z.core.$strip>;
|
|
@@ -536,8 +536,8 @@ export declare const notionPageSchema: <T extends ZodObject<any>>(properties: T)
|
|
|
536
536
|
archived: z.ZodBoolean;
|
|
537
537
|
icon: z.ZodNullable<z.ZodUnion<[ZodObject<{
|
|
538
538
|
type: z.ZodEnum<{
|
|
539
|
-
file: "file";
|
|
540
539
|
external: "external";
|
|
540
|
+
file: "file";
|
|
541
541
|
}>;
|
|
542
542
|
name: z.ZodOptional<z.ZodString>;
|
|
543
543
|
file: z.ZodOptional<ZodObject<{
|
|
@@ -581,8 +581,8 @@ export declare const notionPagesSchema: <T extends ZodObject<any>>(properties: T
|
|
|
581
581
|
archived: z.ZodBoolean;
|
|
582
582
|
icon: z.ZodNullable<z.ZodUnion<[ZodObject<{
|
|
583
583
|
type: z.ZodEnum<{
|
|
584
|
-
file: "file";
|
|
585
584
|
external: "external";
|
|
585
|
+
file: "file";
|
|
586
586
|
}>;
|
|
587
587
|
name: z.ZodOptional<z.ZodString>;
|
|
588
588
|
file: z.ZodOptional<ZodObject<{
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { type DisplayVehicle, type MileagePackage, type PlanType, type UltraTier, type Vehicle, type VehicleType } from '@driveflux/db';
|
|
2
2
|
export declare const fetchDisplayVehicle: (displayVehicle: DisplayVehicle | string) => Promise<{
|
|
3
3
|
object: import("@driveflux/db").DisplayVehicleObject;
|
|
4
|
-
type: VehicleType;
|
|
5
4
|
id: string;
|
|
6
5
|
createdAt: Date;
|
|
7
6
|
updatedAt: Date;
|
|
@@ -10,6 +9,7 @@ export declare const fetchDisplayVehicle: (displayVehicle: DisplayVehicle | stri
|
|
|
10
9
|
vehicleModel: string;
|
|
11
10
|
variant: string;
|
|
12
11
|
year: number;
|
|
12
|
+
type: VehicleType;
|
|
13
13
|
brandSlug: string;
|
|
14
14
|
brandId: string;
|
|
15
15
|
defaultHostId: string;
|
|
@@ -198,24 +198,24 @@ export declare const fetchDisplayVehicle: (displayVehicle: DisplayVehicle | stri
|
|
|
198
198
|
export declare const createVehicleFromDisplayVehicle: (displayVehicle: DisplayVehicle | string, selectedColor?: string) => Promise<({
|
|
199
199
|
host: {
|
|
200
200
|
object: import("@driveflux/db").HostObject;
|
|
201
|
-
|
|
202
|
-
type: import("@driveflux/db").HostType | null;
|
|
201
|
+
name: string;
|
|
203
202
|
id: string;
|
|
204
203
|
metadata: PrismaJson.AnyMetadata | null;
|
|
205
|
-
name: string;
|
|
206
204
|
createdAt: Date;
|
|
207
205
|
updatedAt: Date;
|
|
206
|
+
registrationNumber: string | null;
|
|
207
|
+
type: import("@driveflux/db").HostType | null;
|
|
208
|
+
active: boolean;
|
|
208
209
|
email: string | null;
|
|
210
|
+
phoneNumber: string | null;
|
|
209
211
|
race: import("@driveflux/db").Race | null;
|
|
210
212
|
emergencyContactName: string | null;
|
|
211
213
|
emergencyPhoneNumber: string | null;
|
|
212
214
|
companyName: string | null;
|
|
213
|
-
|
|
215
|
+
faxNumber: string | null;
|
|
214
216
|
sstNumber: string | null;
|
|
215
217
|
tinNumber: string | null;
|
|
216
218
|
commencementDate: Date | null;
|
|
217
|
-
registrationNumber: string | null;
|
|
218
|
-
faxNumber: string | null;
|
|
219
219
|
stripeAccountId: string | null;
|
|
220
220
|
isStripeConnected: boolean;
|
|
221
221
|
serviceCenterIds: string[];
|
|
@@ -275,15 +275,11 @@ export declare const createVehicleFromDisplayVehicle: (displayVehicle: DisplayVe
|
|
|
275
275
|
};
|
|
276
276
|
} & {
|
|
277
277
|
object: import("@driveflux/db").VehicleObject;
|
|
278
|
-
type: VehicleType;
|
|
279
278
|
id: string;
|
|
279
|
+
status: import("@driveflux/db").VehicleStatus;
|
|
280
280
|
metadata: PrismaJson.AnyMetadata | null;
|
|
281
281
|
createdAt: Date;
|
|
282
282
|
updatedAt: Date;
|
|
283
|
-
hostId: string;
|
|
284
|
-
status: import("@driveflux/db").VehicleStatus;
|
|
285
|
-
temporary: boolean;
|
|
286
|
-
registrationNumber: string | null;
|
|
287
283
|
make: string;
|
|
288
284
|
vehicleModel: string;
|
|
289
285
|
variant: string;
|
|
@@ -295,6 +291,7 @@ export declare const createVehicleFromDisplayVehicle: (displayVehicle: DisplayVe
|
|
|
295
291
|
lastSearchIndexedAt: Date | null;
|
|
296
292
|
registrationDate: Date | null;
|
|
297
293
|
mileage: number | null;
|
|
294
|
+
registrationNumber: string | null;
|
|
298
295
|
vin: string | null;
|
|
299
296
|
engineNumber: string | null;
|
|
300
297
|
availability: import("@driveflux/db").VehicleAvailablity | null;
|
|
@@ -309,6 +306,8 @@ export declare const createVehicleFromDisplayVehicle: (displayVehicle: DisplayVe
|
|
|
309
306
|
delistedAt: Date | null;
|
|
310
307
|
imagesNotActual: boolean;
|
|
311
308
|
imagesNotActualMessage: string | null;
|
|
309
|
+
hostId: string;
|
|
310
|
+
type: VehicleType;
|
|
312
311
|
allowedServiceCenterIds: string[];
|
|
313
312
|
displayVehicleId: string | null;
|
|
314
313
|
isHostConfirmed: boolean | null;
|
|
@@ -321,6 +320,7 @@ export declare const createVehicleFromDisplayVehicle: (displayVehicle: DisplayVe
|
|
|
321
320
|
featureOnLandingPage: boolean;
|
|
322
321
|
lastMileageRecordedAt: Date | null;
|
|
323
322
|
locationAvailability: string[];
|
|
323
|
+
temporary: boolean;
|
|
324
324
|
hotDeal: boolean | null;
|
|
325
325
|
activeSubscriptionId: string | null;
|
|
326
326
|
addresses: {
|
|
@@ -704,15 +704,11 @@ export declare const createVehicleFromDisplayVehicle: (displayVehicle: DisplayVe
|
|
|
704
704
|
}) | undefined>;
|
|
705
705
|
export declare const transfromVehicleDisplayToVehicle: (displayVehicle: DisplayVehicle | string, selectedColor: string) => Promise<({
|
|
706
706
|
object: import("@driveflux/db").VehicleObject;
|
|
707
|
-
type: VehicleType;
|
|
708
707
|
id: string;
|
|
708
|
+
status: import("@driveflux/db").VehicleStatus;
|
|
709
709
|
metadata: PrismaJson.AnyMetadata | null;
|
|
710
710
|
createdAt: Date;
|
|
711
711
|
updatedAt: Date;
|
|
712
|
-
hostId: string;
|
|
713
|
-
status: import("@driveflux/db").VehicleStatus;
|
|
714
|
-
temporary: boolean;
|
|
715
|
-
registrationNumber: string | null;
|
|
716
712
|
make: string;
|
|
717
713
|
vehicleModel: string;
|
|
718
714
|
variant: string;
|
|
@@ -724,6 +720,7 @@ export declare const transfromVehicleDisplayToVehicle: (displayVehicle: DisplayV
|
|
|
724
720
|
lastSearchIndexedAt: Date | null;
|
|
725
721
|
registrationDate: Date | null;
|
|
726
722
|
mileage: number | null;
|
|
723
|
+
registrationNumber: string | null;
|
|
727
724
|
vin: string | null;
|
|
728
725
|
engineNumber: string | null;
|
|
729
726
|
availability: import("@driveflux/db").VehicleAvailablity | null;
|
|
@@ -738,6 +735,8 @@ export declare const transfromVehicleDisplayToVehicle: (displayVehicle: DisplayV
|
|
|
738
735
|
delistedAt: Date | null;
|
|
739
736
|
imagesNotActual: boolean;
|
|
740
737
|
imagesNotActualMessage: string | null;
|
|
738
|
+
hostId: string;
|
|
739
|
+
type: VehicleType;
|
|
741
740
|
allowedServiceCenterIds: string[];
|
|
742
741
|
displayVehicleId: string | null;
|
|
743
742
|
isHostConfirmed: boolean | null;
|
|
@@ -750,6 +749,7 @@ export declare const transfromVehicleDisplayToVehicle: (displayVehicle: DisplayV
|
|
|
750
749
|
featureOnLandingPage: boolean;
|
|
751
750
|
lastMileageRecordedAt: Date | null;
|
|
752
751
|
locationAvailability: string[];
|
|
752
|
+
temporary: boolean;
|
|
753
753
|
hotDeal: boolean | null;
|
|
754
754
|
activeSubscriptionId: string | null;
|
|
755
755
|
addresses: {
|
|
@@ -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
|
|
@@ -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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@driveflux/api-functions",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.138",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./notion": {
|
|
@@ -73,14 +73,14 @@
|
|
|
73
73
|
],
|
|
74
74
|
"dependencies": {
|
|
75
75
|
"@casl/ability": "^6.7.3",
|
|
76
|
-
"@driveflux/auth": "4.0.
|
|
76
|
+
"@driveflux/auth": "4.0.79",
|
|
77
77
|
"@driveflux/billing": "8.1.4",
|
|
78
78
|
"@driveflux/config": "3.0.9",
|
|
79
79
|
"@driveflux/coupon": "9.1.9",
|
|
80
80
|
"@driveflux/db": "4.1.8",
|
|
81
81
|
"@driveflux/email": "7.1.8",
|
|
82
82
|
"@driveflux/email-templates": "1.2.9",
|
|
83
|
-
"@driveflux/engine": "1.1.
|
|
83
|
+
"@driveflux/engine": "1.1.22",
|
|
84
84
|
"@driveflux/fetch": "8.0.1",
|
|
85
85
|
"@driveflux/format-money": "7.0.0",
|
|
86
86
|
"@driveflux/logger": "1.1.3",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"@driveflux/result": "6.0.1",
|
|
90
90
|
"@driveflux/scheduler": "8.1.9",
|
|
91
91
|
"@driveflux/singleton": "3.0.0",
|
|
92
|
-
"@driveflux/subscription": "9.1.
|
|
92
|
+
"@driveflux/subscription": "9.1.6",
|
|
93
93
|
"@driveflux/time": "6.0.2",
|
|
94
94
|
"@driveflux/utils": "6.0.0",
|
|
95
95
|
"@notionhq/client": "^5.3.0",
|