@things-factory/worksheet-base 4.3.248 → 4.3.250
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/controllers/outbound/picking-worksheet-controller.js +241 -27
- package/dist-server/controllers/outbound/picking-worksheet-controller.js.map +1 -1
- package/dist-server/entities/warehouse-bizplace-onhand-inventory.js +6 -4
- package/dist-server/entities/warehouse-bizplace-onhand-inventory.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js +1 -0
- package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/worksheet.js +15 -8
- package/dist-server/graphql/resolvers/worksheet/worksheet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet-detail/regenerate-release-good-worksheet-details.js +1 -0
- package/dist-server/graphql/resolvers/worksheet-detail/regenerate-release-good-worksheet-details.js.map +1 -1
- package/package.json +4 -4
- package/server/controllers/outbound/picking-worksheet-controller.ts +328 -36
- package/server/entities/warehouse-bizplace-onhand-inventory.ts +6 -4
- package/server/graphql/resolvers/worksheet/inventories-by-pallet.ts +48 -62
- package/server/graphql/resolvers/worksheet/worksheet.ts +11 -4
- package/server/graphql/resolvers/worksheet-detail/regenerate-release-good-worksheet-details.ts +1 -0
|
@@ -7,6 +7,7 @@ import { generateId } from '@things-factory/id-rule-base'
|
|
|
7
7
|
import { Powrup } from '@things-factory/integration-powrup'
|
|
8
8
|
import { Sellercraft, SellercraftStatus } from '@things-factory/integration-sellercraft'
|
|
9
9
|
import { Product, ProductBarcode, ProductDetail } from '@things-factory/product-base'
|
|
10
|
+
|
|
10
11
|
import {
|
|
11
12
|
GenerateBatchPickInfo,
|
|
12
13
|
ORDER_INVENTORY_STATUS,
|
|
@@ -20,6 +21,8 @@ import {
|
|
|
20
21
|
OrderToteSeal,
|
|
21
22
|
OrderVas,
|
|
22
23
|
ReleaseGood,
|
|
24
|
+
InventoryUtil,
|
|
25
|
+
ORDER_TYPES,
|
|
23
26
|
PowrupController
|
|
24
27
|
} from '@things-factory/sales-base'
|
|
25
28
|
import { Setting } from '@things-factory/setting-base'
|
|
@@ -34,13 +37,14 @@ import {
|
|
|
34
37
|
Location,
|
|
35
38
|
LOCATION_TYPE,
|
|
36
39
|
Tote,
|
|
37
|
-
TOTE_STATUS
|
|
40
|
+
TOTE_STATUS,
|
|
41
|
+
ProductDetailStock
|
|
38
42
|
} from '@things-factory/warehouse-base'
|
|
39
43
|
|
|
40
44
|
import { TASK_NUMBER_RULE_TYPE, TASK_NUMBER_SETTING_KEY, WORKSHEET_STATUS, WORKSHEET_TYPE } from '../../constants'
|
|
41
45
|
import { SellercraftController } from '../../controllers'
|
|
42
46
|
import { Worksheet, WorksheetDetail } from '../../entities'
|
|
43
|
-
import { isInventoryObsolete, WorksheetNoGenerator } from '../../utils'
|
|
47
|
+
import { isInventoryObsolete, WorksheetNoGenerator, inventoriesByStrategy } from '../../utils'
|
|
44
48
|
import { VasWorksheetController } from '../vas/vas-worksheet-controller'
|
|
45
49
|
|
|
46
50
|
export class PickingWorksheetController extends VasWorksheetController {
|
|
@@ -113,6 +117,10 @@ export class PickingWorksheetController extends VasWorksheetController {
|
|
|
113
117
|
})
|
|
114
118
|
})
|
|
115
119
|
|
|
120
|
+
const worksheetPickingAssignment: Setting = await this.trxMgr.getRepository(Setting).findOne({
|
|
121
|
+
where: { domain: this.domain, category: 'id-rule', name: 'enable-worksheet-picking-activation-assignment' }
|
|
122
|
+
})
|
|
123
|
+
|
|
116
124
|
const worksheetSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
|
|
117
125
|
where: {
|
|
118
126
|
domain: this.domain,
|
|
@@ -136,24 +144,42 @@ export class PickingWorksheetController extends VasWorksheetController {
|
|
|
136
144
|
worksheet.updater = this.user
|
|
137
145
|
worksheet = await this.trxMgr.getRepository(Worksheet).save(worksheet)
|
|
138
146
|
|
|
139
|
-
if (orderInventories
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
147
|
+
if (orderInventories?.length > 0) {
|
|
148
|
+
if (orderInventories.some((oi: OrderInventory) => oi.inventory?.id)) {
|
|
149
|
+
const hasInventoryOIs: OrderInventory[] = orderInventories.filter(
|
|
150
|
+
(orderInventory: OrderInventory) => orderInventory.inventory !== null
|
|
151
|
+
)
|
|
143
152
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
153
|
+
worksheet.worksheetDetails = await this.createWorksheetDetails(
|
|
154
|
+
worksheet,
|
|
155
|
+
WORKSHEET_TYPE.BATCH_PICKING,
|
|
156
|
+
hasInventoryOIs
|
|
157
|
+
)
|
|
158
|
+
}
|
|
150
159
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
160
|
+
orderInventories.forEach((oi: OrderInventory) => {
|
|
161
|
+
oi.refWorksheetId = worksheet.id
|
|
162
|
+
oi.status = oi.inventory?.id ? ORDER_INVENTORY_STATUS.READY_TO_PICK : ORDER_INVENTORY_STATUS.PENDING_SPLIT
|
|
163
|
+
oi.updater = this.user
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
await this.updateOrderTargets(orderInventories)
|
|
167
|
+
} else {
|
|
168
|
+
let orderProducts: OrderProduct[] = []
|
|
169
|
+
releaseGoods.map((releaseGood: ReleaseGood) => {
|
|
170
|
+
const foundOPs: OrderProduct[] = releaseGood.orderProducts
|
|
171
|
+
foundOPs.map((op: OrderProduct) => {
|
|
172
|
+
orderProducts.push(op)
|
|
173
|
+
})
|
|
174
|
+
})
|
|
175
|
+
if (worksheetPickingAssignment && orderProducts?.length > 0) {
|
|
176
|
+
worksheet.worksheetDetails = await this.createWorksheetDetails(
|
|
177
|
+
worksheet,
|
|
178
|
+
WORKSHEET_TYPE.BATCH_PICKING,
|
|
179
|
+
orderProducts
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
157
183
|
|
|
158
184
|
releaseGoods = releaseGoods.map((releaseGood: ReleaseGood) => {
|
|
159
185
|
return {
|
|
@@ -192,6 +218,9 @@ export class PickingWorksheetController extends VasWorksheetController {
|
|
|
192
218
|
'releaseGood.domain',
|
|
193
219
|
'releaseGood.lastMileDelivery',
|
|
194
220
|
'releaseGood.bizplace.domain',
|
|
221
|
+
'releaseGood.orderProducts',
|
|
222
|
+
'releaseGood.orderProducts.productDetail',
|
|
223
|
+
'releaseGood.orderProducts.productDetail.product',
|
|
195
224
|
'releaseGood.orderPackages',
|
|
196
225
|
'releaseGood.orderPackages.orderPackageItems',
|
|
197
226
|
'releaseGood.orderPackages.orderPackageItems.orderProduct',
|
|
@@ -206,17 +235,25 @@ export class PickingWorksheetController extends VasWorksheetController {
|
|
|
206
235
|
'worksheetDetails.targetInventory.product'
|
|
207
236
|
])
|
|
208
237
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
let targetInventory: OrderInventory = wsd.targetInventory
|
|
212
|
-
targetInventory.status = ORDER_INVENTORY_STATUS.PICKING
|
|
213
|
-
targetInventory.updater = this.user
|
|
238
|
+
let worksheetDetails: WorksheetDetail[]
|
|
239
|
+
let releaseGood: ReleaseGood = worksheet.releaseGood
|
|
214
240
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
241
|
+
// assign inventory if unassigned
|
|
242
|
+
if (!releaseGood.assignedInventory) {
|
|
243
|
+
worksheetDetails = await this.assignInventoriesForUnassignedOrder(worksheet)
|
|
244
|
+
worksheet.worksheetDetails = worksheetDetails
|
|
245
|
+
releaseGood.assignedInventory = true
|
|
246
|
+
} else {
|
|
247
|
+
worksheetDetails = worksheet.worksheetDetails.filter(x => x.status == 'DEACTIVATED')
|
|
248
|
+
const targetInventories: OrderInventory[] = worksheetDetails.map((wsd: WorksheetDetail) => {
|
|
249
|
+
let targetInventory: OrderInventory = wsd.targetInventory
|
|
250
|
+
targetInventory.status = ORDER_INVENTORY_STATUS.PICKING
|
|
251
|
+
targetInventory.updater = this.user
|
|
218
252
|
|
|
219
|
-
|
|
253
|
+
return targetInventory
|
|
254
|
+
})
|
|
255
|
+
this.updateOrderTargets(targetInventories)
|
|
256
|
+
}
|
|
220
257
|
releaseGood.status = ORDER_STATUS.PICKING
|
|
221
258
|
releaseGood.updater = this.user
|
|
222
259
|
this.updateRefOrder(releaseGood)
|
|
@@ -311,6 +348,11 @@ export class PickingWorksheetController extends VasWorksheetController {
|
|
|
311
348
|
async activateBatchPicking(worksheetNo: string): Promise<Worksheet> {
|
|
312
349
|
let worksheet: Worksheet = await this.findActivatableWorksheet(worksheetNo, WORKSHEET_TYPE.BATCH_PICKING, [
|
|
313
350
|
'worksheetDetails',
|
|
351
|
+
'worksheetDetails.targetProduct',
|
|
352
|
+
'worksheetDetails.targetProduct.bizplace',
|
|
353
|
+
'worksheetDetails.targetProduct.product',
|
|
354
|
+
'worksheetDetails.targetProduct.productDetail',
|
|
355
|
+
'worksheetDetails.targetProduct.releaseGood',
|
|
314
356
|
'worksheetDetails.targetInventory',
|
|
315
357
|
'worksheetDetails.targetInventory.releaseGood',
|
|
316
358
|
'worksheetDetails.targetInventory.releaseGood.domain',
|
|
@@ -321,15 +363,21 @@ export class PickingWorksheetController extends VasWorksheetController {
|
|
|
321
363
|
'bizplace.company.domain'
|
|
322
364
|
])
|
|
323
365
|
|
|
324
|
-
|
|
325
|
-
const targetInventories: OrderInventory[] = worksheetDetails.map((wsd: WorksheetDetail) => {
|
|
326
|
-
let targetInventory: OrderInventory = wsd.targetInventory
|
|
327
|
-
targetInventory.status = ORDER_INVENTORY_STATUS.PICKING
|
|
328
|
-
targetInventory.updater = this.user
|
|
366
|
+
let worksheetDetails: WorksheetDetail[] = worksheet.worksheetDetails.filter(x => x.status == 'DEACTIVATED')
|
|
329
367
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
368
|
+
if (worksheet.worksheetDetails.find(wsd => wsd.targetProduct?.releaseGood?.assignedInventory == false)) {
|
|
369
|
+
worksheetDetails = await this.assignInventoriesForUnassignedMergedOrder(worksheet)
|
|
370
|
+
worksheet.worksheetDetails = worksheetDetails
|
|
371
|
+
} else {
|
|
372
|
+
const targetInventories: OrderInventory[] = worksheetDetails.map((wsd: WorksheetDetail) => {
|
|
373
|
+
let targetInventory: OrderInventory = wsd.targetInventory
|
|
374
|
+
targetInventory.status = ORDER_INVENTORY_STATUS.PICKING
|
|
375
|
+
targetInventory.updater = this.user
|
|
376
|
+
|
|
377
|
+
return targetInventory
|
|
378
|
+
})
|
|
379
|
+
this.updateOrderTargets(targetInventories)
|
|
380
|
+
}
|
|
333
381
|
|
|
334
382
|
worksheet = await this.activateWorksheet(worksheet, worksheetDetails, [])
|
|
335
383
|
|
|
@@ -419,7 +467,8 @@ export class PickingWorksheetController extends VasWorksheetController {
|
|
|
419
467
|
return {
|
|
420
468
|
...releaseGood,
|
|
421
469
|
status: ORDER_STATUS.PICKING,
|
|
422
|
-
updater: this.user
|
|
470
|
+
updater: this.user,
|
|
471
|
+
assignedInventory: true
|
|
423
472
|
}
|
|
424
473
|
})
|
|
425
474
|
)
|
|
@@ -1970,4 +2019,247 @@ export class PickingWorksheetController extends VasWorksheetController {
|
|
|
1970
2019
|
})
|
|
1971
2020
|
}
|
|
1972
2021
|
}
|
|
2022
|
+
|
|
2023
|
+
async assignInventoriesForUnassignedOrder(worksheet: Worksheet): Promise<any> {
|
|
2024
|
+
const releaseGood = worksheet.releaseGood
|
|
2025
|
+
const orderProducts = releaseGood.orderProducts
|
|
2026
|
+
let finalOrderInventories: OrderInventory[] = []
|
|
2027
|
+
let newWorksheetDetails: WorksheetDetail[] = []
|
|
2028
|
+
const inventoryAssignmentSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
|
|
2029
|
+
where: { domain: this.domain, name: 'rule-for-inventory-assignment' }
|
|
2030
|
+
})
|
|
2031
|
+
|
|
2032
|
+
for (let op of orderProducts) {
|
|
2033
|
+
let locationSortingRules = []
|
|
2034
|
+
if (inventoryAssignmentSetting) {
|
|
2035
|
+
let locationSetting = JSON.parse(inventoryAssignmentSetting.value)
|
|
2036
|
+
for (const key in locationSetting) {
|
|
2037
|
+
locationSortingRules.push({ name: key, desc: locationSetting[key] == 'ASC' ? false : true })
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
let assignedOrderInventories: OrderInventory[] = await InventoryUtil.autoAssignInventoryForRelease(
|
|
2042
|
+
op,
|
|
2043
|
+
op.productDetail.product,
|
|
2044
|
+
op.productDetail,
|
|
2045
|
+
locationSortingRules,
|
|
2046
|
+
releaseGood.bizplace,
|
|
2047
|
+
this.domain,
|
|
2048
|
+
this.trxMgr,
|
|
2049
|
+
op.batchId
|
|
2050
|
+
)
|
|
2051
|
+
|
|
2052
|
+
assignedOrderInventories = assignedOrderInventories.map(aoi => {
|
|
2053
|
+
delete aoi.id
|
|
2054
|
+
return {
|
|
2055
|
+
...aoi,
|
|
2056
|
+
orderProduct: op,
|
|
2057
|
+
status: ORDER_INVENTORY_STATUS.PICKING,
|
|
2058
|
+
name: OrderNoGenerator.orderInventory(),
|
|
2059
|
+
domain: this.domain,
|
|
2060
|
+
bizplace: { id: releaseGood.bizplace.id },
|
|
2061
|
+
releaseGood
|
|
2062
|
+
}
|
|
2063
|
+
})
|
|
2064
|
+
|
|
2065
|
+
finalOrderInventories.push(...assignedOrderInventories)
|
|
2066
|
+
|
|
2067
|
+
await this.trxMgr
|
|
2068
|
+
.getRepository(OrderProduct)
|
|
2069
|
+
.update({ id: op.id }, { status: ORDER_PRODUCT_STATUS.ASSIGNED, updater: this.user })
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
for (let oi of finalOrderInventories) {
|
|
2073
|
+
// update inventory locked qty and uom value
|
|
2074
|
+
oi = await this.trxMgr.getRepository(OrderInventory).save({ ...oi })
|
|
2075
|
+
|
|
2076
|
+
await this.trxMgr.getRepository(Inventory).update(oi.inventory.id, {
|
|
2077
|
+
lockedQty: (oi.inventory?.lockedQty || 0) + oi.releaseQty,
|
|
2078
|
+
lockedUomValue: (oi.inventory?.lockedUomValue || 0) + oi.releaseUomValue,
|
|
2079
|
+
updater: this.user
|
|
2080
|
+
})
|
|
2081
|
+
|
|
2082
|
+
// update product detail stock deduct unassigned qty and unassigned uom value
|
|
2083
|
+
await this.trxMgr
|
|
2084
|
+
.getRepository(ProductDetailStock)
|
|
2085
|
+
.createQueryBuilder()
|
|
2086
|
+
.update(ProductDetailStock)
|
|
2087
|
+
.set({
|
|
2088
|
+
unassignedQty: () => `"unassigned_qty" - ${oi.releaseQty}`,
|
|
2089
|
+
unassignedUomValue: () => `"unassigned_uom_value" - ${oi.releaseUomValue}`
|
|
2090
|
+
})
|
|
2091
|
+
.where({ productDetail: oi.productDetail.id })
|
|
2092
|
+
.execute()
|
|
2093
|
+
|
|
2094
|
+
const worksheetDetail: WorksheetDetail = Object.assign(new WorksheetDetail(), {
|
|
2095
|
+
domain: this.domain,
|
|
2096
|
+
bizplace: { id: releaseGood.bizplace.id },
|
|
2097
|
+
worksheet,
|
|
2098
|
+
name: WorksheetNoGenerator.pickingDetail(),
|
|
2099
|
+
seq: 0,
|
|
2100
|
+
targetInventory: oi,
|
|
2101
|
+
targetProduct: oi.orderProduct,
|
|
2102
|
+
type: WORKSHEET_TYPE.PICKING,
|
|
2103
|
+
status: WORKSHEET_STATUS.DEACTIVATED,
|
|
2104
|
+
creator: this.user,
|
|
2105
|
+
updater: this.user
|
|
2106
|
+
})
|
|
2107
|
+
|
|
2108
|
+
newWorksheetDetails.push(worksheetDetail)
|
|
2109
|
+
}
|
|
2110
|
+
newWorksheetDetails = await this.trxMgr.getRepository(WorksheetDetail).save(newWorksheetDetails)
|
|
2111
|
+
|
|
2112
|
+
return newWorksheetDetails
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
async assignInventoriesForUnassignedMergedOrder(worksheet: Worksheet): Promise<any> {
|
|
2116
|
+
//const releaseGood = worksheet.releaseGood
|
|
2117
|
+
const orderProducts = worksheet.worksheetDetails
|
|
2118
|
+
.filter(itm => itm.targetProduct.releaseGood.assignedInventory == false)
|
|
2119
|
+
.map(wsd => wsd.targetProduct)
|
|
2120
|
+
const releaseGoodIds = [...new Set(orderProducts.map(op => op.releaseGood.id))]
|
|
2121
|
+
let newWorksheetDetails: WorksheetDetail[] = []
|
|
2122
|
+
|
|
2123
|
+
const inventoryAssignmentSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
|
|
2124
|
+
where: { domain: this.domain, name: 'rule-for-inventory-assignment' }
|
|
2125
|
+
})
|
|
2126
|
+
|
|
2127
|
+
for (let i = 0; i < orderProducts.length; i++) {
|
|
2128
|
+
let pInventoryList = inventoriesByStrategy(
|
|
2129
|
+
{
|
|
2130
|
+
...orderProducts[i],
|
|
2131
|
+
worksheetId: worksheet.id,
|
|
2132
|
+
bizplaceId: worksheet.bizplace.id,
|
|
2133
|
+
locationSortingRules: inventoryAssignmentSetting ? JSON.parse(inventoryAssignmentSetting.value) : false,
|
|
2134
|
+
pickingStrategy: orderProducts[i].product.pickingStrategy
|
|
2135
|
+
},
|
|
2136
|
+
this.domain,
|
|
2137
|
+
this.trxMgr
|
|
2138
|
+
)
|
|
2139
|
+
|
|
2140
|
+
let idx = 0
|
|
2141
|
+
let [inventoryList] = await Promise.all([pInventoryList])
|
|
2142
|
+
|
|
2143
|
+
let { releaseQty, releaseUomValue } = orderProducts[i]
|
|
2144
|
+
|
|
2145
|
+
while (releaseQty > 0 && idx < inventoryList.items.length) {
|
|
2146
|
+
let targetInventory: Inventory = await this.trxMgr
|
|
2147
|
+
.getRepository(Inventory)
|
|
2148
|
+
.findOne({ where: { id: inventoryList.items[idx].id } })
|
|
2149
|
+
|
|
2150
|
+
let inventoryAvailableQty = targetInventory.qty - (targetInventory?.lockedQty || 0)
|
|
2151
|
+
let inventoryAvailableUomValue = targetInventory.uomValue - (targetInventory?.lockedUomValue || 0)
|
|
2152
|
+
|
|
2153
|
+
if (inventoryAvailableQty > 0) {
|
|
2154
|
+
let allocatedQty = 0,
|
|
2155
|
+
allocatedUomValue = 0
|
|
2156
|
+
if (inventoryAvailableQty < releaseQty) {
|
|
2157
|
+
idx = idx + 1
|
|
2158
|
+
allocatedQty = inventoryAvailableQty
|
|
2159
|
+
allocatedUomValue = inventoryAvailableUomValue
|
|
2160
|
+
} else {
|
|
2161
|
+
allocatedQty = releaseQty
|
|
2162
|
+
allocatedUomValue = releaseUomValue
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
releaseQty = releaseQty - allocatedQty
|
|
2166
|
+
releaseUomValue = releaseUomValue - allocatedUomValue
|
|
2167
|
+
|
|
2168
|
+
//// Update inventory locked quantity
|
|
2169
|
+
await this.trxMgr
|
|
2170
|
+
.getRepository(Inventory)
|
|
2171
|
+
.createQueryBuilder('inv')
|
|
2172
|
+
.update(Inventory)
|
|
2173
|
+
.set({
|
|
2174
|
+
lockedUomValue: () => `COALESCE(locked_uom_value,0) + ${allocatedUomValue}`,
|
|
2175
|
+
lockedQty: () => `COALESCE(locked_qty,0) + ${allocatedQty}`
|
|
2176
|
+
})
|
|
2177
|
+
.where('id = :id', { id: targetInventory.id })
|
|
2178
|
+
.execute()
|
|
2179
|
+
|
|
2180
|
+
// update product detail stock deduct unassigned qty and unassigned uom value
|
|
2181
|
+
await this.trxMgr
|
|
2182
|
+
.getRepository(ProductDetailStock)
|
|
2183
|
+
.createQueryBuilder()
|
|
2184
|
+
.update(ProductDetailStock)
|
|
2185
|
+
.set({
|
|
2186
|
+
unassignedQty: () => `"unassigned_qty" - ${allocatedQty}`,
|
|
2187
|
+
unassignedUomValue: () => `"unassigned_uom_value" - ${allocatedUomValue}`
|
|
2188
|
+
})
|
|
2189
|
+
.where({ productDetail: orderProducts[i].productDetail.id })
|
|
2190
|
+
.execute()
|
|
2191
|
+
|
|
2192
|
+
// update order product status to ASSIGNED
|
|
2193
|
+
await this.trxMgr
|
|
2194
|
+
.getRepository(OrderProduct)
|
|
2195
|
+
.update({ id: orderProducts[i].id }, { status: ORDER_PRODUCT_STATUS.ASSIGNED, updater: this.user })
|
|
2196
|
+
|
|
2197
|
+
// Create new order inventory with status -> READY_TO_PICK, type -> RELEASE_OF_GOODS
|
|
2198
|
+
let newTargetInventory: OrderInventory = new OrderInventory()
|
|
2199
|
+
newTargetInventory = {
|
|
2200
|
+
domain: this.domain,
|
|
2201
|
+
bizplace: orderProducts[i].bizplace,
|
|
2202
|
+
name: OrderNoGenerator.orderInventory(),
|
|
2203
|
+
releaseGood: orderProducts[i].releaseGood,
|
|
2204
|
+
batchId: orderProducts[i].batchId,
|
|
2205
|
+
status: ORDER_INVENTORY_STATUS.PICKING,
|
|
2206
|
+
type: ORDER_TYPES.RELEASE_OF_GOODS,
|
|
2207
|
+
refWorksheetId: worksheet.id,
|
|
2208
|
+
product: orderProducts[i].product,
|
|
2209
|
+
productDetail: orderProducts[i].productDetail,
|
|
2210
|
+
packingType: orderProducts[i].packingType,
|
|
2211
|
+
packingSize: parseFloat(orderProducts[i].packingSize),
|
|
2212
|
+
creator: this.user,
|
|
2213
|
+
inventory: targetInventory,
|
|
2214
|
+
releaseQty: allocatedQty,
|
|
2215
|
+
releaseUomValue: allocatedUomValue,
|
|
2216
|
+
uom: orderProducts[i].uom,
|
|
2217
|
+
orderProduct: orderProducts[i]
|
|
2218
|
+
}
|
|
2219
|
+
newTargetInventory = await this.trxMgr.getRepository(OrderInventory).save(newTargetInventory)
|
|
2220
|
+
|
|
2221
|
+
if (idx == 0) {
|
|
2222
|
+
let updatedWorksheetDetail = {
|
|
2223
|
+
...worksheet.worksheetDetails[i],
|
|
2224
|
+
targetInventory: newTargetInventory,
|
|
2225
|
+
worksheet,
|
|
2226
|
+
bizplace: worksheet.bizplace,
|
|
2227
|
+
domain: this.domain,
|
|
2228
|
+
updater: this.user,
|
|
2229
|
+
creator: this.user
|
|
2230
|
+
}
|
|
2231
|
+
await this.trxMgr.getRepository(WorksheetDetail).update(worksheet.worksheetDetails[i].id, {
|
|
2232
|
+
targetInventory: newTargetInventory,
|
|
2233
|
+
worksheet,
|
|
2234
|
+
bizplace: worksheet.bizplace,
|
|
2235
|
+
domain: this.domain,
|
|
2236
|
+
updater: this.user,
|
|
2237
|
+
creator: this.user
|
|
2238
|
+
})
|
|
2239
|
+
|
|
2240
|
+
newWorksheetDetails.push(updatedWorksheetDetail)
|
|
2241
|
+
} else {
|
|
2242
|
+
let newWorksheetDetail = {
|
|
2243
|
+
...worksheet.worksheetDetails[i],
|
|
2244
|
+
name: WorksheetNoGenerator.batchPickingDetail(),
|
|
2245
|
+
targetInventory: newTargetInventory,
|
|
2246
|
+
worksheet,
|
|
2247
|
+
bizplace: worksheet.bizplace,
|
|
2248
|
+
domain: this.domain,
|
|
2249
|
+
updater: this.user,
|
|
2250
|
+
creator: this.user
|
|
2251
|
+
}
|
|
2252
|
+
delete newWorksheetDetail.id
|
|
2253
|
+
|
|
2254
|
+
newWorksheetDetail = await this.trxMgr.getRepository(WorksheetDetail).save(newWorksheetDetail)
|
|
2255
|
+
newWorksheetDetails.push(newWorksheetDetail)
|
|
2256
|
+
}
|
|
2257
|
+
} else {
|
|
2258
|
+
idx = idx + 1
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
await this.trxMgr.getRepository(ReleaseGood).update(releaseGoodIds, { assignedInventory: true })
|
|
2262
|
+
}
|
|
2263
|
+
return newWorksheetDetails
|
|
2264
|
+
}
|
|
1973
2265
|
}
|
|
@@ -12,8 +12,8 @@ import { ViewColumn, ViewEntity } from 'typeorm'
|
|
|
12
12
|
i.uom,
|
|
13
13
|
i.product_id as "product_id",
|
|
14
14
|
null as "product_bundle_id",
|
|
15
|
-
COALESCE(SUM(COALESCE(i.qty, 0)) - SUM(COALESCE(i.locked_qty, 0))) AS "remain_qty",
|
|
16
|
-
COALESCE(SUM(COALESCE(i.uom_value, 0)) - SUM(COALESCE(i.locked_uom_value, 0))) AS "remain_uom_value",
|
|
15
|
+
COALESCE(SUM(COALESCE(i.qty, 0)) - SUM(COALESCE(i.locked_qty, 0)) - SUM(COALESCE(pds.unassigned_qty, 0))) AS "remain_qty",
|
|
16
|
+
COALESCE(SUM(COALESCE(i.uom_value, 0)) - SUM(COALESCE(i.locked_uom_value, 0)) - SUM(COALESCE(pds.unassigned_uom_value, 0))) AS "remain_uom_value",
|
|
17
17
|
COALESCE(sum(COALESCE(i.qty, 0::double precision))) AS "qty",
|
|
18
18
|
COALESCE(sum(COALESCE(i.uom_value, 0::double precision))) AS "uom_value",
|
|
19
19
|
COALESCE(sum(COALESCE(i.transfer_qty, 0::double precision))) AS "transfer_qty",
|
|
@@ -22,6 +22,7 @@ import { ViewColumn, ViewEntity } from 'typeorm'
|
|
|
22
22
|
FROM inventories i
|
|
23
23
|
INNER JOIN locations l2 ON i.location_id = l2.id AND i.domain_id = l2.domain_id AND l2.type NOT IN ('QUARANTINE', 'RESERVE')
|
|
24
24
|
INNER JOIN products p ON p.id = i.product_id
|
|
25
|
+
LEFT JOIN product_detail_stocks pds on pds.product_detail_id = i.product_detail_id
|
|
25
26
|
WHERE i.status = 'STORED' AND CASE WHEN i.expiration_date is not null and p.shelf_life is not null then CURRENT_DATE < i.expiration_date - p.shelf_life else true end
|
|
26
27
|
AND i.obsolete is false
|
|
27
28
|
GROUP by
|
|
@@ -51,14 +52,15 @@ import { ViewColumn, ViewEntity } from 'typeorm'
|
|
|
51
52
|
FROM product_bundles pb
|
|
52
53
|
INNER JOIN (
|
|
53
54
|
SELECT i.domain_id, i.bizplace_id, pbs.product_id, pbs.product_bundle_id, min(pbs.bundle_qty),
|
|
54
|
-
(SUM(COALESCE(i.qty, 0)) - SUM(COALESCE(i.locked_qty, 0))) / min(pbs.bundle_qty) AS "available_qty",
|
|
55
|
-
(SUM(COALESCE(i.uom_value, 0)) - SUM(COALESCE(i.locked_uom_value, 0))) / min(pbs.bundle_qty) AS "available_uom_value",
|
|
55
|
+
(SUM(COALESCE(i.qty, 0)) - SUM(COALESCE(i.locked_qty, 0)) - SUM(COALESCE(pds.unassigned_qty, 0))) / min(pbs.bundle_qty) AS "available_qty",
|
|
56
|
+
(SUM(COALESCE(i.uom_value, 0)) - SUM(COALESCE(i.locked_uom_value, 0)) - SUM(COALESCE(pds.unassigned_uom_value, 0))) / min(pbs.bundle_qty) AS "available_uom_value",
|
|
56
57
|
(sum(COALESCE(i.qty, 0::double precision))) / min(pbs.bundle_qty)::double precision AS "qty",
|
|
57
58
|
(sum(COALESCE(i.uom_value, 0::double precision))) / min(pbs.bundle_qty)::double precision AS "uom_value",
|
|
58
59
|
(sum(COALESCE(i.transfer_qty, 0::double precision))) / min(pbs.bundle_qty)::double precision AS "transfer_qty",
|
|
59
60
|
(sum(COALESCE(i.transfer_uom_value, 0::double precision))) / min(pbs.bundle_qty)::double precision AS "transfer_uom_value"
|
|
60
61
|
FROM product_bundle_settings pbs
|
|
61
62
|
LEFT JOIN inventories i ON i.product_id = pbs.product_id AND i.status = 'STORED' AND i.obsolete = false
|
|
63
|
+
LEFT JOIN product_detail_stocks pds ON pds.product_detail_id = i.product_detail_id
|
|
62
64
|
INNER JOIN products p ON p.id = pbs.product_id AND CASE WHEN i.expiration_date is not null and p.shelf_life is not null then CURRENT_DATE < i.expiration_date - p.shelf_life else true end
|
|
63
65
|
INNER JOIN locations l ON i.location_id = l.id AND i.domain_id = l.domain_id AND l.type NOT IN ('QUARANTINE', 'RESERVE')
|
|
64
66
|
GROUP by
|
|
@@ -1,28 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Brackets,
|
|
3
|
-
getRepository,
|
|
4
|
-
SelectQueryBuilder
|
|
5
|
-
} from 'typeorm'
|
|
1
|
+
import { Brackets, getRepository, SelectQueryBuilder } from 'typeorm'
|
|
6
2
|
|
|
7
3
|
import { User } from '@things-factory/auth-base'
|
|
8
4
|
import { getPermittedBizplaceIds } from '@things-factory/biz-base'
|
|
9
5
|
import { ORDER_INVENTORY_STATUS } from '@things-factory/sales-base'
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
buildQuery,
|
|
13
|
-
Domain
|
|
14
|
-
} from '@things-factory/shell'
|
|
15
|
-
import {
|
|
16
|
-
Inventory,
|
|
17
|
-
LOCATION_TYPE
|
|
18
|
-
} from '@things-factory/warehouse-base'
|
|
6
|
+
import { buildCondition, buildQuery, Domain } from '@things-factory/shell'
|
|
7
|
+
import { Inventory, LOCATION_TYPE } from '@things-factory/warehouse-base'
|
|
19
8
|
|
|
20
9
|
export const inventoriesByPalletResolver = {
|
|
21
10
|
async inventoriesByPallet(_: any, { filters, pagination, sortings, locationSortingRules }, context: any) {
|
|
22
11
|
const { domain, user }: { domain: Domain; user: User } = context.state
|
|
23
12
|
const params = { filters, pagination }
|
|
24
13
|
let permittedBizplaceIds: string[] = await getPermittedBizplaceIds(domain, user)
|
|
25
|
-
const bizplaceId =
|
|
14
|
+
const bizplaceId = params.filters.find(x => x.name == 'bizplace_id')
|
|
26
15
|
const productFilters = params.filters.filter(x => x.name == 'productName')
|
|
27
16
|
const recallFilters = params.filters.find(x => x.name === 'recall')
|
|
28
17
|
const skipLockCheckFilters = params.filters.find(x => x.name === 'skipLockCheck')
|
|
@@ -46,6 +35,7 @@ export const inventoriesByPalletResolver = {
|
|
|
46
35
|
.leftJoinAndSelect('iv.bizplace', 'bizplace')
|
|
47
36
|
.leftJoinAndSelect('iv.product', 'product')
|
|
48
37
|
.leftJoinAndSelect('iv.productDetail', 'productDetail')
|
|
38
|
+
.leftJoin('product_detail_stocks', 'pds', 'pds.product_detail_id = iv.product_detail_id')
|
|
49
39
|
.leftJoinAndSelect('iv.warehouse', 'warehouse')
|
|
50
40
|
.leftJoinAndSelect('iv.location', 'location')
|
|
51
41
|
.leftJoinAndSelect('iv.creator', 'creator')
|
|
@@ -54,7 +44,9 @@ export const inventoriesByPalletResolver = {
|
|
|
54
44
|
.andWhere('iv.transfer_qty <= 0')
|
|
55
45
|
.andWhere('iv.transfer_uom_value <= 0')
|
|
56
46
|
.andWhere(
|
|
57
|
-
`location.type ${recallFilters?.value === true ? '' : 'NOT'} IN ('${LOCATION_TYPE.QUARANTINE}', '${
|
|
47
|
+
`location.type ${recallFilters?.value === true ? '' : 'NOT'} IN ('${LOCATION_TYPE.QUARANTINE}', '${
|
|
48
|
+
LOCATION_TYPE.RESERVE
|
|
49
|
+
}', '${LOCATION_TYPE.DAMAGE}')`
|
|
58
50
|
)
|
|
59
51
|
.andWhere(
|
|
60
52
|
`(iv.batch_id, product.name, iv.packing_type, product.brand) NOT IN (
|
|
@@ -71,14 +63,43 @@ export const inventoriesByPalletResolver = {
|
|
|
71
63
|
AND oi.domain_id = (:domainId)
|
|
72
64
|
AND oi.bizplace_id = (:bizplaceId)
|
|
73
65
|
)`,
|
|
74
|
-
{ bizplaceId: bizplaceId.value
|
|
66
|
+
{ bizplaceId: bizplaceId.value, domainId: domain.id }
|
|
75
67
|
)
|
|
76
68
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
69
|
+
if (locationFilters) {
|
|
70
|
+
qb.andWhere(`location.name ilike '${locationFilters.value}'`)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (productFilters && productFilters.length > 0) {
|
|
74
|
+
let productInfo = productFilters[0]
|
|
75
|
+
qb.andWhere(
|
|
76
|
+
new Brackets(qb2 => {
|
|
77
|
+
productFilterColumns.forEach(filter => {
|
|
78
|
+
const condition = buildCondition(
|
|
79
|
+
'product',
|
|
80
|
+
filter,
|
|
81
|
+
'i_like',
|
|
82
|
+
productInfo.value,
|
|
83
|
+
false,
|
|
84
|
+
Object.keys(qb.getParameters()).length
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
qb2.orWhere(condition.clause, condition.parameters)
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
)
|
|
91
|
+
}
|
|
81
92
|
|
|
93
|
+
if (!skipLockCheck) {
|
|
94
|
+
qb.andWhere('CASE WHEN iv.lockedQty IS NULL THEN 0 ELSE iv.lockedQty END >= 0')
|
|
95
|
+
qb.andWhere('iv.qty - CASE WHEN iv.lockedQty IS NULL THEN 0 ELSE iv.lockedQty END > 0')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (recallFilters?.value === true) {
|
|
99
|
+
qb.orWhere('(iv.domain_id = (:domainId) and iv.bizplace_id = (:bizplaceId)')
|
|
100
|
+
if (locationFilters) {
|
|
101
|
+
qb.andWhere(`location.name ilike '${locationFilters.value}'`)
|
|
102
|
+
}
|
|
82
103
|
if (productFilters && productFilters.length > 0) {
|
|
83
104
|
let productInfo = productFilters[0]
|
|
84
105
|
qb.andWhere(
|
|
@@ -92,53 +113,18 @@ export const inventoriesByPalletResolver = {
|
|
|
92
113
|
false,
|
|
93
114
|
Object.keys(qb.getParameters()).length
|
|
94
115
|
)
|
|
95
|
-
|
|
116
|
+
|
|
96
117
|
qb2.orWhere(condition.clause, condition.parameters)
|
|
97
118
|
})
|
|
98
119
|
})
|
|
99
120
|
)
|
|
100
121
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
qb.andWhere('iv.qty - CASE WHEN iv.lockedQty IS NULL THEN 0 ELSE iv.lockedQty END > 0')
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (recallFilters?.value === true) {
|
|
108
|
-
qb.orWhere(
|
|
109
|
-
'(iv.domain_id = (:domainId) and iv.bizplace_id = (:bizplaceId)'
|
|
110
|
-
)
|
|
111
|
-
if (locationFilters){
|
|
112
|
-
qb.andWhere
|
|
113
|
-
(`location.name ilike '${locationFilters.value}'`)
|
|
114
|
-
}
|
|
115
|
-
if (productFilters && productFilters.length > 0) {
|
|
116
|
-
let productInfo = productFilters[0]
|
|
117
|
-
qb.andWhere(
|
|
118
|
-
new Brackets(qb2 => {
|
|
119
|
-
productFilterColumns.forEach(filter => {
|
|
120
|
-
const condition = buildCondition(
|
|
121
|
-
'product',
|
|
122
|
-
filter,
|
|
123
|
-
'i_like',
|
|
124
|
-
productInfo.value,
|
|
125
|
-
false,
|
|
126
|
-
Object.keys(qb.getParameters()).length
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
qb2.orWhere(condition.clause, condition.parameters)
|
|
130
|
-
})
|
|
131
|
-
})
|
|
132
|
-
)
|
|
133
|
-
}
|
|
134
|
-
if (batchIdFilters) {
|
|
135
|
-
qb.andWhere(
|
|
136
|
-
`iv.batch_id ilike '${batchIdFilters.value}'`
|
|
137
|
-
)
|
|
138
|
-
}
|
|
122
|
+
if (batchIdFilters) {
|
|
123
|
+
qb.andWhere(`iv.batch_id ilike '${batchIdFilters.value}'`)
|
|
124
|
+
}
|
|
139
125
|
qb.andWhere(
|
|
140
126
|
'iv.obsolete = true and case when iv.expiration_date is not null and product.shelf_life is not null then CURRENT_DATE > iv.expiration_date - product.shelf_life else true end)'
|
|
141
|
-
|
|
127
|
+
)
|
|
142
128
|
} else {
|
|
143
129
|
qb.andWhere('iv.obsolete = false')
|
|
144
130
|
qb.andWhere(
|
|
@@ -199,4 +185,4 @@ async function getRemainAmount(inventory: Inventory): Promise<{ remainQty: numbe
|
|
|
199
185
|
remainQty: inventory.qty - (inventory.lockedQty || 0),
|
|
200
186
|
remainUomValue: inventory.uomValue - (inventory.lockedUomValue || 0)
|
|
201
187
|
}
|
|
202
|
-
}
|
|
188
|
+
}
|