@instockng/api-client 1.0.8 → 1.0.10
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/fetchers/brands.d.ts +1 -1
- package/dist/fetchers/carts.d.ts +85 -47
- package/dist/fetchers/delivery-zones.d.ts +2 -0
- package/dist/fetchers/orders.d.ts +26 -14
- package/dist/fetchers/products.d.ts +14 -6
- package/dist/hooks/admin/abandoned-carts.d.ts +18 -10
- package/dist/hooks/admin/brands.d.ts +4 -4
- package/dist/hooks/admin/customers.d.ts +13 -7
- package/dist/hooks/admin/delivery-zones.d.ts +23 -15
- package/dist/hooks/admin/discount-codes.d.ts +10 -10
- package/dist/hooks/admin/inventory.d.ts +4 -0
- package/dist/hooks/admin/orders.d.ts +78 -42
- package/dist/hooks/admin/products.d.ts +14 -6
- package/dist/hooks/admin/stats.d.ts +13 -7
- package/dist/hooks/admin/variants.d.ts +5 -5
- package/dist/hooks/admin/warehouses.d.ts +11 -7
- package/dist/hooks/public/brands.d.ts +1 -1
- package/dist/hooks/public/carts.d.ts +85 -47
- package/dist/hooks/public/delivery-zones.d.ts +2 -0
- package/dist/hooks/public/orders.d.ts +26 -14
- package/dist/hooks/public/products.d.ts +14 -6
- package/dist/rpc-client.d.ts +335 -187
- package/package.json +1 -1
- package/dist/apps/backend/src/generated/zod/index.d.ts +0 -1114
- package/dist/apps/backend/src/generated/zod/index.js +0 -670
- package/dist/apps/backend/src/http-app.d.ts +0 -40
- package/dist/apps/backend/src/http-app.js +0 -134
- package/dist/apps/backend/src/lib/brand-response.d.ts +0 -14
- package/dist/apps/backend/src/lib/brand-response.js +0 -8
- package/dist/apps/backend/src/lib/cart-helpers.d.ts +0 -282
- package/dist/apps/backend/src/lib/cart-helpers.js +0 -121
- package/dist/apps/backend/src/lib/cart-recovery.d.ts +0 -30
- package/dist/apps/backend/src/lib/cart-recovery.js +0 -147
- package/dist/apps/backend/src/lib/cart-response.d.ts +0 -121
- package/dist/apps/backend/src/lib/cart-response.js +0 -150
- package/dist/apps/backend/src/lib/clerk.d.ts +0 -18
- package/dist/apps/backend/src/lib/clerk.js +0 -190
- package/dist/apps/backend/src/lib/delivery-zone-response.d.ts +0 -64
- package/dist/apps/backend/src/lib/delivery-zone-response.js +0 -24
- package/dist/apps/backend/src/lib/discount-code-response.d.ts +0 -42
- package/dist/apps/backend/src/lib/discount-code-response.js +0 -19
- package/dist/apps/backend/src/lib/discount.d.ts +0 -20
- package/dist/apps/backend/src/lib/discount.js +0 -35
- package/dist/apps/backend/src/lib/inventory.d.ts +0 -26
- package/dist/apps/backend/src/lib/inventory.js +0 -160
- package/dist/apps/backend/src/lib/meta-capi.d.ts +0 -53
- package/dist/apps/backend/src/lib/meta-capi.js +0 -151
- package/dist/apps/backend/src/lib/openapi.d.ts +0 -36
- package/dist/apps/backend/src/lib/openapi.js +0 -69
- package/dist/apps/backend/src/lib/order-recovery.d.ts +0 -459
- package/dist/apps/backend/src/lib/order-recovery.js +0 -378
- package/dist/apps/backend/src/lib/order-response.d.ts +0 -138
- package/dist/apps/backend/src/lib/order-response.js +0 -61
- package/dist/apps/backend/src/lib/pricing.d.ts +0 -39
- package/dist/apps/backend/src/lib/pricing.js +0 -62
- package/dist/apps/backend/src/lib/prisma.d.ts +0 -9
- package/dist/apps/backend/src/lib/prisma.js +0 -30
- package/dist/apps/backend/src/lib/product-response.d.ts +0 -82
- package/dist/apps/backend/src/lib/product-response.js +0 -29
- package/dist/apps/backend/src/lib/sentry.d.ts +0 -48
- package/dist/apps/backend/src/lib/sentry.js +0 -180
- package/dist/apps/backend/src/lib/utils.d.ts +0 -32
- package/dist/apps/backend/src/lib/utils.js +0 -63
- package/dist/apps/backend/src/middleware/clerk-auth.d.ts +0 -8
- package/dist/apps/backend/src/middleware/clerk-auth.js +0 -89
- package/dist/apps/backend/src/middleware/cors.d.ts +0 -8
- package/dist/apps/backend/src/middleware/cors.js +0 -11
- package/dist/apps/backend/src/notifications/producers/meta-capi-producer.d.ts +0 -62
- package/dist/apps/backend/src/notifications/producers/meta-capi-producer.js +0 -180
- package/dist/apps/backend/src/notifications/producers/order-notification.d.ts +0 -9
- package/dist/apps/backend/src/notifications/producers/order-notification.js +0 -18
- package/dist/apps/backend/src/notifications/producers/prospect-recovery-notification.d.ts +0 -10
- package/dist/apps/backend/src/notifications/producers/prospect-recovery-notification.js +0 -11
- package/dist/apps/backend/src/routes/admin/abandoned-carts.d.ts +0 -605
- package/dist/apps/backend/src/routes/admin/abandoned-carts.js +0 -194
- package/dist/apps/backend/src/routes/admin/brands.d.ts +0 -175
- package/dist/apps/backend/src/routes/admin/brands.js +0 -118
- package/dist/apps/backend/src/routes/admin/customers.d.ts +0 -308
- package/dist/apps/backend/src/routes/admin/customers.js +0 -39
- package/dist/apps/backend/src/routes/admin/delivery-zones.d.ts +0 -446
- package/dist/apps/backend/src/routes/admin/delivery-zones.js +0 -300
- package/dist/apps/backend/src/routes/admin/discount-codes.d.ts +0 -478
- package/dist/apps/backend/src/routes/admin/discount-codes.js +0 -418
- package/dist/apps/backend/src/routes/admin/inventory.d.ts +0 -273
- package/dist/apps/backend/src/routes/admin/inventory.js +0 -199
- package/dist/apps/backend/src/routes/admin/orders.d.ts +0 -1780
- package/dist/apps/backend/src/routes/admin/orders.js +0 -552
- package/dist/apps/backend/src/routes/admin/products.d.ts +0 -860
- package/dist/apps/backend/src/routes/admin/products.js +0 -126
- package/dist/apps/backend/src/routes/admin/stats.d.ts +0 -290
- package/dist/apps/backend/src/routes/admin/stats.js +0 -55
- package/dist/apps/backend/src/routes/admin/variants.d.ts +0 -239
- package/dist/apps/backend/src/routes/admin/variants.js +0 -197
- package/dist/apps/backend/src/routes/admin/warehouses.d.ts +0 -373
- package/dist/apps/backend/src/routes/admin/warehouses.js +0 -123
- package/dist/apps/backend/src/routes/public/brands.d.ts +0 -40
- package/dist/apps/backend/src/routes/public/brands.js +0 -38
- package/dist/apps/backend/src/routes/public/carts.d.ts +0 -2657
- package/dist/apps/backend/src/routes/public/carts.js +0 -778
- package/dist/apps/backend/src/routes/public/delivery-zones.d.ts +0 -37
- package/dist/apps/backend/src/routes/public/delivery-zones.js +0 -64
- package/dist/apps/backend/src/routes/public/orders.d.ts +0 -609
- package/dist/apps/backend/src/routes/public/orders.js +0 -184
- package/dist/apps/backend/src/routes/public/products.d.ts +0 -449
- package/dist/apps/backend/src/routes/public/products.js +0 -133
- package/dist/apps/backend/src/types/index.d.ts +0 -43
- package/dist/apps/backend/src/types/index.js +0 -2
- package/dist/apps/backend/src/validators/brand.d.ts +0 -17
- package/dist/apps/backend/src/validators/brand.js +0 -15
- package/dist/apps/backend/src/validators/delivery-zone.d.ts +0 -35
- package/dist/apps/backend/src/validators/delivery-zone.js +0 -55
- package/dist/apps/backend/src/validators/discount-code.d.ts +0 -74
- package/dist/apps/backend/src/validators/discount-code.js +0 -50
- package/dist/apps/backend/src/validators/inventory.d.ts +0 -20
- package/dist/apps/backend/src/validators/inventory.js +0 -15
- package/dist/apps/backend/src/validators/order.d.ts +0 -58
- package/dist/apps/backend/src/validators/order.js +0 -62
- package/dist/apps/backend/src/validators/product.d.ts +0 -18
- package/dist/apps/backend/src/validators/product.js +0 -19
- package/dist/apps/backend/src/validators/variant.d.ts +0 -19
- package/dist/apps/backend/src/validators/variant.js +0 -19
- package/dist/apps/backend/src/validators/warehouse.d.ts +0 -15
- package/dist/apps/backend/src/validators/warehouse.js +0 -15
- package/dist/packages/api-client/src/backend-types.d.ts +0 -10
- package/dist/packages/api-client/src/backend-types.js +0 -10
- package/dist/packages/api-client/src/client.d.ts +0 -20
- package/dist/packages/api-client/src/client.js +0 -40
- package/dist/packages/api-client/src/enum-types.d.ts +0 -8
- package/dist/packages/api-client/src/enum-types.js +0 -5
- package/dist/packages/api-client/src/fetchers/brands.d.ts +0 -25
- package/dist/packages/api-client/src/fetchers/brands.js +0 -26
- package/dist/packages/api-client/src/fetchers/carts.d.ts +0 -2337
- package/dist/packages/api-client/src/fetchers/carts.js +0 -174
- package/dist/packages/api-client/src/fetchers/delivery-zones.d.ts +0 -30
- package/dist/packages/api-client/src/fetchers/delivery-zones.js +0 -26
- package/dist/packages/api-client/src/fetchers/index.d.ts +0 -22
- package/dist/packages/api-client/src/fetchers/index.js +0 -22
- package/dist/packages/api-client/src/fetchers/orders.d.ts +0 -544
- package/dist/packages/api-client/src/fetchers/orders.js +0 -44
- package/dist/packages/api-client/src/fetchers/products.d.ts +0 -386
- package/dist/packages/api-client/src/fetchers/products.js +0 -42
- package/dist/packages/api-client/src/hooks/admin/abandoned-carts.d.ts +0 -535
- package/dist/packages/api-client/src/hooks/admin/abandoned-carts.js +0 -83
- package/dist/packages/api-client/src/hooks/admin/brands.d.ts +0 -79
- package/dist/packages/api-client/src/hooks/admin/brands.js +0 -108
- package/dist/packages/api-client/src/hooks/admin/customers.d.ts +0 -280
- package/dist/packages/api-client/src/hooks/admin/customers.js +0 -26
- package/dist/packages/api-client/src/hooks/admin/delivery-zones.d.ts +0 -278
- package/dist/packages/api-client/src/hooks/admin/delivery-zones.js +0 -176
- package/dist/packages/api-client/src/hooks/admin/discount-codes.d.ts +0 -299
- package/dist/packages/api-client/src/hooks/admin/discount-codes.js +0 -165
- package/dist/packages/api-client/src/hooks/admin/index.d.ts +0 -16
- package/dist/packages/api-client/src/hooks/admin/index.js +0 -16
- package/dist/packages/api-client/src/hooks/admin/inventory.d.ts +0 -224
- package/dist/packages/api-client/src/hooks/admin/inventory.js +0 -107
- package/dist/packages/api-client/src/hooks/admin/orders.d.ts +0 -1674
- package/dist/packages/api-client/src/hooks/admin/orders.js +0 -178
- package/dist/packages/api-client/src/hooks/admin/products.d.ts +0 -374
- package/dist/packages/api-client/src/hooks/admin/products.js +0 -89
- package/dist/packages/api-client/src/hooks/admin/stats.d.ts +0 -279
- package/dist/packages/api-client/src/hooks/admin/stats.js +0 -25
- package/dist/packages/api-client/src/hooks/admin/variants.d.ts +0 -115
- package/dist/packages/api-client/src/hooks/admin/variants.js +0 -127
- package/dist/packages/api-client/src/hooks/admin/warehouses.d.ts +0 -277
- package/dist/packages/api-client/src/hooks/admin/warehouses.js +0 -108
- package/dist/packages/api-client/src/hooks/public/brands.d.ts +0 -33
- package/dist/packages/api-client/src/hooks/public/brands.js +0 -30
- package/dist/packages/api-client/src/hooks/public/carts.d.ts +0 -2407
- package/dist/packages/api-client/src/hooks/public/carts.js +0 -213
- package/dist/packages/api-client/src/hooks/public/delivery-zones.d.ts +0 -36
- package/dist/packages/api-client/src/hooks/public/delivery-zones.js +0 -28
- package/dist/packages/api-client/src/hooks/public/index.d.ts +0 -10
- package/dist/packages/api-client/src/hooks/public/index.js +0 -10
- package/dist/packages/api-client/src/hooks/public/orders.d.ts +0 -563
- package/dist/packages/api-client/src/hooks/public/orders.js +0 -50
- package/dist/packages/api-client/src/hooks/public/products.d.ts +0 -398
- package/dist/packages/api-client/src/hooks/public/products.js +0 -47
- package/dist/packages/api-client/src/hooks/use-query-unwrapped.d.ts +0 -20
- package/dist/packages/api-client/src/hooks/use-query-unwrapped.js +0 -22
- package/dist/packages/api-client/src/hooks/useApiConfig.d.ts +0 -12
- package/dist/packages/api-client/src/hooks/useApiConfig.js +0 -14
- package/dist/packages/api-client/src/index.d.ts +0 -20
- package/dist/packages/api-client/src/index.js +0 -25
- package/dist/packages/api-client/src/provider.d.ts +0 -36
- package/dist/packages/api-client/src/provider.js +0 -54
- package/dist/packages/api-client/src/rpc-client.d.ts +0 -9639
- package/dist/packages/api-client/src/rpc-client.js +0 -78
- package/dist/packages/api-client/src/rpc-types.d.ts +0 -76
- package/dist/packages/api-client/src/rpc-types.js +0 -7
- package/dist/packages/api-client/src/types.d.ts +0 -34
- package/dist/packages/api-client/src/types.js +0 -16
- package/dist/packages/api-client/src/utils/query-keys.d.ts +0 -106
- package/dist/packages/api-client/src/utils/query-keys.js +0 -108
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Abandoned cart recovery scheduler
|
|
3
|
-
* Handles automatic sending of recovery WhatsApp messages at different intervals
|
|
4
|
-
*/
|
|
5
|
-
import { getRecoveryDiscountPercentage, generateDiscountCode } from './discount';
|
|
6
|
-
/**
|
|
7
|
-
* Recovery schedule configuration
|
|
8
|
-
*/
|
|
9
|
-
export const RECOVERY_SCHEDULE = [
|
|
10
|
-
{ attemptNumber: 1, hoursAfterAbandonment: 1, discountPercent: 0 },
|
|
11
|
-
{ attemptNumber: 2, hoursAfterAbandonment: 24, discountPercent: 5 },
|
|
12
|
-
{ attemptNumber: 3, hoursAfterAbandonment: 72, discountPercent: 10 },
|
|
13
|
-
];
|
|
14
|
-
/**
|
|
15
|
-
* Find carts eligible for recovery message at specific attempt
|
|
16
|
-
*/
|
|
17
|
-
export async function findCartsForRecovery(prisma, attemptNumber) {
|
|
18
|
-
const schedule = RECOVERY_SCHEDULE.find((s) => s.attemptNumber === attemptNumber);
|
|
19
|
-
if (!schedule)
|
|
20
|
-
return [];
|
|
21
|
-
const now = new Date();
|
|
22
|
-
const cutoffTime = new Date(now.getTime() - schedule.hoursAfterAbandonment * 60 * 60 * 1000);
|
|
23
|
-
// Buffer window: send messages for carts abandoned between cutoffTime and cutoffTime - 1 hour
|
|
24
|
-
const bufferTime = new Date(cutoffTime.getTime() - 60 * 60 * 1000);
|
|
25
|
-
// Don't message anyone who has received a recovery attempt in the last 22 hours
|
|
26
|
-
const lastAttemptCutoff = new Date(now.getTime() - 22 * 60 * 60 * 1000);
|
|
27
|
-
const carts = await prisma.cart.findMany({
|
|
28
|
-
where: {
|
|
29
|
-
OR: [{ customerPhone: { not: null } }, { customerEmail: { not: null } }],
|
|
30
|
-
updatedAt: {
|
|
31
|
-
gte: bufferTime,
|
|
32
|
-
lte: cutoffTime,
|
|
33
|
-
},
|
|
34
|
-
AND: [
|
|
35
|
-
{
|
|
36
|
-
OR: [
|
|
37
|
-
{ lastRecoveryAttemptAt: null },
|
|
38
|
-
{ lastRecoveryAttemptAt: { lte: lastAttemptCutoff } },
|
|
39
|
-
],
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
expiresAt: { gt: now },
|
|
43
|
-
items: { some: {} },
|
|
44
|
-
recoveryAttempts: attemptNumber - 1, // Only send to carts at this attempt
|
|
45
|
-
convertedToOrderId: null, // Not already converted
|
|
46
|
-
},
|
|
47
|
-
include: {
|
|
48
|
-
brand: true,
|
|
49
|
-
items: {
|
|
50
|
-
include: {
|
|
51
|
-
variant: {
|
|
52
|
-
include: {
|
|
53
|
-
product: true,
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
});
|
|
60
|
-
return carts;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Prepares a cart for a recovery attempt.
|
|
64
|
-
* This is the key atomic operation that:
|
|
65
|
-
* 1. Updates the recovery attempt number to prevent duplicate messages
|
|
66
|
-
* 2. Creates/updates the recovery discount code
|
|
67
|
-
* 3. Applies the discount to the cart
|
|
68
|
-
* This should be called *before* queueing any notifications.
|
|
69
|
-
*/
|
|
70
|
-
export async function prepareCartForRecoveryAttempt(prisma, cart, attemptNumber) {
|
|
71
|
-
// 1. Atomically update the attempt number to "claim" this cart for processing
|
|
72
|
-
const updateResult = await prisma.cart.updateMany({
|
|
73
|
-
where: { id: cart.id, recoveryAttempts: attemptNumber - 1 },
|
|
74
|
-
data: { recoveryAttempts: attemptNumber, lastRecoveryAttemptAt: new Date() },
|
|
75
|
-
});
|
|
76
|
-
// If the update failed, it means another process already handled this cart.
|
|
77
|
-
if (updateResult.count === 0) {
|
|
78
|
-
console.log(`[RECOVERY] Cart ${cart.id} already processed for attempt ${attemptNumber}. Skipping.`);
|
|
79
|
-
return { success: false };
|
|
80
|
-
}
|
|
81
|
-
// 2. Create or update the discount code for this recovery attempt, if applicable
|
|
82
|
-
const discountPercent = getRecoveryDiscountPercentage(attemptNumber);
|
|
83
|
-
if (discountPercent > 0) {
|
|
84
|
-
let recoveryCode = null;
|
|
85
|
-
if (cart.recoveryDiscountCodeId) {
|
|
86
|
-
recoveryCode = await prisma.discountCode.findUnique({ where: { id: cart.recoveryDiscountCodeId } });
|
|
87
|
-
if (!recoveryCode) {
|
|
88
|
-
cart.recoveryDiscountCodeId = null; // Stale ID, will create a new one
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
const currentValue = parseFloat(recoveryCode.value.toString());
|
|
92
|
-
// If the existing code is not a percentage or has a lower value, update it
|
|
93
|
-
if (recoveryCode.type !== 'percentage' || currentValue < discountPercent) {
|
|
94
|
-
recoveryCode = await prisma.discountCode.update({
|
|
95
|
-
where: { id: recoveryCode.id },
|
|
96
|
-
data: {
|
|
97
|
-
type: 'percentage',
|
|
98
|
-
value: discountPercent,
|
|
99
|
-
category: 'recovery',
|
|
100
|
-
isActive: true,
|
|
101
|
-
description: `Cart recovery ${discountPercent}%`,
|
|
102
|
-
},
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
// If no valid recovery code exists, create one
|
|
108
|
-
if (!cart.recoveryDiscountCodeId) {
|
|
109
|
-
const codeStr = generateDiscountCode();
|
|
110
|
-
recoveryCode = await prisma.discountCode.create({
|
|
111
|
-
data: {
|
|
112
|
-
code: codeStr,
|
|
113
|
-
brandId: cart.brandId,
|
|
114
|
-
type: 'percentage',
|
|
115
|
-
value: discountPercent,
|
|
116
|
-
category: 'recovery',
|
|
117
|
-
isActive: true,
|
|
118
|
-
description: `Cart recovery ${discountPercent}%`,
|
|
119
|
-
},
|
|
120
|
-
});
|
|
121
|
-
await prisma.cart.update({ where: { id: cart.id }, data: { recoveryDiscountCodeId: recoveryCode.id } });
|
|
122
|
-
}
|
|
123
|
-
// 3. Apply the recovery discount to the cart so it's ready for the customer
|
|
124
|
-
await prisma.cart.update({ where: { id: cart.id }, data: { appliedDiscountCodeId: recoveryCode.id } });
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
// No discount for this attempt, ensure no discount is applied
|
|
128
|
-
await prisma.cart.update({ where: { id: cart.id }, data: { appliedDiscountCodeId: null } });
|
|
129
|
-
}
|
|
130
|
-
// 4. Return the fully updated cart for the producer to use
|
|
131
|
-
const updatedCart = (await prisma.cart.findUnique({
|
|
132
|
-
where: { id: cart.id },
|
|
133
|
-
include: {
|
|
134
|
-
brand: true,
|
|
135
|
-
items: {
|
|
136
|
-
include: {
|
|
137
|
-
variant: {
|
|
138
|
-
include: {
|
|
139
|
-
product: true,
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
-
}));
|
|
146
|
-
return { success: true, cartWithDiscount: updatedCart };
|
|
147
|
-
}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { Prisma, PrismaClient } from '@prisma/client';
|
|
2
|
-
export type DiscountInfo = {
|
|
3
|
-
code: string;
|
|
4
|
-
type: 'percentage' | 'fixed';
|
|
5
|
-
value: number;
|
|
6
|
-
amount: number;
|
|
7
|
-
description: string | null;
|
|
8
|
-
};
|
|
9
|
-
export type CartWithItemsAndBrand = Prisma.CartGetPayload<{
|
|
10
|
-
include: {
|
|
11
|
-
recoveryDiscountCode: true;
|
|
12
|
-
deliveryZone: true;
|
|
13
|
-
brand: true;
|
|
14
|
-
items: {
|
|
15
|
-
include: {
|
|
16
|
-
variant: {
|
|
17
|
-
include: {
|
|
18
|
-
product: true;
|
|
19
|
-
};
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
}>;
|
|
25
|
-
export type CartResponse = Awaited<ReturnType<typeof buildCartResponseWithPricing>>;
|
|
26
|
-
export declare function toPricingItems(cart: CartWithItemsAndBrand): import('./pricing').CartItemForCalculation[];
|
|
27
|
-
export declare function buildCartResponseWithPricing(prisma: PrismaClient, cart: CartWithItemsAndBrand): Promise<{
|
|
28
|
-
id: string;
|
|
29
|
-
brand: {
|
|
30
|
-
createdAt: string;
|
|
31
|
-
updatedAt: string;
|
|
32
|
-
deletedAt: string;
|
|
33
|
-
id: string;
|
|
34
|
-
name: string;
|
|
35
|
-
slug: string;
|
|
36
|
-
logoUrl: string | null;
|
|
37
|
-
siteUrl: string;
|
|
38
|
-
domain: string;
|
|
39
|
-
metaPixelId: string | null;
|
|
40
|
-
};
|
|
41
|
-
customerPhone: string;
|
|
42
|
-
customerEmail: string;
|
|
43
|
-
customerFirstName: string;
|
|
44
|
-
customerLastName: string;
|
|
45
|
-
availablePaymentMethods: import("@prisma/client").$Enums.PaymentMethod[];
|
|
46
|
-
deliveryZone: {
|
|
47
|
-
id: string;
|
|
48
|
-
name: string;
|
|
49
|
-
};
|
|
50
|
-
recoveryAttempts: number;
|
|
51
|
-
lastRecoveryAttemptAt: Date;
|
|
52
|
-
recoveryDiscountCode: {
|
|
53
|
-
id: string;
|
|
54
|
-
type: string;
|
|
55
|
-
value: Prisma.Decimal;
|
|
56
|
-
createdAt: Date;
|
|
57
|
-
updatedAt: Date;
|
|
58
|
-
deletedAt: Date | null;
|
|
59
|
-
brandId: string | null;
|
|
60
|
-
isActive: boolean;
|
|
61
|
-
code: string;
|
|
62
|
-
minPurchase: Prisma.Decimal | null;
|
|
63
|
-
maxDiscount: Prisma.Decimal | null;
|
|
64
|
-
usageLimit: number | null;
|
|
65
|
-
usageCount: number;
|
|
66
|
-
perCustomerLimit: number | null;
|
|
67
|
-
validFrom: Date;
|
|
68
|
-
validUntil: Date | null;
|
|
69
|
-
isAutoApply: boolean;
|
|
70
|
-
description: string | null;
|
|
71
|
-
category: string;
|
|
72
|
-
createdBy: string | null;
|
|
73
|
-
};
|
|
74
|
-
items: {
|
|
75
|
-
id: string;
|
|
76
|
-
variant: {
|
|
77
|
-
price: number;
|
|
78
|
-
product: {
|
|
79
|
-
id: string;
|
|
80
|
-
name: string;
|
|
81
|
-
slug: string;
|
|
82
|
-
createdAt: Date;
|
|
83
|
-
updatedAt: Date;
|
|
84
|
-
deletedAt: Date | null;
|
|
85
|
-
brandId: string;
|
|
86
|
-
isActive: boolean;
|
|
87
|
-
description: string | null;
|
|
88
|
-
thumbnailUrl: string | null;
|
|
89
|
-
quantityDiscounts: Prisma.JsonValue | null;
|
|
90
|
-
};
|
|
91
|
-
id: string;
|
|
92
|
-
name: string | null;
|
|
93
|
-
createdAt: Date;
|
|
94
|
-
updatedAt: Date;
|
|
95
|
-
deletedAt: Date | null;
|
|
96
|
-
isActive: boolean;
|
|
97
|
-
thumbnailUrl: string | null;
|
|
98
|
-
productId: string;
|
|
99
|
-
sku: string;
|
|
100
|
-
trackInventory: boolean;
|
|
101
|
-
lowStockThreshold: number | null;
|
|
102
|
-
};
|
|
103
|
-
quantity: number;
|
|
104
|
-
basePrice: number;
|
|
105
|
-
discountPercent: number;
|
|
106
|
-
finalPrice: number;
|
|
107
|
-
subtotal: number;
|
|
108
|
-
}[];
|
|
109
|
-
pricing: {
|
|
110
|
-
subtotal: number;
|
|
111
|
-
deliveryCharge: number;
|
|
112
|
-
discount: DiscountInfo;
|
|
113
|
-
total: number;
|
|
114
|
-
};
|
|
115
|
-
createdAt: string;
|
|
116
|
-
updatedAt: string;
|
|
117
|
-
expiresAt: string;
|
|
118
|
-
convertedToOrderId: string;
|
|
119
|
-
wasRecovered: boolean;
|
|
120
|
-
recoveryUrl: string;
|
|
121
|
-
}>;
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { calculateCartCost } from './pricing';
|
|
2
|
-
function toNumber(value) {
|
|
3
|
-
if (typeof value === 'number')
|
|
4
|
-
return value;
|
|
5
|
-
return parseFloat(value.toString());
|
|
6
|
-
}
|
|
7
|
-
function round(value) {
|
|
8
|
-
return Math.round(value * 100) / 100;
|
|
9
|
-
}
|
|
10
|
-
export function toPricingItems(cart) {
|
|
11
|
-
return cart.items.map((item) => {
|
|
12
|
-
const rawQtyDiscounts = item.variant.product.quantityDiscounts;
|
|
13
|
-
let quantityDiscounts = null;
|
|
14
|
-
if (rawQtyDiscounts && typeof rawQtyDiscounts === 'object' && !Array.isArray(rawQtyDiscounts)) {
|
|
15
|
-
quantityDiscounts = rawQtyDiscounts;
|
|
16
|
-
}
|
|
17
|
-
return {
|
|
18
|
-
variantId: item.variantId,
|
|
19
|
-
quantity: item.quantity,
|
|
20
|
-
variant: {
|
|
21
|
-
price: item.variant.price,
|
|
22
|
-
product: {
|
|
23
|
-
id: item.variant.product.id,
|
|
24
|
-
quantityDiscounts,
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
async function computePricingWithZone(prisma, cart) {
|
|
31
|
-
const subtotalOnly = calculateCartCost(toPricingItems(cart)).subtotal;
|
|
32
|
-
let deliveryCharge = 0;
|
|
33
|
-
let estimatedDays = null;
|
|
34
|
-
if (cart.deliveryZoneId) {
|
|
35
|
-
const zone = await prisma.deliveryZone.findFirst({
|
|
36
|
-
where: { id: cart.deliveryZoneId, isActive: true, deletedAt: null },
|
|
37
|
-
});
|
|
38
|
-
if (zone) {
|
|
39
|
-
const threshold = zone.freeShippingThreshold ? Number(zone.freeShippingThreshold) : null;
|
|
40
|
-
const base = Number(zone.deliveryCost);
|
|
41
|
-
deliveryCharge = threshold !== null && subtotalOnly >= threshold ? 0 : base;
|
|
42
|
-
estimatedDays = zone.estimatedDays ?? null;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
const pricing = calculateCartCost(toPricingItems(cart), deliveryCharge);
|
|
46
|
-
return { pricing, estimatedDays };
|
|
47
|
-
}
|
|
48
|
-
async function computeAppliedDiscount(prisma, cart, subtotal) {
|
|
49
|
-
if (!cart.appliedDiscountCodeId)
|
|
50
|
-
return { discountAmount: 0, discountInfo: null };
|
|
51
|
-
const discountCode = await prisma.discountCode.findUnique({ where: { id: cart.appliedDiscountCodeId } });
|
|
52
|
-
if (!discountCode || !discountCode.isActive) {
|
|
53
|
-
return { discountAmount: 0, discountInfo: null };
|
|
54
|
-
}
|
|
55
|
-
const now = new Date();
|
|
56
|
-
if (discountCode.validFrom && discountCode.validFrom > now)
|
|
57
|
-
return { discountAmount: 0, discountInfo: null };
|
|
58
|
-
if (discountCode.validUntil && discountCode.validUntil <= now)
|
|
59
|
-
return { discountAmount: 0, discountInfo: null };
|
|
60
|
-
if (discountCode.brandId && discountCode.brandId !== cart.brandId)
|
|
61
|
-
return { discountAmount: 0, discountInfo: null };
|
|
62
|
-
let discountAmount = 0;
|
|
63
|
-
if (discountCode.type === 'percentage') {
|
|
64
|
-
discountAmount = round(subtotal * (toNumber(discountCode.value) / 100));
|
|
65
|
-
if (discountCode.maxDiscount) {
|
|
66
|
-
const maxDiscountNum = toNumber(discountCode.maxDiscount);
|
|
67
|
-
if (discountAmount > maxDiscountNum)
|
|
68
|
-
discountAmount = maxDiscountNum;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
discountAmount = Math.min(toNumber(discountCode.value), subtotal);
|
|
73
|
-
}
|
|
74
|
-
const discountType = discountCode.type === 'percentage' ? 'percentage' : 'fixed';
|
|
75
|
-
const discountInfo = {
|
|
76
|
-
code: discountCode.code,
|
|
77
|
-
type: discountType,
|
|
78
|
-
value: toNumber(discountCode.value),
|
|
79
|
-
amount: discountAmount,
|
|
80
|
-
description: discountCode.description,
|
|
81
|
-
};
|
|
82
|
-
return { discountAmount, discountInfo };
|
|
83
|
-
}
|
|
84
|
-
function formatCartResponse(cart, pricing) {
|
|
85
|
-
const pricingMap = new Map(pricing.items.map((p) => [p.variantId, p]));
|
|
86
|
-
const { id, brand, customerPhone, customerEmail, customerFirstName, customerLastName, availablePaymentMethods, deliveryZone, recoveryAttempts, lastRecoveryAttemptAt, recoveryDiscountCode, convertedToOrderId, wasRecovered, expiresAt } = cart;
|
|
87
|
-
return {
|
|
88
|
-
id,
|
|
89
|
-
brand: {
|
|
90
|
-
...brand,
|
|
91
|
-
createdAt: brand.createdAt.toISOString(),
|
|
92
|
-
updatedAt: brand.updatedAt.toISOString(),
|
|
93
|
-
deletedAt: brand.deletedAt?.toISOString() ?? null,
|
|
94
|
-
},
|
|
95
|
-
customerPhone,
|
|
96
|
-
customerEmail,
|
|
97
|
-
customerFirstName,
|
|
98
|
-
customerLastName,
|
|
99
|
-
availablePaymentMethods,
|
|
100
|
-
deliveryZone: deliveryZone ? {
|
|
101
|
-
id: deliveryZone.id,
|
|
102
|
-
name: deliveryZone.name,
|
|
103
|
-
} : null,
|
|
104
|
-
// recovery
|
|
105
|
-
recoveryAttempts,
|
|
106
|
-
lastRecoveryAttemptAt,
|
|
107
|
-
recoveryDiscountCode,
|
|
108
|
-
items: cart.items.map((item) => {
|
|
109
|
-
const itemPricing = pricingMap.get(item.variantId);
|
|
110
|
-
const ip = itemPricing;
|
|
111
|
-
return {
|
|
112
|
-
id: item.id,
|
|
113
|
-
variant: {
|
|
114
|
-
...item.variant,
|
|
115
|
-
price: toNumber(item.variant.price),
|
|
116
|
-
product: item.variant.product,
|
|
117
|
-
},
|
|
118
|
-
quantity: item.quantity,
|
|
119
|
-
basePrice: ip ? ip.basePrice : 0,
|
|
120
|
-
discountPercent: ip ? ip.discountPercent : 0,
|
|
121
|
-
finalPrice: ip ? ip.finalPrice : 0,
|
|
122
|
-
subtotal: ip ? ip.subtotal : 0,
|
|
123
|
-
};
|
|
124
|
-
}),
|
|
125
|
-
pricing: {
|
|
126
|
-
subtotal: pricing.subtotal,
|
|
127
|
-
deliveryCharge: pricing.deliveryCharge,
|
|
128
|
-
discount: pricing.discount ?? null,
|
|
129
|
-
total: pricing.total,
|
|
130
|
-
},
|
|
131
|
-
createdAt: cart.createdAt.toISOString(),
|
|
132
|
-
updatedAt: cart.updatedAt.toISOString(),
|
|
133
|
-
expiresAt: expiresAt?.toISOString() ?? null,
|
|
134
|
-
convertedToOrderId,
|
|
135
|
-
wasRecovered,
|
|
136
|
-
recoveryUrl: `${cart.brand.siteUrl}?cartId=${id}`
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
export async function buildCartResponseWithPricing(prisma, cart) {
|
|
140
|
-
const { pricing } = await computePricingWithZone(prisma, cart);
|
|
141
|
-
const { discountAmount, discountInfo } = await computeAppliedDiscount(prisma, cart, pricing.subtotal);
|
|
142
|
-
const finalSubtotal = round(Math.max(0, pricing.subtotal - discountAmount));
|
|
143
|
-
const pricingWithDiscount = {
|
|
144
|
-
...pricing,
|
|
145
|
-
discount: discountInfo,
|
|
146
|
-
finalSubtotal,
|
|
147
|
-
total: round(Math.max(0, finalSubtotal + pricing.deliveryCharge)),
|
|
148
|
-
};
|
|
149
|
-
return formatCartResponse(cart, pricingWithDiscount);
|
|
150
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export interface ClerkUser {
|
|
2
|
-
id: string;
|
|
3
|
-
email: string;
|
|
4
|
-
name?: string;
|
|
5
|
-
}
|
|
6
|
-
export interface ClerkUserData {
|
|
7
|
-
id: string;
|
|
8
|
-
first_name?: string;
|
|
9
|
-
last_name?: string;
|
|
10
|
-
email_addresses?: Array<{
|
|
11
|
-
email_address: string;
|
|
12
|
-
id: string;
|
|
13
|
-
}>;
|
|
14
|
-
primary_email_address_id?: string;
|
|
15
|
-
primary_email_address?: string;
|
|
16
|
-
}
|
|
17
|
-
export declare function verifyClerkToken(token: string, publishableKey: string): Promise<ClerkUser | null>;
|
|
18
|
-
export declare function extractBearerToken(authHeader?: string): string | null;
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import { captureException } from './sentry';
|
|
2
|
-
// In-memory cache for JWKS (in production, consider using Workers KV or Durable Objects)
|
|
3
|
-
let jwksCache = null;
|
|
4
|
-
const JWKS_CACHE_TTL = 3600000; // 1 hour in milliseconds
|
|
5
|
-
// Decode base64url (used in JWT)
|
|
6
|
-
function base64UrlDecode(str) {
|
|
7
|
-
// Replace URL-safe characters
|
|
8
|
-
let base64 = str.replace(/-/g, '+').replace(/_/g, '/');
|
|
9
|
-
// Pad with '=' to make length multiple of 4
|
|
10
|
-
while (base64.length % 4 !== 0) {
|
|
11
|
-
base64 += '=';
|
|
12
|
-
}
|
|
13
|
-
const binary = atob(base64);
|
|
14
|
-
const bytes = new Uint8Array(binary.length);
|
|
15
|
-
for (let i = 0; i < binary.length; i++) {
|
|
16
|
-
bytes[i] = binary.charCodeAt(i);
|
|
17
|
-
}
|
|
18
|
-
return bytes;
|
|
19
|
-
}
|
|
20
|
-
// Decode base64url to string
|
|
21
|
-
function base64UrlDecodeString(str) {
|
|
22
|
-
const bytes = base64UrlDecode(str);
|
|
23
|
-
return new TextDecoder().decode(bytes);
|
|
24
|
-
}
|
|
25
|
-
// Fetch Clerk's JWKS
|
|
26
|
-
async function fetchJWKS(publishableKey) {
|
|
27
|
-
// Check cache first
|
|
28
|
-
if (jwksCache && Date.now() - jwksCache.timestamp < JWKS_CACHE_TTL) {
|
|
29
|
-
console.log('Using cached JWKS with', jwksCache.keys.length, 'keys');
|
|
30
|
-
return jwksCache.keys;
|
|
31
|
-
}
|
|
32
|
-
try {
|
|
33
|
-
// Decode the publishable key to get the frontend API domain
|
|
34
|
-
// Format: pk_test_<base64> or pk_live_<base64>
|
|
35
|
-
const parts = publishableKey.split('_');
|
|
36
|
-
if (parts.length < 3) {
|
|
37
|
-
console.error('Invalid publishable key format');
|
|
38
|
-
return [];
|
|
39
|
-
}
|
|
40
|
-
const base64Part = parts.slice(2).join('_');
|
|
41
|
-
const decoded = atob(base64Part);
|
|
42
|
-
// The decoded value should be the domain (e.g., "climbing-oyster-86.clerk.accounts.dev$")
|
|
43
|
-
// Remove trailing $ if present
|
|
44
|
-
const domain = decoded.replace(/\$+$/, '');
|
|
45
|
-
console.log('Decoded Clerk domain:', domain);
|
|
46
|
-
// Clerk JWKS endpoint format: https://<frontend-api>/.well-known/jwks.json
|
|
47
|
-
const jwksUrl = `https://${domain}/.well-known/jwks.json`;
|
|
48
|
-
console.log('Fetching JWKS from:', jwksUrl);
|
|
49
|
-
const response = await fetch(jwksUrl);
|
|
50
|
-
if (!response.ok) {
|
|
51
|
-
const errorText = await response.text();
|
|
52
|
-
console.error('Failed to fetch JWKS:', response.status, errorText);
|
|
53
|
-
// Capture JWKS fetch errors
|
|
54
|
-
captureException(new Error(`Failed to fetch JWKS: ${response.status} ${errorText}`), {
|
|
55
|
-
level: 'error',
|
|
56
|
-
tags: {
|
|
57
|
-
error_type: 'clerk_jwks_fetch_error',
|
|
58
|
-
http_status: response.status.toString(),
|
|
59
|
-
},
|
|
60
|
-
extra: {
|
|
61
|
-
jwksUrl: jwksUrl,
|
|
62
|
-
publishableKey: publishableKey.substring(0, 20) + '...', // Truncate for security
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
return [];
|
|
66
|
-
}
|
|
67
|
-
const jwks = await response.json();
|
|
68
|
-
console.log('Successfully fetched', jwks.keys?.length || 0, 'JWKS keys');
|
|
69
|
-
// Log the key IDs for debugging
|
|
70
|
-
if (jwks.keys) {
|
|
71
|
-
console.log('Available key IDs:', jwks.keys.map(k => k.kid).join(', '));
|
|
72
|
-
}
|
|
73
|
-
// Update cache
|
|
74
|
-
jwksCache = {
|
|
75
|
-
keys: jwks.keys,
|
|
76
|
-
timestamp: Date.now(),
|
|
77
|
-
};
|
|
78
|
-
return jwks.keys;
|
|
79
|
-
}
|
|
80
|
-
catch (error) {
|
|
81
|
-
console.error('Error fetching JWKS:', error);
|
|
82
|
-
// Capture JWKS exception errors
|
|
83
|
-
captureException(error instanceof Error ? error : new Error(String(error)), {
|
|
84
|
-
level: 'error',
|
|
85
|
-
tags: {
|
|
86
|
-
error_type: 'clerk_jwks_exception',
|
|
87
|
-
},
|
|
88
|
-
extra: {
|
|
89
|
-
publishableKey: publishableKey.substring(0, 20) + '...', // Truncate for security
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
return [];
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
// Convert base64url-encoded RSA components to CryptoKey
|
|
96
|
-
async function importRSAKey(jwk) {
|
|
97
|
-
try {
|
|
98
|
-
const keyData = {
|
|
99
|
-
kty: jwk.kty,
|
|
100
|
-
n: jwk.n,
|
|
101
|
-
e: jwk.e,
|
|
102
|
-
alg: jwk.alg,
|
|
103
|
-
ext: true,
|
|
104
|
-
key_ops: ['verify'],
|
|
105
|
-
};
|
|
106
|
-
return await crypto.subtle.importKey('jwk', keyData, {
|
|
107
|
-
name: 'RSASSA-PKCS1-v1_5',
|
|
108
|
-
hash: 'SHA-256',
|
|
109
|
-
}, false, ['verify']);
|
|
110
|
-
}
|
|
111
|
-
catch (error) {
|
|
112
|
-
console.error('Error importing RSA key:', error);
|
|
113
|
-
return null;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
// Verify JWT signature
|
|
117
|
-
async function verifySignature(token, publicKey) {
|
|
118
|
-
try {
|
|
119
|
-
const parts = token.split('.');
|
|
120
|
-
const signature = base64UrlDecode(parts[2]);
|
|
121
|
-
const data = new TextEncoder().encode(`${parts[0]}.${parts[1]}`);
|
|
122
|
-
return await crypto.subtle.verify('RSASSA-PKCS1-v1_5', publicKey, signature, data);
|
|
123
|
-
}
|
|
124
|
-
catch (error) {
|
|
125
|
-
console.error('Error verifying signature:', error);
|
|
126
|
-
return false;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
// Verify JWT token using Clerk's JWKS
|
|
130
|
-
export async function verifyClerkToken(token, publishableKey) {
|
|
131
|
-
try {
|
|
132
|
-
// Parse JWT to get header and payload
|
|
133
|
-
const parts = token.split('.');
|
|
134
|
-
if (parts.length !== 3) {
|
|
135
|
-
console.error('Invalid JWT format');
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
const header = JSON.parse(base64UrlDecodeString(parts[0]));
|
|
139
|
-
const payload = JSON.parse(base64UrlDecodeString(parts[1]));
|
|
140
|
-
console.log('JWT Header kid:', header.kid);
|
|
141
|
-
console.log('JWT Payload sub:', payload.sub);
|
|
142
|
-
// Check if token is expired
|
|
143
|
-
if (payload.exp && payload.exp < Math.floor(Date.now() / 1000)) {
|
|
144
|
-
console.error('Token expired');
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
// Verify required claims
|
|
148
|
-
if (!payload.sub) {
|
|
149
|
-
console.error('Missing sub claim');
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
// Fetch JWKS and find the matching key
|
|
153
|
-
const jwks = await fetchJWKS(publishableKey);
|
|
154
|
-
console.log('Looking for kid:', header.kid, 'in', jwks.length, 'keys');
|
|
155
|
-
const jwk = jwks.find((key) => key.kid === header.kid);
|
|
156
|
-
if (!jwk) {
|
|
157
|
-
console.error('No matching JWK found for kid:', header.kid);
|
|
158
|
-
console.error('Available kids:', jwks.map(k => k.kid).join(', '));
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
// Import the public key
|
|
162
|
-
const publicKey = await importRSAKey(jwk);
|
|
163
|
-
if (!publicKey) {
|
|
164
|
-
console.error('Failed to import public key');
|
|
165
|
-
return null;
|
|
166
|
-
}
|
|
167
|
-
// Verify the signature
|
|
168
|
-
const isValid = await verifySignature(token, publicKey);
|
|
169
|
-
if (!isValid) {
|
|
170
|
-
console.error('Invalid signature');
|
|
171
|
-
return null;
|
|
172
|
-
}
|
|
173
|
-
// Token is valid, return user info
|
|
174
|
-
return {
|
|
175
|
-
id: payload.sub,
|
|
176
|
-
email: payload.email || payload.primary_email_address_id || '',
|
|
177
|
-
name: payload.name || payload.first_name || payload.given_name || '',
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
catch (error) {
|
|
181
|
-
console.error('Clerk token verification failed:', error);
|
|
182
|
-
return null;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
export function extractBearerToken(authHeader) {
|
|
186
|
-
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
187
|
-
return null;
|
|
188
|
-
}
|
|
189
|
-
return authHeader.substring(7);
|
|
190
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import type { Prisma } from '@prisma/client';
|
|
2
|
-
export type DeliveryZoneDBResponse = Prisma.DeliveryZoneGetPayload<{
|
|
3
|
-
include: {
|
|
4
|
-
brand: true;
|
|
5
|
-
state: true;
|
|
6
|
-
};
|
|
7
|
-
}>;
|
|
8
|
-
export type StateDBResponse = Prisma.StateGetPayload<{
|
|
9
|
-
include?: {
|
|
10
|
-
deliveryZones?: true;
|
|
11
|
-
};
|
|
12
|
-
}>;
|
|
13
|
-
export declare function formatStateResponse(state: StateDBResponse & {
|
|
14
|
-
deliveryZones?: any[];
|
|
15
|
-
}): {
|
|
16
|
-
zonesCount: number;
|
|
17
|
-
createdAt: string;
|
|
18
|
-
updatedAt: string;
|
|
19
|
-
deletedAt: string;
|
|
20
|
-
id: string;
|
|
21
|
-
name: string;
|
|
22
|
-
isActive: boolean;
|
|
23
|
-
deliveryZones?: any[];
|
|
24
|
-
};
|
|
25
|
-
export declare function formatDeliveryZoneResponse(deliveryZone: DeliveryZoneDBResponse): {
|
|
26
|
-
deliveryCost: number;
|
|
27
|
-
freeShippingThreshold: number;
|
|
28
|
-
createdAt: string;
|
|
29
|
-
updatedAt: string;
|
|
30
|
-
deletedAt: string;
|
|
31
|
-
brand: {
|
|
32
|
-
createdAt: string;
|
|
33
|
-
updatedAt: string;
|
|
34
|
-
deletedAt: string;
|
|
35
|
-
id: string;
|
|
36
|
-
name: string;
|
|
37
|
-
slug: string;
|
|
38
|
-
logoUrl: string | null;
|
|
39
|
-
siteUrl: string;
|
|
40
|
-
domain: string;
|
|
41
|
-
metaPixelId: string | null;
|
|
42
|
-
};
|
|
43
|
-
stateName: string;
|
|
44
|
-
brandName: string;
|
|
45
|
-
state: {
|
|
46
|
-
id: string;
|
|
47
|
-
name: string;
|
|
48
|
-
createdAt: Date;
|
|
49
|
-
updatedAt: Date;
|
|
50
|
-
deletedAt: Date | null;
|
|
51
|
-
isActive: boolean;
|
|
52
|
-
};
|
|
53
|
-
id: string;
|
|
54
|
-
name: string;
|
|
55
|
-
brandId: string | null;
|
|
56
|
-
stateId: string;
|
|
57
|
-
allowCOD: boolean;
|
|
58
|
-
allowOnline: boolean;
|
|
59
|
-
waybillOnly: boolean;
|
|
60
|
-
estimatedDays: number | null;
|
|
61
|
-
noteTitle: string | null;
|
|
62
|
-
noteContent: string | null;
|
|
63
|
-
isActive: boolean;
|
|
64
|
-
};
|