@rytass/wms-module-graphql 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -6
- package/docs/api-reference.md +81 -6
- package/docs/events.md +23 -4
- package/index.cjs.js +919 -110
- package/index.d.ts +3 -1
- package/index.js +2 -0
- package/lib/dto/index.d.ts +1 -0
- package/lib/dto/inventory-count-order.dto.d.ts +49 -0
- package/lib/dto/inventory-count-order.dto.js +146 -0
- package/lib/events/operation-result-map.d.ts +8 -0
- package/lib/graphql.module.d.ts +6 -2
- package/lib/graphql.module.js +18 -1
- package/lib/inputs/inventory-count-order.args.d.ts +55 -0
- package/lib/inputs/inventory-count-order.args.js +196 -0
- package/lib/mutations/inventory-count-order.mutation.d.ts +19 -0
- package/lib/mutations/inventory-count-order.mutation.js +138 -0
- package/lib/mutations/loader.mutation.js +1 -0
- package/lib/mutations/material.mutation.js +1 -0
- package/lib/mutations/receive-inventory-order.mutation.js +1 -0
- package/lib/mutations/ship-inventory-order.mutation.js +1 -0
- package/lib/queries/inventory-count-order.query.d.ts +9 -0
- package/lib/queries/inventory-count-order.query.js +44 -0
- package/lib/queries/loader.query.js +1 -0
- package/lib/queries/material.query.js +1 -0
- package/lib/queries/recieve-inventory-order.query.js +1 -0
- package/lib/queries/ship-inventory-order.query.js +1 -0
- package/lib/queries/stock.query.js +1 -0
- package/lib/registry/index.d.ts +1 -0
- package/lib/registry/operation-registry.d.ts +59 -0
- package/lib/registry/operation-registry.js +136 -0
- package/lib/resolvers/aggregated-stock.resolver.d.ts +3 -11
- package/lib/resolvers/aggregated-stock.resolver.js +10 -18
- package/lib/resolvers/change-log.resolver.d.ts +8 -8
- package/lib/resolvers/change-log.resolver.js +14 -15
- package/lib/resolvers/inventory-count-order.resolver.d.ts +34 -0
- package/lib/resolvers/inventory-count-order.resolver.js +148 -0
- package/lib/resolvers/loader-type.resolver.js +1 -0
- package/lib/resolvers/loader.resolver.d.ts +10 -2
- package/lib/resolvers/loader.resolver.js +15 -4
- package/lib/resolvers/location.resolver.d.ts +10 -1
- package/lib/resolvers/location.resolver.js +17 -6
- package/lib/resolvers/material.resolver.js +1 -0
- package/lib/resolvers/receive-inventory-order.resolver.d.ts +8 -8
- package/lib/resolvers/receive-inventory-order.resolver.js +14 -15
- package/lib/resolvers/ship-inventory-order.resolver.d.ts +15 -15
- package/lib/resolvers/ship-inventory-order.resolver.js +27 -29
- package/lib/resolvers/stock.resolver.d.ts +8 -8
- package/lib/resolvers/stock.resolver.js +14 -15
- package/lib/resolvers/transfer-order.resolver.d.ts +17 -8
- package/lib/resolvers/transfer-order.resolver.js +30 -19
- package/lib/resolvers/warehouse-map.resolver.d.ts +10 -1
- package/lib/resolvers/warehouse-map.resolver.js +15 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -62,21 +62,27 @@ You register a **single** `GraphQLModule.forRootAsync(...)` of your own, mix you
|
|
|
62
62
|
|
|
63
63
|
`WmsModuleGraphqlModule` internally wires `WmsModuleCoreModule.forRootAsync` so you do not need to import the core module separately when using this package.
|
|
64
64
|
|
|
65
|
-
## Custom
|
|
65
|
+
## Custom entities
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
Every entity option `WMSBaseModuleOptions` exposes reaches all the way down, so a downstream project's own tables can *be* the WMS tables — every resolver's DataLoader resolves against them too:
|
|
68
68
|
|
|
69
69
|
```ts
|
|
70
70
|
WmsModuleGraphqlModule.forRootAsync({
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
useFactory: async () => ({
|
|
72
|
+
materialEntity: ItemMasterEntity, // a @ChildEntity() of MaterialEntityClass
|
|
73
|
+
batchEntity: LotEntity,
|
|
74
|
+
locationEntity: BinEntity,
|
|
75
|
+
stockEntity: LedgerEntryEntity,
|
|
76
|
+
orderEntity: MovementEntity,
|
|
77
|
+
warehouseMapEntity: FloorPlanEntity,
|
|
78
|
+
}),
|
|
73
79
|
defaultLoaderSerialId: 'DEFAULT',
|
|
74
80
|
defaultLoaderTypeKey: 'DEFAULT',
|
|
75
81
|
defaultLocationKey: 'DEFAULT',
|
|
76
82
|
});
|
|
77
83
|
```
|
|
78
84
|
|
|
79
|
-
Register
|
|
85
|
+
Override as few or as many as you like. Register them with TypeORM yourself (`TypeOrmModule.forFeature([...])`); the module checks at startup and refuses to boot if any is missing. Requires `@rytass/wms-base-nestjs-module` >= 0.4.0. See [`@rytass/wms-module-core`'s custom-entities guide](https://github.com/Rytass/WMS-Module/blob/main/libs/core/docs/custom-entities.md) for the single-table-inheritance caveats.
|
|
80
86
|
|
|
81
87
|
## Authorization
|
|
82
88
|
|
|
@@ -104,9 +110,91 @@ The member-base adapter reuses everything `CasbinGuard` already put on the reque
|
|
|
104
110
|
|
|
105
111
|
➡️ **Full design & recipes: [`docs/authorization.md`](./docs/authorization.md)** (the problem, execution order, member-base / custom-JWT / no-guard recipes, the single coupling point, public API, FAQ).
|
|
106
112
|
|
|
113
|
+
## Turning operations off per deployment
|
|
114
|
+
|
|
115
|
+
`authChecker` **refuses** an operation; these options stop it being **registered at all**.
|
|
116
|
+
The difference matters once someone reads the schema: a refused mutation still appears in
|
|
117
|
+
introspection, in your frontend's codegen and in a security review, as a mutation that is
|
|
118
|
+
guaranteed to fail.
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
WmsModuleGraphqlModule.forRootAsync({
|
|
122
|
+
...coreOptions,
|
|
123
|
+
|
|
124
|
+
// deny-list — these never enter the schema
|
|
125
|
+
disabledOperations: ['quality-inspection-order:inspect', 'material:create'],
|
|
126
|
+
|
|
127
|
+
// or an allow-list instead (the two are mutually exclusive; passing both throws)
|
|
128
|
+
// enabledOperations: ['material:read', 'stock:read'],
|
|
129
|
+
|
|
130
|
+
// escape hatch by GraphQL field name, for when a requirement is too coarse
|
|
131
|
+
disabledFields: ['availableLoaders'],
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Names are the same `` `${resource}:${action}` `` strings `@WmsOperation` declares and your
|
|
136
|
+
`authChecker` receives, exported as the `WmsOperationName` union and the
|
|
137
|
+
`WMS_OPERATION_NAMES` array so you can iterate or diff them.
|
|
138
|
+
|
|
139
|
+
Two things to know before you use it:
|
|
140
|
+
|
|
141
|
+
- **A name is not one field.** Several queries share a requirement — `loader:read` covers
|
|
142
|
+
6 fields, `stock:read` 5, `material:read` and `loader:create` 3 each. Disabling a name
|
|
143
|
+
disables every field carrying it; use `disabledFields` when you need one.
|
|
144
|
+
- **Disabling a resolver does not disable the domain.** The services stay injectable, so a
|
|
145
|
+
host that owns that step of the workflow itself can still drive
|
|
146
|
+
`ReceiveInventoryOrderService` (or any other) directly. That is the intended pattern.
|
|
147
|
+
|
|
148
|
+
Because the switches mutate process-global registration state, a process may register
|
|
149
|
+
`WmsModuleGraphqlModule` **once**.
|
|
150
|
+
|
|
151
|
+
## Inventory counting
|
|
152
|
+
|
|
153
|
+
Compare the ledger against what is physically on the shelf, then adjust the ledger to
|
|
154
|
+
match. Eleven operations (`inventory-count-order:{read,create,update,start,count,add-item,remove-item,reset,cancel,settle}`)
|
|
155
|
+
back the flow:
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
建立盤點 ──▶ PENDING ──開始盤點──▶ COUNTING ──執行盤差──▶ COMPLETED
|
|
159
|
+
│ │
|
|
160
|
+
└───── 取消盤點 ─────┴────────▶ CANCELLED
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
- **Scope is by location, expanded downwards.** Counting an aisle counts every shelf under
|
|
164
|
+
it; `createInventoryCountOrder` stores the expansion.
|
|
165
|
+
- **Counting never moves stock between locations.** A line in the wrong place is a
|
|
166
|
+
transfer, not a count — `transfer-order:create` already does that. Counting only ever
|
|
167
|
+
adjusts quantity in place.
|
|
168
|
+
- **Nothing touches stock until `settleInventoryCount`.** Counted quantities are working
|
|
169
|
+
notes; settlement runs in one transaction and writes the difference as `+`/`-` rows,
|
|
170
|
+
which surface as `stock.count-gained` / `stock.count-lost`.
|
|
171
|
+
- **Uncounted lines are left alone.** "Not counted" is not "counted as zero".
|
|
172
|
+
- **Surpluses may name a batch that does not exist yet**; it is created during settlement.
|
|
173
|
+
- **`countDate` is the business date.** The variance is reported under the date the count
|
|
174
|
+
was created for, not the day settlement happened to run. `createdAt` keeps the real
|
|
175
|
+
wall-clock time.
|
|
176
|
+
|
|
177
|
+
### ⚠️ Starting a count locks its locations
|
|
178
|
+
|
|
179
|
+
This is the one part that changes the behaviour of operations you already use. While an
|
|
180
|
+
order is `COUNTING`, **any** stock movement touching a location in its scope is refused
|
|
181
|
+
with a `409 Conflict` naming the count:
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
Location <id> is locked by inventory count order IC2508300001;
|
|
185
|
+
finish or cancel that count before moving this stock.
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The check sits on the insert of every `*_order_change` row — the same choke point the
|
|
189
|
+
stock events use — so it covers resolvers **and** direct service calls, including your own
|
|
190
|
+
integration code. Without it the book snapshot the variance is measured against would go
|
|
191
|
+
stale and settlement would silently write off somebody else's legitimate movement.
|
|
192
|
+
|
|
193
|
+
Settling or cancelling the count releases the lock.
|
|
194
|
+
|
|
107
195
|
## Events & Hooks
|
|
108
196
|
|
|
109
|
-
Intervene in and get notified about mutations. Every root mutation carries a typed **operation event** (`material.created`, `ship-inventory-order.shipped`, …) and fans out **stock domain events** (`stock.allocated`, `stock.shipped`, …) driven by the `ChangeType` state machine. Wire two opt-in hook points via `forRootAsync`:
|
|
197
|
+
Intervene in and get notified about mutations. Every root mutation carries a typed **operation event** (`material.created`, `ship-inventory-order.shipped`, `inventory-count-order.settled`, …) and fans out **stock domain events** (`stock.allocated`, `stock.shipped`, `stock.count-gained`, …) driven by the `ChangeType` state machine. Wire two opt-in hook points via `forRootAsync`:
|
|
110
198
|
|
|
111
199
|
- **`beforeHooks`** run before any DB work — **throw to veto** the mutation (zero side effects).
|
|
112
200
|
- **`afterListeners`** run **after the outermost transaction commits** — never notified about rolled-back changes.
|
package/docs/api-reference.md
CHANGED
|
@@ -71,6 +71,13 @@ static forRootAsync(
|
|
|
71
71
|
|
|
72
72
|
同樣每個都有 Symbol + EntityClass 雙匯出,共 37 個:
|
|
73
73
|
|
|
74
|
+
**盤點單 (Inventory Count Order)**
|
|
75
|
+
- `InventoryCountOrderEntity` / `InventoryCountOrderEntityClass` — 盤點單主檔(`countDate` 為盤差記帳基準日)
|
|
76
|
+
- `InventoryCountOrderLocationEntity` / `InventoryCountOrderLocationEntityClass` — 盤點範圍,已展開至所有下層儲位(`isRoot` 標示使用者實際選的節點)
|
|
77
|
+
- `InventoryCountOrderItemEntity` / `InventoryCountOrderItemEntityClass` — 盤點單身(`isAddition` 標示盤盈新增列)
|
|
78
|
+
- `InventoryCountOrderChangeEntity` / `InventoryCountOrderChangeEntityClass` — 盤差異動(正=盤盈、負=盤虧)
|
|
79
|
+
- 來源: `lib/models/extensions/inventory-count-order/`
|
|
80
|
+
|
|
74
81
|
**入庫訂單 (Receive Inventory Order)**
|
|
75
82
|
- `ReceiveInventoryOrderEntity` / `ReceiveInventoryOrderEntityClass` — 入庫單主檔
|
|
76
83
|
- `ReceiveInventoryOrderItemEntity` / `ReceiveInventoryOrderItemEntityClass` — 入庫單明細
|
|
@@ -171,6 +178,7 @@ static forRootAsync(
|
|
|
171
178
|
| `MergeBatchOrderService<T>` | `merge` | 批號合併 | `lib/services/merge-batch-order.service.ts` |
|
|
172
179
|
| `ReclassifyInventoryOrderService<T>` | `reclassify` | 庫存轉料號 | `lib/services/reclassify-inventory-order.service.ts` |
|
|
173
180
|
| `ScrapeService<T>` | `scrape` | 庫存報廢 | `lib/services/scrape.service.ts` |
|
|
181
|
+
| `InventoryCountOrderService<T>` | `findMany`, `findOne`, `create`, `update`, `start`, `count`, `addItem`, `removeItem`, `reset`, `cancel`, `settle` | 盤點單管理。`start` 會鎖定盤點範圍內的儲位,`settle` 是唯一會改動庫存的方法 | `lib/services/inventory-count-order.service.ts` |
|
|
174
182
|
| `QualityInspectionOrderService<T>` | `inspect` | 品質檢驗 | `lib/services/quality-inspection-order.service.ts` |
|
|
175
183
|
| `SaleOrderService` | (DataSource 直接操作) | 銷售訂單查詢 | `lib/services/sale-order.service.ts` |
|
|
176
184
|
| `HelperService` | `getSeq` | 序號產生工具 | `lib/services/helper.service.ts` |
|
|
@@ -262,11 +270,32 @@ enum ChangeType {
|
|
|
262
270
|
RECEIVED, IN_SHIPMENT, SHIPPED, IN_TRANSFER, TRANSFERRED,
|
|
263
271
|
VENDOR_TRANSFERRED, VENDOR_RETURNED, HELD, RELEASED,
|
|
264
272
|
CUSTOMER_HELD, CUSTOMER_RETURNED, SPLITTED, MERGED,
|
|
265
|
-
ALLOCATED, DEALLOCATED, RECLASSIFIED, SCRAPED
|
|
273
|
+
ALLOCATED, DEALLOCATED, RECLASSIFIED, SCRAPED,
|
|
274
|
+
COUNT_GAINED, COUNT_LOST
|
|
266
275
|
}
|
|
267
276
|
```
|
|
268
277
|
來源: `lib/constants/stock-status.ts`
|
|
269
278
|
|
|
279
|
+
### `InventoryCountStatus` (enum)
|
|
280
|
+
```ts
|
|
281
|
+
enum InventoryCountStatus { PENDING, COUNTING, COMPLETED, CANCELLED }
|
|
282
|
+
```
|
|
283
|
+
盤點單狀態:尚未執行 / 盤點中 / 已完成 / 已取消。只有 `COUNTING` 接受盤點數量,也只有
|
|
284
|
+
`COUNTING` 會鎖定範圍內儲位;`COMPLETED` 只能由執行盤差達成。
|
|
285
|
+
來源: `lib/constants/inventory-count-status.ts`
|
|
286
|
+
|
|
287
|
+
### `WmsOperationName` (type) / `WMS_OPERATION_NAMES` (const)
|
|
288
|
+
```ts
|
|
289
|
+
type WmsOperationName = 'material:read' | 'material:create' | /* …58 項… */;
|
|
290
|
+
const WMS_OPERATION_NAMES: readonly WmsOperationName[];
|
|
291
|
+
```
|
|
292
|
+
本套件所有 root operation 的 `` `${resource}:${action}` `` 名稱。同一組字串有三個用途:
|
|
293
|
+
`authChecker` 收到的 requirement、`@rytass/wms-module-graphql` 的
|
|
294
|
+
`enabledOperations` / `disabledOperations`、以及
|
|
295
|
+
`@rytass/wms-module-react` 的 `INVENTORY_ACTION_OPERATIONS` 對照表。
|
|
296
|
+
**注意名稱不等於欄位**:多支 query 共用同一組 requirement(`loader:read` 對應 6 支)。
|
|
297
|
+
來源: `lib/constants/operations.ts`
|
|
298
|
+
|
|
270
299
|
### `ReceiveInventoryOrderStatus` (enum)
|
|
271
300
|
```ts
|
|
272
301
|
enum ReceiveInventoryOrderStatus { PENDING, PARTIAL_RECEIVED, RECEIVED, REMOVED }
|
|
@@ -311,17 +340,25 @@ static forRootAsync(
|
|
|
311
340
|
// defaultLocationKey: string — 預設儲存位置 key
|
|
312
341
|
// + WmsAuthModuleOptions:
|
|
313
342
|
// authChecker?: WmsAuthChecker — 選填;resolver 授權委派函式(見 Authorization)
|
|
343
|
+
// + WmsOperationRegistrationOptions(since 0.9.0):
|
|
344
|
+
// enabledOperations?: readonly WmsOperationName[] — 白名單,只註冊列出的 operation
|
|
345
|
+
// disabledOperations?: readonly WmsOperationName[] — 黑名單;與白名單互斥,同時給會 throw
|
|
346
|
+
// disabledFields?: readonly string[] — 以 GraphQL 欄位名精準停用單一欄位
|
|
347
|
+
// 被停用者「不會進 schema」(introspection 與 SDL 皆無),
|
|
348
|
+
// 但對應的 service 仍可注入 — 宿主可繼續直呼。詳見下方 Operation registration。
|
|
314
349
|
//
|
|
315
|
-
// since 0.
|
|
316
|
-
// WMSBaseModuleOptions
|
|
317
|
-
//
|
|
318
|
-
// forRoot 與 async factory 皆支援;
|
|
319
|
-
//
|
|
350
|
+
// since 0.8.0(需 wms-base-nestjs-module >= 0.4.0):
|
|
351
|
+
// WMSBaseModuleOptions 的六個 entity 選項(material / batch / location /
|
|
352
|
+
// stock / order / warehouseMap)會一路作用到所有 resolver 的 DataLoader。
|
|
353
|
+
// 傳入對應 class 的 @ChildEntity() 即可,forRoot 與 async factory 皆支援;
|
|
354
|
+
// entity 需自行註冊給 TypeORM。詳見 core 的 docs/custom-entities.md。
|
|
320
355
|
): DynamicModule
|
|
321
356
|
```
|
|
322
357
|
|
|
323
358
|
> **Breaking from 0.2.x**: 0.2.0 took a second `gqlOptions` argument and started Apollo Server internally; 0.3.0 dropped it. Consumers now own `GraphQLModule.forRootAsync(...)` and the GraphQL context factory. Use `createWmsLoaders(loaderService)` inside `context` to provide the WMS DataLoader trio (see below).
|
|
324
359
|
|
|
360
|
+
> **Operation registration (`enabledOperations` / `disabledOperations` / `disabledFields`)**: optional. Omit them and every operation is registered as before. They mutate process-global registration state, so a process may register `WmsModuleGraphqlModule` **once**.
|
|
361
|
+
|
|
325
362
|
> **Authorization (`authChecker`)**: optional. Omit it and the module stays fully permissive. Supply it to authorize every WMS root op against your permission system — see the dedicated [**Authorization**](#authorization) section below and [`docs/authorization.md`](./authorization.md).
|
|
326
363
|
|
|
327
364
|
### `LoaderService` (`@Injectable()`, since 0.3.0 publicly exported)
|
|
@@ -455,6 +492,42 @@ The adapter imports nothing from member-base — it reads the `payload` / `enfor
|
|
|
455
492
|
|
|
456
493
|
---
|
|
457
494
|
|
|
495
|
+
## Operation registration
|
|
496
|
+
|
|
497
|
+
以部署為單位決定「哪些 operation 根本不進 schema」。`authChecker` 是**拒絕執行**,
|
|
498
|
+
這組選項是**不註冊**——差別在於被拒絕的 mutation 仍會出現在 introspection、前端 codegen
|
|
499
|
+
與安全稽核清單裡,看起來像一支保證會失敗的 API。
|
|
500
|
+
|
|
501
|
+
### Root exports (`@rytass/wms-module-graphql`)
|
|
502
|
+
|
|
503
|
+
| 匯出 | 種類 | 說明 |
|
|
504
|
+
|---|---|---|
|
|
505
|
+
| `WmsOperationRegistrationOptions` | type | `enabledOperations` / `disabledOperations` / `disabledFields` 三個選填欄位 |
|
|
506
|
+
| `pruneDisabledOperations(resolverClasses, options)` | function | `forRootAsync` 內部使用;公開匯出供進階情境(自組 provider 清單)使用 |
|
|
507
|
+
| `PrunedOperations` | type | `{ queries, mutations }` — 實際被移除的欄位名 |
|
|
508
|
+
| `WmsOperationName` | type | 從 `@rytass/wms-module-core` 轉出 |
|
|
509
|
+
| `WMS_OPERATION_NAMES` | const | 從 `@rytass/wms-module-core` 轉出 |
|
|
510
|
+
|
|
511
|
+
### 語意
|
|
512
|
+
|
|
513
|
+
- **名稱不等於欄位。** 多支 query 共用同一組 requirement(`loader:read` 6 支、
|
|
514
|
+
`stock:read` 5 支、`material:read` 與 `loader:create` 各 3 支),停用名稱會一次移除全部;
|
|
515
|
+
需要更細的粒度時用 `disabledFields`。
|
|
516
|
+
- **停用 resolver 不會停用 domain。** service 照常可注入,這是刻意的:自有流程的宿主
|
|
517
|
+
仍能直呼 `ReceiveInventoryOrderService` 等服務。
|
|
518
|
+
- **`@ResolveField` 不受影響**——它們只能透過已註冊的 root 欄位抵達。
|
|
519
|
+
|
|
520
|
+
### 實作備註
|
|
521
|
+
|
|
522
|
+
resolver metadata 在 `@nestjs/graphql` 是 **lazy** 的(`@Query()` 只登記 thunk,真正寫入
|
|
523
|
+
要等 schema build),所以停用同時做兩件事:`forRootAsync` 當下刪掉 resolver prototype 上
|
|
524
|
+
的方法(`ResolversExplorerService` 掃 prototype,且早於 metadata 載入),並包裝
|
|
525
|
+
`TypeMetadataStorage.addQueryMetadata` / `addMutationMetadata` 擋掉該筆。兩者必須成對,
|
|
526
|
+
否則 schema 會留下沒有 resolver 的死欄位,或 `makeExecutableSchema` 因 resolver 與
|
|
527
|
+
typeDefs 不符而拒絕整份 schema。
|
|
528
|
+
|
|
529
|
+
---
|
|
530
|
+
|
|
458
531
|
## Events & Hooks
|
|
459
532
|
|
|
460
533
|
Opt-in `beforeHooks` (veto) and post-commit `afterListeners` for every mutation. Each root mutation carries `@WmsMutationEvent({ event })` (already applied); a per-mutation interceptor runs the before-hook, opens an `AsyncLocalStorage` dispatch scope, and flushes collected events after the transaction commits. Stock domain events are collected centrally by a TypeORM subscriber on `*_order_change` inserts. Full design & the complete event list: [`docs/events.md`](./events.md).
|
|
@@ -554,6 +627,7 @@ WmsModuleGraphqlModule.forRootAsync({
|
|
|
554
627
|
| `MaterialQuery` | `material`, `materials` | `MaterialDto`, `Materials` | `lib/queries/material.query.ts` |
|
|
555
628
|
| `StockQuery` | `stock`, `stocks`, `stocksGroupedByMaterial`, `aggregatedStocks`, `changeLogs` | `StockDto`, `Stocks`, `Materials`, `AggregatedStocks`, `ChangeLogs` | `lib/queries/stock.query.ts` |
|
|
556
629
|
| `BatchQuery` | `batches` | `Batches` | `lib/queries/batch.query.ts` |
|
|
630
|
+
| `InventoryCountOrderQuery` | `inventoryCountOrders`, `inventoryCountOrder` | `InventoryCountOrders`, `InventoryCountOrderDto` | `lib/queries/inventory-count-order.query.ts` |
|
|
557
631
|
| `LocationQuery` | `location`, `locations` | `LocationDto`, `Locations` | `lib/queries/location.query.ts` |
|
|
558
632
|
| `ReceiveInventoryOrderQuery` | `receiveInventoryOrder`, `receiveInventoryOrders` | `ReceiveInventoryOrderDto`, `ReceiveInventoryOrders` | `lib/queries/recieve-inventory-order.query.ts` |
|
|
559
633
|
| `ShipInventoryOrderQuery` | `shipInventoryOrder`, `shipInventoryOrders` | `ShipInventoryOrderDto`, `ShipInventoryOrders` | `lib/queries/ship-inventory-order.query.ts` |
|
|
@@ -572,6 +646,7 @@ WmsModuleGraphqlModule.forRootAsync({
|
|
|
572
646
|
| `LoaderMutation` | `createLoader`, `createBatchLoader`, `updateLoader`, `createLoaderType`(方法名未確認), `updateLoaderType` | 載具與類型 | `lib/mutations/loader.mutation.ts` |
|
|
573
647
|
| `LocationMutation` | `createLocation`, `updateLocation` | 庫位 | `lib/mutations/location.mutation.ts` |
|
|
574
648
|
| `MaterialMutation` | `createMaterial`, `updateMaterial` | 料號 | `lib/mutations/material.mutation.ts` |
|
|
649
|
+
| `InventoryCountOrderMutation` | `createInventoryCountOrder`, `updateInventoryCountOrder`, `startInventoryCount`, `countInventory`, `addInventoryCountItem`, `removeInventoryCountItem`, `resetInventoryCount`, `cancelInventoryCount`, `settleInventoryCount` | 盤點單。`startInventoryCount` 會鎖定範圍內儲位;`settleInventoryCount` 是唯一會改動庫存的一支 | `lib/mutations/inventory-count-order.mutation.ts` |
|
|
575
650
|
| `ReceiveInventoryOrderMutation` | `createReceiveInventoryOrder`, `updateReceiveInventoryOrder`, `receive` | 入庫單 | `lib/mutations/receive-inventory-order.mutation.ts` |
|
|
576
651
|
| `ShipInventoryOrderMutation` | `createShipInventoryOrder`, `updateShipInventoryOrder`, `ship`, `cancelShip` | 出庫單 | `lib/mutations/ship-inventory-order.mutation.ts` |
|
|
577
652
|
| `TransferOrderMutation` | `createTransferOrder`, `updateTransferOrder`, `transfer`, `cancelTransfer` | 調撥單 | `lib/mutations/transfer-order.mutation.ts` |
|
package/docs/events.md
CHANGED
|
@@ -215,7 +215,7 @@ and the bridge can be used together — both fire.
|
|
|
215
215
|
|
|
216
216
|
## 5. Complete event list
|
|
217
217
|
|
|
218
|
-
### Operation events (
|
|
218
|
+
### Operation events (45) — `<domain>.<past-tense-action>`
|
|
219
219
|
|
|
220
220
|
The **v2 `result` type** column shows the concrete type subscribers receive via
|
|
221
221
|
`WmsOperationResultMap`. Events marked ⚠️ **boolean** are the 9 action mutations
|
|
@@ -269,24 +269,43 @@ events they fan out (see §3.1).
|
|
|
269
269
|
> `quantityChanged`. So a mutation emits a stock event only on the code paths
|
|
270
270
|
> that actually write a change row (e.g. an `update*` only when it adds items).
|
|
271
271
|
>
|
|
272
|
+
|
|
273
|
+
Inventory counting adds seven. Only `settled` moves stock; the rest record progress
|
|
274
|
+
through the count, which is what makes them useful for an audit trail of who counted
|
|
275
|
+
what and when.
|
|
276
|
+
|
|
277
|
+
| Event | Mutation | v2 `result` type | Fans out to stock event |
|
|
278
|
+
|--------------------------------------|----------------------------|--------------------------------------|---------------------------------------------|
|
|
279
|
+
| `inventory-count-order.created` | createInventoryCountOrder | `InventoryCountOrderDto` | — |
|
|
280
|
+
| `inventory-count-order.updated` | updateInventoryCountOrder / addInventoryCountItem / removeInventoryCountItem | `InventoryCountOrderDto` \| `InventoryCountOrderItemDto` | — |
|
|
281
|
+
| `inventory-count-order.started` | startInventoryCount | `InventoryCountOrderDto` | — (snapshots the ledger, locks the scope) |
|
|
282
|
+
| `inventory-count-order.counted` | countInventory | `InventoryCountOrderDto` | — |
|
|
283
|
+
| `inventory-count-order.reset` | resetInventoryCount | `InventoryCountOrderDto` | — |
|
|
284
|
+
| `inventory-count-order.cancelled` | cancelInventoryCount | `InventoryCountOrderDto` | — (releases the lock) |
|
|
285
|
+
| `inventory-count-order.settled` | settleInventoryCount | `InventoryCountOrderDto` | `stock.count-gained` / `stock.count-lost` |
|
|
286
|
+
|
|
272
287
|
> The "v2 `result` type" column refers to the typed overlay provided by
|
|
273
288
|
> `WmsOperationResultMap` (exported from `@rytass/wms-module-graphql`). In v1
|
|
274
289
|
> `result` is typed `unknown`; consumer code using the typed maps gets the
|
|
275
290
|
> concrete DTO automatically.
|
|
276
291
|
|
|
277
|
-
### Stock domain events (
|
|
292
|
+
### Stock domain events (20) — `stock.<change-type>`
|
|
278
293
|
|
|
279
294
|
`stock.received`, `stock.in-shipment`, `stock.shipped`, `stock.in-transfer`,
|
|
280
295
|
`stock.transferred`, `stock.vendor-transferred`, `stock.vendor-returned`,
|
|
281
296
|
`stock.held`, `stock.released`, `stock.customer-held`,
|
|
282
297
|
`stock.customer-returned`, `stock.splitted`, `stock.merged`, `stock.allocated`,
|
|
283
298
|
`stock.deallocated`, `stock.reclassified`, `stock.scraped`,
|
|
284
|
-
`stock.inspection-resolved`.
|
|
299
|
+
`stock.count-gained`, `stock.count-lost`, `stock.inspection-resolved`.
|
|
285
300
|
|
|
286
|
-
|
|
301
|
+
19 of them map 1:1 to `ChangeType`. `stock.inspection-resolved` has no
|
|
287
302
|
`ChangeType` (quality inspection only flips the `inspectionResult` flag) and
|
|
288
303
|
carries `changeType: null` plus `inspectionResult`.
|
|
289
304
|
|
|
305
|
+
`stock.count-gained` / `stock.count-lost` are emitted only by
|
|
306
|
+
`settleInventoryCount`, one per line whose counted quantity differed from the
|
|
307
|
+
books — a line that matched writes no change row and therefore no event.
|
|
308
|
+
|
|
290
309
|
A single operation can emit **several** stock events — one per `*_order_change`
|
|
291
310
|
row written, i.e. one per affected item. Cancellations re-use the forward event
|
|
292
311
|
with a negative `quantityDelta` (`cancelShip` -> `stock.shipped`,
|