@contractspec/example.marketplace 3.7.5 → 3.7.7
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/README.md +63 -131
- package/dist/browser/entities/index.js +470 -470
- package/dist/browser/index.js +945 -944
- package/dist/browser/order/index.js +155 -155
- package/dist/browser/order/order.event.js +1 -1
- package/dist/browser/payout/index.js +71 -71
- package/dist/browser/payout/payout.event.js +1 -1
- package/dist/browser/product/index.js +104 -104
- package/dist/browser/product/product.event.js +1 -1
- package/dist/browser/review/index.js +75 -75
- package/dist/browser/review/review.event.js +1 -1
- package/dist/browser/store/index.js +68 -68
- package/dist/browser/store/store.event.js +1 -1
- package/dist/browser/ui/MarketplaceDashboard.js +35 -35
- package/dist/browser/ui/hooks/index.js +1 -1
- package/dist/browser/ui/hooks/useMarketplaceData.js +1 -1
- package/dist/browser/ui/index.js +285 -284
- package/dist/entities/index.d.ts +110 -110
- package/dist/entities/index.js +470 -470
- package/dist/index.d.ts +3 -3
- package/dist/index.js +945 -944
- package/dist/node/entities/index.js +470 -470
- package/dist/node/index.js +945 -944
- package/dist/node/order/index.js +155 -155
- package/dist/node/order/order.event.js +1 -1
- package/dist/node/payout/index.js +71 -71
- package/dist/node/payout/payout.event.js +1 -1
- package/dist/node/product/index.js +104 -104
- package/dist/node/product/product.event.js +1 -1
- package/dist/node/review/index.js +75 -75
- package/dist/node/review/review.event.js +1 -1
- package/dist/node/store/index.js +68 -68
- package/dist/node/store/store.event.js +1 -1
- package/dist/node/ui/MarketplaceDashboard.js +35 -35
- package/dist/node/ui/hooks/index.js +1 -1
- package/dist/node/ui/hooks/useMarketplaceData.js +1 -1
- package/dist/node/ui/index.js +285 -284
- package/dist/order/index.d.ts +2 -2
- package/dist/order/index.js +155 -155
- package/dist/order/order.event.js +1 -1
- package/dist/payout/index.d.ts +2 -2
- package/dist/payout/index.js +71 -71
- package/dist/payout/payout.event.js +1 -1
- package/dist/product/index.d.ts +2 -2
- package/dist/product/index.js +104 -104
- package/dist/product/product.event.js +1 -1
- package/dist/review/index.d.ts +2 -2
- package/dist/review/index.js +75 -75
- package/dist/review/review.event.js +1 -1
- package/dist/store/index.d.ts +2 -2
- package/dist/store/index.js +68 -68
- package/dist/store/store.event.js +1 -1
- package/dist/ui/MarketplaceDashboard.js +35 -35
- package/dist/ui/hooks/index.d.ts +1 -1
- package/dist/ui/hooks/index.js +1 -1
- package/dist/ui/hooks/useMarketplaceData.js +1 -1
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.js +285 -284
- package/dist/ui/renderers/index.d.ts +1 -1
- package/package.json +10 -10
package/dist/entities/index.js
CHANGED
|
@@ -1,250 +1,12 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// src/entities/
|
|
2
|
+
// src/entities/order.ts
|
|
3
3
|
import {
|
|
4
4
|
defineEntity,
|
|
5
5
|
defineEntityEnum,
|
|
6
6
|
field,
|
|
7
7
|
index
|
|
8
8
|
} from "@contractspec/lib.schema";
|
|
9
|
-
var
|
|
10
|
-
name: "StoreStatus",
|
|
11
|
-
values: ["PENDING", "ACTIVE", "SUSPENDED", "CLOSED"],
|
|
12
|
-
schema: "marketplace",
|
|
13
|
-
description: "Status of a store."
|
|
14
|
-
});
|
|
15
|
-
var StoreTypeEnum = defineEntityEnum({
|
|
16
|
-
name: "StoreType",
|
|
17
|
-
values: ["INDIVIDUAL", "BUSINESS", "ENTERPRISE"],
|
|
18
|
-
schema: "marketplace",
|
|
19
|
-
description: "Type of store account."
|
|
20
|
-
});
|
|
21
|
-
var StoreEntity = defineEntity({
|
|
22
|
-
name: "Store",
|
|
23
|
-
description: "A seller storefront on the marketplace.",
|
|
24
|
-
schema: "marketplace",
|
|
25
|
-
map: "store",
|
|
26
|
-
fields: {
|
|
27
|
-
id: field.id({ description: "Unique store ID" }),
|
|
28
|
-
name: field.string({ description: "Store display name" }),
|
|
29
|
-
slug: field.string({ description: "URL-friendly identifier" }),
|
|
30
|
-
description: field.string({ isOptional: true }),
|
|
31
|
-
status: field.enum("StoreStatus", { default: "PENDING" }),
|
|
32
|
-
type: field.enum("StoreType", { default: "INDIVIDUAL" }),
|
|
33
|
-
ownerId: field.foreignKey({ description: "Store owner user ID" }),
|
|
34
|
-
organizationId: field.foreignKey({ isOptional: true }),
|
|
35
|
-
logoFileId: field.string({
|
|
36
|
-
isOptional: true,
|
|
37
|
-
description: "Logo file reference"
|
|
38
|
-
}),
|
|
39
|
-
bannerFileId: field.string({
|
|
40
|
-
isOptional: true,
|
|
41
|
-
description: "Banner file reference"
|
|
42
|
-
}),
|
|
43
|
-
email: field.string({ isOptional: true }),
|
|
44
|
-
phone: field.string({ isOptional: true }),
|
|
45
|
-
website: field.string({ isOptional: true }),
|
|
46
|
-
country: field.string({ isOptional: true }),
|
|
47
|
-
currency: field.string({ default: '"USD"' }),
|
|
48
|
-
timezone: field.string({ isOptional: true }),
|
|
49
|
-
commissionRate: field.decimal({
|
|
50
|
-
default: 0.1,
|
|
51
|
-
description: "Platform commission rate (e.g., 0.1 = 10%)"
|
|
52
|
-
}),
|
|
53
|
-
isVerified: field.boolean({ default: false }),
|
|
54
|
-
verifiedAt: field.dateTime({ isOptional: true }),
|
|
55
|
-
settings: field.json({ isOptional: true }),
|
|
56
|
-
metadata: field.json({ isOptional: true }),
|
|
57
|
-
totalProducts: field.int({ default: 0 }),
|
|
58
|
-
totalOrders: field.int({ default: 0 }),
|
|
59
|
-
totalRevenue: field.decimal({ default: 0 }),
|
|
60
|
-
averageRating: field.decimal({ default: 0 }),
|
|
61
|
-
createdAt: field.createdAt(),
|
|
62
|
-
updatedAt: field.updatedAt(),
|
|
63
|
-
products: field.hasMany("Product"),
|
|
64
|
-
orders: field.hasMany("Order"),
|
|
65
|
-
payouts: field.hasMany("Payout")
|
|
66
|
-
},
|
|
67
|
-
indexes: [
|
|
68
|
-
index.unique(["slug"]),
|
|
69
|
-
index.on(["ownerId"]),
|
|
70
|
-
index.on(["status"]),
|
|
71
|
-
index.on(["country", "status"]),
|
|
72
|
-
index.on(["averageRating"])
|
|
73
|
-
],
|
|
74
|
-
enums: [StoreStatusEnum, StoreTypeEnum]
|
|
75
|
-
});
|
|
76
|
-
var StoreCategoryEntity = defineEntity({
|
|
77
|
-
name: "StoreCategory",
|
|
78
|
-
description: "Category assignment for stores.",
|
|
79
|
-
schema: "marketplace",
|
|
80
|
-
map: "store_category",
|
|
81
|
-
fields: {
|
|
82
|
-
id: field.id(),
|
|
83
|
-
storeId: field.foreignKey(),
|
|
84
|
-
categoryId: field.foreignKey(),
|
|
85
|
-
isPrimary: field.boolean({ default: false }),
|
|
86
|
-
createdAt: field.createdAt(),
|
|
87
|
-
store: field.belongsTo("Store", ["storeId"], ["id"], {
|
|
88
|
-
onDelete: "Cascade"
|
|
89
|
-
})
|
|
90
|
-
},
|
|
91
|
-
indexes: [index.unique(["storeId", "categoryId"]), index.on(["categoryId"])]
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// src/entities/product.ts
|
|
95
|
-
import {
|
|
96
|
-
defineEntity as defineEntity2,
|
|
97
|
-
defineEntityEnum as defineEntityEnum2,
|
|
98
|
-
field as field2,
|
|
99
|
-
index as index2
|
|
100
|
-
} from "@contractspec/lib.schema";
|
|
101
|
-
var ProductStatusEnum = defineEntityEnum2({
|
|
102
|
-
name: "ProductStatus",
|
|
103
|
-
values: [
|
|
104
|
-
"DRAFT",
|
|
105
|
-
"PENDING_REVIEW",
|
|
106
|
-
"ACTIVE",
|
|
107
|
-
"OUT_OF_STOCK",
|
|
108
|
-
"DISCONTINUED",
|
|
109
|
-
"REJECTED"
|
|
110
|
-
],
|
|
111
|
-
schema: "marketplace",
|
|
112
|
-
description: "Status of a product listing."
|
|
113
|
-
});
|
|
114
|
-
var ProductTypeEnum = defineEntityEnum2({
|
|
115
|
-
name: "ProductType",
|
|
116
|
-
values: ["PHYSICAL", "DIGITAL", "SERVICE", "SUBSCRIPTION"],
|
|
117
|
-
schema: "marketplace",
|
|
118
|
-
description: "Type of product."
|
|
119
|
-
});
|
|
120
|
-
var ProductEntity = defineEntity2({
|
|
121
|
-
name: "Product",
|
|
122
|
-
description: "A product listing on the marketplace.",
|
|
123
|
-
schema: "marketplace",
|
|
124
|
-
map: "product",
|
|
125
|
-
fields: {
|
|
126
|
-
id: field2.id({ description: "Unique product ID" }),
|
|
127
|
-
storeId: field2.foreignKey(),
|
|
128
|
-
name: field2.string({ description: "Product name" }),
|
|
129
|
-
slug: field2.string({ description: "URL-friendly identifier" }),
|
|
130
|
-
description: field2.string({ isOptional: true }),
|
|
131
|
-
shortDescription: field2.string({ isOptional: true }),
|
|
132
|
-
status: field2.enum("ProductStatus", { default: "DRAFT" }),
|
|
133
|
-
type: field2.enum("ProductType", { default: "PHYSICAL" }),
|
|
134
|
-
price: field2.decimal({ description: "Base price" }),
|
|
135
|
-
compareAtPrice: field2.decimal({
|
|
136
|
-
isOptional: true,
|
|
137
|
-
description: "Original price for showing discounts"
|
|
138
|
-
}),
|
|
139
|
-
currency: field2.string({ default: '"USD"' }),
|
|
140
|
-
sku: field2.string({ isOptional: true }),
|
|
141
|
-
barcode: field2.string({ isOptional: true }),
|
|
142
|
-
quantity: field2.int({ default: 0 }),
|
|
143
|
-
trackInventory: field2.boolean({ default: true }),
|
|
144
|
-
allowBackorder: field2.boolean({ default: false }),
|
|
145
|
-
lowStockThreshold: field2.int({ default: 5 }),
|
|
146
|
-
weight: field2.decimal({ isOptional: true }),
|
|
147
|
-
weightUnit: field2.string({ default: '"kg"' }),
|
|
148
|
-
categoryId: field2.string({ isOptional: true }),
|
|
149
|
-
tags: field2.string({ isArray: true }),
|
|
150
|
-
primaryImageId: field2.string({ isOptional: true }),
|
|
151
|
-
seoTitle: field2.string({ isOptional: true }),
|
|
152
|
-
seoDescription: field2.string({ isOptional: true }),
|
|
153
|
-
attributes: field2.json({
|
|
154
|
-
isOptional: true,
|
|
155
|
-
description: "Custom product attributes"
|
|
156
|
-
}),
|
|
157
|
-
reviewCount: field2.int({ default: 0 }),
|
|
158
|
-
averageRating: field2.decimal({ default: 0 }),
|
|
159
|
-
totalSold: field2.int({ default: 0 }),
|
|
160
|
-
createdAt: field2.createdAt(),
|
|
161
|
-
updatedAt: field2.updatedAt(),
|
|
162
|
-
publishedAt: field2.dateTime({ isOptional: true }),
|
|
163
|
-
store: field2.belongsTo("Store", ["storeId"], ["id"]),
|
|
164
|
-
variants: field2.hasMany("ProductVariant"),
|
|
165
|
-
orderItems: field2.hasMany("OrderItem"),
|
|
166
|
-
reviews: field2.hasMany("Review")
|
|
167
|
-
},
|
|
168
|
-
indexes: [
|
|
169
|
-
index2.unique(["storeId", "slug"]),
|
|
170
|
-
index2.on(["storeId", "status"]),
|
|
171
|
-
index2.on(["status", "publishedAt"]),
|
|
172
|
-
index2.on(["categoryId", "status"]),
|
|
173
|
-
index2.on(["averageRating"]),
|
|
174
|
-
index2.on(["totalSold"]),
|
|
175
|
-
index2.on(["price"])
|
|
176
|
-
],
|
|
177
|
-
enums: [ProductStatusEnum, ProductTypeEnum]
|
|
178
|
-
});
|
|
179
|
-
var ProductVariantEntity = defineEntity2({
|
|
180
|
-
name: "ProductVariant",
|
|
181
|
-
description: "A variant of a product with specific options.",
|
|
182
|
-
schema: "marketplace",
|
|
183
|
-
map: "product_variant",
|
|
184
|
-
fields: {
|
|
185
|
-
id: field2.id(),
|
|
186
|
-
productId: field2.foreignKey(),
|
|
187
|
-
name: field2.string({ description: 'Variant name (e.g., "Large / Blue")' }),
|
|
188
|
-
options: field2.json({
|
|
189
|
-
description: 'Variant options (e.g., {size: "L", color: "Blue"})'
|
|
190
|
-
}),
|
|
191
|
-
price: field2.decimal({ description: "Variant-specific price" }),
|
|
192
|
-
compareAtPrice: field2.decimal({ isOptional: true }),
|
|
193
|
-
sku: field2.string({ isOptional: true }),
|
|
194
|
-
barcode: field2.string({ isOptional: true }),
|
|
195
|
-
quantity: field2.int({ default: 0 }),
|
|
196
|
-
imageId: field2.string({ isOptional: true }),
|
|
197
|
-
isActive: field2.boolean({ default: true }),
|
|
198
|
-
position: field2.int({ default: 0 }),
|
|
199
|
-
createdAt: field2.createdAt(),
|
|
200
|
-
updatedAt: field2.updatedAt(),
|
|
201
|
-
product: field2.belongsTo("Product", ["productId"], ["id"], {
|
|
202
|
-
onDelete: "Cascade"
|
|
203
|
-
})
|
|
204
|
-
},
|
|
205
|
-
indexes: [
|
|
206
|
-
index2.on(["productId", "sku"]),
|
|
207
|
-
index2.on(["productId", "position"]),
|
|
208
|
-
index2.on(["barcode"])
|
|
209
|
-
]
|
|
210
|
-
});
|
|
211
|
-
var CategoryEntity = defineEntity2({
|
|
212
|
-
name: "Category",
|
|
213
|
-
description: "Product category for organization.",
|
|
214
|
-
schema: "marketplace",
|
|
215
|
-
map: "category",
|
|
216
|
-
fields: {
|
|
217
|
-
id: field2.id(),
|
|
218
|
-
name: field2.string(),
|
|
219
|
-
slug: field2.string(),
|
|
220
|
-
description: field2.string({ isOptional: true }),
|
|
221
|
-
parentId: field2.string({ isOptional: true }),
|
|
222
|
-
path: field2.string({ description: "Full path for hierarchical queries" }),
|
|
223
|
-
level: field2.int({ default: 0 }),
|
|
224
|
-
position: field2.int({ default: 0 }),
|
|
225
|
-
imageId: field2.string({ isOptional: true }),
|
|
226
|
-
isActive: field2.boolean({ default: true }),
|
|
227
|
-
createdAt: field2.createdAt(),
|
|
228
|
-
updatedAt: field2.updatedAt(),
|
|
229
|
-
parent: field2.belongsTo("Category", ["parentId"], ["id"]),
|
|
230
|
-
children: field2.hasMany("Category")
|
|
231
|
-
},
|
|
232
|
-
indexes: [
|
|
233
|
-
index2.unique(["slug"]),
|
|
234
|
-
index2.on(["parentId", "position"]),
|
|
235
|
-
index2.on(["path"]),
|
|
236
|
-
index2.on(["isActive"])
|
|
237
|
-
]
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
// src/entities/order.ts
|
|
241
|
-
import {
|
|
242
|
-
defineEntity as defineEntity3,
|
|
243
|
-
defineEntityEnum as defineEntityEnum3,
|
|
244
|
-
field as field3,
|
|
245
|
-
index as index3
|
|
246
|
-
} from "@contractspec/lib.schema";
|
|
247
|
-
var OrderStatusEnum = defineEntityEnum3({
|
|
9
|
+
var OrderStatusEnum = defineEntityEnum({
|
|
248
10
|
name: "OrderStatus",
|
|
249
11
|
values: [
|
|
250
12
|
"PENDING",
|
|
@@ -261,7 +23,7 @@ var OrderStatusEnum = defineEntityEnum3({
|
|
|
261
23
|
schema: "marketplace",
|
|
262
24
|
description: "Status of an order."
|
|
263
25
|
});
|
|
264
|
-
var PaymentStatusEnum =
|
|
26
|
+
var PaymentStatusEnum = defineEntityEnum({
|
|
265
27
|
name: "PaymentStatus",
|
|
266
28
|
values: [
|
|
267
29
|
"PENDING",
|
|
@@ -274,384 +36,622 @@ var PaymentStatusEnum = defineEntityEnum3({
|
|
|
274
36
|
schema: "marketplace",
|
|
275
37
|
description: "Status of payment."
|
|
276
38
|
});
|
|
277
|
-
var OrderEntity =
|
|
39
|
+
var OrderEntity = defineEntity({
|
|
278
40
|
name: "Order",
|
|
279
41
|
description: "A purchase order on the marketplace.",
|
|
280
42
|
schema: "marketplace",
|
|
281
43
|
map: "order",
|
|
282
44
|
fields: {
|
|
283
|
-
id:
|
|
284
|
-
orderNumber:
|
|
285
|
-
buyerId:
|
|
286
|
-
storeId:
|
|
287
|
-
status:
|
|
288
|
-
paymentStatus:
|
|
289
|
-
subtotal:
|
|
290
|
-
shippingTotal:
|
|
291
|
-
taxTotal:
|
|
292
|
-
discountTotal:
|
|
293
|
-
total:
|
|
294
|
-
currency:
|
|
295
|
-
platformFee:
|
|
296
|
-
sellerPayout:
|
|
297
|
-
shippingAddress:
|
|
298
|
-
billingAddress:
|
|
299
|
-
shippingMethod:
|
|
300
|
-
trackingNumber:
|
|
301
|
-
trackingUrl:
|
|
302
|
-
paymentMethod:
|
|
303
|
-
paymentIntentId:
|
|
304
|
-
buyerNote:
|
|
305
|
-
sellerNote:
|
|
306
|
-
internalNote:
|
|
307
|
-
createdAt:
|
|
308
|
-
updatedAt:
|
|
309
|
-
paidAt:
|
|
310
|
-
shippedAt:
|
|
311
|
-
deliveredAt:
|
|
312
|
-
completedAt:
|
|
313
|
-
cancelledAt:
|
|
314
|
-
store:
|
|
315
|
-
items:
|
|
316
|
-
refunds:
|
|
45
|
+
id: field.id({ description: "Unique order ID" }),
|
|
46
|
+
orderNumber: field.string({ description: "Human-readable order number" }),
|
|
47
|
+
buyerId: field.foreignKey({ description: "Buyer user ID" }),
|
|
48
|
+
storeId: field.foreignKey({ description: "Seller store ID" }),
|
|
49
|
+
status: field.enum("OrderStatus", { default: "PENDING" }),
|
|
50
|
+
paymentStatus: field.enum("PaymentStatus", { default: "PENDING" }),
|
|
51
|
+
subtotal: field.decimal({ description: "Sum of item prices" }),
|
|
52
|
+
shippingTotal: field.decimal({ default: 0 }),
|
|
53
|
+
taxTotal: field.decimal({ default: 0 }),
|
|
54
|
+
discountTotal: field.decimal({ default: 0 }),
|
|
55
|
+
total: field.decimal({ description: "Final total" }),
|
|
56
|
+
currency: field.string({ default: '"USD"' }),
|
|
57
|
+
platformFee: field.decimal({ description: "Platform commission amount" }),
|
|
58
|
+
sellerPayout: field.decimal({ description: "Amount due to seller" }),
|
|
59
|
+
shippingAddress: field.json({ isOptional: true }),
|
|
60
|
+
billingAddress: field.json({ isOptional: true }),
|
|
61
|
+
shippingMethod: field.string({ isOptional: true }),
|
|
62
|
+
trackingNumber: field.string({ isOptional: true }),
|
|
63
|
+
trackingUrl: field.string({ isOptional: true }),
|
|
64
|
+
paymentMethod: field.string({ isOptional: true }),
|
|
65
|
+
paymentIntentId: field.string({ isOptional: true }),
|
|
66
|
+
buyerNote: field.string({ isOptional: true }),
|
|
67
|
+
sellerNote: field.string({ isOptional: true }),
|
|
68
|
+
internalNote: field.string({ isOptional: true }),
|
|
69
|
+
createdAt: field.createdAt(),
|
|
70
|
+
updatedAt: field.updatedAt(),
|
|
71
|
+
paidAt: field.dateTime({ isOptional: true }),
|
|
72
|
+
shippedAt: field.dateTime({ isOptional: true }),
|
|
73
|
+
deliveredAt: field.dateTime({ isOptional: true }),
|
|
74
|
+
completedAt: field.dateTime({ isOptional: true }),
|
|
75
|
+
cancelledAt: field.dateTime({ isOptional: true }),
|
|
76
|
+
store: field.belongsTo("Store", ["storeId"], ["id"]),
|
|
77
|
+
items: field.hasMany("OrderItem"),
|
|
78
|
+
refunds: field.hasMany("Refund")
|
|
317
79
|
},
|
|
318
80
|
indexes: [
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
81
|
+
index.unique(["orderNumber"]),
|
|
82
|
+
index.on(["buyerId", "status"]),
|
|
83
|
+
index.on(["storeId", "status"]),
|
|
84
|
+
index.on(["status", "createdAt"]),
|
|
85
|
+
index.on(["paymentStatus"]),
|
|
86
|
+
index.on(["createdAt"])
|
|
325
87
|
],
|
|
326
88
|
enums: [OrderStatusEnum, PaymentStatusEnum]
|
|
327
89
|
});
|
|
328
|
-
var OrderItemEntity =
|
|
90
|
+
var OrderItemEntity = defineEntity({
|
|
329
91
|
name: "OrderItem",
|
|
330
92
|
description: "An item within an order.",
|
|
331
93
|
schema: "marketplace",
|
|
332
94
|
map: "order_item",
|
|
333
95
|
fields: {
|
|
334
|
-
id:
|
|
335
|
-
orderId:
|
|
336
|
-
productId:
|
|
337
|
-
variantId:
|
|
338
|
-
productName:
|
|
339
|
-
variantName:
|
|
340
|
-
sku:
|
|
341
|
-
unitPrice:
|
|
342
|
-
quantity:
|
|
343
|
-
subtotal:
|
|
344
|
-
quantityFulfilled:
|
|
345
|
-
quantityRefunded:
|
|
346
|
-
createdAt:
|
|
347
|
-
updatedAt:
|
|
348
|
-
order:
|
|
96
|
+
id: field.id(),
|
|
97
|
+
orderId: field.foreignKey(),
|
|
98
|
+
productId: field.foreignKey(),
|
|
99
|
+
variantId: field.string({ isOptional: true }),
|
|
100
|
+
productName: field.string(),
|
|
101
|
+
variantName: field.string({ isOptional: true }),
|
|
102
|
+
sku: field.string({ isOptional: true }),
|
|
103
|
+
unitPrice: field.decimal(),
|
|
104
|
+
quantity: field.int(),
|
|
105
|
+
subtotal: field.decimal(),
|
|
106
|
+
quantityFulfilled: field.int({ default: 0 }),
|
|
107
|
+
quantityRefunded: field.int({ default: 0 }),
|
|
108
|
+
createdAt: field.createdAt(),
|
|
109
|
+
updatedAt: field.updatedAt(),
|
|
110
|
+
order: field.belongsTo("Order", ["orderId"], ["id"], {
|
|
349
111
|
onDelete: "Cascade"
|
|
350
112
|
}),
|
|
351
|
-
product:
|
|
113
|
+
product: field.belongsTo("Product", ["productId"], ["id"])
|
|
352
114
|
},
|
|
353
|
-
indexes: [
|
|
115
|
+
indexes: [index.on(["orderId"]), index.on(["productId"])]
|
|
354
116
|
});
|
|
355
|
-
var RefundEntity =
|
|
117
|
+
var RefundEntity = defineEntity({
|
|
356
118
|
name: "Refund",
|
|
357
119
|
description: "A refund for an order.",
|
|
358
120
|
schema: "marketplace",
|
|
359
121
|
map: "refund",
|
|
360
122
|
fields: {
|
|
361
|
-
id:
|
|
362
|
-
orderId:
|
|
363
|
-
amount:
|
|
364
|
-
currency:
|
|
365
|
-
reason:
|
|
366
|
-
notes:
|
|
367
|
-
status:
|
|
368
|
-
refundId:
|
|
123
|
+
id: field.id(),
|
|
124
|
+
orderId: field.foreignKey(),
|
|
125
|
+
amount: field.decimal(),
|
|
126
|
+
currency: field.string(),
|
|
127
|
+
reason: field.string(),
|
|
128
|
+
notes: field.string({ isOptional: true }),
|
|
129
|
+
status: field.string({ default: '"PENDING"' }),
|
|
130
|
+
refundId: field.string({
|
|
369
131
|
isOptional: true,
|
|
370
132
|
description: "Payment provider refund ID"
|
|
371
133
|
}),
|
|
372
|
-
issuedBy:
|
|
373
|
-
createdAt:
|
|
374
|
-
processedAt:
|
|
375
|
-
order:
|
|
376
|
-
items:
|
|
134
|
+
issuedBy: field.foreignKey({ description: "User who issued the refund" }),
|
|
135
|
+
createdAt: field.createdAt(),
|
|
136
|
+
processedAt: field.dateTime({ isOptional: true }),
|
|
137
|
+
order: field.belongsTo("Order", ["orderId"], ["id"]),
|
|
138
|
+
items: field.hasMany("RefundItem")
|
|
377
139
|
},
|
|
378
|
-
indexes: [
|
|
140
|
+
indexes: [index.on(["orderId"]), index.on(["status"])]
|
|
379
141
|
});
|
|
380
|
-
var RefundItemEntity =
|
|
142
|
+
var RefundItemEntity = defineEntity({
|
|
381
143
|
name: "RefundItem",
|
|
382
144
|
description: "An item within a refund.",
|
|
383
145
|
schema: "marketplace",
|
|
384
146
|
map: "refund_item",
|
|
385
147
|
fields: {
|
|
386
|
-
id:
|
|
387
|
-
refundId:
|
|
388
|
-
orderItemId:
|
|
389
|
-
quantity:
|
|
390
|
-
amount:
|
|
391
|
-
createdAt:
|
|
392
|
-
refund:
|
|
148
|
+
id: field.id(),
|
|
149
|
+
refundId: field.foreignKey(),
|
|
150
|
+
orderItemId: field.foreignKey(),
|
|
151
|
+
quantity: field.int(),
|
|
152
|
+
amount: field.decimal(),
|
|
153
|
+
createdAt: field.createdAt(),
|
|
154
|
+
refund: field.belongsTo("Refund", ["refundId"], ["id"], {
|
|
393
155
|
onDelete: "Cascade"
|
|
394
156
|
}),
|
|
395
|
-
orderItem:
|
|
157
|
+
orderItem: field.belongsTo("OrderItem", ["orderItemId"], ["id"])
|
|
396
158
|
},
|
|
397
|
-
indexes: [
|
|
159
|
+
indexes: [index.on(["refundId"]), index.on(["orderItemId"])]
|
|
398
160
|
});
|
|
399
161
|
|
|
400
162
|
// src/entities/payout.ts
|
|
401
163
|
import {
|
|
402
|
-
defineEntity as
|
|
403
|
-
defineEntityEnum as
|
|
404
|
-
field as
|
|
405
|
-
index as
|
|
164
|
+
defineEntity as defineEntity2,
|
|
165
|
+
defineEntityEnum as defineEntityEnum2,
|
|
166
|
+
field as field2,
|
|
167
|
+
index as index2
|
|
406
168
|
} from "@contractspec/lib.schema";
|
|
407
|
-
var PayoutStatusEnum =
|
|
169
|
+
var PayoutStatusEnum = defineEntityEnum2({
|
|
408
170
|
name: "PayoutStatus",
|
|
409
171
|
values: ["PENDING", "PROCESSING", "PAID", "FAILED", "CANCELLED"],
|
|
410
172
|
schema: "marketplace",
|
|
411
173
|
description: "Status of a payout."
|
|
412
174
|
});
|
|
413
|
-
var PayoutScheduleEnum =
|
|
175
|
+
var PayoutScheduleEnum = defineEntityEnum2({
|
|
414
176
|
name: "PayoutSchedule",
|
|
415
177
|
values: ["DAILY", "WEEKLY", "BIWEEKLY", "MONTHLY", "MANUAL"],
|
|
416
178
|
schema: "marketplace",
|
|
417
179
|
description: "Payout schedule frequency."
|
|
418
180
|
});
|
|
419
|
-
var PayoutEntity =
|
|
181
|
+
var PayoutEntity = defineEntity2({
|
|
420
182
|
name: "Payout",
|
|
421
183
|
description: "A payout to a seller.",
|
|
422
184
|
schema: "marketplace",
|
|
423
185
|
map: "payout",
|
|
424
186
|
fields: {
|
|
425
|
-
id:
|
|
426
|
-
storeId:
|
|
427
|
-
payoutNumber:
|
|
428
|
-
status:
|
|
429
|
-
grossAmount:
|
|
430
|
-
platformFees:
|
|
431
|
-
otherDeductions:
|
|
432
|
-
netAmount:
|
|
433
|
-
currency:
|
|
434
|
-
periodStart:
|
|
435
|
-
periodEnd:
|
|
436
|
-
paymentMethod:
|
|
437
|
-
paymentReference:
|
|
438
|
-
bankAccountId:
|
|
439
|
-
bankAccountLast4:
|
|
440
|
-
notes:
|
|
441
|
-
failureReason:
|
|
442
|
-
orderCount:
|
|
443
|
-
createdAt:
|
|
444
|
-
updatedAt:
|
|
445
|
-
scheduledAt:
|
|
446
|
-
processedAt:
|
|
447
|
-
paidAt:
|
|
448
|
-
store:
|
|
449
|
-
items:
|
|
187
|
+
id: field2.id({ description: "Unique payout ID" }),
|
|
188
|
+
storeId: field2.foreignKey(),
|
|
189
|
+
payoutNumber: field2.string({ description: "Human-readable payout number" }),
|
|
190
|
+
status: field2.enum("PayoutStatus", { default: "PENDING" }),
|
|
191
|
+
grossAmount: field2.decimal({ description: "Total before fees" }),
|
|
192
|
+
platformFees: field2.decimal({ description: "Platform fees deducted" }),
|
|
193
|
+
otherDeductions: field2.decimal({ default: 0 }),
|
|
194
|
+
netAmount: field2.decimal({ description: "Final payout amount" }),
|
|
195
|
+
currency: field2.string({ default: '"USD"' }),
|
|
196
|
+
periodStart: field2.dateTime({ description: "Start of payout period" }),
|
|
197
|
+
periodEnd: field2.dateTime({ description: "End of payout period" }),
|
|
198
|
+
paymentMethod: field2.string({ isOptional: true }),
|
|
199
|
+
paymentReference: field2.string({ isOptional: true }),
|
|
200
|
+
bankAccountId: field2.string({ isOptional: true }),
|
|
201
|
+
bankAccountLast4: field2.string({ isOptional: true }),
|
|
202
|
+
notes: field2.string({ isOptional: true }),
|
|
203
|
+
failureReason: field2.string({ isOptional: true }),
|
|
204
|
+
orderCount: field2.int({ default: 0 }),
|
|
205
|
+
createdAt: field2.createdAt(),
|
|
206
|
+
updatedAt: field2.updatedAt(),
|
|
207
|
+
scheduledAt: field2.dateTime({ isOptional: true }),
|
|
208
|
+
processedAt: field2.dateTime({ isOptional: true }),
|
|
209
|
+
paidAt: field2.dateTime({ isOptional: true }),
|
|
210
|
+
store: field2.belongsTo("Store", ["storeId"], ["id"]),
|
|
211
|
+
items: field2.hasMany("PayoutItem")
|
|
450
212
|
},
|
|
451
213
|
indexes: [
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
214
|
+
index2.unique(["payoutNumber"]),
|
|
215
|
+
index2.on(["storeId", "status"]),
|
|
216
|
+
index2.on(["status", "scheduledAt"]),
|
|
217
|
+
index2.on(["periodStart", "periodEnd"])
|
|
456
218
|
],
|
|
457
219
|
enums: [PayoutStatusEnum]
|
|
458
220
|
});
|
|
459
|
-
var PayoutItemEntity =
|
|
221
|
+
var PayoutItemEntity = defineEntity2({
|
|
460
222
|
name: "PayoutItem",
|
|
461
223
|
description: "An order included in a payout.",
|
|
462
224
|
schema: "marketplace",
|
|
463
225
|
map: "payout_item",
|
|
464
226
|
fields: {
|
|
465
|
-
id:
|
|
466
|
-
payoutId:
|
|
467
|
-
orderId:
|
|
468
|
-
orderTotal:
|
|
469
|
-
platformFee:
|
|
470
|
-
netAmount:
|
|
471
|
-
createdAt:
|
|
472
|
-
payout:
|
|
227
|
+
id: field2.id(),
|
|
228
|
+
payoutId: field2.foreignKey(),
|
|
229
|
+
orderId: field2.foreignKey(),
|
|
230
|
+
orderTotal: field2.decimal(),
|
|
231
|
+
platformFee: field2.decimal(),
|
|
232
|
+
netAmount: field2.decimal(),
|
|
233
|
+
createdAt: field2.createdAt(),
|
|
234
|
+
payout: field2.belongsTo("Payout", ["payoutId"], ["id"], {
|
|
473
235
|
onDelete: "Cascade"
|
|
474
236
|
}),
|
|
475
|
-
order:
|
|
237
|
+
order: field2.belongsTo("Order", ["orderId"], ["id"])
|
|
476
238
|
},
|
|
477
|
-
indexes: [
|
|
239
|
+
indexes: [index2.on(["payoutId"]), index2.on(["orderId"])]
|
|
478
240
|
});
|
|
479
|
-
var BankAccountEntity =
|
|
241
|
+
var BankAccountEntity = defineEntity2({
|
|
480
242
|
name: "BankAccount",
|
|
481
243
|
description: "A bank account for receiving payouts.",
|
|
482
244
|
schema: "marketplace",
|
|
483
245
|
map: "bank_account",
|
|
484
246
|
fields: {
|
|
485
|
-
id:
|
|
486
|
-
storeId:
|
|
487
|
-
accountHolderName:
|
|
488
|
-
accountType:
|
|
489
|
-
bankName:
|
|
490
|
-
last4:
|
|
491
|
-
routingLast4:
|
|
492
|
-
externalId:
|
|
247
|
+
id: field2.id(),
|
|
248
|
+
storeId: field2.foreignKey(),
|
|
249
|
+
accountHolderName: field2.string(),
|
|
250
|
+
accountType: field2.string({ default: '"CHECKING"' }),
|
|
251
|
+
bankName: field2.string({ isOptional: true }),
|
|
252
|
+
last4: field2.string({ description: "Last 4 digits of account" }),
|
|
253
|
+
routingLast4: field2.string({ isOptional: true }),
|
|
254
|
+
externalId: field2.string({
|
|
493
255
|
isOptional: true,
|
|
494
256
|
description: "External provider account ID"
|
|
495
257
|
}),
|
|
496
|
-
isDefault:
|
|
497
|
-
isVerified:
|
|
498
|
-
createdAt:
|
|
499
|
-
updatedAt:
|
|
500
|
-
verifiedAt:
|
|
501
|
-
store:
|
|
258
|
+
isDefault: field2.boolean({ default: false }),
|
|
259
|
+
isVerified: field2.boolean({ default: false }),
|
|
260
|
+
createdAt: field2.createdAt(),
|
|
261
|
+
updatedAt: field2.updatedAt(),
|
|
262
|
+
verifiedAt: field2.dateTime({ isOptional: true }),
|
|
263
|
+
store: field2.belongsTo("Store", ["storeId"], ["id"])
|
|
502
264
|
},
|
|
503
|
-
indexes: [
|
|
265
|
+
indexes: [index2.on(["storeId", "isDefault"]), index2.on(["externalId"])]
|
|
504
266
|
});
|
|
505
|
-
var PayoutSettingsEntity =
|
|
267
|
+
var PayoutSettingsEntity = defineEntity2({
|
|
506
268
|
name: "PayoutSettings",
|
|
507
269
|
description: "Payout configuration for a store.",
|
|
508
270
|
schema: "marketplace",
|
|
509
271
|
map: "payout_settings",
|
|
510
272
|
fields: {
|
|
511
|
-
id:
|
|
512
|
-
storeId:
|
|
513
|
-
schedule:
|
|
514
|
-
dayOfWeek:
|
|
273
|
+
id: field2.id(),
|
|
274
|
+
storeId: field2.foreignKey(),
|
|
275
|
+
schedule: field2.enum("PayoutSchedule", { default: "WEEKLY" }),
|
|
276
|
+
dayOfWeek: field2.int({
|
|
515
277
|
isOptional: true,
|
|
516
278
|
description: "Day for weekly/biweekly (0=Sunday)"
|
|
517
279
|
}),
|
|
518
|
-
dayOfMonth:
|
|
280
|
+
dayOfMonth: field2.int({
|
|
519
281
|
isOptional: true,
|
|
520
282
|
description: "Day for monthly (1-28)"
|
|
521
283
|
}),
|
|
522
|
-
minimumPayout:
|
|
284
|
+
minimumPayout: field2.decimal({
|
|
523
285
|
default: 50,
|
|
524
286
|
description: "Minimum amount for payout"
|
|
525
287
|
}),
|
|
526
|
-
defaultBankAccountId:
|
|
527
|
-
createdAt:
|
|
528
|
-
updatedAt:
|
|
529
|
-
store:
|
|
288
|
+
defaultBankAccountId: field2.string({ isOptional: true }),
|
|
289
|
+
createdAt: field2.createdAt(),
|
|
290
|
+
updatedAt: field2.updatedAt(),
|
|
291
|
+
store: field2.belongsTo("Store", ["storeId"], ["id"])
|
|
530
292
|
},
|
|
531
|
-
indexes: [
|
|
293
|
+
indexes: [index2.unique(["storeId"])],
|
|
532
294
|
enums: [PayoutScheduleEnum]
|
|
533
295
|
});
|
|
534
296
|
|
|
297
|
+
// src/entities/product.ts
|
|
298
|
+
import {
|
|
299
|
+
defineEntity as defineEntity3,
|
|
300
|
+
defineEntityEnum as defineEntityEnum3,
|
|
301
|
+
field as field3,
|
|
302
|
+
index as index3
|
|
303
|
+
} from "@contractspec/lib.schema";
|
|
304
|
+
var ProductStatusEnum = defineEntityEnum3({
|
|
305
|
+
name: "ProductStatus",
|
|
306
|
+
values: [
|
|
307
|
+
"DRAFT",
|
|
308
|
+
"PENDING_REVIEW",
|
|
309
|
+
"ACTIVE",
|
|
310
|
+
"OUT_OF_STOCK",
|
|
311
|
+
"DISCONTINUED",
|
|
312
|
+
"REJECTED"
|
|
313
|
+
],
|
|
314
|
+
schema: "marketplace",
|
|
315
|
+
description: "Status of a product listing."
|
|
316
|
+
});
|
|
317
|
+
var ProductTypeEnum = defineEntityEnum3({
|
|
318
|
+
name: "ProductType",
|
|
319
|
+
values: ["PHYSICAL", "DIGITAL", "SERVICE", "SUBSCRIPTION"],
|
|
320
|
+
schema: "marketplace",
|
|
321
|
+
description: "Type of product."
|
|
322
|
+
});
|
|
323
|
+
var ProductEntity = defineEntity3({
|
|
324
|
+
name: "Product",
|
|
325
|
+
description: "A product listing on the marketplace.",
|
|
326
|
+
schema: "marketplace",
|
|
327
|
+
map: "product",
|
|
328
|
+
fields: {
|
|
329
|
+
id: field3.id({ description: "Unique product ID" }),
|
|
330
|
+
storeId: field3.foreignKey(),
|
|
331
|
+
name: field3.string({ description: "Product name" }),
|
|
332
|
+
slug: field3.string({ description: "URL-friendly identifier" }),
|
|
333
|
+
description: field3.string({ isOptional: true }),
|
|
334
|
+
shortDescription: field3.string({ isOptional: true }),
|
|
335
|
+
status: field3.enum("ProductStatus", { default: "DRAFT" }),
|
|
336
|
+
type: field3.enum("ProductType", { default: "PHYSICAL" }),
|
|
337
|
+
price: field3.decimal({ description: "Base price" }),
|
|
338
|
+
compareAtPrice: field3.decimal({
|
|
339
|
+
isOptional: true,
|
|
340
|
+
description: "Original price for showing discounts"
|
|
341
|
+
}),
|
|
342
|
+
currency: field3.string({ default: '"USD"' }),
|
|
343
|
+
sku: field3.string({ isOptional: true }),
|
|
344
|
+
barcode: field3.string({ isOptional: true }),
|
|
345
|
+
quantity: field3.int({ default: 0 }),
|
|
346
|
+
trackInventory: field3.boolean({ default: true }),
|
|
347
|
+
allowBackorder: field3.boolean({ default: false }),
|
|
348
|
+
lowStockThreshold: field3.int({ default: 5 }),
|
|
349
|
+
weight: field3.decimal({ isOptional: true }),
|
|
350
|
+
weightUnit: field3.string({ default: '"kg"' }),
|
|
351
|
+
categoryId: field3.string({ isOptional: true }),
|
|
352
|
+
tags: field3.string({ isArray: true }),
|
|
353
|
+
primaryImageId: field3.string({ isOptional: true }),
|
|
354
|
+
seoTitle: field3.string({ isOptional: true }),
|
|
355
|
+
seoDescription: field3.string({ isOptional: true }),
|
|
356
|
+
attributes: field3.json({
|
|
357
|
+
isOptional: true,
|
|
358
|
+
description: "Custom product attributes"
|
|
359
|
+
}),
|
|
360
|
+
reviewCount: field3.int({ default: 0 }),
|
|
361
|
+
averageRating: field3.decimal({ default: 0 }),
|
|
362
|
+
totalSold: field3.int({ default: 0 }),
|
|
363
|
+
createdAt: field3.createdAt(),
|
|
364
|
+
updatedAt: field3.updatedAt(),
|
|
365
|
+
publishedAt: field3.dateTime({ isOptional: true }),
|
|
366
|
+
store: field3.belongsTo("Store", ["storeId"], ["id"]),
|
|
367
|
+
variants: field3.hasMany("ProductVariant"),
|
|
368
|
+
orderItems: field3.hasMany("OrderItem"),
|
|
369
|
+
reviews: field3.hasMany("Review")
|
|
370
|
+
},
|
|
371
|
+
indexes: [
|
|
372
|
+
index3.unique(["storeId", "slug"]),
|
|
373
|
+
index3.on(["storeId", "status"]),
|
|
374
|
+
index3.on(["status", "publishedAt"]),
|
|
375
|
+
index3.on(["categoryId", "status"]),
|
|
376
|
+
index3.on(["averageRating"]),
|
|
377
|
+
index3.on(["totalSold"]),
|
|
378
|
+
index3.on(["price"])
|
|
379
|
+
],
|
|
380
|
+
enums: [ProductStatusEnum, ProductTypeEnum]
|
|
381
|
+
});
|
|
382
|
+
var ProductVariantEntity = defineEntity3({
|
|
383
|
+
name: "ProductVariant",
|
|
384
|
+
description: "A variant of a product with specific options.",
|
|
385
|
+
schema: "marketplace",
|
|
386
|
+
map: "product_variant",
|
|
387
|
+
fields: {
|
|
388
|
+
id: field3.id(),
|
|
389
|
+
productId: field3.foreignKey(),
|
|
390
|
+
name: field3.string({ description: 'Variant name (e.g., "Large / Blue")' }),
|
|
391
|
+
options: field3.json({
|
|
392
|
+
description: 'Variant options (e.g., {size: "L", color: "Blue"})'
|
|
393
|
+
}),
|
|
394
|
+
price: field3.decimal({ description: "Variant-specific price" }),
|
|
395
|
+
compareAtPrice: field3.decimal({ isOptional: true }),
|
|
396
|
+
sku: field3.string({ isOptional: true }),
|
|
397
|
+
barcode: field3.string({ isOptional: true }),
|
|
398
|
+
quantity: field3.int({ default: 0 }),
|
|
399
|
+
imageId: field3.string({ isOptional: true }),
|
|
400
|
+
isActive: field3.boolean({ default: true }),
|
|
401
|
+
position: field3.int({ default: 0 }),
|
|
402
|
+
createdAt: field3.createdAt(),
|
|
403
|
+
updatedAt: field3.updatedAt(),
|
|
404
|
+
product: field3.belongsTo("Product", ["productId"], ["id"], {
|
|
405
|
+
onDelete: "Cascade"
|
|
406
|
+
})
|
|
407
|
+
},
|
|
408
|
+
indexes: [
|
|
409
|
+
index3.on(["productId", "sku"]),
|
|
410
|
+
index3.on(["productId", "position"]),
|
|
411
|
+
index3.on(["barcode"])
|
|
412
|
+
]
|
|
413
|
+
});
|
|
414
|
+
var CategoryEntity = defineEntity3({
|
|
415
|
+
name: "Category",
|
|
416
|
+
description: "Product category for organization.",
|
|
417
|
+
schema: "marketplace",
|
|
418
|
+
map: "category",
|
|
419
|
+
fields: {
|
|
420
|
+
id: field3.id(),
|
|
421
|
+
name: field3.string(),
|
|
422
|
+
slug: field3.string(),
|
|
423
|
+
description: field3.string({ isOptional: true }),
|
|
424
|
+
parentId: field3.string({ isOptional: true }),
|
|
425
|
+
path: field3.string({ description: "Full path for hierarchical queries" }),
|
|
426
|
+
level: field3.int({ default: 0 }),
|
|
427
|
+
position: field3.int({ default: 0 }),
|
|
428
|
+
imageId: field3.string({ isOptional: true }),
|
|
429
|
+
isActive: field3.boolean({ default: true }),
|
|
430
|
+
createdAt: field3.createdAt(),
|
|
431
|
+
updatedAt: field3.updatedAt(),
|
|
432
|
+
parent: field3.belongsTo("Category", ["parentId"], ["id"]),
|
|
433
|
+
children: field3.hasMany("Category")
|
|
434
|
+
},
|
|
435
|
+
indexes: [
|
|
436
|
+
index3.unique(["slug"]),
|
|
437
|
+
index3.on(["parentId", "position"]),
|
|
438
|
+
index3.on(["path"]),
|
|
439
|
+
index3.on(["isActive"])
|
|
440
|
+
]
|
|
441
|
+
});
|
|
442
|
+
|
|
535
443
|
// src/entities/review.ts
|
|
536
444
|
import {
|
|
537
|
-
defineEntity as
|
|
538
|
-
defineEntityEnum as
|
|
539
|
-
field as
|
|
540
|
-
index as
|
|
445
|
+
defineEntity as defineEntity4,
|
|
446
|
+
defineEntityEnum as defineEntityEnum4,
|
|
447
|
+
field as field4,
|
|
448
|
+
index as index4
|
|
541
449
|
} from "@contractspec/lib.schema";
|
|
542
|
-
var ReviewStatusEnum =
|
|
450
|
+
var ReviewStatusEnum = defineEntityEnum4({
|
|
543
451
|
name: "ReviewStatus",
|
|
544
452
|
values: ["PENDING", "APPROVED", "REJECTED", "FLAGGED"],
|
|
545
453
|
schema: "marketplace",
|
|
546
454
|
description: "Status of a review."
|
|
547
455
|
});
|
|
548
|
-
var ReviewTypeEnum =
|
|
456
|
+
var ReviewTypeEnum = defineEntityEnum4({
|
|
549
457
|
name: "ReviewType",
|
|
550
458
|
values: ["PRODUCT", "STORE", "ORDER"],
|
|
551
459
|
schema: "marketplace",
|
|
552
460
|
description: "Type of review."
|
|
553
461
|
});
|
|
554
|
-
var ReviewEntity =
|
|
462
|
+
var ReviewEntity = defineEntity4({
|
|
555
463
|
name: "Review",
|
|
556
464
|
description: "A customer review on the marketplace.",
|
|
557
465
|
schema: "marketplace",
|
|
558
466
|
map: "review",
|
|
559
467
|
fields: {
|
|
560
|
-
id:
|
|
561
|
-
type:
|
|
562
|
-
productId:
|
|
563
|
-
storeId:
|
|
564
|
-
orderId:
|
|
565
|
-
orderItemId:
|
|
566
|
-
authorId:
|
|
567
|
-
rating:
|
|
568
|
-
title:
|
|
569
|
-
content:
|
|
570
|
-
isVerifiedPurchase:
|
|
571
|
-
status:
|
|
572
|
-
hasMedia:
|
|
573
|
-
helpfulCount:
|
|
574
|
-
notHelpfulCount:
|
|
575
|
-
moderatedBy:
|
|
576
|
-
moderatedAt:
|
|
577
|
-
moderationNote:
|
|
578
|
-
hasResponse:
|
|
579
|
-
createdAt:
|
|
580
|
-
updatedAt:
|
|
581
|
-
product:
|
|
582
|
-
store:
|
|
583
|
-
responses:
|
|
584
|
-
votes:
|
|
468
|
+
id: field4.id({ description: "Unique review ID" }),
|
|
469
|
+
type: field4.enum("ReviewType", { default: "PRODUCT" }),
|
|
470
|
+
productId: field4.string({ isOptional: true }),
|
|
471
|
+
storeId: field4.string({ isOptional: true }),
|
|
472
|
+
orderId: field4.string({ isOptional: true }),
|
|
473
|
+
orderItemId: field4.string({ isOptional: true }),
|
|
474
|
+
authorId: field4.foreignKey({ description: "Reviewer user ID" }),
|
|
475
|
+
rating: field4.int({ description: "Rating 1-5" }),
|
|
476
|
+
title: field4.string({ isOptional: true }),
|
|
477
|
+
content: field4.string({ isOptional: true }),
|
|
478
|
+
isVerifiedPurchase: field4.boolean({ default: false }),
|
|
479
|
+
status: field4.enum("ReviewStatus", { default: "PENDING" }),
|
|
480
|
+
hasMedia: field4.boolean({ default: false }),
|
|
481
|
+
helpfulCount: field4.int({ default: 0 }),
|
|
482
|
+
notHelpfulCount: field4.int({ default: 0 }),
|
|
483
|
+
moderatedBy: field4.string({ isOptional: true }),
|
|
484
|
+
moderatedAt: field4.dateTime({ isOptional: true }),
|
|
485
|
+
moderationNote: field4.string({ isOptional: true }),
|
|
486
|
+
hasResponse: field4.boolean({ default: false }),
|
|
487
|
+
createdAt: field4.createdAt(),
|
|
488
|
+
updatedAt: field4.updatedAt(),
|
|
489
|
+
product: field4.belongsTo("Product", ["productId"], ["id"]),
|
|
490
|
+
store: field4.belongsTo("Store", ["storeId"], ["id"]),
|
|
491
|
+
responses: field4.hasMany("ReviewResponse"),
|
|
492
|
+
votes: field4.hasMany("ReviewVote")
|
|
585
493
|
},
|
|
586
494
|
indexes: [
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
495
|
+
index4.on(["productId", "status", "createdAt"]),
|
|
496
|
+
index4.on(["storeId", "status", "createdAt"]),
|
|
497
|
+
index4.on(["authorId"]),
|
|
498
|
+
index4.on(["orderId"]),
|
|
499
|
+
index4.on(["status"]),
|
|
500
|
+
index4.on(["rating"]),
|
|
501
|
+
index4.on(["isVerifiedPurchase", "status"])
|
|
594
502
|
],
|
|
595
503
|
enums: [ReviewStatusEnum, ReviewTypeEnum]
|
|
596
504
|
});
|
|
597
|
-
var ReviewResponseEntity =
|
|
505
|
+
var ReviewResponseEntity = defineEntity4({
|
|
598
506
|
name: "ReviewResponse",
|
|
599
507
|
description: "A seller response to a review.",
|
|
600
508
|
schema: "marketplace",
|
|
601
509
|
map: "review_response",
|
|
602
510
|
fields: {
|
|
603
|
-
id:
|
|
604
|
-
reviewId:
|
|
605
|
-
authorId:
|
|
606
|
-
content:
|
|
607
|
-
createdAt:
|
|
608
|
-
updatedAt:
|
|
609
|
-
review:
|
|
511
|
+
id: field4.id(),
|
|
512
|
+
reviewId: field4.foreignKey(),
|
|
513
|
+
authorId: field4.foreignKey(),
|
|
514
|
+
content: field4.string(),
|
|
515
|
+
createdAt: field4.createdAt(),
|
|
516
|
+
updatedAt: field4.updatedAt(),
|
|
517
|
+
review: field4.belongsTo("Review", ["reviewId"], ["id"], {
|
|
610
518
|
onDelete: "Cascade"
|
|
611
519
|
})
|
|
612
520
|
},
|
|
613
|
-
indexes: [
|
|
521
|
+
indexes: [index4.on(["reviewId"]), index4.on(["authorId"])]
|
|
614
522
|
});
|
|
615
|
-
var ReviewVoteEntity =
|
|
523
|
+
var ReviewVoteEntity = defineEntity4({
|
|
616
524
|
name: "ReviewVote",
|
|
617
525
|
description: "A helpfulness vote on a review.",
|
|
618
526
|
schema: "marketplace",
|
|
619
527
|
map: "review_vote",
|
|
620
528
|
fields: {
|
|
621
|
-
id:
|
|
622
|
-
reviewId:
|
|
623
|
-
userId:
|
|
624
|
-
isHelpful:
|
|
625
|
-
createdAt:
|
|
626
|
-
review:
|
|
529
|
+
id: field4.id(),
|
|
530
|
+
reviewId: field4.foreignKey(),
|
|
531
|
+
userId: field4.foreignKey(),
|
|
532
|
+
isHelpful: field4.boolean(),
|
|
533
|
+
createdAt: field4.createdAt(),
|
|
534
|
+
review: field4.belongsTo("Review", ["reviewId"], ["id"], {
|
|
627
535
|
onDelete: "Cascade"
|
|
628
536
|
})
|
|
629
537
|
},
|
|
630
|
-
indexes: [
|
|
538
|
+
indexes: [index4.unique(["reviewId", "userId"]), index4.on(["userId"])]
|
|
631
539
|
});
|
|
632
|
-
var ReviewReportEntity =
|
|
540
|
+
var ReviewReportEntity = defineEntity4({
|
|
633
541
|
name: "ReviewReport",
|
|
634
542
|
description: "A report/flag on a review.",
|
|
635
543
|
schema: "marketplace",
|
|
636
544
|
map: "review_report",
|
|
637
545
|
fields: {
|
|
638
|
-
id:
|
|
639
|
-
reviewId:
|
|
640
|
-
reporterId:
|
|
641
|
-
reason:
|
|
642
|
-
details:
|
|
643
|
-
status:
|
|
644
|
-
resolvedBy:
|
|
645
|
-
resolvedAt:
|
|
646
|
-
resolution:
|
|
546
|
+
id: field4.id(),
|
|
547
|
+
reviewId: field4.foreignKey(),
|
|
548
|
+
reporterId: field4.foreignKey(),
|
|
549
|
+
reason: field4.string({ description: "Report reason category" }),
|
|
550
|
+
details: field4.string({ isOptional: true }),
|
|
551
|
+
status: field4.string({ default: '"PENDING"' }),
|
|
552
|
+
resolvedBy: field4.string({ isOptional: true }),
|
|
553
|
+
resolvedAt: field4.dateTime({ isOptional: true }),
|
|
554
|
+
resolution: field4.string({ isOptional: true }),
|
|
555
|
+
createdAt: field4.createdAt(),
|
|
556
|
+
review: field4.belongsTo("Review", ["reviewId"], ["id"])
|
|
557
|
+
},
|
|
558
|
+
indexes: [
|
|
559
|
+
index4.on(["reviewId"]),
|
|
560
|
+
index4.on(["status"]),
|
|
561
|
+
index4.on(["reporterId"])
|
|
562
|
+
]
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
// src/entities/store.ts
|
|
566
|
+
import {
|
|
567
|
+
defineEntity as defineEntity5,
|
|
568
|
+
defineEntityEnum as defineEntityEnum5,
|
|
569
|
+
field as field5,
|
|
570
|
+
index as index5
|
|
571
|
+
} from "@contractspec/lib.schema";
|
|
572
|
+
var StoreStatusEnum = defineEntityEnum5({
|
|
573
|
+
name: "StoreStatus",
|
|
574
|
+
values: ["PENDING", "ACTIVE", "SUSPENDED", "CLOSED"],
|
|
575
|
+
schema: "marketplace",
|
|
576
|
+
description: "Status of a store."
|
|
577
|
+
});
|
|
578
|
+
var StoreTypeEnum = defineEntityEnum5({
|
|
579
|
+
name: "StoreType",
|
|
580
|
+
values: ["INDIVIDUAL", "BUSINESS", "ENTERPRISE"],
|
|
581
|
+
schema: "marketplace",
|
|
582
|
+
description: "Type of store account."
|
|
583
|
+
});
|
|
584
|
+
var StoreEntity = defineEntity5({
|
|
585
|
+
name: "Store",
|
|
586
|
+
description: "A seller storefront on the marketplace.",
|
|
587
|
+
schema: "marketplace",
|
|
588
|
+
map: "store",
|
|
589
|
+
fields: {
|
|
590
|
+
id: field5.id({ description: "Unique store ID" }),
|
|
591
|
+
name: field5.string({ description: "Store display name" }),
|
|
592
|
+
slug: field5.string({ description: "URL-friendly identifier" }),
|
|
593
|
+
description: field5.string({ isOptional: true }),
|
|
594
|
+
status: field5.enum("StoreStatus", { default: "PENDING" }),
|
|
595
|
+
type: field5.enum("StoreType", { default: "INDIVIDUAL" }),
|
|
596
|
+
ownerId: field5.foreignKey({ description: "Store owner user ID" }),
|
|
597
|
+
organizationId: field5.foreignKey({ isOptional: true }),
|
|
598
|
+
logoFileId: field5.string({
|
|
599
|
+
isOptional: true,
|
|
600
|
+
description: "Logo file reference"
|
|
601
|
+
}),
|
|
602
|
+
bannerFileId: field5.string({
|
|
603
|
+
isOptional: true,
|
|
604
|
+
description: "Banner file reference"
|
|
605
|
+
}),
|
|
606
|
+
email: field5.string({ isOptional: true }),
|
|
607
|
+
phone: field5.string({ isOptional: true }),
|
|
608
|
+
website: field5.string({ isOptional: true }),
|
|
609
|
+
country: field5.string({ isOptional: true }),
|
|
610
|
+
currency: field5.string({ default: '"USD"' }),
|
|
611
|
+
timezone: field5.string({ isOptional: true }),
|
|
612
|
+
commissionRate: field5.decimal({
|
|
613
|
+
default: 0.1,
|
|
614
|
+
description: "Platform commission rate (e.g., 0.1 = 10%)"
|
|
615
|
+
}),
|
|
616
|
+
isVerified: field5.boolean({ default: false }),
|
|
617
|
+
verifiedAt: field5.dateTime({ isOptional: true }),
|
|
618
|
+
settings: field5.json({ isOptional: true }),
|
|
619
|
+
metadata: field5.json({ isOptional: true }),
|
|
620
|
+
totalProducts: field5.int({ default: 0 }),
|
|
621
|
+
totalOrders: field5.int({ default: 0 }),
|
|
622
|
+
totalRevenue: field5.decimal({ default: 0 }),
|
|
623
|
+
averageRating: field5.decimal({ default: 0 }),
|
|
647
624
|
createdAt: field5.createdAt(),
|
|
648
|
-
|
|
625
|
+
updatedAt: field5.updatedAt(),
|
|
626
|
+
products: field5.hasMany("Product"),
|
|
627
|
+
orders: field5.hasMany("Order"),
|
|
628
|
+
payouts: field5.hasMany("Payout")
|
|
649
629
|
},
|
|
650
630
|
indexes: [
|
|
651
|
-
index5.
|
|
631
|
+
index5.unique(["slug"]),
|
|
632
|
+
index5.on(["ownerId"]),
|
|
652
633
|
index5.on(["status"]),
|
|
653
|
-
index5.on(["
|
|
654
|
-
|
|
634
|
+
index5.on(["country", "status"]),
|
|
635
|
+
index5.on(["averageRating"])
|
|
636
|
+
],
|
|
637
|
+
enums: [StoreStatusEnum, StoreTypeEnum]
|
|
638
|
+
});
|
|
639
|
+
var StoreCategoryEntity = defineEntity5({
|
|
640
|
+
name: "StoreCategory",
|
|
641
|
+
description: "Category assignment for stores.",
|
|
642
|
+
schema: "marketplace",
|
|
643
|
+
map: "store_category",
|
|
644
|
+
fields: {
|
|
645
|
+
id: field5.id(),
|
|
646
|
+
storeId: field5.foreignKey(),
|
|
647
|
+
categoryId: field5.foreignKey(),
|
|
648
|
+
isPrimary: field5.boolean({ default: false }),
|
|
649
|
+
createdAt: field5.createdAt(),
|
|
650
|
+
store: field5.belongsTo("Store", ["storeId"], ["id"], {
|
|
651
|
+
onDelete: "Cascade"
|
|
652
|
+
})
|
|
653
|
+
},
|
|
654
|
+
indexes: [index5.unique(["storeId", "categoryId"]), index5.on(["categoryId"])]
|
|
655
655
|
});
|
|
656
656
|
// src/entities/index.ts
|
|
657
657
|
var marketplaceEntities = [
|