@endora-commerce/mod-delivery-methods 0.100.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/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/admin/api/delivery-methods-client.d.ts +41 -0
- package/dist/admin/api/delivery-methods-client.d.ts.map +1 -0
- package/dist/admin/api/delivery-methods-client.js +20 -0
- package/dist/admin/api/delivery-methods-client.js.map +1 -0
- package/dist/admin/index.d.ts +34 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +44 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/DeliveryMethodsPage.d.ts +4 -0
- package/dist/admin/pages/DeliveryMethodsPage.d.ts.map +1 -0
- package/dist/admin/pages/DeliveryMethodsPage.js +167 -0
- package/dist/admin/pages/DeliveryMethodsPage.js.map +1 -0
- package/dist/admin/renderers/registry.d.ts +15 -0
- package/dist/admin/renderers/registry.d.ts.map +1 -0
- package/dist/admin/renderers/registry.js +18 -0
- package/dist/admin/renderers/registry.js.map +1 -0
- package/dist/backend/adapters/built-in-adapters.d.ts +46 -0
- package/dist/backend/adapters/built-in-adapters.d.ts.map +1 -0
- package/dist/backend/adapters/built-in-adapters.js +62 -0
- package/dist/backend/adapters/built-in-adapters.js.map +1 -0
- package/dist/backend/commands/delivery-method.commands.d.ts +61 -0
- package/dist/backend/commands/delivery-method.commands.d.ts.map +1 -0
- package/dist/backend/commands/delivery-method.commands.js +107 -0
- package/dist/backend/commands/delivery-method.commands.js.map +1 -0
- package/dist/backend/demo/reset.d.ts +12 -0
- package/dist/backend/demo/reset.d.ts.map +1 -0
- package/dist/backend/demo/reset.js +13 -0
- package/dist/backend/demo/reset.js.map +1 -0
- package/dist/backend/demo/rows.d.ts +24 -0
- package/dist/backend/demo/rows.d.ts.map +1 -0
- package/dist/backend/demo/rows.js +22 -0
- package/dist/backend/demo/rows.js.map +1 -0
- package/dist/backend/demo/seed.d.ts +14 -0
- package/dist/backend/demo/seed.d.ts.map +1 -0
- package/dist/backend/demo/seed.js +28 -0
- package/dist/backend/demo/seed.js.map +1 -0
- package/dist/backend/entities/delivery-method.entity.d.ts +30 -0
- package/dist/backend/entities/delivery-method.entity.d.ts.map +1 -0
- package/dist/backend/entities/delivery-method.entity.js +91 -0
- package/dist/backend/entities/delivery-method.entity.js.map +1 -0
- package/dist/backend/index.d.ts +88 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +144 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/routes.d.ts +51 -0
- package/dist/backend/routes.d.ts.map +1 -0
- package/dist/backend/routes.js +152 -0
- package/dist/backend/routes.js.map +1 -0
- package/dist/backend/services/delivery-method-read-port.d.ts +25 -0
- package/dist/backend/services/delivery-method-read-port.d.ts.map +1 -0
- package/dist/backend/services/delivery-method-read-port.js +56 -0
- package/dist/backend/services/delivery-method-read-port.js.map +1 -0
- package/dist/backend/services/delivery-method-reconciler.d.ts +97 -0
- package/dist/backend/services/delivery-method-reconciler.d.ts.map +1 -0
- package/dist/backend/services/delivery-method-reconciler.js +157 -0
- package/dist/backend/services/delivery-method-reconciler.js.map +1 -0
- package/dist/backend/services/order-status-registry.port.d.ts +50 -0
- package/dist/backend/services/order-status-registry.port.d.ts.map +1 -0
- package/dist/backend/services/order-status-registry.port.js +45 -0
- package/dist/backend/services/order-status-registry.port.js.map +1 -0
- package/dist/backend/services/registry-singleton.d.ts +20 -0
- package/dist/backend/services/registry-singleton.d.ts.map +1 -0
- package/dist/backend/services/registry-singleton.js +21 -0
- package/dist/backend/services/registry-singleton.js.map +1 -0
- package/dist/backend/services/shipment-usage-guard.d.ts +31 -0
- package/dist/backend/services/shipment-usage-guard.d.ts.map +1 -0
- package/dist/backend/services/shipment-usage-guard.js +33 -0
- package/dist/backend/services/shipment-usage-guard.js.map +1 -0
- package/dist/backend/services/shipping-adapter-registry.d.ts +98 -0
- package/dist/backend/services/shipping-adapter-registry.d.ts.map +1 -0
- package/dist/backend/services/shipping-adapter-registry.js +92 -0
- package/dist/backend/services/shipping-adapter-registry.js.map +1 -0
- package/dist/backend/services/shipping-method-eligibility.d.ts +24 -0
- package/dist/backend/services/shipping-method-eligibility.d.ts.map +1 -0
- package/dist/backend/services/shipping-method-eligibility.js +46 -0
- package/dist/backend/services/shipping-method-eligibility.js.map +1 -0
- package/dist/install/index.d.ts +59 -0
- package/dist/install/index.d.ts.map +1 -0
- package/dist/install/index.js +59 -0
- package/dist/install/index.js.map +1 -0
- package/dist/manifest.d.ts +193 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +185 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260611T140354_delivery_methods_shipping_methods_adapter_and_shipments.d.ts +30 -0
- package/dist/migrations/20260611T140354_delivery_methods_shipping_methods_adapter_and_shipments.d.ts.map +1 -0
- package/dist/migrations/20260611T140354_delivery_methods_shipping_methods_adapter_and_shipments.js +72 -0
- package/dist/migrations/20260611T140354_delivery_methods_shipping_methods_adapter_and_shipments.js.map +1 -0
- package/dist/migrations/20260611T140416_delivery_methods_fix_in_person_pickup_adapter.d.ts +24 -0
- package/dist/migrations/20260611T140416_delivery_methods_fix_in_person_pickup_adapter.d.ts.map +1 -0
- package/dist/migrations/20260611T140416_delivery_methods_fix_in_person_pickup_adapter.js +28 -0
- package/dist/migrations/20260611T140416_delivery_methods_fix_in_person_pickup_adapter.js.map +1 -0
- package/dist/migrations/20260912T094638_delivery_methods_sales_channel_delivery_methods.d.ts +27 -0
- package/dist/migrations/20260912T094638_delivery_methods_sales_channel_delivery_methods.d.ts.map +1 -0
- package/dist/migrations/20260912T094638_delivery_methods_sales_channel_delivery_methods.js +44 -0
- package/dist/migrations/20260912T094638_delivery_methods_sales_channel_delivery_methods.js.map +1 -0
- package/dist/migrations/index.d.ts +29 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +33 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/ports/index.d.ts +129 -0
- package/dist/ports/index.d.ts.map +1 -0
- package/dist/ports/index.js +2 -0
- package/dist/ports/index.js.map +1 -0
- package/docs/delivery_methods.md +197 -0
- package/i18n/en.json +5 -0
- package/i18n/pl.json +5 -0
- package/package.json +100 -0
- package/tailwind.css +14 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { lazyPort } from '@endora-commerce/platform/kernel';
|
|
2
|
+
import { effectiveState } from '@endora-commerce/platform/kernel';
|
|
3
|
+
import { builtInShippingAdapters } from './adapters/built-in-adapters.js';
|
|
4
|
+
import { registerDeliveryMethodsAdminRoutes, registerDeliveryMethodsPublicRoutes, } from './routes.js';
|
|
5
|
+
import { EnumOrderStatusRegistry } from './services/order-status-registry.port.js';
|
|
6
|
+
import { shippingAdapterRegistry } from './services/registry-singleton.js';
|
|
7
|
+
import { DeliveryMethodReadService } from './services/delivery-method-read-port.js';
|
|
8
|
+
import { ShippingMethodEligibilityService } from './services/shipping-method-eligibility.js';
|
|
9
|
+
import { makeShipmentUsageCounter } from './services/shipment-usage-guard.js';
|
|
10
|
+
import { DeliveryMethod } from './entities/delivery-method.entity.js';
|
|
11
|
+
export function registerModule(ctx) {
|
|
12
|
+
/**
|
|
13
|
+
* Feature 120 (FR-015) — the sales-channel membership bridge this module owns.
|
|
14
|
+
*
|
|
15
|
+
* The platform used to hold a map **total** over
|
|
16
|
+
* `ChannelMemberEntityTypeSchema`, naming this module's bridge table from
|
|
17
|
+
* inside the kernel. That is D-52/D-53's prohibition expressed in a contract
|
|
18
|
+
* instead of an import, and it meant a membership call for 'delivery-method' on an
|
|
19
|
+
* instance that never installed this module executed SQL against a relation
|
|
20
|
+
* that is not there (D-226). The module whose migration creates the table is
|
|
21
|
+
* the one that says where it is; a member nothing registers now refuses at
|
|
22
|
+
* the call instead.
|
|
23
|
+
*
|
|
24
|
+
* A **contribution** hook and deliberately **unprobed** (D-62/D-68): a
|
|
25
|
+
* registration is an inert statement about the schema rather than a
|
|
26
|
+
* capability, the rows outlive an operator switching this module off, and
|
|
27
|
+
* probing would make a runtime activation flip require a restart. It is
|
|
28
|
+
* declared first in this module so any later hook of its own that binds a
|
|
29
|
+
* membership finds the bridge already there.
|
|
30
|
+
*/
|
|
31
|
+
ctx.onBoot(() => {
|
|
32
|
+
const { salesChannelBridgeRegistry } = ctx.cradle();
|
|
33
|
+
for (const bridge of salesChannelBridges)
|
|
34
|
+
salesChannelBridgeRegistry.register(bridge);
|
|
35
|
+
});
|
|
36
|
+
ctx.di.register({
|
|
37
|
+
shippingAdapterRegistry: ctx.asFunction(() => shippingAdapterRegistry).singleton(),
|
|
38
|
+
shippingMethodEligibility: ctx
|
|
39
|
+
.asFunction((cradle) => new ShippingMethodEligibilityService(cradle.shippingAdapterRegistry))
|
|
40
|
+
.singleton(),
|
|
41
|
+
shippingOrderStatusRegistry: ctx.asFunction(() => new EnumOrderStatusRegistry()).singleton(),
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
* Feature 075, Phase P — the row-level read model.
|
|
45
|
+
*
|
|
46
|
+
* A **port**, unlike the registry registrations above. The distinction is
|
|
47
|
+
* the deactivation-consequence one: `shippingAdapterRegistry` is a
|
|
48
|
+
* contribution seam whose absent-owner policy lives inside it and whose
|
|
49
|
+
* edges classify as `contributes`, so a gate over the registration would
|
|
50
|
+
* withdraw the table rather than one contributor's entry. A read of this
|
|
51
|
+
* module's own table is nothing of the kind — with `delivery_methods` off, a
|
|
52
|
+
* caller asking which methods exist should be told the module is off.
|
|
53
|
+
*/
|
|
54
|
+
ctx.di.providePort('deliveryMethodReadPort', ctx
|
|
55
|
+
.asFunction(({ emFactory }) => new DeliveryMethodReadService(emFactory))
|
|
56
|
+
.singleton());
|
|
57
|
+
ctx.routes(async (app) => {
|
|
58
|
+
const { emFactory, requireAdmin, shippingAdapterRegistry: registry, shippingMethodEligibility, shippingOrderStatusRegistry, } = ctx.cradle();
|
|
59
|
+
const membership = ctx.cradle().salesChannelMembershipPort;
|
|
60
|
+
/** Composed from the two halves, without a `catch` — see the payment twin. */
|
|
61
|
+
const resolveAllowList = async (req) => {
|
|
62
|
+
const cradle = ctx.cradle();
|
|
63
|
+
const organizationId = cradle.customerOrganizationIdResolver(req);
|
|
64
|
+
if (organizationId === null)
|
|
65
|
+
return null;
|
|
66
|
+
return cradle.organizationRestrictionPort.allowedIdsFor(organizationId, 'deliveryMethodIds');
|
|
67
|
+
};
|
|
68
|
+
await registerDeliveryMethodsPublicRoutes(app, {
|
|
69
|
+
emFactory,
|
|
70
|
+
registry,
|
|
71
|
+
eligibility: shippingMethodEligibility,
|
|
72
|
+
resolveOrganizationDeliveryMethodAllowList: resolveAllowList,
|
|
73
|
+
});
|
|
74
|
+
await registerDeliveryMethodsAdminRoutes(app, {
|
|
75
|
+
emFactory,
|
|
76
|
+
requireAdmin,
|
|
77
|
+
commandBus: ctx.cradle().commandBus,
|
|
78
|
+
registry,
|
|
79
|
+
orderStatusRegistry: shippingOrderStatusRegistry,
|
|
80
|
+
/**
|
|
81
|
+
* Feature 075 — the FR-003 delete guard, asked of the module that owns
|
|
82
|
+
* the rows instead of counting its table in raw SQL.
|
|
83
|
+
*
|
|
84
|
+
* The port is resolved **per call**, inside the counter, and only after
|
|
85
|
+
* `effectiveState` has answered: `lazyPort`'s proxy may not be captured
|
|
86
|
+
* into a singleton, and a gate resolved before the first request is one
|
|
87
|
+
* of the three fail-open shapes the deactivation-consequence ledger
|
|
88
|
+
* refuses. The edge is `nonBindingDependencies` rather than a
|
|
89
|
+
* dependency — see the manifest for why the cycle forbids the ordinary
|
|
90
|
+
* declaration, and `shipment-usage-guard.ts` for what absence means.
|
|
91
|
+
*/
|
|
92
|
+
countShipmentsForMethod: makeShipmentUsageCounter({
|
|
93
|
+
isShipmentsPresent: () => effectiveState.isPresent('shipments'),
|
|
94
|
+
shipmentUsage: () => lazyPort(ctx, 'shipmentUsagePort'),
|
|
95
|
+
}),
|
|
96
|
+
...(membership === undefined ? {} : { salesChannelMembership: membership }),
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
/**
|
|
100
|
+
* The two shipping kinds this module implements, pushed into the registry it
|
|
101
|
+
* holds — from a boot hook rather than from the registry's own factory
|
|
102
|
+
* (issue #96).
|
|
103
|
+
*
|
|
104
|
+
* Seeding inside the factory tied "which adapters exist" to whoever resolved
|
|
105
|
+
* the name first, and left the entries unowned: nothing recorded that these
|
|
106
|
+
* two came from this module, so the enumeration had nothing to filter on when
|
|
107
|
+
* an operator switched a contributor off. A boot hook runs once per
|
|
108
|
+
* composition, regardless of effective state, which is exactly the D-39
|
|
109
|
+
* contract — the push is ungated, the *enumeration* answers presence.
|
|
110
|
+
*/
|
|
111
|
+
ctx.onBoot(() => {
|
|
112
|
+
const registry = ctx.cradle().shippingAdapterRegistry;
|
|
113
|
+
for (const adapter of builtInShippingAdapters()) {
|
|
114
|
+
registry.register(adapter, 'delivery_methods');
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The module's persisted entity classes, on the `./backend` subpath, as one
|
|
120
|
+
* array and **no named class export** (D-168).
|
|
121
|
+
*
|
|
122
|
+
* This is the shape the platform reads when the package is *installed*: the
|
|
123
|
+
* boot-time loader (`src/packages/package-runtime.ts`, `exported['entities']`)
|
|
124
|
+
* and the static declaration reader (`scripts/lib/package-declarations.ts`),
|
|
125
|
+
* which is the third source of `check:module-boundary`'s `table→owner` map and
|
|
126
|
+
* the package pass of `check-entity-tenant-classification`. A missing array is
|
|
127
|
+
* answered with `[]` — zero entities registered, no error anywhere.
|
|
128
|
+
*/
|
|
129
|
+
export const entities = [
|
|
130
|
+
DeliveryMethod,
|
|
131
|
+
];
|
|
132
|
+
/**
|
|
133
|
+
* The sales-channel membership bridge this module owns (feature 120, FR-015).
|
|
134
|
+
*
|
|
135
|
+
* Exported as well as registered because the owning module is the only honest
|
|
136
|
+
* source for it: a caller that composes no platform — the bare-database test
|
|
137
|
+
* harness, which constructs the kernel's membership service directly — declares
|
|
138
|
+
* these from here rather than from a list of nine it keeps itself, which is
|
|
139
|
+
* exactly the total map this feature deleted.
|
|
140
|
+
*/
|
|
141
|
+
export const salesChannelBridges = [
|
|
142
|
+
{ entityType: 'delivery-method', table: 'sales_channel_delivery_methods', entityIdColumn: 'delivery_method_id' },
|
|
143
|
+
];
|
|
144
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { FastifyInstance, FastifyRequest } from 'fastify';
|
|
2
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
3
|
+
import type { CommandBus } from '@endora-commerce/platform/commands';
|
|
4
|
+
import { type ShipmentUsageCounter } from './commands/delivery-method.commands.js';
|
|
5
|
+
import type { SalesChannelMembershipPort } from '@endora-commerce/platform/kernel';
|
|
6
|
+
import type { ShippingAdapterRegistry } from './services/shipping-adapter-registry.js';
|
|
7
|
+
import type { ShippingMethodEligibilityService } from './services/shipping-method-eligibility.js';
|
|
8
|
+
import { type OrderStatusRegistry } from './services/order-status-registry.port.js';
|
|
9
|
+
import type { RequireAdminFactory } from '@endora-commerce/platform/kernel';
|
|
10
|
+
/**
|
|
11
|
+
* Delivery-method catalog routes (feature 035 — adapter framework).
|
|
12
|
+
*
|
|
13
|
+
* Public read endpoint lists active, eligible methods for storefront checkout;
|
|
14
|
+
* admin mutation lives under `/api/v1/admin/delivery-methods`. Eligibility
|
|
15
|
+
* validators (validateUseOnStorefront) + registered-adapter filtering are
|
|
16
|
+
* layered on by the eligibility service; the org allow-list filter is retained.
|
|
17
|
+
*/
|
|
18
|
+
export interface DeliveryMethodsPublicDeps {
|
|
19
|
+
emFactory: () => EntityManager;
|
|
20
|
+
/**
|
|
21
|
+
* Feature 026 US4 — per-Organization allow-list of delivery-method IDs.
|
|
22
|
+
* Empty / null ⇒ platform defaults apply (every active method is offered).
|
|
23
|
+
*/
|
|
24
|
+
resolveOrganizationDeliveryMethodAllowList?: (req: FastifyRequest) => Promise<string[] | null>;
|
|
25
|
+
/** Feature 035 — resolves a method's storefront renderer key. */
|
|
26
|
+
registry?: ShippingAdapterRegistry;
|
|
27
|
+
/** Feature 035 — applies adapter `validateUseOnStorefront` + registered-adapter filtering. */
|
|
28
|
+
eligibility?: ShippingMethodEligibilityService;
|
|
29
|
+
}
|
|
30
|
+
export interface DeliveryMethodsAdminDeps {
|
|
31
|
+
emFactory: () => EntityManager;
|
|
32
|
+
requireAdmin: RequireAdminFactory;
|
|
33
|
+
/** Issue #125 — the two admin writes run on the bus (Principle XIII). */
|
|
34
|
+
commandBus: CommandBus;
|
|
35
|
+
/** Feature 005 / T027b — new delivery methods auto-bind to the system default. */
|
|
36
|
+
salesChannelMembership?: SalesChannelMembershipPort;
|
|
37
|
+
/** Feature 035 — validates `adapter` against the registered adapters. */
|
|
38
|
+
registry?: ShippingAdapterRegistry;
|
|
39
|
+
/** Feature 035 — validates `statusOn*` references + powers /admin/order-statuses. */
|
|
40
|
+
orderStatusRegistry?: OrderStatusRegistry;
|
|
41
|
+
/**
|
|
42
|
+
* Feature 075 — the FR-003 delete guard's count, asked of `shipments` because
|
|
43
|
+
* the rows are its own. Required, not optional: a guard that can be left out
|
|
44
|
+
* is a guard that silently is, and it is the only thing protecting shipment
|
|
45
|
+
* history from a delete (there is no foreign key).
|
|
46
|
+
*/
|
|
47
|
+
countShipmentsForMethod: ShipmentUsageCounter;
|
|
48
|
+
}
|
|
49
|
+
export declare function registerDeliveryMethodsPublicRoutes(app: FastifyInstance, deps: DeliveryMethodsPublicDeps): Promise<void>;
|
|
50
|
+
export declare function registerDeliveryMethodsAdminRoutes(app: FastifyInstance, deps: DeliveryMethodsAdminDeps): Promise<void>;
|
|
51
|
+
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/backend/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,wCAAwC,CAAC;AAEhD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AACvF,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,2CAA2C,CAAC;AAClG,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAE5E;;;;;;;GAOG;AACH,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,aAAa,CAAC;IAC/B;;;OAGG;IACH,0CAA0C,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC;IAC/F,iEAAiE;IACjE,QAAQ,CAAC,EAAE,uBAAuB,CAAC;IACnC,8FAA8F;IAC9F,WAAW,CAAC,EAAE,gCAAgC,CAAC;CAChD;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,aAAa,CAAC;IAC/B,YAAY,EAAE,mBAAmB,CAAC;IAClC,yEAAyE;IACzE,UAAU,EAAE,UAAU,CAAC;IACvB,kFAAkF;IAClF,sBAAsB,CAAC,EAAE,0BAA0B,CAAC;IACpD,yEAAyE;IACzE,QAAQ,CAAC,EAAE,uBAAuB,CAAC;IACnC,qFAAqF;IACrF,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C;;;;;OAKG;IACH,uBAAuB,EAAE,oBAAoB,CAAC;CAC/C;AAMD,wBAAsB,mCAAmC,CACvD,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAED,wBAAsB,kCAAkC,CACtD,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,wBAAwB,GAC7B,OAAO,CAAC,IAAI,CAAC,CA2Ff"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { ERROR_CODES, deliveryMethodUpsertSchema } from '@endora-commerce/contracts';
|
|
2
|
+
import { HttpError } from '@endora-commerce/platform/http';
|
|
3
|
+
import { makeDeleteDeliveryMethodCommand, makeUpsertDeliveryMethodCommand, } from './commands/delivery-method.commands.js';
|
|
4
|
+
import { DeliveryMethod } from './entities/delivery-method.entity.js';
|
|
5
|
+
import { OrderStatusRegistryError, } from './services/order-status-registry.port.js';
|
|
6
|
+
function rendererKeyFor(deps, adapter) {
|
|
7
|
+
return deps.registry?.get(adapter)?.renderers?.storefront ?? null;
|
|
8
|
+
}
|
|
9
|
+
export async function registerDeliveryMethodsPublicRoutes(app, deps) {
|
|
10
|
+
app.get('/api/v1/delivery-methods', async (request) => {
|
|
11
|
+
const em = deps.emFactory();
|
|
12
|
+
let rows = await em.find(DeliveryMethod, { status: 'active' }, { orderBy: { code: 'asc' } });
|
|
13
|
+
// Feature 026 US4 — intersect with the Organization's delivery-method
|
|
14
|
+
// allow-list when one is configured.
|
|
15
|
+
if (deps.resolveOrganizationDeliveryMethodAllowList) {
|
|
16
|
+
const allowList = await deps.resolveOrganizationDeliveryMethodAllowList(request);
|
|
17
|
+
if (allowList && allowList.length > 0) {
|
|
18
|
+
const allowSet = new Set(allowList);
|
|
19
|
+
rows = rows.filter((m) => allowSet.has(m.id));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// Feature 035 — adapter validateUseOnStorefront + registered-adapter filter.
|
|
23
|
+
if (deps.eligibility) {
|
|
24
|
+
rows = await deps.eligibility.filter(rows, {
|
|
25
|
+
salesChannelId: null,
|
|
26
|
+
organizationId: null,
|
|
27
|
+
customerAccountId: null,
|
|
28
|
+
surface: 'storefront',
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return { data: rows.map((m) => serializeDeliveryMethod(m, deps)) };
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export async function registerDeliveryMethodsAdminRoutes(app, deps) {
|
|
35
|
+
const requireAdmin = deps.requireAdmin;
|
|
36
|
+
app.get('/api/v1/admin/delivery-methods', { preHandler: requireAdmin('delivery_methods:read') }, async () => {
|
|
37
|
+
const em = deps.emFactory();
|
|
38
|
+
const rows = await em.find(DeliveryMethod, {}, { orderBy: { code: 'asc' } });
|
|
39
|
+
const data = await Promise.all(rows.map((m) => serializeAdmin(m, deps)));
|
|
40
|
+
return { data };
|
|
41
|
+
});
|
|
42
|
+
// Note: `GET /api/v1/admin/order-statuses` is registered once by the
|
|
43
|
+
// payment-methods admin routes (same OrderStatusRegistry data); the admin
|
|
44
|
+
// delivery-methods page reuses that endpoint for its status selectors. Since
|
|
45
|
+
// this module took its own codes it is gated
|
|
46
|
+
// `requireAdminAny(['payment_methods:read', 'delivery_methods:read'])` — an
|
|
47
|
+
// any-of over the two editors' read codes, so whichever screen an operator
|
|
48
|
+
// may open, the shared status list opens with it.
|
|
49
|
+
app.put('/api/v1/admin/delivery-methods/:code', {
|
|
50
|
+
preHandler: requireAdmin('delivery_methods:write'),
|
|
51
|
+
schema: { body: deliveryMethodUpsertSchema },
|
|
52
|
+
}, async (request) => {
|
|
53
|
+
const body = deliveryMethodUpsertSchema.parse(request.body);
|
|
54
|
+
const em = deps.emFactory();
|
|
55
|
+
// Only hard-reject an *explicitly* provided unknown adapter. A row whose
|
|
56
|
+
// derived adapter is not registered is retained but excluded from
|
|
57
|
+
// selection by the eligibility filter (FR-003), so admins can still
|
|
58
|
+
// manage catalog rows whose adapter module is currently disabled.
|
|
59
|
+
if (body.adapter !== undefined && deps.registry && !deps.registry.isRegistered(body.adapter)) {
|
|
60
|
+
throw new HttpError(400, ERROR_CODES.VALIDATION_FAILED, `Unknown shipping adapter "${body.adapter}". Register an adapter module first.`);
|
|
61
|
+
}
|
|
62
|
+
// Validate any explicitly-provided Order-status references (FR-008).
|
|
63
|
+
if (deps.orderStatusRegistry) {
|
|
64
|
+
for (const ref of [body.statusOnSuccess, body.statusOnFailure]) {
|
|
65
|
+
if (ref !== undefined)
|
|
66
|
+
assertValidStatus(deps.orderStatusRegistry, ref);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// The read below only tells the Command whether this call creates or
|
|
70
|
+
// updates; the write itself happens inside the bus transaction, which is
|
|
71
|
+
// also where the adapter is resolved against the row it finds (#125).
|
|
72
|
+
const existing = await em.findOne(DeliveryMethod, { code: request.params.code });
|
|
73
|
+
const { method: row, created: isNew } = await deps.commandBus.run(makeUpsertDeliveryMethodCommand({
|
|
74
|
+
code: request.params.code,
|
|
75
|
+
body,
|
|
76
|
+
existingId: existing?.id ?? null,
|
|
77
|
+
}));
|
|
78
|
+
// Channel membership is the sales-channel bridge's own write, on its own
|
|
79
|
+
// EntityManager, so it stays outside the Command rather than pretending to
|
|
80
|
+
// share its transaction.
|
|
81
|
+
if (isNew && deps.salesChannelMembership) {
|
|
82
|
+
await deps.salesChannelMembership.bindToDefaultIfEmpty('delivery-method', row.id);
|
|
83
|
+
}
|
|
84
|
+
// Replace sales-channel membership when an explicit (non-empty) set is given.
|
|
85
|
+
if (body.salesChannelIds && body.salesChannelIds.length > 0 && deps.salesChannelMembership) {
|
|
86
|
+
await replaceChannelMembership(deps.salesChannelMembership, row.id, body.salesChannelIds);
|
|
87
|
+
}
|
|
88
|
+
return { data: await serializeAdmin(row, deps) };
|
|
89
|
+
});
|
|
90
|
+
app.delete('/api/v1/admin/delivery-methods/:id', { preHandler: requireAdmin('delivery_methods:write') }, async (request, reply) => {
|
|
91
|
+
// The 404 and the delete-guard (FR-003) live inside the Command, so a
|
|
92
|
+
// method that is gone is answered before another module is asked about
|
|
93
|
+
// it. The count itself comes from `shipments` — see the Command's
|
|
94
|
+
// `ShipmentUsageCounter` for why it no longer runs on this transaction.
|
|
95
|
+
await deps.commandBus.run(makeDeleteDeliveryMethodCommand(request.params.id, deps.countShipmentsForMethod));
|
|
96
|
+
return reply.status(204).send();
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function assertValidStatus(registry, ref) {
|
|
100
|
+
try {
|
|
101
|
+
registry.assertValid(ref);
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
if (err instanceof OrderStatusRegistryError) {
|
|
105
|
+
throw new HttpError(400, ERROR_CODES.VALIDATION_FAILED, `Unknown order status "${ref}".`);
|
|
106
|
+
}
|
|
107
|
+
throw err;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async function replaceChannelMembership(membership, methodId, desiredChannelIds) {
|
|
111
|
+
const current = await membership.listChannelsForEntity('delivery-method', methodId);
|
|
112
|
+
const currentIds = new Set(current.map((c) => c.id));
|
|
113
|
+
const desired = new Set(desiredChannelIds);
|
|
114
|
+
// Add first so a later removal never transiently leaves zero channels.
|
|
115
|
+
for (const id of desired) {
|
|
116
|
+
if (!currentIds.has(id))
|
|
117
|
+
await membership.addToChannel(id, 'delivery-method', methodId);
|
|
118
|
+
}
|
|
119
|
+
for (const id of currentIds) {
|
|
120
|
+
if (!desired.has(id))
|
|
121
|
+
await membership.removeFromChannel(id, 'delivery-method', methodId);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function serializeDeliveryMethod(m, deps) {
|
|
125
|
+
return {
|
|
126
|
+
id: m.id,
|
|
127
|
+
code: m.code,
|
|
128
|
+
name: m.name,
|
|
129
|
+
adapter: m.adapter,
|
|
130
|
+
cost: { amount: Number(m.cost), currency: m.currency },
|
|
131
|
+
status: m.status,
|
|
132
|
+
rendererKey: rendererKeyFor(deps, m.adapter),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
async function serializeAdmin(m, deps) {
|
|
136
|
+
const channels = deps.salesChannelMembership
|
|
137
|
+
? await deps.salesChannelMembership.listChannelsForEntity('delivery-method', m.id)
|
|
138
|
+
: [];
|
|
139
|
+
return {
|
|
140
|
+
id: m.id,
|
|
141
|
+
code: m.code,
|
|
142
|
+
adapter: m.adapter,
|
|
143
|
+
name: m.name,
|
|
144
|
+
cost: { amount: Number(m.cost), currency: m.currency },
|
|
145
|
+
status: m.status,
|
|
146
|
+
statusOnSuccess: m.statusOnSuccess,
|
|
147
|
+
statusOnFailure: m.statusOnFailure,
|
|
148
|
+
salesChannelIds: channels.map((c) => c.id),
|
|
149
|
+
rendererKey: deps.registry?.get(m.adapter)?.renderers?.admin ?? null,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/backend/routes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACrF,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAE3D,OAAO,EACL,+BAA+B,EAC/B,+BAA+B,GAEhC,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAItE,OAAO,EACL,wBAAwB,GAEzB,MAAM,0CAA0C,CAAC;AA4ClD,SAAS,cAAc,CAAC,IAA4C,EAAE,OAAe;IACnF,OAAO,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,UAAU,IAAI,IAAI,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mCAAmC,CACvD,GAAoB,EACpB,IAA+B;IAE/B,GAAG,CAAC,GAAG,CAAC,0BAA0B,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACpD,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,IAAI,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QAE7F,sEAAsE;QACtE,qCAAqC;QACrC,IAAI,IAAI,CAAC,0CAA0C,EAAE,CAAC;YACpD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,0CAA0C,CAAC,OAAO,CAAC,CAAC;YACjF,IAAI,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;gBACpC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QAED,6EAA6E;QAC7E,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE;gBACzC,cAAc,EAAE,IAAI;gBACpB,cAAc,EAAE,IAAI;gBACpB,iBAAiB,EAAE,IAAI;gBACvB,OAAO,EAAE,YAAY;aACtB,CAAC,CAAC;QACL,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,uBAAuB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;IACrE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kCAAkC,CACtD,GAAoB,EACpB,IAA8B;IAE9B,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;IAEvC,GAAG,CAAC,GAAG,CACL,gCAAgC,EAChC,EAAE,UAAU,EAAE,YAAY,CAAC,uBAAuB,CAAC,EAAE,EACrD,KAAK,IAAI,EAAE;QACT,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QAC7E,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QACzE,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC,CACF,CAAC;IAEF,qEAAqE;IACrE,0EAA0E;IAC1E,6EAA6E;IAC7E,6CAA6C;IAC7C,4EAA4E;IAC5E,2EAA2E;IAC3E,kDAAkD;IAElD,GAAG,CAAC,GAAG,CACL,sCAAsC,EACtC;QACE,UAAU,EAAE,YAAY,CAAC,wBAAwB,CAAC;QAClD,MAAM,EAAE,EAAE,IAAI,EAAE,0BAA0B,EAAE;KAC7C,EACD,KAAK,EAAE,OAAO,EAAE,EAAE;QAChB,MAAM,IAAI,GAAG,0BAA0B,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5D,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAE5B,yEAAyE;QACzE,kEAAkE;QAClE,oEAAoE;QACpE,kEAAkE;QAClE,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7F,MAAM,IAAI,SAAS,CACjB,GAAG,EACH,WAAW,CAAC,iBAAiB,EAC7B,6BAA6B,IAAI,CAAC,OAAO,sCAAsC,CAChF,CAAC;QACJ,CAAC;QACD,qEAAqE;QACrE,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC7B,KAAK,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC;gBAC/D,IAAI,GAAG,KAAK,SAAS;oBAAE,iBAAiB,CAAC,IAAI,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;YAC1E,CAAC;QACH,CAAC;QAED,qEAAqE;QACrE,yEAAyE;QACzE,sEAAsE;QACtE,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QACjF,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAC/D,+BAA+B,CAAC;YAC9B,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI;YACzB,IAAI;YACJ,UAAU,EAAE,QAAQ,EAAE,EAAE,IAAI,IAAI;SACjC,CAAC,CACH,CAAC;QAEF,yEAAyE;QACzE,2EAA2E;QAC3E,yBAAyB;QACzB,IAAI,KAAK,IAAI,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACzC,MAAM,IAAI,CAAC,sBAAsB,CAAC,oBAAoB,CAAC,iBAAiB,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QACpF,CAAC;QACD,8EAA8E;QAC9E,IAAI,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,sBAAsB,EAAE,CAAC;YAC3F,MAAM,wBAAwB,CAAC,IAAI,CAAC,sBAAsB,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;QAC5F,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC;IACnD,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,MAAM,CACR,oCAAoC,EACpC,EAAE,UAAU,EAAE,YAAY,CAAC,wBAAwB,CAAC,EAAE,EACtD,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACvB,sEAAsE;QACtE,uEAAuE;QACvE,kEAAkE;QAClE,wEAAwE;QACxE,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CACvB,+BAA+B,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,uBAAuB,CAAC,CACjF,CAAC;QACF,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAClC,CAAC,CACF,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,QAA6B,EAAE,GAAW;IACnE,IAAI,CAAC;QACH,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,wBAAwB,EAAE,CAAC;YAC5C,MAAM,IAAI,SAAS,CAAC,GAAG,EAAE,WAAW,CAAC,iBAAiB,EAAE,yBAAyB,GAAG,IAAI,CAAC,CAAC;QAC5F,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,wBAAwB,CACrC,UAAsC,EACtC,QAAgB,EAChB,iBAA2B;IAE3B,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,qBAAqB,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IACpF,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC3C,uEAAuE;IACvE,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACzB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,MAAM,UAAU,CAAC,YAAY,CAAC,EAAE,EAAE,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IAC1F,CAAC;IACD,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,MAAM,UAAU,CAAC,iBAAiB,CAAC,EAAE,EAAE,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IAC5F,CAAC;AACH,CAAC;AAED,SAAS,uBAAuB,CAAC,CAAiB,EAAE,IAA4C;IAC9F,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE;QACtD,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,WAAW,EAAE,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC;KAC7C,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,CAAiB,EAAE,IAA8B;IAC7E,MAAM,QAAQ,GAAG,IAAI,CAAC,sBAAsB;QAC1C,CAAC,CAAC,MAAM,IAAI,CAAC,sBAAsB,CAAC,qBAAqB,CAAC,iBAAiB,EAAE,CAAC,CAAC,EAAE,CAAC;QAClF,CAAC,CAAC,EAAE,CAAC;IACP,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE;QACtD,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,eAAe,EAAE,CAAC,CAAC,eAAe;QAClC,eAAe,EAAE,CAAC,CAAC,eAAe;QAClC,eAAe,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1C,WAAW,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK,IAAI,IAAI;KACrE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import type { DeliveryMethodReadPort, DeliveryMethodRecord } from '@endora-commerce/contracts';
|
|
3
|
+
import { DeliveryMethod } from '../entities/delivery-method.entity.js';
|
|
4
|
+
/**
|
|
5
|
+
* The row-level read model `delivery_methods` publishes (feature 075, Phase P).
|
|
6
|
+
*
|
|
7
|
+
* Five of the thirteen inbound sites read the entity: `orders` resolving the
|
|
8
|
+
* method at placement, `shipments` resolving it at dispatch and again in its
|
|
9
|
+
* receive handler, `quick_order` resolving a buyer's default, and the dev
|
|
10
|
+
* seed.
|
|
11
|
+
*
|
|
12
|
+
* `cost` stays a decimal string — it lands verbatim in the order's
|
|
13
|
+
* `deliveryMethodSnapshot`, and a `number` cannot round-trip it.
|
|
14
|
+
*/
|
|
15
|
+
export declare class DeliveryMethodReadService implements DeliveryMethodReadPort {
|
|
16
|
+
private readonly emFactory;
|
|
17
|
+
constructor(emFactory: () => EntityManager);
|
|
18
|
+
findById(id: string): Promise<DeliveryMethodRecord | null>;
|
|
19
|
+
findByIds(ids: readonly string[]): Promise<DeliveryMethodRecord[]>;
|
|
20
|
+
findByCode(code: string): Promise<DeliveryMethodRecord | null>;
|
|
21
|
+
listAll(): Promise<DeliveryMethodRecord[]>;
|
|
22
|
+
listActive(): Promise<DeliveryMethodRecord[]>;
|
|
23
|
+
}
|
|
24
|
+
export declare function toDeliveryMethodRecord(method: DeliveryMethod): DeliveryMethodRecord;
|
|
25
|
+
//# sourceMappingURL=delivery-method-read-port.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivery-method-read-port.d.ts","sourceRoot":"","sources":["../../../src/backend/services/delivery-method-read-port.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAC/F,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAEvE;;;;;;;;;;GAUG;AACH,qBAAa,yBAA0B,YAAW,sBAAsB;IAC1D,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM,aAAa;IAErD,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAK1D,SAAS,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAMlE,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAK9D,OAAO,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAK1C,UAAU,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;CAQpD;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,cAAc,GAAG,oBAAoB,CAcnF"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { DeliveryMethod } from '../entities/delivery-method.entity.js';
|
|
2
|
+
/**
|
|
3
|
+
* The row-level read model `delivery_methods` publishes (feature 075, Phase P).
|
|
4
|
+
*
|
|
5
|
+
* Five of the thirteen inbound sites read the entity: `orders` resolving the
|
|
6
|
+
* method at placement, `shipments` resolving it at dispatch and again in its
|
|
7
|
+
* receive handler, `quick_order` resolving a buyer's default, and the dev
|
|
8
|
+
* seed.
|
|
9
|
+
*
|
|
10
|
+
* `cost` stays a decimal string — it lands verbatim in the order's
|
|
11
|
+
* `deliveryMethodSnapshot`, and a `number` cannot round-trip it.
|
|
12
|
+
*/
|
|
13
|
+
export class DeliveryMethodReadService {
|
|
14
|
+
emFactory;
|
|
15
|
+
constructor(emFactory) {
|
|
16
|
+
this.emFactory = emFactory;
|
|
17
|
+
}
|
|
18
|
+
async findById(id) {
|
|
19
|
+
const method = await this.emFactory().findOne(DeliveryMethod, { id });
|
|
20
|
+
return method ? toDeliveryMethodRecord(method) : null;
|
|
21
|
+
}
|
|
22
|
+
async findByIds(ids) {
|
|
23
|
+
if (ids.length === 0)
|
|
24
|
+
return [];
|
|
25
|
+
const methods = await this.emFactory().find(DeliveryMethod, { id: { $in: [...ids] } });
|
|
26
|
+
return methods.map(toDeliveryMethodRecord);
|
|
27
|
+
}
|
|
28
|
+
async findByCode(code) {
|
|
29
|
+
const method = await this.emFactory().findOne(DeliveryMethod, { code });
|
|
30
|
+
return method ? toDeliveryMethodRecord(method) : null;
|
|
31
|
+
}
|
|
32
|
+
async listAll() {
|
|
33
|
+
const methods = await this.emFactory().find(DeliveryMethod, {}, { orderBy: { code: 'asc' } });
|
|
34
|
+
return methods.map(toDeliveryMethodRecord);
|
|
35
|
+
}
|
|
36
|
+
async listActive() {
|
|
37
|
+
const methods = await this.emFactory().find(DeliveryMethod, { status: 'active' }, { orderBy: { code: 'asc' } });
|
|
38
|
+
return methods.map(toDeliveryMethodRecord);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function toDeliveryMethodRecord(method) {
|
|
42
|
+
return {
|
|
43
|
+
id: method.id,
|
|
44
|
+
code: method.code,
|
|
45
|
+
name: method.name,
|
|
46
|
+
cost: method.cost,
|
|
47
|
+
currency: method.currency,
|
|
48
|
+
status: method.status,
|
|
49
|
+
adapter: method.adapter,
|
|
50
|
+
statusOnSuccess: method.statusOnSuccess,
|
|
51
|
+
statusOnFailure: method.statusOnFailure,
|
|
52
|
+
createdAt: method.createdAt,
|
|
53
|
+
updatedAt: method.updatedAt,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=delivery-method-read-port.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivery-method-read-port.js","sourceRoot":"","sources":["../../../src/backend/services/delivery-method-read-port.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAEvE;;;;;;;;;;GAUG;AACH,MAAM,OAAO,yBAAyB;IACP;IAA7B,YAA6B,SAA8B;QAA9B,cAAS,GAAT,SAAS,CAAqB;IAAG,CAAC;IAE/D,KAAK,CAAC,QAAQ,CAAC,EAAU;QACvB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QACtE,OAAO,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,GAAsB;QACpC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QACvF,OAAO,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAY;QAC3B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QACxE,OAAO,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QAC9F,OAAO,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,UAAU;QACd,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CACzC,cAAc,EACd,EAAE,MAAM,EAAE,QAAQ,EAAE,EACpB,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAC7B,CAAC;QACF,OAAO,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IAC7C,CAAC;CACF;AAED,MAAM,UAAU,sBAAsB,CAAC,MAAsB;IAC3D,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import type { DeliveryMethodSeedApi, DeliveryMethodSeedDefaults, DeliveryMethodSeedOutcome } from '../../ports/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* DeliveryMethodReconciler (feature 035, FR-002) — the implementation behind
|
|
5
|
+
* `DeliveryMethodSeedApi`, this module's published install surface
|
|
6
|
+
* (`../../ports/index.ts`, `createDeliveryMethodSeeder` below).
|
|
7
|
+
*
|
|
8
|
+
* A module that must create its `delivery_methods` row from code calls
|
|
9
|
+
* `ensureMethodForAdapter` from its **install hook**, so installing a
|
|
10
|
+
* shipping-method module surfaces a configurable entry at `/delivery-methods`
|
|
11
|
+
* with no core change. Idempotent and prune-safe: an existing row (matched by
|
|
12
|
+
* `code`) keeps its admin-edited configuration; the reconciler only fills a
|
|
13
|
+
* missing `adapter` link.
|
|
14
|
+
*
|
|
15
|
+
* The row and the adapter are contributed at **different moments, on purpose**.
|
|
16
|
+
* This row is durable state and is written once, at install; the adapter is an
|
|
17
|
+
* in-memory entry in a per-process table and is pushed from the contributing
|
|
18
|
+
* module's boot hook, on every composition (see `shipping-adapter-registry.ts`).
|
|
19
|
+
* Neither waits for the other: a row whose `adapter` key nothing has contributed
|
|
20
|
+
* is simply not offered, and the registry is not read until a request reads it.
|
|
21
|
+
*
|
|
22
|
+
* **The `EntityManager` is a parameter of every method and is never held**
|
|
23
|
+
* (feature 134, FR-064; D-169). It used to be a constructor `emFactory`, which is
|
|
24
|
+
* the shape of a service resolved from a container — and the caller this class
|
|
25
|
+
* was written for has no container: `ModuleLifecycleContext` is
|
|
26
|
+
* `{ em, redis, log, module }` and `module:install` composes nothing (D-46). The
|
|
27
|
+
* hook's own `ctx.em` is therefore what every statement here runs on, handed in
|
|
28
|
+
* at the call, so the write lands in the transaction the orchestrator will
|
|
29
|
+
* commit or revert rather than on a fork of it.
|
|
30
|
+
*
|
|
31
|
+
* **It no longer rebinds sales-channel membership (issue #96)** — see the
|
|
32
|
+
* payment twin (`payment_methods/services/payment-method-reconciler.ts`).
|
|
33
|
+
* `bindToDefaultChannel` exists, and is the seed's own *once, for the rows it
|
|
34
|
+
* creates* half rather than a reconcile: the caller guards it on
|
|
35
|
+
* `created === true`. What issue #96 removed was the unconditional call, which
|
|
36
|
+
* brought a method an operator had deliberately unbound from every channel back
|
|
37
|
+
* to Default at the next boot, and nothing said so. "Unbound" is a state an
|
|
38
|
+
* operator is entitled to reach and to keep.
|
|
39
|
+
*/
|
|
40
|
+
export declare class DeliveryMethodReconciler implements DeliveryMethodSeedApi {
|
|
41
|
+
ensureMethodForAdapter(em: EntityManager, adapterKey: string, defaults: DeliveryMethodSeedDefaults): Promise<DeliveryMethodSeedOutcome>;
|
|
42
|
+
/**
|
|
43
|
+
* The seed's channel binding — one membership row in the system-default
|
|
44
|
+
* channel, written against **this module's own** bridge table.
|
|
45
|
+
*
|
|
46
|
+
* Not through `SalesChannelMembershipService`, and the reason is structural
|
|
47
|
+
* rather than a preference: that service needs the `EventBus`, the audit port
|
|
48
|
+
* and the channel-bridge registry, and the registry is contributed from a boot
|
|
49
|
+
* hook. An install composes nothing, so at this seam it holds no registration
|
|
50
|
+
* for `'delivery-method'` and `bridges.require` would refuse (FR-017) before
|
|
51
|
+
* the database was touched. `sales_channel_delivery_methods` is this module's
|
|
52
|
+
* since `specs/120-migration-closure-bridge-ownership/` Phase 2 (D-226), so the
|
|
53
|
+
* statement is the owner's own and crosses no boundary — which is what FR-064
|
|
54
|
+
* buys by putting the writer here instead of in the seeding module.
|
|
55
|
+
*
|
|
56
|
+
* The channel itself is read through the kernel's own `SalesChannel` entity
|
|
57
|
+
* rather than in SQL — `api_keys` reads it the same way — because a raw
|
|
58
|
+
* `select … from "sales_channels"` from a module is a `check:module-boundary`
|
|
59
|
+
* finding against a kernel-owned table, and correctly so: the table is not
|
|
60
|
+
* this module's and the entity is the platform's published name for it.
|
|
61
|
+
*
|
|
62
|
+
* `em.execute` for the insert rather than `em.getConnection().execute`, so the
|
|
63
|
+
* statement runs inside the caller's transaction (issue #200). The bridge has
|
|
64
|
+
* no entity class — the kernel's membership service writes it in SQL too.
|
|
65
|
+
*
|
|
66
|
+
* **No system-default channel answers `false` rather than raising, and that is
|
|
67
|
+
* measured rather than defensive.** The default channel is created by
|
|
68
|
+
* `DefaultChannelReconciler` at **boot**, from `composeApp` — not by a migration
|
|
69
|
+
* and not by an install — and `module:install` composes nothing (D-46). So a
|
|
70
|
+
* database that has been migrated and never booted has no default channel, and
|
|
71
|
+
* a seeding module installed there is the ordinary case, not a broken instance:
|
|
72
|
+
* `pnpm --filter backend run db:fresh && module:install dhl_parcel` is exactly
|
|
73
|
+
* it. The seed migration this replaced degraded the same way, silently — its
|
|
74
|
+
* `cross join "sales_channels" where "system_default"` produced no rows and
|
|
75
|
+
* inserted no membership — so answering `false` is what keeps a fresh install
|
|
76
|
+
* and an upgraded one at the same row state in that state too. Raising instead
|
|
77
|
+
* **aborts the install**, and the hook is not inside a database transaction:
|
|
78
|
+
* measured on a throwaway database, the first of two rows stayed and the second
|
|
79
|
+
* never arrived.
|
|
80
|
+
*/
|
|
81
|
+
bindToDefaultChannel(em: EntityManager, deliveryMethodId: string): Promise<boolean>;
|
|
82
|
+
/**
|
|
83
|
+
* The hard-uninstall half. Channel memberships go with the row: the bridge's
|
|
84
|
+
* foreign key onto `delivery_methods` is `on delete cascade`.
|
|
85
|
+
*/
|
|
86
|
+
removeMethodForAdapter(em: EntityManager, code: string): Promise<boolean>;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The runtime half of this module's install surface (feature 134, FR-064).
|
|
90
|
+
*
|
|
91
|
+
* A seeding module's `installHook` writes `createDeliveryMethodSeeder()` and
|
|
92
|
+
* hands `ctx.em` to each call. The factory takes no arguments because the `em`
|
|
93
|
+
* belongs to the call and not to the seeder: one `em`, named at every statement,
|
|
94
|
+
* with no second source of truth for which transaction the write lands in.
|
|
95
|
+
*/
|
|
96
|
+
export declare function createDeliveryMethodSeeder(): DeliveryMethodSeedApi;
|
|
97
|
+
//# sourceMappingURL=delivery-method-reconciler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivery-method-reconciler.d.ts","sourceRoot":"","sources":["../../../src/backend/services/delivery-method-reconciler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EACV,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EAE1B,MAAM,sBAAsB,CAAC;AAG9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,wBAAyB,YAAW,qBAAqB;IAC9D,sBAAsB,CAC1B,EAAE,EAAE,aAAa,EACjB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,0BAA0B,GACnC,OAAO,CAAC,yBAAyB,CAAC;IA4BrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAsCG;IACG,oBAAoB,CAAC,EAAE,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAezF;;;OAGG;IACG,sBAAsB,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAOhF;AAoBD;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,IAAI,qBAAqB,CAElE"}
|