@porulle/core 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +26 -7
- package/dist/auth/setup.d.ts.map +1 -1
- package/dist/auth/setup.js +8 -5
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +7 -0
- package/dist/config/types.d.ts +26 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/generated/plugin-manifest.d.ts +3 -0
- package/dist/generated/plugin-manifest.d.ts.map +1 -1
- package/dist/generated/plugin-manifest.js +1 -0
- package/dist/hooks/checkout-completion.d.ts.map +1 -1
- package/dist/hooks/checkout-completion.js +2 -2
- package/dist/hooks/checkout.d.ts.map +1 -1
- package/dist/hooks/checkout.js +17 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/interfaces/rest/index.d.ts.map +1 -1
- package/dist/interfaces/rest/index.js +12 -0
- package/dist/interfaces/rest/routes/admin/staff.d.ts +12 -0
- package/dist/interfaces/rest/routes/admin/staff.d.ts.map +1 -0
- package/dist/interfaces/rest/routes/admin/staff.js +206 -0
- package/dist/interfaces/rest/routes/analytics.d.ts +5 -0
- package/dist/interfaces/rest/routes/analytics.d.ts.map +1 -0
- package/dist/interfaces/rest/routes/analytics.js +24 -0
- package/dist/interfaces/rest/routes/carts.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/carts.js +39 -2
- package/dist/interfaces/rest/routes/catalog.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/catalog.js +17 -1
- package/dist/interfaces/rest/routes/checkout.d.ts +9 -0
- package/dist/interfaces/rest/routes/checkout.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/checkout.js +97 -21
- package/dist/interfaces/rest/routes/documents.d.ts +10 -0
- package/dist/interfaces/rest/routes/documents.d.ts.map +1 -0
- package/dist/interfaces/rest/routes/documents.js +40 -0
- package/dist/interfaces/rest/routes/inventory.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/inventory.js +13 -0
- package/dist/interfaces/rest/routes/orders.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/orders.js +111 -1
- package/dist/interfaces/rest/routes/pricing.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/pricing.js +36 -1
- package/dist/interfaces/rest/routes/settings.d.ts +5 -0
- package/dist/interfaces/rest/routes/settings.d.ts.map +1 -0
- package/dist/interfaces/rest/routes/settings.js +50 -0
- package/dist/interfaces/rest/routes/shipping.d.ts +5 -0
- package/dist/interfaces/rest/routes/shipping.d.ts.map +1 -0
- package/dist/interfaces/rest/routes/shipping.js +68 -0
- package/dist/interfaces/rest/routes/tax.d.ts +5 -0
- package/dist/interfaces/rest/routes/tax.d.ts.map +1 -0
- package/dist/interfaces/rest/routes/tax.js +68 -0
- package/dist/interfaces/rest/schemas/admin-staff.d.ts +899 -0
- package/dist/interfaces/rest/schemas/admin-staff.d.ts.map +1 -0
- package/dist/interfaces/rest/schemas/admin-staff.js +98 -0
- package/dist/interfaces/rest/schemas/analytics.d.ts +252 -0
- package/dist/interfaces/rest/schemas/analytics.d.ts.map +1 -0
- package/dist/interfaces/rest/schemas/analytics.js +33 -0
- package/dist/interfaces/rest/schemas/carts.d.ts +656 -0
- package/dist/interfaces/rest/schemas/carts.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/carts.js +38 -0
- package/dist/interfaces/rest/schemas/catalog.d.ts +1218 -1
- package/dist/interfaces/rest/schemas/catalog.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/catalog.js +48 -0
- package/dist/interfaces/rest/schemas/checkout.d.ts +2 -0
- package/dist/interfaces/rest/schemas/checkout.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/checkout.js +4 -0
- package/dist/interfaces/rest/schemas/customer-portal.d.ts +35 -0
- package/dist/interfaces/rest/schemas/customer-portal.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/documents.d.ts +509 -0
- package/dist/interfaces/rest/schemas/documents.d.ts.map +1 -0
- package/dist/interfaces/rest/schemas/documents.js +65 -0
- package/dist/interfaces/rest/schemas/orders.d.ts +3110 -43
- package/dist/interfaces/rest/schemas/orders.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/orders.js +234 -1
- package/dist/interfaces/rest/schemas/pricing.d.ts +405 -0
- package/dist/interfaces/rest/schemas/pricing.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/pricing.js +70 -0
- package/dist/interfaces/rest/schemas/responses.d.ts +190 -0
- package/dist/interfaces/rest/schemas/responses.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/search.d.ts +17 -0
- package/dist/interfaces/rest/schemas/search.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/settings.d.ts +397 -0
- package/dist/interfaces/rest/schemas/settings.d.ts.map +1 -0
- package/dist/interfaces/rest/schemas/settings.js +79 -0
- package/dist/interfaces/rest/schemas/shipping.d.ts +1093 -0
- package/dist/interfaces/rest/schemas/shipping.d.ts.map +1 -0
- package/dist/interfaces/rest/schemas/shipping.js +146 -0
- package/dist/interfaces/rest/schemas/tax.d.ts +1074 -0
- package/dist/interfaces/rest/schemas/tax.d.ts.map +1 -0
- package/dist/interfaces/rest/schemas/tax.js +132 -0
- package/dist/kernel/database/schema.d.ts +4 -0
- package/dist/kernel/database/schema.d.ts.map +1 -1
- package/dist/kernel/database/schema.js +8 -0
- package/dist/kernel/database/scoped-db.d.ts +2 -1
- package/dist/kernel/database/scoped-db.d.ts.map +1 -1
- package/dist/kernel/database/scoped-db.js +62 -1
- package/dist/kernel/hooks/types.d.ts +1 -1
- package/dist/kernel/hooks/types.d.ts.map +1 -1
- package/dist/kernel/plugin/manifest.d.ts +26 -0
- package/dist/kernel/plugin/manifest.d.ts.map +1 -1
- package/dist/kernel/plugin/manifest.js +17 -2
- package/dist/modules/analytics/drizzle-adapter.d.ts.map +1 -1
- package/dist/modules/analytics/drizzle-adapter.js +16 -3
- package/dist/modules/analytics/module.d.ts.map +1 -1
- package/dist/modules/analytics/module.js +6 -0
- package/dist/modules/analytics/reports.d.ts +58 -0
- package/dist/modules/analytics/reports.d.ts.map +1 -0
- package/dist/modules/analytics/reports.js +249 -0
- package/dist/modules/analytics/service.d.ts +10 -0
- package/dist/modules/analytics/service.d.ts.map +1 -1
- package/dist/modules/analytics/service.js +14 -0
- package/dist/modules/cart/repository/index.d.ts +7 -0
- package/dist/modules/cart/repository/index.d.ts.map +1 -1
- package/dist/modules/cart/repository/index.js +25 -1
- package/dist/modules/cart/schema.d.ts +17 -0
- package/dist/modules/cart/schema.d.ts.map +1 -1
- package/dist/modules/cart/schema.js +2 -0
- package/dist/modules/cart/schemas.d.ts +1 -0
- package/dist/modules/cart/schemas.d.ts.map +1 -1
- package/dist/modules/cart/schemas.js +1 -0
- package/dist/modules/cart/service.d.ts +32 -0
- package/dist/modules/cart/service.d.ts.map +1 -1
- package/dist/modules/cart/service.js +61 -2
- package/dist/modules/catalog/entity-service.d.ts +21 -0
- package/dist/modules/catalog/entity-service.d.ts.map +1 -1
- package/dist/modules/catalog/entity-service.js +166 -5
- package/dist/modules/catalog/schema.d.ts +34 -0
- package/dist/modules/catalog/schema.d.ts.map +1 -1
- package/dist/modules/catalog/schema.js +5 -0
- package/dist/modules/catalog/schemas.d.ts +3 -0
- package/dist/modules/catalog/schemas.d.ts.map +1 -1
- package/dist/modules/catalog/schemas.js +3 -0
- package/dist/modules/catalog/service.d.ts +36 -0
- package/dist/modules/catalog/service.d.ts.map +1 -1
- package/dist/modules/catalog/service.js +6 -0
- package/dist/modules/customers/service.d.ts.map +1 -1
- package/dist/modules/customers/service.js +6 -0
- package/dist/modules/documents/module.d.ts +7 -0
- package/dist/modules/documents/module.d.ts.map +1 -0
- package/dist/modules/documents/module.js +12 -0
- package/dist/modules/documents/pdf.d.ts +25 -0
- package/dist/modules/documents/pdf.d.ts.map +1 -0
- package/dist/modules/documents/pdf.js +80 -0
- package/dist/modules/documents/render.d.ts +32 -0
- package/dist/modules/documents/render.d.ts.map +1 -0
- package/dist/modules/documents/render.js +190 -0
- package/dist/modules/documents/repository/index.d.ts +25 -0
- package/dist/modules/documents/repository/index.d.ts.map +1 -0
- package/dist/modules/documents/repository/index.js +47 -0
- package/dist/modules/documents/schema.d.ts +214 -0
- package/dist/modules/documents/schema.d.ts.map +1 -0
- package/dist/modules/documents/schema.js +42 -0
- package/dist/modules/documents/service.d.ts +51 -0
- package/dist/modules/documents/service.d.ts.map +1 -0
- package/dist/modules/documents/service.js +119 -0
- package/dist/modules/fulfillment/service.d.ts +18 -0
- package/dist/modules/fulfillment/service.d.ts.map +1 -1
- package/dist/modules/fulfillment/service.js +85 -1
- package/dist/modules/orders/repository/index.d.ts +18 -1
- package/dist/modules/orders/repository/index.d.ts.map +1 -1
- package/dist/modules/orders/repository/index.js +86 -1
- package/dist/modules/orders/schema.d.ts +391 -0
- package/dist/modules/orders/schema.d.ts.map +1 -1
- package/dist/modules/orders/schema.js +56 -1
- package/dist/modules/orders/service.d.ts +102 -3
- package/dist/modules/orders/service.d.ts.map +1 -1
- package/dist/modules/orders/service.js +653 -29
- package/dist/modules/orders/stale-order-cleanup.d.ts.map +1 -1
- package/dist/modules/orders/stale-order-cleanup.js +13 -1
- package/dist/modules/pricing/repository/index.d.ts +5 -0
- package/dist/modules/pricing/repository/index.d.ts.map +1 -1
- package/dist/modules/pricing/repository/index.js +19 -0
- package/dist/modules/pricing/service.d.ts +18 -0
- package/dist/modules/pricing/service.d.ts.map +1 -1
- package/dist/modules/pricing/service.js +43 -5
- package/dist/modules/settings/module.d.ts +6 -0
- package/dist/modules/settings/module.d.ts.map +1 -0
- package/dist/modules/settings/module.js +11 -0
- package/dist/modules/settings/repository/index.d.ts +16 -0
- package/dist/modules/settings/repository/index.d.ts.map +1 -0
- package/dist/modules/settings/repository/index.js +41 -0
- package/dist/modules/settings/schema.d.ts +121 -0
- package/dist/modules/settings/schema.d.ts.map +1 -0
- package/dist/modules/settings/schema.js +24 -0
- package/dist/modules/settings/service.d.ts +26 -0
- package/dist/modules/settings/service.d.ts.map +1 -0
- package/dist/modules/settings/service.js +51 -0
- package/dist/modules/shipping/calculator.d.ts +5 -0
- package/dist/modules/shipping/calculator.d.ts.map +1 -1
- package/dist/modules/shipping/calculator.js +10 -0
- package/dist/modules/shipping/module.d.ts +5 -1
- package/dist/modules/shipping/module.d.ts.map +1 -1
- package/dist/modules/shipping/module.js +4 -1
- package/dist/modules/shipping/repository/index.d.ts +27 -2
- package/dist/modules/shipping/repository/index.d.ts.map +1 -1
- package/dist/modules/shipping/repository/index.js +105 -1
- package/dist/modules/shipping/schema.d.ts +419 -0
- package/dist/modules/shipping/schema.d.ts.map +1 -0
- package/dist/modules/shipping/schema.js +56 -0
- package/dist/modules/shipping/service.d.ts +54 -0
- package/dist/modules/shipping/service.d.ts.map +1 -1
- package/dist/modules/shipping/service.js +161 -2
- package/dist/modules/tax/adapter.d.ts +13 -0
- package/dist/modules/tax/adapter.d.ts.map +1 -1
- package/dist/modules/tax/module.d.ts +5 -1
- package/dist/modules/tax/module.d.ts.map +1 -1
- package/dist/modules/tax/module.js +4 -1
- package/dist/modules/tax/repository/index.d.ts +38 -2
- package/dist/modules/tax/repository/index.d.ts.map +1 -1
- package/dist/modules/tax/repository/index.js +138 -1
- package/dist/modules/tax/schema.d.ts +355 -0
- package/dist/modules/tax/schema.d.ts.map +1 -0
- package/dist/modules/tax/schema.js +55 -0
- package/dist/modules/tax/service.d.ts +60 -1
- package/dist/modules/tax/service.d.ts.map +1 -1
- package/dist/modules/tax/service.js +227 -2
- package/dist/runtime/kernel-modules.d.ts +15 -2
- package/dist/runtime/kernel-modules.d.ts.map +1 -1
- package/dist/runtime/kernel-modules.js +4 -0
- package/dist/runtime/kernel-types.d.ts +5 -1
- package/dist/runtime/kernel-types.d.ts.map +1 -1
- package/dist/runtime/kernel-types.js +2 -0
- package/dist/runtime/server.js +1 -1
- package/dist/test-utils/create-plugin-test-app.d.ts +3 -0
- package/dist/test-utils/create-plugin-test-app.d.ts.map +1 -1
- package/dist/test-utils/create-plugin-test-app.js +15 -3
- package/dist/test-utils/create-test-config.d.ts.map +1 -1
- package/dist/test-utils/create-test-config.js +2 -0
- package/dist/test-utils/order-test-helpers.d.ts +12 -0
- package/dist/test-utils/order-test-helpers.d.ts.map +1 -0
- package/dist/test-utils/order-test-helpers.js +18 -0
- package/dist/test-utils/rest-api-test-utils.d.ts.map +1 -1
- package/dist/test-utils/rest-api-test-utils.js +7 -0
- package/dist/test-utils/test-actors.js +1 -1
- package/dist/testing.d.ts +1 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +1 -0
- package/package.json +3 -3
- package/src/auth/middleware.ts +26 -7
- package/src/auth/setup.ts +11 -4
- package/src/config/defaults.ts +7 -0
- package/src/config/types.ts +26 -1
- package/src/generated/plugin-capabilities.d.ts +1 -0
- package/src/generated/plugin-manifest.ts +1 -0
- package/src/generated/plugin-repositories.d.ts +1 -0
- package/src/hooks/checkout-completion.ts +22 -16
- package/src/hooks/checkout.ts +36 -11
- package/src/index.ts +1 -0
- package/src/interfaces/rest/index.ts +12 -0
- package/src/interfaces/rest/routes/admin/staff.ts +260 -0
- package/src/interfaces/rest/routes/analytics.ts +33 -0
- package/src/interfaces/rest/routes/carts.ts +52 -2
- package/src/interfaces/rest/routes/catalog.ts +34 -0
- package/src/interfaces/rest/routes/checkout.ts +114 -27
- package/src/interfaces/rest/routes/documents.ts +61 -0
- package/src/interfaces/rest/routes/inventory.ts +14 -0
- package/src/interfaces/rest/routes/orders.ts +148 -1
- package/src/interfaces/rest/routes/pricing.ts +44 -1
- package/src/interfaces/rest/routes/settings.ts +61 -0
- package/src/interfaces/rest/routes/shipping.ts +92 -0
- package/src/interfaces/rest/routes/tax.ts +90 -0
- package/src/interfaces/rest/schemas/admin-staff.ts +110 -0
- package/src/interfaces/rest/schemas/analytics.ts +39 -0
- package/src/interfaces/rest/schemas/carts.ts +40 -0
- package/src/interfaces/rest/schemas/catalog.ts +53 -0
- package/src/interfaces/rest/schemas/checkout.ts +4 -0
- package/src/interfaces/rest/schemas/documents.ts +72 -0
- package/src/interfaces/rest/schemas/orders.ts +258 -1
- package/src/interfaces/rest/schemas/pricing.ts +75 -0
- package/src/interfaces/rest/schemas/settings.ts +93 -0
- package/src/interfaces/rest/schemas/shipping.ts +164 -0
- package/src/interfaces/rest/schemas/tax.ts +148 -0
- package/src/kernel/database/schema.ts +12 -0
- package/src/kernel/database/scoped-db.ts +70 -1
- package/src/kernel/hooks/types.ts +1 -0
- package/src/kernel/plugin/manifest.ts +41 -2
- package/src/modules/analytics/drizzle-adapter.ts +19 -3
- package/src/modules/analytics/module.ts +10 -0
- package/src/modules/analytics/reports.ts +311 -0
- package/src/modules/analytics/service.ts +23 -0
- package/src/modules/cart/repository/index.ts +30 -1
- package/src/modules/cart/schema.ts +2 -0
- package/src/modules/cart/schemas.ts +1 -0
- package/src/modules/cart/service.ts +104 -2
- package/src/modules/catalog/entity-service.ts +196 -4
- package/src/modules/catalog/schema.ts +5 -0
- package/src/modules/catalog/schemas.ts +3 -0
- package/src/modules/catalog/service.ts +30 -0
- package/src/modules/customers/service.ts +6 -0
- package/src/modules/documents/module.ts +19 -0
- package/src/modules/documents/pdf.ts +101 -0
- package/src/modules/documents/render.ts +231 -0
- package/src/modules/documents/repository/index.ts +68 -0
- package/src/modules/documents/schema.ts +44 -0
- package/src/modules/documents/service.ts +176 -0
- package/src/modules/fulfillment/service.ts +139 -1
- package/src/modules/orders/repository/index.ts +127 -1
- package/src/modules/orders/schema.ts +58 -1
- package/src/modules/orders/service.ts +1041 -65
- package/src/modules/orders/stale-order-cleanup.ts +18 -4
- package/src/modules/pricing/repository/index.ts +34 -0
- package/src/modules/pricing/service.ts +76 -6
- package/src/modules/settings/module.ts +18 -0
- package/src/modules/settings/repository/index.ts +59 -0
- package/src/modules/settings/schema.ts +25 -0
- package/src/modules/settings/service.ts +82 -0
- package/src/modules/shipping/calculator.ts +27 -0
- package/src/modules/shipping/module.ts +6 -2
- package/src/modules/shipping/repository/index.ts +136 -2
- package/src/modules/shipping/schema.ts +58 -0
- package/src/modules/shipping/service.ts +260 -1
- package/src/modules/tax/adapter.ts +9 -0
- package/src/modules/tax/module.ts +6 -2
- package/src/modules/tax/repository/index.ts +169 -2
- package/src/modules/tax/schema.ts +57 -0
- package/src/modules/tax/service.ts +313 -2
- package/src/runtime/kernel-modules.ts +4 -0
- package/src/runtime/kernel-types.ts +6 -0
- package/src/runtime/server.ts +1 -1
- package/src/test-utils/create-plugin-test-app.ts +17 -4
- package/src/test-utils/create-test-config.ts +2 -0
- package/src/test-utils/order-test-helpers.ts +26 -0
- package/src/test-utils/rest-api-test-utils.ts +7 -0
- package/src/test-utils/test-actors.ts +1 -1
- package/src/testing.ts +1 -0
|
@@ -39,6 +39,10 @@ const CreateOrderLineItemSchema = z.object({
|
|
|
39
39
|
|
|
40
40
|
export const CreateOrderBodySchema = z.object({
|
|
41
41
|
customerId: z.uuid().optional(),
|
|
42
|
+
idempotencyKey: z.string().min(8).max(255).optional().openapi({
|
|
43
|
+
example: "pos-sale-8f14e45f-1738312200",
|
|
44
|
+
description: "Client-supplied retry key. Re-submitting a create with the same key returns the original order instead of creating a duplicate (safe offline-queue replay).",
|
|
45
|
+
}),
|
|
42
46
|
currency: z.string().min(3).max(3).openapi({ example: "USD" }),
|
|
43
47
|
subtotal: z.number().int().nonnegative().openapi({ example: 2500 }),
|
|
44
48
|
taxTotal: z.number().int().nonnegative().openapi({ example: 200 }),
|
|
@@ -140,12 +144,47 @@ export const getOrderFulfillmentsRoute = createRoute({
|
|
|
140
144
|
},
|
|
141
145
|
});
|
|
142
146
|
|
|
147
|
+
export const CreateFulfillmentBodySchema = z.object({
|
|
148
|
+
lineItems: z.array(z.object({
|
|
149
|
+
orderLineItemId: z.uuid().openapi({ example: "550e8400-e29b-41d4-a716-446655440000" }),
|
|
150
|
+
quantity: z.number().int().positive().openapi({ example: 2 }),
|
|
151
|
+
})).min(1),
|
|
152
|
+
carrier: z.string().optional().openapi({ example: "DHL" }),
|
|
153
|
+
trackingNumber: z.string().optional().openapi({ example: "DHL-123456" }),
|
|
154
|
+
trackingUrl: z.string().optional().openapi({ example: "https://track.dhl.com/DHL-123456" }),
|
|
155
|
+
type: z.string().optional().openapi({ example: "physical" }),
|
|
156
|
+
status: z.string().optional().openapi({ example: "shipped" }),
|
|
157
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
158
|
+
}).openapi("CreateFulfillmentRequest");
|
|
159
|
+
|
|
160
|
+
export const createOrderFulfillmentRoute = createRoute({
|
|
161
|
+
method: "post",
|
|
162
|
+
path: "/{id}/fulfillments",
|
|
163
|
+
tags: ["Orders"],
|
|
164
|
+
summary: "Record a fulfillment (shipment) for an order",
|
|
165
|
+
description: "Creates a fulfillment for a subset of the order's line items with optional carrier/tracking details. Supports partial fulfillment (per-line quantities) and multiple fulfillments per order.",
|
|
166
|
+
request: {
|
|
167
|
+
params: OrderIdParam,
|
|
168
|
+
body: {
|
|
169
|
+
content: { "application/json": { schema: CreateFulfillmentBodySchema } },
|
|
170
|
+
required: true,
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
responses: {
|
|
174
|
+
201: {
|
|
175
|
+
content: { "application/json": { schema: OrderDataResponseSchema } },
|
|
176
|
+
description: "Fulfillment recorded.",
|
|
177
|
+
},
|
|
178
|
+
...errorResponses,
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
|
|
143
182
|
export const createOrderRoute = createRoute({
|
|
144
183
|
method: "post",
|
|
145
184
|
path: "/",
|
|
146
185
|
tags: ["Orders"],
|
|
147
186
|
summary: "Create a draft / manual order",
|
|
148
|
-
description: "
|
|
187
|
+
description: "Requires `orders:manage`. Creates an operator-entered order (phone / POS / manual); supplied line prices are stored as audited manual overrides.",
|
|
149
188
|
request: {
|
|
150
189
|
body: {
|
|
151
190
|
content: { "application/json": { schema: CreateOrderBodySchema } },
|
|
@@ -205,6 +244,91 @@ export const captureOrderRoute = createRoute({
|
|
|
205
244
|
},
|
|
206
245
|
});
|
|
207
246
|
|
|
247
|
+
export const AddOrderLineItemBodySchema = z.object({
|
|
248
|
+
entityId: z.uuid().openapi({ example: "550e8400-e29b-41d4-a716-446655440000" }),
|
|
249
|
+
entityType: z.string().min(1).openapi({ example: "product" }),
|
|
250
|
+
variantId: z.uuid().optional(),
|
|
251
|
+
sku: z.string().optional(),
|
|
252
|
+
title: z.string().min(1).openapi({ example: "Ceylon Black Tea 250g" }),
|
|
253
|
+
quantity: z.number().int().positive().openapi({ example: 1 }),
|
|
254
|
+
unitPrice: z.number().int().nonnegative().openapi({ example: 1250 }),
|
|
255
|
+
totalPrice: z.number().int().nonnegative().optional().openapi({ example: 1250 }),
|
|
256
|
+
taxAmount: z.number().int().nonnegative().optional(),
|
|
257
|
+
discountAmount: z.number().int().nonnegative().optional(),
|
|
258
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
259
|
+
}).openapi("AddOrderLineItemRequest");
|
|
260
|
+
|
|
261
|
+
export const UpdateOrderLineItemBodySchema = z.object({
|
|
262
|
+
quantity: z.number().int().positive().openapi({ example: 3 }),
|
|
263
|
+
}).openapi("UpdateOrderLineItemRequest");
|
|
264
|
+
|
|
265
|
+
const OrderLineItemParams = z.object({
|
|
266
|
+
id: z.uuid().openapi({ example: "550e8400-e29b-41d4-a716-446655440000" }),
|
|
267
|
+
lineItemId: z.uuid().openapi({ example: "660e8400-e29b-41d4-a716-446655440001" }),
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
export const addOrderLineItemRoute = createRoute({
|
|
271
|
+
method: "post",
|
|
272
|
+
path: "/{id}/line-items",
|
|
273
|
+
tags: ["Orders"],
|
|
274
|
+
summary: "Add a line item to a placed order",
|
|
275
|
+
description: "Requires `orders:manage`. Adds a line item to a non-terminal order, records its supplied price as a manual override, and recalculates totals.",
|
|
276
|
+
request: {
|
|
277
|
+
params: OrderIdParam,
|
|
278
|
+
body: {
|
|
279
|
+
content: { "application/json": { schema: AddOrderLineItemBodySchema } },
|
|
280
|
+
required: true,
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
responses: {
|
|
284
|
+
201: {
|
|
285
|
+
content: { "application/json": { schema: OrderDataResponseSchema } },
|
|
286
|
+
description: "Line item added; updated order returned.",
|
|
287
|
+
},
|
|
288
|
+
...errorResponses,
|
|
289
|
+
},
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
export const updateOrderLineItemRoute = createRoute({
|
|
293
|
+
method: "patch",
|
|
294
|
+
path: "/{id}/line-items/{lineItemId}",
|
|
295
|
+
tags: ["Orders"],
|
|
296
|
+
summary: "Adjust a line item's quantity on a placed order",
|
|
297
|
+
description: "Changes a line item's quantity on a non-terminal order, scaling line totals/tax and recalculating order totals. Records an audit entry.",
|
|
298
|
+
request: {
|
|
299
|
+
params: OrderLineItemParams,
|
|
300
|
+
body: {
|
|
301
|
+
content: { "application/json": { schema: UpdateOrderLineItemBodySchema } },
|
|
302
|
+
required: true,
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
responses: {
|
|
306
|
+
200: {
|
|
307
|
+
content: { "application/json": { schema: OrderDataResponseSchema } },
|
|
308
|
+
description: "Line item updated; updated order returned.",
|
|
309
|
+
},
|
|
310
|
+
...errorResponses,
|
|
311
|
+
},
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
export const removeOrderLineItemRoute = createRoute({
|
|
315
|
+
method: "delete",
|
|
316
|
+
path: "/{id}/line-items/{lineItemId}",
|
|
317
|
+
tags: ["Orders"],
|
|
318
|
+
summary: "Remove a line item from a placed order",
|
|
319
|
+
description: "Removes a line item from a non-terminal order (at least one line item must remain) and recalculates order totals. Records an audit entry.",
|
|
320
|
+
request: {
|
|
321
|
+
params: OrderLineItemParams,
|
|
322
|
+
},
|
|
323
|
+
responses: {
|
|
324
|
+
200: {
|
|
325
|
+
content: { "application/json": { schema: OrderDataResponseSchema } },
|
|
326
|
+
description: "Line item removed; updated order returned.",
|
|
327
|
+
},
|
|
328
|
+
...errorResponses,
|
|
329
|
+
},
|
|
330
|
+
});
|
|
331
|
+
|
|
208
332
|
export const changeOrderStatusRoute = createRoute({
|
|
209
333
|
method: "patch",
|
|
210
334
|
path: "/{id}/status",
|
|
@@ -227,3 +351,136 @@ export const changeOrderStatusRoute = createRoute({
|
|
|
227
351
|
...errorResponses,
|
|
228
352
|
},
|
|
229
353
|
});
|
|
354
|
+
|
|
355
|
+
// ── Line-level refund policy primitives (issue #52) ─────────────────────────
|
|
356
|
+
|
|
357
|
+
export const RefundLinesBodySchema = z.object({
|
|
358
|
+
lines: z.array(z.object({
|
|
359
|
+
lineItemId: z.uuid(),
|
|
360
|
+
quantity: z.number().int().min(1),
|
|
361
|
+
})).min(1),
|
|
362
|
+
reason: z.string().max(500).optional(),
|
|
363
|
+
}).openapi("RefundLinesRequest");
|
|
364
|
+
|
|
365
|
+
const RefundParam = z.object({
|
|
366
|
+
id: z.uuid(),
|
|
367
|
+
refundId: z.uuid(),
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
const RefundDataResponse = z.object({ data: z.any() }).openapi("RefundResponse");
|
|
371
|
+
|
|
372
|
+
export const refundOrderLinesRoute = createRoute({
|
|
373
|
+
method: "post",
|
|
374
|
+
path: "/{id}/refunds",
|
|
375
|
+
tags: ["Orders"],
|
|
376
|
+
summary: "Refund specific line-item quantities",
|
|
377
|
+
description: "Enforces per-line refundable quantity and the operator's daily refund cap (policies.refundDailyCap). Records an auditable refund ledger row supporting undo.",
|
|
378
|
+
request: {
|
|
379
|
+
params: OrderIdParam,
|
|
380
|
+
body: { content: { "application/json": { schema: RefundLinesBodySchema } }, required: true },
|
|
381
|
+
},
|
|
382
|
+
responses: {
|
|
383
|
+
201: { content: { "application/json": { schema: RefundDataResponse } }, description: "Refund recorded." },
|
|
384
|
+
...errorResponses,
|
|
385
|
+
},
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
export const undoOrderRefundRoute = createRoute({
|
|
389
|
+
method: "post",
|
|
390
|
+
path: "/{id}/refunds/{refundId}/undo",
|
|
391
|
+
tags: ["Orders"],
|
|
392
|
+
summary: "Undo a refund within the policy window",
|
|
393
|
+
request: { params: RefundParam },
|
|
394
|
+
responses: {
|
|
395
|
+
200: { content: { "application/json": { schema: RefundDataResponse } }, description: "Refund undone." },
|
|
396
|
+
...errorResponses,
|
|
397
|
+
},
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
export const listOrderRefundsRoute = createRoute({
|
|
401
|
+
method: "get",
|
|
402
|
+
path: "/{id}/refunds",
|
|
403
|
+
tags: ["Orders"],
|
|
404
|
+
summary: "List an order's refunds",
|
|
405
|
+
request: { params: OrderIdParam },
|
|
406
|
+
responses: {
|
|
407
|
+
200: { content: { "application/json": { schema: RefundDataResponse } }, description: "Refund ledger rows." },
|
|
408
|
+
...errorResponses,
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
export const refundCapStatusRoute = createRoute({
|
|
413
|
+
method: "get",
|
|
414
|
+
path: "/refunds/cap",
|
|
415
|
+
tags: ["Orders"],
|
|
416
|
+
summary: "The acting operator's daily refund-cap status",
|
|
417
|
+
responses: {
|
|
418
|
+
200: { content: { "application/json": { schema: RefundDataResponse } }, description: "Cap, used-today, and remaining." },
|
|
419
|
+
...errorResponses,
|
|
420
|
+
},
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
// ── Order notes + activity timeline (issue #56) ─────────────────────────────
|
|
424
|
+
|
|
425
|
+
export const CreateOrderNoteBodySchema = z.object({
|
|
426
|
+
body: z.string().min(1).max(2000),
|
|
427
|
+
pinned: z.boolean().optional(),
|
|
428
|
+
}).openapi("CreateOrderNoteRequest");
|
|
429
|
+
|
|
430
|
+
const NoteParam = z.object({
|
|
431
|
+
id: z.uuid(),
|
|
432
|
+
noteId: z.uuid(),
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
const NoteDataResponse = z.object({ data: z.any() }).openapi("OrderNoteResponse");
|
|
436
|
+
|
|
437
|
+
export const createOrderNoteRoute = createRoute({
|
|
438
|
+
method: "post",
|
|
439
|
+
path: "/{id}/notes",
|
|
440
|
+
tags: ["Orders"],
|
|
441
|
+
summary: "Add an operator note to an order",
|
|
442
|
+
request: {
|
|
443
|
+
params: OrderIdParam,
|
|
444
|
+
body: { content: { "application/json": { schema: CreateOrderNoteBodySchema } }, required: true },
|
|
445
|
+
},
|
|
446
|
+
responses: {
|
|
447
|
+
201: { content: { "application/json": { schema: NoteDataResponse } }, description: "Note created." },
|
|
448
|
+
...errorResponses,
|
|
449
|
+
},
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
export const listOrderNotesRoute = createRoute({
|
|
453
|
+
method: "get",
|
|
454
|
+
path: "/{id}/notes",
|
|
455
|
+
tags: ["Orders"],
|
|
456
|
+
summary: "List an order's notes (pinned first)",
|
|
457
|
+
request: { params: OrderIdParam },
|
|
458
|
+
responses: {
|
|
459
|
+
200: { content: { "application/json": { schema: NoteDataResponse } }, description: "Notes." },
|
|
460
|
+
...errorResponses,
|
|
461
|
+
},
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
export const deleteOrderNoteRoute = createRoute({
|
|
465
|
+
method: "delete",
|
|
466
|
+
path: "/{id}/notes/{noteId}",
|
|
467
|
+
tags: ["Orders"],
|
|
468
|
+
summary: "Delete an order note",
|
|
469
|
+
request: { params: NoteParam },
|
|
470
|
+
responses: {
|
|
471
|
+
200: { content: { "application/json": { schema: NoteDataResponse } }, description: "Note deleted." },
|
|
472
|
+
...errorResponses,
|
|
473
|
+
},
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
export const orderTimelineRoute = createRoute({
|
|
477
|
+
method: "get",
|
|
478
|
+
path: "/{id}/timeline",
|
|
479
|
+
tags: ["Orders"],
|
|
480
|
+
summary: "Merged activity timeline: status changes + notes + refunds, newest first",
|
|
481
|
+
request: { params: OrderIdParam },
|
|
482
|
+
responses: {
|
|
483
|
+
200: { content: { "application/json": { schema: NoteDataResponse } }, description: "Timeline events." },
|
|
484
|
+
...errorResponses,
|
|
485
|
+
},
|
|
486
|
+
});
|
|
@@ -57,6 +57,81 @@ export const setBasePriceRoute = createRoute({
|
|
|
57
57
|
},
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
+
export const UpdateModifierBodySchema = z.object({
|
|
61
|
+
name: z.string().optional(),
|
|
62
|
+
value: z.number().optional(),
|
|
63
|
+
priority: z.number().int().optional(),
|
|
64
|
+
validFrom: z.coerce.date().nullable().optional(),
|
|
65
|
+
validUntil: z.coerce.date().nullable().optional(),
|
|
66
|
+
minQuantity: z.number().int().nullable().optional(),
|
|
67
|
+
maxQuantity: z.number().int().nullable().optional(),
|
|
68
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
69
|
+
}).openapi("UpdateModifierRequest");
|
|
70
|
+
|
|
71
|
+
const ModifierIdParam = z.object({
|
|
72
|
+
id: z.uuid().openapi({ example: "550e8400-e29b-41d4-a716-446655440000" }),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
export const listModifiersRoute = createRoute({
|
|
76
|
+
method: "get",
|
|
77
|
+
path: "/modifiers",
|
|
78
|
+
tags: ["Pricing"],
|
|
79
|
+
summary: "List price modifiers",
|
|
80
|
+
description: "Lists active and scheduled price modifiers. Filter by entityId, currency, or active=true (currently within validity window).",
|
|
81
|
+
request: {
|
|
82
|
+
query: z.object({
|
|
83
|
+
entityId: z.string().optional(),
|
|
84
|
+
currency: z.string().optional(),
|
|
85
|
+
active: z.string().optional().openapi({ example: "true" }),
|
|
86
|
+
}),
|
|
87
|
+
},
|
|
88
|
+
responses: {
|
|
89
|
+
200: {
|
|
90
|
+
content: { "application/json": { schema: PricingResponseSchema } },
|
|
91
|
+
description: "Price modifiers",
|
|
92
|
+
},
|
|
93
|
+
...errorResponses,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
export const updateModifierRoute = createRoute({
|
|
98
|
+
method: "patch",
|
|
99
|
+
path: "/modifiers/{id}",
|
|
100
|
+
tags: ["Pricing"],
|
|
101
|
+
summary: "Update a price modifier's value or validity",
|
|
102
|
+
request: {
|
|
103
|
+
params: ModifierIdParam,
|
|
104
|
+
body: {
|
|
105
|
+
content: { "application/json": { schema: UpdateModifierBodySchema } },
|
|
106
|
+
required: true,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
responses: {
|
|
110
|
+
200: {
|
|
111
|
+
content: { "application/json": { schema: PricingResponseSchema } },
|
|
112
|
+
description: "Price modifier updated.",
|
|
113
|
+
},
|
|
114
|
+
...errorResponses,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
export const deleteModifierRoute = createRoute({
|
|
119
|
+
method: "delete",
|
|
120
|
+
path: "/modifiers/{id}",
|
|
121
|
+
tags: ["Pricing"],
|
|
122
|
+
summary: "Delete a price modifier (end a sale early)",
|
|
123
|
+
request: {
|
|
124
|
+
params: ModifierIdParam,
|
|
125
|
+
},
|
|
126
|
+
responses: {
|
|
127
|
+
200: {
|
|
128
|
+
content: { "application/json": { schema: PricingResponseSchema } },
|
|
129
|
+
description: "Price modifier deleted.",
|
|
130
|
+
},
|
|
131
|
+
...errorResponses,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
60
135
|
export const createModifierRoute = createRoute({
|
|
61
136
|
method: "post",
|
|
62
137
|
path: "/modifiers",
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { z, createRoute } from "@hono/zod-openapi";
|
|
2
|
+
import { errorResponses } from "./shared.js";
|
|
3
|
+
|
|
4
|
+
function isValidTimezone(tz: string): boolean {
|
|
5
|
+
try {
|
|
6
|
+
new Intl.DateTimeFormat("en-US", { timeZone: tz });
|
|
7
|
+
return true;
|
|
8
|
+
} catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Known typed groups. Every field is optional (PATCH is a partial merge) and
|
|
14
|
+
// nullable (null deletes the key). Unknown groups accept any flat JSON object
|
|
15
|
+
// so plugins can namespace their own settings.
|
|
16
|
+
export const GeneralSettingsPatchSchema = z.object({
|
|
17
|
+
currency: z.string().regex(/^[A-Z]{3}$/, "ISO 4217 uppercase code").nullable().optional(),
|
|
18
|
+
timezone: z.string().refine(isValidTimezone, "Must be a valid IANA timezone (e.g. Asia/Colombo)").nullable().optional(),
|
|
19
|
+
locale: z.string().min(2).nullable().optional(),
|
|
20
|
+
}).strict();
|
|
21
|
+
|
|
22
|
+
export const BrandingSettingsPatchSchema = z.object({
|
|
23
|
+
storeName: z.string().nullable().optional(),
|
|
24
|
+
receiptHeader: z.string().nullable().optional(),
|
|
25
|
+
receiptFooter: z.string().nullable().optional(),
|
|
26
|
+
logoUrl: z.string().nullable().optional(),
|
|
27
|
+
address: z.string().nullable().optional(),
|
|
28
|
+
phone: z.string().nullable().optional(),
|
|
29
|
+
email: z.string().nullable().optional(),
|
|
30
|
+
taxId: z.string().nullable().optional(),
|
|
31
|
+
}).strict();
|
|
32
|
+
|
|
33
|
+
export const PoliciesSettingsPatchSchema = z.record(
|
|
34
|
+
z.string(),
|
|
35
|
+
z.union([z.string(), z.number(), z.boolean(), z.null()]),
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
export const KNOWN_GROUP_SCHEMAS: Record<string, z.ZodTypeAny> = {
|
|
39
|
+
general: GeneralSettingsPatchSchema,
|
|
40
|
+
branding: BrandingSettingsPatchSchema,
|
|
41
|
+
policies: PoliciesSettingsPatchSchema,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const GroupParam = z.object({
|
|
45
|
+
group: z.string().regex(/^[a-z][a-z0-9_-]*$/).openapi({ example: "branding" }),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const SettingsPatchBodySchema = z
|
|
49
|
+
.record(z.string(), z.unknown())
|
|
50
|
+
.openapi("SettingsPatchRequest", {
|
|
51
|
+
description:
|
|
52
|
+
"Shallow merge into the group: keys overwrite, null deletes a key. Known groups (general, branding, policies) are validated.",
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const DataResponse = z.object({ data: z.any() }).openapi("SettingsResponse");
|
|
56
|
+
|
|
57
|
+
export const getAllSettingsRoute = createRoute({
|
|
58
|
+
method: "get",
|
|
59
|
+
path: "/",
|
|
60
|
+
tags: ["Settings"],
|
|
61
|
+
summary: "Get all settings groups for the organization",
|
|
62
|
+
responses: {
|
|
63
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "All settings groups" },
|
|
64
|
+
...errorResponses,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export const getSettingsGroupRoute = createRoute({
|
|
69
|
+
method: "get",
|
|
70
|
+
path: "/{group}",
|
|
71
|
+
tags: ["Settings"],
|
|
72
|
+
summary: "Get one settings group",
|
|
73
|
+
request: { params: GroupParam },
|
|
74
|
+
responses: {
|
|
75
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Settings group (empty object if unset)" },
|
|
76
|
+
...errorResponses,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
export const patchSettingsGroupRoute = createRoute({
|
|
81
|
+
method: "patch",
|
|
82
|
+
path: "/{group}",
|
|
83
|
+
tags: ["Settings"],
|
|
84
|
+
summary: "Merge values into a settings group",
|
|
85
|
+
request: {
|
|
86
|
+
params: GroupParam,
|
|
87
|
+
body: { content: { "application/json": { schema: SettingsPatchBodySchema } }, required: true },
|
|
88
|
+
},
|
|
89
|
+
responses: {
|
|
90
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "The merged group value" },
|
|
91
|
+
...errorResponses,
|
|
92
|
+
},
|
|
93
|
+
});
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { z, createRoute } from "@hono/zod-openapi";
|
|
2
|
+
import { errorResponses } from "./shared.js";
|
|
3
|
+
|
|
4
|
+
// ─── Request Schemas ────────────────────────────────────────────────────────
|
|
5
|
+
|
|
6
|
+
export const CreateShippingZoneBodySchema = z.object({
|
|
7
|
+
name: z.string().min(1).openapi({ example: "United States" }),
|
|
8
|
+
countries: z.array(z.string().min(1)).min(1).openapi({ example: ["US"] }),
|
|
9
|
+
states: z.array(z.string().min(1)).optional().openapi({ example: ["NY", "NJ"] }),
|
|
10
|
+
priority: z.number().int().optional(),
|
|
11
|
+
isActive: z.boolean().optional(),
|
|
12
|
+
}).openapi("CreateShippingZoneRequest");
|
|
13
|
+
|
|
14
|
+
export const UpdateShippingZoneBodySchema = z.object({
|
|
15
|
+
name: z.string().min(1).optional(),
|
|
16
|
+
countries: z.array(z.string().min(1)).min(1).optional(),
|
|
17
|
+
states: z.array(z.string().min(1)).optional(),
|
|
18
|
+
priority: z.number().int().optional(),
|
|
19
|
+
isActive: z.boolean().optional(),
|
|
20
|
+
}).openapi("UpdateShippingZoneRequest");
|
|
21
|
+
|
|
22
|
+
export const CreateShippingRateBodySchema = z.object({
|
|
23
|
+
zoneId: z.uuid(),
|
|
24
|
+
name: z.string().min(1).openapi({ example: "Standard" }),
|
|
25
|
+
amount: z.number().int().nonnegative().openapi({ example: 1500, description: "Flat cost in minor units" }),
|
|
26
|
+
currency: z.string().length(3).optional().openapi({ example: "USD" }),
|
|
27
|
+
minSubtotal: z.number().int().nonnegative().optional(),
|
|
28
|
+
maxSubtotal: z.number().int().nonnegative().optional(),
|
|
29
|
+
minWeightGrams: z.number().int().nonnegative().optional(),
|
|
30
|
+
maxWeightGrams: z.number().int().nonnegative().optional(),
|
|
31
|
+
freeShippingThreshold: z.number().int().nonnegative().optional().openapi({ example: 10000, description: "Subtotal at or above which shipping is free" }),
|
|
32
|
+
isActive: z.boolean().optional(),
|
|
33
|
+
}).openapi("CreateShippingRateRequest");
|
|
34
|
+
|
|
35
|
+
export const UpdateShippingRateBodySchema = z.object({
|
|
36
|
+
name: z.string().min(1).optional(),
|
|
37
|
+
amount: z.number().int().nonnegative().optional(),
|
|
38
|
+
currency: z.string().length(3).optional(),
|
|
39
|
+
minSubtotal: z.number().int().nonnegative().nullable().optional(),
|
|
40
|
+
maxSubtotal: z.number().int().nonnegative().nullable().optional(),
|
|
41
|
+
minWeightGrams: z.number().int().nonnegative().nullable().optional(),
|
|
42
|
+
maxWeightGrams: z.number().int().nonnegative().nullable().optional(),
|
|
43
|
+
freeShippingThreshold: z.number().int().nonnegative().nullable().optional(),
|
|
44
|
+
isActive: z.boolean().optional(),
|
|
45
|
+
}).openapi("UpdateShippingRateRequest");
|
|
46
|
+
|
|
47
|
+
// ─── Shared ─────────────────────────────────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
const IdParam = z.object({
|
|
50
|
+
id: z.uuid().openapi({ example: "550e8400-e29b-41d4-a716-446655440000" }),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const DataResponse = z.object({ data: z.any() }).openapi("ShippingConfigResponse");
|
|
54
|
+
|
|
55
|
+
// ─── Zone Routes ────────────────────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
export const createShippingZoneRoute = createRoute({
|
|
58
|
+
method: "post",
|
|
59
|
+
path: "/zones",
|
|
60
|
+
tags: ["Shipping"],
|
|
61
|
+
summary: "Create a shipping zone",
|
|
62
|
+
request: {
|
|
63
|
+
body: { content: { "application/json": { schema: CreateShippingZoneBodySchema } }, required: true },
|
|
64
|
+
},
|
|
65
|
+
responses: {
|
|
66
|
+
201: { content: { "application/json": { schema: DataResponse } }, description: "Zone created." },
|
|
67
|
+
...errorResponses,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
export const listShippingZonesRoute = createRoute({
|
|
72
|
+
method: "get",
|
|
73
|
+
path: "/zones",
|
|
74
|
+
tags: ["Shipping"],
|
|
75
|
+
summary: "List shipping zones",
|
|
76
|
+
responses: {
|
|
77
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Zones" },
|
|
78
|
+
...errorResponses,
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
export const updateShippingZoneRoute = createRoute({
|
|
83
|
+
method: "patch",
|
|
84
|
+
path: "/zones/{id}",
|
|
85
|
+
tags: ["Shipping"],
|
|
86
|
+
summary: "Update a shipping zone",
|
|
87
|
+
request: {
|
|
88
|
+
params: IdParam,
|
|
89
|
+
body: { content: { "application/json": { schema: UpdateShippingZoneBodySchema } }, required: true },
|
|
90
|
+
},
|
|
91
|
+
responses: {
|
|
92
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Zone updated." },
|
|
93
|
+
...errorResponses,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
export const deleteShippingZoneRoute = createRoute({
|
|
98
|
+
method: "delete",
|
|
99
|
+
path: "/zones/{id}",
|
|
100
|
+
tags: ["Shipping"],
|
|
101
|
+
summary: "Delete a shipping zone (and its rates)",
|
|
102
|
+
request: { params: IdParam },
|
|
103
|
+
responses: {
|
|
104
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Zone deleted." },
|
|
105
|
+
...errorResponses,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// ─── Rate Routes ────────────────────────────────────────────────────────────
|
|
110
|
+
|
|
111
|
+
export const createShippingRateRoute = createRoute({
|
|
112
|
+
method: "post",
|
|
113
|
+
path: "/rates",
|
|
114
|
+
tags: ["Shipping"],
|
|
115
|
+
summary: "Create a shipping rate in a zone",
|
|
116
|
+
request: {
|
|
117
|
+
body: { content: { "application/json": { schema: CreateShippingRateBodySchema } }, required: true },
|
|
118
|
+
},
|
|
119
|
+
responses: {
|
|
120
|
+
201: { content: { "application/json": { schema: DataResponse } }, description: "Rate created." },
|
|
121
|
+
...errorResponses,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
export const listShippingRatesRoute = createRoute({
|
|
126
|
+
method: "get",
|
|
127
|
+
path: "/rates",
|
|
128
|
+
tags: ["Shipping"],
|
|
129
|
+
summary: "List shipping rates",
|
|
130
|
+
request: {
|
|
131
|
+
query: z.object({ zoneId: z.string().optional() }),
|
|
132
|
+
},
|
|
133
|
+
responses: {
|
|
134
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Rates" },
|
|
135
|
+
...errorResponses,
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
export const updateShippingRateRoute = createRoute({
|
|
140
|
+
method: "patch",
|
|
141
|
+
path: "/rates/{id}",
|
|
142
|
+
tags: ["Shipping"],
|
|
143
|
+
summary: "Update a shipping rate",
|
|
144
|
+
request: {
|
|
145
|
+
params: IdParam,
|
|
146
|
+
body: { content: { "application/json": { schema: UpdateShippingRateBodySchema } }, required: true },
|
|
147
|
+
},
|
|
148
|
+
responses: {
|
|
149
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Rate updated." },
|
|
150
|
+
...errorResponses,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
export const deleteShippingRateRoute = createRoute({
|
|
155
|
+
method: "delete",
|
|
156
|
+
path: "/rates/{id}",
|
|
157
|
+
tags: ["Shipping"],
|
|
158
|
+
summary: "Delete a shipping rate",
|
|
159
|
+
request: { params: IdParam },
|
|
160
|
+
responses: {
|
|
161
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Rate deleted." },
|
|
162
|
+
...errorResponses,
|
|
163
|
+
},
|
|
164
|
+
});
|