@endora-commerce/mod-inventory 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 +61 -0
- package/dist/admin/api/warehouses-client.d.ts +22 -0
- package/dist/admin/api/warehouses-client.d.ts.map +1 -0
- package/dist/admin/api/warehouses-client.js +32 -0
- package/dist/admin/api/warehouses-client.js.map +1 -0
- package/dist/admin/index.d.ts +43 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +190 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/AvailabilityNotificationsPage.d.ts +15 -0
- package/dist/admin/pages/AvailabilityNotificationsPage.d.ts.map +1 -0
- package/dist/admin/pages/AvailabilityNotificationsPage.js +111 -0
- package/dist/admin/pages/AvailabilityNotificationsPage.js.map +1 -0
- package/dist/admin/pages/InventoryPage.d.ts +17 -0
- package/dist/admin/pages/InventoryPage.d.ts.map +1 -0
- package/dist/admin/pages/InventoryPage.js +135 -0
- package/dist/admin/pages/InventoryPage.js.map +1 -0
- package/dist/admin/pages/LowStockPage.d.ts +16 -0
- package/dist/admin/pages/LowStockPage.d.ts.map +1 -0
- package/dist/admin/pages/LowStockPage.js +61 -0
- package/dist/admin/pages/LowStockPage.js.map +1 -0
- package/dist/admin/pages/StockImportWizard.d.ts +17 -0
- package/dist/admin/pages/StockImportWizard.d.ts.map +1 -0
- package/dist/admin/pages/StockImportWizard.js +111 -0
- package/dist/admin/pages/StockImportWizard.js.map +1 -0
- package/dist/admin/pages/WarehouseEditor.d.ts +12 -0
- package/dist/admin/pages/WarehouseEditor.d.ts.map +1 -0
- package/dist/admin/pages/WarehouseEditor.js +194 -0
- package/dist/admin/pages/WarehouseEditor.js.map +1 -0
- package/dist/admin/pages/WarehousesList.d.ts +12 -0
- package/dist/admin/pages/WarehousesList.d.ts.map +1 -0
- package/dist/admin/pages/WarehousesList.js +69 -0
- package/dist/admin/pages/WarehousesList.js.map +1 -0
- package/dist/admin/zones/ChannelWarehouses.d.ts +49 -0
- package/dist/admin/zones/ChannelWarehouses.d.ts.map +1 -0
- package/dist/admin/zones/ChannelWarehouses.js +109 -0
- package/dist/admin/zones/ChannelWarehouses.js.map +1 -0
- package/dist/backend/demo/reset.d.ts +18 -0
- package/dist/backend/demo/reset.d.ts.map +1 -0
- package/dist/backend/demo/reset.js +20 -0
- package/dist/backend/demo/reset.js.map +1 -0
- package/dist/backend/demo/rows.d.ts +38 -0
- package/dist/backend/demo/rows.d.ts.map +1 -0
- package/dist/backend/demo/rows.js +38 -0
- package/dist/backend/demo/rows.js.map +1 -0
- package/dist/backend/demo/seed.d.ts +26 -0
- package/dist/backend/demo/seed.d.ts.map +1 -0
- package/dist/backend/demo/seed.js +65 -0
- package/dist/backend/demo/seed.js.map +1 -0
- package/dist/backend/email-templates/transactional-defaults.d.ts +11 -0
- package/dist/backend/email-templates/transactional-defaults.d.ts.map +1 -0
- package/dist/backend/email-templates/transactional-defaults.js +49 -0
- package/dist/backend/email-templates/transactional-defaults.js.map +1 -0
- package/dist/backend/entities/availability-notification.entity.d.ts +49 -0
- package/dist/backend/entities/availability-notification.entity.d.ts.map +1 -0
- package/dist/backend/entities/availability-notification.entity.js +93 -0
- package/dist/backend/entities/availability-notification.entity.js.map +1 -0
- package/dist/backend/entities/inventory-threshold.entity.d.ts +24 -0
- package/dist/backend/entities/inventory-threshold.entity.d.ts.map +1 -0
- package/dist/backend/entities/inventory-threshold.entity.js +61 -0
- package/dist/backend/entities/inventory-threshold.entity.js.map +1 -0
- package/dist/backend/entities/product-warehouse-low-stock-threshold.entity.d.ts +15 -0
- package/dist/backend/entities/product-warehouse-low-stock-threshold.entity.d.ts.map +1 -0
- package/dist/backend/entities/product-warehouse-low-stock-threshold.entity.js +51 -0
- package/dist/backend/entities/product-warehouse-low-stock-threshold.entity.js.map +1 -0
- package/dist/backend/entities/stock-allocation.entity.d.ts +22 -0
- package/dist/backend/entities/stock-allocation.entity.d.ts.map +1 -0
- package/dist/backend/entities/stock-allocation.entity.js +69 -0
- package/dist/backend/entities/stock-allocation.entity.js.map +1 -0
- package/dist/backend/entities/stock-level.entity.d.ts +24 -0
- package/dist/backend/entities/stock-level.entity.d.ts.map +1 -0
- package/dist/backend/entities/stock-level.entity.js +74 -0
- package/dist/backend/entities/stock-level.entity.js.map +1 -0
- package/dist/backend/entities/warehouse-channel-assignment.entity.d.ts +17 -0
- package/dist/backend/entities/warehouse-channel-assignment.entity.d.ts.map +1 -0
- package/dist/backend/entities/warehouse-channel-assignment.entity.js +60 -0
- package/dist/backend/entities/warehouse-channel-assignment.entity.js.map +1 -0
- package/dist/backend/entities/warehouse.entity.d.ts +37 -0
- package/dist/backend/entities/warehouse.entity.d.ts.map +1 -0
- package/dist/backend/entities/warehouse.entity.js +90 -0
- package/dist/backend/entities/warehouse.entity.js.map +1 -0
- package/dist/backend/index.d.ts +139 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +351 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/plugin.d.ts +113 -0
- package/dist/backend/plugin.d.ts.map +1 -0
- package/dist/backend/plugin.js +75 -0
- package/dist/backend/plugin.js.map +1 -0
- package/dist/backend/prompt-tools.d.ts +23 -0
- package/dist/backend/prompt-tools.d.ts.map +1 -0
- package/dist/backend/prompt-tools.js +77 -0
- package/dist/backend/prompt-tools.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +62 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +383 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.d.ts +40 -0
- package/dist/backend/routes.d.ts.map +1 -0
- package/dist/backend/routes.js +263 -0
- package/dist/backend/routes.js.map +1 -0
- package/dist/backend/services/audit-references.d.ts +15 -0
- package/dist/backend/services/audit-references.d.ts.map +1 -0
- package/dist/backend/services/audit-references.js +27 -0
- package/dist/backend/services/audit-references.js.map +1 -0
- package/dist/backend/services/availability-notification-service.d.ts +155 -0
- package/dist/backend/services/availability-notification-service.d.ts.map +1 -0
- package/dist/backend/services/availability-notification-service.js +363 -0
- package/dist/backend/services/availability-notification-service.js.map +1 -0
- package/dist/backend/services/availability-worker.d.ts +57 -0
- package/dist/backend/services/availability-worker.d.ts.map +1 -0
- package/dist/backend/services/availability-worker.js +135 -0
- package/dist/backend/services/availability-worker.js.map +1 -0
- package/dist/backend/services/csv-stock-importer.d.ts +52 -0
- package/dist/backend/services/csv-stock-importer.d.ts.map +1 -0
- package/dist/backend/services/csv-stock-importer.js +154 -0
- package/dist/backend/services/csv-stock-importer.js.map +1 -0
- package/dist/backend/services/display-band-resolver.d.ts +19 -0
- package/dist/backend/services/display-band-resolver.d.ts.map +1 -0
- package/dist/backend/services/display-band-resolver.js +21 -0
- package/dist/backend/services/display-band-resolver.js.map +1 -0
- package/dist/backend/services/effective-fulfilment-strategy.d.ts +16 -0
- package/dist/backend/services/effective-fulfilment-strategy.d.ts.map +1 -0
- package/dist/backend/services/effective-fulfilment-strategy.js +16 -0
- package/dist/backend/services/effective-fulfilment-strategy.js.map +1 -0
- package/dist/backend/services/fulfilment-strategy-resolver.d.ts +13 -0
- package/dist/backend/services/fulfilment-strategy-resolver.d.ts.map +1 -0
- package/dist/backend/services/fulfilment-strategy-resolver.js +13 -0
- package/dist/backend/services/fulfilment-strategy-resolver.js.map +1 -0
- package/dist/backend/services/inventory-read-port.d.ts +65 -0
- package/dist/backend/services/inventory-read-port.d.ts.map +1 -0
- package/dist/backend/services/inventory-read-port.js +168 -0
- package/dist/backend/services/inventory-read-port.js.map +1 -0
- package/dist/backend/services/inventory-reservation-apply-port.d.ts +62 -0
- package/dist/backend/services/inventory-reservation-apply-port.d.ts.map +1 -0
- package/dist/backend/services/inventory-reservation-apply-port.js +134 -0
- package/dist/backend/services/inventory-reservation-apply-port.js.map +1 -0
- package/dist/backend/services/low-stock-alert-service.d.ts +87 -0
- package/dist/backend/services/low-stock-alert-service.d.ts.map +1 -0
- package/dist/backend/services/low-stock-alert-service.js +164 -0
- package/dist/backend/services/low-stock-alert-service.js.map +1 -0
- package/dist/backend/services/product-threshold-write.service.d.ts +38 -0
- package/dist/backend/services/product-threshold-write.service.d.ts.map +1 -0
- package/dist/backend/services/product-threshold-write.service.js +80 -0
- package/dist/backend/services/product-threshold-write.service.js.map +1 -0
- package/dist/backend/services/stock-import.service.d.ts +43 -0
- package/dist/backend/services/stock-import.service.d.ts.map +1 -0
- package/dist/backend/services/stock-import.service.js +124 -0
- package/dist/backend/services/stock-import.service.js.map +1 -0
- package/dist/backend/services/stock-level-service.d.ts +146 -0
- package/dist/backend/services/stock-level-service.d.ts.map +1 -0
- package/dist/backend/services/stock-level-service.js +489 -0
- package/dist/backend/services/stock-level-service.js.map +1 -0
- package/dist/backend/services/threshold-admin-service.d.ts +73 -0
- package/dist/backend/services/threshold-admin-service.d.ts.map +1 -0
- package/dist/backend/services/threshold-admin-service.js +167 -0
- package/dist/backend/services/threshold-admin-service.js.map +1 -0
- package/dist/backend/services/threshold-resolver.d.ts +23 -0
- package/dist/backend/services/threshold-resolver.d.ts.map +1 -0
- package/dist/backend/services/threshold-resolver.js +29 -0
- package/dist/backend/services/threshold-resolver.js.map +1 -0
- package/dist/backend/services/threshold-settings-mirror.d.ts +55 -0
- package/dist/backend/services/threshold-settings-mirror.d.ts.map +1 -0
- package/dist/backend/services/threshold-settings-mirror.js +84 -0
- package/dist/backend/services/threshold-settings-mirror.js.map +1 -0
- package/dist/backend/services/warehouse-channel-reconciler.d.ts +19 -0
- package/dist/backend/services/warehouse-channel-reconciler.d.ts.map +1 -0
- package/dist/backend/services/warehouse-channel-reconciler.js +65 -0
- package/dist/backend/services/warehouse-channel-reconciler.js.map +1 -0
- package/dist/backend/services/warehouse-channel-service.d.ts +57 -0
- package/dist/backend/services/warehouse-channel-service.d.ts.map +1 -0
- package/dist/backend/services/warehouse-channel-service.js +205 -0
- package/dist/backend/services/warehouse-channel-service.js.map +1 -0
- package/dist/backend/services/warehouse-country-reference.d.ts +14 -0
- package/dist/backend/services/warehouse-country-reference.d.ts.map +1 -0
- package/dist/backend/services/warehouse-country-reference.js +27 -0
- package/dist/backend/services/warehouse-country-reference.js.map +1 -0
- package/dist/backend/services/warehouse-service.d.ts +86 -0
- package/dist/backend/services/warehouse-service.d.ts.map +1 -0
- package/dist/backend/services/warehouse-service.js +267 -0
- package/dist/backend/services/warehouse-service.js.map +1 -0
- package/dist/manifest.d.ts +219 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +377 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260503T182812_inventory_workflow.d.ts +39 -0
- package/dist/migrations/20260503T182812_inventory_workflow.d.ts.map +1 -0
- package/dist/migrations/20260503T182812_inventory_workflow.js +205 -0
- package/dist/migrations/20260503T182812_inventory_workflow.js.map +1 -0
- package/dist/migrations/20260611T140347_inventory_warehouse_default_low_stock_threshold.d.ts +14 -0
- package/dist/migrations/20260611T140347_inventory_warehouse_default_low_stock_threshold.d.ts.map +1 -0
- package/dist/migrations/20260611T140347_inventory_warehouse_default_low_stock_threshold.js +18 -0
- package/dist/migrations/20260611T140347_inventory_warehouse_default_low_stock_threshold.js.map +1 -0
- package/dist/migrations/20260611T140348_inventory_per_warehouse_low_stock_thresholds.d.ts +28 -0
- package/dist/migrations/20260611T140348_inventory_per_warehouse_low_stock_thresholds.d.ts.map +1 -0
- package/dist/migrations/20260611T140348_inventory_per_warehouse_low_stock_thresholds.js +48 -0
- package/dist/migrations/20260611T140348_inventory_per_warehouse_low_stock_thresholds.js.map +1 -0
- package/dist/migrations/20260818T081243_inventory_stock_allocation_order_item_fk.d.ts +44 -0
- package/dist/migrations/20260818T081243_inventory_stock_allocation_order_item_fk.d.ts.map +1 -0
- package/dist/migrations/20260818T081243_inventory_stock_allocation_order_item_fk.js +81 -0
- package/dist/migrations/20260818T081243_inventory_stock_allocation_order_item_fk.js.map +1 -0
- package/dist/migrations/20260830T182139_inventory_organization_attribution.d.ts +109 -0
- package/dist/migrations/20260830T182139_inventory_organization_attribution.d.ts.map +1 -0
- package/dist/migrations/20260830T182139_inventory_organization_attribution.js +178 -0
- package/dist/migrations/20260830T182139_inventory_organization_attribution.js.map +1 -0
- package/dist/migrations/20260912T125716_inventory_organization_warehouses.d.ts +34 -0
- package/dist/migrations/20260912T125716_inventory_organization_warehouses.d.ts.map +1 -0
- package/dist/migrations/20260912T125716_inventory_organization_warehouses.js +50 -0
- package/dist/migrations/20260912T125716_inventory_organization_warehouses.js.map +1 -0
- package/dist/migrations/index.d.ts +32 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +39 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/ports/index.d.ts +183 -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/inventory.md +177 -0
- package/i18n/en.json +32 -0
- package/i18n/pl.json +32 -0
- package/package.json +105 -0
- package/tailwind.css +14 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { HttpError } from '@endora-commerce/platform/http';
|
|
2
|
+
import { InventoryThreshold } from '../entities/inventory-threshold.entity.js';
|
|
3
|
+
/**
|
|
4
|
+
* ThresholdAdminService (US5 / FR-017).
|
|
5
|
+
*
|
|
6
|
+
* Reads + writes the inventory display-band thresholds. Storage:
|
|
7
|
+
* - global → singleton row in `inventory_thresholds` (scopeKind='global')
|
|
8
|
+
* - perCategory → `categories.inventory_threshold_*` columns
|
|
9
|
+
* - perProduct → `inventory_thresholds` rows with scopeKind='product'
|
|
10
|
+
*
|
|
11
|
+
* The split exists for read-path performance: category thresholds inline
|
|
12
|
+
* with the category row keep the storefront resolver one query light.
|
|
13
|
+
*/
|
|
14
|
+
export class ThresholdAdminService {
|
|
15
|
+
emFactory;
|
|
16
|
+
catalogCategories;
|
|
17
|
+
catalogCategoryWrites;
|
|
18
|
+
catalogProducts;
|
|
19
|
+
auditLog;
|
|
20
|
+
constructor(emFactory,
|
|
21
|
+
/** `catalogCategoryReadPort`, owned by `catalog` (feature 075, Phase C). */
|
|
22
|
+
catalogCategories,
|
|
23
|
+
/**
|
|
24
|
+
* `catalogCategoryWritePort`, owned by `catalog`. The per-category half of
|
|
25
|
+
* these thresholds lives in three columns on `catalog`'s `categories` row,
|
|
26
|
+
* so the write belongs to `catalog` and this module hands it the patch.
|
|
27
|
+
*/
|
|
28
|
+
catalogCategoryWrites,
|
|
29
|
+
/** `catalogProductReadPort`, owned by `catalog` — the per-product existence check. */
|
|
30
|
+
catalogProducts, auditLog) {
|
|
31
|
+
this.emFactory = emFactory;
|
|
32
|
+
this.catalogCategories = catalogCategories;
|
|
33
|
+
this.catalogCategoryWrites = catalogCategoryWrites;
|
|
34
|
+
this.catalogProducts = catalogProducts;
|
|
35
|
+
this.auditLog = auditLog;
|
|
36
|
+
}
|
|
37
|
+
async read() {
|
|
38
|
+
const em = this.emFactory();
|
|
39
|
+
const globalRow = await em.findOne(InventoryThreshold, {
|
|
40
|
+
scopeKind: 'global',
|
|
41
|
+
scopeId: null,
|
|
42
|
+
});
|
|
43
|
+
const global = {
|
|
44
|
+
high: globalRow?.thresholdHigh ?? 100,
|
|
45
|
+
medium: globalRow?.thresholdMedium ?? 20,
|
|
46
|
+
low: globalRow?.thresholdLow ?? 1,
|
|
47
|
+
};
|
|
48
|
+
const perCategoryRows = await this.catalogCategories.listWithInventoryThresholds();
|
|
49
|
+
const perCategory = perCategoryRows.map((c) => ({
|
|
50
|
+
categoryId: c.id,
|
|
51
|
+
high: c.inventoryThresholdHigh,
|
|
52
|
+
medium: c.inventoryThresholdMedium,
|
|
53
|
+
low: c.inventoryThresholdLow,
|
|
54
|
+
}));
|
|
55
|
+
const perProductRows = await em.find(InventoryThreshold, { scopeKind: 'product' });
|
|
56
|
+
const perProduct = perProductRows.map((r) => ({
|
|
57
|
+
productId: r.scopeId,
|
|
58
|
+
high: r.thresholdHigh ?? null,
|
|
59
|
+
medium: r.thresholdMedium ?? null,
|
|
60
|
+
low: r.thresholdLow ?? null,
|
|
61
|
+
}));
|
|
62
|
+
return { global, perCategory, perProduct };
|
|
63
|
+
}
|
|
64
|
+
async patch(input, auditCtx) {
|
|
65
|
+
const em = this.emFactory();
|
|
66
|
+
// Validate every scope before applying any of it (feature 075, Phase C).
|
|
67
|
+
// The category half is `catalog`'s write now, so it no longer shares this
|
|
68
|
+
// module's flush: an unknown product id used to roll the whole patch back
|
|
69
|
+
// because nothing had been flushed yet, and it still applies nothing —
|
|
70
|
+
// because nothing has been *written* yet.
|
|
71
|
+
if (input.perCategory) {
|
|
72
|
+
for (const c of input.perCategory) {
|
|
73
|
+
const category = await this.catalogCategories.findById(c.categoryId);
|
|
74
|
+
if (!category) {
|
|
75
|
+
throw new HttpError(404, 'NOT_FOUND', `Category ${c.categoryId} not found`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (input.perProduct) {
|
|
80
|
+
for (const p of input.perProduct) {
|
|
81
|
+
const product = await this.catalogProducts.findById(p.productId);
|
|
82
|
+
if (!product) {
|
|
83
|
+
throw new HttpError(404, 'PRODUCT_NOT_FOUND', `Product ${p.productId} not found`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (input.global) {
|
|
88
|
+
await this.applyGlobal(em, input.global);
|
|
89
|
+
}
|
|
90
|
+
if (input.perProduct) {
|
|
91
|
+
for (const p of input.perProduct) {
|
|
92
|
+
await this.applyProduct(em, p);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
await em.flush();
|
|
96
|
+
if (input.perCategory) {
|
|
97
|
+
for (const c of input.perCategory) {
|
|
98
|
+
await this.catalogCategoryWrites.setInventoryThresholds(c.categoryId, {
|
|
99
|
+
...(c.high !== undefined ? { high: c.high } : {}),
|
|
100
|
+
...(c.medium !== undefined ? { medium: c.medium } : {}),
|
|
101
|
+
...(c.low !== undefined ? { low: c.low } : {}),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const view = await this.read();
|
|
106
|
+
// Feature 024 — audit threshold patches as a single
|
|
107
|
+
// `low_stock_threshold.update` row per request. Bulk patches across
|
|
108
|
+
// global / perCategory / perProduct collapse into one summary row so
|
|
109
|
+
// the dashboard isn't flooded (FR-011, SC-010).
|
|
110
|
+
if (this.auditLog && auditCtx) {
|
|
111
|
+
const touched = {};
|
|
112
|
+
if (input.global)
|
|
113
|
+
touched['global'] = input.global;
|
|
114
|
+
if (input.perCategory)
|
|
115
|
+
touched['perCategoryCount'] = input.perCategory.length;
|
|
116
|
+
if (input.perProduct)
|
|
117
|
+
touched['perProductCount'] = input.perProduct.length;
|
|
118
|
+
await this.auditLog.record({
|
|
119
|
+
actorAdminUserId: auditCtx.actorAdminUserId,
|
|
120
|
+
...(auditCtx.impersonatedCustomerAccountId !== undefined
|
|
121
|
+
? { impersonatedCustomerAccountId: auditCtx.impersonatedCustomerAccountId }
|
|
122
|
+
: {}),
|
|
123
|
+
action: 'low_stock_threshold.update',
|
|
124
|
+
objectType: 'low_stock_threshold',
|
|
125
|
+
objectId: 'global',
|
|
126
|
+
stateAfter: touched,
|
|
127
|
+
...(auditCtx.ipAddress !== undefined ? { ipAddress: auditCtx.ipAddress } : {}),
|
|
128
|
+
...(auditCtx.userAgent !== undefined ? { userAgent: auditCtx.userAgent } : {}),
|
|
129
|
+
...(auditCtx.requestId !== undefined ? { requestId: auditCtx.requestId } : {}),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return view;
|
|
133
|
+
}
|
|
134
|
+
async applyGlobal(em, patch) {
|
|
135
|
+
let row = await em.findOne(InventoryThreshold, { scopeKind: 'global', scopeId: null });
|
|
136
|
+
if (!row) {
|
|
137
|
+
row = em.create(InventoryThreshold, { scopeKind: 'global', scopeId: null });
|
|
138
|
+
em.persist(row);
|
|
139
|
+
}
|
|
140
|
+
if (patch.high !== undefined)
|
|
141
|
+
row.thresholdHigh = patch.high;
|
|
142
|
+
if (patch.medium !== undefined)
|
|
143
|
+
row.thresholdMedium = patch.medium;
|
|
144
|
+
if (patch.low !== undefined)
|
|
145
|
+
row.thresholdLow = patch.low;
|
|
146
|
+
}
|
|
147
|
+
async applyProduct(em, patch) {
|
|
148
|
+
let row = await em.findOne(InventoryThreshold, {
|
|
149
|
+
scopeKind: 'product',
|
|
150
|
+
scopeId: patch.productId,
|
|
151
|
+
});
|
|
152
|
+
if (!row) {
|
|
153
|
+
row = em.create(InventoryThreshold, {
|
|
154
|
+
scopeKind: 'product',
|
|
155
|
+
scopeId: patch.productId,
|
|
156
|
+
});
|
|
157
|
+
em.persist(row);
|
|
158
|
+
}
|
|
159
|
+
if (patch.high !== undefined)
|
|
160
|
+
row.thresholdHigh = patch.high;
|
|
161
|
+
if (patch.medium !== undefined)
|
|
162
|
+
row.thresholdMedium = patch.medium;
|
|
163
|
+
if (patch.low !== undefined)
|
|
164
|
+
row.thresholdLow = patch.low;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=threshold-admin-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threshold-admin-service.js","sourceRoot":"","sources":["../../../src/backend/services/threshold-admin-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Threshold resolver — pure function (feature 010 / FR-017).
|
|
3
|
+
*
|
|
4
|
+
* Resolves the `(high, medium, low)` threshold triple from the
|
|
5
|
+
* priority chain Product → Category → Global. Each threshold key is
|
|
6
|
+
* resolved independently; a missing value at one level falls through
|
|
7
|
+
* to the next, so a product can override only `low` while inheriting
|
|
8
|
+
* `high` and `medium` from the global scope.
|
|
9
|
+
*/
|
|
10
|
+
export interface ThresholdLevel {
|
|
11
|
+
high: number | null;
|
|
12
|
+
medium: number | null;
|
|
13
|
+
low: number | null;
|
|
14
|
+
}
|
|
15
|
+
export interface ResolveThresholdsInput {
|
|
16
|
+
productThresholds?: ThresholdLevel | null;
|
|
17
|
+
/** Each category in the product's category list, ordered by relevance.
|
|
18
|
+
* The resolver returns the first defined value walking the array. */
|
|
19
|
+
categoryThresholds?: ThresholdLevel[];
|
|
20
|
+
globalThresholds: ThresholdLevel;
|
|
21
|
+
}
|
|
22
|
+
export declare function resolveThresholds(input: ResolveThresholdsInput): ThresholdLevel;
|
|
23
|
+
//# sourceMappingURL=threshold-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threshold-resolver.d.ts","sourceRoot":"","sources":["../../../src/backend/services/threshold-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,iBAAiB,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAC1C;0EACsE;IACtE,kBAAkB,CAAC,EAAE,cAAc,EAAE,CAAC;IACtC,gBAAgB,EAAE,cAAc,CAAC;CAClC;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,cAAc,CAU/E"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Threshold resolver — pure function (feature 010 / FR-017).
|
|
3
|
+
*
|
|
4
|
+
* Resolves the `(high, medium, low)` threshold triple from the
|
|
5
|
+
* priority chain Product → Category → Global. Each threshold key is
|
|
6
|
+
* resolved independently; a missing value at one level falls through
|
|
7
|
+
* to the next, so a product can override only `low` while inheriting
|
|
8
|
+
* `high` and `medium` from the global scope.
|
|
9
|
+
*/
|
|
10
|
+
export function resolveThresholds(input) {
|
|
11
|
+
const product = input.productThresholds ?? null;
|
|
12
|
+
const categories = input.categoryThresholds ?? [];
|
|
13
|
+
const global = input.globalThresholds;
|
|
14
|
+
return {
|
|
15
|
+
high: pick('high', product, categories, global),
|
|
16
|
+
medium: pick('medium', product, categories, global),
|
|
17
|
+
low: pick('low', product, categories, global),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function pick(key, product, categories, global) {
|
|
21
|
+
if (product && product[key] !== null && product[key] !== undefined)
|
|
22
|
+
return product[key];
|
|
23
|
+
for (const cat of categories) {
|
|
24
|
+
if (cat[key] !== null && cat[key] !== undefined)
|
|
25
|
+
return cat[key];
|
|
26
|
+
}
|
|
27
|
+
return global[key];
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=threshold-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threshold-resolver.js","sourceRoot":"","sources":["../../../src/backend/services/threshold-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgBH,MAAM,UAAU,iBAAiB,CAAC,KAA6B;IAC7D,MAAM,OAAO,GAAG,KAAK,CAAC,iBAAiB,IAAI,IAAI,CAAC;IAChD,MAAM,UAAU,GAAG,KAAK,CAAC,kBAAkB,IAAI,EAAE,CAAC;IAClD,MAAM,MAAM,GAAG,KAAK,CAAC,gBAAgB,CAAC;IAEtC,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC;QAC/C,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC;QACnD,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC;KAC9C,CAAC;AACJ,CAAC;AAED,SAAS,IAAI,CACX,GAA8B,EAC9B,OAA8B,EAC9B,UAA4B,EAC5B,MAAsB;IAEtB,IAAI,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;IACxF,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS;YAAE,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import type { SettingsReadPort } from '@endora-commerce/platform/kernel';
|
|
3
|
+
export interface SettingsValueChangedPayload {
|
|
4
|
+
settingCode: string;
|
|
5
|
+
salesChannelIds: string[];
|
|
6
|
+
valueType: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* ThresholdSettingsMirror (US5 / T058).
|
|
10
|
+
*
|
|
11
|
+
* The `inventory.global_threshold_{high,medium,low}` settings live in
|
|
12
|
+
* the Settings module so admins can edit them through the Module
|
|
13
|
+
* Settings UI alongside every other inventory key. The display-band
|
|
14
|
+
* resolver, however, reads the global thresholds from
|
|
15
|
+
* `inventory_thresholds` because that's where category and product
|
|
16
|
+
* thresholds also live (one read path, three scopes — research §R3).
|
|
17
|
+
*
|
|
18
|
+
* This subscriber bridges the two: when a settings.value_changed event
|
|
19
|
+
* carries one of the three threshold keys, we mirror the new value
|
|
20
|
+
* into the singleton `(scope_kind='global', scope_id=null)` row.
|
|
21
|
+
*
|
|
22
|
+
* The mirror is best-effort — failures are logged but never propagate
|
|
23
|
+
* back to the settings writer. The seeded defaults in migration 030
|
|
24
|
+
* keep the resolver happy if the mirror has never run.
|
|
25
|
+
*/
|
|
26
|
+
export declare class ThresholdSettingsMirror {
|
|
27
|
+
private readonly emFactory;
|
|
28
|
+
private readonly settingsService;
|
|
29
|
+
/** Resolves the channel id used to read the settings value. System
|
|
30
|
+
* default is fine because the global thresholds are not per-channel.
|
|
31
|
+
* Resolved lazily so the mirror does not block module construction
|
|
32
|
+
* on channel lookups. */
|
|
33
|
+
private readonly resolveSettingsChannelId;
|
|
34
|
+
private readonly onError?;
|
|
35
|
+
constructor(emFactory: () => EntityManager, settingsService: SettingsReadPort,
|
|
36
|
+
/** Resolves the channel id used to read the settings value. System
|
|
37
|
+
* default is fine because the global thresholds are not per-channel.
|
|
38
|
+
* Resolved lazily so the mirror does not block module construction
|
|
39
|
+
* on channel lookups. */
|
|
40
|
+
resolveSettingsChannelId: () => Promise<string | null>, onError?: ((err: unknown) => void) | undefined);
|
|
41
|
+
/**
|
|
42
|
+
* `settings.value_changed` — mirror one of the three global threshold codes
|
|
43
|
+
* into the singleton `inventory_thresholds` row.
|
|
44
|
+
*
|
|
45
|
+
* The registration lives in this module's `backend.ts` and goes through
|
|
46
|
+
* `ctx.subscribe` (issue #107): as a bare `eventBus.on` this kept writing the
|
|
47
|
+
* mirror row while `inventory` was switched off. The read it performs sees the
|
|
48
|
+
* new value because the settings write seam drops the cache and awaits the
|
|
49
|
+
* drop before it emits (issue #45) — not because of where this handler sits
|
|
50
|
+
* in the dispatch order.
|
|
51
|
+
*/
|
|
52
|
+
onSettingChanged(payload: SettingsValueChangedPayload): Promise<void>;
|
|
53
|
+
private mirror;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=threshold-settings-mirror.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threshold-settings-mirror.d.ts","sourceRoot":"","sources":["../../../src/backend/services/threshold-settings-mirror.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAIzE,MAAM,WAAW,2BAA2B;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAUD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,uBAAuB;IAEhC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC;;;8BAG0B;IAC1B,OAAO,CAAC,QAAQ,CAAC,wBAAwB;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAPR,SAAS,EAAE,MAAM,aAAa,EAC9B,eAAe,EAAE,gBAAgB;IAClD;;;8BAG0B;IACT,wBAAwB,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EACtD,OAAO,CAAC,GAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,aAAA;IAGnD;;;;;;;;;;OAUG;IACG,gBAAgB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC;YAW7D,MAAM;CAsBrB"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { InventoryThreshold } from '../entities/inventory-threshold.entity.js';
|
|
3
|
+
import { INVENTORY_SETTING_CODES } from '../../manifest.js';
|
|
4
|
+
const NUMBER_OR_NULL = z.number().int().nullable();
|
|
5
|
+
const KEY_TO_FIELD = {
|
|
6
|
+
[INVENTORY_SETTING_CODES.GLOBAL_THRESHOLD_HIGH]: 'thresholdHigh',
|
|
7
|
+
[INVENTORY_SETTING_CODES.GLOBAL_THRESHOLD_MEDIUM]: 'thresholdMedium',
|
|
8
|
+
[INVENTORY_SETTING_CODES.GLOBAL_THRESHOLD_LOW]: 'thresholdLow',
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* ThresholdSettingsMirror (US5 / T058).
|
|
12
|
+
*
|
|
13
|
+
* The `inventory.global_threshold_{high,medium,low}` settings live in
|
|
14
|
+
* the Settings module so admins can edit them through the Module
|
|
15
|
+
* Settings UI alongside every other inventory key. The display-band
|
|
16
|
+
* resolver, however, reads the global thresholds from
|
|
17
|
+
* `inventory_thresholds` because that's where category and product
|
|
18
|
+
* thresholds also live (one read path, three scopes — research §R3).
|
|
19
|
+
*
|
|
20
|
+
* This subscriber bridges the two: when a settings.value_changed event
|
|
21
|
+
* carries one of the three threshold keys, we mirror the new value
|
|
22
|
+
* into the singleton `(scope_kind='global', scope_id=null)` row.
|
|
23
|
+
*
|
|
24
|
+
* The mirror is best-effort — failures are logged but never propagate
|
|
25
|
+
* back to the settings writer. The seeded defaults in migration 030
|
|
26
|
+
* keep the resolver happy if the mirror has never run.
|
|
27
|
+
*/
|
|
28
|
+
export class ThresholdSettingsMirror {
|
|
29
|
+
emFactory;
|
|
30
|
+
settingsService;
|
|
31
|
+
resolveSettingsChannelId;
|
|
32
|
+
onError;
|
|
33
|
+
constructor(emFactory, settingsService,
|
|
34
|
+
/** Resolves the channel id used to read the settings value. System
|
|
35
|
+
* default is fine because the global thresholds are not per-channel.
|
|
36
|
+
* Resolved lazily so the mirror does not block module construction
|
|
37
|
+
* on channel lookups. */
|
|
38
|
+
resolveSettingsChannelId, onError) {
|
|
39
|
+
this.emFactory = emFactory;
|
|
40
|
+
this.settingsService = settingsService;
|
|
41
|
+
this.resolveSettingsChannelId = resolveSettingsChannelId;
|
|
42
|
+
this.onError = onError;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* `settings.value_changed` — mirror one of the three global threshold codes
|
|
46
|
+
* into the singleton `inventory_thresholds` row.
|
|
47
|
+
*
|
|
48
|
+
* The registration lives in this module's `backend.ts` and goes through
|
|
49
|
+
* `ctx.subscribe` (issue #107): as a bare `eventBus.on` this kept writing the
|
|
50
|
+
* mirror row while `inventory` was switched off. The read it performs sees the
|
|
51
|
+
* new value because the settings write seam drops the cache and awaits the
|
|
52
|
+
* drop before it emits (issue #45) — not because of where this handler sits
|
|
53
|
+
* in the dispatch order.
|
|
54
|
+
*/
|
|
55
|
+
async onSettingChanged(payload) {
|
|
56
|
+
const field = KEY_TO_FIELD[payload.settingCode];
|
|
57
|
+
if (!field)
|
|
58
|
+
return;
|
|
59
|
+
try {
|
|
60
|
+
await this.mirror(payload.settingCode, field);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
const log = this.onError ?? ((e) => console.warn('threshold-mirror failed', e));
|
|
64
|
+
log(err);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async mirror(settingCode, field) {
|
|
68
|
+
// command-coverage-ignore: derived-state sync — mirrors a Settings value into
|
|
69
|
+
// the global InventoryThreshold row; the Settings write is the audited source.
|
|
70
|
+
const channelId = await this.resolveSettingsChannelId();
|
|
71
|
+
if (!channelId)
|
|
72
|
+
return;
|
|
73
|
+
const value = await this.settingsService.get(settingCode, channelId, NUMBER_OR_NULL);
|
|
74
|
+
const em = this.emFactory();
|
|
75
|
+
let row = await em.findOne(InventoryThreshold, { scopeKind: 'global', scopeId: null });
|
|
76
|
+
if (!row) {
|
|
77
|
+
row = em.create(InventoryThreshold, { scopeKind: 'global', scopeId: null });
|
|
78
|
+
em.persist(row);
|
|
79
|
+
}
|
|
80
|
+
row[field] = value;
|
|
81
|
+
await em.flush();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=threshold-settings-mirror.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threshold-settings-mirror.js","sourceRoot":"","sources":["../../../src/backend/services/threshold-settings-mirror.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAC/E,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAQ5D,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;AAEnD,MAAM,YAAY,GAAyE;IACzF,CAAC,uBAAuB,CAAC,qBAAqB,CAAC,EAAE,eAAe;IAChE,CAAC,uBAAuB,CAAC,uBAAuB,CAAC,EAAE,iBAAiB;IACpE,CAAC,uBAAuB,CAAC,oBAAoB,CAAC,EAAE,cAAc;CAC/D,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,uBAAuB;IAEf;IACA;IAKA;IACA;IARnB,YACmB,SAA8B,EAC9B,eAAiC;IAClD;;;8BAG0B;IACT,wBAAsD,EACtD,OAAgC;QAPhC,cAAS,GAAT,SAAS,CAAqB;QAC9B,oBAAe,GAAf,eAAe,CAAkB;QAKjC,6BAAwB,GAAxB,wBAAwB,CAA8B;QACtD,YAAO,GAAP,OAAO,CAAyB;IAChD,CAAC;IAEJ;;;;;;;;;;OAUG;IACH,KAAK,CAAC,gBAAgB,CAAC,OAAoC;QACzD,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAChD,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,CAAU,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,yBAAyB,EAAE,CAAC,CAAC,CAAC,CAAC;YACzF,GAAG,CAAC,GAAG,CAAC,CAAC;QACX,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,MAAM,CAClB,WAAmB,EACnB,KAA2D;QAE3D,8EAA8E;QAC9E,+EAA+E;QAC/E,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,wBAAwB,EAAE,CAAC;QACxD,IAAI,CAAC,SAAS;YAAE,OAAO;QACvB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,GAAG,CAC1C,WAAW,EACX,SAAS,EACT,cAAc,CACf,CAAC;QACF,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,IAAI,GAAG,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACvF,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,kBAAkB,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5E,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;QACD,GAAG,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;QACnB,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
/**
|
|
3
|
+
* WarehouseChannelReconciler — idempotent boot-time check that every
|
|
4
|
+
* active sales channel has at least one warehouse assigned and that
|
|
5
|
+
* exactly one of those assignments carries `isDefault = true`.
|
|
6
|
+
*
|
|
7
|
+
* Why a runtime reconciler: the inventory migration cannot know about
|
|
8
|
+
* future channels because the DefaultChannelReconciler creates the
|
|
9
|
+
* platform's first channel at boot time, AFTER migrations run. This
|
|
10
|
+
* reconciler runs after every boot and catches up.
|
|
11
|
+
*/
|
|
12
|
+
export declare class WarehouseChannelReconciler {
|
|
13
|
+
private readonly em;
|
|
14
|
+
constructor(em: EntityManager);
|
|
15
|
+
run(): Promise<{
|
|
16
|
+
assignmentsCreated: number;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=warehouse-channel-reconciler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warehouse-channel-reconciler.d.ts","sourceRoot":"","sources":["../../../src/backend/services/warehouse-channel-reconciler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAK3D;;;;;;;;;GASG;AACH,qBAAa,0BAA0B;IACzB,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,aAAa;IAExC,GAAG,IAAI,OAAO,CAAC;QAAE,kBAAkB,EAAE,MAAM,CAAA;KAAE,CAAC;CA6CrD"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { WarehouseChannelAssignment } from '../entities/warehouse-channel-assignment.entity.js';
|
|
2
|
+
import { Warehouse, DEFAULT_WAREHOUSE_ID } from '../entities/warehouse.entity.js';
|
|
3
|
+
import { SalesChannel } from '@endora-commerce/platform/kernel';
|
|
4
|
+
/**
|
|
5
|
+
* WarehouseChannelReconciler — idempotent boot-time check that every
|
|
6
|
+
* active sales channel has at least one warehouse assigned and that
|
|
7
|
+
* exactly one of those assignments carries `isDefault = true`.
|
|
8
|
+
*
|
|
9
|
+
* Why a runtime reconciler: the inventory migration cannot know about
|
|
10
|
+
* future channels because the DefaultChannelReconciler creates the
|
|
11
|
+
* platform's first channel at boot time, AFTER migrations run. This
|
|
12
|
+
* reconciler runs after every boot and catches up.
|
|
13
|
+
*/
|
|
14
|
+
export class WarehouseChannelReconciler {
|
|
15
|
+
em;
|
|
16
|
+
constructor(em) {
|
|
17
|
+
this.em = em;
|
|
18
|
+
}
|
|
19
|
+
async run() {
|
|
20
|
+
// command-coverage-ignore: startup reconciler — backfills the default
|
|
21
|
+
// warehouse↔channel assignment for channels missing one, an idempotent
|
|
22
|
+
// system-invariant repair, not an operator-initiated audited write.
|
|
23
|
+
// The kernel's own entity, not `select id from sales_channels` (feature 075,
|
|
24
|
+
// D-87). `sales_channels` is the kernel's table since feature 072 moved the
|
|
25
|
+
// resolution machinery there, and a module relating into the kernel by ORM
|
|
26
|
+
// is the sanctioned access.
|
|
27
|
+
//
|
|
28
|
+
// Read through `this.em`, not through a knex handle and not through
|
|
29
|
+
// `salesChannelResolutionPort` — both take their own pooled connection, so
|
|
30
|
+
// the channel list would be read from outside any transaction the caller
|
|
31
|
+
// holds open while the assignments below are written through `this.em` from
|
|
32
|
+
// inside it (issue #207).
|
|
33
|
+
const channels = await this.em.find(SalesChannel, {}, { fields: ['id'] });
|
|
34
|
+
if (channels.length === 0)
|
|
35
|
+
return { assignmentsCreated: 0 };
|
|
36
|
+
const defaultWarehouse = await this.em.findOne(Warehouse, { id: DEFAULT_WAREHOUSE_ID });
|
|
37
|
+
if (!defaultWarehouse) {
|
|
38
|
+
// Migration 030 should have seeded this — bail rather than silently
|
|
39
|
+
// creating a row with a dangling foreign key.
|
|
40
|
+
return { assignmentsCreated: 0 };
|
|
41
|
+
}
|
|
42
|
+
let created = 0;
|
|
43
|
+
for (const channel of channels) {
|
|
44
|
+
const existing = await this.em.find(WarehouseChannelAssignment, {
|
|
45
|
+
salesChannelId: channel.id,
|
|
46
|
+
});
|
|
47
|
+
if (existing.length === 0) {
|
|
48
|
+
const row = this.em.create(WarehouseChannelAssignment, {
|
|
49
|
+
warehouseId: DEFAULT_WAREHOUSE_ID,
|
|
50
|
+
salesChannelId: channel.id,
|
|
51
|
+
isDefault: true,
|
|
52
|
+
});
|
|
53
|
+
await this.em.persistAndFlush(row);
|
|
54
|
+
created += 1;
|
|
55
|
+
}
|
|
56
|
+
else if (!existing.some((a) => a.isDefault)) {
|
|
57
|
+
// Channel has assignments but no default — promote the first one.
|
|
58
|
+
existing[0].isDefault = true;
|
|
59
|
+
await this.em.flush();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return { assignmentsCreated: created };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=warehouse-channel-reconciler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warehouse-channel-reconciler.js","sourceRoot":"","sources":["../../../src/backend/services/warehouse-channel-reconciler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,MAAM,oDAAoD,CAAC;AAChG,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAEhE;;;;;;;;;GASG;AACH,MAAM,OAAO,0BAA0B;IACR;IAA7B,YAA6B,EAAiB;QAAjB,OAAE,GAAF,EAAE,CAAe;IAAG,CAAC;IAElD,KAAK,CAAC,GAAG;QACP,sEAAsE;QACtE,uEAAuE;QACvE,oEAAoE;QACpE,6EAA6E;QAC7E,4EAA4E;QAC5E,2EAA2E;QAC3E,4BAA4B;QAC5B,EAAE;QACF,oEAAoE;QACpE,2EAA2E;QAC3E,yEAAyE;QACzE,4EAA4E;QAC5E,0BAA0B;QAC1B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC1E,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC,EAAE,CAAC;QAE5D,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,oBAAoB,EAAE,CAAC,CAAC;QACxF,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,oEAAoE;YACpE,8CAA8C;YAC9C,OAAO,EAAE,kBAAkB,EAAE,CAAC,EAAE,CAAC;QACnC,CAAC;QAED,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,0BAA0B,EAAE;gBAC9D,cAAc,EAAE,OAAO,CAAC,EAAE;aAC3B,CAAC,CAAC;YACH,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,0BAA0B,EAAE;oBACrD,WAAW,EAAE,oBAAoB;oBACjC,cAAc,EAAE,OAAO,CAAC,EAAE;oBAC1B,SAAS,EAAE,IAAI;iBAChB,CAAC,CAAC;gBACH,MAAM,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;gBACnC,OAAO,IAAI,CAAC,CAAC;YACf,CAAC;iBAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC9C,kEAAkE;gBAClE,QAAQ,CAAC,CAAC,CAAE,CAAC,SAAS,GAAG,IAAI,CAAC;gBAC9B,MAAM,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;YACxB,CAAC;QACH,CAAC;QACD,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,CAAC;IACzC,CAAC;CACF"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import type { AuditPort } from '@endora-commerce/platform/kernel';
|
|
3
|
+
export interface ChannelWarehouseAssignmentDTO {
|
|
4
|
+
id: string;
|
|
5
|
+
warehouseId: string;
|
|
6
|
+
warehouseName: string;
|
|
7
|
+
warehouseCode: string;
|
|
8
|
+
isDefault: boolean;
|
|
9
|
+
sortOrder: number;
|
|
10
|
+
assignedAt: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AssignToChannelInput {
|
|
13
|
+
warehouseId: string;
|
|
14
|
+
isDefault?: boolean;
|
|
15
|
+
sortOrder?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface PatchAssignmentInput {
|
|
18
|
+
isDefault?: boolean;
|
|
19
|
+
sortOrder?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* WarehouseChannelService (US3) — manages the m:n binding between
|
|
23
|
+
* warehouses and sales channels with at most one `isDefault = true`
|
|
24
|
+
* row per channel.
|
|
25
|
+
*
|
|
26
|
+
* Invariants:
|
|
27
|
+
* - Every active channel must have at least one warehouse (refuse
|
|
28
|
+
* `unassign` when this would leave the channel orphaned).
|
|
29
|
+
* - At most one assignment per channel carries `isDefault = true`
|
|
30
|
+
* (`setDefault` demotes the previous default in the same flush).
|
|
31
|
+
*/
|
|
32
|
+
export declare class WarehouseChannelService {
|
|
33
|
+
#private;
|
|
34
|
+
private readonly emFactory;
|
|
35
|
+
/** Feature 054 — audits assignment writes co-transactionally when provided. */
|
|
36
|
+
private readonly auditLog?;
|
|
37
|
+
constructor(emFactory: () => EntityManager,
|
|
38
|
+
/** Feature 054 — audits assignment writes co-transactionally when provided. */
|
|
39
|
+
auditLog?: AuditPort | undefined);
|
|
40
|
+
listForChannel(channelId: string): Promise<ChannelWarehouseAssignmentDTO[]>;
|
|
41
|
+
listChannelsForWarehouse(warehouseId: string): Promise<Array<{
|
|
42
|
+
salesChannelId: string;
|
|
43
|
+
isDefault: boolean;
|
|
44
|
+
sortOrder: number;
|
|
45
|
+
}>>;
|
|
46
|
+
assign(channelId: string, input: AssignToChannelInput): Promise<ChannelWarehouseAssignmentDTO>;
|
|
47
|
+
patch(channelId: string, assignmentId: string, input: PatchAssignmentInput): Promise<ChannelWarehouseAssignmentDTO>;
|
|
48
|
+
unassign(channelId: string, assignmentId: string): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Resolves the warehouses bound to a sales channel for the storefront
|
|
51
|
+
* cumulative-on-hand readout (research §R7).
|
|
52
|
+
*/
|
|
53
|
+
resolveCandidateWarehouseIds(channelId: string): Promise<string[]>;
|
|
54
|
+
private demoteOtherDefaults;
|
|
55
|
+
private toDTO;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=warehouse-channel-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warehouse-channel-service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/warehouse-channel-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAMlE,MAAM,WAAW,6BAA6B;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,uBAAuB;;IAEhC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,+EAA+E;IAC/E,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBAFT,SAAS,EAAE,MAAM,aAAa;IAC/C,+EAA+E;IAC9D,QAAQ,CAAC,EAAE,SAAS,YAAA;IA6BjC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,6BAA6B,EAAE,CAAC;IAmB3E,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QACjE,cAAc,EAAE,MAAM,CAAC;QACvB,SAAS,EAAE,OAAO,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;IAUG,MAAM,CACV,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,oBAAoB,GAC1B,OAAO,CAAC,6BAA6B,CAAC;IAiDnC,KAAK,CACT,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,oBAAoB,GAC1B,OAAO,CAAC,6BAA6B,CAAC;IA+BnC,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmCtE;;;OAGG;IACG,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAQ1D,mBAAmB;IAWjC,OAAO,CAAC,KAAK;CAcd"}
|