@things-factory/worksheet-base 4.3.185 → 4.3.187
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-server/constants/worksheet.js +3 -1
- package/dist-server/constants/worksheet.js.map +1 -1
- package/dist-server/controllers/ecommerce/ecommerce-controller.js +4 -1
- package/dist-server/controllers/ecommerce/ecommerce-controller.js.map +1 -1
- package/dist-server/controllers/ecommerce/sellercraft-controller.js +10 -1
- package/dist-server/controllers/ecommerce/sellercraft-controller.js.map +1 -1
- package/dist-server/controllers/index.js +1 -0
- package/dist-server/controllers/index.js.map +1 -1
- package/dist-server/controllers/outbound/picking-worksheet-controller.js +19 -4
- package/dist-server/controllers/outbound/picking-worksheet-controller.js.map +1 -1
- package/dist-server/controllers/pos/xilnex-controller.js +5 -1
- package/dist-server/controllers/pos/xilnex-controller.js.map +1 -1
- package/dist-server/controllers/replenishment/index.js +18 -0
- package/dist-server/controllers/replenishment/index.js.map +1 -0
- package/dist-server/controllers/replenishment/replenishment-worksheet-controller.js +455 -0
- package/dist-server/controllers/replenishment/replenishment-worksheet-controller.js.map +1 -0
- package/dist-server/controllers/worksheet-controller.js +32 -9
- package/dist-server/controllers/worksheet-controller.js.map +1 -1
- package/dist-server/entities/index.js +10 -2
- package/dist-server/entities/index.js.map +1 -1
- package/dist-server/entities/warehouse-bizplace-onhand-inventory.js +15 -1
- package/dist-server/entities/warehouse-bizplace-onhand-inventory.js.map +1 -1
- package/dist-server/entities/warehouse-inventory-assignment-ranking.js +37 -0
- package/dist-server/entities/warehouse-inventory-assignment-ranking.js.map +1 -0
- package/dist-server/entities/worksheet.js +13 -9
- package/dist-server/entities/worksheet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/cancel-replenishment.js +57 -0
- package/dist-server/graphql/resolvers/worksheet/cancel-replenishment.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/confirm-cancellation-release-order.js +23 -1
- package/dist-server/graphql/resolvers/worksheet/confirm-cancellation-release-order.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/generate-worksheet/generate-release-good-worksheet.js +7 -1
- package/dist-server/graphql/resolvers/worksheet/generate-worksheet/generate-release-good-worksheet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/generate-worksheet/generate-replenishement-worksheet.js +19 -0
- package/dist-server/graphql/resolvers/worksheet/generate-worksheet/generate-replenishement-worksheet.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/generate-worksheet/index.js +2 -1
- package/dist-server/graphql/resolvers/worksheet/generate-worksheet/index.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/index.js +5 -2
- package/dist-server/graphql/resolvers/worksheet/index.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js +37 -26
- package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/picking/complete-batch-picking.js +16 -2
- package/dist-server/graphql/resolvers/worksheet/picking/complete-batch-picking.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js +290 -264
- package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/picking/index.js +2 -1
- package/dist-server/graphql/resolvers/worksheet/picking/index.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/picking/replenishment-picking.js +12 -0
- package/dist-server/graphql/resolvers/worksheet/picking/replenishment-picking.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/picking-worksheet.js +142 -78
- package/dist-server/graphql/resolvers/worksheet/picking-worksheet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/putaway/complete-replenishment-putaway.js +16 -0
- package/dist-server/graphql/resolvers/worksheet/putaway/complete-replenishment-putaway.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/putaway/index.js +4 -1
- package/dist-server/graphql/resolvers/worksheet/putaway/index.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/putaway/replenishment-putaway.js +15 -0
- package/dist-server/graphql/resolvers/worksheet/putaway/replenishment-putaway.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/putaway/undo-replenishment-putaway.js +16 -0
- package/dist-server/graphql/resolvers/worksheet/putaway/undo-replenishment-putaway.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/putaway-replenishment-worksheet.js +81 -0
- package/dist-server/graphql/resolvers/worksheet/putaway-replenishment-worksheet.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/replenishment/activate-picking-replenishment.js +17 -0
- package/dist-server/graphql/resolvers/worksheet/replenishment/activate-picking-replenishment.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/replenishment/index.js +6 -0
- package/dist-server/graphql/resolvers/worksheet/replenishment/index.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/worksheet.js +1 -0
- package/dist-server/graphql/resolvers/worksheet/worksheet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/worksheets.js +28 -2
- package/dist-server/graphql/resolvers/worksheet/worksheets.js.map +1 -1
- package/dist-server/graphql/types/worksheet/index.js +42 -1
- package/dist-server/graphql/types/worksheet/index.js.map +1 -1
- package/dist-server/graphql/types/worksheet/replenish-inventory-patch.js +11 -0
- package/dist-server/graphql/types/worksheet/replenish-inventory-patch.js.map +1 -0
- package/dist-server/graphql/types/worksheet/worksheet-info.js +1 -0
- package/dist-server/graphql/types/worksheet/worksheet-info.js.map +1 -1
- package/dist-server/graphql/types/worksheet/worksheet.js +1 -0
- package/dist-server/graphql/types/worksheet/worksheet.js.map +1 -1
- package/dist-server/index.js +1 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/utils/index.js +1 -0
- package/dist-server/utils/index.js.map +1 -1
- package/dist-server/utils/inventory-util.js +2 -0
- package/dist-server/utils/inventory-util.js.map +1 -1
- package/dist-server/utils/lmd-util.js +76 -0
- package/dist-server/utils/lmd-util.js.map +1 -0
- package/dist-server/utils/worksheet-no-generator.js +21 -1
- package/dist-server/utils/worksheet-no-generator.js.map +1 -1
- package/dist-server/utils/worksheet-util.js +3 -0
- package/dist-server/utils/worksheet-util.js.map +1 -1
- package/package.json +13 -13
- package/server/constants/worksheet.ts +3 -1
- package/server/controllers/ecommerce/ecommerce-controller.ts +4 -1
- package/server/controllers/ecommerce/sellercraft-controller.ts +15 -1
- package/server/controllers/index.ts +1 -1
- package/server/controllers/outbound/picking-worksheet-controller.ts +30 -10
- package/server/controllers/pos/xilnex-controller.ts +6 -1
- package/server/controllers/replenishment/index.ts +1 -0
- package/server/controllers/replenishment/replenishment-worksheet-controller.ts +632 -0
- package/server/controllers/worksheet-controller.ts +47 -13
- package/server/entities/index.ts +15 -2
- package/server/entities/warehouse-bizplace-onhand-inventory.ts +13 -1
- package/server/entities/warehouse-inventory-assignment-ranking.ts +19 -0
- package/server/entities/worksheet.ts +5 -1
- package/server/graphql/resolvers/worksheet/cancel-replenishment.ts +69 -0
- package/server/graphql/resolvers/worksheet/confirm-cancellation-release-order.ts +22 -1
- package/server/graphql/resolvers/worksheet/generate-worksheet/generate-release-good-worksheet.ts +6 -1
- package/server/graphql/resolvers/worksheet/generate-worksheet/generate-replenishement-worksheet.ts +30 -0
- package/server/graphql/resolvers/worksheet/generate-worksheet/index.ts +3 -1
- package/server/graphql/resolvers/worksheet/index.ts +8 -2
- package/server/graphql/resolvers/worksheet/inventories-by-pallet.ts +81 -41
- package/server/graphql/resolvers/worksheet/picking/complete-batch-picking.ts +16 -2
- package/server/graphql/resolvers/worksheet/picking/complete-picking.ts +347 -301
- package/server/graphql/resolvers/worksheet/picking/index.ts +3 -1
- package/server/graphql/resolvers/worksheet/picking/replenishment-picking.ts +27 -0
- package/server/graphql/resolvers/worksheet/picking-worksheet.ts +177 -95
- package/server/graphql/resolvers/worksheet/putaway/complete-replenishment-putaway.ts +25 -0
- package/server/graphql/resolvers/worksheet/putaway/index.ts +7 -1
- package/server/graphql/resolvers/worksheet/putaway/replenishment-putaway.ts +23 -0
- package/server/graphql/resolvers/worksheet/putaway/undo-replenishment-putaway.ts +22 -0
- package/server/graphql/resolvers/worksheet/putaway-replenishment-worksheet.ts +95 -0
- package/server/graphql/resolvers/worksheet/replenishment/activate-picking-replenishment.ts +26 -0
- package/server/graphql/resolvers/worksheet/replenishment/index.ts +5 -0
- package/server/graphql/resolvers/worksheet/worksheet.ts +1 -0
- package/server/graphql/resolvers/worksheet/worksheets.ts +38 -3
- package/server/graphql/types/worksheet/index.ts +42 -1
- package/server/graphql/types/worksheet/replenish-inventory-patch.ts +8 -0
- package/server/graphql/types/worksheet/worksheet-info.ts +1 -0
- package/server/graphql/types/worksheet/worksheet.ts +1 -0
- package/server/index.ts +1 -0
- package/server/utils/index.ts +1 -0
- package/server/utils/inventory-util.ts +3 -0
- package/server/utils/lmd-util.ts +86 -0
- package/server/utils/worksheet-no-generator.ts +29 -1
- package/server/utils/worksheet-util.ts +4 -2
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
import { In, Not, getConnection, EntityManager } from 'typeorm'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ORDER_INVENTORY_STATUS,
|
|
5
|
+
ORDER_STATUS,
|
|
6
|
+
OrderInventory,
|
|
7
|
+
Replenishment,
|
|
8
|
+
ORDER_TYPES,
|
|
9
|
+
ORDER_PRODUCT_STATUS
|
|
10
|
+
} from '@things-factory/sales-base'
|
|
11
|
+
|
|
12
|
+
import { generateId } from '@things-factory/id-rule-base'
|
|
13
|
+
import { DateGenerator } from '../../utils'
|
|
14
|
+
import { WORKSHEET_TYPE, WORKSHEET_STATUS, RULE_TYPE } from '../../constants'
|
|
15
|
+
import { Worksheet, WorksheetDetail } from '../../entities'
|
|
16
|
+
import { WorksheetController } from '../worksheet-controller'
|
|
17
|
+
import { Product, ProductBarcode, ProductDetail } from '@things-factory/product-base'
|
|
18
|
+
import {
|
|
19
|
+
Inventory,
|
|
20
|
+
LOCATION_TYPE,
|
|
21
|
+
InventoryItem,
|
|
22
|
+
INVENTORY_STATUS,
|
|
23
|
+
InventoryNoGenerator,
|
|
24
|
+
INVENTORY_ITEM_SOURCE,
|
|
25
|
+
generateInventoryHistory,
|
|
26
|
+
INVENTORY_TRANSACTION_TYPE,
|
|
27
|
+
Warehouse,
|
|
28
|
+
Location,
|
|
29
|
+
InventoryHistory
|
|
30
|
+
} from '@things-factory/warehouse-base'
|
|
31
|
+
|
|
32
|
+
export class ReplenishmentWorksheetController extends WorksheetController {
|
|
33
|
+
async generateReplenishmentWorksheet(replenishmentNo: string): Promise<Worksheet> {
|
|
34
|
+
let replenishment: Replenishment = await this.findRefOrder(
|
|
35
|
+
Replenishment,
|
|
36
|
+
{
|
|
37
|
+
domain: this.domain,
|
|
38
|
+
name: replenishmentNo,
|
|
39
|
+
status: ORDER_STATUS.PENDING_WORKSHEET
|
|
40
|
+
},
|
|
41
|
+
['orderInventories', 'orderInventories.inventory', 'orderInventories.bizplace']
|
|
42
|
+
)
|
|
43
|
+
const orderInventories: OrderInventory[] = replenishment.orderInventories
|
|
44
|
+
|
|
45
|
+
let worksheet: Worksheet = await this.createWorksheet(replenishment, WORKSHEET_TYPE.PICKING_REPLENISHMENT)
|
|
46
|
+
|
|
47
|
+
if (orderInventories.every((oi: OrderInventory) => oi.inventory?.id)) {
|
|
48
|
+
worksheet.worksheetDetails = await this.createWorksheetDetails(
|
|
49
|
+
worksheet,
|
|
50
|
+
WORKSHEET_TYPE.PICKING_REPLENISHMENT,
|
|
51
|
+
orderInventories
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
await this.trxMgr
|
|
56
|
+
.getRepository(OrderInventory)
|
|
57
|
+
.update(
|
|
58
|
+
{ id: In(orderInventories.map(oi => oi.id)) },
|
|
59
|
+
{ status: ORDER_INVENTORY_STATUS.READY_TO_PICK, updater: this.user }
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
await this.trxMgr
|
|
63
|
+
.getRepository(Replenishment)
|
|
64
|
+
.update({ id: replenishment.id }, { status: ORDER_STATUS.READY_TO_PICK, updater: this.user })
|
|
65
|
+
|
|
66
|
+
return worksheet
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async activatePickingReplenishment(worksheetNo: string): Promise<Worksheet> {
|
|
70
|
+
let worksheet: Worksheet = await this.findActivatableWorksheet(worksheetNo, WORKSHEET_TYPE.PICKING_REPLENISHMENT, [
|
|
71
|
+
'replenishment',
|
|
72
|
+
'worksheetDetails',
|
|
73
|
+
'worksheetDetails.targetInventory'
|
|
74
|
+
])
|
|
75
|
+
let updater = this.user
|
|
76
|
+
const worksheetDetails: WorksheetDetail[] = worksheet.worksheetDetails.filter(x => x.status == 'DEACTIVATED')
|
|
77
|
+
const targetInventories: OrderInventory[] = worksheetDetails.map(wds => wds.targetInventory)
|
|
78
|
+
|
|
79
|
+
await this.trxMgr
|
|
80
|
+
.getRepository(OrderInventory)
|
|
81
|
+
.update({ id: In(targetInventories.map(itm => itm.id)) }, { status: ORDER_INVENTORY_STATUS.PICKING, updater })
|
|
82
|
+
|
|
83
|
+
let replenishment: Replenishment = worksheet.replenishment
|
|
84
|
+
await this.trxMgr
|
|
85
|
+
.getRepository(Replenishment)
|
|
86
|
+
.update({ id: replenishment.id }, { status: ORDER_STATUS.PICKING, updater })
|
|
87
|
+
|
|
88
|
+
worksheet = await this.activateWorksheet(worksheet, worksheetDetails, [])
|
|
89
|
+
|
|
90
|
+
return worksheet
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async replenishmentPicking(
|
|
94
|
+
worksheetDetailName: string,
|
|
95
|
+
worksheetType: string,
|
|
96
|
+
productBarcode: string,
|
|
97
|
+
cartonId: string,
|
|
98
|
+
binLocation?: string,
|
|
99
|
+
serialNumber?: string,
|
|
100
|
+
pickedQty: number = 1
|
|
101
|
+
): Promise<WorksheetDetail> {
|
|
102
|
+
try {
|
|
103
|
+
//find existing worksheet detail
|
|
104
|
+
let worksheetDetail: WorksheetDetail = await this.trxMgr
|
|
105
|
+
.getRepository(WorksheetDetail)
|
|
106
|
+
.createQueryBuilder('wd')
|
|
107
|
+
.innerJoinAndSelect('wd.worksheet', 'ws')
|
|
108
|
+
.innerJoinAndSelect('wd.targetInventory', 'oi')
|
|
109
|
+
.innerJoinAndSelect('oi.replenishment', 'rp')
|
|
110
|
+
.innerJoinAndSelect('oi.inventory', 'inv')
|
|
111
|
+
.innerJoinAndSelect('oi.product', 'prd')
|
|
112
|
+
.innerJoinAndSelect('oi.productDetail', 'pd')
|
|
113
|
+
.innerJoinAndSelect('pd.productBarcodes', 'pb')
|
|
114
|
+
.where('wd.name = :name', { name: worksheetDetailName })
|
|
115
|
+
.andWhere('wd.domain_id = :domainId', { domainId: this.domain.id })
|
|
116
|
+
.andWhere('wd.type = :type', { type: worksheetType })
|
|
117
|
+
.andWhere('wd.status = :status', { status: WORKSHEET_STATUS.EXECUTING })
|
|
118
|
+
.andWhere('inv.carton_id = :cartonId', { cartonId: cartonId })
|
|
119
|
+
.getOne()
|
|
120
|
+
|
|
121
|
+
//validation to check matching worksheet detail based on name
|
|
122
|
+
if (!worksheetDetail) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(worksheetDetailName))
|
|
123
|
+
|
|
124
|
+
const replenishment: Replenishment = worksheetDetail.targetInventory.replenishment
|
|
125
|
+
let targetInventory: OrderInventory = worksheetDetail.targetInventory
|
|
126
|
+
const product: Product = targetInventory.product
|
|
127
|
+
const productDetail: ProductDetail = targetInventory.productDetail
|
|
128
|
+
const productBarcodes: [ProductBarcode] = productDetail.productBarcodes
|
|
129
|
+
let inventory: Inventory = targetInventory.inventory
|
|
130
|
+
let pickedUomValue = pickedQty * productDetail.uomValue
|
|
131
|
+
let matchingProduct
|
|
132
|
+
|
|
133
|
+
//validation to prevent duplicated picking
|
|
134
|
+
if (targetInventory?.status != ORDER_INVENTORY_STATUS.PICKING)
|
|
135
|
+
throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `is done`))
|
|
136
|
+
|
|
137
|
+
if (!productBarcodes.find(itm => itm.gtin == productBarcode) && product?.isRequireSerialNumberScanningOutbound) {
|
|
138
|
+
throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
matchingProduct = await this.getDirectQty(
|
|
142
|
+
{
|
|
143
|
+
...productDetail,
|
|
144
|
+
product: targetInventory?.product
|
|
145
|
+
},
|
|
146
|
+
productBarcode,
|
|
147
|
+
pickedQty
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
//validate matching product details based on scanned barcode
|
|
151
|
+
if (!matchingProduct) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
|
|
152
|
+
|
|
153
|
+
pickedQty = matchingProduct.qty
|
|
154
|
+
pickedUomValue = matchingProduct.uomValue
|
|
155
|
+
|
|
156
|
+
//validation to prevent over release
|
|
157
|
+
if (
|
|
158
|
+
!worksheetDetail?.targetInventory ||
|
|
159
|
+
worksheetDetail?.targetInventory.inventory.qty < 1 ||
|
|
160
|
+
pickedQty + (worksheetDetail.targetInventory?.pickedQty || 0) > worksheetDetail.targetInventory.releaseQty
|
|
161
|
+
)
|
|
162
|
+
throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `over release`))
|
|
163
|
+
|
|
164
|
+
targetInventory = await this.checkAndSetBinPicking(targetInventory, binLocation)
|
|
165
|
+
|
|
166
|
+
// for required outbound serial number scanning
|
|
167
|
+
if (product?.isRequireSerialNumberScanningOutbound) {
|
|
168
|
+
if (!serialNumber || serialNumber == '') {
|
|
169
|
+
throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `require serial number`))
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
let totalInventoryItems = await this.trxMgr.getRepository(InventoryItem).count({
|
|
173
|
+
where: {
|
|
174
|
+
inventory,
|
|
175
|
+
status: Not(In([INVENTORY_STATUS.TERMINATED, INVENTORY_STATUS.PICKED]))
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
let foundSerialNumber: InventoryItem = await this.trxMgr
|
|
180
|
+
.getRepository(InventoryItem)
|
|
181
|
+
.findOne({ where: { domain: this.domain, serialNumber: serialNumber, product } })
|
|
182
|
+
|
|
183
|
+
if (foundSerialNumber) {
|
|
184
|
+
if (foundSerialNumber.inventoryId !== inventory.id) {
|
|
185
|
+
throw new Error('Serial Number scanned is in another inventory')
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (foundSerialNumber.outboundOrderId) {
|
|
189
|
+
let replenishment: Replenishment = await this.trxMgr
|
|
190
|
+
.getRepository(Replenishment)
|
|
191
|
+
.findOne({ where: { id: foundSerialNumber.outboundOrderId } })
|
|
192
|
+
throw new Error(`Inventory Item is already picked in ${replenishment.name}`)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
foundSerialNumber.status = INVENTORY_STATUS.PICKING
|
|
196
|
+
foundSerialNumber.updater = this.user
|
|
197
|
+
foundSerialNumber.outboundOrderId = replenishment.id
|
|
198
|
+
|
|
199
|
+
await this.trxMgr.getRepository(InventoryItem).save(foundSerialNumber)
|
|
200
|
+
} else {
|
|
201
|
+
if (totalInventoryItems >= inventory.qty) {
|
|
202
|
+
throw new Error('Insufficient inventory quantity to scan new serial number')
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
let inventoryItem: InventoryItem = new InventoryItem()
|
|
206
|
+
inventoryItem.name = InventoryNoGenerator.inventoryItemName()
|
|
207
|
+
inventoryItem.serialNumber = serialNumber
|
|
208
|
+
inventoryItem.status = INVENTORY_STATUS.PICKING
|
|
209
|
+
inventoryItem.outboundOrderId = replenishment.id
|
|
210
|
+
inventoryItem.source = INVENTORY_ITEM_SOURCE.OUTBOUND
|
|
211
|
+
inventoryItem.product = product
|
|
212
|
+
inventoryItem.productDetail = productDetail
|
|
213
|
+
inventoryItem.inventory = inventory
|
|
214
|
+
inventoryItem.domain = this.domain
|
|
215
|
+
|
|
216
|
+
await this.trxMgr.getRepository(InventoryItem).save(inventoryItem)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const releaseQty: number = targetInventory.releaseQty
|
|
221
|
+
|
|
222
|
+
targetInventory.pickedQty = (targetInventory?.pickedQty || 0) + pickedQty
|
|
223
|
+
|
|
224
|
+
let updateOiObj = {
|
|
225
|
+
pickedQty: () => `"picked_qty" + ${pickedQty}`,
|
|
226
|
+
updatedAt: new Date(),
|
|
227
|
+
updater: this.user,
|
|
228
|
+
pickedBy: this.user.name,
|
|
229
|
+
pickedByUser: this.user,
|
|
230
|
+
pickedAt: new Date()
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (targetInventory.pickedQty == releaseQty) {
|
|
234
|
+
updateOiObj['status'] = ORDER_INVENTORY_STATUS.PICKED
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (targetInventory.binLocation) {
|
|
238
|
+
updateOiObj['binLocation'] = targetInventory.binLocation
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
await this.trxMgr
|
|
242
|
+
.getRepository(OrderInventory)
|
|
243
|
+
.createQueryBuilder()
|
|
244
|
+
.update(OrderInventory)
|
|
245
|
+
.set(updateOiObj)
|
|
246
|
+
.where({ id: targetInventory.id })
|
|
247
|
+
.andWhere(`picked_qty + :pickedQty <= release_qty`, { pickedQty })
|
|
248
|
+
.execute()
|
|
249
|
+
|
|
250
|
+
if (targetInventory.pickedQty == releaseQty) {
|
|
251
|
+
//update worksheet details only when line item picking complete
|
|
252
|
+
await this.trxMgr
|
|
253
|
+
.getRepository(WorksheetDetail)
|
|
254
|
+
.createQueryBuilder()
|
|
255
|
+
.update(WorksheetDetail)
|
|
256
|
+
.set({
|
|
257
|
+
status: WORKSHEET_STATUS.DONE,
|
|
258
|
+
updater: this.user,
|
|
259
|
+
updatedAt: new Date()
|
|
260
|
+
})
|
|
261
|
+
.where('id = :id', { id: worksheetDetail.id })
|
|
262
|
+
.execute()
|
|
263
|
+
|
|
264
|
+
getConnection().transaction(async (tx: EntityManager) => {
|
|
265
|
+
let releaseUomValue = Math.round((pickedUomValue / pickedQty) * releaseQty * 100) / 100
|
|
266
|
+
|
|
267
|
+
let updateInvObj = {
|
|
268
|
+
qty: () => `"qty" - ${releaseQty}`,
|
|
269
|
+
uomValue: () => `"uom_value" - ${releaseUomValue}`,
|
|
270
|
+
updater: this.user,
|
|
271
|
+
updatedAt: new Date()
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
let remainingQty = await tx
|
|
275
|
+
.getRepository(Inventory)
|
|
276
|
+
.createQueryBuilder()
|
|
277
|
+
.update(Inventory)
|
|
278
|
+
.set(updateInvObj)
|
|
279
|
+
.where('id = :id', { id: targetInventory.inventory.id })
|
|
280
|
+
.returning(['qty'])
|
|
281
|
+
.execute()
|
|
282
|
+
.then(dt => {
|
|
283
|
+
return dt.raw[0].qty
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
await generateInventoryHistory(
|
|
287
|
+
inventory,
|
|
288
|
+
replenishment,
|
|
289
|
+
INVENTORY_TRANSACTION_TYPE.RELOCATE,
|
|
290
|
+
-releaseQty,
|
|
291
|
+
-releaseUomValue,
|
|
292
|
+
this.user,
|
|
293
|
+
tx
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
let inventoryItems: InventoryItem = await tx
|
|
297
|
+
.getRepository(InventoryItem)
|
|
298
|
+
.find({ where: { outboundOrderId: replenishment.id } })
|
|
299
|
+
|
|
300
|
+
if (inventoryItems.length > 0) {
|
|
301
|
+
inventoryItems.forEach((itm: InventoryItem) => {
|
|
302
|
+
itm.status = INVENTORY_STATUS.PICKED
|
|
303
|
+
itm.updater = this.user
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
await tx.getRepository(InventoryItem).save(inventoryItems)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (remainingQty === 0) {
|
|
310
|
+
await tx
|
|
311
|
+
.getRepository(Inventory)
|
|
312
|
+
.createQueryBuilder()
|
|
313
|
+
.update(Inventory)
|
|
314
|
+
.set({ status: INVENTORY_STATUS.TERMINATED })
|
|
315
|
+
.where('id = :id', { id: targetInventory.inventory.id })
|
|
316
|
+
.execute()
|
|
317
|
+
}
|
|
318
|
+
})
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// return worksheet details
|
|
322
|
+
worksheetDetail = await this.trxMgr
|
|
323
|
+
.getRepository(WorksheetDetail)
|
|
324
|
+
.createQueryBuilder('wd')
|
|
325
|
+
.innerJoin('wd.targetInventory', 'oi')
|
|
326
|
+
.innerJoinAndSelect('oi.replenishment', 'rg')
|
|
327
|
+
.where('wd.id = :id', { id: worksheetDetail.id })
|
|
328
|
+
.getOne()
|
|
329
|
+
|
|
330
|
+
return worksheetDetail
|
|
331
|
+
} catch (error) {
|
|
332
|
+
throw error
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
private async checkAndSetBinPicking(orderInventory, binLocation) {
|
|
337
|
+
// bin picking validation
|
|
338
|
+
if (binLocation) {
|
|
339
|
+
const foundBinLocation: Location = await this.trxMgr.getRepository(Location).findOne({
|
|
340
|
+
where: { domain: this.domain, name: binLocation, type: LOCATION_TYPE.BIN }
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
if (!foundBinLocation)
|
|
344
|
+
throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `invalid bin location id`))
|
|
345
|
+
|
|
346
|
+
orderInventory.binLocation = foundBinLocation
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return orderInventory
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
async completeReplenishmentPicking(replenishment: Replenishment, worksheet: Worksheet): Promise<any> {
|
|
353
|
+
await this.checkRecordValidity(worksheet, { status: WORKSHEET_STATUS.EXECUTING })
|
|
354
|
+
|
|
355
|
+
let inventoryItems: InventoryItem = await this.trxMgr
|
|
356
|
+
.getRepository(InventoryItem)
|
|
357
|
+
.find({ where: { outboundOrderId: replenishment.id } })
|
|
358
|
+
|
|
359
|
+
if (inventoryItems.length > 0) {
|
|
360
|
+
inventoryItems.forEach((itm: InventoryItem) => {
|
|
361
|
+
itm.status = INVENTORY_STATUS.RELOCATE
|
|
362
|
+
itm.updater = this.user
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
await this.trxMgr.getRepository(InventoryItem).save(inventoryItems)
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
let orderStatus: string = ORDER_STATUS.PUTTING_AWAY
|
|
369
|
+
|
|
370
|
+
return await this.completeWorksheet(worksheet, orderStatus)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
async generatePutawayReplenishmentWorksheet(replenishmentNo: string): Promise<Worksheet> {
|
|
374
|
+
let replenishment: Replenishment = await this.findRefOrder(
|
|
375
|
+
Replenishment,
|
|
376
|
+
{
|
|
377
|
+
domain: this.domain,
|
|
378
|
+
name: replenishmentNo
|
|
379
|
+
},
|
|
380
|
+
['orderInventories', 'orderInventories.inventory']
|
|
381
|
+
)
|
|
382
|
+
let orderInventories: OrderInventory[] = replenishment.orderInventories
|
|
383
|
+
|
|
384
|
+
const existingPutawayReplenishmentWorksheet: Worksheet = await this.trxMgr.getRepository(Worksheet).findOne({
|
|
385
|
+
where: {
|
|
386
|
+
domain: this.domain,
|
|
387
|
+
replenishment,
|
|
388
|
+
type: WORKSHEET_TYPE.PUTAWAY_REPLENISHMENT
|
|
389
|
+
}
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
if (existingPutawayReplenishmentWorksheet)
|
|
393
|
+
throw new Error('There is existing putaway replenishment worksheet that has been generated')
|
|
394
|
+
let worksheet: Worksheet = await this.createWorksheet(replenishment, WORKSHEET_TYPE.PUTAWAY_REPLENISHMENT)
|
|
395
|
+
|
|
396
|
+
if (orderInventories.every((oi: OrderInventory) => oi.inventory?.id)) {
|
|
397
|
+
worksheet.worksheetDetails = await this.createWorksheetDetails(
|
|
398
|
+
worksheet,
|
|
399
|
+
WORKSHEET_TYPE.PUTAWAY_REPLENISHMENT,
|
|
400
|
+
orderInventories
|
|
401
|
+
)
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
orderInventories.forEach((oi: OrderInventory) => {
|
|
405
|
+
oi.status = ORDER_INVENTORY_STATUS.PUTTING_AWAY
|
|
406
|
+
oi.updater = this.user
|
|
407
|
+
})
|
|
408
|
+
await this.updateOrderTargets(orderInventories)
|
|
409
|
+
|
|
410
|
+
return worksheet
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
async replenishmentPutaway(worksheetDetailName: [string], cartonId: string, locationName: string): Promise<void> {
|
|
414
|
+
const worksheetDetails: WorksheetDetail[] = await this.findExecutableWorksheetDetailByNames(
|
|
415
|
+
worksheetDetailName,
|
|
416
|
+
WORKSHEET_TYPE.PUTAWAY_REPLENISHMENT,
|
|
417
|
+
[
|
|
418
|
+
'worksheet',
|
|
419
|
+
'worksheet.replenishment',
|
|
420
|
+
'targetInventory',
|
|
421
|
+
'targetInventory.inventory',
|
|
422
|
+
'targetInventory.inventory.bizplace',
|
|
423
|
+
'targetInventory.inventory.product',
|
|
424
|
+
'targetInventory.inventory.productDetail'
|
|
425
|
+
]
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
for (var i = 0; i < worksheetDetails.length; i++) {
|
|
429
|
+
const worksheetDetail = worksheetDetails[i]
|
|
430
|
+
const worksheet: Worksheet = worksheetDetail.worksheet
|
|
431
|
+
const replenishment: Replenishment = worksheet.replenishment
|
|
432
|
+
let targetInventory: OrderInventory = worksheetDetail.targetInventory
|
|
433
|
+
let inventory: Inventory = targetInventory.inventory
|
|
434
|
+
|
|
435
|
+
if (inventory.cartonId !== cartonId) {
|
|
436
|
+
throw new Error(this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE('cartonId', cartonId, inventory.cartonId))
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const location: Location = await this.trxMgr.getRepository(Location).findOne({
|
|
440
|
+
where: {
|
|
441
|
+
domain: this.domain,
|
|
442
|
+
name: locationName,
|
|
443
|
+
type: In([
|
|
444
|
+
LOCATION_TYPE.SHELF,
|
|
445
|
+
LOCATION_TYPE.BUFFER,
|
|
446
|
+
LOCATION_TYPE.FLOOR,
|
|
447
|
+
LOCATION_TYPE.BIN,
|
|
448
|
+
LOCATION_TYPE.QUARANTINE,
|
|
449
|
+
LOCATION_TYPE.RESERVE
|
|
450
|
+
])
|
|
451
|
+
},
|
|
452
|
+
relations: ['warehouse']
|
|
453
|
+
})
|
|
454
|
+
|
|
455
|
+
if (!location) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(locationName))
|
|
456
|
+
const warehouse: Warehouse = location.warehouse
|
|
457
|
+
const zone: string = location.zone
|
|
458
|
+
|
|
459
|
+
let updateInvObj = {
|
|
460
|
+
transferQty: () => `"transfer_qty" - ${targetInventory.releaseQty}`,
|
|
461
|
+
transferUomValue: () => `"transfer_uom_value" - ${targetInventory.releaseUomValue}`,
|
|
462
|
+
updater: this.user,
|
|
463
|
+
updatedAt: new Date()
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
await this.trxMgr
|
|
467
|
+
.getRepository(Inventory)
|
|
468
|
+
.createQueryBuilder()
|
|
469
|
+
.update(Inventory)
|
|
470
|
+
.set(updateInvObj)
|
|
471
|
+
.where('id = :id', { id: targetInventory.inventory.id })
|
|
472
|
+
.execute()
|
|
473
|
+
|
|
474
|
+
let newInventory = {
|
|
475
|
+
...inventory,
|
|
476
|
+
palletId: await generateId({
|
|
477
|
+
domain: this.domain,
|
|
478
|
+
type: RULE_TYPE.LOT_NUMBER_ID,
|
|
479
|
+
seed: { date: DateGenerator.generateDate() }
|
|
480
|
+
}),
|
|
481
|
+
location: location,
|
|
482
|
+
status: INVENTORY_STATUS.STORED,
|
|
483
|
+
warehouse: warehouse,
|
|
484
|
+
zone: zone,
|
|
485
|
+
creator: this.user,
|
|
486
|
+
updater: this.user
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
delete newInventory.id
|
|
490
|
+
delete newInventory.updatedAt
|
|
491
|
+
delete newInventory.created_at
|
|
492
|
+
delete newInventory.adjustmentCode
|
|
493
|
+
delete newInventory.adjustmentNote
|
|
494
|
+
|
|
495
|
+
newInventory.cartonId = cartonId
|
|
496
|
+
newInventory.qty = targetInventory.releaseQty
|
|
497
|
+
newInventory.lockedQty = 0
|
|
498
|
+
newInventory.transferQty = 0
|
|
499
|
+
newInventory.uomValue = targetInventory.releaseUomValue
|
|
500
|
+
newInventory.lockedUomValue = 0
|
|
501
|
+
newInventory.transferUomValue = 0
|
|
502
|
+
newInventory.refOrderId = replenishment.id
|
|
503
|
+
|
|
504
|
+
await this.trxMgr.getRepository(Inventory).save(newInventory)
|
|
505
|
+
|
|
506
|
+
let inventoryItems: InventoryItem = await this.trxMgr
|
|
507
|
+
.getRepository(InventoryItem)
|
|
508
|
+
.find({ where: { outboundOrderId: replenishment.id, inventory, status: INVENTORY_STATUS.RELOCATE } })
|
|
509
|
+
|
|
510
|
+
if (inventoryItems.length > 0) {
|
|
511
|
+
inventoryItems.forEach((itm: InventoryItem) => {
|
|
512
|
+
itm.status = INVENTORY_STATUS.STORED
|
|
513
|
+
itm.source = INVENTORY_ITEM_SOURCE.RELOCATE
|
|
514
|
+
itm.updater = this.user
|
|
515
|
+
itm.inventory = newInventory
|
|
516
|
+
})
|
|
517
|
+
|
|
518
|
+
await this.trxMgr.getRepository(InventoryItem).save(inventoryItems)
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
await this.transactionInventory(
|
|
522
|
+
newInventory,
|
|
523
|
+
replenishment,
|
|
524
|
+
targetInventory.releaseQty,
|
|
525
|
+
targetInventory.releaseUomValue,
|
|
526
|
+
INVENTORY_TRANSACTION_TYPE.RELOCATE
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
targetInventory.status = ORDER_INVENTORY_STATUS.TERMINATED
|
|
530
|
+
targetInventory.updater = this.user
|
|
531
|
+
await this.updateOrderTargets([targetInventory])
|
|
532
|
+
|
|
533
|
+
worksheetDetail.status = WORKSHEET_STATUS.DONE
|
|
534
|
+
worksheetDetail.updater = this.user
|
|
535
|
+
await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
async undoReplenishmentPutaway(worksheetDetailName: [string], cartonId: string): Promise<void> {
|
|
540
|
+
let worksheetDetails: WorksheetDetail[] = await this.findWorksheetDetailByNames(worksheetDetailName, [
|
|
541
|
+
'worksheet',
|
|
542
|
+
'worksheet.replenishment',
|
|
543
|
+
'targetInventory',
|
|
544
|
+
'targetInventory.inventory',
|
|
545
|
+
'fromLocation'
|
|
546
|
+
])
|
|
547
|
+
|
|
548
|
+
for (var i = 0; i < worksheetDetails?.length; i++) {
|
|
549
|
+
const worksheetDetail = worksheetDetails[i]
|
|
550
|
+
this.checkRecordValidity(worksheetDetail, { status: WORKSHEET_STATUS.DONE })
|
|
551
|
+
const worksheet: Worksheet = worksheetDetail.worksheet
|
|
552
|
+
const replenishment: Replenishment = worksheet.replenishment
|
|
553
|
+
const targetInventory: OrderInventory = worksheetDetail.targetInventory
|
|
554
|
+
|
|
555
|
+
let inventory: Inventory = await this.trxMgr.getRepository(Inventory).findOne({
|
|
556
|
+
where: { domain: this.domain, cartonId, refOrderId: replenishment.id }
|
|
557
|
+
})
|
|
558
|
+
|
|
559
|
+
let inventoryItems: InventoryItem = await this.trxMgr
|
|
560
|
+
.getRepository(InventoryItem)
|
|
561
|
+
.find({ where: { outboundOrderId: replenishment.id, inventory } })
|
|
562
|
+
|
|
563
|
+
if (inventoryItems.length > 0) {
|
|
564
|
+
inventoryItems.forEach((itm: InventoryItem) => {
|
|
565
|
+
itm.status = INVENTORY_STATUS.RELOCATE
|
|
566
|
+
itm.updater = this.user
|
|
567
|
+
itm.inventory = targetInventory.inventory
|
|
568
|
+
})
|
|
569
|
+
|
|
570
|
+
await this.trxMgr.getRepository(InventoryItem).save(inventoryItems)
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
let updateInvObj = {
|
|
574
|
+
transferQty: () => `"transfer_qty" + ${targetInventory.releaseQty}`,
|
|
575
|
+
transferUomValue: () => `"transfer_uom_value" + ${targetInventory.releaseUomValue}`,
|
|
576
|
+
updater: this.user,
|
|
577
|
+
updatedAt: new Date()
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
await this.trxMgr
|
|
581
|
+
.getRepository(Inventory)
|
|
582
|
+
.createQueryBuilder()
|
|
583
|
+
.update(Inventory)
|
|
584
|
+
.set(updateInvObj)
|
|
585
|
+
.where('id = :id', { id: targetInventory.inventory.id })
|
|
586
|
+
.execute()
|
|
587
|
+
|
|
588
|
+
await this.checkReleaseTarget(inventory)
|
|
589
|
+
|
|
590
|
+
await this.trxMgr.getRepository(InventoryHistory).delete({ inventory })
|
|
591
|
+
|
|
592
|
+
await this.trxMgr.getRepository(Inventory).delete(inventory.id)
|
|
593
|
+
|
|
594
|
+
targetInventory.status = ORDER_PRODUCT_STATUS.PUTTING_AWAY
|
|
595
|
+
targetInventory.updater = this.user
|
|
596
|
+
await this.updateOrderTargets([targetInventory])
|
|
597
|
+
|
|
598
|
+
worksheetDetail.status = WORKSHEET_STATUS.EXECUTING
|
|
599
|
+
worksheetDetail.updater = this.user
|
|
600
|
+
await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
async completeReplenishmentPutaway(replenishmentNo: string): Promise<Worksheet> {
|
|
605
|
+
let replenishment: Replenishment = await this.findRefOrder(Replenishment, {
|
|
606
|
+
name: replenishmentNo,
|
|
607
|
+
status: ORDER_STATUS.PUTTING_AWAY
|
|
608
|
+
})
|
|
609
|
+
|
|
610
|
+
const putawayReplenishmentWorksheet: Worksheet = await this.findWorksheetByRefOrder(
|
|
611
|
+
replenishment,
|
|
612
|
+
WORKSHEET_TYPE.PUTAWAY_REPLENISHMENT,
|
|
613
|
+
['worksheetDetails', 'worksheetDetails.targetInventory']
|
|
614
|
+
)
|
|
615
|
+
return await this.completeWorksheet(putawayReplenishmentWorksheet, ORDER_STATUS.DONE)
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
private async checkReleaseTarget(inventory: Inventory): Promise<void> {
|
|
619
|
+
const releaseTargetInventory: OrderInventory = await this.trxMgr.getRepository(OrderInventory).findOne({
|
|
620
|
+
where: {
|
|
621
|
+
domain: this.domain,
|
|
622
|
+
type: ORDER_TYPES.RELEASE_OF_GOODS,
|
|
623
|
+
inventory
|
|
624
|
+
}
|
|
625
|
+
})
|
|
626
|
+
|
|
627
|
+
if (releaseTargetInventory)
|
|
628
|
+
throw new Error(
|
|
629
|
+
this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('undo putaway', 'this pallet ID has been selected for releasing')
|
|
630
|
+
)
|
|
631
|
+
}
|
|
632
|
+
}
|