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