@rytass/wms-module-core 0.1.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 +80 -0
- package/index.cjs.js +6479 -0
- package/index.d.ts +5 -0
- package/index.js +74 -0
- package/lib/constants/index.d.ts +1 -0
- package/lib/constants/stock-status.d.ts +30 -0
- package/lib/constants/stock-status.js +51 -0
- package/lib/core.module.d.ts +7 -0
- package/lib/core.module.js +102 -0
- package/lib/models/extensions/allocate-inventory-order/allocate-inventory-order-change.entity.d.ts +10 -0
- package/lib/models/extensions/allocate-inventory-order/allocate-inventory-order-change.entity.js +40 -0
- package/lib/models/extensions/allocate-inventory-order/allocate-inventory-order-item.entity.d.ts +20 -0
- package/lib/models/extensions/allocate-inventory-order/allocate-inventory-order-item.entity.js +103 -0
- package/lib/models/extensions/allocate-inventory-order/allocate-inventory-order.entity.d.ts +8 -0
- package/lib/models/extensions/allocate-inventory-order/allocate-inventory-order.entity.js +33 -0
- package/lib/models/extensions/hold-inventory-order/hold-inventory-order-change.entity.d.ts +10 -0
- package/lib/models/extensions/hold-inventory-order/hold-inventory-order-change.entity.js +40 -0
- package/lib/models/extensions/hold-inventory-order/hold-inventory-order-item.entity.d.ts +19 -0
- package/lib/models/extensions/hold-inventory-order/hold-inventory-order-item.entity.js +97 -0
- package/lib/models/extensions/hold-inventory-order/hold-inventory-order.entity.d.ts +10 -0
- package/lib/models/extensions/hold-inventory-order/hold-inventory-order.entity.js +43 -0
- package/lib/models/extensions/index.d.ts +37 -0
- package/lib/models/extensions/merge-batch-order/merge-batch-order-change.entity.d.ts +10 -0
- package/lib/models/extensions/merge-batch-order/merge-batch-order-change.entity.js +40 -0
- package/lib/models/extensions/merge-batch-order/merge-batch-order-item.entity.d.ts +15 -0
- package/lib/models/extensions/merge-batch-order/merge-batch-order-item.entity.js +74 -0
- package/lib/models/extensions/merge-batch-order/merge-batch-order.entity.d.ts +8 -0
- package/lib/models/extensions/merge-batch-order/merge-batch-order.entity.js +33 -0
- package/lib/models/extensions/quality-inspection-order/quality-inspection-order-change.entity.d.ts +11 -0
- package/lib/models/extensions/quality-inspection-order/quality-inspection-order-change.entity.js +45 -0
- package/lib/models/extensions/quality-inspection-order/quality-inspection-order-item.entity.d.ts +18 -0
- package/lib/models/extensions/quality-inspection-order/quality-inspection-order-item.entity.js +93 -0
- package/lib/models/extensions/quality-inspection-order/quality-inspection-order.entity.d.ts +9 -0
- package/lib/models/extensions/quality-inspection-order/quality-inspection-order.entity.js +38 -0
- package/lib/models/extensions/receive-inventory-order/receive-inventory-order-change.entity.d.ts +12 -0
- package/lib/models/extensions/receive-inventory-order/receive-inventory-order-change.entity.js +46 -0
- package/lib/models/extensions/receive-inventory-order/receive-inventory-order-item.entity.d.ts +19 -0
- package/lib/models/extensions/receive-inventory-order/receive-inventory-order-item.entity.js +89 -0
- package/lib/models/extensions/receive-inventory-order/receive-inventory-order.entity.d.ts +13 -0
- package/lib/models/extensions/receive-inventory-order/receive-inventory-order.entity.js +57 -0
- package/lib/models/extensions/reclassify-inventory-order/reclassify-inventory-order-change.entity.d.ts +10 -0
- package/lib/models/extensions/reclassify-inventory-order/reclassify-inventory-order-change.entity.js +40 -0
- package/lib/models/extensions/reclassify-inventory-order/reclassify-inventory-order-item.entity.d.ts +15 -0
- package/lib/models/extensions/reclassify-inventory-order/reclassify-inventory-order-item.entity.js +74 -0
- package/lib/models/extensions/reclassify-inventory-order/reclassify-inventory-order.entity.d.ts +8 -0
- package/lib/models/extensions/reclassify-inventory-order/reclassify-inventory-order.entity.js +33 -0
- package/lib/models/extensions/scrape-order/scrape-order-change.entity.d.ts +10 -0
- package/lib/models/extensions/scrape-order/scrape-order-change.entity.js +40 -0
- package/lib/models/extensions/scrape-order/scrape-order-item.entity.d.ts +18 -0
- package/lib/models/extensions/scrape-order/scrape-order-item.entity.js +93 -0
- package/lib/models/extensions/scrape-order/scrape-order.entity.d.ts +8 -0
- package/lib/models/extensions/scrape-order/scrape-order.entity.js +33 -0
- package/lib/models/extensions/ship-inventory-order/ship-inventory-order-change.entity.d.ts +12 -0
- package/lib/models/extensions/ship-inventory-order/ship-inventory-order-change.entity.js +46 -0
- package/lib/models/extensions/ship-inventory-order/ship-inventory-order-item.entity.d.ts +19 -0
- package/lib/models/extensions/ship-inventory-order/ship-inventory-order-item.entity.js +90 -0
- package/lib/models/extensions/ship-inventory-order/ship-inventory-order-reference.entity.d.ts +13 -0
- package/lib/models/extensions/ship-inventory-order/ship-inventory-order-reference.entity.js +65 -0
- package/lib/models/extensions/ship-inventory-order/ship-inventory-order.entity.d.ts +13 -0
- package/lib/models/extensions/ship-inventory-order/ship-inventory-order.entity.js +56 -0
- package/lib/models/extensions/split-batch-order/split-batch-order-change.entity.d.ts +10 -0
- package/lib/models/extensions/split-batch-order/split-batch-order-change.entity.js +40 -0
- package/lib/models/extensions/split-batch-order/split-batch-order-item.entity.d.ts +15 -0
- package/lib/models/extensions/split-batch-order/split-batch-order-item.entity.js +74 -0
- package/lib/models/extensions/split-batch-order/split-batch-order.entity.d.ts +8 -0
- package/lib/models/extensions/split-batch-order/split-batch-order.entity.js +33 -0
- package/lib/models/extensions/transfer-customer-order/transfer-customer-order-change.entity.d.ts +10 -0
- package/lib/models/extensions/transfer-customer-order/transfer-customer-order-change.entity.js +40 -0
- package/lib/models/extensions/transfer-customer-order/transfer-customer-order-item.entity.d.ts +19 -0
- package/lib/models/extensions/transfer-customer-order/transfer-customer-order-item.entity.js +98 -0
- package/lib/models/extensions/transfer-customer-order/transfer-customer-order.entity.d.ts +8 -0
- package/lib/models/extensions/transfer-customer-order/transfer-customer-order.entity.js +33 -0
- package/lib/models/extensions/transfer-order/transfer-order-change.entity.d.ts +10 -0
- package/lib/models/extensions/transfer-order/transfer-order-change.entity.js +40 -0
- package/lib/models/extensions/transfer-order/transfer-order-item.entity.d.ts +21 -0
- package/lib/models/extensions/transfer-order/transfer-order-item.entity.js +108 -0
- package/lib/models/extensions/transfer-order/transfer-order.entity.d.ts +12 -0
- package/lib/models/extensions/transfer-order/transfer-order.entity.js +53 -0
- package/lib/models/extensions/transfer-vendor-order/transfer-vendor-order-change.entity.d.ts +10 -0
- package/lib/models/extensions/transfer-vendor-order/transfer-vendor-order-change.entity.js +40 -0
- package/lib/models/extensions/transfer-vendor-order/transfer-vendor-order-item.entity.d.ts +19 -0
- package/lib/models/extensions/transfer-vendor-order/transfer-vendor-order-item.entity.js +98 -0
- package/lib/models/extensions/transfer-vendor-order/transfer-vendor-order.entity.d.ts +8 -0
- package/lib/models/extensions/transfer-vendor-order/transfer-vendor-order.entity.js +33 -0
- package/lib/models/index.d.ts +2 -0
- package/lib/models/metadata/batch-group.entity.d.ts +8 -0
- package/lib/models/metadata/batch-group.entity.js +31 -0
- package/lib/models/metadata/batch.entity.d.ts +15 -0
- package/lib/models/metadata/batch.entity.js +73 -0
- package/lib/models/metadata/index.d.ts +11 -0
- package/lib/models/metadata/loader-type.entity.d.ts +9 -0
- package/lib/models/metadata/loader-type.entity.js +43 -0
- package/lib/models/metadata/loader-unit.entity.d.ts +5 -0
- package/lib/models/metadata/loader-unit.entity.js +21 -0
- package/lib/models/metadata/loader.entity.d.ts +21 -0
- package/lib/models/metadata/loader.entity.js +98 -0
- package/lib/models/metadata/location.entity.d.ts +8 -0
- package/lib/models/metadata/location.entity.js +28 -0
- package/lib/models/metadata/material-unit.entity.d.ts +11 -0
- package/lib/models/metadata/material-unit.entity.js +51 -0
- package/lib/models/metadata/material.entity.d.ts +7 -0
- package/lib/models/metadata/material.entity.js +28 -0
- package/lib/models/metadata/sale-order.entity.d.ts +5 -0
- package/lib/models/metadata/sale-order.entity.js +21 -0
- package/lib/models/metadata/stock.entity.d.ts +8 -0
- package/lib/models/metadata/stock.entity.js +29 -0
- package/lib/models/metadata/unit.entity.d.ts +5 -0
- package/lib/models/metadata/unit.entity.js +21 -0
- package/lib/models/models.module.d.ts +6 -0
- package/lib/models/models.module.js +122 -0
- package/lib/services/allocate-inventory-order.service.d.ts +29 -0
- package/lib/services/allocate-inventory-order.service.js +299 -0
- package/lib/services/base-order.service.d.ts +41 -0
- package/lib/services/batch.service.d.ts +30 -0
- package/lib/services/batch.service.js +218 -0
- package/lib/services/helper.service.d.ts +6 -0
- package/lib/services/helper.service.js +28 -0
- package/lib/services/hold-inventory-order.service.d.ts +29 -0
- package/lib/services/hold-inventory-order.service.js +285 -0
- package/lib/services/index.d.ts +22 -0
- package/lib/services/loader.service.d.ts +43 -0
- package/lib/services/loader.service.js +282 -0
- package/lib/services/location.service.d.ts +13 -0
- package/lib/services/location.service.js +130 -0
- package/lib/services/material.service.d.ts +27 -0
- package/lib/services/material.service.js +172 -0
- package/lib/services/merge-batch-order.service.d.ts +19 -0
- package/lib/services/merge-batch-order.service.js +195 -0
- package/lib/services/quality-inspection-order.service.d.ts +19 -0
- package/lib/services/quality-inspection-order.service.js +135 -0
- package/lib/services/receive-inventory-order.service.d.ts +41 -0
- package/lib/services/receive-inventory-order.service.js +407 -0
- package/lib/services/reclassify-inventory-order.service.d.ts +19 -0
- package/lib/services/reclassify-inventory-order.service.js +181 -0
- package/lib/services/sale-order.service.d.ts +7 -0
- package/lib/services/sale-order.service.js +20 -0
- package/lib/services/scrape.service.d.ts +18 -0
- package/lib/services/scrape.service.js +139 -0
- package/lib/services/ship-inventory-order.service.d.ts +60 -0
- package/lib/services/ship-inventory-order.service.js +599 -0
- package/lib/services/split-batch-order.service.d.ts +19 -0
- package/lib/services/split-batch-order.service.js +161 -0
- package/lib/services/stock.service.d.ts +38 -0
- package/lib/services/stock.service.js +477 -0
- package/lib/services/transfer-customer-order.service.d.ts +35 -0
- package/lib/services/transfer-customer-order.service.js +279 -0
- package/lib/services/transfer-order.service.d.ts +44 -0
- package/lib/services/transfer-order.service.js +632 -0
- package/lib/services/transfer-vendor-order.service.d.ts +35 -0
- package/lib/services/transfer-vendor-order.service.js +279 -0
- package/lib/services/unit.service.d.ts +7 -0
- package/lib/services/unit.service.js +67 -0
- package/lib/services/warehouse-map.service.d.ts +10 -0
- package/lib/services/warehouse-map.service.js +38 -0
- package/lib/typings/aggregated-stock.d.ts +22 -0
- package/lib/typings/cancel-ship-inventory-order.input.d.ts +4 -0
- package/lib/typings/cancel-transfer-order.input.d.ts +4 -0
- package/lib/typings/core-module-options.d.ts +8 -0
- package/lib/typings/core-module-options.js +3 -0
- package/lib/typings/create-allocate-inventory-order.input.d.ts +25 -0
- package/lib/typings/create-hold-inventory-order.input.d.ts +21 -0
- package/lib/typings/create-inspection-order.input.d.ts +14 -0
- package/lib/typings/create-loader-type.input.d.ts +9 -0
- package/lib/typings/create-loader.input.d.ts +15 -0
- package/lib/typings/create-location.input.d.ts +12 -0
- package/lib/typings/create-material-unit.input.d.ts +5 -0
- package/lib/typings/create-material.input.d.ts +11 -0
- package/lib/typings/create-receive-inventory-order.input.d.ts +26 -0
- package/lib/typings/create-ship-inventory-order.input.d.ts +46 -0
- package/lib/typings/create-transfer-customer-order.input.d.ts +25 -0
- package/lib/typings/create-transfer-order.input.d.ts +25 -0
- package/lib/typings/create-transfer-vendor-order.input.d.ts +25 -0
- package/lib/typings/deallocate-inventory-order.d.ts +8 -0
- package/lib/typings/find-allocate-inventory-order.input.d.ts +13 -0
- package/lib/typings/find-batch.input.d.ts +8 -0
- package/lib/typings/find-hold-inventory-order.input.d.ts +13 -0
- package/lib/typings/find-loader.input.d.ts +33 -0
- package/lib/typings/find-location.input.d.ts +10 -0
- package/lib/typings/find-material.input.d.ts +10 -0
- package/lib/typings/find-receive-inventory-order.input.d.ts +26 -0
- package/lib/typings/find-receive-inventory-order.input.js +9 -0
- package/lib/typings/find-ship-inventory-order.input.d.ts +26 -0
- package/lib/typings/find-ship-inventory-order.input.js +9 -0
- package/lib/typings/find-stock.input.d.ts +21 -0
- package/lib/typings/find-transfer-order.input.d.ts +21 -0
- package/lib/typings/get-batch.input.d.ts +14 -0
- package/lib/typings/index.d.ts +18 -0
- package/lib/typings/merge-batch.input.d.ts +11 -0
- package/lib/typings/paginations.d.ts +4 -0
- package/lib/typings/receive-inventory-order.input.d.ts +8 -0
- package/lib/typings/reclassify-inventory-order.input.d.ts +11 -0
- package/lib/typings/release-inventory-order.input.d.ts +8 -0
- package/lib/typings/scrape.input.d.ts +8 -0
- package/lib/typings/ship-inventory-order.input.d.ts +4 -0
- package/lib/typings/split-batch.input.d.ts +10 -0
- package/lib/typings/transfer-order.input.d.ts +4 -0
- package/package.json +52 -0
- package/src/lib/models/extensions/README.md +219 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { __decorate, __param, __metadata } from 'tslib';
|
|
2
|
+
import { Injectable, Inject } from '@nestjs/common';
|
|
3
|
+
import '../models/metadata/batch.entity.js';
|
|
4
|
+
import '../models/metadata/batch-group.entity.js';
|
|
5
|
+
import '../models/metadata/loader.entity.js';
|
|
6
|
+
import '../models/metadata/loader-type.entity.js';
|
|
7
|
+
import '../models/metadata/loader-unit.entity.js';
|
|
8
|
+
import '../models/metadata/location.entity.js';
|
|
9
|
+
import '../models/metadata/material.entity.js';
|
|
10
|
+
import '../models/metadata/material-unit.entity.js';
|
|
11
|
+
import '../models/metadata/sale-order.entity.js';
|
|
12
|
+
import { StockEntity } from '../models/metadata/stock.entity.js';
|
|
13
|
+
import '../models/metadata/unit.entity.js';
|
|
14
|
+
import '../models/extensions/receive-inventory-order/receive-inventory-order-item.entity.js';
|
|
15
|
+
import '../models/extensions/receive-inventory-order/receive-inventory-order.entity.js';
|
|
16
|
+
import '../models/extensions/receive-inventory-order/receive-inventory-order-change.entity.js';
|
|
17
|
+
import '../models/extensions/ship-inventory-order/ship-inventory-order-item.entity.js';
|
|
18
|
+
import '../models/extensions/ship-inventory-order/ship-inventory-order.entity.js';
|
|
19
|
+
import '../models/extensions/ship-inventory-order/ship-inventory-order-reference.entity.js';
|
|
20
|
+
import '../models/extensions/ship-inventory-order/ship-inventory-order-change.entity.js';
|
|
21
|
+
import '../models/extensions/transfer-order/transfer-order.entity.js';
|
|
22
|
+
import '../models/extensions/transfer-order/transfer-order-item.entity.js';
|
|
23
|
+
import '../models/extensions/transfer-order/transfer-order-change.entity.js';
|
|
24
|
+
import '../models/extensions/hold-inventory-order/hold-inventory-order.entity.js';
|
|
25
|
+
import '../models/extensions/hold-inventory-order/hold-inventory-order-item.entity.js';
|
|
26
|
+
import '../models/extensions/hold-inventory-order/hold-inventory-order-change.entity.js';
|
|
27
|
+
import { AllocateInventoryOrderEntity } from '../models/extensions/allocate-inventory-order/allocate-inventory-order.entity.js';
|
|
28
|
+
import { AllocateInventoryOrderItemEntity } from '../models/extensions/allocate-inventory-order/allocate-inventory-order-item.entity.js';
|
|
29
|
+
import { AllocateInventoryOrderChangeEntityClass } from '../models/extensions/allocate-inventory-order/allocate-inventory-order-change.entity.js';
|
|
30
|
+
import '../models/extensions/split-batch-order/split-batch-order.entity.js';
|
|
31
|
+
import '../models/extensions/split-batch-order/split-batch-order-item.entity.js';
|
|
32
|
+
import '../models/extensions/split-batch-order/split-batch-order-change.entity.js';
|
|
33
|
+
import '../models/extensions/merge-batch-order/merge-batch-order.entity.js';
|
|
34
|
+
import '../models/extensions/merge-batch-order/merge-batch-order-item.entity.js';
|
|
35
|
+
import '../models/extensions/merge-batch-order/merge-batch-order-change.entity.js';
|
|
36
|
+
import '../models/extensions/reclassify-inventory-order/reclassify-inventory-order.entity.js';
|
|
37
|
+
import '../models/extensions/reclassify-inventory-order/reclassify-inventory-order-item.entity.js';
|
|
38
|
+
import '../models/extensions/reclassify-inventory-order/reclassify-inventory-order-change.entity.js';
|
|
39
|
+
import '../models/extensions/transfer-vendor-order/transfer-vendor-order.entity.js';
|
|
40
|
+
import '../models/extensions/transfer-vendor-order/transfer-vendor-order-item.entity.js';
|
|
41
|
+
import '../models/extensions/transfer-vendor-order/transfer-vendor-order-change.entity.js';
|
|
42
|
+
import '../models/extensions/quality-inspection-order/quality-inspection-order.entity.js';
|
|
43
|
+
import '../models/extensions/quality-inspection-order/quality-inspection-order-item.entity.js';
|
|
44
|
+
import '../models/extensions/quality-inspection-order/quality-inspection-order-change.entity.js';
|
|
45
|
+
import '../models/extensions/transfer-customer-order/transfer-customer-order.entity.js';
|
|
46
|
+
import '../models/extensions/transfer-customer-order/transfer-customer-order-item.entity.js';
|
|
47
|
+
import '../models/extensions/transfer-customer-order/transfer-customer-order-change.entity.js';
|
|
48
|
+
import '../models/extensions/scrape-order/scrape-order.entity.js';
|
|
49
|
+
import '../models/extensions/scrape-order/scrape-order-item.entity.js';
|
|
50
|
+
import '../models/extensions/scrape-order/scrape-order-change.entity.js';
|
|
51
|
+
import { DataSource, Not, IsNull } from 'typeorm';
|
|
52
|
+
import { OrderEntity } from '@rytass/wms-base-nestjs-module';
|
|
53
|
+
import { HelperService } from './helper.service.js';
|
|
54
|
+
import { MaterialService } from './material.service.js';
|
|
55
|
+
import { BatchService } from './batch.service.js';
|
|
56
|
+
import { StockService } from './stock.service.js';
|
|
57
|
+
|
|
58
|
+
let AllocateInventoryOrderService = class AllocateInventoryOrderService {
|
|
59
|
+
dataSource;
|
|
60
|
+
helperService;
|
|
61
|
+
materialService;
|
|
62
|
+
batchService;
|
|
63
|
+
stockService;
|
|
64
|
+
allocateInventoryOrderEntity;
|
|
65
|
+
allocateInventoryOrderItemEntity;
|
|
66
|
+
stockEntity;
|
|
67
|
+
seqPrefix = 'AIO';
|
|
68
|
+
constructor(dataSource, helperService, materialService, batchService, stockService, allocateInventoryOrderEntity, allocateInventoryOrderItemEntity, stockEntity) {
|
|
69
|
+
this.dataSource = dataSource;
|
|
70
|
+
this.helperService = helperService;
|
|
71
|
+
this.materialService = materialService;
|
|
72
|
+
this.batchService = batchService;
|
|
73
|
+
this.stockService = stockService;
|
|
74
|
+
this.allocateInventoryOrderEntity = allocateInventoryOrderEntity;
|
|
75
|
+
this.allocateInventoryOrderItemEntity = allocateInventoryOrderItemEntity;
|
|
76
|
+
this.stockEntity = stockEntity;
|
|
77
|
+
}
|
|
78
|
+
getRepositories(manager) {
|
|
79
|
+
return {
|
|
80
|
+
allocateInventoryOrder: manager.getRepository(this.allocateInventoryOrderEntity),
|
|
81
|
+
allocateInventoryOrderItem: manager.getRepository(this.allocateInventoryOrderItemEntity),
|
|
82
|
+
allocateInventoryOrderChange: manager.getRepository(AllocateInventoryOrderChangeEntityClass),
|
|
83
|
+
order: manager.getRepository(OrderEntity),
|
|
84
|
+
stock: manager.getRepository(this.stockEntity),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
async processAllocateInventoryOrderItems(items, manager) {
|
|
88
|
+
const repos = this.getRepositories(manager);
|
|
89
|
+
await Promise.all(items.map(async (data) => {
|
|
90
|
+
// Ensure required fields are present
|
|
91
|
+
if (!data.batchId || !data.materialId)
|
|
92
|
+
return;
|
|
93
|
+
// Split batch first with saleId/saleSerialId to track allocation state
|
|
94
|
+
const splittedBatch = await this.batchService.splitBatch({
|
|
95
|
+
id: data.batchId,
|
|
96
|
+
saleId: data.saleId,
|
|
97
|
+
saleSerialId: data.saleSerialId,
|
|
98
|
+
manager,
|
|
99
|
+
});
|
|
100
|
+
// Save item with ORIGINAL batch id to maintain source state
|
|
101
|
+
const item = await repos.allocateInventoryOrderItem.save(repos.allocateInventoryOrderItem.create(data));
|
|
102
|
+
const base = await repos.order.save({});
|
|
103
|
+
const conversionFactor = await this.materialService.getConversionFactor(item.materialId, item.unitId || undefined);
|
|
104
|
+
await repos.allocateInventoryOrderChange.save(repos.allocateInventoryOrderChange.create({
|
|
105
|
+
item,
|
|
106
|
+
order: base,
|
|
107
|
+
quantityChanged: item.targetAllocatedQuantity * conversionFactor,
|
|
108
|
+
}));
|
|
109
|
+
// Stock movements track the allocation through splitted batch
|
|
110
|
+
await this.stockService.validateStockAvailability({
|
|
111
|
+
materialId: item.materialId,
|
|
112
|
+
batchId: item.batchId,
|
|
113
|
+
locationId: this.stockService.resolveLocationId(item.locationId),
|
|
114
|
+
loaderId: this.stockService.resolveLoaderId(item.loaderId),
|
|
115
|
+
quantity: item.targetAllocatedQuantity * conversionFactor,
|
|
116
|
+
}, manager);
|
|
117
|
+
await repos.stock.save(repos.stock.create([
|
|
118
|
+
// deduct from original batch available stock
|
|
119
|
+
{
|
|
120
|
+
orderId: base.id,
|
|
121
|
+
materialId: item.materialId,
|
|
122
|
+
batchId: item.batchId, // original batch
|
|
123
|
+
locationId: this.stockService.resolveLocationId(item.locationId),
|
|
124
|
+
loaderId: this.stockService.resolveLoaderId(item.loaderId),
|
|
125
|
+
quantity: -1 * item.targetAllocatedQuantity * conversionFactor,
|
|
126
|
+
},
|
|
127
|
+
// add to splitted batch in allocated state
|
|
128
|
+
{
|
|
129
|
+
orderId: base.id,
|
|
130
|
+
materialId: item.materialId,
|
|
131
|
+
batchId: splittedBatch.id, // splitted batch marked with saleId
|
|
132
|
+
locationId: this.stockService.resolveLocationId(item.locationId),
|
|
133
|
+
loaderId: this.stockService.resolveLoaderId(item.loaderId),
|
|
134
|
+
quantity: item.targetAllocatedQuantity * conversionFactor,
|
|
135
|
+
},
|
|
136
|
+
]));
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
async createAllocateInventoryOrder(options, manager = this.dataSource.manager) {
|
|
140
|
+
const repos = this.getRepositories(manager);
|
|
141
|
+
const key = await this.helperService.getSeq(this.seqPrefix);
|
|
142
|
+
const { items, ...orderOptions } = options;
|
|
143
|
+
const order = await repos.allocateInventoryOrder.save(repos.allocateInventoryOrder.create({
|
|
144
|
+
key,
|
|
145
|
+
...orderOptions,
|
|
146
|
+
}));
|
|
147
|
+
if (items?.length) {
|
|
148
|
+
const processedItems = items.map((item) => ({
|
|
149
|
+
...item,
|
|
150
|
+
orderId: order.id,
|
|
151
|
+
}));
|
|
152
|
+
await this.processAllocateInventoryOrderItems(processedItems, manager);
|
|
153
|
+
}
|
|
154
|
+
return order;
|
|
155
|
+
}
|
|
156
|
+
async updateAllocateInventoryOrder({ id, manager = this.dataSource.manager, ...options }) {
|
|
157
|
+
const repos = this.getRepositories(manager);
|
|
158
|
+
const { items, ...orderOptions } = options;
|
|
159
|
+
const order = await repos.allocateInventoryOrder.findOneBy({ id });
|
|
160
|
+
const updated = await repos.allocateInventoryOrder.save({
|
|
161
|
+
...order,
|
|
162
|
+
...orderOptions,
|
|
163
|
+
});
|
|
164
|
+
if (items?.length) {
|
|
165
|
+
const existingItemIds = new Set((await repos.allocateInventoryOrderItem.find({
|
|
166
|
+
where: { orderId: id },
|
|
167
|
+
relations: ['changes'],
|
|
168
|
+
})).map((item) => item.id));
|
|
169
|
+
const newItems = [];
|
|
170
|
+
const existingItems = [];
|
|
171
|
+
items.forEach((item) => {
|
|
172
|
+
if (!item.id)
|
|
173
|
+
newItems.push({ ...item, orderId: id });
|
|
174
|
+
else if (existingItemIds.has(item.id))
|
|
175
|
+
existingItems.push({ ...item, orderId: id });
|
|
176
|
+
});
|
|
177
|
+
if (newItems.length)
|
|
178
|
+
await this.processAllocateInventoryOrderItems(newItems, manager);
|
|
179
|
+
if (existingItems.length)
|
|
180
|
+
await repos.allocateInventoryOrderItem.save(await Promise.all(existingItems.map((item) => repos.allocateInventoryOrderItem.create(item))));
|
|
181
|
+
}
|
|
182
|
+
return updated;
|
|
183
|
+
}
|
|
184
|
+
async deallocate(options, manager = this.dataSource.manager) {
|
|
185
|
+
if (!Array.isArray(options))
|
|
186
|
+
options = [options];
|
|
187
|
+
const repos = this.getRepositories(manager);
|
|
188
|
+
const key = await this.helperService.getSeq(this.seqPrefix, manager);
|
|
189
|
+
const order = await repos.allocateInventoryOrder.save(repos.allocateInventoryOrder.create({ key }));
|
|
190
|
+
if (options.length > 0) {
|
|
191
|
+
await Promise.all(options.map(async (data) => {
|
|
192
|
+
// Ensure required fields are present
|
|
193
|
+
if (!data.batchId || !data.materialId)
|
|
194
|
+
return;
|
|
195
|
+
const originalBatch = await this.batchService.batchRepository.findOneByOrFail({
|
|
196
|
+
id: data.batchId,
|
|
197
|
+
saleId: Not(IsNull()),
|
|
198
|
+
saleSerialId: Not(IsNull()),
|
|
199
|
+
});
|
|
200
|
+
const splittedBatch = await this.batchService.splitBatch({
|
|
201
|
+
id: data.batchId,
|
|
202
|
+
saleId: null, // mark splitted batch with null saleId to indicate deallocation
|
|
203
|
+
saleSerialId: null,
|
|
204
|
+
manager,
|
|
205
|
+
});
|
|
206
|
+
// Save item with ORIGINAL batch id to maintain source state
|
|
207
|
+
const item = await repos.allocateInventoryOrderItem.save(repos.allocateInventoryOrderItem.create({
|
|
208
|
+
...data,
|
|
209
|
+
saleId: originalBatch.saleId,
|
|
210
|
+
saleSerialId: originalBatch.saleSerialId,
|
|
211
|
+
targetAllocatedQuantity: -1 * data.quantity,
|
|
212
|
+
orderId: order.id,
|
|
213
|
+
}));
|
|
214
|
+
const base = await repos.order.save({});
|
|
215
|
+
const conversionFactor = await this.materialService.getConversionFactor(item.materialId, item.unitId || undefined);
|
|
216
|
+
const change = await repos.allocateInventoryOrderChange.save(repos.allocateInventoryOrderChange.create({
|
|
217
|
+
itemId: item.id,
|
|
218
|
+
id: base.id,
|
|
219
|
+
quantityChanged: -1 * item.targetAllocatedQuantity * conversionFactor,
|
|
220
|
+
}));
|
|
221
|
+
// Stock movements track the hold through splitted batch
|
|
222
|
+
await this.stockService.validateStockAvailability({
|
|
223
|
+
materialId: item.materialId,
|
|
224
|
+
batchId: item.batchId,
|
|
225
|
+
locationId: this.stockService.resolveLocationId(item.locationId),
|
|
226
|
+
loaderId: this.stockService.resolveLoaderId(item.loaderId),
|
|
227
|
+
quantity: change.quantityChanged,
|
|
228
|
+
}, manager);
|
|
229
|
+
await repos.stock.save(repos.stock.create([
|
|
230
|
+
// deduct from original batch available stock
|
|
231
|
+
{
|
|
232
|
+
orderId: base.id,
|
|
233
|
+
materialId: item.materialId,
|
|
234
|
+
batchId: item.batchId, // original batch
|
|
235
|
+
locationId: this.stockService.resolveLocationId(item.locationId),
|
|
236
|
+
loaderId: this.stockService.resolveLoaderId(item.loaderId),
|
|
237
|
+
quantity: -1 * change.quantityChanged,
|
|
238
|
+
},
|
|
239
|
+
// add to splitted batch in released state
|
|
240
|
+
{
|
|
241
|
+
orderId: base.id,
|
|
242
|
+
materialId: item.materialId,
|
|
243
|
+
batchId: splittedBatch.id, // splitted batch marked deallocated with null saleId
|
|
244
|
+
locationId: this.stockService.resolveLocationId(item.locationId),
|
|
245
|
+
loaderId: this.stockService.resolveLoaderId(item.loaderId),
|
|
246
|
+
quantity: change.quantityChanged,
|
|
247
|
+
},
|
|
248
|
+
]));
|
|
249
|
+
}));
|
|
250
|
+
}
|
|
251
|
+
return order;
|
|
252
|
+
}
|
|
253
|
+
findMany(options) {
|
|
254
|
+
const queryBuilder = this.dataSource
|
|
255
|
+
.getRepository(this.allocateInventoryOrderEntity)
|
|
256
|
+
.createQueryBuilder('to');
|
|
257
|
+
if (options.key)
|
|
258
|
+
queryBuilder.andWhere('to.key ILIKE :key', { key: `%${options.key}%` });
|
|
259
|
+
if (options.dateRange)
|
|
260
|
+
queryBuilder.andWhere('to.createdAt BETWEEN :start AND :end', {
|
|
261
|
+
start: options.dateRange.from,
|
|
262
|
+
end: options.dateRange.to,
|
|
263
|
+
});
|
|
264
|
+
if (options.materialId)
|
|
265
|
+
queryBuilder.innerJoin('to.items', 'm_items', 'm_items.materialId = :materialId', {
|
|
266
|
+
materialId: options.materialId,
|
|
267
|
+
});
|
|
268
|
+
if (options.batchId)
|
|
269
|
+
queryBuilder.innerJoin('to.items', 'b_items', 'b_items.batchId = :batchId', {
|
|
270
|
+
batchId: options.batchId,
|
|
271
|
+
});
|
|
272
|
+
if (options.locationId)
|
|
273
|
+
queryBuilder.innerJoin('to.items', 'l_items', 'l_items.locationId = :locationId', {
|
|
274
|
+
locationId: options.locationId,
|
|
275
|
+
});
|
|
276
|
+
if (options.loaderId)
|
|
277
|
+
queryBuilder.innerJoin('to.items', 'ld_items', 'ld_items.loaderId = :loaderId', {
|
|
278
|
+
loaderId: options.loaderId,
|
|
279
|
+
});
|
|
280
|
+
if (options.offset !== undefined && options.offset >= 0)
|
|
281
|
+
queryBuilder.skip(options.offset);
|
|
282
|
+
if (options.limit !== undefined && options.limit > 0)
|
|
283
|
+
queryBuilder.take(options.limit);
|
|
284
|
+
return queryBuilder.getManyAndCount();
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
AllocateInventoryOrderService = __decorate([
|
|
288
|
+
Injectable(),
|
|
289
|
+
__param(5, Inject(AllocateInventoryOrderEntity)),
|
|
290
|
+
__param(6, Inject(AllocateInventoryOrderItemEntity)),
|
|
291
|
+
__param(7, Inject(StockEntity)),
|
|
292
|
+
__metadata("design:paramtypes", [DataSource,
|
|
293
|
+
HelperService,
|
|
294
|
+
MaterialService,
|
|
295
|
+
BatchService,
|
|
296
|
+
StockService, Object, Object, Object])
|
|
297
|
+
], AllocateInventoryOrderService);
|
|
298
|
+
|
|
299
|
+
export { AllocateInventoryOrderService };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Repository } from 'typeorm';
|
|
2
|
+
import { StockEntityClass } from '../models';
|
|
3
|
+
import { OrderEntity } from '@rytass/wms-base-nestjs-module';
|
|
4
|
+
import { MaterialService } from './material.service';
|
|
5
|
+
import { StockService } from './stock.service';
|
|
6
|
+
export interface StockEntryParams {
|
|
7
|
+
materialId: string;
|
|
8
|
+
batchId: string;
|
|
9
|
+
quantity: number;
|
|
10
|
+
locationId?: string;
|
|
11
|
+
loaderId?: string;
|
|
12
|
+
unitId?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface Repositories {
|
|
15
|
+
order: Repository<OrderEntity>;
|
|
16
|
+
stock: Repository<StockEntityClass>;
|
|
17
|
+
[key: string]: Repository<any>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Base service for order operations that create/deduct stock entries.
|
|
21
|
+
* Provides common methods for adding and deducting inventory across different order types.
|
|
22
|
+
*/
|
|
23
|
+
export declare abstract class BaseOrderService {
|
|
24
|
+
protected abstract materialService: MaterialService;
|
|
25
|
+
protected abstract stockService: StockService;
|
|
26
|
+
/**
|
|
27
|
+
* Creates a new order and saves a positive quantity stock entry
|
|
28
|
+
* @param repos Repository map containing order and stock repositories
|
|
29
|
+
* @param params Stock entry parameters (materialId, batchId, quantity, locationId?, loaderId?, unitId?)
|
|
30
|
+
* @returns Created order ID
|
|
31
|
+
*/
|
|
32
|
+
protected add(repos: Repositories, params: StockEntryParams): Promise<string>;
|
|
33
|
+
/**
|
|
34
|
+
* Creates a negative quantity stock entry linked to a source order
|
|
35
|
+
* Used to deduct stock from an existing status (FREE, ALLOCATED, IN_TRANSFER, etc.)
|
|
36
|
+
* @param repos Repository map containing order and stock repositories
|
|
37
|
+
* @param sourceOrderId The order ID to link the deduction to (typically an existing allocated/transferred order)
|
|
38
|
+
* @param params Stock entry parameters (materialId, batchId, quantity, locationId?, loaderId?, unitId?)
|
|
39
|
+
*/
|
|
40
|
+
protected deduct(repos: Repositories, params: StockEntryParams): Promise<void>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { DataSource, EntityManager, EntityTarget, Repository } from 'typeorm';
|
|
2
|
+
import { BatchEntityClass } from '../models';
|
|
3
|
+
import { FindBatchInput } from '../typings/find-batch.input';
|
|
4
|
+
import { GetBatchInput, SplitBatchInput } from '../typings/get-batch.input';
|
|
5
|
+
import { BatchGroupEntityClass } from '../models/metadata/batch-group.entity';
|
|
6
|
+
export declare class BatchService<T extends BatchEntityClass = BatchEntityClass> {
|
|
7
|
+
private readonly dataSource;
|
|
8
|
+
readonly batchEntity: EntityTarget<T>;
|
|
9
|
+
readonly batchGroupEntity: EntityTarget<BatchGroupEntityClass>;
|
|
10
|
+
readonly batchRepository: Repository<T>;
|
|
11
|
+
readonly batchGroupRepository: Repository<BatchGroupEntityClass>;
|
|
12
|
+
constructor(dataSource: DataSource, batchEntity: EntityTarget<T>, batchGroupEntity: EntityTarget<BatchGroupEntityClass>);
|
|
13
|
+
/**
|
|
14
|
+
* Validates batch state transition based on hierarchy:
|
|
15
|
+
* inShipment = held = transferId = vendorId = customerId > saleId+saleSerialId > inspectionResult
|
|
16
|
+
*
|
|
17
|
+
* - Top tier (terminal): inShipment, held, transferId, vendorId, customerId → no state change allowed
|
|
18
|
+
* - Middle tier: saleId+saleSerialId → can only go UP to top tier
|
|
19
|
+
* - Bottom tier: inspectionResult → can go UP to middle or top tier, but cannot change inspectionResult
|
|
20
|
+
*/
|
|
21
|
+
private validateStateTransition;
|
|
22
|
+
getBatch({ manager, ...options }: GetBatchInput & {
|
|
23
|
+
manager?: EntityManager;
|
|
24
|
+
}): Promise<T>;
|
|
25
|
+
splitBatch({ manager, ...options }: {
|
|
26
|
+
id: string;
|
|
27
|
+
manager?: EntityManager;
|
|
28
|
+
} & SplitBatchInput): Promise<BatchEntityClass>;
|
|
29
|
+
findMany(options: FindBatchInput<T>): Promise<[BatchGroupEntityClass[], number]>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { __decorate, __param, __metadata } from 'tslib';
|
|
2
|
+
import { Injectable, Inject } from '@nestjs/common';
|
|
3
|
+
import { DataSource, IsNull } from 'typeorm';
|
|
4
|
+
import { BatchEntity, BatchEntityClass } from '../models/metadata/batch.entity.js';
|
|
5
|
+
import { BatchGroupEntity } from '../models/metadata/batch-group.entity.js';
|
|
6
|
+
import '../models/metadata/loader.entity.js';
|
|
7
|
+
import '../models/metadata/loader-type.entity.js';
|
|
8
|
+
import '../models/metadata/loader-unit.entity.js';
|
|
9
|
+
import '../models/metadata/location.entity.js';
|
|
10
|
+
import '../models/metadata/material.entity.js';
|
|
11
|
+
import '../models/metadata/material-unit.entity.js';
|
|
12
|
+
import '../models/metadata/sale-order.entity.js';
|
|
13
|
+
import '../models/metadata/stock.entity.js';
|
|
14
|
+
import '../models/metadata/unit.entity.js';
|
|
15
|
+
import '../models/extensions/receive-inventory-order/receive-inventory-order-item.entity.js';
|
|
16
|
+
import '../models/extensions/receive-inventory-order/receive-inventory-order.entity.js';
|
|
17
|
+
import '../models/extensions/receive-inventory-order/receive-inventory-order-change.entity.js';
|
|
18
|
+
import '../models/extensions/ship-inventory-order/ship-inventory-order-item.entity.js';
|
|
19
|
+
import '../models/extensions/ship-inventory-order/ship-inventory-order.entity.js';
|
|
20
|
+
import '../models/extensions/ship-inventory-order/ship-inventory-order-reference.entity.js';
|
|
21
|
+
import '../models/extensions/ship-inventory-order/ship-inventory-order-change.entity.js';
|
|
22
|
+
import '../models/extensions/transfer-order/transfer-order.entity.js';
|
|
23
|
+
import '../models/extensions/transfer-order/transfer-order-item.entity.js';
|
|
24
|
+
import '../models/extensions/transfer-order/transfer-order-change.entity.js';
|
|
25
|
+
import '../models/extensions/hold-inventory-order/hold-inventory-order.entity.js';
|
|
26
|
+
import '../models/extensions/hold-inventory-order/hold-inventory-order-item.entity.js';
|
|
27
|
+
import '../models/extensions/hold-inventory-order/hold-inventory-order-change.entity.js';
|
|
28
|
+
import '../models/extensions/allocate-inventory-order/allocate-inventory-order.entity.js';
|
|
29
|
+
import '../models/extensions/allocate-inventory-order/allocate-inventory-order-item.entity.js';
|
|
30
|
+
import '../models/extensions/allocate-inventory-order/allocate-inventory-order-change.entity.js';
|
|
31
|
+
import '../models/extensions/split-batch-order/split-batch-order.entity.js';
|
|
32
|
+
import '../models/extensions/split-batch-order/split-batch-order-item.entity.js';
|
|
33
|
+
import '../models/extensions/split-batch-order/split-batch-order-change.entity.js';
|
|
34
|
+
import '../models/extensions/merge-batch-order/merge-batch-order.entity.js';
|
|
35
|
+
import '../models/extensions/merge-batch-order/merge-batch-order-item.entity.js';
|
|
36
|
+
import '../models/extensions/merge-batch-order/merge-batch-order-change.entity.js';
|
|
37
|
+
import '../models/extensions/reclassify-inventory-order/reclassify-inventory-order.entity.js';
|
|
38
|
+
import '../models/extensions/reclassify-inventory-order/reclassify-inventory-order-item.entity.js';
|
|
39
|
+
import '../models/extensions/reclassify-inventory-order/reclassify-inventory-order-change.entity.js';
|
|
40
|
+
import '../models/extensions/transfer-vendor-order/transfer-vendor-order.entity.js';
|
|
41
|
+
import '../models/extensions/transfer-vendor-order/transfer-vendor-order-item.entity.js';
|
|
42
|
+
import '../models/extensions/transfer-vendor-order/transfer-vendor-order-change.entity.js';
|
|
43
|
+
import '../models/extensions/quality-inspection-order/quality-inspection-order.entity.js';
|
|
44
|
+
import '../models/extensions/quality-inspection-order/quality-inspection-order-item.entity.js';
|
|
45
|
+
import '../models/extensions/quality-inspection-order/quality-inspection-order-change.entity.js';
|
|
46
|
+
import '../models/extensions/transfer-customer-order/transfer-customer-order.entity.js';
|
|
47
|
+
import '../models/extensions/transfer-customer-order/transfer-customer-order-item.entity.js';
|
|
48
|
+
import '../models/extensions/transfer-customer-order/transfer-customer-order-change.entity.js';
|
|
49
|
+
import '../models/extensions/scrape-order/scrape-order.entity.js';
|
|
50
|
+
import '../models/extensions/scrape-order/scrape-order-item.entity.js';
|
|
51
|
+
import '../models/extensions/scrape-order/scrape-order-change.entity.js';
|
|
52
|
+
|
|
53
|
+
let BatchService = class BatchService {
|
|
54
|
+
dataSource;
|
|
55
|
+
batchEntity;
|
|
56
|
+
batchGroupEntity;
|
|
57
|
+
batchRepository;
|
|
58
|
+
batchGroupRepository;
|
|
59
|
+
constructor(dataSource, batchEntity, batchGroupEntity) {
|
|
60
|
+
this.dataSource = dataSource;
|
|
61
|
+
this.batchEntity = batchEntity;
|
|
62
|
+
this.batchGroupEntity = batchGroupEntity;
|
|
63
|
+
this.batchRepository = this.dataSource.getRepository(this.batchEntity);
|
|
64
|
+
this.batchGroupRepository =
|
|
65
|
+
this.dataSource.getRepository(this.batchGroupEntity);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Validates batch state transition based on hierarchy:
|
|
69
|
+
* inShipment = held = transferId = vendorId = customerId > saleId+saleSerialId > inspectionResult
|
|
70
|
+
*
|
|
71
|
+
* - Top tier (terminal): inShipment, held, transferId, vendorId, customerId → no state change allowed
|
|
72
|
+
* - Middle tier: saleId+saleSerialId → can only go UP to top tier
|
|
73
|
+
* - Bottom tier: inspectionResult → can go UP to middle or top tier, but cannot change inspectionResult
|
|
74
|
+
*/
|
|
75
|
+
validateStateTransition(batch, options) {
|
|
76
|
+
// Check if trying to clear/release a top-tier state
|
|
77
|
+
const isReleasingInShipment = batch.inShipment === true && options.inShipment === false;
|
|
78
|
+
const isReleasingHeld = batch.held === true && options.held === false;
|
|
79
|
+
const isReleasingTransfer = batch.transferId != null && options.transferId === null;
|
|
80
|
+
const isReleasingVendor = batch.vendorId != null && options.vendorId === null;
|
|
81
|
+
const isReleasingCustomer = batch.customerId != null && options.customerId === null;
|
|
82
|
+
const isReleasing = isReleasingInShipment ||
|
|
83
|
+
isReleasingHeld ||
|
|
84
|
+
isReleasingTransfer ||
|
|
85
|
+
isReleasingVendor ||
|
|
86
|
+
isReleasingCustomer;
|
|
87
|
+
// Determine current state tier
|
|
88
|
+
const isTopTier = batch.inShipment === true ||
|
|
89
|
+
batch.held === true ||
|
|
90
|
+
batch.transferId != null ||
|
|
91
|
+
batch.vendorId != null ||
|
|
92
|
+
batch.customerId != null;
|
|
93
|
+
const isMiddleTier = batch.saleId != null || batch.saleSerialId != null;
|
|
94
|
+
// What is being changed (explicitly set, not undefined)
|
|
95
|
+
const changingMiddleTier = options.saleId !== undefined || options.saleSerialId !== undefined;
|
|
96
|
+
const changingInspection = options.inspectionResult !== undefined;
|
|
97
|
+
// Rule 1: Top tier is terminal unless explicitly releasing that state
|
|
98
|
+
if (isTopTier && !isReleasing) {
|
|
99
|
+
const state = batch.inShipment
|
|
100
|
+
? 'in shipment'
|
|
101
|
+
: batch.held
|
|
102
|
+
? 'held'
|
|
103
|
+
: batch.transferId
|
|
104
|
+
? 'in transfer'
|
|
105
|
+
: batch.vendorId
|
|
106
|
+
? 'vendor inventory'
|
|
107
|
+
: 'customer inventory';
|
|
108
|
+
throw new Error(`Batch is ${state}, cannot transition to other states. Only release is allowed.`);
|
|
109
|
+
}
|
|
110
|
+
// Rule 2: Middle tier cannot change to same tier
|
|
111
|
+
if (isMiddleTier && changingMiddleTier) {
|
|
112
|
+
throw new Error('Cannot modify allocation (saleId/saleSerialId) for already allocated batch');
|
|
113
|
+
}
|
|
114
|
+
// Rule 3: Cannot change inspection result after it's set (unless releasing to higher tier)
|
|
115
|
+
if (batch.inspectionResult != null &&
|
|
116
|
+
!isMiddleTier &&
|
|
117
|
+
!isTopTier &&
|
|
118
|
+
changingInspection) {
|
|
119
|
+
throw new Error('Inspection result already set, cannot modify');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async getBatch({ manager = this.dataSource.manager, ...options }) {
|
|
123
|
+
const batchRepository = manager.getRepository(BatchEntityClass);
|
|
124
|
+
const batchGroupRepository = manager.getRepository(this.batchGroupEntity);
|
|
125
|
+
const unsplittedCondition = {
|
|
126
|
+
saleId: IsNull(),
|
|
127
|
+
saleSerialId: IsNull(),
|
|
128
|
+
customerId: IsNull(),
|
|
129
|
+
vendorId: IsNull(),
|
|
130
|
+
transferId: IsNull(),
|
|
131
|
+
inspectionResult: IsNull(),
|
|
132
|
+
held: false,
|
|
133
|
+
inShipment: false,
|
|
134
|
+
};
|
|
135
|
+
const existed = await batchRepository.findOneBy({
|
|
136
|
+
...unsplittedCondition,
|
|
137
|
+
key: options.key,
|
|
138
|
+
materialId: options.materialId,
|
|
139
|
+
});
|
|
140
|
+
if (existed)
|
|
141
|
+
return existed;
|
|
142
|
+
const batchGroup = await batchGroupRepository.save(batchGroupRepository.create({
|
|
143
|
+
key: options.key,
|
|
144
|
+
materialId: options.materialId,
|
|
145
|
+
}));
|
|
146
|
+
const batch = await batchRepository.save(batchRepository.create({
|
|
147
|
+
...options,
|
|
148
|
+
groupId: batchGroup.id,
|
|
149
|
+
}));
|
|
150
|
+
return batch;
|
|
151
|
+
}
|
|
152
|
+
async splitBatch({ manager = this.dataSource.manager, ...options }) {
|
|
153
|
+
const batchRepository = manager.getRepository(BatchEntityClass);
|
|
154
|
+
const batch = await batchRepository.findOneOrFail({
|
|
155
|
+
where: { id: options.id },
|
|
156
|
+
relations: ['batchGroup'],
|
|
157
|
+
});
|
|
158
|
+
// Validate state transition before proceeding
|
|
159
|
+
this.validateStateTransition(batch, options);
|
|
160
|
+
// Create merged batch object with new metrics
|
|
161
|
+
const mergedBatch = {
|
|
162
|
+
...batch,
|
|
163
|
+
...options,
|
|
164
|
+
groupId: batch.batchGroup.id,
|
|
165
|
+
};
|
|
166
|
+
// Build where condition dynamically to handle optional fields
|
|
167
|
+
const whereCondition = {
|
|
168
|
+
groupId: mergedBatch.groupId,
|
|
169
|
+
saleId: mergedBatch.saleId ?? null,
|
|
170
|
+
saleSerialId: mergedBatch.saleSerialId ?? null,
|
|
171
|
+
customerId: mergedBatch.customerId ?? null,
|
|
172
|
+
vendorId: mergedBatch.vendorId ?? null,
|
|
173
|
+
inspectionResult: mergedBatch.inspectionResult ?? null,
|
|
174
|
+
transferId: mergedBatch.transferId ?? null,
|
|
175
|
+
held: mergedBatch.held ?? false,
|
|
176
|
+
inShipment: mergedBatch.inShipment ?? false,
|
|
177
|
+
};
|
|
178
|
+
// Check if a batch with these exact metrics already exists in the same group
|
|
179
|
+
const existingBatch = await batchRepository.findOne({
|
|
180
|
+
where: whereCondition,
|
|
181
|
+
});
|
|
182
|
+
if (existingBatch) {
|
|
183
|
+
return existingBatch;
|
|
184
|
+
}
|
|
185
|
+
// If no matching batch exists, create a new one
|
|
186
|
+
return batchRepository.save(batchRepository.create({
|
|
187
|
+
...mergedBatch,
|
|
188
|
+
key: `${batch.batchGroup.key}_${Date.now().toString()}`,
|
|
189
|
+
id: undefined,
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
async findMany(options) {
|
|
193
|
+
const queryBuilder = this.batchGroupRepository.createQueryBuilder('batch');
|
|
194
|
+
if (options.wildcard) {
|
|
195
|
+
const { key, value } = options.wildcard;
|
|
196
|
+
queryBuilder.andWhere(`batch."${String(key)}" ILIKE :value`, {
|
|
197
|
+
value: `%${value}%`,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
if (options.materialId)
|
|
201
|
+
queryBuilder.andWhere('batch."materialId" = :materialId', {
|
|
202
|
+
materialId: options.materialId,
|
|
203
|
+
});
|
|
204
|
+
if (options.offset !== undefined && options.offset >= 0)
|
|
205
|
+
queryBuilder.skip(options.offset);
|
|
206
|
+
if (options.limit !== undefined && options.limit > 0)
|
|
207
|
+
queryBuilder.take(options.limit);
|
|
208
|
+
return queryBuilder.getManyAndCount();
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
BatchService = __decorate([
|
|
212
|
+
Injectable(),
|
|
213
|
+
__param(1, Inject(BatchEntity)),
|
|
214
|
+
__param(2, Inject(BatchGroupEntity)),
|
|
215
|
+
__metadata("design:paramtypes", [DataSource, Object, Object])
|
|
216
|
+
], BatchService);
|
|
217
|
+
|
|
218
|
+
export { BatchService };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { __decorate, __metadata } from 'tslib';
|
|
2
|
+
import { Injectable } from '@nestjs/common';
|
|
3
|
+
import { DataSource } from 'typeorm';
|
|
4
|
+
import { DateTime } from 'luxon';
|
|
5
|
+
|
|
6
|
+
let HelperService = class HelperService {
|
|
7
|
+
dataSource;
|
|
8
|
+
constructor(dataSource) {
|
|
9
|
+
this.dataSource = dataSource;
|
|
10
|
+
}
|
|
11
|
+
async getSeq(prefix, manager = this.dataSource.manager) {
|
|
12
|
+
const dateStr = DateTime.now().toFormat('yyyyMMdd');
|
|
13
|
+
const seqName = `${prefix}_${dateStr}`;
|
|
14
|
+
const quotedSeqName = `"${seqName}"`;
|
|
15
|
+
await this.dataSource.query(`CREATE SEQUENCE IF NOT EXISTS ${quotedSeqName} START 1`);
|
|
16
|
+
const [{ seq_num }] = await manager.query(`SELECT nextval($1) as seq_num`, [
|
|
17
|
+
`"${seqName}"`,
|
|
18
|
+
]);
|
|
19
|
+
const serialNumber = String(seq_num).padStart(4, '0');
|
|
20
|
+
return `${dateStr}${serialNumber}`;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
HelperService = __decorate([
|
|
24
|
+
Injectable(),
|
|
25
|
+
__metadata("design:paramtypes", [DataSource])
|
|
26
|
+
], HelperService);
|
|
27
|
+
|
|
28
|
+
export { HelperService };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { HoldInventoryOrderEntityClass, HoldInventoryOrderItemEntityClass, StockEntityClass } from '../models';
|
|
2
|
+
import { DataSource, EntityManager, EntityTarget } from 'typeorm';
|
|
3
|
+
import { HelperService } from './helper.service';
|
|
4
|
+
import { CreateHoldInventoryOrderInput, UpdateHoldInventoryOrderInput } from '../typings/create-hold-inventory-order.input';
|
|
5
|
+
import { FindHoldInventoryOrderInput } from '../typings/find-hold-inventory-order.input';
|
|
6
|
+
import { ReleaseInventoryOrderItemInput } from '../typings/release-inventory-order.input';
|
|
7
|
+
import { MaterialService } from './material.service';
|
|
8
|
+
import { BatchService } from './batch.service';
|
|
9
|
+
import { StockService } from './stock.service';
|
|
10
|
+
export declare class HoldInventoryOrderService<T extends HoldInventoryOrderEntityClass = HoldInventoryOrderEntityClass, K extends HoldInventoryOrderItemEntityClass = HoldInventoryOrderItemEntityClass> {
|
|
11
|
+
private readonly dataSource;
|
|
12
|
+
private readonly helperService;
|
|
13
|
+
private readonly materialService;
|
|
14
|
+
private readonly batchService;
|
|
15
|
+
private readonly stockService;
|
|
16
|
+
readonly holdInventoryOrderEntity: EntityTarget<T>;
|
|
17
|
+
readonly holdInventoryOrderItemEntity: EntityTarget<K>;
|
|
18
|
+
readonly stockEntity: EntityTarget<StockEntityClass>;
|
|
19
|
+
private readonly seqPrefix;
|
|
20
|
+
constructor(dataSource: DataSource, helperService: HelperService, materialService: MaterialService, batchService: BatchService, stockService: StockService, holdInventoryOrderEntity: EntityTarget<T>, holdInventoryOrderItemEntity: EntityTarget<K>, stockEntity: EntityTarget<StockEntityClass>);
|
|
21
|
+
private getRepositories;
|
|
22
|
+
private processHoldInventoryOrderItems;
|
|
23
|
+
createHoldInventoryOrder(options: CreateHoldInventoryOrderInput, manager?: EntityManager): Promise<T>;
|
|
24
|
+
updateHoldInventoryOrder({ id, manager, ...options }: UpdateHoldInventoryOrderInput & {
|
|
25
|
+
manager?: EntityManager;
|
|
26
|
+
}): Promise<T>;
|
|
27
|
+
findMany(options: FindHoldInventoryOrderInput): Promise<[T[], number]>;
|
|
28
|
+
release(options: ReleaseInventoryOrderItemInput | ReleaseInventoryOrderItemInput[], manager?: EntityManager): Promise<T>;
|
|
29
|
+
}
|