@things-factory/worksheet-base 4.3.356 → 4.3.357
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 +2 -1
- package/dist-server/constants/worksheet.js.map +1 -1
- package/dist-server/controllers/inspect/cycle-count-worksheet-controller.js +691 -257
- package/dist-server/controllers/inspect/cycle-count-worksheet-controller.js.map +1 -1
- package/dist-server/controllers/outbound/picking-worksheet-controller.js +76 -0
- package/dist-server/controllers/outbound/picking-worksheet-controller.js.map +1 -1
- package/dist-server/controllers/worksheet-controller.js +9 -2
- package/dist-server/controllers/worksheet-controller.js.map +1 -1
- package/dist-server/entities/worksheet-detail.js +9 -4
- package/dist-server/entities/worksheet-detail.js.map +1 -1
- package/dist-server/entities/worksheet.js +4 -0
- package/dist-server/entities/worksheet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/check-stock-take-current-location.js +18 -11
- package/dist-server/graphql/resolvers/worksheet/check-stock-take-current-location.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/cycle-count-adjustment.js +75 -48
- package/dist-server/graphql/resolvers/worksheet/cycle-count-adjustment.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/cycle-count-worksheet-for-carton.js +82 -0
- package/dist-server/graphql/resolvers/worksheet/cycle-count-worksheet-for-carton.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/cycle-count-worksheet-for-pallet.js +82 -0
- package/dist-server/graphql/resolvers/worksheet/cycle-count-worksheet-for-pallet.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/generate-worksheet/generate-cycle-count-worksheet-carton.js +17 -0
- package/dist-server/graphql/resolvers/worksheet/generate-worksheet/generate-cycle-count-worksheet-carton.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/generate-worksheet/generate-cycle-count-worksheet.js +4 -4
- package/dist-server/graphql/resolvers/worksheet/generate-worksheet/generate-cycle-count-worksheet.js.map +1 -1
- 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 +3 -2
- package/dist-server/graphql/resolvers/worksheet/index.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/inspecting/add-extra-inventory.js +16 -0
- package/dist-server/graphql/resolvers/worksheet/inspecting/add-extra-inventory.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/inspecting/check-missing-inventory-carton.js +16 -0
- package/dist-server/graphql/resolvers/worksheet/inspecting/check-missing-inventory-carton.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/inspecting/check-missing-inventory.js +16 -0
- package/dist-server/graphql/resolvers/worksheet/inspecting/check-missing-inventory.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/inspecting/index.js +9 -5
- package/dist-server/graphql/resolvers/worksheet/inspecting/index.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/inspecting/inspecting-carton.js +16 -0
- package/dist-server/graphql/resolvers/worksheet/inspecting/inspecting-carton.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/inspecting/inspecting-pallet.js +16 -0
- package/dist-server/graphql/resolvers/worksheet/inspecting/inspecting-pallet.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/inspecting/relocate-inventory-carton.js +16 -0
- package/dist-server/graphql/resolvers/worksheet/inspecting/relocate-inventory-carton.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/inspecting/relocate-inventory.js +16 -0
- package/dist-server/graphql/resolvers/worksheet/inspecting/relocate-inventory.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/inspecting/undo-inspection-carton.js +16 -0
- package/dist-server/graphql/resolvers/worksheet/inspecting/undo-inspection-carton.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/not-tally-target-inventories.js +9 -5
- package/dist-server/graphql/resolvers/worksheet/not-tally-target-inventories.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/worksheet-with-pagination.js +9 -7
- package/dist-server/graphql/resolvers/worksheet/worksheet-with-pagination.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/worksheets.js +23 -9
- package/dist-server/graphql/resolvers/worksheet/worksheets.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet-detail/create-worksheet-detail.js +8 -1
- package/dist-server/graphql/resolvers/worksheet-detail/create-worksheet-detail.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet-detail/worksheet-detail.js +12 -1
- package/dist-server/graphql/resolvers/worksheet-detail/worksheet-detail.js.map +1 -1
- package/dist-server/graphql/types/worksheet/index.js +65 -9
- package/dist-server/graphql/types/worksheet/index.js.map +1 -1
- package/dist-server/graphql/types/worksheet/inventory-check-worksheet.js +2 -1
- package/dist-server/graphql/types/worksheet/inventory-check-worksheet.js.map +1 -1
- package/dist-server/graphql/types/worksheet/worksheet-detail-info.js +3 -0
- package/dist-server/graphql/types/worksheet/worksheet-detail-info.js.map +1 -1
- package/dist-server/graphql/types/worksheet/worksheet.js +2 -0
- package/dist-server/graphql/types/worksheet/worksheet.js.map +1 -1
- package/dist-server/graphql/types/worksheet-detail/new-worksheet-detail.js +1 -0
- package/dist-server/graphql/types/worksheet-detail/new-worksheet-detail.js.map +1 -1
- package/dist-server/graphql/types/worksheet-detail/worksheet-detail-patch.js +1 -0
- package/dist-server/graphql/types/worksheet-detail/worksheet-detail-patch.js.map +1 -1
- package/dist-server/graphql/types/worksheet-detail/worksheet-detail.js +1 -0
- package/dist-server/graphql/types/worksheet-detail/worksheet-detail.js.map +1 -1
- package/package.json +6 -6
- package/server/constants/worksheet.ts +2 -1
- package/server/controllers/inspect/cycle-count-worksheet-controller.ts +904 -296
- package/server/controllers/outbound/picking-worksheet-controller.ts +95 -1
- package/server/controllers/worksheet-controller.ts +10 -4
- package/server/entities/worksheet-detail.ts +7 -10
- package/server/entities/worksheet.ts +3 -0
- package/server/graphql/resolvers/worksheet/check-stock-take-current-location.ts +21 -14
- package/server/graphql/resolvers/worksheet/cycle-count-adjustment.ts +114 -51
- package/server/graphql/resolvers/worksheet/cycle-count-worksheet-for-carton.ts +90 -0
- package/server/graphql/resolvers/worksheet/cycle-count-worksheet-for-pallet.ts +91 -0
- package/server/graphql/resolvers/worksheet/generate-worksheet/generate-cycle-count-worksheet-carton.ts +57 -0
- package/server/graphql/resolvers/worksheet/generate-worksheet/generate-cycle-count-worksheet.ts +17 -11
- package/server/graphql/resolvers/worksheet/generate-worksheet/index.ts +2 -0
- package/server/graphql/resolvers/worksheet/index.ts +4 -2
- package/server/graphql/resolvers/worksheet/inspecting/{add-extra-pallet.ts → add-extra-inventory.ts} +27 -12
- package/server/graphql/resolvers/worksheet/inspecting/check-missing-inventory-carton.ts +24 -0
- package/server/graphql/resolvers/worksheet/inspecting/{check-missing-pallet.ts → check-missing-inventory.ts} +10 -5
- package/server/graphql/resolvers/worksheet/inspecting/index.ts +17 -9
- package/server/graphql/resolvers/worksheet/inspecting/inspecting-carton.ts +51 -0
- package/server/graphql/resolvers/worksheet/inspecting/{inspecting.ts → inspecting-pallet.ts} +5 -5
- package/server/graphql/resolvers/worksheet/inspecting/relocate-inventory-carton.ts +62 -0
- package/server/graphql/resolvers/worksheet/inspecting/{relocate-pallet.ts → relocate-inventory.ts} +15 -5
- package/server/graphql/resolvers/worksheet/inspecting/undo-inspection-carton.ts +24 -0
- package/server/graphql/resolvers/worksheet/not-tally-target-inventories.ts +11 -7
- package/server/graphql/resolvers/worksheet/worksheet-with-pagination.ts +9 -7
- package/server/graphql/resolvers/worksheet/worksheets.ts +57 -38
- package/server/graphql/resolvers/worksheet-detail/create-worksheet-detail.ts +10 -2
- package/server/graphql/resolvers/worksheet-detail/worksheet-detail.ts +12 -1
- package/server/graphql/types/worksheet/index.ts +65 -9
- package/server/graphql/types/worksheet/inventory-check-worksheet.ts +2 -1
- package/server/graphql/types/worksheet/worksheet-detail-info.ts +3 -0
- package/server/graphql/types/worksheet/worksheet.ts +2 -0
- package/server/graphql/types/worksheet-detail/new-worksheet-detail.ts +1 -0
- package/server/graphql/types/worksheet-detail/worksheet-detail-patch.ts +1 -0
- package/server/graphql/types/worksheet-detail/worksheet-detail.ts +1 -0
- package/tsconfig.json +1 -1
- package/dist-server/graphql/resolvers/worksheet/cycle-count-worksheet.js +0 -74
- package/dist-server/graphql/resolvers/worksheet/cycle-count-worksheet.js.map +0 -1
- package/dist-server/graphql/resolvers/worksheet/inspecting/add-extra-pallet.js +0 -16
- package/dist-server/graphql/resolvers/worksheet/inspecting/add-extra-pallet.js.map +0 -1
- package/dist-server/graphql/resolvers/worksheet/inspecting/check-missing-pallet.js +0 -16
- package/dist-server/graphql/resolvers/worksheet/inspecting/check-missing-pallet.js.map +0 -1
- package/dist-server/graphql/resolvers/worksheet/inspecting/inspecting.js +0 -16
- package/dist-server/graphql/resolvers/worksheet/inspecting/inspecting.js.map +0 -1
- package/dist-server/graphql/resolvers/worksheet/inspecting/relocate-pallet.js +0 -16
- package/dist-server/graphql/resolvers/worksheet/inspecting/relocate-pallet.js.map +0 -1
- package/server/graphql/resolvers/worksheet/cycle-count-worksheet.ts +0 -80
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import { Brackets, Equal, In, Not, SelectQueryBuilder } from 'typeorm'
|
|
1
|
+
import { Brackets, Equal, In, Not, SelectQueryBuilder, MoreThan } from 'typeorm'
|
|
2
2
|
|
|
3
3
|
import { Bizplace } from '@things-factory/biz-base'
|
|
4
4
|
import {
|
|
5
5
|
generateCycleCount,
|
|
6
6
|
InventoryCheck,
|
|
7
|
-
|
|
7
|
+
InventoryCheckItem,
|
|
8
8
|
ORDER_STATUS,
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
OrderNoGenerator,
|
|
10
|
+
INVENTORY_CHECK_ITEM_STATUS
|
|
11
11
|
} from '@things-factory/sales-base'
|
|
12
|
-
import { Inventory, INVENTORY_STATUS, Location } from '@things-factory/warehouse-base'
|
|
12
|
+
import { Inventory, INVENTORY_STATUS, Location, InventoryNoGenerator, Warehouse } from '@things-factory/warehouse-base'
|
|
13
|
+
import { ProductDetail, Product } from '@things-factory/product-base'
|
|
14
|
+
import { PartnerSetting, Setting } from '@things-factory/setting-base'
|
|
15
|
+
import { generateId } from '@things-factory/id-rule-base'
|
|
13
16
|
|
|
14
17
|
import { WORKSHEET_STATUS, WORKSHEET_TYPE } from '../../constants'
|
|
15
18
|
import { Worksheet, WorksheetDetail } from '../../entities'
|
|
@@ -17,194 +20,388 @@ import { WorksheetNoGenerator } from '../../utils'
|
|
|
17
20
|
import { WorksheetController } from '../worksheet-controller'
|
|
18
21
|
|
|
19
22
|
export class CycleCountWorksheetController extends WorksheetController {
|
|
23
|
+
private async createCycleCountWorksheet(
|
|
24
|
+
customerBizplace: Bizplace,
|
|
25
|
+
customerId: string,
|
|
26
|
+
executionDate: string,
|
|
27
|
+
inventoryCheckItem: InventoryCheckItem[],
|
|
28
|
+
selectedLocation: string[],
|
|
29
|
+
limit: number
|
|
30
|
+
): Promise<Worksheet> {
|
|
31
|
+
const cycleCount: InventoryCheck = await generateCycleCount(
|
|
32
|
+
this.trxMgr,
|
|
33
|
+
this.domain,
|
|
34
|
+
this.user,
|
|
35
|
+
executionDate,
|
|
36
|
+
customerId
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
// Find out inventories which is target for cycle counting
|
|
40
|
+
const qb: SelectQueryBuilder<Inventory> = this.trxMgr.getRepository(Inventory).createQueryBuilder('INV')
|
|
41
|
+
qb.leftJoinAndSelect('INV.location', 'LOC')
|
|
42
|
+
.leftJoinAndSelect('INV.product', 'PROD')
|
|
43
|
+
.leftJoinAndSelect('INV.productDetail', 'PD')
|
|
44
|
+
.where('INV.domain_id = :domainId', { domainId: this.domain.id })
|
|
45
|
+
.andWhere('INV.bizplace_id = :bizplaceId', { bizplaceId: customerBizplace.id })
|
|
46
|
+
.andWhere('INV.status = :status', { status: INVENTORY_STATUS.STORED })
|
|
47
|
+
|
|
48
|
+
if (inventoryCheckItem && inventoryCheckItem.length > 0) {
|
|
49
|
+
let keyval = {
|
|
50
|
+
batchId: 'batch_id',
|
|
51
|
+
batchIdRef: 'batch_id_ref',
|
|
52
|
+
productDetailId: 'product_detail_id'
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
qb.andWhere(
|
|
56
|
+
new Brackets(qb => {
|
|
57
|
+
inventoryCheckItem.forEach((itm, idx) => {
|
|
58
|
+
qb.orWhere(
|
|
59
|
+
new Brackets(qb2 => {
|
|
60
|
+
let first = true
|
|
61
|
+
for (var prop in itm) {
|
|
62
|
+
if (first) {
|
|
63
|
+
first = false
|
|
64
|
+
qb2.where(`INV.${keyval[prop]} ${itm[prop] == null ? 'is null' : " = '" + itm[prop] + "'"}`)
|
|
65
|
+
} else {
|
|
66
|
+
qb2.andWhere(`INV.${keyval[prop]} ${itm[prop] == null ? 'is null' : " = '" + itm[prop] + "'"}`)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
)
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
)
|
|
74
|
+
} else if (selectedLocation && selectedLocation.length > 0) {
|
|
75
|
+
// If selectedLocation is provided
|
|
76
|
+
// Query inventory items located at the selected location
|
|
77
|
+
qb.andWhere('INV.location_id IN (:...locationIds)', { locationIds: selectedLocation })
|
|
78
|
+
} else {
|
|
79
|
+
if (limit > 0) {
|
|
80
|
+
qb.orderBy('RANDOM()').limit(limit)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let inventories: Inventory[] = await qb.getMany()
|
|
85
|
+
|
|
86
|
+
if (!inventories.length) {
|
|
87
|
+
throw new Error(`Failed to find inventories`)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let cycleCountWorksheet: Worksheet = new Worksheet()
|
|
91
|
+
cycleCountWorksheet.domain = this.domain
|
|
92
|
+
cycleCountWorksheet.bizplace = customerBizplace
|
|
93
|
+
cycleCountWorksheet.name = WorksheetNoGenerator.cycleCount()
|
|
94
|
+
cycleCountWorksheet.inventoryCheck = cycleCount
|
|
95
|
+
cycleCountWorksheet.type = WORKSHEET_TYPE.CYCLE_COUNT
|
|
96
|
+
cycleCountWorksheet.status = WORKSHEET_STATUS.DEACTIVATED
|
|
97
|
+
cycleCountWorksheet.checkCount = 1
|
|
98
|
+
cycleCountWorksheet.creator = this.user
|
|
99
|
+
cycleCountWorksheet.updater = this.user
|
|
100
|
+
cycleCountWorksheet = await this.trxMgr.getRepository(Worksheet).save(cycleCountWorksheet)
|
|
101
|
+
|
|
102
|
+
// generate order inventory mapping with inventory ID
|
|
103
|
+
let targetInventoryCheckItems: InventoryCheckItem[] = []
|
|
104
|
+
for (let i: number = 0; i < inventories.length; i++) {
|
|
105
|
+
const inventory: Inventory = inventories[i]
|
|
106
|
+
|
|
107
|
+
let targetInventoryCheckItem: InventoryCheckItem = new InventoryCheckItem()
|
|
108
|
+
targetInventoryCheckItem.domain = this.domain
|
|
109
|
+
targetInventoryCheckItem.bizplace = customerBizplace
|
|
110
|
+
targetInventoryCheckItem.status = INVENTORY_CHECK_ITEM_STATUS.PENDING
|
|
111
|
+
targetInventoryCheckItem.name = OrderNoGenerator.inventoryCheckItem()
|
|
112
|
+
targetInventoryCheckItem.inventoryCheck = cycleCount
|
|
113
|
+
targetInventoryCheckItem.originQty = inventory.qty
|
|
114
|
+
targetInventoryCheckItem.originWeight = 0
|
|
115
|
+
targetInventoryCheckItem.originUomValue = inventory.uomValue
|
|
116
|
+
targetInventoryCheckItem.originBatchNo = inventory.batchId
|
|
117
|
+
targetInventoryCheckItem.originLocation = inventory.location
|
|
118
|
+
targetInventoryCheckItem.inventory = inventory
|
|
119
|
+
targetInventoryCheckItem.product = inventory.product
|
|
120
|
+
targetInventoryCheckItem.productDetail = inventory.productDetail
|
|
121
|
+
targetInventoryCheckItem.countNo = 1
|
|
122
|
+
targetInventoryCheckItem.creator = this.user
|
|
123
|
+
targetInventoryCheckItem.updater = this.user
|
|
124
|
+
targetInventoryCheckItems.push(targetInventoryCheckItem)
|
|
125
|
+
|
|
126
|
+
inventory.updater = this.user
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
targetInventoryCheckItems = await this.trxMgr
|
|
130
|
+
.getRepository(InventoryCheckItem)
|
|
131
|
+
.save(targetInventoryCheckItems, { chunk: 500 })
|
|
132
|
+
|
|
133
|
+
inventories = await this.trxMgr.getRepository(Inventory).save(inventories, { chunk: 500 })
|
|
134
|
+
|
|
135
|
+
let cycleCountWorksheetDetails: WorksheetDetail[] = []
|
|
136
|
+
for (let i: number = 0; i < targetInventoryCheckItems.length; i++) {
|
|
137
|
+
let targetInventoryCheckItem: InventoryCheckItem = targetInventoryCheckItems[i]
|
|
138
|
+
|
|
139
|
+
let cycleCountWorksheetDetail: WorksheetDetail = new WorksheetDetail()
|
|
140
|
+
cycleCountWorksheetDetail.domain = this.domain
|
|
141
|
+
cycleCountWorksheetDetail.bizplace = customerBizplace
|
|
142
|
+
cycleCountWorksheetDetail.worksheet = cycleCountWorksheet
|
|
143
|
+
cycleCountWorksheetDetail.name = WorksheetNoGenerator.cycleCountDetail()
|
|
144
|
+
cycleCountWorksheetDetail.targetInventoryCheckItem = targetInventoryCheckItem
|
|
145
|
+
cycleCountWorksheetDetail.type = WORKSHEET_TYPE.CYCLE_COUNT
|
|
146
|
+
cycleCountWorksheetDetail.status = WORKSHEET_STATUS.DEACTIVATED
|
|
147
|
+
cycleCountWorksheetDetail.creator = this.user
|
|
148
|
+
cycleCountWorksheetDetail.updater = this.user
|
|
149
|
+
|
|
150
|
+
cycleCountWorksheetDetails.push(cycleCountWorksheetDetail)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
await this.trxMgr.getRepository(WorksheetDetail).save(cycleCountWorksheetDetails, { chunk: 500 })
|
|
154
|
+
|
|
155
|
+
return cycleCountWorksheet
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private async createNextRoundCycleCountWorksheet(
|
|
159
|
+
customerId: string,
|
|
160
|
+
existingInventoryCheck: InventoryCheck,
|
|
161
|
+
nextExecutionDate: string,
|
|
162
|
+
currentCycleCountWorksheet: Worksheet,
|
|
163
|
+
inventoryCheckItemIds: string[]
|
|
164
|
+
): Promise<Worksheet> {
|
|
165
|
+
try {
|
|
166
|
+
// Step 1: Create a new cycle count worksheet for the next round
|
|
167
|
+
let nextRoundWorksheet: Worksheet = new Worksheet()
|
|
168
|
+
Object.assign(nextRoundWorksheet, currentCycleCountWorksheet)
|
|
169
|
+
nextRoundWorksheet.id = undefined
|
|
170
|
+
nextRoundWorksheet.domain = this.domain
|
|
171
|
+
nextRoundWorksheet.bizplace = customerId
|
|
172
|
+
nextRoundWorksheet.name = WorksheetNoGenerator.cycleCount()
|
|
173
|
+
nextRoundWorksheet.status = WORKSHEET_STATUS.EXECUTING
|
|
174
|
+
nextRoundWorksheet.endedAt = null
|
|
175
|
+
nextRoundWorksheet.updater = this.user
|
|
176
|
+
nextRoundWorksheet.worksheetDetails = null
|
|
177
|
+
nextRoundWorksheet.checkCount = currentCycleCountWorksheet.checkCount + 1
|
|
178
|
+
nextRoundWorksheet.inventoryCheck = existingInventoryCheck
|
|
179
|
+
nextRoundWorksheet.type = WORKSHEET_TYPE.CYCLE_COUNT
|
|
180
|
+
|
|
181
|
+
// Step 2: Save the new Worksheet
|
|
182
|
+
await this.trxMgr.getRepository(Worksheet).save(nextRoundWorksheet)
|
|
183
|
+
|
|
184
|
+
// Step 3: Fetch current InventoryCheckItems
|
|
185
|
+
const currentInventoryCheckItems: InventoryCheckItem[] = await this.trxMgr
|
|
186
|
+
.getRepository(InventoryCheckItem)
|
|
187
|
+
.findByIds(inventoryCheckItemIds)
|
|
188
|
+
|
|
189
|
+
// Step 4: Create new InventoryCheckItems based on the current ones
|
|
190
|
+
const nextRoundInventoryCheckItems = currentInventoryCheckItems.map(currentItem => {
|
|
191
|
+
let nextRoundItem: InventoryCheckItem = new InventoryCheckItem()
|
|
192
|
+
|
|
193
|
+
Object.assign(nextRoundItem, currentItem)
|
|
194
|
+
nextRoundItem.id = undefined
|
|
195
|
+
nextRoundItem.domain = this.domain
|
|
196
|
+
nextRoundItem.bizplace = customerId
|
|
197
|
+
nextRoundItem.inventoryCheck = currentItem.inventoryCheckId
|
|
198
|
+
nextRoundItem.status = INVENTORY_CHECK_ITEM_STATUS.INSPECTING
|
|
199
|
+
nextRoundItem.name = OrderNoGenerator.inventoryCheckItem()
|
|
200
|
+
nextRoundItem.originQty = currentItem.inspectedQty || currentItem.originQty
|
|
201
|
+
nextRoundItem.originUomValue = currentItem.inspectedUomValue || currentItem.originUomValue
|
|
202
|
+
nextRoundItem.originBatchNo = currentItem.inspectedBatchNo || currentItem.originBatchNo
|
|
203
|
+
nextRoundItem.originLocation = currentItem.inspectedLocationId || currentItem.originLocationId
|
|
204
|
+
nextRoundItem.inspectedQty = null
|
|
205
|
+
nextRoundItem.inspectedUomValue = null
|
|
206
|
+
nextRoundItem.inspectedBatchNo = null
|
|
207
|
+
nextRoundItem.inspectedLocationId = null
|
|
208
|
+
nextRoundItem.countNo = currentItem.countNo + 1
|
|
209
|
+
nextRoundItem.inventory = currentItem.inventoryId
|
|
210
|
+
nextRoundItem.product = currentItem.productId
|
|
211
|
+
nextRoundItem.productDetail = currentItem.productDetailId
|
|
212
|
+
nextRoundItem.creator = this.user
|
|
213
|
+
nextRoundItem.updater = this.user
|
|
214
|
+
return nextRoundItem
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
// Step 5: Save the new InventoryCheckItems
|
|
218
|
+
await this.trxMgr.getRepository(InventoryCheckItem).save(nextRoundInventoryCheckItems, { chunk: 500 })
|
|
219
|
+
|
|
220
|
+
// Step 6: Create a new cycle count worksheet details for the next round
|
|
221
|
+
let nextRoundWorksheetDetails = nextRoundInventoryCheckItems.map(newItem => {
|
|
222
|
+
let detail: WorksheetDetail = new WorksheetDetail()
|
|
223
|
+
|
|
224
|
+
detail.domain = this.domain
|
|
225
|
+
detail.bizplace = customerId
|
|
226
|
+
detail.worksheet = nextRoundWorksheet
|
|
227
|
+
detail.name = WorksheetNoGenerator.cycleCountDetail()
|
|
228
|
+
detail.targetInventoryCheckItem = newItem
|
|
229
|
+
detail.type = WORKSHEET_TYPE.CYCLE_COUNT
|
|
230
|
+
detail.status = WORKSHEET_STATUS.EXECUTING
|
|
231
|
+
detail.creator = this.user
|
|
232
|
+
detail.updater = this.user
|
|
233
|
+
|
|
234
|
+
return detail
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
// Step 7: Save the new Worksheet Details
|
|
238
|
+
await this.trxMgr.getRepository(WorksheetDetail).save(nextRoundWorksheetDetails, { chunk: 500 })
|
|
239
|
+
|
|
240
|
+
// Step 8: Mark the selected inventory as TERMINATED
|
|
241
|
+
currentInventoryCheckItems.forEach(item => {
|
|
242
|
+
item.status = INVENTORY_CHECK_ITEM_STATUS.TERMINATED
|
|
243
|
+
item.updater = this.user
|
|
244
|
+
})
|
|
245
|
+
await this.trxMgr.getRepository(InventoryCheckItem).save(currentInventoryCheckItems)
|
|
246
|
+
|
|
247
|
+
// Step 9: Directly update the worksheet details
|
|
248
|
+
await this.trxMgr
|
|
249
|
+
.getRepository(WorksheetDetail)
|
|
250
|
+
.createQueryBuilder()
|
|
251
|
+
.update(WorksheetDetail)
|
|
252
|
+
.set({
|
|
253
|
+
status: WORKSHEET_STATUS.DONE,
|
|
254
|
+
updater: this.user
|
|
255
|
+
})
|
|
256
|
+
.where('targetInventoryCheckItem IN (:...ids)', { ids: currentInventoryCheckItems.map(item => item.id) })
|
|
257
|
+
.execute()
|
|
258
|
+
|
|
259
|
+
// Check if any record is not DONE
|
|
260
|
+
const notDoneCount = await this.trxMgr.getRepository(WorksheetDetail).count({
|
|
261
|
+
where: {
|
|
262
|
+
worksheet: currentCycleCountWorksheet,
|
|
263
|
+
status: Not(Equal(WORKSHEET_STATUS.DONE))
|
|
264
|
+
}
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
if (notDoneCount === 0) {
|
|
268
|
+
// Step 11: Update status of existing InventoryCheck
|
|
269
|
+
existingInventoryCheck.status = ORDER_STATUS.INSPECTING
|
|
270
|
+
existingInventoryCheck.updater = this.user
|
|
271
|
+
await this.trxMgr.getRepository(InventoryCheck).save(existingInventoryCheck)
|
|
272
|
+
|
|
273
|
+
// Step 12: Mark the current worksheet as DONE
|
|
274
|
+
currentCycleCountWorksheet.status = WORKSHEET_STATUS.DONE
|
|
275
|
+
currentCycleCountWorksheet.updater = this.user
|
|
276
|
+
await this.trxMgr.getRepository(Worksheet).save(currentCycleCountWorksheet)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
existingInventoryCheck.executionDate = nextExecutionDate
|
|
280
|
+
existingInventoryCheck.updater = this.user
|
|
281
|
+
await this.trxMgr.getRepository(InventoryCheck).save(existingInventoryCheck)
|
|
282
|
+
|
|
283
|
+
return nextRoundWorksheet
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.error('An error occurred while creating the next round cycle count worksheet:', error)
|
|
286
|
+
throw new Error('Failed to create next round cycle count worksheet')
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
20
290
|
async generateCycleCountWorksheet(
|
|
21
291
|
executionDate: string,
|
|
22
292
|
customerId: string,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
limit: number
|
|
293
|
+
inventoryCheckItemIds: string[] = [],
|
|
294
|
+
inventoryCheckItem: InventoryCheckItem[] = [],
|
|
295
|
+
limit: number = 0,
|
|
296
|
+
selectedLocation: string[] = [],
|
|
297
|
+
cycleCountNo: string
|
|
26
298
|
): Promise<Worksheet> {
|
|
27
|
-
// Find out warehouse and customer bizplace
|
|
28
299
|
const customerBizplace: Bizplace = await this.trxMgr.getRepository(Bizplace).findOne(customerId)
|
|
29
|
-
|
|
300
|
+
|
|
301
|
+
const foundInventoryCheck: InventoryCheck = await this.trxMgr.getRepository(InventoryCheck).findOne({
|
|
302
|
+
where: {
|
|
303
|
+
domain: this.domain,
|
|
304
|
+
bizplace: customerBizplace,
|
|
305
|
+
name: cycleCountNo
|
|
306
|
+
}
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
const worksheetRepository = this.trxMgr.getRepository(Worksheet)
|
|
310
|
+
const foundCycleCountWorksheet: Worksheet | undefined = await worksheetRepository.findOne({
|
|
30
311
|
where: {
|
|
31
312
|
domain: this.domain,
|
|
32
313
|
bizplace: customerBizplace,
|
|
33
314
|
type: In([WORKSHEET_TYPE.CYCLE_COUNT, WORKSHEET_TYPE.CYCLE_COUNT_RECHECK]),
|
|
34
315
|
status: Not(WORKSHEET_STATUS.DONE)
|
|
35
316
|
},
|
|
36
|
-
|
|
317
|
+
order: {
|
|
318
|
+
checkCount: 'DESC'
|
|
319
|
+
},
|
|
320
|
+
relations: ['worksheetDetails', 'worksheetDetails.targetInventoryCheckItem', 'inventoryCheck']
|
|
37
321
|
})
|
|
38
322
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
targetInventory.status = ORDER_INVENTORY_STATUS.INSPECTING
|
|
47
|
-
targetInventory.updater = this.user
|
|
48
|
-
})
|
|
49
|
-
await this.trxMgr.getRepository(OrderInventory).save(targetInventories)
|
|
50
|
-
|
|
51
|
-
// Update status of worksheet (NOT_TALLY => EXECUTING)
|
|
52
|
-
foundCycleCountWorksheet.type = WORKSHEET_TYPE.CYCLE_COUNT_RECHECK
|
|
53
|
-
foundCycleCountWorksheet.status = WORKSHEET_STATUS.EXECUTING
|
|
54
|
-
foundCycleCountWorksheet.endedAt = null
|
|
55
|
-
foundCycleCountWorksheet.updater = this.user
|
|
56
|
-
await this.trxMgr.getRepository(Worksheet).save(foundCycleCountWorksheet)
|
|
57
|
-
|
|
58
|
-
// Update status of worksheet details (NOT_TALLY => EXECUTING)
|
|
59
|
-
let worksheetDetails = foundCycleCountWorksheet.worksheetDetails.filter(
|
|
60
|
-
(wsd: WorksheetDetail) => orderInventoryIds.indexOf(wsd.targetInventory.id) >= 0
|
|
323
|
+
if (inventoryCheckItemIds.length) {
|
|
324
|
+
return await this.createNextRoundCycleCountWorksheet(
|
|
325
|
+
customerId,
|
|
326
|
+
foundInventoryCheck,
|
|
327
|
+
executionDate,
|
|
328
|
+
foundCycleCountWorksheet,
|
|
329
|
+
inventoryCheckItemIds
|
|
61
330
|
)
|
|
62
|
-
worksheetDetails.forEach((wsd: WorksheetDetail) => {
|
|
63
|
-
wsd.status = WORKSHEET_STATUS.EXECUTING
|
|
64
|
-
wsd.updater = this.user
|
|
65
|
-
})
|
|
66
|
-
await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetails)
|
|
67
|
-
|
|
68
|
-
// Update status of cycle count
|
|
69
|
-
const cycleCount: InventoryCheck = foundCycleCountWorksheet.inventoryCheck
|
|
70
|
-
cycleCount.status = ORDER_STATUS.INSPECTING
|
|
71
|
-
cycleCount.updater = this.user
|
|
72
|
-
await this.trxMgr.getRepository(InventoryCheck).save(cycleCount)
|
|
73
|
-
|
|
74
|
-
return foundCycleCountWorksheet
|
|
75
331
|
} else {
|
|
76
|
-
// Create first round of cycle count with whole pallets
|
|
77
332
|
if (foundCycleCountWorksheet) {
|
|
78
|
-
throw new Error(
|
|
333
|
+
throw new Error('Unfinished cycle count worksheet exists.')
|
|
79
334
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this.domain,
|
|
84
|
-
this.user,
|
|
335
|
+
return await this.createCycleCountWorksheet(
|
|
336
|
+
customerBizplace,
|
|
337
|
+
customerId,
|
|
85
338
|
executionDate,
|
|
86
|
-
|
|
339
|
+
inventoryCheckItem,
|
|
340
|
+
selectedLocation,
|
|
341
|
+
limit
|
|
87
342
|
)
|
|
343
|
+
}
|
|
344
|
+
}
|
|
88
345
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
})
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
if (orderInventory && orderInventory.length > 0) {
|
|
103
|
-
let keyval = {
|
|
104
|
-
batchId: 'batch_id',
|
|
105
|
-
batchIdRef: 'batch_id_ref',
|
|
106
|
-
productDetailId: 'product_detail_id'
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
qb.andWhere(
|
|
110
|
-
new Brackets(qb => {
|
|
111
|
-
orderInventory.forEach((itm, idx) => {
|
|
112
|
-
// sample itm value
|
|
113
|
-
// batchId: 'WO00019730', batchIdRef: null, productDetailId: '1d679587-c713-42d6-bd0a-74e587e39cc7'
|
|
114
|
-
qb.orWhere(
|
|
115
|
-
new Brackets(qb2 => {
|
|
116
|
-
let first = true
|
|
117
|
-
for (var prop in itm) {
|
|
118
|
-
if (first) {
|
|
119
|
-
first = false
|
|
120
|
-
qb2.where(`INV.${keyval[prop]} ${itm[prop] == null ? 'is null' : " = '" + itm[prop] + "'"}`)
|
|
121
|
-
} else {
|
|
122
|
-
qb2.andWhere(`INV.${keyval[prop]} ${itm[prop] == null ? 'is null' : " = '" + itm[prop] + "'"}`)
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
})
|
|
126
|
-
)
|
|
127
|
-
})
|
|
128
|
-
})
|
|
129
|
-
)
|
|
130
|
-
} else {
|
|
131
|
-
if (limit > 0) {
|
|
132
|
-
qb.orderBy('RANDOM()').limit(limit)
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
let inventories: Inventory[] = await qb.getMany()
|
|
137
|
-
|
|
138
|
-
if (!inventories.length) {
|
|
139
|
-
throw new Error(`Failed to find inventories`)
|
|
140
|
-
}
|
|
346
|
+
async generateCycleCountWorksheetCarton(
|
|
347
|
+
executionDate: string,
|
|
348
|
+
customerId: string,
|
|
349
|
+
cycleCountNo: string,
|
|
350
|
+
cartonIds: string[] = [],
|
|
351
|
+
batchIds: string[] = [],
|
|
352
|
+
productDetailIds: string[] = [],
|
|
353
|
+
locationNames: string[] = []
|
|
354
|
+
): Promise<Worksheet> {
|
|
355
|
+
const customerBizplace: Bizplace = await this.trxMgr.getRepository(Bizplace).findOne(customerId)
|
|
141
356
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
cycleCountWorksheet.type = WORKSHEET_TYPE.CYCLE_COUNT
|
|
148
|
-
cycleCountWorksheet.status = WORKSHEET_STATUS.DEACTIVATED
|
|
149
|
-
cycleCountWorksheet.creator = this.user
|
|
150
|
-
cycleCountWorksheet.updater = this.user
|
|
151
|
-
cycleCountWorksheet = await this.trxMgr.getRepository(Worksheet).save(cycleCountWorksheet)
|
|
152
|
-
|
|
153
|
-
// generate order inventory mapping with inventory ID
|
|
154
|
-
let targetInventories: OrderInventory[] = []
|
|
155
|
-
for (let i: number = 0; i < inventories.length; i++) {
|
|
156
|
-
const inventory: Inventory = inventories[i]
|
|
157
|
-
|
|
158
|
-
let targetInventory: OrderInventory = new OrderInventory()
|
|
159
|
-
targetInventory.domain = this.domain
|
|
160
|
-
targetInventory.bizplace = customerBizplace
|
|
161
|
-
targetInventory.status = ORDER_INVENTORY_STATUS.PENDING
|
|
162
|
-
targetInventory.name = OrderNoGenerator.orderInventory()
|
|
163
|
-
targetInventory.inventoryCheck = cycleCount
|
|
164
|
-
targetInventory.originQty = inventory.qty
|
|
165
|
-
targetInventory.originWeight = 0
|
|
166
|
-
targetInventory.originUomValue = inventory.uomValue
|
|
167
|
-
targetInventory.originBatchNo = inventory.batchId
|
|
168
|
-
targetInventory.originLocation = inventory.location
|
|
169
|
-
targetInventory.releaseQty = 0
|
|
170
|
-
targetInventory.releaseWeight = 0
|
|
171
|
-
targetInventory.releaseUomValue = 0
|
|
172
|
-
targetInventory.inventory = inventory
|
|
173
|
-
targetInventory.creator = this.user
|
|
174
|
-
targetInventory.updater = this.user
|
|
175
|
-
targetInventories.push(targetInventory)
|
|
176
|
-
|
|
177
|
-
inventory.lockedQty = inventory.qty
|
|
178
|
-
inventory.lockedWeight = 0
|
|
179
|
-
inventory.lockedUomValue = inventory.uomValue
|
|
180
|
-
inventory.updater = this.user
|
|
357
|
+
const foundInventoryCheck: InventoryCheck = await this.trxMgr.getRepository(InventoryCheck).findOne({
|
|
358
|
+
where: {
|
|
359
|
+
domain: this.domain,
|
|
360
|
+
bizplace: customerBizplace,
|
|
361
|
+
name: cycleCountNo
|
|
181
362
|
}
|
|
363
|
+
})
|
|
182
364
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
365
|
+
const worksheetRepository = this.trxMgr.getRepository(Worksheet)
|
|
366
|
+
const foundCycleCountWorksheet: Worksheet | undefined = await worksheetRepository.findOne({
|
|
367
|
+
where: {
|
|
368
|
+
domain: this.domain,
|
|
369
|
+
bizplace: customerBizplace,
|
|
370
|
+
type: In([WORKSHEET_TYPE.CYCLE_COUNT, WORKSHEET_TYPE.CYCLE_COUNT_RECHECK]),
|
|
371
|
+
status: Not(WORKSHEET_STATUS.DONE)
|
|
372
|
+
},
|
|
373
|
+
order: {
|
|
374
|
+
checkCount: 'DESC'
|
|
375
|
+
},
|
|
376
|
+
relations: ['worksheetDetails', 'worksheetDetails.targetInventoryCheckItem', 'inventoryCheck']
|
|
377
|
+
})
|
|
190
378
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
379
|
+
const qb = this.trxMgr.getRepository(InventoryCheckItem).createQueryBuilder('inventoryCheckItem')
|
|
380
|
+
qb.innerJoinAndSelect('inventoryCheckItem.inventory', 'inventory')
|
|
381
|
+
.innerJoinAndSelect('inventoryCheckItem.productDetail', 'productDetail')
|
|
382
|
+
.innerJoinAndSelect('inventoryCheckItem.originLocation', 'location')
|
|
383
|
+
.where('inventory.cartonId IN (:...cartonIds)', { cartonIds })
|
|
384
|
+
.andWhere('inventory.batchId IN (:...batchIds)', { batchIds })
|
|
385
|
+
.andWhere('productDetail.id IN (:...productDetailIds)', { productDetailIds })
|
|
386
|
+
.andWhere('location.name IN (:...locationNames)', { locationNames })
|
|
387
|
+
.andWhere('inventoryCheckItem.domain_id = :domainId', { domainId: this.domain.id })
|
|
388
|
+
.andWhere('inventoryCheckItem.bizplace_id = :bizplaceId', { bizplaceId: customerBizplace.id })
|
|
389
|
+
.andWhere('inventoryCheckItem.inventory_check_id = :inventoryCheckId', {
|
|
390
|
+
inventoryCheckId: foundInventoryCheck.id
|
|
391
|
+
})
|
|
201
392
|
|
|
202
|
-
|
|
203
|
-
}
|
|
393
|
+
const inventoryCheckItems: InventoryCheckItem[] = await qb.getMany()
|
|
204
394
|
|
|
205
|
-
|
|
395
|
+
const inventoryCheckItemIds = inventoryCheckItems.map(item => item.id)
|
|
206
396
|
|
|
207
|
-
|
|
397
|
+
if (inventoryCheckItemIds.length) {
|
|
398
|
+
return await this.createNextRoundCycleCountWorksheet(
|
|
399
|
+
customerId,
|
|
400
|
+
foundInventoryCheck,
|
|
401
|
+
executionDate,
|
|
402
|
+
foundCycleCountWorksheet,
|
|
403
|
+
inventoryCheckItemIds
|
|
404
|
+
)
|
|
208
405
|
}
|
|
209
406
|
}
|
|
210
407
|
|
|
@@ -212,18 +409,20 @@ export class CycleCountWorksheetController extends WorksheetController {
|
|
|
212
409
|
let worksheet: Worksheet = await this.findActivatableWorksheet(worksheetNo, WORKSHEET_TYPE.CYCLE_COUNT, [
|
|
213
410
|
'inventoryCheck',
|
|
214
411
|
'worksheetDetails',
|
|
215
|
-
'worksheetDetails.
|
|
412
|
+
'worksheetDetails.targetInventoryCheckItem'
|
|
216
413
|
])
|
|
217
414
|
|
|
218
415
|
let worksheetDetails: WorksheetDetail[] = worksheet.worksheetDetails
|
|
219
|
-
let
|
|
416
|
+
let targetInventoryCheckItems: InventoryCheckItem[] = worksheetDetails.map(
|
|
417
|
+
(wsd: WorksheetDetail) => wsd.targetInventoryCheckItem
|
|
418
|
+
)
|
|
220
419
|
|
|
221
|
-
for (let i: number = 0; i <
|
|
222
|
-
let
|
|
223
|
-
|
|
224
|
-
|
|
420
|
+
for (let i: number = 0; i < targetInventoryCheckItems.length; i++) {
|
|
421
|
+
let targetInventoryCheckItem: InventoryCheckItem = targetInventoryCheckItems[i]
|
|
422
|
+
targetInventoryCheckItem.status = INVENTORY_CHECK_ITEM_STATUS.INSPECTING
|
|
423
|
+
targetInventoryCheckItem.updater = this.user
|
|
225
424
|
}
|
|
226
|
-
await this.trxMgr.getRepository(
|
|
425
|
+
await this.trxMgr.getRepository(InventoryCheckItem).save(targetInventoryCheckItems, { chunk: 500 })
|
|
227
426
|
|
|
228
427
|
for (let i: number = 0; i < worksheetDetails.length; i++) {
|
|
229
428
|
let foundWSD: WorksheetDetail = worksheetDetails[i]
|
|
@@ -244,7 +443,7 @@ export class CycleCountWorksheetController extends WorksheetController {
|
|
|
244
443
|
return worksheet
|
|
245
444
|
}
|
|
246
445
|
|
|
247
|
-
async
|
|
446
|
+
async inspectingPallet(
|
|
248
447
|
worksheetDetailName: string,
|
|
249
448
|
inspectedBatchNo: string,
|
|
250
449
|
inspectedQty: number,
|
|
@@ -253,124 +452,312 @@ export class CycleCountWorksheetController extends WorksheetController {
|
|
|
253
452
|
let worksheetDetail: WorksheetDetail = await this.findExecutableWorksheetDetailByName(
|
|
254
453
|
worksheetDetailName,
|
|
255
454
|
WORKSHEET_TYPE.CYCLE_COUNT,
|
|
256
|
-
['
|
|
455
|
+
['targetInventoryCheckItem', 'targetInventoryCheckItem.inventory', 'targetInventoryCheckItem.inventory.location']
|
|
257
456
|
)
|
|
258
457
|
|
|
259
|
-
let
|
|
260
|
-
const
|
|
261
|
-
|
|
458
|
+
let targetInventoryCheckItem: InventoryCheckItem = worksheetDetail.targetInventoryCheckItem
|
|
459
|
+
const {
|
|
460
|
+
originBatchNo,
|
|
461
|
+
originQty,
|
|
462
|
+
originUomValue
|
|
463
|
+
}: { originBatchNo: string; originQty: number; originUomValue: number } = targetInventoryCheckItem
|
|
262
464
|
|
|
263
|
-
const isChanged: boolean =
|
|
465
|
+
const isChanged: boolean =
|
|
466
|
+
originBatchNo !== inspectedBatchNo || originQty !== inspectedQty || originUomValue !== inspectedUomValue
|
|
264
467
|
const worksheetDetailStatus: string = isChanged ? WORKSHEET_STATUS.NOT_TALLY : WORKSHEET_STATUS.DONE
|
|
265
|
-
const
|
|
266
|
-
?
|
|
267
|
-
:
|
|
468
|
+
const targetInventoryCheckItemStatus: string = isChanged
|
|
469
|
+
? INVENTORY_CHECK_ITEM_STATUS.NOT_TALLY
|
|
470
|
+
: INVENTORY_CHECK_ITEM_STATUS.INSPECTED
|
|
268
471
|
|
|
269
472
|
worksheetDetail.status = worksheetDetailStatus
|
|
270
473
|
worksheetDetail.updater = this.user
|
|
271
474
|
await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
|
|
272
475
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
await this.updateOrderTargets([
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
476
|
+
targetInventoryCheckItem.inspectedBatchNo = inspectedBatchNo
|
|
477
|
+
targetInventoryCheckItem.inspectedQty = inspectedQty
|
|
478
|
+
targetInventoryCheckItem.inspectedUomValue = inspectedUomValue
|
|
479
|
+
targetInventoryCheckItem.inspectedLocation = targetInventoryCheckItem.inventory.location
|
|
480
|
+
targetInventoryCheckItem.status = targetInventoryCheckItemStatus
|
|
481
|
+
targetInventoryCheckItem.updater = this.user
|
|
482
|
+
await this.updateOrderTargets([targetInventoryCheckItem])
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
async inspectingCarton(
|
|
486
|
+
productDetailId: string,
|
|
487
|
+
cartonId: string,
|
|
488
|
+
batchId: string,
|
|
489
|
+
locationId: string,
|
|
490
|
+
inspectedBatchNo: string,
|
|
491
|
+
inspectedQty: number,
|
|
492
|
+
inspectedUomValue: number
|
|
493
|
+
): Promise<void> {
|
|
494
|
+
const productDetail: ProductDetail = await this.trxMgr.getRepository(ProductDetail).findOne({
|
|
495
|
+
where: { id: productDetailId },
|
|
496
|
+
relations: ['product']
|
|
497
|
+
})
|
|
498
|
+
|
|
499
|
+
let qb: SelectQueryBuilder<Inventory> = this.trxMgr
|
|
500
|
+
.getRepository(Inventory)
|
|
501
|
+
.createQueryBuilder('inv')
|
|
502
|
+
.where('inv.product_detail_id = :productDetailId', { productDetailId })
|
|
503
|
+
.andWhere('inv.carton_id = :cartonId', { cartonId })
|
|
504
|
+
.andWhere('inv.batch_id = :batchId', { batchId })
|
|
505
|
+
.andWhere('inv.location_id = :locationId', { locationId })
|
|
506
|
+
|
|
507
|
+
let orderByField = 'created_at'
|
|
508
|
+
let orderByDirection: 'ASC' | 'DESC' = 'ASC'
|
|
509
|
+
|
|
510
|
+
switch (productDetail.product.pickingStrategy) {
|
|
511
|
+
case 'LIFO':
|
|
512
|
+
orderByDirection = 'DESC'
|
|
513
|
+
break
|
|
514
|
+
case 'FEFO':
|
|
515
|
+
orderByField = 'expiration_date'
|
|
516
|
+
break
|
|
517
|
+
case 'FMFO':
|
|
518
|
+
orderByField = 'manufacture_date'
|
|
519
|
+
break
|
|
520
|
+
}
|
|
521
|
+
qb.addOrderBy(`"inv"."${orderByField}"`, orderByDirection)
|
|
522
|
+
|
|
523
|
+
if (['FEFO', 'FMFO'].includes(productDetail.product.pickingStrategy)) {
|
|
524
|
+
qb.addOrderBy('"inv"."created_at"', 'ASC')
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const inventories: Inventory[] = await qb.getMany()
|
|
528
|
+
|
|
529
|
+
const inventoryIds = inventories.map(inv => inv.id)
|
|
530
|
+
const inventoryCheckItems: InventoryCheckItem[] = await this.trxMgr
|
|
531
|
+
.getRepository(InventoryCheckItem)
|
|
532
|
+
.createQueryBuilder('inventoryCheckItem')
|
|
533
|
+
.leftJoinAndSelect('inventoryCheckItem.inventory', 'inventory')
|
|
534
|
+
.where('inventory.id IN (:...ids)', { ids: inventoryIds })
|
|
535
|
+
.andWhere('inventoryCheckItem.status = :status', { status: 'INSPECTING' })
|
|
536
|
+
.getMany()
|
|
537
|
+
|
|
538
|
+
const totalOriginQty = inventoryCheckItems.reduce((total, item) => total + (item.originQty || 0), 0)
|
|
539
|
+
const totalOriginUomValue = inventoryCheckItems.reduce((total, item) => total + (item.originUomValue || 0), 0)
|
|
540
|
+
|
|
541
|
+
const hasQtyDiscrepancy = totalOriginQty !== inspectedQty
|
|
542
|
+
const hasUomValueDiscrepancy = totalOriginUomValue !== inspectedUomValue
|
|
543
|
+
|
|
544
|
+
const hasBatchNoDiscrepancy = inventoryCheckItems.some(checkItem => checkItem.originBatchNo !== inspectedBatchNo)
|
|
545
|
+
|
|
546
|
+
const hasDiscrepancies = hasQtyDiscrepancy || hasUomValueDiscrepancy || hasBatchNoDiscrepancy
|
|
547
|
+
|
|
548
|
+
let inventoryCheckItemStatus
|
|
549
|
+
let worksheetDetailStatus
|
|
550
|
+
|
|
551
|
+
if (inventoryCheckItems.length > 1) {
|
|
552
|
+
inventoryCheckItemStatus = hasDiscrepancies
|
|
553
|
+
? INVENTORY_CHECK_ITEM_STATUS.GROUP_NOT_TALLY
|
|
554
|
+
: INVENTORY_CHECK_ITEM_STATUS.INSPECTED
|
|
555
|
+
worksheetDetailStatus = hasDiscrepancies ? WORKSHEET_STATUS.NOT_TALLY : WORKSHEET_STATUS.DONE
|
|
556
|
+
} else {
|
|
557
|
+
inventoryCheckItemStatus = hasDiscrepancies
|
|
558
|
+
? INVENTORY_CHECK_ITEM_STATUS.NOT_TALLY
|
|
559
|
+
: INVENTORY_CHECK_ITEM_STATUS.INSPECTED
|
|
560
|
+
worksheetDetailStatus = hasDiscrepancies ? WORKSHEET_STATUS.NOT_TALLY : WORKSHEET_STATUS.DONE
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
let totalInspectedQty = inspectedQty
|
|
564
|
+
let totalInspectedUomValue = inspectedUomValue
|
|
565
|
+
|
|
566
|
+
for (const checkItem of inventoryCheckItems) {
|
|
567
|
+
const qtyToInspect = totalInspectedQty > 0 ? Math.min(totalInspectedQty, checkItem.originQty) : 0
|
|
568
|
+
const uomValueToInspect =
|
|
569
|
+
totalInspectedUomValue > 0 ? Math.min(totalInspectedUomValue, checkItem.originUomValue) : 0
|
|
570
|
+
|
|
571
|
+
checkItem.inspectedQty = (checkItem.inspectedQty ?? 0) + qtyToInspect
|
|
572
|
+
totalInspectedQty -= qtyToInspect
|
|
573
|
+
|
|
574
|
+
checkItem.inspectedUomValue = (checkItem.inspectedUomValue ?? 0) + uomValueToInspect
|
|
575
|
+
totalInspectedUomValue -= uomValueToInspect
|
|
576
|
+
|
|
577
|
+
checkItem.inspectedBatchNo = inspectedBatchNo
|
|
578
|
+
checkItem.inspectedLocation = checkItem.originLocationId
|
|
579
|
+
checkItem.status = inventoryCheckItemStatus
|
|
580
|
+
checkItem.updater = this.user
|
|
581
|
+
|
|
582
|
+
await this.trxMgr.getRepository(InventoryCheckItem).save(checkItem)
|
|
583
|
+
|
|
584
|
+
let worksheetDetail = await this.trxMgr.getRepository(WorksheetDetail).findOne({
|
|
585
|
+
where: { targetInventoryCheckItem: checkItem.id, type: WORKSHEET_TYPE.CYCLE_COUNT }
|
|
586
|
+
})
|
|
587
|
+
|
|
588
|
+
if (worksheetDetail) {
|
|
589
|
+
worksheetDetail.status = worksheetDetailStatus
|
|
590
|
+
worksheetDetail.updater = this.user
|
|
591
|
+
await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (totalInspectedQty > 0 && totalInspectedUomValue > 0 && inventoryCheckItems.length > 0) {
|
|
596
|
+
const lastItem = inventoryCheckItems[inventoryCheckItems.length - 1]
|
|
597
|
+
lastItem.inspectedQty = (lastItem.inspectedQty ?? 0) + totalInspectedQty
|
|
598
|
+
lastItem.inspectedUomValue = (lastItem.inspectedUomValue ?? 0) + totalInspectedUomValue
|
|
599
|
+
await this.trxMgr.getRepository(InventoryCheckItem).save(lastItem)
|
|
288
600
|
}
|
|
289
601
|
}
|
|
290
602
|
|
|
291
603
|
async undoInspection(worksheetDetailName: string): Promise<void> {
|
|
292
604
|
let worksheetDetail: WorksheetDetail = await this.findWorksheetDetail(
|
|
293
605
|
{ domain: this.domain, name: worksheetDetailName, status: Not(Equal(WORKSHEET_STATUS.EXECUTING)) },
|
|
294
|
-
['
|
|
606
|
+
['targetInventoryCheckItem', 'targetInventoryCheckItem.inventory']
|
|
295
607
|
)
|
|
296
608
|
|
|
297
|
-
let
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
?
|
|
306
|
-
:
|
|
307
|
-
|
|
308
|
-
await this.updateOrderTargets([
|
|
609
|
+
let targetInventoryCheckItem: InventoryCheckItem = worksheetDetail.targetInventoryCheckItem
|
|
610
|
+
targetInventoryCheckItem.inspectedBatchNo = null
|
|
611
|
+
targetInventoryCheckItem.inspectedQty = null
|
|
612
|
+
targetInventoryCheckItem.inspectedWeight = null
|
|
613
|
+
targetInventoryCheckItem.inspectedUomValue = null
|
|
614
|
+
targetInventoryCheckItem.inspectedLocation = null
|
|
615
|
+
targetInventoryCheckItem.status =
|
|
616
|
+
targetInventoryCheckItem.status === INVENTORY_CHECK_ITEM_STATUS.RELOCATED
|
|
617
|
+
? INVENTORY_CHECK_ITEM_STATUS.MISSING
|
|
618
|
+
: INVENTORY_CHECK_ITEM_STATUS.INSPECTING
|
|
619
|
+
targetInventoryCheckItem.updater = this.user
|
|
620
|
+
await this.updateOrderTargets([targetInventoryCheckItem])
|
|
309
621
|
|
|
310
622
|
worksheetDetail.status =
|
|
311
|
-
|
|
623
|
+
targetInventoryCheckItem.status === INVENTORY_CHECK_ITEM_STATUS.MISSING
|
|
312
624
|
? WORKSHEET_STATUS.NOT_TALLY
|
|
313
625
|
: WORKSHEET_STATUS.EXECUTING
|
|
314
626
|
worksheetDetail.updater = this.user
|
|
315
627
|
await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
async undoInspectionCarton(
|
|
631
|
+
productDetailId: string,
|
|
632
|
+
cartonId: string,
|
|
633
|
+
batchId: string,
|
|
634
|
+
locationId: string
|
|
635
|
+
): Promise<void> {
|
|
636
|
+
let qb: SelectQueryBuilder<Inventory> = this.trxMgr.getRepository(Inventory).createQueryBuilder('inv')
|
|
637
|
+
qb.where('inv.product_detail_id = :productDetailId', { productDetailId })
|
|
638
|
+
.andWhere('inv.carton_id = :cartonId', { cartonId })
|
|
639
|
+
.andWhere('inv.batch_id = :batchId', { batchId })
|
|
640
|
+
.andWhere('inv.location_id = :locationId', { locationId })
|
|
641
|
+
|
|
642
|
+
const inventories: Inventory[] = await qb.getMany()
|
|
643
|
+
|
|
644
|
+
const inventoryCheckItems: InventoryCheckItem[] = await Promise.all(
|
|
645
|
+
inventories.map(inventory =>
|
|
646
|
+
this.trxMgr.getRepository(InventoryCheckItem).findOne({ where: { inventory: inventory.id } })
|
|
647
|
+
)
|
|
648
|
+
)
|
|
649
|
+
|
|
650
|
+
for (const checkItem of inventoryCheckItems) {
|
|
651
|
+
checkItem.inspectedBatchNo = null
|
|
652
|
+
checkItem.inspectedQty = null
|
|
653
|
+
checkItem.inspectedWeight = null
|
|
654
|
+
checkItem.inspectedUomValue = null
|
|
655
|
+
checkItem.inspectedLocation = null
|
|
656
|
+
checkItem.status = INVENTORY_CHECK_ITEM_STATUS.INSPECTING
|
|
657
|
+
checkItem.updater = this.user
|
|
658
|
+
|
|
659
|
+
let worksheetDetail = await this.trxMgr.getRepository(WorksheetDetail).findOne({
|
|
660
|
+
where: { targetInventoryCheckItem: checkItem.id, type: WORKSHEET_TYPE.CYCLE_COUNT },
|
|
661
|
+
relations: ['targetInventoryCheckItem']
|
|
662
|
+
})
|
|
316
663
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
664
|
+
if (worksheetDetail) {
|
|
665
|
+
worksheetDetail.status = WORKSHEET_STATUS.EXECUTING
|
|
666
|
+
worksheetDetail.updater = this.user
|
|
667
|
+
await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
|
|
668
|
+
}
|
|
669
|
+
await this.trxMgr.getRepository(InventoryCheckItem).save(checkItem)
|
|
670
|
+
}
|
|
323
671
|
}
|
|
324
672
|
|
|
325
|
-
async
|
|
673
|
+
async checkMissingInventory(worksheetDetailName: string): Promise<void> {
|
|
326
674
|
let worksheetDetail: WorksheetDetail = await this.findExecutableWorksheetDetailByName(
|
|
327
675
|
worksheetDetailName,
|
|
328
676
|
WORKSHEET_TYPE.CYCLE_COUNT,
|
|
329
|
-
['
|
|
677
|
+
['targetInventoryCheckItem']
|
|
330
678
|
)
|
|
331
679
|
|
|
332
|
-
let
|
|
680
|
+
let targetInventoryCheckItem: InventoryCheckItem = worksheetDetail.targetInventoryCheckItem
|
|
333
681
|
worksheetDetail.status = WORKSHEET_STATUS.NOT_TALLY
|
|
334
682
|
worksheetDetail.updater = this.user
|
|
335
683
|
await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
|
|
336
684
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
await this.updateOrderTargets([
|
|
685
|
+
targetInventoryCheckItem.status = INVENTORY_CHECK_ITEM_STATUS.MISSING
|
|
686
|
+
targetInventoryCheckItem.updater = this.user
|
|
687
|
+
await this.updateOrderTargets([targetInventoryCheckItem])
|
|
340
688
|
}
|
|
341
689
|
|
|
342
|
-
async
|
|
690
|
+
async checkMissingInventoryCarton(
|
|
691
|
+
productDetailId: string,
|
|
692
|
+
cartonId: string,
|
|
693
|
+
batchId: string,
|
|
694
|
+
locationId: string
|
|
695
|
+
): Promise<void> {
|
|
696
|
+
let qb: SelectQueryBuilder<Inventory> = this.trxMgr.getRepository(Inventory).createQueryBuilder('inv')
|
|
697
|
+
qb.where('inv.product_detail_id = :productDetailId', { productDetailId })
|
|
698
|
+
.andWhere('inv.carton_id = :cartonId', { cartonId })
|
|
699
|
+
.andWhere('inv.batch_id = :batchId', { batchId })
|
|
700
|
+
.andWhere('inv.location_id = :locationId', { locationId })
|
|
701
|
+
|
|
702
|
+
const inventories: Inventory[] = await qb.getMany()
|
|
703
|
+
|
|
704
|
+
const inventoryCheckItems: InventoryCheckItem[] = await Promise.all(
|
|
705
|
+
inventories.map(inventory =>
|
|
706
|
+
this.trxMgr.getRepository(InventoryCheckItem).findOne({ where: { inventory: inventory.id } })
|
|
707
|
+
)
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
for (const checkItem of inventoryCheckItems) {
|
|
711
|
+
checkItem.inspectedBatchNo = null
|
|
712
|
+
checkItem.inspectedQty = null
|
|
713
|
+
checkItem.inspectedWeight = null
|
|
714
|
+
checkItem.inspectedUomValue = null
|
|
715
|
+
checkItem.inspectedLocation = null
|
|
716
|
+
checkItem.status = INVENTORY_CHECK_ITEM_STATUS.MISSING
|
|
717
|
+
checkItem.updater = this.user
|
|
718
|
+
|
|
719
|
+
let worksheetDetail = await this.trxMgr.getRepository(WorksheetDetail).findOne({
|
|
720
|
+
where: { targetInventoryCheckItem: checkItem.id, type: WORKSHEET_TYPE.CYCLE_COUNT },
|
|
721
|
+
relations: ['targetInventoryCheckItem']
|
|
722
|
+
})
|
|
723
|
+
|
|
724
|
+
if (worksheetDetail) {
|
|
725
|
+
worksheetDetail.status = WORKSHEET_STATUS.NOT_TALLY
|
|
726
|
+
worksheetDetail.updater = this.user
|
|
727
|
+
await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
|
|
728
|
+
}
|
|
729
|
+
await this.trxMgr.getRepository(InventoryCheckItem).save(checkItem)
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
async addExtraInventory(
|
|
343
734
|
cycleCountNo: string,
|
|
344
|
-
|
|
735
|
+
inspectedLocation: string,
|
|
736
|
+
productDetailId: string,
|
|
737
|
+
productId: string,
|
|
345
738
|
inspectedBatchNo: string,
|
|
346
739
|
inspectedQty: number,
|
|
347
740
|
inspectedUomValue: number,
|
|
348
|
-
|
|
741
|
+
countNo: number
|
|
349
742
|
): Promise<void> {
|
|
743
|
+
let today = new Date(),
|
|
744
|
+
year = today.getFullYear(),
|
|
745
|
+
month = today.getMonth(),
|
|
746
|
+
date = today.getDate()
|
|
747
|
+
|
|
350
748
|
const inventoryCheck: InventoryCheck = await this.findRefOrder(
|
|
351
749
|
InventoryCheck,
|
|
352
750
|
{
|
|
353
751
|
name: cycleCountNo,
|
|
354
752
|
status: ORDER_STATUS.INSPECTING
|
|
355
753
|
},
|
|
356
|
-
['bizplace']
|
|
754
|
+
['bizplace', 'bizplace.domain']
|
|
357
755
|
)
|
|
358
756
|
|
|
359
|
-
const bizplace: Bizplace =
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
.andWhere('INV.bizplace = :bizplaceId', { bizplaceId: bizplace.id })
|
|
364
|
-
.andWhere('INV.palletId = :palletId', { palletId })
|
|
365
|
-
.andWhere('INV.status = :status', { status: INVENTORY_STATUS.STORED })
|
|
366
|
-
.andWhere(
|
|
367
|
-
new Brackets(qb => {
|
|
368
|
-
qb.where('INV.lockedQty ISNULL')
|
|
369
|
-
qb.orWhere('INV.lockedQty = 0')
|
|
370
|
-
})
|
|
371
|
-
)
|
|
372
|
-
.getOne()
|
|
373
|
-
if (!inventory) throw new Error('Failed to find inventory')
|
|
757
|
+
const bizplace: Bizplace = await this.trxMgr.getRepository(Bizplace).findOne({
|
|
758
|
+
where: { id: inventoryCheck.bizplace.id },
|
|
759
|
+
relations: ['domain']
|
|
760
|
+
})
|
|
374
761
|
|
|
375
762
|
const worksheet: Worksheet = await this.trxMgr.getRepository(Worksheet).findOne({
|
|
376
763
|
where: {
|
|
@@ -381,31 +768,104 @@ export class CycleCountWorksheetController extends WorksheetController {
|
|
|
381
768
|
}
|
|
382
769
|
})
|
|
383
770
|
const location: Location = await this.trxMgr.getRepository(Location).findOne({
|
|
384
|
-
where: { domain: this.domain, name:
|
|
771
|
+
where: { domain: this.domain, name: inspectedLocation },
|
|
772
|
+
relations: ['warehouse']
|
|
773
|
+
})
|
|
774
|
+
|
|
775
|
+
const productDetail: ProductDetail = await this.trxMgr.getRepository(ProductDetail).findOne({
|
|
776
|
+
where: { id: productDetailId }
|
|
777
|
+
})
|
|
778
|
+
|
|
779
|
+
const product: Product = await this.trxMgr.getRepository(Product).findOne({
|
|
780
|
+
where: { id: productId }
|
|
781
|
+
})
|
|
782
|
+
|
|
783
|
+
const total = await this.trxMgr.getRepository(Inventory).count({
|
|
784
|
+
createdAt: MoreThan(new Date(year, month, date))
|
|
785
|
+
})
|
|
786
|
+
|
|
787
|
+
const yy = String(year).substr(String(year).length - 2)
|
|
788
|
+
const mm = String(month + 1).padStart(2, '0')
|
|
789
|
+
const dd = String(date).padStart(2, '0')
|
|
790
|
+
|
|
791
|
+
const dateStr = yy + mm + dd
|
|
792
|
+
|
|
793
|
+
let newInventory: Partial<Inventory> = new Inventory()
|
|
794
|
+
newInventory.bizplace = bizplace
|
|
795
|
+
newInventory.domain = this.domain
|
|
796
|
+
newInventory.name = InventoryNoGenerator.inventoryName()
|
|
797
|
+
newInventory.palletId = await generateId({
|
|
798
|
+
domain: this.domain,
|
|
799
|
+
type: 'adjustment_pallet_id',
|
|
800
|
+
seed: {
|
|
801
|
+
batchId: inspectedBatchNo,
|
|
802
|
+
date: dateStr
|
|
803
|
+
}
|
|
385
804
|
})
|
|
386
805
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
806
|
+
const warehouseCartonSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
|
|
807
|
+
where: { domain: this.domain, category: 'id-rule', name: 'enable-carton-label', value: true }
|
|
808
|
+
})
|
|
809
|
+
|
|
810
|
+
const partnerCartonSetting: PartnerSetting = await this.trxMgr.getRepository(PartnerSetting).findOne({
|
|
811
|
+
where: {
|
|
812
|
+
setting: warehouseCartonSetting,
|
|
813
|
+
domain: this.domain,
|
|
814
|
+
partnerDomain: inventoryCheck.bizplace?.domain,
|
|
815
|
+
value: true
|
|
816
|
+
}
|
|
817
|
+
})
|
|
818
|
+
|
|
819
|
+
if (partnerCartonSetting?.value || warehouseCartonSetting?.value) {
|
|
820
|
+
let cartonId = await generateId({
|
|
821
|
+
domain: this.domain,
|
|
822
|
+
type: 'adjustment_carton_id',
|
|
823
|
+
seed: { date: dateStr }
|
|
824
|
+
})
|
|
825
|
+
if (!cartonId) throw new Error('No adjustment carton id setting rule found')
|
|
826
|
+
|
|
827
|
+
newInventory.cartonId = cartonId
|
|
828
|
+
}
|
|
829
|
+
newInventory.batchId = inspectedBatchNo
|
|
830
|
+
newInventory.product = product
|
|
831
|
+
newInventory.productDetail = productDetail
|
|
832
|
+
newInventory.packingType = productDetail.packingType
|
|
833
|
+
newInventory.packingSize = productDetail.packingSize
|
|
834
|
+
newInventory.uom = productDetail.uom
|
|
835
|
+
newInventory.qty = inspectedQty
|
|
836
|
+
newInventory.uomValue = inspectedUomValue
|
|
837
|
+
newInventory.location = location
|
|
838
|
+
newInventory.warehouse = location.warehouse
|
|
839
|
+
newInventory.zone = location.zone
|
|
840
|
+
newInventory.status = INVENTORY_STATUS.CC_ADDED
|
|
841
|
+
newInventory.creator = this.user
|
|
842
|
+
newInventory.updater = this.user
|
|
843
|
+
await this.trxMgr.getRepository(Inventory).save(newInventory)
|
|
844
|
+
|
|
845
|
+
let targetInventoryCheckItem: InventoryCheckItem = new InventoryCheckItem()
|
|
846
|
+
targetInventoryCheckItem.domain = this.domain
|
|
847
|
+
targetInventoryCheckItem.bizplace = bizplace
|
|
848
|
+
targetInventoryCheckItem.status = INVENTORY_CHECK_ITEM_STATUS.ADDED
|
|
849
|
+
targetInventoryCheckItem.name = OrderNoGenerator.inventoryCheckItem()
|
|
850
|
+
targetInventoryCheckItem.inventoryCheck = inventoryCheck
|
|
851
|
+
targetInventoryCheckItem.inventory = newInventory
|
|
852
|
+
targetInventoryCheckItem.inspectedBatchNo = inspectedBatchNo
|
|
853
|
+
targetInventoryCheckItem.inspectedQty = inspectedQty
|
|
854
|
+
targetInventoryCheckItem.inspectedUomValue = inspectedUomValue
|
|
855
|
+
targetInventoryCheckItem.inspectedLocation = location
|
|
856
|
+
targetInventoryCheckItem.productDetail = productDetail
|
|
857
|
+
targetInventoryCheckItem.product = product
|
|
858
|
+
targetInventoryCheckItem.countNo = countNo
|
|
859
|
+
targetInventoryCheckItem.creator = this.user
|
|
860
|
+
targetInventoryCheckItem.updater = this.user
|
|
861
|
+
await this.trxMgr.getRepository(InventoryCheckItem).save(targetInventoryCheckItem)
|
|
402
862
|
|
|
403
863
|
let worksheetDetail: WorksheetDetail = new WorksheetDetail()
|
|
404
864
|
worksheetDetail.domain = this.domain
|
|
405
865
|
worksheetDetail.bizplace = bizplace
|
|
406
866
|
worksheetDetail.worksheet = worksheet
|
|
407
867
|
worksheetDetail.name = WorksheetNoGenerator.cycleCountDetail()
|
|
408
|
-
worksheetDetail.
|
|
868
|
+
worksheetDetail.targetInventoryCheckItem = targetInventoryCheckItem
|
|
409
869
|
worksheetDetail.type = WORKSHEET_TYPE.CYCLE_COUNT
|
|
410
870
|
worksheetDetail.status = WORKSHEET_STATUS.NOT_TALLY
|
|
411
871
|
worksheetDetail.creator = this.user
|
|
@@ -413,7 +873,7 @@ export class CycleCountWorksheetController extends WorksheetController {
|
|
|
413
873
|
await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
|
|
414
874
|
}
|
|
415
875
|
|
|
416
|
-
async
|
|
876
|
+
async relocateInventory(
|
|
417
877
|
worksheetDetailName: string,
|
|
418
878
|
inspectedBatchNo: string,
|
|
419
879
|
inspectedQty: number,
|
|
@@ -422,13 +882,17 @@ export class CycleCountWorksheetController extends WorksheetController {
|
|
|
422
882
|
): Promise<void> {
|
|
423
883
|
let worksheetDetail: WorksheetDetail = await this.trxMgr.getRepository(WorksheetDetail).findOne({
|
|
424
884
|
where: { domain: this.domain, name: worksheetDetailName, type: WORKSHEET_TYPE.CYCLE_COUNT },
|
|
425
|
-
relations: [
|
|
885
|
+
relations: [
|
|
886
|
+
'targetInventoryCheckItem',
|
|
887
|
+
'targetInventoryCheckItem.inventory',
|
|
888
|
+
'targetInventoryCheckItem.inventory.location'
|
|
889
|
+
]
|
|
426
890
|
})
|
|
427
891
|
|
|
428
892
|
if (!worksheetDetail) throw new Error('Failed to find worksheet detail')
|
|
429
893
|
|
|
430
|
-
let
|
|
431
|
-
const location: Location =
|
|
894
|
+
let targetInventoryCheckItem: InventoryCheckItem = worksheetDetail.targetInventoryCheckItem
|
|
895
|
+
const location: Location = targetInventoryCheckItem?.inventory?.location
|
|
432
896
|
if (location.name === inspectedLocationName) throw new Error(`You can't relocate at same location`)
|
|
433
897
|
|
|
434
898
|
const inspectedLocation: Location = await this.trxMgr.getRepository(Location).findOne({
|
|
@@ -439,14 +903,156 @@ export class CycleCountWorksheetController extends WorksheetController {
|
|
|
439
903
|
worksheetDetail.updater = this.user
|
|
440
904
|
await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
|
|
441
905
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
await this.updateOrderTargets([
|
|
906
|
+
targetInventoryCheckItem.inspectedLocation = inspectedLocation
|
|
907
|
+
targetInventoryCheckItem.inspectedBatchNo = inspectedBatchNo
|
|
908
|
+
targetInventoryCheckItem.inspectedQty = inspectedQty
|
|
909
|
+
targetInventoryCheckItem.inspectedWeight = 0
|
|
910
|
+
targetInventoryCheckItem.inspectedUomValue = inspectedUomValue
|
|
911
|
+
targetInventoryCheckItem.status = INVENTORY_CHECK_ITEM_STATUS.RELOCATED
|
|
912
|
+
targetInventoryCheckItem.updater = this.user
|
|
913
|
+
await this.updateOrderTargets([targetInventoryCheckItem])
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
async relocateInventoryCarton(
|
|
917
|
+
productDetailId: string,
|
|
918
|
+
cartonId: string,
|
|
919
|
+
batchId: string,
|
|
920
|
+
locationId: string,
|
|
921
|
+
inspectedBatchNo: string,
|
|
922
|
+
inspectedQty: number,
|
|
923
|
+
inspectedUomValue: number,
|
|
924
|
+
inspectedLocationName: string
|
|
925
|
+
): Promise<void> {
|
|
926
|
+
const productDetail: ProductDetail = await this.trxMgr.getRepository(ProductDetail).findOne({
|
|
927
|
+
where: { id: productDetailId },
|
|
928
|
+
relations: ['product']
|
|
929
|
+
})
|
|
930
|
+
|
|
931
|
+
let qb: SelectQueryBuilder<Inventory> = this.trxMgr
|
|
932
|
+
.getRepository(Inventory)
|
|
933
|
+
.createQueryBuilder('inv')
|
|
934
|
+
.where('inv.product_detail_id = :productDetailId', { productDetailId })
|
|
935
|
+
.andWhere('inv.carton_id = :cartonId', { cartonId })
|
|
936
|
+
.andWhere('inv.batch_id = :batchId', { batchId })
|
|
937
|
+
.andWhere('inv.location_id = :locationId', { locationId })
|
|
938
|
+
|
|
939
|
+
let orderByField = 'created_at'
|
|
940
|
+
let orderByDirection: 'ASC' | 'DESC' = 'ASC'
|
|
941
|
+
|
|
942
|
+
switch (productDetail.product.pickingStrategy) {
|
|
943
|
+
case 'LIFO':
|
|
944
|
+
orderByDirection = 'DESC'
|
|
945
|
+
break
|
|
946
|
+
case 'FEFO':
|
|
947
|
+
orderByField = 'expiration_date'
|
|
948
|
+
break
|
|
949
|
+
case 'FMFO':
|
|
950
|
+
orderByField = 'manufacture_date'
|
|
951
|
+
break
|
|
952
|
+
}
|
|
953
|
+
qb.addOrderBy(`"inv"."${orderByField}"`, orderByDirection)
|
|
954
|
+
|
|
955
|
+
if (['FEFO', 'FMFO'].includes(productDetail.product.pickingStrategy)) {
|
|
956
|
+
qb.addOrderBy('"inv"."created_at"', 'ASC')
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
const inventories: Inventory[] = await qb.getMany()
|
|
960
|
+
if (inventories.length === 0) {
|
|
961
|
+
throw new Error('No inventories found.')
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
const location: Location = await this.trxMgr.getRepository(Location).findOne({
|
|
965
|
+
where: { id: locationId }
|
|
966
|
+
})
|
|
967
|
+
if (location.name === inspectedLocationName) {
|
|
968
|
+
throw new Error(`You can't relocate to the same location.`)
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
const inspectedLocation: Location = await this.trxMgr.getRepository(Location).findOne({
|
|
972
|
+
where: { name: inspectedLocationName, domain: this.domain }
|
|
973
|
+
})
|
|
974
|
+
if (!inspectedLocation) {
|
|
975
|
+
throw new Error(`Inspected location "${inspectedLocationName}" not found.`)
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
const inventoryIds = inventories.map(inv => inv.id)
|
|
979
|
+
const inventoryCheckItems: InventoryCheckItem[] = await this.trxMgr
|
|
980
|
+
.getRepository(InventoryCheckItem)
|
|
981
|
+
.createQueryBuilder('inventoryCheckItem')
|
|
982
|
+
.leftJoinAndSelect('inventoryCheckItem.inventory', 'inventory')
|
|
983
|
+
.where('inventory.id IN (:...ids)', { ids: inventoryIds })
|
|
984
|
+
.andWhere('inventoryCheckItem.status = :status', { status: 'INSPECTING' })
|
|
985
|
+
.getMany()
|
|
986
|
+
|
|
987
|
+
if (inventoryCheckItems.length === 0) {
|
|
988
|
+
throw new Error('No inventory check items found.')
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
const totalOriginQty = inventoryCheckItems.reduce((total, item) => total + (item.originQty || 0), 0)
|
|
992
|
+
const totalOriginUomValue = inventoryCheckItems.reduce((total, item) => total + (item.originUomValue || 0), 0)
|
|
993
|
+
|
|
994
|
+
const hasQtyDiscrepancy = totalOriginQty !== inspectedQty
|
|
995
|
+
const hasUomValueDiscrepancy = totalOriginUomValue !== inspectedUomValue
|
|
996
|
+
|
|
997
|
+
const hasBatchNoDiscrepancy = inventoryCheckItems.some(checkItem => checkItem.originBatchNo !== inspectedBatchNo)
|
|
998
|
+
|
|
999
|
+
const hasLocationDiscrepancy = inventoryCheckItems.some(
|
|
1000
|
+
checkItem => checkItem.originLocationId !== inspectedLocation.id
|
|
1001
|
+
)
|
|
1002
|
+
|
|
1003
|
+
const hasDiscrepancies =
|
|
1004
|
+
hasQtyDiscrepancy || hasUomValueDiscrepancy || hasBatchNoDiscrepancy || hasLocationDiscrepancy
|
|
1005
|
+
|
|
1006
|
+
let inventoryCheckItemStatus, worksheetDetailStatus
|
|
1007
|
+
|
|
1008
|
+
if (inventoryCheckItems.length > 1) {
|
|
1009
|
+
inventoryCheckItemStatus = hasDiscrepancies
|
|
1010
|
+
? INVENTORY_CHECK_ITEM_STATUS.RELOCATED
|
|
1011
|
+
: INVENTORY_CHECK_ITEM_STATUS.INSPECTED
|
|
1012
|
+
worksheetDetailStatus = hasDiscrepancies ? WORKSHEET_STATUS.NOT_TALLY : WORKSHEET_STATUS.DONE
|
|
1013
|
+
} else {
|
|
1014
|
+
inventoryCheckItemStatus = hasDiscrepancies
|
|
1015
|
+
? INVENTORY_CHECK_ITEM_STATUS.RELOCATED
|
|
1016
|
+
: INVENTORY_CHECK_ITEM_STATUS.INSPECTED
|
|
1017
|
+
worksheetDetailStatus = hasDiscrepancies ? WORKSHEET_STATUS.NOT_TALLY : WORKSHEET_STATUS.DONE
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
let totalInspectedQty = inspectedQty
|
|
1021
|
+
let totalInspectedUomValue = inspectedUomValue
|
|
1022
|
+
|
|
1023
|
+
for (const checkItem of inventoryCheckItems) {
|
|
1024
|
+
const qtyToInspect = totalInspectedQty > 0 ? Math.min(totalInspectedQty, checkItem.originQty) : 0
|
|
1025
|
+
const uomValueToInspect =
|
|
1026
|
+
totalInspectedUomValue > 0 ? Math.min(totalInspectedUomValue, checkItem.originUomValue) : 0
|
|
1027
|
+
checkItem.inspectedQty = (checkItem.inspectedQty ?? 0) + qtyToInspect
|
|
1028
|
+
totalInspectedQty -= qtyToInspect
|
|
1029
|
+
checkItem.inspectedUomValue = (checkItem.inspectedUomValue ?? 0) + uomValueToInspect
|
|
1030
|
+
totalInspectedUomValue -= uomValueToInspect
|
|
1031
|
+
|
|
1032
|
+
checkItem.inspectedBatchNo = inspectedBatchNo
|
|
1033
|
+
checkItem.inspectedLocation = inspectedLocation
|
|
1034
|
+
checkItem.status = inventoryCheckItemStatus
|
|
1035
|
+
checkItem.updater = this.user
|
|
1036
|
+
|
|
1037
|
+
await this.trxMgr.getRepository(InventoryCheckItem).save(checkItem)
|
|
1038
|
+
|
|
1039
|
+
let worksheetDetail = await this.trxMgr.getRepository(WorksheetDetail).findOne({
|
|
1040
|
+
where: { targetInventoryCheckItem: checkItem.id, type: WORKSHEET_TYPE.CYCLE_COUNT }
|
|
1041
|
+
})
|
|
1042
|
+
|
|
1043
|
+
if (worksheetDetail) {
|
|
1044
|
+
worksheetDetail.status = worksheetDetailStatus
|
|
1045
|
+
worksheetDetail.updater = this.user
|
|
1046
|
+
await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
if (totalInspectedQty > 0 && totalInspectedUomValue > 0 && inventoryCheckItems.length > 0) {
|
|
1051
|
+
const lastItem = inventoryCheckItems[inventoryCheckItems.length - 1]
|
|
1052
|
+
lastItem.inspectedQty = (lastItem.inspectedQty ?? 0) + totalInspectedQty
|
|
1053
|
+
lastItem.inspectedUomValue = (lastItem.inspectedUomValue ?? 0) + totalInspectedUomValue
|
|
1054
|
+
await this.trxMgr.getRepository(InventoryCheckItem).save(lastItem)
|
|
1055
|
+
}
|
|
450
1056
|
}
|
|
451
1057
|
|
|
452
1058
|
async completeCycleCount(inventoryCheckNo: string): Promise<Worksheet> {
|
|
@@ -462,51 +1068,53 @@ export class CycleCountWorksheetController extends WorksheetController {
|
|
|
462
1068
|
type: In([WORKSHEET_TYPE.CYCLE_COUNT, WORKSHEET_TYPE.CYCLE_COUNT_RECHECK]),
|
|
463
1069
|
inventoryCheck
|
|
464
1070
|
},
|
|
465
|
-
relations: [
|
|
1071
|
+
relations: [
|
|
1072
|
+
'worksheetDetails',
|
|
1073
|
+
'worksheetDetails.targetInventoryCheckItem',
|
|
1074
|
+
'worksheetDetails.targetInventoryCheckItem.inventory'
|
|
1075
|
+
]
|
|
466
1076
|
})
|
|
467
1077
|
this.checkRecordValidity(worksheet, { status: WORKSHEET_STATUS.EXECUTING })
|
|
468
1078
|
|
|
469
1079
|
const worksheetDetails: WorksheetDetail[] = worksheet.worksheetDetails
|
|
470
|
-
const
|
|
1080
|
+
const targetInventoryCheckItems: InventoryCheckItem[] = worksheetDetails.map(
|
|
1081
|
+
(wsd: WorksheetDetail) => wsd.targetInventoryCheckItem
|
|
1082
|
+
)
|
|
471
1083
|
|
|
472
1084
|
const {
|
|
473
|
-
|
|
474
|
-
|
|
1085
|
+
tallyTargetInventoryCheckItems,
|
|
1086
|
+
notTallyTargetInventoryCheckItems
|
|
475
1087
|
}: {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
} =
|
|
479
|
-
(result,
|
|
480
|
-
if (
|
|
481
|
-
result.
|
|
1088
|
+
tallyTargetInventoryCheckItems: InventoryCheckItem[]
|
|
1089
|
+
notTallyTargetInventoryCheckItems: InventoryCheckItem[]
|
|
1090
|
+
} = targetInventoryCheckItems.reduce(
|
|
1091
|
+
(result, targetInventoryCheckItem: InventoryCheckItem) => {
|
|
1092
|
+
if (targetInventoryCheckItem.status !== INVENTORY_CHECK_ITEM_STATUS.INSPECTED) {
|
|
1093
|
+
result.notTallyTargetInventoryCheckItems.push(targetInventoryCheckItem)
|
|
482
1094
|
} else {
|
|
483
|
-
result.
|
|
1095
|
+
result.tallyTargetInventoryCheckItems.push(targetInventoryCheckItem)
|
|
484
1096
|
}
|
|
485
1097
|
|
|
486
1098
|
return result
|
|
487
1099
|
},
|
|
488
1100
|
{
|
|
489
|
-
|
|
490
|
-
|
|
1101
|
+
tallyTargetInventoryCheckItems: [],
|
|
1102
|
+
notTallyTargetInventoryCheckItems: []
|
|
491
1103
|
}
|
|
492
1104
|
)
|
|
493
1105
|
|
|
494
|
-
const tallyInventories: Inventory[] =
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
1106
|
+
const tallyInventories: Inventory[] = tallyTargetInventoryCheckItems.map(
|
|
1107
|
+
targetInventoryCheckItem => targetInventoryCheckItem.inventory
|
|
1108
|
+
)
|
|
1109
|
+
tallyTargetInventoryCheckItems.forEach((targetInventoryCheckItem: InventoryCheckItem) => {
|
|
1110
|
+
targetInventoryCheckItem.status = INVENTORY_CHECK_ITEM_STATUS.TERMINATED
|
|
1111
|
+
targetInventoryCheckItem.updater = this.user
|
|
498
1112
|
})
|
|
499
|
-
await this.trxMgr.getRepository(
|
|
1113
|
+
await this.trxMgr.getRepository(InventoryCheckItem).save(tallyTargetInventoryCheckItems, { chunk: 500 })
|
|
500
1114
|
|
|
501
|
-
tallyInventories.forEach((inventory: Inventory) => {
|
|
502
|
-
inventory.lockedQty = 0
|
|
503
|
-
inventory.lockedWeight = 0
|
|
504
|
-
inventory.lockedUomValue = 0
|
|
505
|
-
inventory.updater = this.user
|
|
506
|
-
})
|
|
507
1115
|
await this.trxMgr.getRepository(Inventory).save(tallyInventories, { chunk: 500 })
|
|
508
1116
|
|
|
509
|
-
if (
|
|
1117
|
+
if (notTallyTargetInventoryCheckItems.length) {
|
|
510
1118
|
worksheet.status = WORKSHEET_STATUS.NOT_TALLY
|
|
511
1119
|
inventoryCheck.status = ORDER_STATUS.PENDING_REVIEW
|
|
512
1120
|
} else {
|