@things-factory/worksheet-base 3.6.46 → 3.6.50
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/render-grn.js +8 -0
- package/dist-server/controllers/render-grn.js.map +1 -1
- package/dist-server/controllers/render-ro-do.js +18 -5
- package/dist-server/controllers/render-ro-do.js.map +1 -1
- package/dist-server/controllers/vas/vas-worksheet-controller.js +75 -14
- package/dist-server/controllers/vas/vas-worksheet-controller.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js +8 -7
- package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/vas-transactions/common-utils.js +302 -11
- package/dist-server/graphql/resolvers/worksheet/vas-transactions/common-utils.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/vas-transactions/interfaces/index.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/vas-transactions/interfaces/repackaging.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/vas-transactions/repackaging/complete-repackaging.js +137 -31
- package/dist-server/graphql/resolvers/worksheet/vas-transactions/repackaging/complete-repackaging.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/vas-transactions/repackaging/repackaging.js +157 -42
- package/dist-server/graphql/resolvers/worksheet/vas-transactions/repackaging/repackaging.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/vas-transactions/repackaging/undo-repackaging.js +35 -21
- package/dist-server/graphql/resolvers/worksheet/vas-transactions/repackaging/undo-repackaging.js.map +1 -1
- package/dist-server/utils/inventory-util.js +3 -2
- package/dist-server/utils/inventory-util.js.map +1 -1
- package/package.json +14 -14
- package/server/controllers/render-grn.ts +8 -0
- package/server/controllers/render-ro-do.ts +21 -6
- package/server/controllers/vas/vas-worksheet-controller.ts +104 -23
- package/server/graphql/resolvers/worksheet/picking/complete-picking.ts +8 -13
- package/server/graphql/resolvers/worksheet/vas-transactions/common-utils.ts +452 -14
- package/server/graphql/resolvers/worksheet/vas-transactions/interfaces/index.ts +36 -1
- package/server/graphql/resolvers/worksheet/vas-transactions/interfaces/repackaging.ts +8 -2
- package/server/graphql/resolvers/worksheet/vas-transactions/repackaging/complete-repackaging.ts +185 -56
- package/server/graphql/resolvers/worksheet/vas-transactions/repackaging/repackaging.ts +210 -54
- package/server/graphql/resolvers/worksheet/vas-transactions/repackaging/undo-repackaging.ts +64 -32
- package/server/utils/inventory-util.ts +10 -5
|
@@ -1,29 +1,37 @@
|
|
|
1
|
+
import { EntityManager, Equal, In, IsNull, Not } from 'typeorm'
|
|
2
|
+
|
|
1
3
|
import { User } from '@things-factory/auth-base'
|
|
2
4
|
import { Bizplace } from '@things-factory/biz-base'
|
|
3
5
|
import {
|
|
4
6
|
ArrivalNotice,
|
|
7
|
+
ORDER_INVENTORY_STATUS,
|
|
8
|
+
ORDER_TYPES,
|
|
5
9
|
OrderInventory,
|
|
6
10
|
OrderNoGenerator,
|
|
7
11
|
OrderVas,
|
|
8
|
-
ORDER_INVENTORY_STATUS,
|
|
9
|
-
ORDER_TYPES,
|
|
10
12
|
ReleaseGood
|
|
11
13
|
} from '@things-factory/sales-base'
|
|
12
14
|
import { Domain } from '@things-factory/shell'
|
|
13
15
|
import {
|
|
14
16
|
Inventory,
|
|
15
|
-
InventoryNoGenerator,
|
|
16
17
|
INVENTORY_STATUS,
|
|
17
18
|
INVENTORY_TRANSACTION_TYPE,
|
|
19
|
+
InventoryNoGenerator,
|
|
18
20
|
Location,
|
|
19
21
|
Pallet,
|
|
20
22
|
Warehouse
|
|
21
23
|
} from '@things-factory/warehouse-base'
|
|
22
|
-
|
|
24
|
+
|
|
23
25
|
import { WORKSHEET_STATUS, WORKSHEET_TYPE } from '../../../../constants'
|
|
24
26
|
import { Worksheet, WorksheetDetail } from '../../../../entities'
|
|
25
27
|
import { generateInventoryHistory, WorksheetNoGenerator } from '../../../../utils'
|
|
26
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
OperationGuideInterface,
|
|
30
|
+
PackingUnits,
|
|
31
|
+
PalletChangesInterface,
|
|
32
|
+
RefOrderType,
|
|
33
|
+
TemporaryPalletChangesInterface
|
|
34
|
+
} from './interfaces'
|
|
27
35
|
|
|
28
36
|
/**
|
|
29
37
|
* @description Find worksheet detail by name
|
|
@@ -184,6 +192,368 @@ export async function getRemainInventoryAmount(
|
|
|
184
192
|
return { remainQty, remainUomValue }
|
|
185
193
|
}
|
|
186
194
|
|
|
195
|
+
/** REMARK
|
|
196
|
+
* @farishelmi created temporary function @temporaryGetReducedAmount and
|
|
197
|
+
* @temporaryGetRemainInventoryAmount specifically for @Repackaging
|
|
198
|
+
* - because in repackaging we need to calculate based on unit qty of a product
|
|
199
|
+
* - eg: Carton of 12 Cokes repack into Boxes of 6 Cokes
|
|
200
|
+
* - this function should be merged with its origin once the logic in other vas is updated
|
|
201
|
+
* */
|
|
202
|
+
|
|
203
|
+
export function temporaryGetCurrentAmount(
|
|
204
|
+
palletChanges: TemporaryPalletChangesInterface[],
|
|
205
|
+
palletId: string,
|
|
206
|
+
packingUnit: string,
|
|
207
|
+
stdAmount: number
|
|
208
|
+
): { qty: number; uomValue: number } {
|
|
209
|
+
return palletChanges
|
|
210
|
+
.filter((pc: TemporaryPalletChangesInterface) => pc.toPalletId === palletId)
|
|
211
|
+
.reduce(
|
|
212
|
+
(currentAmount: { qty: number; uomValue: number }, pc: TemporaryPalletChangesInterface) => {
|
|
213
|
+
if (packingUnit == PackingUnits.QTY) {
|
|
214
|
+
return {
|
|
215
|
+
qty: currentAmount.qty + pc.reducedUnitQty / stdAmount,
|
|
216
|
+
uomValue: currentAmount.uomValue + pc.reducedUomValue
|
|
217
|
+
}
|
|
218
|
+
} else if (packingUnit == PackingUnits.UOM) {
|
|
219
|
+
return {
|
|
220
|
+
qty: currentAmount.qty + pc.reducedQty,
|
|
221
|
+
uomValue: currentAmount.uomValue + pc.reducedUomValue
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
return { qty: 0, uomValue: 0 }
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
{ qty: 0, uomValue: 0 }
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* @description need to consider unit amount because we have packingSize for each packingType
|
|
233
|
+
* @param palletChanges
|
|
234
|
+
* @param palletId
|
|
235
|
+
* @returns reducedUomValue: used for packingUnit == UOM
|
|
236
|
+
* @returns reducedUnitQty: used for packingUnit == QTY
|
|
237
|
+
*/
|
|
238
|
+
export function temporaryGetReducedAmount(
|
|
239
|
+
palletChanges: TemporaryPalletChangesInterface[],
|
|
240
|
+
palletId: string
|
|
241
|
+
): { reducedUomValue: number; reducedUnitQty: number } {
|
|
242
|
+
return palletChanges
|
|
243
|
+
.filter((pc: TemporaryPalletChangesInterface) => pc.fromPalletId === palletId)
|
|
244
|
+
.reduce(
|
|
245
|
+
(
|
|
246
|
+
reducedAmount: {
|
|
247
|
+
reducedUomValue: number
|
|
248
|
+
reducedUnitQty: number
|
|
249
|
+
},
|
|
250
|
+
pc: TemporaryPalletChangesInterface
|
|
251
|
+
) => {
|
|
252
|
+
return {
|
|
253
|
+
reducedUomValue: reducedAmount.reducedUomValue + pc.reducedUomValue || 0,
|
|
254
|
+
reducedUnitQty: reducedAmount.reducedUnitQty + pc.reducedUnitQty || 0
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
{ reducedUomValue: 0, reducedUnitQty: 0 }
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export async function temporaryGetRemainInventoryAmount(
|
|
262
|
+
trxMgr: EntityManager,
|
|
263
|
+
refOrder: RefOrderType,
|
|
264
|
+
domain: Domain,
|
|
265
|
+
bizplace: Bizplace,
|
|
266
|
+
originInv: Inventory,
|
|
267
|
+
palletChanges: TemporaryPalletChangesInterface[],
|
|
268
|
+
palletId: string
|
|
269
|
+
): Promise<{ remainUomValue: number; remainUnitQty: number }> {
|
|
270
|
+
let remainUomValue: number = 0
|
|
271
|
+
let remainUnitQty: number = 0
|
|
272
|
+
|
|
273
|
+
const packingSize: number = originInv.packingSize
|
|
274
|
+
const { reducedUomValue, reducedUnitQty } = temporaryGetReducedAmount(palletChanges, palletId)
|
|
275
|
+
if (refOrder instanceof ReleaseGood) {
|
|
276
|
+
// Find loading order inventory to figure out uomValue
|
|
277
|
+
const orderInv: OrderInventory = await trxMgr.getRepository(OrderInventory).findOne({
|
|
278
|
+
where: { domain, bizplace, inventory: originInv, releaseGood: refOrder, type: ORDER_TYPES.RELEASE_OF_GOODS }
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
remainUomValue = orderInv.releaseUomValue - reducedUomValue
|
|
282
|
+
remainUnitQty = orderInv.releaseQty * packingSize - reducedUnitQty
|
|
283
|
+
} else {
|
|
284
|
+
remainUomValue = originInv.uomValue - reducedUomValue
|
|
285
|
+
remainUnitQty = originInv.qty * packingSize - reducedUnitQty
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (remainUomValue <= 0 || remainUnitQty <= 0) throw new Error(`There's no more remaining product on the pallet`)
|
|
289
|
+
return { remainUomValue, remainUnitQty }
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export async function updateOriginInventories(
|
|
293
|
+
trxMgr: EntityManager,
|
|
294
|
+
domain: Domain,
|
|
295
|
+
bizplace: Bizplace,
|
|
296
|
+
user: User,
|
|
297
|
+
refOrder: RefOrderType,
|
|
298
|
+
repackedFroms: Partial<TemporaryPalletChangesInterface[]>,
|
|
299
|
+
packingUnit: string,
|
|
300
|
+
transactionType: string
|
|
301
|
+
): Promise<Inventory[]> {
|
|
302
|
+
const inventories: Inventory[] = []
|
|
303
|
+
|
|
304
|
+
for (let inv of repackedFroms) {
|
|
305
|
+
let foundInventory: Inventory = await trxMgr.getRepository(Inventory).findOne({
|
|
306
|
+
where: { domain, bizplace, palletId: inv.fromPalletId, status: Not(Equal(INVENTORY_STATUS.TERMINATED)) }
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
if (foundInventory) {
|
|
310
|
+
let repackedPkgQty: number = 0
|
|
311
|
+
let repackedPkgUomValue: number = 0
|
|
312
|
+
|
|
313
|
+
switch (packingUnit) {
|
|
314
|
+
case PackingUnits.QTY:
|
|
315
|
+
repackedPkgQty = inv.reducedUnitQty / inv.packingSize
|
|
316
|
+
repackedPkgUomValue = inv.reducedUomValue // it should be called reducedUomValue instead. sbb dh kira smua dgn packingsize
|
|
317
|
+
break
|
|
318
|
+
|
|
319
|
+
case PackingUnits.UOM:
|
|
320
|
+
// repackedPkgQty = inv.reducedQty / inv.packingSize
|
|
321
|
+
// repackedPkgUomValue = rf.reducedUomValue
|
|
322
|
+
break
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
foundInventory = await trxMgr.getRepository(Inventory).save({
|
|
326
|
+
...foundInventory,
|
|
327
|
+
qty: repackedPkgQty,
|
|
328
|
+
uomValue: repackedPkgUomValue,
|
|
329
|
+
creator: user,
|
|
330
|
+
updater: user
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
await generateInventoryHistory(
|
|
334
|
+
foundInventory,
|
|
335
|
+
refOrder,
|
|
336
|
+
transactionType,
|
|
337
|
+
repackedPkgQty,
|
|
338
|
+
repackedPkgUomValue,
|
|
339
|
+
user,
|
|
340
|
+
trxMgr
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
inventories.push(foundInventory)
|
|
344
|
+
} else {
|
|
345
|
+
throw new Error(`${inv.fromPalletId} is not exist in inventory. Hence, qty cannot be updated.`)
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return inventories
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
//// @farishelmi What is the difference between upsertInventory vs temporaryUpsertInventory? If it is repeated function, kindly remove one of them.
|
|
353
|
+
export async function temporaryUpsertInventory(
|
|
354
|
+
trxMgr: EntityManager,
|
|
355
|
+
domain: Domain,
|
|
356
|
+
bizplace: Bizplace,
|
|
357
|
+
user: User,
|
|
358
|
+
originInv: Inventory,
|
|
359
|
+
refOrder: RefOrderType,
|
|
360
|
+
palletId: string,
|
|
361
|
+
locationName: string,
|
|
362
|
+
packingType: string,
|
|
363
|
+
addedQty: number,
|
|
364
|
+
addedUomValue: number,
|
|
365
|
+
transactionType: string,
|
|
366
|
+
stdAmount?: number,
|
|
367
|
+
packingUnit?: string
|
|
368
|
+
): Promise<Inventory> {
|
|
369
|
+
const location: Location = await trxMgr.getRepository(Location).findOne({
|
|
370
|
+
where: { domain, name: locationName },
|
|
371
|
+
relations: ['warehouse']
|
|
372
|
+
})
|
|
373
|
+
if (!location) throw new Error(`Location is not found by (${locationName})`)
|
|
374
|
+
const warehouse: Warehouse = location.warehouse
|
|
375
|
+
const zone: string = location.zone
|
|
376
|
+
|
|
377
|
+
let inv: Inventory = await trxMgr.getRepository(Inventory).findOne({
|
|
378
|
+
where: {
|
|
379
|
+
domain,
|
|
380
|
+
bizplace,
|
|
381
|
+
palletId,
|
|
382
|
+
batchId: originInv.batchId,
|
|
383
|
+
product: originInv.product,
|
|
384
|
+
packingType,
|
|
385
|
+
packingSize: stdAmount,
|
|
386
|
+
refOrderId: originInv.refOrderId,
|
|
387
|
+
status: Not(Equal(INVENTORY_STATUS.TERMINATED))
|
|
388
|
+
},
|
|
389
|
+
relations: ['product', 'refInventory']
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
// Create new inventory
|
|
393
|
+
if (!inv) {
|
|
394
|
+
let newInventory: Inventory = new Inventory()
|
|
395
|
+
|
|
396
|
+
inv = {
|
|
397
|
+
...newInventory,
|
|
398
|
+
domain,
|
|
399
|
+
bizplace,
|
|
400
|
+
palletId,
|
|
401
|
+
name: InventoryNoGenerator.inventoryName(),
|
|
402
|
+
packingType,
|
|
403
|
+
qty: addedQty,
|
|
404
|
+
weight: 0,
|
|
405
|
+
uomValue: addedUomValue,
|
|
406
|
+
lockedQty: 0,
|
|
407
|
+
lockedUomValue: 0,
|
|
408
|
+
packingSize: packingUnit == PackingUnits.QTY ? stdAmount : 1,
|
|
409
|
+
warehouse,
|
|
410
|
+
location,
|
|
411
|
+
zone,
|
|
412
|
+
creator: user,
|
|
413
|
+
updater: user
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Save changed inventory
|
|
417
|
+
inv = await trxMgr.getRepository(Inventory).save(inv)
|
|
418
|
+
|
|
419
|
+
// Check whether the pallet is resuable or not
|
|
420
|
+
const pallet: Pallet = await trxMgr.getRepository(Pallet).findOne({
|
|
421
|
+
where: { domain, name: palletId, inventory: IsNull() }
|
|
422
|
+
})
|
|
423
|
+
// If it's exists => it's reusable pallet and need to update it's inventory field
|
|
424
|
+
if (pallet) {
|
|
425
|
+
pallet.inventory = inv
|
|
426
|
+
pallet.updater = user
|
|
427
|
+
await trxMgr.getRepository(Pallet).save(pallet)
|
|
428
|
+
}
|
|
429
|
+
} else {
|
|
430
|
+
// Update inventory
|
|
431
|
+
inv.qty += addedQty
|
|
432
|
+
inv.uomValue += addedUomValue
|
|
433
|
+
inv.warehouse = warehouse
|
|
434
|
+
inv.location = location
|
|
435
|
+
inv.zone = location.zone
|
|
436
|
+
inv.updater = user
|
|
437
|
+
|
|
438
|
+
// Save changed inventory
|
|
439
|
+
inv = await trxMgr.getRepository(Inventory).save(inv)
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Create inventory history
|
|
443
|
+
await generateInventoryHistory(inv, refOrder, transactionType, addedQty, addedUomValue, user, trxMgr)
|
|
444
|
+
|
|
445
|
+
return inv
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
//// @farishelmi What is the difference between deductProductAmount vs temporaryDeductProductAmount? If it is repeated function, kindly remove one of them.
|
|
449
|
+
export async function temporaryDeductProductAmount(
|
|
450
|
+
trxMgr: EntityManager,
|
|
451
|
+
domain: Domain,
|
|
452
|
+
bizplace: Bizplace,
|
|
453
|
+
user: User,
|
|
454
|
+
refOrder: RefOrderType,
|
|
455
|
+
originInv: Inventory,
|
|
456
|
+
reducedQty: number,
|
|
457
|
+
reducedUomValue: number,
|
|
458
|
+
transactionType: string,
|
|
459
|
+
originalQty?: number,
|
|
460
|
+
originalUomValue?: number,
|
|
461
|
+
currentUnitQty?: number,
|
|
462
|
+
currentUomValue?: number
|
|
463
|
+
) {
|
|
464
|
+
if (refOrder instanceof ReleaseGood) {
|
|
465
|
+
const loadingWS: Worksheet = await trxMgr.getRepository(Worksheet).findOne({
|
|
466
|
+
where: { domain, bizplace, releaseGood: refOrder, type: WORKSHEET_TYPE.LOADING },
|
|
467
|
+
relations: ['worksheetDetails', 'worksheetDetails.targetInventory', 'worksheetDetails.targetInventory.inventory']
|
|
468
|
+
})
|
|
469
|
+
|
|
470
|
+
if (!loadingWS)
|
|
471
|
+
throw new Error(
|
|
472
|
+
`Picking process is not finished yet. Please complete picking first before complete Repalletizing`
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
let orderInv: OrderInventory = loadingWS.worksheetDetails
|
|
476
|
+
.map((wsd: WorksheetDetail) => wsd.targetInventory)
|
|
477
|
+
.find((oi: OrderInventory) => oi.inventory.id === originInv.id)
|
|
478
|
+
if (!orderInv) {
|
|
479
|
+
throw new Error(`Failed to find order inventory (Pallet ID: ${originInv.palletId})`)
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
orderInv.releaseQty -= reducedQty
|
|
483
|
+
orderInv.releaseUomValue -= reducedUomValue
|
|
484
|
+
orderInv.updater = user
|
|
485
|
+
|
|
486
|
+
await trxMgr.getRepository(OrderInventory).save(orderInv)
|
|
487
|
+
} else {
|
|
488
|
+
// currentUnitQty > 0 only belongs to PackingUnits.QTY
|
|
489
|
+
if (currentUnitQty > 0) {
|
|
490
|
+
const unitUomValue: number = originInv.uomValue / originInv.qty
|
|
491
|
+
|
|
492
|
+
reducedQty = Math.floor((originalQty * originInv.packingSize - currentUnitQty) / originInv.packingSize)
|
|
493
|
+
reducedUomValue = unitUomValue * reducedQty
|
|
494
|
+
|
|
495
|
+
originInv.qty -= reducedQty
|
|
496
|
+
originInv.uomValue -= reducedUomValue
|
|
497
|
+
originInv.lockedQty -= originalQty
|
|
498
|
+
originInv.lockedUomValue -= originalUomValue
|
|
499
|
+
originInv.updater = user
|
|
500
|
+
|
|
501
|
+
originInv = await trxMgr.getRepository(Inventory).save(originInv)
|
|
502
|
+
await generateInventoryHistory(originInv, refOrder, transactionType, -reducedQty, -reducedUomValue, user, trxMgr)
|
|
503
|
+
|
|
504
|
+
// minus 1 because remain unit qty only exist if the unitQty < 1
|
|
505
|
+
if (originInv.qty - 1 == 0) {
|
|
506
|
+
originInv.status = INVENTORY_STATUS.TERMINATED
|
|
507
|
+
originInv.qty = 0
|
|
508
|
+
originInv.uomValue = 0
|
|
509
|
+
originInv = await trxMgr.getRepository(Inventory).save(originInv)
|
|
510
|
+
await generateInventoryHistory(originInv, refOrder, transactionType, -1, -unitUomValue, user, trxMgr)
|
|
511
|
+
|
|
512
|
+
const newQty: number = currentUnitQty
|
|
513
|
+
const newUomValue: number = (unitUomValue / originInv.packingSize) * newQty
|
|
514
|
+
|
|
515
|
+
originInv.qty = newQty
|
|
516
|
+
originInv.uomValue = newUomValue
|
|
517
|
+
originInv.packingSize = 1
|
|
518
|
+
originInv.status = INVENTORY_STATUS.STORED
|
|
519
|
+
originInv = await trxMgr.getRepository(Inventory).save(originInv)
|
|
520
|
+
await generateInventoryHistory(originInv, refOrder, transactionType, newQty, newUomValue, user, trxMgr)
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// currentUnitUomValue > 0 only belongs to PackingUnits.QTY
|
|
524
|
+
} else if (currentUomValue > 0) {
|
|
525
|
+
reducedUomValue = Math.round((originalUomValue - currentUomValue + Number.EPSILON) * 100) / 100
|
|
526
|
+
|
|
527
|
+
originInv.qty -= reducedQty
|
|
528
|
+
originInv.uomValue -= reducedUomValue
|
|
529
|
+
originInv.lockedQty -= originalQty
|
|
530
|
+
originInv.lockedUomValue -= originalUomValue
|
|
531
|
+
originInv.updater = user
|
|
532
|
+
|
|
533
|
+
originInv = await trxMgr.getRepository(Inventory).save(originInv)
|
|
534
|
+
await generateInventoryHistory(originInv, refOrder, transactionType, -reducedQty, -reducedUomValue, user, trxMgr)
|
|
535
|
+
} else {
|
|
536
|
+
originInv.qty -= reducedQty
|
|
537
|
+
originInv.uomValue -= reducedUomValue
|
|
538
|
+
originInv.lockedQty -= originalQty
|
|
539
|
+
originInv.lockedUomValue -= originalUomValue
|
|
540
|
+
originInv.updater = user
|
|
541
|
+
originInv.status = originInv.qty > 0 ? INVENTORY_STATUS.STORED : INVENTORY_STATUS.TERMINATED
|
|
542
|
+
|
|
543
|
+
originInv = await trxMgr.getRepository(Inventory).save(originInv)
|
|
544
|
+
await generateInventoryHistory(originInv, refOrder, transactionType, -reducedQty, -reducedUomValue, user, trxMgr)
|
|
545
|
+
|
|
546
|
+
if (originInv.qty <= 0 || originInv.uomValue <= 0) {
|
|
547
|
+
originInv.status = INVENTORY_STATUS.TERMINATED
|
|
548
|
+
originInv = await trxMgr.getRepository(Inventory).save(originInv)
|
|
549
|
+
await generateInventoryHistory(originInv, refOrder, INVENTORY_TRANSACTION_TYPE.TERMINATED, 0, 0, user, trxMgr)
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
return originInv
|
|
555
|
+
}
|
|
556
|
+
|
|
187
557
|
/**
|
|
188
558
|
* @description Assign inventory to targetVas
|
|
189
559
|
* When Vas order comes together with Arrival Notice or Release Good
|
|
@@ -375,7 +745,9 @@ export async function upsertInventory(
|
|
|
375
745
|
packingType: string,
|
|
376
746
|
addedQty: number,
|
|
377
747
|
addedUomValue: number,
|
|
378
|
-
transactionType: string
|
|
748
|
+
transactionType: string,
|
|
749
|
+
stdAmount?: number,
|
|
750
|
+
packingUnit?: string
|
|
379
751
|
): Promise<Inventory> {
|
|
380
752
|
const location: Location = await trxMgr.getRepository(Location).findOne({
|
|
381
753
|
where: { domain, name: locationName },
|
|
@@ -393,6 +765,7 @@ export async function upsertInventory(
|
|
|
393
765
|
batchId: originInv.batchId,
|
|
394
766
|
product: originInv.product,
|
|
395
767
|
packingType,
|
|
768
|
+
packingSize: stdAmount,
|
|
396
769
|
refOrderId: originInv.refOrderId,
|
|
397
770
|
status: Not(Equal(INVENTORY_STATUS.TERMINATED))
|
|
398
771
|
},
|
|
@@ -412,8 +785,11 @@ export async function upsertInventory(
|
|
|
412
785
|
name: InventoryNoGenerator.inventoryName(),
|
|
413
786
|
packingType,
|
|
414
787
|
qty: addedQty,
|
|
415
|
-
weight:0,
|
|
788
|
+
weight: 0,
|
|
416
789
|
uomValue: addedUomValue,
|
|
790
|
+
lockedQty: 0,
|
|
791
|
+
lockedUomValue: 0,
|
|
792
|
+
packingSize: packingUnit == PackingUnits.QTY ? stdAmount : 1,
|
|
417
793
|
warehouse,
|
|
418
794
|
location,
|
|
419
795
|
zone,
|
|
@@ -462,7 +838,11 @@ export async function deductProductAmount(
|
|
|
462
838
|
originInv: Inventory,
|
|
463
839
|
reducedQty: number,
|
|
464
840
|
reducedUomValue: number,
|
|
465
|
-
transactionType: string
|
|
841
|
+
transactionType: string,
|
|
842
|
+
originalQty?: number,
|
|
843
|
+
originalUomValue?: number,
|
|
844
|
+
currentUnitQty?: number,
|
|
845
|
+
currentUomValue?: number
|
|
466
846
|
) {
|
|
467
847
|
if (refOrder instanceof ReleaseGood) {
|
|
468
848
|
const loadingWS: Worksheet = await trxMgr.getRepository(Worksheet).findOne({
|
|
@@ -488,14 +868,72 @@ export async function deductProductAmount(
|
|
|
488
868
|
|
|
489
869
|
await trxMgr.getRepository(OrderInventory).save(orderInv)
|
|
490
870
|
} else {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
871
|
+
// currentUnitQty > 0 only belongs to PackingUnits.QTY
|
|
872
|
+
if (currentUnitQty > 0) {
|
|
873
|
+
const unitUomValue: number = originInv.uomValue / originInv.qty
|
|
874
|
+
|
|
875
|
+
reducedQty = Math.floor((originalQty * originInv.packingSize - currentUnitQty) / originInv.packingSize)
|
|
876
|
+
reducedUomValue = unitUomValue * reducedQty
|
|
495
877
|
|
|
496
|
-
|
|
497
|
-
|
|
878
|
+
originInv.qty -= reducedQty
|
|
879
|
+
originInv.uomValue -= reducedUomValue
|
|
880
|
+
originInv.lockedQty -= reducedQty
|
|
881
|
+
originInv.lockedUomValue -= reducedUomValue
|
|
882
|
+
originInv.updater = user
|
|
883
|
+
|
|
884
|
+
originInv = await trxMgr.getRepository(Inventory).save(originInv)
|
|
885
|
+
await generateInventoryHistory(originInv, refOrder, transactionType, -reducedQty, -reducedUomValue, user, trxMgr)
|
|
886
|
+
|
|
887
|
+
// minus 1 because remain unit qty only exist if the unitQty < 1
|
|
888
|
+
if (originInv.qty - 1 == 0) {
|
|
889
|
+
originInv.status = INVENTORY_STATUS.TERMINATED
|
|
890
|
+
originInv.qty = 0
|
|
891
|
+
originInv.uomValue = 0
|
|
892
|
+
originInv = await trxMgr.getRepository(Inventory).save(originInv)
|
|
893
|
+
await generateInventoryHistory(originInv, refOrder, transactionType, -1, -unitUomValue, user, trxMgr)
|
|
894
|
+
|
|
895
|
+
const newQty: number = currentUnitQty
|
|
896
|
+
const newUomValue: number = (unitUomValue / originInv.packingSize) * newQty
|
|
897
|
+
|
|
898
|
+
originInv.qty = newQty
|
|
899
|
+
originInv.uomValue = newUomValue
|
|
900
|
+
originInv.packingSize = 1
|
|
901
|
+
originInv.status = INVENTORY_STATUS.STORED
|
|
902
|
+
originInv = await trxMgr.getRepository(Inventory).save(originInv)
|
|
903
|
+
await generateInventoryHistory(originInv, refOrder, transactionType, newQty, newUomValue, user, trxMgr)
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// currentUnitUomValue > 0 only belongs to PackingUnits.UOM
|
|
907
|
+
} else if (currentUomValue > 0) {
|
|
908
|
+
reducedUomValue = Math.round((originalUomValue - currentUomValue + Number.EPSILON) * 100) / 100
|
|
909
|
+
|
|
910
|
+
originInv.qty -= reducedQty
|
|
911
|
+
originInv.uomValue -= reducedUomValue
|
|
912
|
+
originInv.lockedQty -= reducedQty
|
|
913
|
+
originInv.lockedUomValue -= reducedUomValue
|
|
914
|
+
originInv.updater = user
|
|
915
|
+
|
|
916
|
+
originInv = await trxMgr.getRepository(Inventory).save(originInv)
|
|
917
|
+
await generateInventoryHistory(originInv, refOrder, transactionType, -reducedQty, -reducedUomValue, user, trxMgr)
|
|
918
|
+
} else {
|
|
919
|
+
originInv.qty -= reducedQty
|
|
920
|
+
originInv.uomValue -= reducedUomValue
|
|
921
|
+
originInv.lockedQty -= reducedQty
|
|
922
|
+
originInv.lockedUomValue -= reducedUomValue
|
|
923
|
+
originInv.updater = user
|
|
924
|
+
originInv.status = originInv.qty > 0 ? INVENTORY_STATUS.STORED : INVENTORY_STATUS.TERMINATED
|
|
925
|
+
|
|
926
|
+
originInv = await trxMgr.getRepository(Inventory).save(originInv)
|
|
927
|
+
await generateInventoryHistory(originInv, refOrder, transactionType, -reducedQty, -reducedUomValue, user, trxMgr)
|
|
928
|
+
|
|
929
|
+
if (originInv.qty <= 0 || originInv.uomValue <= 0) {
|
|
930
|
+
originInv.status = INVENTORY_STATUS.TERMINATED
|
|
931
|
+
originInv = await trxMgr.getRepository(Inventory).save(originInv)
|
|
932
|
+
await generateInventoryHistory(originInv, refOrder, INVENTORY_TRANSACTION_TYPE.TERMINATED, 0, 0, user, trxMgr)
|
|
933
|
+
}
|
|
934
|
+
}
|
|
498
935
|
}
|
|
936
|
+
|
|
499
937
|
return originInv
|
|
500
938
|
}
|
|
501
939
|
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ArrivalNotice,
|
|
3
|
+
ReleaseGood,
|
|
4
|
+
ShippingOrder,
|
|
5
|
+
VasOrder
|
|
6
|
+
} from '@things-factory/sales-base'
|
|
2
7
|
|
|
3
8
|
export * from './repalletizing'
|
|
4
9
|
export * from './repackaging'
|
|
@@ -19,3 +24,33 @@ export interface PalletChangesInterface {
|
|
|
19
24
|
reducedUomValue: number
|
|
20
25
|
locationName?: string
|
|
21
26
|
}
|
|
27
|
+
|
|
28
|
+
export interface FeaturedInventoryInterface {
|
|
29
|
+
palletId: string
|
|
30
|
+
originalQty: number
|
|
31
|
+
originalUomValue: number
|
|
32
|
+
currentUnitQty?: number
|
|
33
|
+
currentUomValue?: number
|
|
34
|
+
packingSize: number
|
|
35
|
+
uomValuePerQty: number
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** REMARK
|
|
39
|
+
* @farishelmi created this temporary interface solely for @Repackaging
|
|
40
|
+
* - because in repackaging we need to calculate based on unit qty of a product
|
|
41
|
+
* - eg: Carton of 12 Cokes repack into Boxes of 6 Cokes
|
|
42
|
+
* - this interface should be merged with its origin once the logic in other vas is updated
|
|
43
|
+
* */
|
|
44
|
+
export interface TemporaryPalletChangesInterface {
|
|
45
|
+
fromPalletId: string
|
|
46
|
+
toPalletId: string
|
|
47
|
+
reducedQty?: number
|
|
48
|
+
reducedUomValue?: number
|
|
49
|
+
reducedUnitQty?: number
|
|
50
|
+
originalQty?: number
|
|
51
|
+
originalUomValue?: number
|
|
52
|
+
currentUnitQty?: number
|
|
53
|
+
currentUomValue?: number
|
|
54
|
+
locationName?: string
|
|
55
|
+
packingSize: number
|
|
56
|
+
}
|
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Inventory } from '@things-factory/warehouse-base'
|
|
2
|
+
|
|
3
|
+
import { TemporaryPalletChangesInterface } from './index'
|
|
2
4
|
|
|
3
5
|
export interface RepackedInvInfo {
|
|
4
6
|
palletId: string
|
|
5
7
|
locationName: string
|
|
6
8
|
repackedPkgQty: number
|
|
7
|
-
repackedFrom:
|
|
9
|
+
repackedFrom: TemporaryPalletChangesInterface[]
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
export interface RepackagingGuide {
|
|
11
13
|
packingUnit: string
|
|
14
|
+
toProduct?: string
|
|
15
|
+
toBatchId?: string
|
|
12
16
|
toPackingType: string
|
|
13
17
|
stdAmount: number
|
|
14
18
|
requiredPackageQty: number
|
|
15
19
|
repackedInvs: RepackedInvInfo[]
|
|
20
|
+
featuredInvs: Partial<Inventory[]>
|
|
21
|
+
remainder: number
|
|
16
22
|
}
|
|
17
23
|
|
|
18
24
|
export enum PackingUnits {
|