@unifiedcommerce/plugin-marketplace 0.0.1
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 +479 -0
- package/dist/analytics-models.d.ts +13 -0
- package/dist/analytics-models.d.ts.map +1 -0
- package/dist/analytics-models.js +69 -0
- package/dist/hooks.d.ts +4 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +187 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +105 -0
- package/dist/mcp-tools.d.ts +21 -0
- package/dist/mcp-tools.d.ts.map +1 -0
- package/dist/mcp-tools.js +183 -0
- package/dist/routes/b2b.d.ts +9 -0
- package/dist/routes/b2b.d.ts.map +1 -0
- package/dist/routes/b2b.js +156 -0
- package/dist/routes/commission.d.ts +6 -0
- package/dist/routes/commission.d.ts.map +1 -0
- package/dist/routes/commission.js +85 -0
- package/dist/routes/disputes-returns-reviews.d.ts +10 -0
- package/dist/routes/disputes-returns-reviews.d.ts.map +1 -0
- package/dist/routes/disputes-returns-reviews.js +179 -0
- package/dist/routes/payouts.d.ts +6 -0
- package/dist/routes/payouts.d.ts.map +1 -0
- package/dist/routes/payouts.js +40 -0
- package/dist/routes/sub-orders.d.ts +6 -0
- package/dist/routes/sub-orders.d.ts.map +1 -0
- package/dist/routes/sub-orders.js +44 -0
- package/dist/routes/util.d.ts +23 -0
- package/dist/routes/util.d.ts.map +1 -0
- package/dist/routes/util.js +41 -0
- package/dist/routes/vendor-portal.d.ts +14 -0
- package/dist/routes/vendor-portal.d.ts.map +1 -0
- package/dist/routes/vendor-portal.js +255 -0
- package/dist/routes/vendors.d.ts +11 -0
- package/dist/routes/vendors.d.ts.map +1 -0
- package/dist/routes/vendors.js +185 -0
- package/dist/schema.d.ts +3255 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +225 -0
- package/dist/schemas/b2b.d.ts +1009 -0
- package/dist/schemas/b2b.d.ts.map +1 -0
- package/dist/schemas/b2b.js +208 -0
- package/dist/schemas/commission.d.ts +532 -0
- package/dist/schemas/commission.d.ts.map +1 -0
- package/dist/schemas/commission.js +113 -0
- package/dist/schemas/disputes-returns-reviews.d.ts +1405 -0
- package/dist/schemas/disputes-returns-reviews.d.ts.map +1 -0
- package/dist/schemas/disputes-returns-reviews.js +270 -0
- package/dist/schemas/payouts.d.ts +375 -0
- package/dist/schemas/payouts.d.ts.map +1 -0
- package/dist/schemas/payouts.js +78 -0
- package/dist/schemas/sub-orders.d.ts +303 -0
- package/dist/schemas/sub-orders.d.ts.map +1 -0
- package/dist/schemas/sub-orders.js +67 -0
- package/dist/schemas/vendor-portal.d.ts +1785 -0
- package/dist/schemas/vendor-portal.d.ts.map +1 -0
- package/dist/schemas/vendor-portal.js +294 -0
- package/dist/schemas/vendors.d.ts +1348 -0
- package/dist/schemas/vendors.d.ts.map +1 -0
- package/dist/schemas/vendors.js +245 -0
- package/dist/services/commission.d.ts +81 -0
- package/dist/services/commission.d.ts.map +1 -0
- package/dist/services/commission.js +98 -0
- package/dist/services/contract-price.d.ts +64 -0
- package/dist/services/contract-price.d.ts.map +1 -0
- package/dist/services/contract-price.js +57 -0
- package/dist/services/dispute.d.ts +156 -0
- package/dist/services/dispute.d.ts.map +1 -0
- package/dist/services/dispute.js +77 -0
- package/dist/services/payout.d.ts +126 -0
- package/dist/services/payout.d.ts.map +1 -0
- package/dist/services/payout.js +130 -0
- package/dist/services/return.d.ts +181 -0
- package/dist/services/return.d.ts.map +1 -0
- package/dist/services/return.js +80 -0
- package/dist/services/review.d.ts +70 -0
- package/dist/services/review.d.ts.map +1 -0
- package/dist/services/review.js +60 -0
- package/dist/services/rfq.d.ts +122 -0
- package/dist/services/rfq.d.ts.map +1 -0
- package/dist/services/rfq.js +60 -0
- package/dist/services/sub-order.d.ts +336 -0
- package/dist/services/sub-order.d.ts.map +1 -0
- package/dist/services/sub-order.js +121 -0
- package/dist/services/vendor.d.ts +528 -0
- package/dist/services/vendor.d.ts.map +1 -0
- package/dist/services/vendor.js +119 -0
- package/dist/types.d.ts +67 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/package.json +43 -0
- package/src/analytics-models.ts +75 -0
- package/src/hooks.ts +215 -0
- package/src/index.ts +124 -0
- package/src/mcp-tools.ts +210 -0
- package/src/routes/b2b.ts +179 -0
- package/src/routes/commission.ts +95 -0
- package/src/routes/disputes-returns-reviews.ts +209 -0
- package/src/routes/payouts.ts +49 -0
- package/src/routes/sub-orders.ts +54 -0
- package/src/routes/util.ts +42 -0
- package/src/routes/vendor-portal.ts +277 -0
- package/src/routes/vendors.ts +201 -0
- package/src/schema.ts +260 -0
- package/src/schemas/b2b.ts +238 -0
- package/src/schemas/commission.ts +129 -0
- package/src/schemas/disputes-returns-reviews.ts +311 -0
- package/src/schemas/payouts.ts +90 -0
- package/src/schemas/sub-orders.ts +77 -0
- package/src/schemas/vendor-portal.ts +344 -0
- package/src/schemas/vendors.ts +281 -0
- package/src/services/commission.ts +120 -0
- package/src/services/contract-price.ts +80 -0
- package/src/services/dispute.ts +92 -0
- package/src/services/payout.ts +154 -0
- package/src/services/return.ts +92 -0
- package/src/services/review.ts +76 -0
- package/src/services/rfq.ts +82 -0
- package/src/services/sub-order.ts +136 -0
- package/src/services/vendor.ts +151 -0
- package/src/types.ts +164 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vendors.d.ts","sourceRoot":"","sources":["../../src/schemas/vendors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAe,MAAM,mBAAmB,CAAC;AAqBnD,eAAO,MAAM,sBAAsB;;;;;;iBAOF,CAAC;AAElC,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAY5B,CAAC;AAIH,eAAO,MAAM,sBAAsB;;;;;;;iBAOF,CAAC;AAElC,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAa5B,CAAC;AAIH,eAAO,MAAM,sBAAsB;;iBAEF,CAAC;AAElC,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAa5B,CAAC;AAIH,eAAO,MAAM,uBAAuB;;iBAEF,CAAC;AAEnC,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAa7B,CAAC;AAIH,eAAO,MAAM,wBAAwB;;;iBAGI,CAAC;AAE1C,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAa9B,CAAC;AAIH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgB3B,CAAC;AAIH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYzB,CAAC;AAIH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAY7B,CAAC;AAIH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAY/B,CAAC;AAIH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYnC,CAAC;AAIH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAY/B,CAAC;AAIH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAY9B,CAAC;AAIH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAY7B,CAAC;AAIH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYjC,CAAC"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { z, createRoute } from "@hono/zod-openapi";
|
|
2
|
+
const ErrorSchema = z.object({
|
|
3
|
+
error: z.object({
|
|
4
|
+
code: z.string(),
|
|
5
|
+
message: z.string(),
|
|
6
|
+
}),
|
|
7
|
+
});
|
|
8
|
+
const errorResponses = {
|
|
9
|
+
401: { content: { "application/json": { schema: ErrorSchema } }, description: "Authentication required." },
|
|
10
|
+
403: { content: { "application/json": { schema: ErrorSchema } }, description: "Insufficient permissions." },
|
|
11
|
+
404: { content: { "application/json": { schema: ErrorSchema } }, description: "Not found." },
|
|
12
|
+
422: { content: { "application/json": { schema: ErrorSchema } }, description: "Validation error." },
|
|
13
|
+
500: { content: { "application/json": { schema: ErrorSchema } }, description: "Server error." },
|
|
14
|
+
};
|
|
15
|
+
const VendorResponseSchema = z.object({ data: z.any() });
|
|
16
|
+
// ─── Create Vendor ───────────────────────────────────────────────────────────
|
|
17
|
+
export const CreateVendorBodySchema = z.object({
|
|
18
|
+
name: z.string().min(1).openapi({ example: "Acme Co" }),
|
|
19
|
+
slug: z.string().optional(),
|
|
20
|
+
contactEmail: z.string().email().optional(),
|
|
21
|
+
commissionRateBps: z.number().int().min(0).max(10000).optional()
|
|
22
|
+
.openapi({ example: 1000, description: "Basis points (100 = 1%)" }),
|
|
23
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
24
|
+
}).openapi("CreateVendorRequest");
|
|
25
|
+
export const createVendorRoute = createRoute({
|
|
26
|
+
method: "post",
|
|
27
|
+
path: "/api/marketplace/vendors",
|
|
28
|
+
tags: ["Marketplace - Vendors"],
|
|
29
|
+
summary: "Create a vendor",
|
|
30
|
+
request: {
|
|
31
|
+
body: { content: { "application/json": { schema: CreateVendorBodySchema } }, required: true },
|
|
32
|
+
},
|
|
33
|
+
responses: {
|
|
34
|
+
201: { content: { "application/json": { schema: VendorResponseSchema } }, description: "Vendor created." },
|
|
35
|
+
...errorResponses,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
// ─── Update Vendor ───────────────────────────────────────────────────────────
|
|
39
|
+
export const UpdateVendorBodySchema = z.object({
|
|
40
|
+
name: z.string().optional(),
|
|
41
|
+
description: z.string().optional(),
|
|
42
|
+
contactEmail: z.string().email().optional(),
|
|
43
|
+
commissionRateBps: z.number().int().min(0).max(10000).optional(),
|
|
44
|
+
tier: z.string().optional(),
|
|
45
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
46
|
+
}).openapi("UpdateVendorRequest");
|
|
47
|
+
export const updateVendorRoute = createRoute({
|
|
48
|
+
method: "patch",
|
|
49
|
+
path: "/api/marketplace/vendors/{id}",
|
|
50
|
+
tags: ["Marketplace - Vendors"],
|
|
51
|
+
summary: "Update a vendor",
|
|
52
|
+
request: {
|
|
53
|
+
params: z.object({ id: z.uuid() }),
|
|
54
|
+
body: { content: { "application/json": { schema: UpdateVendorBodySchema } }, required: true },
|
|
55
|
+
},
|
|
56
|
+
responses: {
|
|
57
|
+
200: { content: { "application/json": { schema: VendorResponseSchema } }, description: "Vendor updated." },
|
|
58
|
+
...errorResponses,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
// ─── Reject Vendor ───────────────────────────────────────────────────────────
|
|
62
|
+
export const RejectVendorBodySchema = z.object({
|
|
63
|
+
reason: z.string().min(1).openapi({ example: "Incomplete documentation" }),
|
|
64
|
+
}).openapi("RejectVendorRequest");
|
|
65
|
+
export const rejectVendorRoute = createRoute({
|
|
66
|
+
method: "post",
|
|
67
|
+
path: "/api/marketplace/vendors/{id}/reject",
|
|
68
|
+
tags: ["Marketplace - Vendors"],
|
|
69
|
+
summary: "Reject a vendor application",
|
|
70
|
+
request: {
|
|
71
|
+
params: z.object({ id: z.uuid() }),
|
|
72
|
+
body: { content: { "application/json": { schema: RejectVendorBodySchema } }, required: true },
|
|
73
|
+
},
|
|
74
|
+
responses: {
|
|
75
|
+
200: { content: { "application/json": { schema: VendorResponseSchema } }, description: "Vendor rejected." },
|
|
76
|
+
...errorResponses,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
// ─── Suspend Vendor ──────────────────────────────────────────────────────────
|
|
80
|
+
export const SuspendVendorBodySchema = z.object({
|
|
81
|
+
reason: z.string().min(1).openapi({ example: "Policy violation" }),
|
|
82
|
+
}).openapi("SuspendVendorRequest");
|
|
83
|
+
export const suspendVendorRoute = createRoute({
|
|
84
|
+
method: "post",
|
|
85
|
+
path: "/api/marketplace/vendors/{id}/suspend",
|
|
86
|
+
tags: ["Marketplace - Vendors"],
|
|
87
|
+
summary: "Suspend a vendor",
|
|
88
|
+
request: {
|
|
89
|
+
params: z.object({ id: z.uuid() }),
|
|
90
|
+
body: { content: { "application/json": { schema: SuspendVendorBodySchema } }, required: true },
|
|
91
|
+
},
|
|
92
|
+
responses: {
|
|
93
|
+
200: { content: { "application/json": { schema: VendorResponseSchema } }, description: "Vendor suspended." },
|
|
94
|
+
...errorResponses,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
// ─── Upload Document ─────────────────────────────────────────────────────────
|
|
98
|
+
export const UploadDocumentBodySchema = z.object({
|
|
99
|
+
type: z.string().min(1).openapi({ example: "business_license" }),
|
|
100
|
+
fileUrl: z.string().url().openapi({ example: "https://storage.example.com/doc.pdf" }),
|
|
101
|
+
}).openapi("UploadVendorDocumentRequest");
|
|
102
|
+
export const uploadDocumentRoute = createRoute({
|
|
103
|
+
method: "post",
|
|
104
|
+
path: "/api/marketplace/vendors/{id}/documents",
|
|
105
|
+
tags: ["Marketplace - Vendors"],
|
|
106
|
+
summary: "Upload a vendor document",
|
|
107
|
+
request: {
|
|
108
|
+
params: z.object({ id: z.uuid() }),
|
|
109
|
+
body: { content: { "application/json": { schema: UploadDocumentBodySchema } }, required: true },
|
|
110
|
+
},
|
|
111
|
+
responses: {
|
|
112
|
+
201: { content: { "application/json": { schema: VendorResponseSchema } }, description: "Document uploaded." },
|
|
113
|
+
...errorResponses,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
// ─── List Vendors ───────────────────────────────────────────────────────────
|
|
117
|
+
export const listVendorsRoute = createRoute({
|
|
118
|
+
method: "get",
|
|
119
|
+
path: "/api/marketplace/vendors",
|
|
120
|
+
tags: ["Marketplace - Vendors"],
|
|
121
|
+
summary: "List all vendors",
|
|
122
|
+
request: {
|
|
123
|
+
query: z.object({
|
|
124
|
+
status: z.string().optional(),
|
|
125
|
+
tier: z.string().optional(),
|
|
126
|
+
search: z.string().optional(),
|
|
127
|
+
}),
|
|
128
|
+
},
|
|
129
|
+
responses: {
|
|
130
|
+
200: { content: { "application/json": { schema: VendorResponseSchema } }, description: "Success" },
|
|
131
|
+
...errorResponses,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
// ─── Get Vendor ─────────────────────────────────────────────────────────────
|
|
135
|
+
export const getVendorRoute = createRoute({
|
|
136
|
+
method: "get",
|
|
137
|
+
path: "/api/marketplace/vendors/{id}",
|
|
138
|
+
tags: ["Marketplace - Vendors"],
|
|
139
|
+
summary: "Get vendor detail",
|
|
140
|
+
request: {
|
|
141
|
+
params: z.object({ id: z.uuid() }),
|
|
142
|
+
},
|
|
143
|
+
responses: {
|
|
144
|
+
200: { content: { "application/json": { schema: VendorResponseSchema } }, description: "Success" },
|
|
145
|
+
...errorResponses,
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
// ─── Approve Vendor ─────────────────────────────────────────────────────────
|
|
149
|
+
export const approveVendorRoute = createRoute({
|
|
150
|
+
method: "post",
|
|
151
|
+
path: "/api/marketplace/vendors/{id}/approve",
|
|
152
|
+
tags: ["Marketplace - Vendors"],
|
|
153
|
+
summary: "Approve a vendor application",
|
|
154
|
+
request: {
|
|
155
|
+
params: z.object({ id: z.uuid() }),
|
|
156
|
+
},
|
|
157
|
+
responses: {
|
|
158
|
+
200: { content: { "application/json": { schema: VendorResponseSchema } }, description: "Vendor approved." },
|
|
159
|
+
...errorResponses,
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
// ─── Reinstate Vendor ───────────────────────────────────────────────────────
|
|
163
|
+
export const reinstateVendorRoute = createRoute({
|
|
164
|
+
method: "post",
|
|
165
|
+
path: "/api/marketplace/vendors/{id}/reinstate",
|
|
166
|
+
tags: ["Marketplace - Vendors"],
|
|
167
|
+
summary: "Reinstate a suspended vendor",
|
|
168
|
+
request: {
|
|
169
|
+
params: z.object({ id: z.uuid() }),
|
|
170
|
+
},
|
|
171
|
+
responses: {
|
|
172
|
+
200: { content: { "application/json": { schema: VendorResponseSchema } }, description: "Vendor reinstated." },
|
|
173
|
+
...errorResponses,
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
// ─── List Vendor Documents ──────────────────────────────────────────────────
|
|
177
|
+
export const listVendorDocumentsRoute = createRoute({
|
|
178
|
+
method: "get",
|
|
179
|
+
path: "/api/marketplace/vendors/{id}/documents",
|
|
180
|
+
tags: ["Marketplace - Vendors"],
|
|
181
|
+
summary: "List vendor documents",
|
|
182
|
+
request: {
|
|
183
|
+
params: z.object({ id: z.uuid() }),
|
|
184
|
+
},
|
|
185
|
+
responses: {
|
|
186
|
+
200: { content: { "application/json": { schema: VendorResponseSchema } }, description: "Success" },
|
|
187
|
+
...errorResponses,
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
// ─── Approve Document ───────────────────────────────────────────────────────
|
|
191
|
+
export const approveDocumentRoute = createRoute({
|
|
192
|
+
method: "post",
|
|
193
|
+
path: "/api/marketplace/vendors/{id}/documents/{docId}/approve",
|
|
194
|
+
tags: ["Marketplace - Vendors"],
|
|
195
|
+
summary: "Approve a vendor document",
|
|
196
|
+
request: {
|
|
197
|
+
params: z.object({ id: z.uuid(), docId: z.uuid() }),
|
|
198
|
+
},
|
|
199
|
+
responses: {
|
|
200
|
+
200: { content: { "application/json": { schema: VendorResponseSchema } }, description: "Document approved." },
|
|
201
|
+
...errorResponses,
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
// ─── Reject Document ────────────────────────────────────────────────────────
|
|
205
|
+
export const rejectDocumentRoute = createRoute({
|
|
206
|
+
method: "post",
|
|
207
|
+
path: "/api/marketplace/vendors/{id}/documents/{docId}/reject",
|
|
208
|
+
tags: ["Marketplace - Vendors"],
|
|
209
|
+
summary: "Reject a vendor document",
|
|
210
|
+
request: {
|
|
211
|
+
params: z.object({ id: z.uuid(), docId: z.uuid() }),
|
|
212
|
+
},
|
|
213
|
+
responses: {
|
|
214
|
+
200: { content: { "application/json": { schema: VendorResponseSchema } }, description: "Document rejected." },
|
|
215
|
+
...errorResponses,
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
// ─── Vendor Balance ─────────────────────────────────────────────────────────
|
|
219
|
+
export const vendorBalanceRoute = createRoute({
|
|
220
|
+
method: "get",
|
|
221
|
+
path: "/api/marketplace/vendors/{id}/balance",
|
|
222
|
+
tags: ["Marketplace - Vendors"],
|
|
223
|
+
summary: "Get vendor balance",
|
|
224
|
+
request: {
|
|
225
|
+
params: z.object({ id: z.uuid() }),
|
|
226
|
+
},
|
|
227
|
+
responses: {
|
|
228
|
+
200: { content: { "application/json": { schema: VendorResponseSchema } }, description: "Success" },
|
|
229
|
+
...errorResponses,
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
// ─── Vendor Performance ─────────────────────────────────────────────────────
|
|
233
|
+
export const vendorPerformanceRoute = createRoute({
|
|
234
|
+
method: "get",
|
|
235
|
+
path: "/api/marketplace/vendors/{id}/performance",
|
|
236
|
+
tags: ["Marketplace - Vendors"],
|
|
237
|
+
summary: "Get vendor performance metrics",
|
|
238
|
+
request: {
|
|
239
|
+
params: z.object({ id: z.uuid() }),
|
|
240
|
+
},
|
|
241
|
+
responses: {
|
|
242
|
+
200: { content: { "application/json": { schema: VendorResponseSchema } }, description: "Success" },
|
|
243
|
+
...errorResponses,
|
|
244
|
+
},
|
|
245
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Db, MarketplacePluginOptions } from "../types";
|
|
2
|
+
export declare class CommissionService {
|
|
3
|
+
private db;
|
|
4
|
+
private options;
|
|
5
|
+
constructor(db: Db, options: MarketplacePluginOptions);
|
|
6
|
+
createRule(data: {
|
|
7
|
+
name: string;
|
|
8
|
+
type: string;
|
|
9
|
+
rateBps: number;
|
|
10
|
+
categorySlug?: string;
|
|
11
|
+
vendorId?: string;
|
|
12
|
+
vendorTier?: string;
|
|
13
|
+
minVolumeCents?: number;
|
|
14
|
+
maxVolumeCents?: number;
|
|
15
|
+
validFrom?: Date | undefined;
|
|
16
|
+
validUntil?: Date | undefined;
|
|
17
|
+
priority?: number;
|
|
18
|
+
}): Promise<{
|
|
19
|
+
id: string;
|
|
20
|
+
vendorId: string | null;
|
|
21
|
+
type: string;
|
|
22
|
+
name: string;
|
|
23
|
+
categorySlug: string | null;
|
|
24
|
+
vendorTier: string | null;
|
|
25
|
+
minVolumeCents: number | null;
|
|
26
|
+
maxVolumeCents: number | null;
|
|
27
|
+
rateBps: number;
|
|
28
|
+
validFrom: Date | null;
|
|
29
|
+
validUntil: Date | null;
|
|
30
|
+
priority: number;
|
|
31
|
+
isActive: boolean;
|
|
32
|
+
} | undefined>;
|
|
33
|
+
updateRule(id: string, data: Record<string, unknown>): Promise<{
|
|
34
|
+
id: string;
|
|
35
|
+
name: string;
|
|
36
|
+
type: string;
|
|
37
|
+
categorySlug: string | null;
|
|
38
|
+
vendorId: string | null;
|
|
39
|
+
vendorTier: string | null;
|
|
40
|
+
minVolumeCents: number | null;
|
|
41
|
+
maxVolumeCents: number | null;
|
|
42
|
+
rateBps: number;
|
|
43
|
+
validFrom: Date | null;
|
|
44
|
+
validUntil: Date | null;
|
|
45
|
+
priority: number;
|
|
46
|
+
isActive: boolean;
|
|
47
|
+
} | null>;
|
|
48
|
+
deleteRule(id: string): Promise<void>;
|
|
49
|
+
listRules(): Promise<{
|
|
50
|
+
id: string;
|
|
51
|
+
name: string;
|
|
52
|
+
type: string;
|
|
53
|
+
categorySlug: string | null;
|
|
54
|
+
vendorId: string | null;
|
|
55
|
+
vendorTier: string | null;
|
|
56
|
+
minVolumeCents: number | null;
|
|
57
|
+
maxVolumeCents: number | null;
|
|
58
|
+
rateBps: number;
|
|
59
|
+
validFrom: Date | null;
|
|
60
|
+
validUntil: Date | null;
|
|
61
|
+
priority: number;
|
|
62
|
+
isActive: boolean;
|
|
63
|
+
}[]>;
|
|
64
|
+
/**
|
|
65
|
+
* Resolve the effective commission rate for a given vendor+category+volume.
|
|
66
|
+
* Priority order per RFC §5.2:
|
|
67
|
+
* 1. Vendor-specific + category-specific
|
|
68
|
+
* 2. Category-specific (any vendor)
|
|
69
|
+
* 3. Vendor tier rule
|
|
70
|
+
* 4. Volume tier rule
|
|
71
|
+
* 5. Promotional rule
|
|
72
|
+
* 6. Vendor-level flat rate
|
|
73
|
+
* 7. Plugin default
|
|
74
|
+
*/
|
|
75
|
+
resolveRate(vendorId: string, categorySlug?: string, volumeCents?: number): Promise<number>;
|
|
76
|
+
previewRate(vendorId: string, categorySlug?: string, volumeCents?: number): Promise<{
|
|
77
|
+
rateBps: number;
|
|
78
|
+
ratePercent: number;
|
|
79
|
+
}>;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=commission.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commission.d.ts","sourceRoot":"","sources":["../../src/services/commission.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAE7D,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,OAAO;gBADP,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,wBAAwB;IAGrC,UAAU,CAAC,IAAI,EAAE;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,SAAS,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;QAC7B,UAAU,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;QAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB;;;;;;;;;;;;;;;IAKK,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;;;;IAMpD,UAAU,CAAC,EAAE,EAAE,MAAM;IAIrB,SAAS;;;;;;;;;;;;;;;IAIf;;;;;;;;;;OAUG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA+D3F,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM;;;;CAIhF"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { eq, desc } from "drizzle-orm";
|
|
2
|
+
import { commissionRules, vendors } from "../schema";
|
|
3
|
+
export class CommissionService {
|
|
4
|
+
db;
|
|
5
|
+
options;
|
|
6
|
+
constructor(db, options) {
|
|
7
|
+
this.db = db;
|
|
8
|
+
this.options = options;
|
|
9
|
+
}
|
|
10
|
+
async createRule(data) {
|
|
11
|
+
const [rule] = await this.db.insert(commissionRules).values(data).returning();
|
|
12
|
+
return rule;
|
|
13
|
+
}
|
|
14
|
+
async updateRule(id, data) {
|
|
15
|
+
const [updated] = await this.db.update(commissionRules).set(data)
|
|
16
|
+
.where(eq(commissionRules.id, id)).returning();
|
|
17
|
+
return updated ?? null;
|
|
18
|
+
}
|
|
19
|
+
async deleteRule(id) {
|
|
20
|
+
await this.db.delete(commissionRules).where(eq(commissionRules.id, id));
|
|
21
|
+
}
|
|
22
|
+
async listRules() {
|
|
23
|
+
return this.db.select().from(commissionRules).orderBy(desc(commissionRules.priority));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Resolve the effective commission rate for a given vendor+category+volume.
|
|
27
|
+
* Priority order per RFC §5.2:
|
|
28
|
+
* 1. Vendor-specific + category-specific
|
|
29
|
+
* 2. Category-specific (any vendor)
|
|
30
|
+
* 3. Vendor tier rule
|
|
31
|
+
* 4. Volume tier rule
|
|
32
|
+
* 5. Promotional rule
|
|
33
|
+
* 6. Vendor-level flat rate
|
|
34
|
+
* 7. Plugin default
|
|
35
|
+
*/
|
|
36
|
+
async resolveRate(vendorId, categorySlug, volumeCents) {
|
|
37
|
+
const now = new Date();
|
|
38
|
+
const rules = await this.db.select().from(commissionRules)
|
|
39
|
+
.where(eq(commissionRules.isActive, true))
|
|
40
|
+
.orderBy(desc(commissionRules.priority));
|
|
41
|
+
// Load vendor for tier and flat rate fallback
|
|
42
|
+
const [vendor] = await this.db.select().from(vendors).where(eq(vendors.id, vendorId));
|
|
43
|
+
for (const rule of rules) {
|
|
44
|
+
// Check time validity
|
|
45
|
+
if (rule.validFrom && rule.validFrom > now)
|
|
46
|
+
continue;
|
|
47
|
+
if (rule.validUntil && rule.validUntil < now)
|
|
48
|
+
continue;
|
|
49
|
+
// 1. Vendor-specific + category-specific
|
|
50
|
+
if (rule.type === "category" && rule.vendorId === vendorId && rule.categorySlug === categorySlug) {
|
|
51
|
+
return rule.rateBps;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
for (const rule of rules) {
|
|
55
|
+
if (rule.validFrom && rule.validFrom > now)
|
|
56
|
+
continue;
|
|
57
|
+
if (rule.validUntil && rule.validUntil < now)
|
|
58
|
+
continue;
|
|
59
|
+
// 2. Category-specific (any vendor)
|
|
60
|
+
if (rule.type === "category" && !rule.vendorId && rule.categorySlug === categorySlug) {
|
|
61
|
+
return rule.rateBps;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
for (const rule of rules) {
|
|
65
|
+
if (rule.validFrom && rule.validFrom > now)
|
|
66
|
+
continue;
|
|
67
|
+
if (rule.validUntil && rule.validUntil < now)
|
|
68
|
+
continue;
|
|
69
|
+
// 3. Vendor tier
|
|
70
|
+
if (rule.type === "vendor_tier" && vendor && rule.vendorTier === vendor.tier) {
|
|
71
|
+
return rule.rateBps;
|
|
72
|
+
}
|
|
73
|
+
// 4. Volume tier
|
|
74
|
+
if (rule.type === "volume_tier" && volumeCents != null) {
|
|
75
|
+
const min = rule.minVolumeCents ?? 0;
|
|
76
|
+
const max = rule.maxVolumeCents ?? Number.MAX_SAFE_INTEGER;
|
|
77
|
+
if (volumeCents >= min && volumeCents <= max) {
|
|
78
|
+
return rule.rateBps;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// 5. Promotional
|
|
82
|
+
if (rule.type === "promotional") {
|
|
83
|
+
if (!rule.vendorId || rule.vendorId === vendorId) {
|
|
84
|
+
return rule.rateBps;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// 6. Vendor flat rate
|
|
89
|
+
if (vendor)
|
|
90
|
+
return vendor.commissionRateBps;
|
|
91
|
+
// 7. Plugin default
|
|
92
|
+
return this.options.defaultCommissionRateBps ?? 1000;
|
|
93
|
+
}
|
|
94
|
+
async previewRate(vendorId, categorySlug, volumeCents) {
|
|
95
|
+
const rateBps = await this.resolveRate(vendorId, categorySlug, volumeCents);
|
|
96
|
+
return { rateBps, ratePercent: rateBps / 100 };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Db } from "../types";
|
|
2
|
+
export declare class ContractPriceService {
|
|
3
|
+
private db;
|
|
4
|
+
constructor(db: Db);
|
|
5
|
+
create(data: {
|
|
6
|
+
vendorId: string;
|
|
7
|
+
buyerId: string;
|
|
8
|
+
entityId: string;
|
|
9
|
+
variantId?: string;
|
|
10
|
+
priceCents: number;
|
|
11
|
+
minQuantity?: number;
|
|
12
|
+
currency?: string;
|
|
13
|
+
validFrom?: Date | undefined;
|
|
14
|
+
validUntil?: Date | undefined;
|
|
15
|
+
}): Promise<{
|
|
16
|
+
id: string;
|
|
17
|
+
vendorId: string;
|
|
18
|
+
createdAt: Date;
|
|
19
|
+
entityId: string;
|
|
20
|
+
validFrom: Date | null;
|
|
21
|
+
validUntil: Date | null;
|
|
22
|
+
buyerId: string;
|
|
23
|
+
currency: string;
|
|
24
|
+
variantId: string | null;
|
|
25
|
+
priceCents: number;
|
|
26
|
+
minQuantity: number;
|
|
27
|
+
} | undefined>;
|
|
28
|
+
update(id: string, data: Record<string, unknown>): Promise<{
|
|
29
|
+
id: string;
|
|
30
|
+
vendorId: string;
|
|
31
|
+
buyerId: string;
|
|
32
|
+
entityId: string;
|
|
33
|
+
variantId: string | null;
|
|
34
|
+
priceCents: number;
|
|
35
|
+
minQuantity: number;
|
|
36
|
+
currency: string;
|
|
37
|
+
validFrom: Date | null;
|
|
38
|
+
validUntil: Date | null;
|
|
39
|
+
createdAt: Date;
|
|
40
|
+
} | null>;
|
|
41
|
+
delete(id: string): Promise<void>;
|
|
42
|
+
list(filters?: {
|
|
43
|
+
vendorId?: string;
|
|
44
|
+
buyerId?: string;
|
|
45
|
+
}): Promise<{
|
|
46
|
+
id: string;
|
|
47
|
+
vendorId: string;
|
|
48
|
+
buyerId: string;
|
|
49
|
+
entityId: string;
|
|
50
|
+
variantId: string | null;
|
|
51
|
+
priceCents: number;
|
|
52
|
+
minQuantity: number;
|
|
53
|
+
currency: string;
|
|
54
|
+
validFrom: Date | null;
|
|
55
|
+
validUntil: Date | null;
|
|
56
|
+
createdAt: Date;
|
|
57
|
+
}[]>;
|
|
58
|
+
/**
|
|
59
|
+
* Resolve the best contract price for a buyer+vendor+entity+quantity.
|
|
60
|
+
* Returns null if no matching contract exists.
|
|
61
|
+
*/
|
|
62
|
+
resolvePrice(vendorId: string, buyerId: string, entityId: string, variantId: string | null, quantity: number): Promise<number | null>;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=contract-price.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-price.d.ts","sourceRoot":"","sources":["../../src/services/contract-price.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAEnC,qBAAa,oBAAoB;IACnB,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,EAAE;IAEpB,MAAM,CAAC,IAAI,EAAE;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;QAC7B,UAAU,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;KAC/B;;;;;;;;;;;;;IAKK,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;;IAMhD,MAAM,CAAC,EAAE,EAAE,MAAM;IAIjB,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;;IAW5D;;;OAGG;IACG,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CA0B1B"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { eq, and, desc } from "drizzle-orm";
|
|
2
|
+
import { contractPrices } from "../schema";
|
|
3
|
+
export class ContractPriceService {
|
|
4
|
+
db;
|
|
5
|
+
constructor(db) {
|
|
6
|
+
this.db = db;
|
|
7
|
+
}
|
|
8
|
+
async create(data) {
|
|
9
|
+
const [price] = await this.db.insert(contractPrices).values(data).returning();
|
|
10
|
+
return price;
|
|
11
|
+
}
|
|
12
|
+
async update(id, data) {
|
|
13
|
+
const [updated] = await this.db.update(contractPrices).set(data)
|
|
14
|
+
.where(eq(contractPrices.id, id)).returning();
|
|
15
|
+
return updated ?? null;
|
|
16
|
+
}
|
|
17
|
+
async delete(id) {
|
|
18
|
+
await this.db.delete(contractPrices).where(eq(contractPrices.id, id));
|
|
19
|
+
}
|
|
20
|
+
async list(filters) {
|
|
21
|
+
let query = this.db.select().from(contractPrices).$dynamic();
|
|
22
|
+
const conditions = [];
|
|
23
|
+
if (filters?.vendorId)
|
|
24
|
+
conditions.push(eq(contractPrices.vendorId, filters.vendorId));
|
|
25
|
+
if (filters?.buyerId)
|
|
26
|
+
conditions.push(eq(contractPrices.buyerId, filters.buyerId));
|
|
27
|
+
if (conditions.length > 0) {
|
|
28
|
+
query = query.where(conditions.length === 1 ? conditions[0] : and(...conditions));
|
|
29
|
+
}
|
|
30
|
+
return query.orderBy(desc(contractPrices.createdAt));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the best contract price for a buyer+vendor+entity+quantity.
|
|
34
|
+
* Returns null if no matching contract exists.
|
|
35
|
+
*/
|
|
36
|
+
async resolvePrice(vendorId, buyerId, entityId, variantId, quantity) {
|
|
37
|
+
const now = new Date();
|
|
38
|
+
const all = await this.db.select().from(contractPrices)
|
|
39
|
+
.where(and(eq(contractPrices.vendorId, vendorId), eq(contractPrices.buyerId, buyerId), eq(contractPrices.entityId, entityId)))
|
|
40
|
+
.orderBy(desc(contractPrices.priceCents));
|
|
41
|
+
for (const cp of all) {
|
|
42
|
+
// Check variant match
|
|
43
|
+
if (variantId != null && cp.variantId != null && cp.variantId !== variantId)
|
|
44
|
+
continue;
|
|
45
|
+
// Check quantity
|
|
46
|
+
if (quantity < (cp.minQuantity ?? 1))
|
|
47
|
+
continue;
|
|
48
|
+
// Check time validity
|
|
49
|
+
if (cp.validFrom && cp.validFrom > now)
|
|
50
|
+
continue;
|
|
51
|
+
if (cp.validUntil && cp.validUntil < now)
|
|
52
|
+
continue;
|
|
53
|
+
return cp.priceCents;
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|