@porulle/core 0.11.0 → 0.13.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/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 +13 -5
- 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 +17 -0
- 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 +30 -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 +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -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/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 +6 -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 +1 -0
- 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 +10 -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/auth-schema-guard.ts +143 -0
- package/src/auth/auth-schema.ts +50 -19
- package/src/auth/middleware.ts +17 -5
- 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 +17 -0
- 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 +29 -4
- package/src/hooks/checkout.ts +19 -12
- package/src/index.ts +16 -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/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 +6 -0
- package/src/modules/search/module.ts +1 -0
- 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 +16 -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,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
2
2
|
import { assertPermission } from "../../auth/permissions.js";
|
|
3
3
|
import type { Actor } from "../../auth/types.js";
|
|
4
|
+
import type { CommerceConfig } from "../../config/types.js";
|
|
4
5
|
import { CommerceNotFoundError, toCommerceError } from "../../kernel/errors.js";
|
|
5
6
|
import { runAfterHooks } from "../../kernel/hooks/executor.js";
|
|
6
7
|
import { createHookContext } from "../../kernel/hooks/create-context.js";
|
|
@@ -22,6 +23,7 @@ import type {
|
|
|
22
23
|
interface CustomerServiceDeps {
|
|
23
24
|
repository: CustomersRepository;
|
|
24
25
|
hooks: HookRegistry;
|
|
26
|
+
config: CommerceConfig;
|
|
25
27
|
services: Record<string, unknown>;
|
|
26
28
|
database: DatabaseAdapter;
|
|
27
29
|
}
|
|
@@ -30,6 +32,7 @@ function hookContext(
|
|
|
30
32
|
actor: Actor | null,
|
|
31
33
|
services: Record<string, unknown>,
|
|
32
34
|
database: DatabaseAdapter,
|
|
35
|
+
config: CommerceConfig,
|
|
33
36
|
tx: unknown,
|
|
34
37
|
): HookContext {
|
|
35
38
|
return createHookContext({
|
|
@@ -39,6 +42,7 @@ function hookContext(
|
|
|
39
42
|
services,
|
|
40
43
|
context: { moduleName: "customers" },
|
|
41
44
|
database: { db: database.db as PluginDb },
|
|
45
|
+
commerceConfig: config,
|
|
42
46
|
});
|
|
43
47
|
}
|
|
44
48
|
|
|
@@ -73,7 +77,7 @@ export class CustomerService {
|
|
|
73
77
|
return Err(toCommerceError(error));
|
|
74
78
|
}
|
|
75
79
|
|
|
76
|
-
const orgId =
|
|
80
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
77
81
|
const isWalkIn = input.userId === undefined;
|
|
78
82
|
const userId = input.userId ?? `anonymous_${crypto.randomUUID()}`;
|
|
79
83
|
const metadata = {
|
|
@@ -97,7 +101,7 @@ export class CustomerService {
|
|
|
97
101
|
const afterHooks = this.deps.hooks.resolve(
|
|
98
102
|
"customers.afterCreate",
|
|
99
103
|
) as AfterHook<Customer>[];
|
|
100
|
-
const hctx = hookContext(actor ?? null, this.deps.services, this.deps.database, ctx?.tx ?? null);
|
|
104
|
+
const hctx = hookContext(actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
101
105
|
await runAfterHooks(afterHooks, null, customer, "create", hctx);
|
|
102
106
|
|
|
103
107
|
return Ok(customer);
|
|
@@ -107,7 +111,7 @@ export class CustomerService {
|
|
|
107
111
|
|
|
108
112
|
async listInteractions(customerId: string, actor?: Actor | null, ctx?: TxContext): Promise<Result<CustomerInteraction[]>> {
|
|
109
113
|
try { assertPermission(actor ?? null, "customers:read"); } catch (error) { return Err(toCommerceError(error)); }
|
|
110
|
-
const orgId =
|
|
114
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
111
115
|
return Ok(await this.repo.listInteractions(orgId, customerId, ctx));
|
|
112
116
|
}
|
|
113
117
|
|
|
@@ -118,7 +122,7 @@ export class CustomerService {
|
|
|
118
122
|
ctx?: TxContext,
|
|
119
123
|
): Promise<Result<CustomerInteraction>> {
|
|
120
124
|
try { assertPermission(actor ?? null, "customers:update"); } catch (error) { return Err(toCommerceError(error)); }
|
|
121
|
-
const orgId =
|
|
125
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
122
126
|
const customer = await this.repo.findById(orgId, customerId, ctx);
|
|
123
127
|
if (!customer) return Err(new CommerceNotFoundError("Customer not found."));
|
|
124
128
|
const interaction = await this.repo.createInteraction(
|
|
@@ -144,7 +148,7 @@ export class CustomerService {
|
|
|
144
148
|
ctx?: TxContext,
|
|
145
149
|
): Promise<Result<CustomerInteraction>> {
|
|
146
150
|
try { assertPermission(actor ?? null, "customers:update"); } catch (error) { return Err(toCommerceError(error)); }
|
|
147
|
-
const orgId =
|
|
151
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
148
152
|
const existing = await this.repo.findInteractionById(orgId, interactionId, ctx);
|
|
149
153
|
if (!existing || existing.customerId !== customerId) return Err(new CommerceNotFoundError("Interaction not found."));
|
|
150
154
|
const patch = {
|
|
@@ -160,7 +164,7 @@ export class CustomerService {
|
|
|
160
164
|
|
|
161
165
|
async deleteInteraction(customerId: string, interactionId: string, actor?: Actor | null, ctx?: TxContext): Promise<Result<void>> {
|
|
162
166
|
try { assertPermission(actor ?? null, "customers:update"); } catch (error) { return Err(toCommerceError(error)); }
|
|
163
|
-
const orgId =
|
|
167
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
164
168
|
const existing = await this.repo.findInteractionById(orgId, interactionId, ctx);
|
|
165
169
|
if (!existing || existing.customerId !== customerId) return Err(new CommerceNotFoundError("Interaction not found."));
|
|
166
170
|
await this.repo.deleteInteraction(orgId, interactionId, ctx);
|
|
@@ -190,7 +194,7 @@ export class CustomerService {
|
|
|
190
194
|
const afterHooks = this.deps.hooks.resolve(
|
|
191
195
|
"customers.afterCreate",
|
|
192
196
|
) as AfterHook<Customer>[];
|
|
193
|
-
const hctx = hookContext(actor, this.deps.services, this.deps.database, ctx?.tx ?? null);
|
|
197
|
+
const hctx = hookContext(actor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
194
198
|
await runAfterHooks(afterHooks, null, customer, "create", hctx);
|
|
195
199
|
|
|
196
200
|
return customer;
|
|
@@ -200,7 +204,7 @@ export class CustomerService {
|
|
|
200
204
|
actor?: Actor | null,
|
|
201
205
|
ctx?: TxContext,
|
|
202
206
|
): Promise<Result<Customer[]>> {
|
|
203
|
-
const orgId =
|
|
207
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
204
208
|
const customers = await this.repo.findAll(orgId, ctx);
|
|
205
209
|
return Ok(customers);
|
|
206
210
|
}
|
|
@@ -210,7 +214,7 @@ export class CustomerService {
|
|
|
210
214
|
actor?: Actor | null,
|
|
211
215
|
ctx?: TxContext,
|
|
212
216
|
): Promise<Result<Customer>> {
|
|
213
|
-
const orgId =
|
|
217
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
214
218
|
const customer = await this.repo.findById(orgId, id, ctx);
|
|
215
219
|
if (!customer) return Err(new CommerceNotFoundError("Customer not found."));
|
|
216
220
|
return Ok(customer);
|
|
@@ -221,7 +225,7 @@ export class CustomerService {
|
|
|
221
225
|
actor?: Actor | null,
|
|
222
226
|
ctx?: TxContext,
|
|
223
227
|
): Promise<Result<Customer>> {
|
|
224
|
-
const orgId =
|
|
228
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
225
229
|
const resolvedActor = actor ?? ctx?.actor ?? null;
|
|
226
230
|
const customer = await this.getOrCreateByUserId(
|
|
227
231
|
orgId,
|
|
@@ -247,7 +251,7 @@ export class CustomerService {
|
|
|
247
251
|
return Err(toCommerceError(error));
|
|
248
252
|
}
|
|
249
253
|
|
|
250
|
-
const orgId =
|
|
254
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
251
255
|
const existing = await this.repo.findById(orgId, id, ctx);
|
|
252
256
|
if (!existing) return Err(new CommerceNotFoundError("Customer not found."));
|
|
253
257
|
|
|
@@ -271,10 +275,7 @@ export class CustomerService {
|
|
|
271
275
|
"customers.afterUpdate",
|
|
272
276
|
) as AfterHook<Customer>[];
|
|
273
277
|
const hctx = hookContext(
|
|
274
|
-
actor ?? ctx?.actor ?? null,
|
|
275
|
-
this.deps.services,
|
|
276
|
-
this.deps.database,
|
|
277
|
-
ctx?.tx ?? null,
|
|
278
|
+
actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null,
|
|
278
279
|
);
|
|
279
280
|
await runAfterHooks(afterHooks, existing, updated, "update", hctx);
|
|
280
281
|
|
|
@@ -289,7 +290,7 @@ export class CustomerService {
|
|
|
289
290
|
actor?: Actor | null,
|
|
290
291
|
ctx?: TxContext,
|
|
291
292
|
): Promise<Result<Customer>> {
|
|
292
|
-
const orgId =
|
|
293
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
293
294
|
const resolvedActor = actor ?? ctx?.actor ?? null;
|
|
294
295
|
const customer = await this.getOrCreateByUserId(
|
|
295
296
|
orgId,
|
|
@@ -306,7 +307,7 @@ export class CustomerService {
|
|
|
306
307
|
const afterHooks = this.deps.hooks.resolve(
|
|
307
308
|
"customers.afterUpdate",
|
|
308
309
|
) as AfterHook<Customer>[];
|
|
309
|
-
const hctx = hookContext(resolvedActor, this.deps.services, this.deps.database, ctx?.tx ?? null);
|
|
310
|
+
const hctx = hookContext(resolvedActor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
310
311
|
await runAfterHooks(afterHooks, customer, updated, "update", hctx);
|
|
311
312
|
|
|
312
313
|
return Ok(updated);
|
|
@@ -317,7 +318,7 @@ export class CustomerService {
|
|
|
317
318
|
actor?: Actor | null,
|
|
318
319
|
ctx?: TxContext,
|
|
319
320
|
): Promise<Result<CustomerAddress[]>> {
|
|
320
|
-
const orgId =
|
|
321
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
321
322
|
const resolvedActor = actor ?? ctx?.actor ?? null;
|
|
322
323
|
const customer = await this.getOrCreateByUserId(
|
|
323
324
|
orgId,
|
|
@@ -338,7 +339,7 @@ export class CustomerService {
|
|
|
338
339
|
actor?: Actor | null,
|
|
339
340
|
ctx?: TxContext,
|
|
340
341
|
): Promise<Result<CustomerAddress>> {
|
|
341
|
-
const orgId =
|
|
342
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
342
343
|
const resolvedActor = actor ?? ctx?.actor ?? null;
|
|
343
344
|
const customer = await this.getOrCreateByUserId(
|
|
344
345
|
orgId,
|
|
@@ -376,7 +377,7 @@ export class CustomerService {
|
|
|
376
377
|
actor?: Actor | null,
|
|
377
378
|
ctx?: TxContext,
|
|
378
379
|
): Promise<Result<void>> {
|
|
379
|
-
const orgId =
|
|
380
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
380
381
|
const resolvedActor = actor ?? ctx?.actor ?? null;
|
|
381
382
|
const customer = await this.getOrCreateByUserId(
|
|
382
383
|
orgId,
|
|
@@ -403,7 +404,7 @@ export class CustomerService {
|
|
|
403
404
|
actor?: Actor | null,
|
|
404
405
|
ctx?: TxContext,
|
|
405
406
|
): Promise<{ id: string; name: string } | null> {
|
|
406
|
-
const orgId =
|
|
407
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
407
408
|
const user = await this.repo.findByPosPin(orgId, hashedPin, ctx);
|
|
408
409
|
if (!user) return null;
|
|
409
410
|
return {
|
|
@@ -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 { DocumentsRepository } from "./repository/index.js";
|
|
@@ -15,5 +16,6 @@ export const documentsModule = defineModule<
|
|
|
15
16
|
new DocumentsService({
|
|
16
17
|
repository: new DocumentsRepository(deps.db.db as DrizzleDatabase),
|
|
17
18
|
services: deps.services as Record<string, unknown>,
|
|
19
|
+
config: deps.config as CommerceConfig,
|
|
18
20
|
}),
|
|
19
21
|
});
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
2
2
|
import type { Actor } from "../../auth/types.js";
|
|
3
|
+
import type { CommerceConfig } from "../../config/types.js";
|
|
3
4
|
import type { TxContext } from "../../kernel/database/tx-context.js";
|
|
4
|
-
import {
|
|
5
|
+
import { hasPermission } from "../../auth/permissions.js";
|
|
6
|
+
import { CommerceForbiddenError, CommerceValidationError } from "../../kernel/errors.js";
|
|
5
7
|
import { Err, Ok, type Result } from "../../kernel/result.js";
|
|
6
8
|
import type { HydratedOrder, OrderService } from "../orders/service.js";
|
|
7
9
|
import type { SettingsService } from "../settings/service.js";
|
|
@@ -19,6 +21,15 @@ interface DocumentsServiceDeps {
|
|
|
19
21
|
// The shared kernel service container — orders/settings/email are resolved
|
|
20
22
|
// at call time (they may instantiate after this module).
|
|
21
23
|
services: Record<string, unknown>;
|
|
24
|
+
config: CommerceConfig;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface CustomerLookup {
|
|
28
|
+
getById(
|
|
29
|
+
id: string,
|
|
30
|
+
actor?: Actor | null,
|
|
31
|
+
ctx?: TxContext,
|
|
32
|
+
): Promise<{ ok: true; value: { email: string | null } } | { ok: false }>;
|
|
22
33
|
}
|
|
23
34
|
|
|
24
35
|
interface EmailAdapter {
|
|
@@ -33,10 +44,12 @@ const DEFAULT_INVOICE_PREFIX = "INV-";
|
|
|
33
44
|
export class DocumentsService {
|
|
34
45
|
private repository: DocumentsRepository;
|
|
35
46
|
private services: Record<string, unknown>;
|
|
47
|
+
private config: CommerceConfig;
|
|
36
48
|
|
|
37
49
|
constructor(deps: DocumentsServiceDeps) {
|
|
38
50
|
this.repository = deps.repository;
|
|
39
51
|
this.services = deps.services;
|
|
52
|
+
this.config = deps.config;
|
|
40
53
|
}
|
|
41
54
|
|
|
42
55
|
private get orders(): OrderService {
|
|
@@ -90,16 +103,18 @@ export class DocumentsService {
|
|
|
90
103
|
orderId: string,
|
|
91
104
|
actor: Actor | null,
|
|
92
105
|
ctx?: TxContext,
|
|
106
|
+
guestCredential?: string,
|
|
93
107
|
): Promise<Result<HydratedOrder>> {
|
|
94
|
-
return this.orders.getById(orderId, actor, ctx);
|
|
108
|
+
return this.orders.getById(orderId, actor, ctx, guestCredential);
|
|
95
109
|
}
|
|
96
110
|
|
|
97
111
|
async renderInvoiceHtml(
|
|
98
112
|
orderId: string,
|
|
99
113
|
actor: Actor | null,
|
|
100
114
|
ctx?: TxContext,
|
|
115
|
+
guestCredential?: string,
|
|
101
116
|
): Promise<Result<{ html: string; invoiceNumber: string }>> {
|
|
102
|
-
const order = await this.loadOrder(orderId, actor, ctx);
|
|
117
|
+
const order = await this.loadOrder(orderId, actor, ctx, guestCredential);
|
|
103
118
|
if (!order.ok) return order;
|
|
104
119
|
const branding = await this.brandingFor(order.value.organizationId, ctx);
|
|
105
120
|
const doc = await this.issueInvoiceNumber(order.value, ctx);
|
|
@@ -113,8 +128,9 @@ export class DocumentsService {
|
|
|
113
128
|
orderId: string,
|
|
114
129
|
actor: Actor | null,
|
|
115
130
|
ctx?: TxContext,
|
|
131
|
+
guestCredential?: string,
|
|
116
132
|
): Promise<Result<{ pdf: Uint8Array; invoiceNumber: string }>> {
|
|
117
|
-
const order = await this.loadOrder(orderId, actor, ctx);
|
|
133
|
+
const order = await this.loadOrder(orderId, actor, ctx, guestCredential);
|
|
118
134
|
if (!order.ok) return order;
|
|
119
135
|
const branding = await this.brandingFor(order.value.organizationId, ctx);
|
|
120
136
|
const doc = await this.issueInvoiceNumber(order.value, ctx);
|
|
@@ -130,39 +146,86 @@ export class DocumentsService {
|
|
|
130
146
|
orderId: string,
|
|
131
147
|
actor: Actor | null,
|
|
132
148
|
ctx?: TxContext,
|
|
149
|
+
guestCredential?: string,
|
|
133
150
|
): Promise<Result<{ html: string }>> {
|
|
134
|
-
const order = await this.loadOrder(orderId, actor, ctx);
|
|
151
|
+
const order = await this.loadOrder(orderId, actor, ctx, guestCredential);
|
|
135
152
|
if (!order.ok) return order;
|
|
136
153
|
const branding = await this.brandingFor(order.value.organizationId, ctx);
|
|
137
154
|
return Ok({ html: receiptHtml({ order: order.value, branding }) });
|
|
138
155
|
}
|
|
139
156
|
|
|
157
|
+
/**
|
|
158
|
+
* The address that belongs to this order: its customer profile's email.
|
|
159
|
+
* A guest order has no customer profile and therefore no address of its own.
|
|
160
|
+
*/
|
|
161
|
+
private async orderEmail(
|
|
162
|
+
order: HydratedOrder,
|
|
163
|
+
actor: Actor | null,
|
|
164
|
+
ctx?: TxContext,
|
|
165
|
+
): Promise<string | null> {
|
|
166
|
+
if (!order.customerId) return null;
|
|
167
|
+
const customers = this.services.customers as CustomerLookup | undefined;
|
|
168
|
+
if (!customers) return null;
|
|
169
|
+
const customer = await customers.getById(order.customerId, actor, ctx);
|
|
170
|
+
return customer.ok ? (customer.value.email ?? null) : null;
|
|
171
|
+
}
|
|
172
|
+
|
|
140
173
|
/**
|
|
141
174
|
* Emails the invoice via the configured email adapter. The adapter's
|
|
142
175
|
* template contract is (template, to, data) — the rendered HTML and the
|
|
143
176
|
* fiscal number ride in `data` so template-based adapters can use either.
|
|
177
|
+
*
|
|
178
|
+
* The destination is the order's own address, not the caller's choice. A
|
|
179
|
+
* cart secret authorizes reading an order, and a caller-supplied `to` turned
|
|
180
|
+
* that read into delivery: items, totals and shipping address mailed to any
|
|
181
|
+
* address, with nothing left in the shopper's inbox. Only staff holding
|
|
182
|
+
* org-wide `orders:read` may name a different recipient.
|
|
144
183
|
*/
|
|
145
184
|
async emailInvoice(
|
|
146
185
|
orderId: string,
|
|
147
186
|
to: string,
|
|
148
187
|
actor: Actor | null,
|
|
149
188
|
ctx?: TxContext,
|
|
189
|
+
guestCredential?: string,
|
|
150
190
|
): Promise<Result<{ sent: true; invoiceNumber: string; to: string }>> {
|
|
151
191
|
const email = this.services.email as EmailAdapter | undefined;
|
|
152
192
|
if (!email) {
|
|
153
193
|
return Err(new CommerceValidationError("No email adapter is configured."));
|
|
154
194
|
}
|
|
155
|
-
const rendered = await this.renderInvoiceHtml(orderId, actor, ctx);
|
|
195
|
+
const rendered = await this.renderInvoiceHtml(orderId, actor, ctx, guestCredential);
|
|
156
196
|
if (!rendered.ok) return rendered;
|
|
157
197
|
|
|
158
|
-
const order = await this.loadOrder(orderId, actor, ctx);
|
|
198
|
+
const order = await this.loadOrder(orderId, actor, ctx, guestCredential);
|
|
159
199
|
if (!order.ok) return order;
|
|
160
200
|
|
|
201
|
+
const ownAddress = await this.orderEmail(order.value, actor, ctx);
|
|
202
|
+
const mayDirect = hasPermission(actor, "orders:read");
|
|
203
|
+
const requested = to.trim();
|
|
204
|
+
|
|
205
|
+
let destination: string;
|
|
206
|
+
if (mayDirect && requested.length > 0) {
|
|
207
|
+
destination = requested;
|
|
208
|
+
} else if (ownAddress === null) {
|
|
209
|
+
return Err(
|
|
210
|
+
new CommerceValidationError(
|
|
211
|
+
"This order has no email address of its own. Render the invoice instead, or send it as staff.",
|
|
212
|
+
),
|
|
213
|
+
);
|
|
214
|
+
} else if (requested.length > 0 && requested.toLowerCase() !== ownAddress.toLowerCase()) {
|
|
215
|
+
return Err(
|
|
216
|
+
new CommerceForbiddenError(
|
|
217
|
+
"An invoice can only be emailed to the address on the order.",
|
|
218
|
+
),
|
|
219
|
+
);
|
|
220
|
+
} else {
|
|
221
|
+
destination = ownAddress;
|
|
222
|
+
}
|
|
223
|
+
|
|
161
224
|
await email.send({
|
|
162
225
|
template: "order-invoice",
|
|
163
|
-
to,
|
|
226
|
+
to: destination,
|
|
164
227
|
data: {
|
|
165
|
-
orgId:
|
|
228
|
+
orgId: resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config),
|
|
166
229
|
orderId,
|
|
167
230
|
orderNumber: order.value.orderNumber,
|
|
168
231
|
invoiceNumber: rendered.value.invoiceNumber,
|
|
@@ -171,6 +234,6 @@ export class DocumentsService {
|
|
|
171
234
|
html: rendered.value.html,
|
|
172
235
|
},
|
|
173
236
|
});
|
|
174
|
-
return Ok({ sent: true, invoiceNumber: rendered.value.invoiceNumber, to });
|
|
237
|
+
return Ok({ sent: true, invoiceNumber: rendered.value.invoiceNumber, to: destination });
|
|
175
238
|
}
|
|
176
239
|
}
|
|
@@ -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 { InventoryService } from "../inventory/service.js";
|
|
@@ -36,6 +37,7 @@ export const fulfillmentModule = defineModule<
|
|
|
36
37
|
ordersRepository: new OrdersRepository(deps.db.db as DrizzleDatabase),
|
|
37
38
|
inventoryService: deps.services.inventory,
|
|
38
39
|
hooks: deps.hooks,
|
|
40
|
+
config: deps.config as CommerceConfig,
|
|
39
41
|
services: deps.services,
|
|
40
42
|
database: deps.db,
|
|
41
43
|
}),
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { createHmac } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
3
|
+
import { assertPermission } from "../../auth/permissions.js";
|
|
3
4
|
import type { Actor } from "../../auth/types.js";
|
|
5
|
+
import type { CommerceConfig } from "../../config/types.js";
|
|
4
6
|
import type { DatabaseAdapter } from "../../kernel/database/adapter.js";
|
|
5
7
|
import type { PluginDb } from "../../kernel/database/plugin-types.js";
|
|
6
8
|
import type { TxContext } from "../../kernel/database/tx-context.js";
|
|
7
|
-
import { CommerceNotFoundError, CommerceValidationError } from "../../kernel/errors.js";
|
|
9
|
+
import { CommerceNotFoundError, CommerceValidationError, toCommerceError } from "../../kernel/errors.js";
|
|
8
10
|
import { runAfterHooks } from "../../kernel/hooks/executor.js";
|
|
9
11
|
import { createHookContext } from "../../kernel/hooks/create-context.js";
|
|
10
12
|
import type { HookRegistry } from "../../kernel/hooks/registry.js";
|
|
@@ -48,6 +50,7 @@ interface FulfillmentServiceDeps {
|
|
|
48
50
|
ordersRepository: OrdersRepository;
|
|
49
51
|
inventoryService?: InventoryServiceLike;
|
|
50
52
|
hooks: HookRegistry;
|
|
53
|
+
config: CommerceConfig;
|
|
51
54
|
services: Record<string, unknown>;
|
|
52
55
|
database: DatabaseAdapter;
|
|
53
56
|
}
|
|
@@ -259,7 +262,7 @@ export class FulfillmentService {
|
|
|
259
262
|
}
|
|
260
263
|
|
|
261
264
|
async fulfillOrder(orderId: string, actor?: Actor | null, ctx?: TxContext): Promise<Result<void>> {
|
|
262
|
-
const orgId =
|
|
265
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
263
266
|
const order = await this.deps.ordersRepository.findById(orgId, orderId, ctx);
|
|
264
267
|
if (!order) return Err(new CommerceNotFoundError("Order not found."));
|
|
265
268
|
|
|
@@ -326,6 +329,7 @@ export class FulfillmentService {
|
|
|
326
329
|
services: this.deps.services,
|
|
327
330
|
context: { moduleName: "fulfillment" },
|
|
328
331
|
database: { db: this.deps.database.db as PluginDb },
|
|
332
|
+
commerceConfig: this.deps.config,
|
|
329
333
|
});
|
|
330
334
|
await runAfterHooks(afterHooks, null, record, "create", hookCtx);
|
|
331
335
|
|
|
@@ -365,7 +369,13 @@ export class FulfillmentService {
|
|
|
365
369
|
actor?: Actor | null,
|
|
366
370
|
ctx?: TxContext,
|
|
367
371
|
): Promise<Result<FulfillmentRecord>> {
|
|
368
|
-
|
|
372
|
+
try {
|
|
373
|
+
assertPermission(actor ?? null, "orders:update");
|
|
374
|
+
} catch (error) {
|
|
375
|
+
return Err(toCommerceError(error));
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
369
379
|
const order = await this.deps.ordersRepository.findById(orgId, input.orderId, ctx);
|
|
370
380
|
if (!order) return Err(new CommerceNotFoundError("Order not found."));
|
|
371
381
|
|
|
@@ -432,7 +442,7 @@ export class FulfillmentService {
|
|
|
432
442
|
fulfillmentId: created.id,
|
|
433
443
|
eventType: "created",
|
|
434
444
|
toStatus: status,
|
|
435
|
-
...(actor?.userId
|
|
445
|
+
...(actor?.userId != null ? { actorId: actor.userId } : {}),
|
|
436
446
|
description: input.trackingNumber
|
|
437
447
|
? `Shipment recorded (${input.trackingNumber})`
|
|
438
448
|
: "Fulfillment recorded",
|
|
@@ -478,6 +488,7 @@ export class FulfillmentService {
|
|
|
478
488
|
services: this.deps.services,
|
|
479
489
|
context: { moduleName: "fulfillment" },
|
|
480
490
|
database: { db: this.deps.database.db as PluginDb },
|
|
491
|
+
commerceConfig: this.deps.config,
|
|
481
492
|
});
|
|
482
493
|
await runAfterHooks(afterHooks, null, record, "create", hookCtx);
|
|
483
494
|
|
|
@@ -563,7 +574,7 @@ export class FulfillmentService {
|
|
|
563
574
|
return Err(new CommerceNotFoundError("Digital download not found."));
|
|
564
575
|
}
|
|
565
576
|
|
|
566
|
-
const orgId =
|
|
577
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
567
578
|
const order = await this.deps.ordersRepository.findById(orgId, orderId, ctx);
|
|
568
579
|
if (!order || order.customerId !== userId) {
|
|
569
580
|
return Err(new CommerceNotFoundError("Order not found."));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
2
2
|
import { assertPermission } from "../../auth/permissions.js";
|
|
3
3
|
import type { Actor } from "../../auth/types.js";
|
|
4
4
|
import type { CommerceConfig } from "../../config/types.js";
|
|
@@ -57,7 +57,7 @@ export class InventoryService {
|
|
|
57
57
|
): Promise<string> {
|
|
58
58
|
const orgId =
|
|
59
59
|
orgIdOverride ??
|
|
60
|
-
|
|
60
|
+
resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
61
61
|
const warehouses = await this.repo.findAllWarehouses(orgId, ctx);
|
|
62
62
|
const sorted = warehouses.sort((a, b) => a.priority - b.priority);
|
|
63
63
|
if (sorted.length > 0) {
|
|
@@ -90,9 +90,8 @@ export class InventoryService {
|
|
|
90
90
|
);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
const orgId =
|
|
93
|
+
const orgId = resolveOrgIdForCommerce(
|
|
94
94
|
actor ?? ctx?.actor ?? null,
|
|
95
|
-
undefined,
|
|
96
95
|
this.deps.config,
|
|
97
96
|
);
|
|
98
97
|
|
|
@@ -113,9 +112,8 @@ export class InventoryService {
|
|
|
113
112
|
}
|
|
114
113
|
|
|
115
114
|
async listWarehouses(actor?: Actor | null, ctx?: TxContext): Promise<Result<Warehouse[]>> {
|
|
116
|
-
const orgId =
|
|
115
|
+
const orgId = resolveOrgIdForCommerce(
|
|
117
116
|
actor ?? ctx?.actor ?? null,
|
|
118
|
-
undefined,
|
|
119
117
|
this.deps.config,
|
|
120
118
|
);
|
|
121
119
|
const warehouses = await this.repo.findAllWarehouses(orgId, ctx);
|
|
@@ -128,9 +126,8 @@ export class InventoryService {
|
|
|
128
126
|
ctx?: TxContext,
|
|
129
127
|
actor?: Actor | null,
|
|
130
128
|
): Promise<Result<number>> {
|
|
131
|
-
const orgId =
|
|
129
|
+
const orgId = resolveOrgIdForCommerce(
|
|
132
130
|
actor ?? ctx?.actor ?? null,
|
|
133
|
-
undefined,
|
|
134
131
|
this.deps.config,
|
|
135
132
|
);
|
|
136
133
|
const available = await this.repo.getAvailableQuantity(
|
|
@@ -147,9 +144,8 @@ export class InventoryService {
|
|
|
147
144
|
actor?: Actor | null,
|
|
148
145
|
ctx?: TxContext,
|
|
149
146
|
): Promise<Result<InventoryLevel[]>> {
|
|
150
|
-
const orgId =
|
|
147
|
+
const orgId = resolveOrgIdForCommerce(
|
|
151
148
|
actor ?? ctx?.actor ?? null,
|
|
152
|
-
undefined,
|
|
153
149
|
this.deps.config,
|
|
154
150
|
);
|
|
155
151
|
if (params?.entityId) {
|
|
@@ -177,9 +173,8 @@ export class InventoryService {
|
|
|
177
173
|
actor?: Actor | null,
|
|
178
174
|
ctx?: TxContext,
|
|
179
175
|
): Promise<Result<Record<string, number>>> {
|
|
180
|
-
const orgId =
|
|
176
|
+
const orgId = resolveOrgIdForCommerce(
|
|
181
177
|
actor ?? ctx?.actor ?? null,
|
|
182
|
-
undefined,
|
|
183
178
|
this.deps.config,
|
|
184
179
|
);
|
|
185
180
|
const data = await this.repo.getAvailableQuantities(orgId, entityIds, ctx);
|
|
@@ -191,9 +186,8 @@ export class InventoryService {
|
|
|
191
186
|
ctx?: TxContext,
|
|
192
187
|
actor?: Actor | null,
|
|
193
188
|
): Promise<Result<InventoryLevel[]>> {
|
|
194
|
-
const orgId =
|
|
189
|
+
const orgId = resolveOrgIdForCommerce(
|
|
195
190
|
actor ?? ctx?.actor ?? null,
|
|
196
|
-
undefined,
|
|
197
191
|
this.deps.config,
|
|
198
192
|
);
|
|
199
193
|
const levels = await this.repo.findLevelsByEntityId(orgId, entityId, ctx);
|
|
@@ -213,9 +207,8 @@ export class InventoryService {
|
|
|
213
207
|
);
|
|
214
208
|
}
|
|
215
209
|
|
|
216
|
-
const orgId =
|
|
210
|
+
const orgId = resolveOrgIdForCommerce(
|
|
217
211
|
actor ?? ctx?.actor ?? null,
|
|
218
|
-
undefined,
|
|
219
212
|
this.deps.config,
|
|
220
213
|
);
|
|
221
214
|
const warehouseId = input.warehouseId ?? (await this.pickWarehouse(actor, ctx));
|
|
@@ -267,9 +260,8 @@ export class InventoryService {
|
|
|
267
260
|
actor?: Actor | null,
|
|
268
261
|
ctx?: TxContext,
|
|
269
262
|
): Promise<Result<void>> {
|
|
270
|
-
const orgId =
|
|
263
|
+
const orgId = resolveOrgIdForCommerce(
|
|
271
264
|
actor ?? ctx?.actor ?? null,
|
|
272
|
-
undefined,
|
|
273
265
|
this.deps.config,
|
|
274
266
|
);
|
|
275
267
|
const warehouseId = input.warehouseId ?? (await this.pickWarehouse(actor, ctx));
|
|
@@ -360,7 +352,7 @@ export class InventoryService {
|
|
|
360
352
|
const performedBy = input.performedBy ?? actor?.userId ?? "system";
|
|
361
353
|
|
|
362
354
|
const doAdjust = async (txCtx: TxContext) => {
|
|
363
|
-
const orgId =
|
|
355
|
+
const orgId = resolveOrgIdForCommerce(actor ?? txCtx.actor ?? null, this.deps.config);
|
|
364
356
|
|
|
365
357
|
// Lock the level first so `before` and the write are atomic.
|
|
366
358
|
const existing = await this.repo.findLevelForUpdate(
|
|
@@ -444,6 +436,7 @@ export class InventoryService {
|
|
|
444
436
|
services: this.deps.services,
|
|
445
437
|
context: { moduleName: "inventory" },
|
|
446
438
|
database: { db: this.deps.database.db as PluginDb },
|
|
439
|
+
commerceConfig: this.deps.config,
|
|
447
440
|
});
|
|
448
441
|
|
|
449
442
|
const afterHooks = this.deps.hooks.resolve("inventory.afterAdjust");
|
|
@@ -496,9 +489,8 @@ export class InventoryService {
|
|
|
496
489
|
ctx?: TxContext,
|
|
497
490
|
): Promise<Result<InventoryLevel>> {
|
|
498
491
|
const warehouseId = input.warehouseId ?? (await this.pickWarehouse(actor, ctx));
|
|
499
|
-
const orgId =
|
|
492
|
+
const orgId = resolveOrgIdForCommerce(
|
|
500
493
|
actor ?? ctx?.actor ?? null,
|
|
501
|
-
undefined,
|
|
502
494
|
this.deps.config,
|
|
503
495
|
);
|
|
504
496
|
|
|
@@ -551,7 +543,7 @@ export class InventoryService {
|
|
|
551
543
|
): Promise<Result<void>> {
|
|
552
544
|
const orgId =
|
|
553
545
|
input.orgId ??
|
|
554
|
-
|
|
546
|
+
resolveOrgIdForCommerce(ctx?.actor ?? null, this.deps.config);
|
|
555
547
|
const warehouseId =
|
|
556
548
|
input.warehouseId ?? (await this.pickWarehouse(null, ctx, orgId));
|
|
557
549
|
const variantId = input.variantId ?? null;
|
|
@@ -602,9 +594,8 @@ export class InventoryService {
|
|
|
602
594
|
variantId?: string,
|
|
603
595
|
ctx?: TxContext,
|
|
604
596
|
): Promise<Result<InventoryLevel>> {
|
|
605
|
-
const orgId =
|
|
597
|
+
const orgId = resolveOrgIdForCommerce(
|
|
606
598
|
ctx?.actor ?? null,
|
|
607
|
-
undefined,
|
|
608
599
|
this.deps.config,
|
|
609
600
|
);
|
|
610
601
|
const level = await this.repo.findLevelByKey(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
2
2
|
import { assertPermission } from "../../auth/permissions.js";
|
|
3
3
|
import type { Actor } from "../../auth/types.js";
|
|
4
4
|
import type { CommerceConfig } from "../../config/types.js";
|
|
@@ -138,7 +138,7 @@ export class MediaService {
|
|
|
138
138
|
);
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
const orgId =
|
|
141
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
142
142
|
const bytes = new Uint8Array(input.data);
|
|
143
143
|
const detectedMime = detectMimeFromBuffer(bytes);
|
|
144
144
|
const allowSvg = this.deps.config.media?.allowSvg === true;
|
|
@@ -203,7 +203,7 @@ export class MediaService {
|
|
|
203
203
|
actor?: Actor | null,
|
|
204
204
|
ctx?: TxContext,
|
|
205
205
|
): Promise<Result<string>> {
|
|
206
|
-
const orgId =
|
|
206
|
+
const orgId = resolveOrgIdForCommerce(actor ?? null, this.deps.config);
|
|
207
207
|
const asset = await this.repo.findAssetById(id, ctx, orgId);
|
|
208
208
|
if (!asset) return Err(new CommerceNotFoundError("Media asset not found."));
|
|
209
209
|
return this.deps.storage.getUrl(asset.storageKey);
|
|
@@ -215,7 +215,7 @@ export class MediaService {
|
|
|
215
215
|
actor?: Actor | null,
|
|
216
216
|
ctx?: TxContext,
|
|
217
217
|
): Promise<Result<string>> {
|
|
218
|
-
const orgId =
|
|
218
|
+
const orgId = resolveOrgIdForCommerce(actor ?? null, this.deps.config);
|
|
219
219
|
const asset = await this.repo.findAssetById(id, ctx, orgId);
|
|
220
220
|
if (!asset) return Err(new CommerceNotFoundError("Media asset not found."));
|
|
221
221
|
return this.deps.storage.getSignedUrl(asset.storageKey, expiresIn);
|
|
@@ -226,7 +226,7 @@ export class MediaService {
|
|
|
226
226
|
actor?: Actor | null,
|
|
227
227
|
ctx?: TxContext,
|
|
228
228
|
): Promise<Result<void>> {
|
|
229
|
-
const orgId =
|
|
229
|
+
const orgId = resolveOrgIdForCommerce(actor ?? null, this.deps.config);
|
|
230
230
|
const asset = await this.repo.findAssetById(id, ctx, orgId);
|
|
231
231
|
if (!asset) return Err(new CommerceNotFoundError("Media asset not found."));
|
|
232
232
|
|
|
@@ -257,7 +257,7 @@ export class MediaService {
|
|
|
257
257
|
): Promise<Result<void>> {
|
|
258
258
|
try {
|
|
259
259
|
return await this.withTransaction(actor ?? ctx?.actor ?? null, ctx, async (txCtx) => {
|
|
260
|
-
const orgId =
|
|
260
|
+
const orgId = resolveOrgIdForCommerce(actor ?? txCtx.actor, this.deps.config);
|
|
261
261
|
const entity = await this.catalogRepo.findEntityById(input.entityId, txCtx, orgId);
|
|
262
262
|
if (!entity) return Err(new CommerceNotFoundError("Entity not found."));
|
|
263
263
|
|