@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.
Files changed (122) hide show
  1. package/README.md +479 -0
  2. package/dist/analytics-models.d.ts +13 -0
  3. package/dist/analytics-models.d.ts.map +1 -0
  4. package/dist/analytics-models.js +69 -0
  5. package/dist/hooks.d.ts +4 -0
  6. package/dist/hooks.d.ts.map +1 -0
  7. package/dist/hooks.js +187 -0
  8. package/dist/index.d.ts +4 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +105 -0
  11. package/dist/mcp-tools.d.ts +21 -0
  12. package/dist/mcp-tools.d.ts.map +1 -0
  13. package/dist/mcp-tools.js +183 -0
  14. package/dist/routes/b2b.d.ts +9 -0
  15. package/dist/routes/b2b.d.ts.map +1 -0
  16. package/dist/routes/b2b.js +156 -0
  17. package/dist/routes/commission.d.ts +6 -0
  18. package/dist/routes/commission.d.ts.map +1 -0
  19. package/dist/routes/commission.js +85 -0
  20. package/dist/routes/disputes-returns-reviews.d.ts +10 -0
  21. package/dist/routes/disputes-returns-reviews.d.ts.map +1 -0
  22. package/dist/routes/disputes-returns-reviews.js +179 -0
  23. package/dist/routes/payouts.d.ts +6 -0
  24. package/dist/routes/payouts.d.ts.map +1 -0
  25. package/dist/routes/payouts.js +40 -0
  26. package/dist/routes/sub-orders.d.ts +6 -0
  27. package/dist/routes/sub-orders.d.ts.map +1 -0
  28. package/dist/routes/sub-orders.js +44 -0
  29. package/dist/routes/util.d.ts +23 -0
  30. package/dist/routes/util.d.ts.map +1 -0
  31. package/dist/routes/util.js +41 -0
  32. package/dist/routes/vendor-portal.d.ts +14 -0
  33. package/dist/routes/vendor-portal.d.ts.map +1 -0
  34. package/dist/routes/vendor-portal.js +255 -0
  35. package/dist/routes/vendors.d.ts +11 -0
  36. package/dist/routes/vendors.d.ts.map +1 -0
  37. package/dist/routes/vendors.js +185 -0
  38. package/dist/schema.d.ts +3255 -0
  39. package/dist/schema.d.ts.map +1 -0
  40. package/dist/schema.js +225 -0
  41. package/dist/schemas/b2b.d.ts +1009 -0
  42. package/dist/schemas/b2b.d.ts.map +1 -0
  43. package/dist/schemas/b2b.js +208 -0
  44. package/dist/schemas/commission.d.ts +532 -0
  45. package/dist/schemas/commission.d.ts.map +1 -0
  46. package/dist/schemas/commission.js +113 -0
  47. package/dist/schemas/disputes-returns-reviews.d.ts +1405 -0
  48. package/dist/schemas/disputes-returns-reviews.d.ts.map +1 -0
  49. package/dist/schemas/disputes-returns-reviews.js +270 -0
  50. package/dist/schemas/payouts.d.ts +375 -0
  51. package/dist/schemas/payouts.d.ts.map +1 -0
  52. package/dist/schemas/payouts.js +78 -0
  53. package/dist/schemas/sub-orders.d.ts +303 -0
  54. package/dist/schemas/sub-orders.d.ts.map +1 -0
  55. package/dist/schemas/sub-orders.js +67 -0
  56. package/dist/schemas/vendor-portal.d.ts +1785 -0
  57. package/dist/schemas/vendor-portal.d.ts.map +1 -0
  58. package/dist/schemas/vendor-portal.js +294 -0
  59. package/dist/schemas/vendors.d.ts +1348 -0
  60. package/dist/schemas/vendors.d.ts.map +1 -0
  61. package/dist/schemas/vendors.js +245 -0
  62. package/dist/services/commission.d.ts +81 -0
  63. package/dist/services/commission.d.ts.map +1 -0
  64. package/dist/services/commission.js +98 -0
  65. package/dist/services/contract-price.d.ts +64 -0
  66. package/dist/services/contract-price.d.ts.map +1 -0
  67. package/dist/services/contract-price.js +57 -0
  68. package/dist/services/dispute.d.ts +156 -0
  69. package/dist/services/dispute.d.ts.map +1 -0
  70. package/dist/services/dispute.js +77 -0
  71. package/dist/services/payout.d.ts +126 -0
  72. package/dist/services/payout.d.ts.map +1 -0
  73. package/dist/services/payout.js +130 -0
  74. package/dist/services/return.d.ts +181 -0
  75. package/dist/services/return.d.ts.map +1 -0
  76. package/dist/services/return.js +80 -0
  77. package/dist/services/review.d.ts +70 -0
  78. package/dist/services/review.d.ts.map +1 -0
  79. package/dist/services/review.js +60 -0
  80. package/dist/services/rfq.d.ts +122 -0
  81. package/dist/services/rfq.d.ts.map +1 -0
  82. package/dist/services/rfq.js +60 -0
  83. package/dist/services/sub-order.d.ts +336 -0
  84. package/dist/services/sub-order.d.ts.map +1 -0
  85. package/dist/services/sub-order.js +121 -0
  86. package/dist/services/vendor.d.ts +528 -0
  87. package/dist/services/vendor.d.ts.map +1 -0
  88. package/dist/services/vendor.js +119 -0
  89. package/dist/types.d.ts +67 -0
  90. package/dist/types.d.ts.map +1 -0
  91. package/dist/types.js +13 -0
  92. package/package.json +43 -0
  93. package/src/analytics-models.ts +75 -0
  94. package/src/hooks.ts +215 -0
  95. package/src/index.ts +124 -0
  96. package/src/mcp-tools.ts +210 -0
  97. package/src/routes/b2b.ts +179 -0
  98. package/src/routes/commission.ts +95 -0
  99. package/src/routes/disputes-returns-reviews.ts +209 -0
  100. package/src/routes/payouts.ts +49 -0
  101. package/src/routes/sub-orders.ts +54 -0
  102. package/src/routes/util.ts +42 -0
  103. package/src/routes/vendor-portal.ts +277 -0
  104. package/src/routes/vendors.ts +201 -0
  105. package/src/schema.ts +260 -0
  106. package/src/schemas/b2b.ts +238 -0
  107. package/src/schemas/commission.ts +129 -0
  108. package/src/schemas/disputes-returns-reviews.ts +311 -0
  109. package/src/schemas/payouts.ts +90 -0
  110. package/src/schemas/sub-orders.ts +77 -0
  111. package/src/schemas/vendor-portal.ts +344 -0
  112. package/src/schemas/vendors.ts +281 -0
  113. package/src/services/commission.ts +120 -0
  114. package/src/services/contract-price.ts +80 -0
  115. package/src/services/dispute.ts +92 -0
  116. package/src/services/payout.ts +154 -0
  117. package/src/services/return.ts +92 -0
  118. package/src/services/review.ts +76 -0
  119. package/src/services/rfq.ts +82 -0
  120. package/src/services/sub-order.ts +136 -0
  121. package/src/services/vendor.ts +151 -0
  122. 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
+ }