@porulle/core 0.11.0 → 0.14.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/actor.d.ts +10 -0
- package/dist/auth/actor.d.ts.map +1 -0
- package/dist/auth/actor.js +91 -0
- package/dist/auth/auth-schema-guard.d.ts +2444 -0
- package/dist/auth/auth-schema-guard.d.ts.map +1 -0
- package/dist/auth/auth-schema-guard.js +113 -0
- package/dist/auth/auth-schema.d.ts +228 -0
- package/dist/auth/auth-schema.d.ts.map +1 -1
- package/dist/auth/auth-schema.js +24 -2
- package/dist/auth/middleware.d.ts +1 -0
- package/dist/auth/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +16 -92
- package/dist/auth/org.d.ts +8 -2
- package/dist/auth/org.d.ts.map +1 -1
- package/dist/auth/org.js +12 -4
- package/dist/auth/organization-guard.d.ts +5 -0
- package/dist/auth/organization-guard.d.ts.map +1 -0
- package/dist/auth/organization-guard.js +124 -0
- package/dist/auth/permissions.d.ts +10 -0
- package/dist/auth/permissions.d.ts.map +1 -1
- package/dist/auth/permissions.js +31 -7
- package/dist/auth/role-authority.d.ts +44 -0
- package/dist/auth/role-authority.d.ts.map +1 -0
- package/dist/auth/role-authority.js +85 -0
- package/dist/auth/setup.d.ts.map +1 -1
- package/dist/auth/setup.js +19 -1
- package/dist/auth/strict-org-resolution.d.ts.map +1 -1
- package/dist/auth/strict-org-resolution.js +9 -1
- package/dist/auth/types.d.ts +1 -1
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +2 -0
- package/dist/config/types.d.ts +32 -4
- package/dist/config/types.d.ts.map +1 -1
- package/dist/hooks/checkout.d.ts.map +1 -1
- package/dist/hooks/checkout.js +10 -9
- package/dist/index.d.ts +7 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/interfaces/rest/audit-middleware.d.ts.map +1 -1
- package/dist/interfaces/rest/audit-middleware.js +2 -0
- package/dist/interfaces/rest/customer-portal.d.ts.map +1 -1
- package/dist/interfaces/rest/customer-portal.js +9 -8
- package/dist/interfaces/rest/route-coverage.d.ts +14 -0
- package/dist/interfaces/rest/route-coverage.d.ts.map +1 -0
- package/dist/interfaces/rest/route-coverage.js +81 -0
- package/dist/interfaces/rest/router.d.ts +7 -2
- package/dist/interfaces/rest/router.d.ts.map +1 -1
- package/dist/interfaces/rest/router.js +8 -4
- package/dist/interfaces/rest/routes/admin/compensation-failures.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/admin/compensation-failures.js +7 -5
- package/dist/interfaces/rest/routes/admin/custom-field-proposals.js +2 -2
- package/dist/interfaces/rest/routes/admin/permissions.d.ts +1 -1
- package/dist/interfaces/rest/routes/admin/permissions.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/admin/permissions.js +2 -0
- package/dist/interfaces/rest/routes/admin/staff.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/admin/staff.js +126 -66
- package/dist/interfaces/rest/routes/admin-jobs.js +3 -3
- package/dist/interfaces/rest/routes/audit.js +3 -3
- package/dist/interfaces/rest/routes/carts.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/carts.js +13 -10
- package/dist/interfaces/rest/routes/catalog.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/catalog.js +10 -2
- package/dist/interfaces/rest/routes/checkout.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/checkout.js +30 -35
- package/dist/interfaces/rest/routes/documents.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/documents.js +10 -5
- package/dist/interfaces/rest/routes/inventory.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/inventory.js +2 -0
- package/dist/interfaces/rest/routes/media.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/media.js +7 -3
- package/dist/interfaces/rest/routes/orders.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/orders.js +26 -8
- package/dist/interfaces/rest/routes/pricing.js +2 -2
- package/dist/interfaces/rest/routes/promotions.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/promotions.js +13 -10
- package/dist/interfaces/rest/routes/search.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/search.js +2 -1
- package/dist/interfaces/rest/schemas/carts.d.ts +7 -0
- package/dist/interfaces/rest/schemas/carts.d.ts.map +1 -1
- 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/orders.d.ts +204 -0
- package/dist/interfaces/rest/schemas/orders.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/responses.d.ts +71 -0
- package/dist/interfaces/rest/schemas/responses.d.ts.map +1 -1
- package/dist/interfaces/rest/utils.d.ts +15 -0
- package/dist/interfaces/rest/utils.d.ts.map +1 -1
- package/dist/interfaces/rest/utils.js +45 -2
- package/dist/kernel/compensation/executor.js +2 -2
- package/dist/kernel/database/plugin-types.d.ts +11 -0
- package/dist/kernel/database/plugin-types.d.ts.map +1 -1
- package/dist/kernel/database/scoped-db.d.ts +12 -0
- package/dist/kernel/database/scoped-db.d.ts.map +1 -1
- package/dist/kernel/database/scoped-db.js +12 -0
- package/dist/kernel/database/tx-context.d.ts +8 -0
- package/dist/kernel/database/tx-context.d.ts.map +1 -1
- package/dist/kernel/database/tx-context.js +13 -0
- package/dist/kernel/hooks/create-context.d.ts +2 -0
- package/dist/kernel/hooks/create-context.d.ts.map +1 -1
- package/dist/kernel/hooks/create-context.js +1 -0
- package/dist/kernel/hooks/types.d.ts +2 -0
- package/dist/kernel/hooks/types.d.ts.map +1 -1
- package/dist/kernel/plugin/manifest.d.ts.map +1 -1
- package/dist/kernel/plugin/manifest.js +9 -5
- package/dist/modules/analytics/service.js +2 -2
- package/dist/modules/audit/service.js +3 -3
- package/dist/modules/cart/repository/index.d.ts +13 -7
- package/dist/modules/cart/repository/index.d.ts.map +1 -1
- package/dist/modules/cart/repository/index.js +16 -10
- 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 +4 -0
- package/dist/modules/cart/service.d.ts +22 -9
- package/dist/modules/cart/service.d.ts.map +1 -1
- package/dist/modules/cart/service.js +57 -33
- package/dist/modules/catalog/brand-service.js +7 -7
- package/dist/modules/catalog/category-service.js +7 -7
- package/dist/modules/catalog/entity-service.d.ts +14 -7
- package/dist/modules/catalog/entity-service.d.ts.map +1 -1
- package/dist/modules/catalog/entity-service.js +109 -31
- package/dist/modules/catalog/read-policy.d.ts +9 -0
- package/dist/modules/catalog/read-policy.d.ts.map +1 -0
- package/dist/modules/catalog/read-policy.js +8 -0
- package/dist/modules/catalog/repository/index.d.ts +3 -2
- package/dist/modules/catalog/repository/index.d.ts.map +1 -1
- package/dist/modules/catalog/repository/index.js +14 -4
- package/dist/modules/catalog/service.d.ts +15 -13
- package/dist/modules/catalog/service.d.ts.map +1 -1
- package/dist/modules/catalog/service.js +25 -18
- package/dist/modules/customers/module.d.ts.map +1 -1
- package/dist/modules/customers/module.js +1 -0
- package/dist/modules/customers/service.d.ts +2 -0
- package/dist/modules/customers/service.d.ts.map +1 -1
- package/dist/modules/customers/service.js +21 -20
- package/dist/modules/documents/module.d.ts.map +1 -1
- package/dist/modules/documents/module.js +1 -0
- package/dist/modules/documents/service.d.ts +18 -4
- package/dist/modules/documents/service.d.ts.map +1 -1
- package/dist/modules/documents/service.js +54 -16
- package/dist/modules/fulfillment/module.d.ts.map +1 -1
- package/dist/modules/fulfillment/module.js +1 -0
- package/dist/modules/fulfillment/service.d.ts +2 -0
- package/dist/modules/fulfillment/service.d.ts.map +1 -1
- package/dist/modules/fulfillment/service.js +15 -6
- package/dist/modules/inventory/service.d.ts.map +1 -1
- package/dist/modules/inventory/service.js +15 -14
- package/dist/modules/media/service.js +6 -6
- package/dist/modules/orders/guest-access.d.ts +27 -0
- package/dist/modules/orders/guest-access.d.ts.map +1 -0
- package/dist/modules/orders/guest-access.js +46 -0
- package/dist/modules/orders/module.d.ts.map +1 -1
- package/dist/modules/orders/module.js +1 -0
- package/dist/modules/orders/quote.d.ts.map +1 -1
- package/dist/modules/orders/quote.js +1 -0
- package/dist/modules/orders/repository/index.d.ts +1 -1
- package/dist/modules/orders/repository/index.d.ts.map +1 -1
- package/dist/modules/orders/repository/index.js +2 -2
- package/dist/modules/orders/schema.d.ts +17 -0
- package/dist/modules/orders/schema.d.ts.map +1 -1
- package/dist/modules/orders/schema.js +5 -3
- package/dist/modules/orders/service.d.ts +16 -7
- package/dist/modules/orders/service.d.ts.map +1 -1
- package/dist/modules/orders/service.js +184 -55
- package/dist/modules/pricing/module.d.ts.map +1 -1
- package/dist/modules/pricing/module.js +1 -0
- package/dist/modules/pricing/service.d.ts +2 -0
- package/dist/modules/pricing/service.d.ts.map +1 -1
- package/dist/modules/pricing/service.js +12 -11
- package/dist/modules/promotions/module.d.ts.map +1 -1
- package/dist/modules/promotions/module.js +1 -0
- package/dist/modules/promotions/service.d.ts +3 -0
- package/dist/modules/promotions/service.d.ts.map +1 -1
- package/dist/modules/promotions/service.js +19 -11
- package/dist/modules/search/adapter.d.ts +11 -0
- package/dist/modules/search/adapter.d.ts.map +1 -1
- package/dist/modules/search/module.d.ts.map +1 -1
- package/dist/modules/search/module.js +4 -1
- package/dist/modules/search/service.d.ts +1 -0
- package/dist/modules/search/service.d.ts.map +1 -1
- package/dist/modules/search/service.js +57 -6
- package/dist/modules/settings/module.d.ts.map +1 -1
- package/dist/modules/settings/module.js +1 -0
- package/dist/modules/settings/service.d.ts +3 -0
- package/dist/modules/settings/service.d.ts.map +1 -1
- package/dist/modules/settings/service.js +6 -4
- package/dist/modules/shipping/service.js +9 -9
- package/dist/modules/tax/module.d.ts.map +1 -1
- package/dist/modules/tax/module.js +1 -0
- package/dist/modules/tax/service.d.ts +3 -0
- package/dist/modules/tax/service.d.ts.map +1 -1
- package/dist/modules/tax/service.js +11 -9
- package/dist/modules/webhooks/hook.js +2 -2
- package/dist/modules/webhooks/module.d.ts.map +1 -1
- package/dist/modules/webhooks/module.js +1 -0
- package/dist/modules/webhooks/service.d.ts +2 -0
- package/dist/modules/webhooks/service.d.ts.map +1 -1
- package/dist/modules/webhooks/service.js +4 -4
- package/dist/runtime/server.d.ts.map +1 -1
- package/dist/runtime/server.js +28 -2
- package/dist/test-utils/create-pglite-adapter.d.ts.map +1 -1
- package/dist/test-utils/create-pglite-adapter.js +35 -13
- package/dist/test-utils/create-test-config.d.ts.map +1 -1
- package/dist/test-utils/create-test-config.js +4 -0
- package/dist/test-utils/rest-api-test-utils.d.ts.map +1 -1
- package/dist/test-utils/rest-api-test-utils.js +2 -0
- package/dist/test-utils/test-actors.js +2 -2
- package/dist/utils/id.d.ts +2 -0
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +11 -0
- package/package.json +6 -5
- package/src/auth/actor.ts +110 -0
- package/src/auth/auth-schema-guard.ts +143 -0
- package/src/auth/auth-schema.ts +50 -19
- package/src/auth/middleware.ts +25 -101
- package/src/auth/org.ts +15 -3
- package/src/auth/organization-guard.ts +158 -0
- package/src/auth/permissions.ts +31 -8
- package/src/auth/role-authority.ts +107 -0
- package/src/auth/setup.ts +19 -1
- package/src/auth/strict-org-resolution.ts +7 -1
- package/src/auth/types.ts +1 -1
- package/src/config/defaults.ts +2 -0
- package/src/config/types.ts +31 -4
- package/src/hooks/checkout.ts +19 -12
- package/src/index.ts +21 -6
- package/src/interfaces/rest/audit-middleware.ts +2 -0
- package/src/interfaces/rest/customer-portal.ts +31 -24
- package/src/interfaces/rest/route-coverage.ts +103 -0
- package/src/interfaces/rest/router.ts +16 -10
- package/src/interfaces/rest/routes/admin/compensation-failures.ts +8 -5
- package/src/interfaces/rest/routes/admin/custom-field-proposals.ts +2 -2
- package/src/interfaces/rest/routes/admin/permissions.ts +3 -1
- package/src/interfaces/rest/routes/admin/staff.ts +161 -72
- package/src/interfaces/rest/routes/admin-jobs.ts +3 -3
- package/src/interfaces/rest/routes/audit.ts +3 -3
- package/src/interfaces/rest/routes/carts.ts +17 -7
- package/src/interfaces/rest/routes/catalog.ts +11 -0
- package/src/interfaces/rest/routes/checkout.ts +41 -38
- package/src/interfaces/rest/routes/documents.ts +15 -1
- package/src/interfaces/rest/routes/inventory.ts +2 -0
- package/src/interfaces/rest/routes/media.ts +8 -3
- package/src/interfaces/rest/routes/orders.ts +27 -8
- package/src/interfaces/rest/routes/pricing.ts +2 -2
- package/src/interfaces/rest/routes/promotions.ts +12 -9
- package/src/interfaces/rest/routes/search.ts +3 -1
- package/src/interfaces/rest/utils.ts +61 -2
- package/src/kernel/compensation/executor.ts +2 -2
- package/src/kernel/database/plugin-types.ts +11 -0
- package/src/kernel/database/scoped-db.ts +12 -0
- package/src/kernel/database/tx-context.ts +25 -0
- package/src/kernel/hooks/create-context.ts +3 -0
- package/src/kernel/hooks/types.ts +2 -0
- package/src/kernel/plugin/manifest.ts +9 -5
- package/src/modules/analytics/service.ts +2 -2
- package/src/modules/audit/service.ts +3 -3
- package/src/modules/cart/repository/index.ts +22 -8
- package/src/modules/cart/schema.ts +4 -0
- package/src/modules/cart/service.ts +62 -27
- package/src/modules/catalog/brand-service.ts +7 -7
- package/src/modules/catalog/category-service.ts +7 -7
- package/src/modules/catalog/entity-service.ts +117 -35
- package/src/modules/catalog/read-policy.ts +16 -0
- package/src/modules/catalog/repository/index.ts +19 -3
- package/src/modules/catalog/service.ts +46 -31
- package/src/modules/customers/module.ts +2 -0
- package/src/modules/customers/service.ts +23 -22
- package/src/modules/documents/module.ts +2 -0
- package/src/modules/documents/service.ts +74 -11
- package/src/modules/fulfillment/module.ts +2 -0
- package/src/modules/fulfillment/service.ts +17 -6
- package/src/modules/inventory/service.ts +15 -24
- package/src/modules/media/service.ts +6 -6
- package/src/modules/orders/guest-access.ts +55 -0
- package/src/modules/orders/module.ts +1 -0
- package/src/modules/orders/quote.ts +1 -0
- package/src/modules/orders/repository/index.ts +2 -0
- package/src/modules/orders/schema.ts +5 -3
- package/src/modules/orders/service.ts +302 -52
- package/src/modules/pricing/module.ts +2 -0
- package/src/modules/pricing/service.ts +14 -16
- package/src/modules/promotions/module.ts +2 -0
- package/src/modules/promotions/service.ts +25 -16
- package/src/modules/search/adapter.ts +9 -0
- package/src/modules/search/module.ts +5 -1
- package/src/modules/search/service.ts +55 -6
- package/src/modules/settings/module.ts +2 -0
- package/src/modules/settings/service.ts +8 -4
- package/src/modules/shipping/service.ts +9 -9
- package/src/modules/tax/module.ts +1 -0
- package/src/modules/tax/service.ts +13 -9
- package/src/modules/webhooks/hook.ts +2 -2
- package/src/modules/webhooks/module.ts +2 -0
- package/src/modules/webhooks/service.ts +6 -4
- package/src/runtime/server.ts +41 -2
- package/src/test-utils/create-pglite-adapter.ts +34 -12
- package/src/test-utils/create-test-config.ts +10 -6
- package/src/test-utils/rest-api-test-utils.ts +2 -0
- package/src/test-utils/test-actors.ts +2 -2
- package/src/utils/id.ts +20 -0
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { assertOwnership, assertPermission } from "../../auth/permissions.js";
|
|
1
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
2
|
+
import { assertOwnership, assertPermission, hasPermission } from "../../auth/permissions.js";
|
|
3
3
|
import type { Actor } from "../../auth/types.js";
|
|
4
|
+
import { defaultGuestOrderAccess } from "./guest-access.js";
|
|
5
|
+
import type { CommerceConfig } from "../../config/types.js";
|
|
6
|
+
import { isCatalogEntityVisible } from "../catalog/read-policy.js";
|
|
4
7
|
import {
|
|
8
|
+
CommerceConflictError,
|
|
5
9
|
CommerceForbiddenError,
|
|
6
10
|
CommerceInvalidTransitionError,
|
|
7
11
|
CommerceNotFoundError,
|
|
@@ -25,6 +29,7 @@ import {
|
|
|
25
29
|
} from "../../kernel/state-machine/machine.js";
|
|
26
30
|
import { Err, Ok, type Result } from "../../kernel/result.js";
|
|
27
31
|
import { createLogger } from "../../utils/logger.js";
|
|
32
|
+
import { makeIdempotencyScope } from "../../utils/id.js";
|
|
28
33
|
import { paginate, type Pagination } from "../../utils/pagination.js";
|
|
29
34
|
import {
|
|
30
35
|
withTransaction,
|
|
@@ -99,12 +104,20 @@ export interface ChangeStatusInput {
|
|
|
99
104
|
export interface OrderServiceDeps {
|
|
100
105
|
repository: OrdersRepository;
|
|
101
106
|
hooks: HookRegistry;
|
|
107
|
+
config: CommerceConfig;
|
|
102
108
|
services: Record<string, unknown>;
|
|
103
109
|
/** Custom state machine. If provided, overrides the default order transitions. */
|
|
104
110
|
stateMachine?: StateDefinition<string>;
|
|
105
111
|
database: DatabaseAdapter;
|
|
106
112
|
}
|
|
107
113
|
|
|
114
|
+
export interface CreateOrderOptions {
|
|
115
|
+
trustedPricing?: boolean;
|
|
116
|
+
stockPolicy?: "reserve" | "backorder";
|
|
117
|
+
/** Credential presented by a guest cart owner for idempotent replay. */
|
|
118
|
+
guestCredential?: string;
|
|
119
|
+
}
|
|
120
|
+
|
|
108
121
|
export type HydratedOrder = Order & { lineItems: OrderLineItem[] };
|
|
109
122
|
type OrderListResult = {
|
|
110
123
|
items: HydratedOrder[];
|
|
@@ -126,6 +139,7 @@ function context(
|
|
|
126
139
|
actor: Actor | null,
|
|
127
140
|
services: Record<string, unknown>,
|
|
128
141
|
database: DatabaseAdapter,
|
|
142
|
+
config: CommerceConfig,
|
|
129
143
|
tx: unknown = null,
|
|
130
144
|
): HookContext {
|
|
131
145
|
return createHookContext({
|
|
@@ -136,6 +150,7 @@ function context(
|
|
|
136
150
|
...(services.jobs ? { jobs: services.jobs as JobsAdapter } : {}),
|
|
137
151
|
context: { moduleName: "orders" },
|
|
138
152
|
database: { db: database.db as PluginDb },
|
|
153
|
+
commerceConfig: config,
|
|
139
154
|
});
|
|
140
155
|
}
|
|
141
156
|
|
|
@@ -182,14 +197,18 @@ export class OrderService {
|
|
|
182
197
|
}
|
|
183
198
|
}
|
|
184
199
|
const catalog = this.deps.services.catalog as {
|
|
185
|
-
|
|
200
|
+
getByIdForInternalUse(
|
|
186
201
|
id: string,
|
|
187
|
-
|
|
188
|
-
|
|
202
|
+
organizationId: string,
|
|
203
|
+
options?: Record<string, unknown>,
|
|
189
204
|
ctx?: TxContext,
|
|
190
205
|
): Promise<{
|
|
191
206
|
ok: boolean;
|
|
192
|
-
value?: {
|
|
207
|
+
value?: {
|
|
208
|
+
status?: string;
|
|
209
|
+
isVisible?: boolean;
|
|
210
|
+
variants?: Array<{ id: string }>;
|
|
211
|
+
};
|
|
193
212
|
}>;
|
|
194
213
|
};
|
|
195
214
|
const pricing = this.deps.services.pricing as {
|
|
@@ -210,13 +229,25 @@ export class OrderService {
|
|
|
210
229
|
> = [];
|
|
211
230
|
for (const item of input.lineItems) {
|
|
212
231
|
// Org-integrity — the referenced entity must belong to this order's org.
|
|
213
|
-
|
|
232
|
+
// This is an internal invariant check, so it reads past the storefront
|
|
233
|
+
// visibility policy; unprivileged buyers are gated in the same branch.
|
|
234
|
+
const owned = await catalog.getByIdForInternalUse(
|
|
214
235
|
item.entityId,
|
|
236
|
+
resolveOrgIdForCommerce(actor, this.deps.config),
|
|
215
237
|
{ includeVariants: item.variantId !== undefined },
|
|
216
|
-
actor,
|
|
217
238
|
ctx,
|
|
218
239
|
);
|
|
219
|
-
if (
|
|
240
|
+
if (
|
|
241
|
+
!owned.ok ||
|
|
242
|
+
!owned.value ||
|
|
243
|
+
!isCatalogEntityVisible(
|
|
244
|
+
{
|
|
245
|
+
status: owned.value?.status ?? "draft",
|
|
246
|
+
isVisible: owned.value?.isVisible ?? false,
|
|
247
|
+
},
|
|
248
|
+
actor,
|
|
249
|
+
)
|
|
250
|
+
) {
|
|
220
251
|
return Err(
|
|
221
252
|
new CommerceValidationError(
|
|
222
253
|
`Line item entity ${item.entityId} does not belong to this organization.`,
|
|
@@ -266,11 +297,180 @@ export class OrderService {
|
|
|
266
297
|
return Ok(resolved);
|
|
267
298
|
}
|
|
268
299
|
|
|
300
|
+
private async resolveCreateCustomerId(
|
|
301
|
+
requestedCustomerId: string | undefined,
|
|
302
|
+
actor: Actor | null,
|
|
303
|
+
ctx?: TxContext,
|
|
304
|
+
): Promise<string | undefined> {
|
|
305
|
+
// API keys are the documented POS operator actor. Keep this as an actor
|
|
306
|
+
// type predicate so self-service user actors remain unable to choose a
|
|
307
|
+
// foreign customerId even when they are authenticated.
|
|
308
|
+
const isOperator = actor?.type === "api_key";
|
|
309
|
+
if (isOperator) {
|
|
310
|
+
if (requestedCustomerId === undefined) return undefined;
|
|
311
|
+
return this.resolveRequestedCustomerId(requestedCustomerId, actor, ctx);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (hasPermission(actor, "orders:create:on-behalf")) {
|
|
315
|
+
if (requestedCustomerId === undefined) return undefined;
|
|
316
|
+
return this.resolveRequestedCustomerId(requestedCustomerId, actor, ctx);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// `orders:read:own` is the system's existing "this actor is a shopper"
|
|
320
|
+
// marker -- it is in DEFAULT_CUSTOMER_PERMISSIONS and guards the read-own
|
|
321
|
+
// order routes. Using it here decides *attribution*, which is a proxy and is
|
|
322
|
+
// deliberately a stopgap: the honest discriminator is caller intent, which a
|
|
323
|
+
// storefront route knows and this service cannot see.
|
|
324
|
+
//
|
|
325
|
+
// Known misclassification: a dual-hatted role holding `orders:read:own` for
|
|
326
|
+
// its own personal orders, plus `orders:create`, self-attributes a walk-in
|
|
327
|
+
// sale. The proxy is tolerable only because it fails narrow -- it can attach
|
|
328
|
+
// the actor's own profile or fall through to a guest order, never expose
|
|
329
|
+
// another principal's data.
|
|
330
|
+
if (!hasPermission(actor, "orders:read:own")) return undefined;
|
|
331
|
+
if (!actor?.userId) return undefined;
|
|
332
|
+
const customers = this.deps.services.customers as
|
|
333
|
+
| {
|
|
334
|
+
getByUserId(
|
|
335
|
+
userId: string,
|
|
336
|
+
actor?: Actor | null,
|
|
337
|
+
ctx?: TxContext,
|
|
338
|
+
): Promise<{ ok: boolean; value?: { id: string } }>;
|
|
339
|
+
}
|
|
340
|
+
| undefined;
|
|
341
|
+
if (!customers?.getByUserId) return undefined;
|
|
342
|
+
const own = await customers.getByUserId(actor.userId, actor, ctx);
|
|
343
|
+
return own.ok ? own.value?.id : undefined;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
private async resolveRequestedCustomerId(
|
|
347
|
+
requestedCustomerId: string,
|
|
348
|
+
actor: Actor | null,
|
|
349
|
+
ctx?: TxContext,
|
|
350
|
+
): Promise<string> {
|
|
351
|
+
const customers = this.deps.services.customers as
|
|
352
|
+
| {
|
|
353
|
+
getById(
|
|
354
|
+
id: string,
|
|
355
|
+
actor?: Actor | null,
|
|
356
|
+
ctx?: TxContext,
|
|
357
|
+
): Promise<{ ok: boolean; value?: { id: string } }>;
|
|
358
|
+
}
|
|
359
|
+
| undefined;
|
|
360
|
+
const customer = await customers?.getById(requestedCustomerId, actor, ctx);
|
|
361
|
+
if (!customer?.ok || !customer.value) {
|
|
362
|
+
throw new CommerceValidationError(
|
|
363
|
+
"customerId must reference a customer in this organization.",
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
return customer.value.id;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
private async authorizeOrderRead(
|
|
370
|
+
order: Order,
|
|
371
|
+
actor: Actor | null,
|
|
372
|
+
ctx?: TxContext,
|
|
373
|
+
guestCredential?: string,
|
|
374
|
+
): Promise<Result<void>> {
|
|
375
|
+
try {
|
|
376
|
+
if (
|
|
377
|
+
actor?.permissions.includes("orders:read") ||
|
|
378
|
+
actor?.permissions.includes("*:*")
|
|
379
|
+
) {
|
|
380
|
+
// no-op
|
|
381
|
+
} else if (actor?.permissions.includes("orders:read:own")) {
|
|
382
|
+
if (order.customerId == null) {
|
|
383
|
+
const cartId =
|
|
384
|
+
typeof order.metadata?.cartId === "string"
|
|
385
|
+
? order.metadata.cartId
|
|
386
|
+
: undefined;
|
|
387
|
+
const cart = this.deps.services.cart as
|
|
388
|
+
| {
|
|
389
|
+
getById(
|
|
390
|
+
id: string,
|
|
391
|
+
actor?: Actor | null,
|
|
392
|
+
ctx?: TxContext,
|
|
393
|
+
secret?: string,
|
|
394
|
+
): Promise<{ ok: boolean }>;
|
|
395
|
+
}
|
|
396
|
+
| undefined;
|
|
397
|
+
if (!cartId || !guestCredential || !cart?.getById) {
|
|
398
|
+
throw new CommerceForbiddenError("You do not have access to this resource.");
|
|
399
|
+
}
|
|
400
|
+
const guestCart = await cart.getById(
|
|
401
|
+
cartId,
|
|
402
|
+
actor,
|
|
403
|
+
ctx,
|
|
404
|
+
guestCredential,
|
|
405
|
+
);
|
|
406
|
+
if (!guestCart.ok) {
|
|
407
|
+
throw new CommerceForbiddenError("You do not have access to this resource.");
|
|
408
|
+
}
|
|
409
|
+
// The secret is genuine, but a bearer credential with no lifetime
|
|
410
|
+
// reads this order forever — and a secret leaks far more easily than
|
|
411
|
+
// it is guessed. Bound it to a window after placement, and fail with
|
|
412
|
+
// the identical error so a stale window is not an oracle telling the
|
|
413
|
+
// caller their secret is valid.
|
|
414
|
+
const guestAccess =
|
|
415
|
+
this.deps.config.orders?.guestAccessStrategy ?? defaultGuestOrderAccess;
|
|
416
|
+
if (!guestAccess.canAccessOrder(order, new Date())) {
|
|
417
|
+
throw new CommerceForbiddenError("You do not have access to this resource.");
|
|
418
|
+
}
|
|
419
|
+
} else {
|
|
420
|
+
// Older integrations may have stored the auth user ID directly as
|
|
421
|
+
// customerId. Keep that valid ownership shape while resolving the
|
|
422
|
+
// normal auth-user -> customer-profile relationship below.
|
|
423
|
+
let ownerActor = actor;
|
|
424
|
+
if (actor.userId !== order.customerId) {
|
|
425
|
+
const customers = this.deps.services.customers as
|
|
426
|
+
| {
|
|
427
|
+
getByUserId(
|
|
428
|
+
userId: string,
|
|
429
|
+
actor?: Actor | null,
|
|
430
|
+
ctx?: TxContext,
|
|
431
|
+
): Promise<{ ok: boolean; value?: { id: string } }>;
|
|
432
|
+
}
|
|
433
|
+
| undefined;
|
|
434
|
+
const profile = actor.userId && customers?.getByUserId
|
|
435
|
+
? await customers.getByUserId(actor.userId, actor, ctx)
|
|
436
|
+
: { ok: false as const };
|
|
437
|
+
ownerActor = profile.ok
|
|
438
|
+
? { ...actor, userId: profile.value!.id }
|
|
439
|
+
: actor;
|
|
440
|
+
}
|
|
441
|
+
assertOwnership(ownerActor, order.customerId);
|
|
442
|
+
}
|
|
443
|
+
} else {
|
|
444
|
+
assertPermission(actor, "orders:read");
|
|
445
|
+
}
|
|
446
|
+
} catch (error) {
|
|
447
|
+
return Err(toCommerceError(error));
|
|
448
|
+
}
|
|
449
|
+
return Ok(undefined);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
private async authorizedReplay(
|
|
453
|
+
order: Order,
|
|
454
|
+
actor: Actor | null,
|
|
455
|
+
ctx?: TxContext,
|
|
456
|
+
guestCredential?: string,
|
|
457
|
+
): Promise<Result<HydratedOrder>> {
|
|
458
|
+
const access = await this.authorizeOrderRead(order, actor, ctx, guestCredential);
|
|
459
|
+
if (!access.ok) {
|
|
460
|
+
return Err(
|
|
461
|
+
new CommerceConflictError(
|
|
462
|
+
"Idempotency key does not belong to this account.",
|
|
463
|
+
),
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
return Ok(await this.hydrateOrder(order, ctx));
|
|
467
|
+
}
|
|
468
|
+
|
|
269
469
|
async create(
|
|
270
470
|
input: CreateOrderInput,
|
|
271
471
|
actor: Actor | null,
|
|
272
472
|
ctx?: TxContext,
|
|
273
|
-
opts?:
|
|
473
|
+
opts?: CreateOrderOptions,
|
|
274
474
|
): Promise<Result<HydratedOrder>> {
|
|
275
475
|
if (opts?.stockPolicy === "reserve" && !ctx) {
|
|
276
476
|
return withTransaction(this.deps.database, { actor }, (txCtx) =>
|
|
@@ -290,22 +490,49 @@ export class OrderService {
|
|
|
290
490
|
);
|
|
291
491
|
}
|
|
292
492
|
|
|
493
|
+
let resolvedCustomerId: string | undefined;
|
|
494
|
+
try {
|
|
495
|
+
resolvedCustomerId = await this.resolveCreateCustomerId(
|
|
496
|
+
input.customerId,
|
|
497
|
+
actor,
|
|
498
|
+
ctx,
|
|
499
|
+
);
|
|
500
|
+
} catch (error) {
|
|
501
|
+
return Err(toCommerceError(error));
|
|
502
|
+
}
|
|
503
|
+
const serviceInput: CreateOrderInput = {
|
|
504
|
+
...input,
|
|
505
|
+
...(resolvedCustomerId !== undefined
|
|
506
|
+
? { customerId: resolvedCustomerId }
|
|
507
|
+
: {}),
|
|
508
|
+
};
|
|
509
|
+
if (resolvedCustomerId === undefined) delete serviceInput.customerId;
|
|
510
|
+
|
|
293
511
|
const beforeHooks = this.deps.hooks.resolve(
|
|
294
512
|
"orders.beforeCreate",
|
|
295
513
|
) as BeforeCreateOrderHook[];
|
|
296
514
|
const afterHooks = this.deps.hooks.resolve(
|
|
297
515
|
"orders.afterCreate",
|
|
298
516
|
) as AfterCreateOrderHook[];
|
|
299
|
-
const hookCtx = context(actor, this.deps.services, this.deps.database, ctx?.tx);
|
|
517
|
+
const hookCtx = context(actor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx);
|
|
300
518
|
|
|
301
519
|
const processed = await runBeforeHooks(
|
|
302
520
|
beforeHooks,
|
|
303
|
-
|
|
521
|
+
serviceInput,
|
|
304
522
|
"create",
|
|
305
523
|
hookCtx,
|
|
306
524
|
);
|
|
307
525
|
|
|
308
|
-
const orgId =
|
|
526
|
+
const orgId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
527
|
+
const idempotencyScope = processed.idempotencyKey
|
|
528
|
+
? await makeIdempotencyScope(
|
|
529
|
+
actor,
|
|
530
|
+
opts?.guestCredential,
|
|
531
|
+
typeof processed.metadata?.cartId === "string"
|
|
532
|
+
? processed.metadata.cartId
|
|
533
|
+
: undefined,
|
|
534
|
+
)
|
|
535
|
+
: undefined;
|
|
309
536
|
|
|
310
537
|
// Idempotent replay: offline POS queues and network retries re-submit the
|
|
311
538
|
// same create — return the original order instead of double-creating.
|
|
@@ -313,10 +540,16 @@ export class OrderService {
|
|
|
313
540
|
const existing = await this.repo.findByIdempotencyKey(
|
|
314
541
|
orgId,
|
|
315
542
|
processed.idempotencyKey,
|
|
543
|
+
idempotencyScope!,
|
|
316
544
|
ctx,
|
|
317
545
|
);
|
|
318
546
|
if (existing) {
|
|
319
|
-
return
|
|
547
|
+
return this.authorizedReplay(
|
|
548
|
+
existing,
|
|
549
|
+
actor,
|
|
550
|
+
ctx,
|
|
551
|
+
opts?.guestCredential,
|
|
552
|
+
);
|
|
320
553
|
}
|
|
321
554
|
}
|
|
322
555
|
|
|
@@ -394,6 +627,7 @@ export class OrderService {
|
|
|
394
627
|
...(processed.paymentIntentId != null ? { paymentIntentId: processed.paymentIntentId } : {}),
|
|
395
628
|
...(processed.paymentMethodId != null ? { paymentMethodId: processed.paymentMethodId } : {}),
|
|
396
629
|
...(processed.idempotencyKey != null ? { idempotencyKey: processed.idempotencyKey } : {}),
|
|
630
|
+
...(idempotencyScope !== undefined ? { idempotencyScope } : {}),
|
|
397
631
|
metadata: processed.metadata ?? {},
|
|
398
632
|
placedAt: new Date(),
|
|
399
633
|
...(processed.customerId !== undefined
|
|
@@ -408,9 +642,17 @@ export class OrderService {
|
|
|
408
642
|
const winner = await this.repo.findByIdempotencyKey(
|
|
409
643
|
orgId,
|
|
410
644
|
processed.idempotencyKey,
|
|
645
|
+
idempotencyScope!,
|
|
411
646
|
ctx,
|
|
412
647
|
);
|
|
413
|
-
if (winner)
|
|
648
|
+
if (winner) {
|
|
649
|
+
return this.authorizedReplay(
|
|
650
|
+
winner,
|
|
651
|
+
actor,
|
|
652
|
+
ctx,
|
|
653
|
+
opts?.guestCredential,
|
|
654
|
+
);
|
|
655
|
+
}
|
|
414
656
|
}
|
|
415
657
|
throw error;
|
|
416
658
|
}
|
|
@@ -503,25 +745,19 @@ export class OrderService {
|
|
|
503
745
|
id: string,
|
|
504
746
|
actor: Actor | null,
|
|
505
747
|
ctx?: TxContext,
|
|
748
|
+
guestCredential?: string,
|
|
506
749
|
): Promise<Result<HydratedOrder>> {
|
|
507
|
-
const orgId =
|
|
750
|
+
const orgId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
508
751
|
const order = await this.repo.findById(orgId, id, ctx);
|
|
509
752
|
if (!order) return Err(new CommerceNotFoundError("Order not found."));
|
|
510
753
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
assertOwnership(actor, order.customerId ?? null);
|
|
519
|
-
} else {
|
|
520
|
-
assertPermission(actor, "orders:read");
|
|
521
|
-
}
|
|
522
|
-
} catch (error) {
|
|
523
|
-
return Err(toCommerceError(error));
|
|
524
|
-
}
|
|
754
|
+
const access = await this.authorizeOrderRead(
|
|
755
|
+
order,
|
|
756
|
+
actor,
|
|
757
|
+
ctx,
|
|
758
|
+
guestCredential,
|
|
759
|
+
);
|
|
760
|
+
if (!access.ok) return access;
|
|
525
761
|
|
|
526
762
|
const hydrated = await this.hydrateOrder(order, ctx);
|
|
527
763
|
|
|
@@ -530,7 +766,7 @@ export class OrderService {
|
|
|
530
766
|
"orders.afterGet",
|
|
531
767
|
) as AfterHook<HydratedOrder>[];
|
|
532
768
|
if (afterGetHooks.length > 0) {
|
|
533
|
-
const hookCtx = context(actor, this.deps.services, this.deps.database, ctx?.tx);
|
|
769
|
+
const hookCtx = context(actor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx);
|
|
534
770
|
await runAfterHooks(afterGetHooks, null, hydrated, "read", hookCtx);
|
|
535
771
|
}
|
|
536
772
|
|
|
@@ -541,11 +777,12 @@ export class OrderService {
|
|
|
541
777
|
orderNumber: string,
|
|
542
778
|
actor: Actor | null,
|
|
543
779
|
ctx?: TxContext,
|
|
780
|
+
guestCredential?: string,
|
|
544
781
|
): Promise<Result<HydratedOrder>> {
|
|
545
|
-
const orgId =
|
|
782
|
+
const orgId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
546
783
|
const order = await this.repo.findByOrderNumber(orgId, orderNumber, ctx);
|
|
547
784
|
if (!order) return Err(new CommerceNotFoundError("Order not found."));
|
|
548
|
-
return this.getById(order.id, actor, ctx);
|
|
785
|
+
return this.getById(order.id, actor, ctx, guestCredential);
|
|
549
786
|
}
|
|
550
787
|
|
|
551
788
|
/** Returns the order previously created with this idempotency key, or null. */
|
|
@@ -553,11 +790,24 @@ export class OrderService {
|
|
|
553
790
|
idempotencyKey: string,
|
|
554
791
|
actor?: Actor | null,
|
|
555
792
|
ctx?: TxContext,
|
|
793
|
+
guestCredential?: string,
|
|
556
794
|
): Promise<Result<HydratedOrder | null>> {
|
|
557
|
-
const orgId =
|
|
558
|
-
const
|
|
795
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
796
|
+
const resolvedActor = actor ?? ctx?.actor ?? null;
|
|
797
|
+
const idempotencyScope = await makeIdempotencyScope(resolvedActor, guestCredential);
|
|
798
|
+
const order = await this.repo.findByIdempotencyKey(
|
|
799
|
+
orgId,
|
|
800
|
+
idempotencyKey,
|
|
801
|
+
idempotencyScope,
|
|
802
|
+
ctx,
|
|
803
|
+
);
|
|
559
804
|
if (!order) return Ok(null);
|
|
560
|
-
return
|
|
805
|
+
return this.authorizedReplay(
|
|
806
|
+
order,
|
|
807
|
+
actor ?? ctx?.actor ?? null,
|
|
808
|
+
ctx,
|
|
809
|
+
guestCredential,
|
|
810
|
+
);
|
|
561
811
|
}
|
|
562
812
|
|
|
563
813
|
async list(
|
|
@@ -571,7 +821,7 @@ export class OrderService {
|
|
|
571
821
|
return Err(toCommerceError(error));
|
|
572
822
|
}
|
|
573
823
|
|
|
574
|
-
const orgId =
|
|
824
|
+
const orgId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
575
825
|
let items: Order[];
|
|
576
826
|
if (params.status) {
|
|
577
827
|
items = await this.repo.findByStatus(orgId, params.status, ctx);
|
|
@@ -599,7 +849,7 @@ export class OrderService {
|
|
|
599
849
|
actor?: Actor | null,
|
|
600
850
|
ctx?: TxContext,
|
|
601
851
|
): Promise<Result<OrderListResult>> {
|
|
602
|
-
const orgId =
|
|
852
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
603
853
|
let items = await this.repo.findByCustomerId(orgId, customerId, ctx);
|
|
604
854
|
|
|
605
855
|
if (params.status) {
|
|
@@ -670,7 +920,7 @@ export class OrderService {
|
|
|
670
920
|
return Ok({ items: [], hint: "Enter at least 3 characters to search." });
|
|
671
921
|
}
|
|
672
922
|
|
|
673
|
-
const orgId =
|
|
923
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
674
924
|
const rows = await this.repo.lookup(orgId, term, opts, ctx);
|
|
675
925
|
const items = rows.map((r) => ({
|
|
676
926
|
id: r.id,
|
|
@@ -694,7 +944,7 @@ export class OrderService {
|
|
|
694
944
|
actor: Actor | null,
|
|
695
945
|
ctx?: TxContext,
|
|
696
946
|
): Promise<Result<HydratedOrder>> {
|
|
697
|
-
const orgId =
|
|
947
|
+
const orgId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
698
948
|
const order = await this.repo.findById(orgId, input.orderId, ctx);
|
|
699
949
|
if (!order) return Err(new CommerceNotFoundError("Order not found."));
|
|
700
950
|
|
|
@@ -725,7 +975,7 @@ export class OrderService {
|
|
|
725
975
|
"orders.afterStatusChange",
|
|
726
976
|
) as AfterStatusChangeHook[];
|
|
727
977
|
|
|
728
|
-
const hookCtx = context(actor, this.deps.services, this.deps.database, ctx?.tx);
|
|
978
|
+
const hookCtx = context(actor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx);
|
|
729
979
|
const statusHookInput: StatusChangeHookInput = {
|
|
730
980
|
orderId: order.id,
|
|
731
981
|
fromStatus: order.status as OrderState,
|
|
@@ -1057,7 +1307,7 @@ export class OrderService {
|
|
|
1057
1307
|
} catch (error) {
|
|
1058
1308
|
return Err(toCommerceError(error));
|
|
1059
1309
|
}
|
|
1060
|
-
const orgId =
|
|
1310
|
+
const orgId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
1061
1311
|
const found = await this.repo.findWithLineItems(orgId, orderId, ctx);
|
|
1062
1312
|
if (!found) return Err(new CommerceNotFoundError("Order not found."));
|
|
1063
1313
|
if (input.lines.length === 0) {
|
|
@@ -1206,7 +1456,7 @@ export class OrderService {
|
|
|
1206
1456
|
} catch (error) {
|
|
1207
1457
|
return Err(toCommerceError(error));
|
|
1208
1458
|
}
|
|
1209
|
-
const orgId =
|
|
1459
|
+
const orgId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
1210
1460
|
const refund = await this.repo.findRefundById(orgId, refundId, ctx);
|
|
1211
1461
|
if (!refund || refund.orderId !== orderId) {
|
|
1212
1462
|
return Err(new CommerceNotFoundError("Refund not found."));
|
|
@@ -1265,7 +1515,7 @@ export class OrderService {
|
|
|
1265
1515
|
} catch (error) {
|
|
1266
1516
|
return Err(toCommerceError(error));
|
|
1267
1517
|
}
|
|
1268
|
-
const orgId =
|
|
1518
|
+
const orgId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
1269
1519
|
const order = await this.repo.findById(orgId, orderId, ctx);
|
|
1270
1520
|
if (!order) return Err(new CommerceNotFoundError("Order not found."));
|
|
1271
1521
|
return Ok(await this.repo.findRefundsByOrderId(orderId, ctx));
|
|
@@ -1281,7 +1531,7 @@ export class OrderService {
|
|
|
1281
1531
|
} catch (error) {
|
|
1282
1532
|
return Err(toCommerceError(error));
|
|
1283
1533
|
}
|
|
1284
|
-
const orgId =
|
|
1534
|
+
const orgId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
1285
1535
|
const policies = await this.refundPolicies(orgId, ctx);
|
|
1286
1536
|
const usedToday = await this.repo.sumRefundsByOperatorToday(
|
|
1287
1537
|
orgId,
|
|
@@ -1309,7 +1559,7 @@ export class OrderService {
|
|
|
1309
1559
|
} catch (error) {
|
|
1310
1560
|
return Err(toCommerceError(error));
|
|
1311
1561
|
}
|
|
1312
|
-
const orgId =
|
|
1562
|
+
const orgId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
1313
1563
|
const order = await this.repo.findById(orgId, orderId, ctx);
|
|
1314
1564
|
if (!order) return Err(new CommerceNotFoundError("Order not found."));
|
|
1315
1565
|
return Ok(order);
|
|
@@ -1446,7 +1696,7 @@ export class OrderService {
|
|
|
1446
1696
|
opts?: { amount?: number },
|
|
1447
1697
|
ctx?: TxContext,
|
|
1448
1698
|
): Promise<Result<HydratedOrder>> {
|
|
1449
|
-
const orgId =
|
|
1699
|
+
const orgId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
1450
1700
|
const order = await this.repo.findById(orgId, orderId, ctx);
|
|
1451
1701
|
if (!order) return Err(new CommerceNotFoundError("Order not found."));
|
|
1452
1702
|
|
|
@@ -1515,7 +1765,7 @@ export class OrderService {
|
|
|
1515
1765
|
actor?: Actor | null,
|
|
1516
1766
|
ctx?: TxContext,
|
|
1517
1767
|
): Promise<Result<OrderStatusHistory[]>> {
|
|
1518
|
-
const orgId =
|
|
1768
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
1519
1769
|
const order = await this.repo.findById(orgId, orderId, ctx);
|
|
1520
1770
|
if (!order) {
|
|
1521
1771
|
return Err(new CommerceNotFoundError("Order not found."));
|
|
@@ -1611,7 +1861,7 @@ export class OrderService {
|
|
|
1611
1861
|
} catch (error) {
|
|
1612
1862
|
return Err(toCommerceError(error));
|
|
1613
1863
|
}
|
|
1614
|
-
const orgId =
|
|
1864
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
1615
1865
|
const order = await this.repo.findById(orgId, orderId, ctx);
|
|
1616
1866
|
if (!order) return Err(new CommerceNotFoundError("Order not found."));
|
|
1617
1867
|
const guard = this.lineItemEditGuard(order);
|
|
@@ -1690,7 +1940,7 @@ export class OrderService {
|
|
|
1690
1940
|
} catch (error) {
|
|
1691
1941
|
return Err(toCommerceError(error));
|
|
1692
1942
|
}
|
|
1693
|
-
const orgId =
|
|
1943
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
1694
1944
|
const order = await this.repo.findById(orgId, orderId, ctx);
|
|
1695
1945
|
if (!order) return Err(new CommerceNotFoundError("Order not found."));
|
|
1696
1946
|
const guard = this.lineItemEditGuard(order);
|
|
@@ -1737,7 +1987,7 @@ export class OrderService {
|
|
|
1737
1987
|
} catch (error) {
|
|
1738
1988
|
return Err(toCommerceError(error));
|
|
1739
1989
|
}
|
|
1740
|
-
const orgId =
|
|
1990
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
1741
1991
|
const order = await this.repo.findById(orgId, orderId, ctx);
|
|
1742
1992
|
if (!order) return Err(new CommerceNotFoundError("Order not found."));
|
|
1743
1993
|
const guard = this.lineItemEditGuard(order);
|
|
@@ -1776,7 +2026,7 @@ export class OrderService {
|
|
|
1776
2026
|
actor?: Actor | null,
|
|
1777
2027
|
ctx?: TxContext,
|
|
1778
2028
|
): Promise<Result<Order>> {
|
|
1779
|
-
const orgId =
|
|
2029
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
1780
2030
|
const order = await this.repo.findById(orgId, orderId, ctx);
|
|
1781
2031
|
if (!order) {
|
|
1782
2032
|
return Err(new CommerceNotFoundError("Order not found."));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CommerceConfig } from "../../config/types.js";
|
|
1
2
|
import type { DrizzleDatabase } from "../../kernel/database/drizzle-db.js";
|
|
2
3
|
import { defineModule } from "../../kernel/module/index.js";
|
|
3
4
|
import type { CatalogRepository } from "../catalog/repository/index.js";
|
|
@@ -24,6 +25,7 @@ export const pricingModule = defineModule<
|
|
|
24
25
|
repository: new PricingRepository(deps.db.db as DrizzleDatabase),
|
|
25
26
|
catalogRepository: deps.services.catalog.repository,
|
|
26
27
|
hooks: deps.hooks,
|
|
28
|
+
config: deps.config as CommerceConfig,
|
|
27
29
|
services: deps.services,
|
|
28
30
|
database: deps.db,
|
|
29
31
|
}),
|