@instockng/api-client 1.0.9 → 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 -613
- 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 -312
- 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 -277
- package/dist/apps/backend/src/routes/admin/inventory.js +0 -199
- package/dist/apps/backend/src/routes/admin/orders.d.ts +0 -1804
- package/dist/apps/backend/src/routes/admin/orders.js +0 -552
- package/dist/apps/backend/src/routes/admin/products.d.ts +0 -876
- package/dist/apps/backend/src/routes/admin/products.js +0 -126
- package/dist/apps/backend/src/routes/admin/stats.d.ts +0 -294
- 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 -377
- 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 -2693
- 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 -617
- package/dist/apps/backend/src/routes/public/orders.js +0 -184
- package/dist/apps/backend/src/routes/public/products.d.ts +0 -457
- 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 -2373
- 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 -552
- package/dist/packages/api-client/src/fetchers/orders.js +0 -44
- package/dist/packages/api-client/src/fetchers/products.d.ts +0 -394
- package/dist/packages/api-client/src/fetchers/products.js +0 -42
- package/dist/packages/api-client/src/hooks/admin/abandoned-carts.d.ts +0 -543
- 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 -284
- 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 -228
- package/dist/packages/api-client/src/hooks/admin/inventory.js +0 -107
- package/dist/packages/api-client/src/hooks/admin/orders.d.ts +0 -1698
- package/dist/packages/api-client/src/hooks/admin/orders.js +0 -178
- package/dist/packages/api-client/src/hooks/admin/products.d.ts +0 -382
- package/dist/packages/api-client/src/hooks/admin/products.js +0 -89
- package/dist/packages/api-client/src/hooks/admin/stats.d.ts +0 -283
- 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 -281
- 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 -2443
- 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 -571
- package/dist/packages/api-client/src/hooks/public/orders.js +0 -50
- package/dist/packages/api-client/src/hooks/public/products.d.ts +0 -406
- 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 -9755
- 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,24 +0,0 @@
|
|
|
1
|
-
import { formatBrandResponse } from "./brand-response";
|
|
2
|
-
import { toNumber } from "./utils";
|
|
3
|
-
export function formatStateResponse(state) {
|
|
4
|
-
return {
|
|
5
|
-
...state,
|
|
6
|
-
zonesCount: state.deliveryZones?.length || 0,
|
|
7
|
-
createdAt: state.createdAt.toISOString(),
|
|
8
|
-
updatedAt: state.updatedAt.toISOString(),
|
|
9
|
-
deletedAt: state.deletedAt ? state.deletedAt.toISOString() : null,
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
export function formatDeliveryZoneResponse(deliveryZone) {
|
|
13
|
-
return {
|
|
14
|
-
...deliveryZone,
|
|
15
|
-
deliveryCost: toNumber(deliveryZone.deliveryCost),
|
|
16
|
-
freeShippingThreshold: deliveryZone.freeShippingThreshold ? toNumber(deliveryZone.freeShippingThreshold) : null,
|
|
17
|
-
createdAt: deliveryZone.createdAt.toISOString(),
|
|
18
|
-
updatedAt: deliveryZone.updatedAt.toISOString(),
|
|
19
|
-
deletedAt: deliveryZone.deletedAt ? deliveryZone.deletedAt.toISOString() : null,
|
|
20
|
-
brand: deliveryZone.brand ? formatBrandResponse(deliveryZone.brand) : null,
|
|
21
|
-
stateName: deliveryZone.state?.name || '',
|
|
22
|
-
brandName: deliveryZone.brand?.name || null,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import type { Prisma } from "@prisma/client";
|
|
2
|
-
export type DiscountCodeDBResponse = Prisma.DiscountCodeGetPayload<{
|
|
3
|
-
include: {
|
|
4
|
-
brand: true;
|
|
5
|
-
};
|
|
6
|
-
}>;
|
|
7
|
-
export declare function formatDiscountCodeResponse(discountCode: DiscountCodeDBResponse): {
|
|
8
|
-
value: number;
|
|
9
|
-
minPurchase: number;
|
|
10
|
-
maxDiscount: number;
|
|
11
|
-
createdAt: string;
|
|
12
|
-
updatedAt: string;
|
|
13
|
-
deletedAt: string;
|
|
14
|
-
brand: {
|
|
15
|
-
createdAt: string;
|
|
16
|
-
updatedAt: string;
|
|
17
|
-
deletedAt: string;
|
|
18
|
-
id: string;
|
|
19
|
-
name: string;
|
|
20
|
-
slug: string;
|
|
21
|
-
logoUrl: string | null;
|
|
22
|
-
siteUrl: string;
|
|
23
|
-
domain: string;
|
|
24
|
-
metaPixelId: string | null;
|
|
25
|
-
};
|
|
26
|
-
isExpired: boolean;
|
|
27
|
-
usagePercentage: number;
|
|
28
|
-
id: string;
|
|
29
|
-
type: string;
|
|
30
|
-
brandId: string | null;
|
|
31
|
-
isActive: boolean;
|
|
32
|
-
code: string;
|
|
33
|
-
usageLimit: number | null;
|
|
34
|
-
usageCount: number;
|
|
35
|
-
perCustomerLimit: number | null;
|
|
36
|
-
validFrom: Date;
|
|
37
|
-
validUntil: Date | null;
|
|
38
|
-
isAutoApply: boolean;
|
|
39
|
-
description: string | null;
|
|
40
|
-
category: string;
|
|
41
|
-
createdBy: string | null;
|
|
42
|
-
};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { formatBrandResponse } from "./brand-response";
|
|
2
|
-
import { toNumber } from "./utils";
|
|
3
|
-
export function formatDiscountCodeResponse(discountCode) {
|
|
4
|
-
const now = new Date();
|
|
5
|
-
return {
|
|
6
|
-
...discountCode,
|
|
7
|
-
value: toNumber(discountCode.value),
|
|
8
|
-
minPurchase: discountCode.minPurchase ? toNumber(discountCode.minPurchase) : null,
|
|
9
|
-
maxDiscount: discountCode.maxDiscount ? toNumber(discountCode.maxDiscount) : null,
|
|
10
|
-
createdAt: discountCode.createdAt.toISOString(),
|
|
11
|
-
updatedAt: discountCode.updatedAt.toISOString(),
|
|
12
|
-
deletedAt: discountCode.deletedAt ? discountCode.deletedAt.toISOString() : null,
|
|
13
|
-
brand: discountCode.brand ? formatBrandResponse(discountCode.brand) : null,
|
|
14
|
-
isExpired: discountCode.validUntil ? discountCode.validUntil < now : false,
|
|
15
|
-
usagePercentage: discountCode.usageLimit
|
|
16
|
-
? (discountCode.usageCount / discountCode.usageLimit) * 100
|
|
17
|
-
: null,
|
|
18
|
-
};
|
|
19
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Discount code generation and validation utilities
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Generate a unique discount code for abandoned cart recovery
|
|
6
|
-
* Format: CART{RANDOM8} (e.g., CART5A9F3B2E)
|
|
7
|
-
*/
|
|
8
|
-
export declare function generateDiscountCode(): string;
|
|
9
|
-
/**
|
|
10
|
-
* Calculate discount amount based on cart recovery attempt
|
|
11
|
-
*/
|
|
12
|
-
export declare function getRecoveryDiscountPercentage(attemptNumber: number): number;
|
|
13
|
-
/**
|
|
14
|
-
* Calculate discount amount in currency
|
|
15
|
-
*/
|
|
16
|
-
export declare function calculateDiscountAmount(subtotal: number, discountPercent: number): number;
|
|
17
|
-
/**
|
|
18
|
-
* Validate discount code format
|
|
19
|
-
*/
|
|
20
|
-
export declare function isValidDiscountCodeFormat(code: string): boolean;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Discount code generation and validation utilities
|
|
3
|
-
*/
|
|
4
|
-
import { RECOVERY_SCHEDULE } from './cart-recovery';
|
|
5
|
-
/**
|
|
6
|
-
* Generate a unique discount code for abandoned cart recovery
|
|
7
|
-
* Format: CART{RANDOM8} (e.g., CART5A9F3B2E)
|
|
8
|
-
*/
|
|
9
|
-
export function generateDiscountCode() {
|
|
10
|
-
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; // Excluding similar characters
|
|
11
|
-
let code = 'CART';
|
|
12
|
-
for (let i = 0; i < 8; i++) {
|
|
13
|
-
code += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
14
|
-
}
|
|
15
|
-
return code;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Calculate discount amount based on cart recovery attempt
|
|
19
|
-
*/
|
|
20
|
-
export function getRecoveryDiscountPercentage(attemptNumber) {
|
|
21
|
-
const schedule = RECOVERY_SCHEDULE.find((s) => s.attemptNumber === attemptNumber);
|
|
22
|
-
return schedule ? schedule.discountPercent : 0;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Calculate discount amount in currency
|
|
26
|
-
*/
|
|
27
|
-
export function calculateDiscountAmount(subtotal, discountPercent) {
|
|
28
|
-
return Math.round(subtotal * (discountPercent / 100));
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Validate discount code format
|
|
32
|
-
*/
|
|
33
|
-
export function isValidDiscountCodeFormat(code) {
|
|
34
|
-
return /^CART[A-Z2-9]{8}$/.test(code);
|
|
35
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { PrismaClient, InventoryTransactionType } from '@prisma/client';
|
|
2
|
-
export interface InventoryAdjustment {
|
|
3
|
-
variantId: string;
|
|
4
|
-
warehouseId: string;
|
|
5
|
-
quantity: number;
|
|
6
|
-
type: InventoryTransactionType;
|
|
7
|
-
reason?: string;
|
|
8
|
-
userId?: string;
|
|
9
|
-
metadata?: any;
|
|
10
|
-
orderId?: string;
|
|
11
|
-
}
|
|
12
|
-
export declare function adjustInventory(prisma: PrismaClient, adjustment: InventoryAdjustment): Promise<void>;
|
|
13
|
-
export declare function transferInventory(prisma: PrismaClient, params: {
|
|
14
|
-
variantId: string;
|
|
15
|
-
fromWarehouseId: string;
|
|
16
|
-
toWarehouseId: string;
|
|
17
|
-
quantity: number;
|
|
18
|
-
userId?: string;
|
|
19
|
-
reason?: string;
|
|
20
|
-
}): Promise<void>;
|
|
21
|
-
export declare function getTotalInventoryForVariant(prisma: PrismaClient, variantId: string): Promise<number>;
|
|
22
|
-
export declare function checkInventoryAvailability(prisma: PrismaClient, variantId: string, requiredQuantity: number, warehouseId?: string): Promise<{
|
|
23
|
-
available: boolean;
|
|
24
|
-
totalInventory: number;
|
|
25
|
-
}>;
|
|
26
|
-
export declare function getLowStockVariants(prisma: PrismaClient, brandId?: string): Promise<any[]>;
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
export async function adjustInventory(prisma, adjustment) {
|
|
2
|
-
const { variantId, warehouseId, quantity, type, reason, userId, metadata, orderId } = adjustment;
|
|
3
|
-
// Get current inventory
|
|
4
|
-
let inventory = await prisma.warehouseInventory.findUnique({
|
|
5
|
-
where: {
|
|
6
|
-
variantId_warehouseId: {
|
|
7
|
-
variantId,
|
|
8
|
-
warehouseId,
|
|
9
|
-
},
|
|
10
|
-
},
|
|
11
|
-
});
|
|
12
|
-
// Create inventory record if it doesn't exist
|
|
13
|
-
if (!inventory) {
|
|
14
|
-
inventory = await prisma.warehouseInventory.create({
|
|
15
|
-
data: {
|
|
16
|
-
variantId,
|
|
17
|
-
warehouseId,
|
|
18
|
-
inventoryCount: 0,
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
// Calculate new balance
|
|
23
|
-
const balanceAfter = inventory.inventoryCount + quantity;
|
|
24
|
-
// TODO:Prevent negative inventory (optional - can be configured per variant)
|
|
25
|
-
if (balanceAfter < 0) {
|
|
26
|
-
// throw new Error('Insufficient inventory');
|
|
27
|
-
}
|
|
28
|
-
// Update inventory count
|
|
29
|
-
await prisma.warehouseInventory.update({
|
|
30
|
-
where: {
|
|
31
|
-
variantId_warehouseId: {
|
|
32
|
-
variantId,
|
|
33
|
-
warehouseId,
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
data: {
|
|
37
|
-
inventoryCount: balanceAfter,
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
// Create transaction record
|
|
41
|
-
await prisma.inventoryTransaction.create({
|
|
42
|
-
data: {
|
|
43
|
-
variantId,
|
|
44
|
-
warehouseId,
|
|
45
|
-
type,
|
|
46
|
-
quantity,
|
|
47
|
-
balanceAfter,
|
|
48
|
-
reason,
|
|
49
|
-
userId,
|
|
50
|
-
metadata,
|
|
51
|
-
orderId,
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
export async function transferInventory(prisma, params) {
|
|
56
|
-
const { variantId, fromWarehouseId, toWarehouseId, quantity, userId, reason } = params;
|
|
57
|
-
if (quantity <= 0) {
|
|
58
|
-
throw new Error('Transfer quantity must be positive');
|
|
59
|
-
}
|
|
60
|
-
const metadata = {
|
|
61
|
-
transferFrom: fromWarehouseId,
|
|
62
|
-
transferTo: toWarehouseId,
|
|
63
|
-
transferQuantity: quantity,
|
|
64
|
-
};
|
|
65
|
-
// Use transaction to ensure atomicity
|
|
66
|
-
await prisma.$transaction(async (tx) => {
|
|
67
|
-
// Decrement from source warehouse
|
|
68
|
-
await adjustInventory(tx, {
|
|
69
|
-
variantId,
|
|
70
|
-
warehouseId: fromWarehouseId,
|
|
71
|
-
quantity: -quantity,
|
|
72
|
-
type: 'transfer_out',
|
|
73
|
-
reason: reason || `Transfer to ${toWarehouseId}`,
|
|
74
|
-
userId,
|
|
75
|
-
metadata,
|
|
76
|
-
});
|
|
77
|
-
// Increment to destination warehouse
|
|
78
|
-
await adjustInventory(tx, {
|
|
79
|
-
variantId,
|
|
80
|
-
warehouseId: toWarehouseId,
|
|
81
|
-
quantity: quantity,
|
|
82
|
-
type: 'transfer_in',
|
|
83
|
-
reason: reason || `Transfer from ${fromWarehouseId}`,
|
|
84
|
-
userId,
|
|
85
|
-
metadata,
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
export async function getTotalInventoryForVariant(prisma, variantId) {
|
|
90
|
-
const inventories = await prisma.warehouseInventory.findMany({
|
|
91
|
-
where: { variantId },
|
|
92
|
-
});
|
|
93
|
-
return inventories.reduce((sum, inv) => sum + inv.inventoryCount, 0);
|
|
94
|
-
}
|
|
95
|
-
export async function checkInventoryAvailability(prisma, variantId, requiredQuantity, warehouseId) {
|
|
96
|
-
let totalInventory = 0;
|
|
97
|
-
if (warehouseId) {
|
|
98
|
-
// Check specific warehouse
|
|
99
|
-
const inventory = await prisma.warehouseInventory.findUnique({
|
|
100
|
-
where: {
|
|
101
|
-
variantId_warehouseId: {
|
|
102
|
-
variantId,
|
|
103
|
-
warehouseId,
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
});
|
|
107
|
-
totalInventory = inventory?.inventoryCount || 0;
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
// Check total across all warehouses
|
|
111
|
-
totalInventory = await getTotalInventoryForVariant(prisma, variantId);
|
|
112
|
-
}
|
|
113
|
-
return {
|
|
114
|
-
available: totalInventory >= requiredQuantity,
|
|
115
|
-
totalInventory,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
export async function getLowStockVariants(prisma, brandId) {
|
|
119
|
-
const where = {
|
|
120
|
-
trackInventory: true,
|
|
121
|
-
lowStockThreshold: { not: null },
|
|
122
|
-
deletedAt: null,
|
|
123
|
-
};
|
|
124
|
-
if (brandId) {
|
|
125
|
-
where.product = { brandId };
|
|
126
|
-
}
|
|
127
|
-
const variants = await prisma.productVariant.findMany({
|
|
128
|
-
where,
|
|
129
|
-
include: {
|
|
130
|
-
product: {
|
|
131
|
-
include: { brand: true },
|
|
132
|
-
},
|
|
133
|
-
warehouseInventories: {
|
|
134
|
-
include: { warehouse: true },
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
});
|
|
138
|
-
// Filter variants where total inventory is below threshold
|
|
139
|
-
const lowStockVariants = variants.filter((variant) => {
|
|
140
|
-
const totalInventory = variant.warehouseInventories.reduce((sum, inv) => sum + inv.inventoryCount, 0);
|
|
141
|
-
return totalInventory < (variant.lowStockThreshold || 0);
|
|
142
|
-
});
|
|
143
|
-
return lowStockVariants.map((variant) => {
|
|
144
|
-
const totalInventory = variant.warehouseInventories.reduce((sum, inv) => sum + inv.inventoryCount, 0);
|
|
145
|
-
return {
|
|
146
|
-
id: variant.id,
|
|
147
|
-
sku: variant.sku,
|
|
148
|
-
productName: variant.product.name,
|
|
149
|
-
name: variant.name,
|
|
150
|
-
brandName: variant.product.brand.name,
|
|
151
|
-
totalInventory,
|
|
152
|
-
threshold: variant.lowStockThreshold,
|
|
153
|
-
warehouses: variant.warehouseInventories.map((inv) => ({
|
|
154
|
-
warehouseId: inv.warehouseId,
|
|
155
|
-
warehouseName: inv.warehouse.name,
|
|
156
|
-
inventory: inv.inventoryCount,
|
|
157
|
-
})),
|
|
158
|
-
};
|
|
159
|
-
});
|
|
160
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Meta Conversions API (CAPI) Service
|
|
3
|
-
*
|
|
4
|
-
* Sends server-side events to Meta for conversion tracking.
|
|
5
|
-
* Used alongside browser pixel for maximum reliability and iOS 14+ compliance.
|
|
6
|
-
*/
|
|
7
|
-
export type MetaEventName = 'AddToCart' | 'InitiateCheckout' | 'Purchase' | 'ViewContent' | 'ConfirmedPurchase';
|
|
8
|
-
export interface MetaCapiQueueMessage {
|
|
9
|
-
pixelId: string;
|
|
10
|
-
eventName: MetaEventName;
|
|
11
|
-
eventId: string;
|
|
12
|
-
eventTime: number;
|
|
13
|
-
eventSourceUrl: string;
|
|
14
|
-
userData: {
|
|
15
|
-
email?: string;
|
|
16
|
-
phone?: string;
|
|
17
|
-
firstName?: string;
|
|
18
|
-
lastName?: string;
|
|
19
|
-
city?: string;
|
|
20
|
-
state?: string;
|
|
21
|
-
country?: string;
|
|
22
|
-
zipCode?: string;
|
|
23
|
-
clientIpAddress?: string;
|
|
24
|
-
clientUserAgent?: string;
|
|
25
|
-
fbc?: string;
|
|
26
|
-
fbp?: string;
|
|
27
|
-
};
|
|
28
|
-
customData: {
|
|
29
|
-
value?: number;
|
|
30
|
-
currency?: string;
|
|
31
|
-
contentIds?: string[];
|
|
32
|
-
contents?: Array<{
|
|
33
|
-
id: string;
|
|
34
|
-
quantity: number;
|
|
35
|
-
item_price: number;
|
|
36
|
-
}>;
|
|
37
|
-
contentType?: string;
|
|
38
|
-
numItems?: number;
|
|
39
|
-
contentName?: string;
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Send event to Meta Conversions API
|
|
44
|
-
*
|
|
45
|
-
* @param accessToken - Meta Access Token (from Cloudflare secrets)
|
|
46
|
-
* @param message - Queue message with event data
|
|
47
|
-
*/
|
|
48
|
-
export declare function sendMetaCapiEvent(accessToken: string, message: MetaCapiQueueMessage): Promise<void>;
|
|
49
|
-
/**
|
|
50
|
-
* Helper to generate event ID for deduplication
|
|
51
|
-
* Uses existing DB IDs to ensure same event from browser and server have same ID
|
|
52
|
-
*/
|
|
53
|
-
export declare function generateEventId(type: 'cart' | 'order', id: string, suffix?: string): string;
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Meta Conversions API (CAPI) Service
|
|
3
|
-
*
|
|
4
|
-
* Sends server-side events to Meta for conversion tracking.
|
|
5
|
-
* Used alongside browser pixel for maximum reliability and iOS 14+ compliance.
|
|
6
|
-
*/
|
|
7
|
-
import crypto from 'crypto';
|
|
8
|
-
import { captureException } from './sentry';
|
|
9
|
-
/**
|
|
10
|
-
* Hash data with SHA256 for Meta CAPI
|
|
11
|
-
* Meta requires PII to be hashed before sending
|
|
12
|
-
*/
|
|
13
|
-
function hashData(data) {
|
|
14
|
-
// Normalize: lowercase and trim whitespace
|
|
15
|
-
const normalized = data.toLowerCase().trim();
|
|
16
|
-
return crypto.createHash('sha256').update(normalized).digest('hex');
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Normalize phone number to E.164 format
|
|
20
|
-
* Meta requires: country code + digits only (no spaces, dashes, etc.)
|
|
21
|
-
*/
|
|
22
|
-
function normalizePhone(phone) {
|
|
23
|
-
// Remove all non-digit characters
|
|
24
|
-
let digits = phone.replace(/\D/g, '');
|
|
25
|
-
// If starts with 0, assume Nigerian number and add +234
|
|
26
|
-
if (digits.startsWith('0')) {
|
|
27
|
-
digits = '234' + digits.slice(1);
|
|
28
|
-
}
|
|
29
|
-
// If doesn't start with country code, assume Nigerian
|
|
30
|
-
if (!digits.startsWith('234')) {
|
|
31
|
-
digits = '234' + digits;
|
|
32
|
-
}
|
|
33
|
-
return digits;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Send event to Meta Conversions API
|
|
37
|
-
*
|
|
38
|
-
* @param accessToken - Meta Access Token (from Cloudflare secrets)
|
|
39
|
-
* @param message - Queue message with event data
|
|
40
|
-
*/
|
|
41
|
-
export async function sendMetaCapiEvent(accessToken, message) {
|
|
42
|
-
const { pixelId, eventName, eventId, eventTime, eventSourceUrl, userData, customData } = message;
|
|
43
|
-
// Build user_data with hashed PII
|
|
44
|
-
const user_data = {
|
|
45
|
-
client_ip_address: userData.clientIpAddress,
|
|
46
|
-
client_user_agent: userData.clientUserAgent,
|
|
47
|
-
fbc: userData.fbc,
|
|
48
|
-
fbp: userData.fbp,
|
|
49
|
-
};
|
|
50
|
-
// Hash email if provided
|
|
51
|
-
if (userData.email) {
|
|
52
|
-
user_data.em = [hashData(userData.email)];
|
|
53
|
-
}
|
|
54
|
-
// Hash phone if provided
|
|
55
|
-
if (userData.phone) {
|
|
56
|
-
const normalized = normalizePhone(userData.phone);
|
|
57
|
-
user_data.ph = [hashData(normalized)];
|
|
58
|
-
}
|
|
59
|
-
// Hash name if provided
|
|
60
|
-
if (userData.firstName) {
|
|
61
|
-
user_data.fn = [hashData(userData.firstName)];
|
|
62
|
-
}
|
|
63
|
-
if (userData.lastName) {
|
|
64
|
-
user_data.ln = [hashData(userData.lastName)];
|
|
65
|
-
}
|
|
66
|
-
// Hash location if provided
|
|
67
|
-
if (userData.city) {
|
|
68
|
-
user_data.ct = [hashData(userData.city)];
|
|
69
|
-
}
|
|
70
|
-
if (userData.state) {
|
|
71
|
-
user_data.st = [hashData(userData.state)];
|
|
72
|
-
}
|
|
73
|
-
if (userData.zipCode) {
|
|
74
|
-
user_data.zp = [hashData(userData.zipCode)];
|
|
75
|
-
}
|
|
76
|
-
if (userData.country) {
|
|
77
|
-
user_data.country = [hashData(userData.country)];
|
|
78
|
-
}
|
|
79
|
-
// Build event
|
|
80
|
-
const event = {
|
|
81
|
-
event_name: eventName,
|
|
82
|
-
event_time: eventTime,
|
|
83
|
-
event_id: eventId,
|
|
84
|
-
event_source_url: eventSourceUrl,
|
|
85
|
-
action_source: 'website',
|
|
86
|
-
user_data,
|
|
87
|
-
custom_data: customData,
|
|
88
|
-
};
|
|
89
|
-
// Send to Meta CAPI
|
|
90
|
-
const url = `https://graph.facebook.com/v21.0/${pixelId}/events`;
|
|
91
|
-
const response = await fetch(url, {
|
|
92
|
-
method: 'POST',
|
|
93
|
-
headers: {
|
|
94
|
-
'Content-Type': 'application/json',
|
|
95
|
-
},
|
|
96
|
-
body: JSON.stringify({
|
|
97
|
-
data: [event],
|
|
98
|
-
access_token: accessToken,
|
|
99
|
-
}),
|
|
100
|
-
});
|
|
101
|
-
if (!response.ok) {
|
|
102
|
-
const error = await response.text();
|
|
103
|
-
const metaError = new Error(`Meta CAPI error: ${response.status} ${error}`);
|
|
104
|
-
// Capture Meta CAPI HTTP errors
|
|
105
|
-
captureException(metaError, {
|
|
106
|
-
level: 'warning', // Non-blocking for users
|
|
107
|
-
tags: {
|
|
108
|
-
error_type: 'meta_capi_http_error',
|
|
109
|
-
event_name: message.eventName,
|
|
110
|
-
pixel_id: message.pixelId,
|
|
111
|
-
http_status: response.status.toString(),
|
|
112
|
-
},
|
|
113
|
-
extra: {
|
|
114
|
-
eventId: message.eventId,
|
|
115
|
-
responseBody: error,
|
|
116
|
-
},
|
|
117
|
-
});
|
|
118
|
-
throw metaError;
|
|
119
|
-
}
|
|
120
|
-
const result = await response.json();
|
|
121
|
-
// Log if Meta returned any errors
|
|
122
|
-
if (result.events_received !== 1) {
|
|
123
|
-
console.error('[Meta CAPI] Event not received:', result);
|
|
124
|
-
const receiveError = new Error('Meta CAPI did not receive event');
|
|
125
|
-
// Capture event not received errors
|
|
126
|
-
captureException(receiveError, {
|
|
127
|
-
level: 'warning',
|
|
128
|
-
tags: {
|
|
129
|
-
error_type: 'meta_capi_event_not_received',
|
|
130
|
-
event_name: message.eventName,
|
|
131
|
-
pixel_id: message.pixelId,
|
|
132
|
-
},
|
|
133
|
-
extra: {
|
|
134
|
-
eventId: message.eventId,
|
|
135
|
-
eventsReceived: result.events_received,
|
|
136
|
-
response: result,
|
|
137
|
-
},
|
|
138
|
-
});
|
|
139
|
-
throw receiveError;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Helper to generate event ID for deduplication
|
|
144
|
-
* Uses existing DB IDs to ensure same event from browser and server have same ID
|
|
145
|
-
*/
|
|
146
|
-
export function generateEventId(type, id, suffix) {
|
|
147
|
-
if (type === 'order') {
|
|
148
|
-
return suffix ? `order_${id}_${suffix}` : `order_${id}`;
|
|
149
|
-
}
|
|
150
|
-
return suffix ? `cart_${id}_${suffix}` : `cart_${id}`;
|
|
151
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { OpenAPIHono } from '@hono/zod-openapi';
|
|
2
|
-
import { AppContext } from '../types';
|
|
3
|
-
/**
|
|
4
|
-
* Create a new OpenAPI-enabled Hono app instance
|
|
5
|
-
* This extends the standard Hono with OpenAPI documentation capabilities
|
|
6
|
-
*/
|
|
7
|
-
export declare function createOpenAPIApp(): OpenAPIHono<AppContext, {}, "/">;
|
|
8
|
-
/**
|
|
9
|
-
* OpenAPI documentation configuration
|
|
10
|
-
*/
|
|
11
|
-
export declare const openapiConfig: {
|
|
12
|
-
openapi: string;
|
|
13
|
-
info: {
|
|
14
|
-
title: string;
|
|
15
|
-
version: string;
|
|
16
|
-
description: string;
|
|
17
|
-
};
|
|
18
|
-
servers: {
|
|
19
|
-
url: string;
|
|
20
|
-
description: string;
|
|
21
|
-
}[];
|
|
22
|
-
tags: {
|
|
23
|
-
name: string;
|
|
24
|
-
description: string;
|
|
25
|
-
}[];
|
|
26
|
-
components: {
|
|
27
|
-
securitySchemes: {
|
|
28
|
-
clerkAuth: {
|
|
29
|
-
type: string;
|
|
30
|
-
scheme: string;
|
|
31
|
-
bearerFormat: string;
|
|
32
|
-
description: string;
|
|
33
|
-
};
|
|
34
|
-
};
|
|
35
|
-
};
|
|
36
|
-
};
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { OpenAPIHono } from '@hono/zod-openapi';
|
|
2
|
-
/**
|
|
3
|
-
* Create a new OpenAPI-enabled Hono app instance
|
|
4
|
-
* This extends the standard Hono with OpenAPI documentation capabilities
|
|
5
|
-
*/
|
|
6
|
-
export function createOpenAPIApp() {
|
|
7
|
-
return new OpenAPIHono({
|
|
8
|
-
defaultHook: (result, c) => {
|
|
9
|
-
if (!result.success) {
|
|
10
|
-
return c.json({
|
|
11
|
-
success: false,
|
|
12
|
-
error: {
|
|
13
|
-
code: 'VALIDATION_ERROR',
|
|
14
|
-
message: 'Request validation failed',
|
|
15
|
-
details: 'error' in result ? result.error.flatten() : undefined,
|
|
16
|
-
},
|
|
17
|
-
}, 400);
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* OpenAPI documentation configuration
|
|
24
|
-
*/
|
|
25
|
-
export const openapiConfig = {
|
|
26
|
-
openapi: '3.1.0',
|
|
27
|
-
info: {
|
|
28
|
-
title: 'OMS API',
|
|
29
|
-
version: '1.0.0',
|
|
30
|
-
description: 'Order Management System API - A comprehensive e-commerce backend',
|
|
31
|
-
},
|
|
32
|
-
servers: [
|
|
33
|
-
{
|
|
34
|
-
url: 'https://api.example.com',
|
|
35
|
-
description: 'Production server',
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
url: 'http://localhost:8787',
|
|
39
|
-
description: 'Local development server',
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
tags: [
|
|
43
|
-
{ name: 'Public - Orders', description: 'Public order tracking endpoints' },
|
|
44
|
-
{ name: 'Public - Products', description: 'Public product catalog endpoints' },
|
|
45
|
-
{ name: 'Public - Carts', description: 'Public shopping cart endpoints' },
|
|
46
|
-
{ name: 'Public - Delivery Zones', description: 'Public delivery zone endpoints' },
|
|
47
|
-
{ name: 'Admin - Orders', description: 'Admin order management endpoints' },
|
|
48
|
-
{ name: 'Admin - Products', description: 'Admin product management endpoints' },
|
|
49
|
-
{ name: 'Admin - Brands', description: 'Admin brand management endpoints' },
|
|
50
|
-
{ name: 'Admin - Variants', description: 'Admin variant management endpoints' },
|
|
51
|
-
{ name: 'Admin - Warehouses', description: 'Admin warehouse management endpoints' },
|
|
52
|
-
{ name: 'Admin - Inventory', description: 'Admin inventory management endpoints' },
|
|
53
|
-
{ name: 'Admin - Customers', description: 'Admin customer management endpoints' },
|
|
54
|
-
{ name: 'Admin - Stats', description: 'Admin statistics endpoints' },
|
|
55
|
-
{ name: 'Admin - Abandoned Carts', description: 'Admin abandoned cart management endpoints' },
|
|
56
|
-
{ name: 'Admin - Discount Codes', description: 'Admin discount code management endpoints' },
|
|
57
|
-
{ name: 'Admin - Delivery Zones', description: 'Admin delivery zone management endpoints' },
|
|
58
|
-
],
|
|
59
|
-
components: {
|
|
60
|
-
securitySchemes: {
|
|
61
|
-
clerkAuth: {
|
|
62
|
-
type: 'http',
|
|
63
|
-
scheme: 'bearer',
|
|
64
|
-
bearerFormat: 'JWT',
|
|
65
|
-
description: 'Clerk JWT token for admin authentication',
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
};
|