@things-factory/warehouse-base 8.0.3 → 8.0.6

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.
Files changed (88) hide show
  1. package/dist-server/tsconfig.tsbuildinfo +1 -1
  2. package/package.json +8 -8
  3. package/server/constants/index.ts +0 -5
  4. package/server/constants/inventory.ts +0 -67
  5. package/server/constants/location.ts +0 -14
  6. package/server/constants/pallet.ts +0 -10
  7. package/server/constants/rule-type.ts +0 -5
  8. package/server/constants/tote.ts +0 -5
  9. package/server/controllers/ecommerce/ecommerce-controller.ts +0 -108
  10. package/server/controllers/ecommerce/index.ts +0 -2
  11. package/server/controllers/ecommerce/sellercraft-controller.ts +0 -100
  12. package/server/controllers/index.ts +0 -2
  13. package/server/controllers/warehouse-controller.ts +0 -181
  14. package/server/index.ts +0 -9
  15. package/server/middlewares/index.ts +0 -0
  16. package/server/migrations/index.ts +0 -9
  17. package/server/service/index.ts +0 -80
  18. package/server/service/inventory/index.ts +0 -6
  19. package/server/service/inventory/inventory-mutation.ts +0 -530
  20. package/server/service/inventory/inventory-query.ts +0 -1263
  21. package/server/service/inventory/inventory-types.ts +0 -367
  22. package/server/service/inventory/inventory.ts +0 -408
  23. package/server/service/inventory-change/index.ts +0 -6
  24. package/server/service/inventory-change/inventory-change-mutation.ts +0 -969
  25. package/server/service/inventory-change/inventory-change-query.ts +0 -93
  26. package/server/service/inventory-change/inventory-change-types.ts +0 -36
  27. package/server/service/inventory-change/inventory-change.ts +0 -164
  28. package/server/service/inventory-history/index.ts +0 -6
  29. package/server/service/inventory-history/inventory-history-mutation.ts +0 -116
  30. package/server/service/inventory-history/inventory-history-query.ts +0 -1845
  31. package/server/service/inventory-history/inventory-history-types.ts +0 -444
  32. package/server/service/inventory-history/inventory-history.ts +0 -203
  33. package/server/service/inventory-item/index.ts +0 -6
  34. package/server/service/inventory-item/inventory-item-mutation.ts +0 -217
  35. package/server/service/inventory-item/inventory-item-query.ts +0 -226
  36. package/server/service/inventory-item/inventory-item-type.ts +0 -74
  37. package/server/service/inventory-item/inventory-item.ts +0 -105
  38. package/server/service/inventory-item-change/index.ts +0 -6
  39. package/server/service/inventory-item-change/inventory-item-change-mutation.ts +0 -119
  40. package/server/service/inventory-item-change/inventory-item-change-query.ts +0 -47
  41. package/server/service/inventory-item-change/inventory-item-change-type.ts +0 -68
  42. package/server/service/inventory-item-change/inventory-item-change.ts +0 -92
  43. package/server/service/inventory-product/index.ts +0 -6
  44. package/server/service/inventory-product/inventory-product-mutation.ts +0 -116
  45. package/server/service/inventory-product/inventory-product-query.ts +0 -47
  46. package/server/service/inventory-product/inventory-product-type.ts +0 -59
  47. package/server/service/inventory-product/inventory-product.ts +0 -88
  48. package/server/service/location/index.ts +0 -6
  49. package/server/service/location/location-mutation.ts +0 -134
  50. package/server/service/location/location-query.ts +0 -244
  51. package/server/service/location/location-types.ts +0 -173
  52. package/server/service/location/location.ts +0 -121
  53. package/server/service/movement/index.ts +0 -6
  54. package/server/service/movement/movement-mutation.ts +0 -60
  55. package/server/service/movement/movement-query.ts +0 -263
  56. package/server/service/movement/movement-types.ts +0 -74
  57. package/server/service/movement/movement.ts +0 -81
  58. package/server/service/pallet/index.ts +0 -6
  59. package/server/service/pallet/pallet-mutation.ts +0 -242
  60. package/server/service/pallet/pallet-query.ts +0 -106
  61. package/server/service/pallet/pallet-types.ts +0 -80
  62. package/server/service/pallet/pallet.ts +0 -92
  63. package/server/service/pallet-count/index.ts +0 -6
  64. package/server/service/pallet-count/pallet-count-mutation.ts +0 -151
  65. package/server/service/pallet-count/pallet-count-query.ts +0 -45
  66. package/server/service/pallet-count/pallet-count-types.ts +0 -36
  67. package/server/service/pallet-count/pallet-count.ts +0 -70
  68. package/server/service/pallet-history/index.ts +0 -6
  69. package/server/service/pallet-history/pallet-history-mutation.ts +0 -114
  70. package/server/service/pallet-history/pallet-history-query.ts +0 -48
  71. package/server/service/pallet-history/pallet-history-types.ts +0 -36
  72. package/server/service/pallet-history/pallet-history.ts +0 -89
  73. package/server/service/reduced-inventory-history/index.ts +0 -3
  74. package/server/service/reduced-inventory-history/reduced-inventory-history.ts +0 -92
  75. package/server/service/tote/index.ts +0 -6
  76. package/server/service/tote/tote-mutation.ts +0 -201
  77. package/server/service/tote/tote-query.ts +0 -106
  78. package/server/service/tote/tote-types.ts +0 -44
  79. package/server/service/tote/tote.ts +0 -77
  80. package/server/service/warehouse/index.ts +0 -6
  81. package/server/service/warehouse/warehouse-mutation.ts +0 -152
  82. package/server/service/warehouse/warehouse-query.ts +0 -58
  83. package/server/service/warehouse/warehouse-types.ts +0 -50
  84. package/server/service/warehouse/warehouse.ts +0 -95
  85. package/server/utils/datetime-util.ts +0 -54
  86. package/server/utils/index.ts +0 -3
  87. package/server/utils/inventory-no-generator.ts +0 -15
  88. package/server/utils/inventory-util.ts +0 -490
@@ -1,95 +0,0 @@
1
- import { Field, ID, ObjectType } from 'type-graphql'
2
- import {
3
- Column,
4
- CreateDateColumn,
5
- Entity,
6
- Index,
7
- ManyToOne,
8
- OneToMany,
9
- PrimaryGeneratedColumn,
10
- RelationId,
11
- UpdateDateColumn
12
- } from 'typeorm'
13
-
14
- import { User } from '@things-factory/auth-base'
15
- import { Bizplace } from '@things-factory/biz-base'
16
- import { Domain } from '@things-factory/shell'
17
-
18
- import { Location } from '../location/location'
19
-
20
- @Entity()
21
- @Index('ix_warehouse_0', (warehouse: Warehouse) => [warehouse.domain, warehouse.name], { unique: true })
22
- @Index('ix_warehouse_1', (warehouse: Warehouse) => [warehouse.domain, warehouse.id], { unique: true })
23
- @ObjectType()
24
- export class Warehouse {
25
- @PrimaryGeneratedColumn('uuid')
26
- @Field(type => ID)
27
- id: string
28
-
29
- @ManyToOne(type => Domain)
30
- @Field(type => Domain)
31
- domain: Domain
32
-
33
- @RelationId((warehouse: Warehouse) => warehouse.domain)
34
- domainId: string
35
-
36
- @ManyToOne(type => Bizplace)
37
- @Field()
38
- bizplace: Bizplace
39
-
40
- @Column()
41
- @Field()
42
- name: string
43
-
44
- @OneToMany(type => Location, location => location.warehouse)
45
- @Field(type => [Location])
46
- locations: Location[]
47
-
48
- @Column()
49
- @Field()
50
- type: string
51
-
52
- @Column({
53
- nullable: true
54
- })
55
- @Field({ nullable: true })
56
- description: string
57
-
58
- @ManyToOne(type => User, {
59
- nullable: true
60
- })
61
- @Field({ nullable: true })
62
- creator: User
63
-
64
- @RelationId((warehouse: Warehouse) => warehouse.creator)
65
- creatorId: string
66
-
67
- @ManyToOne(type => User, {
68
- nullable: true
69
- })
70
- @Field({ nullable: true })
71
- updater: User
72
-
73
- @RelationId((warehouse: Warehouse) => warehouse.updater)
74
- updaterId: string
75
-
76
- @CreateDateColumn()
77
- @Field({ nullable: true })
78
- createdAt: Date
79
-
80
- @UpdateDateColumn()
81
- @Field({ nullable: true })
82
- updatedAt: Date
83
-
84
- constructor(obj?) {
85
- if (obj) {
86
- this.id = obj.warehouse_id
87
- this.name = obj.warehouse_name
88
- this.locations = obj.warehouse_locations
89
- this.type = obj.warehouse_type
90
- this.description = obj.warehouse_description
91
- this.createdAt = obj.warehouse_created_at
92
- this.updatedAt = obj.warehouse_updated_at
93
- }
94
- }
95
- }
@@ -1,54 +0,0 @@
1
- export class DateGenerator {
2
- static generateDate() {
3
- const today = new Date()
4
- const year = today.getFullYear()
5
- const month = today.getMonth()
6
- const day = today.getDate()
7
-
8
- const yy = String(year).substr(String(year).length - 2)
9
- const mm = String(month + 1).padStart(2, '0')
10
- const dd = String(day).padStart(2, '0')
11
-
12
- return yy + mm + dd
13
- }
14
- }
15
-
16
- export class DateTimeConverter {
17
- static date(dateTime) {
18
- let unloadDate = ''
19
- if (dateTime) {
20
- const unloadDateTime: Date = new Date(dateTime)
21
- var year = unloadDateTime.getFullYear()
22
-
23
- var month = (1 + unloadDateTime.getMonth()).toString()
24
- month = month.length > 1 ? month : '0' + month
25
-
26
- var day = unloadDateTime.getDate().toString()
27
- day = day.length > 1 ? day : '0' + day
28
-
29
- unloadDate = day + '-' + month + '-' + year
30
- }
31
- return unloadDate
32
- }
33
-
34
- static datetime(dateTime, timezone) {
35
- let unloadDate = ''
36
- if (dateTime) {
37
- const datetime = Number(dateTime)
38
- const timezoneOffset = timezone * 60000
39
- const newUnloadDate = new Date(datetime - timezoneOffset).toISOString().slice(0, -1)
40
-
41
- var dateTimeParts: any = newUnloadDate.split('T')
42
-
43
- //handle date parts
44
- var dateParts = dateTimeParts[0].split('-')
45
- var newDate = DateTimeConverter.date(dateParts)
46
-
47
- //handle time part
48
- var timeParts = dateTimeParts[1].slice(0, -7)
49
-
50
- unloadDate = newDate + ' ' + timeParts
51
- }
52
- return unloadDate
53
- }
54
- }
@@ -1,3 +0,0 @@
1
- export * from './inventory-no-generator'
2
- export * from './inventory-util'
3
- export * from './datetime-util'
@@ -1,15 +0,0 @@
1
- import { v4 as uuidv4 } from 'uuid'
2
-
3
- export class InventoryNoGenerator {
4
- static inventoryName() {
5
- return uuidv4()
6
- }
7
-
8
- static inventoryHistoryName() {
9
- return uuidv4()
10
- }
11
-
12
- static inventoryItemName() {
13
- return uuidv4()
14
- }
15
- }
@@ -1,490 +0,0 @@
1
- import { EntityManager, Repository } from 'typeorm'
2
-
3
- import { User } from '@things-factory/auth-base'
4
- import { Bizplace } from '@things-factory/biz-base'
5
- import { Product } from '@things-factory/product-base'
6
- import { Domain, getRepository } from '@things-factory/shell'
7
-
8
- import { INVENTORY_STATUS, INVENTORY_TRANSACTION_TYPE, LOCATION_STATUS, LOCATION_TYPE } from '../constants'
9
- import { Inventory, InventoryHistory, Location } from '../service'
10
- import { InventoryNoGenerator } from '../utils'
11
-
12
- export class InventoryUtil {
13
- protected trxMgr: EntityManager
14
- protected domain: Domain
15
- protected user: User
16
-
17
- constructor(trxMgr: EntityManager, domain: Domain, user: User) {
18
- this.trxMgr = trxMgr
19
- this.domain = domain
20
- this.user = user
21
- }
22
-
23
- public readonly ERROR_MSG = {
24
- FIND: {
25
- NO_RESULT: (condition: any) => `There's no results matched with condition ${condition}`,
26
- NO_CHILD_RESULT: (condition: any) => `There's no child result matched with condition ${condition}`,
27
- NOT_MATCH: (source: any, target: any) => `Unable to find matching ${target} using ${source}`
28
- },
29
- ORDER_ITEM: {
30
- NO_MATCHING_RESULT: (condition: any, condition2: any) =>
31
- `Current item with ${condition} (${condition2}) not belong to this order`,
32
- EXCESS_QTY: (condition: any, condition2: any, condition3: any) =>
33
- `Excess qty is scanned for item ${condition}, ${condition2} (${condition3})`
34
- },
35
- PRODUCT: {
36
- NO_MATCHING_RESULT: (condition: any, condition2: any) =>
37
- `Order packing type and packing size not match with product master, ${condition} (${condition2})`,
38
- BARCODE_NOT_EXIST: (condition: any, condition2: any, condition3: any) =>
39
- `Product barcode - ${condition} with ${condition2} ${condition3}, not exist in master data.`
40
- },
41
- CREATE: {
42
- ID_EXISTS: 'Target has ID already',
43
- EMPTY_CREATOR: 'Cannot create without creator',
44
- EMPTY_UPDATER: 'Cannot create without updater'
45
- },
46
- UPDATE: {
47
- ID_NOT_EXISTS: `Target doesn't have ID`,
48
- EMPTY_UPDATER: 'Cannot update without updater'
49
- },
50
- VALIDITY: {
51
- UNEXPECTED_FIELD_VALUE: (field: string, expectedValue: any, actualValue: any) =>
52
- `Expected ${field} value is ${expectedValue} but got ${actualValue}`,
53
- DUPLICATED: (field: string, value: any) => `There is duplicated ${field} value (${value})`,
54
- CANT_PROCEED_STEP_BY: (step: string, reason: string) => `Can't proceed to ${step} because ${reason}`
55
- }
56
- }
57
-
58
- async createInventory(inventory: Partial<Inventory>): Promise<Inventory> {
59
- inventory = this.setStamp(inventory)
60
- return await this.trxMgr.getRepository(Inventory).save(inventory)
61
- }
62
-
63
- /**
64
- * @summary Update inventory record
65
- * @description It will update inventory after set a stamp (domain, updater)
66
- * The special point of this function is that this changes won't generate inventory history
67
- * If you want to generate inventory history automatically you would better to use transactionInventory function
68
- */
69
- async updateInventory(inventory: Partial<Inventory>): Promise<Inventory> {
70
- if (!inventory.id) throw new Error(this.ERROR_MSG.UPDATE.ID_NOT_EXISTS)
71
- inventory = this.setStamp(inventory)
72
- return await this.trxMgr.getRepository(Inventory).save(inventory)
73
- }
74
-
75
- /**
76
- * @summary Do transaction on inventory record
77
- * @description It will update inventory after set a temp (domain, updater)
78
- * and then generate inventory history based on current changes
79
- */
80
- async transactionInventory(
81
- inventory: Inventory,
82
- refOrder: any,
83
- changedQty: number,
84
- changedUom: number,
85
- transactionType: string,
86
- description?: string
87
- ): Promise<Inventory> {
88
- if (inventory.id) {
89
- inventory = await this.updateInventory(inventory)
90
- } else {
91
- inventory = await this.createInventory(inventory)
92
- }
93
-
94
- await generateInventoryHistory(
95
- inventory,
96
- refOrder,
97
- transactionType,
98
- changedQty,
99
- changedUom,
100
- this.user,
101
- this.trxMgr,
102
- description || null
103
- )
104
-
105
- return inventory
106
- }
107
-
108
- /**
109
- * @summary set common stamp like domain, creator, updater
110
- * @description Set common stamp to passed record
111
- * If it doesn't have id it will handle it as creating one
112
- * If it has id it will handle it as updating one
113
- */
114
- setStamp(record: Record<string, any>): Record<string, any> {
115
- if (!record.domain) record.domain = this.domain
116
- if (!record.id && !record.creator) record.creator = this.user
117
- if (!record.updater) record.updater = this.user
118
-
119
- return record
120
- }
121
- }
122
-
123
- /**
124
- * @description It will insert new record into inventory histories table.
125
- * seq will be calculated based on number of records for one specific pallet id (provided by inventory object)
126
- */
127
- export async function generateInventoryHistory(
128
- inventory: Inventory,
129
- refOrder: any,
130
- transactionType: string,
131
- qty: number,
132
- uomValue: number,
133
- user: User,
134
- trxMgr?: EntityManager,
135
- description?: string
136
- ): Promise<InventoryHistory> {
137
- const invHistoryRepo: Repository<InventoryHistory> =
138
- trxMgr?.getRepository(InventoryHistory) || getRepository(InventoryHistory)
139
- const invRepo: Repository<Inventory> = trxMgr?.getRepository(Inventory) || getRepository(Inventory)
140
-
141
- if (!inventory?.id) throw new Error(`Can't find out ID of inventory.`)
142
-
143
- inventory = await invRepo.findOne({
144
- where: { id: inventory.id },
145
- relations: ['domain', 'bizplace', 'product', 'warehouse', 'location']
146
- })
147
-
148
- const domain: Domain = inventory.domain
149
- const location: Location = inventory.location
150
-
151
- const lastInvHistory: InventoryHistory = await invHistoryRepo.findOne({
152
- where: {
153
- domain: { id: inventory.domain.id },
154
- palletId: inventory.palletId
155
- },
156
- order: {
157
- seq: 'DESC'
158
- }
159
- })
160
-
161
- let seq: number = 0
162
- let openingQty: number = 0
163
- let openingUomValue: number = 0
164
-
165
- if (lastInvHistory) {
166
- openingQty = lastInvHistory.openingQty + lastInvHistory.qty
167
- openingUomValue = lastInvHistory.openingUomValue + lastInvHistory.uomValue
168
- seq = lastInvHistory.seq + 1
169
- }
170
-
171
- let remainQty = (openingQty || 0) + (qty || 0)
172
-
173
- let inventoryHistory: any = new InventoryHistory()
174
-
175
- inventoryHistory = {
176
- ...inventory,
177
- name: InventoryNoGenerator.inventoryHistoryName(),
178
- description,
179
- inventory,
180
- seq: seq,
181
- status: remainQty == 0 ? INVENTORY_STATUS.TERMINATED : inventory.status,
182
- transactionType,
183
- refOrderId: refOrder?.id || null,
184
- orderNo: refOrder?.name || null,
185
- orderRefNo: refOrder?.refNo || null,
186
- qty,
187
- openingQty,
188
- uomValue,
189
- openingUomValue: openingUomValue,
190
- creator: user,
191
- updater: user
192
- }
193
-
194
- delete inventoryHistory.updatedAt
195
- delete inventoryHistory.createdAt
196
- delete inventoryHistory.id
197
-
198
- let newInventoryHistory = await invHistoryRepo.save(inventoryHistory)
199
-
200
- if (remainQty == 0) {
201
- seq = seq + 1
202
- let terminatedHistory = {
203
- ...newInventoryHistory,
204
- name: InventoryNoGenerator.inventoryHistoryName(),
205
- seq: seq,
206
- status: INVENTORY_STATUS.TERMINATED,
207
- transactionType: INVENTORY_TRANSACTION_TYPE.TERMINATED,
208
- uom: inventory.uom,
209
- qty: 0,
210
- openingQty: 0,
211
- uomValue: 0,
212
- openingUomValue: 0
213
- }
214
-
215
- delete terminatedHistory.id
216
-
217
- newInventoryHistory = await invHistoryRepo.save(terminatedHistory)
218
- inventory.status = INVENTORY_STATUS.TERMINATED
219
- }
220
-
221
- if (inventory.lastSeq !== seq) {
222
- await invRepo.update(inventory.id, { lastSeq: newInventoryHistory.seq, updater: user })
223
- }
224
-
225
- await switchLocationStatus(domain, location, user, trxMgr)
226
- return newInventoryHistory
227
- }
228
-
229
- /**
230
- * @description: Check location emptiness and update status of location
231
- * @param domain
232
- * @param location
233
- * @param updater
234
- * @param trxMgr
235
- */
236
- export async function switchLocationStatus(
237
- domain: Domain,
238
- location: Location,
239
- updater: User,
240
- trxMgr?: EntityManager
241
- ): Promise<Location> {
242
- const invRepo: Repository<Inventory> = trxMgr?.getRepository(Inventory) || getRepository(Inventory)
243
- const locationRepo: Repository<Location> = trxMgr?.getRepository(Location) || getRepository(Location)
244
- const allocatedItemsCnt: number = await invRepo.countBy({
245
- domain: { id: domain.id },
246
- status: INVENTORY_STATUS.STORED,
247
- location: { id: location.id }
248
- })
249
-
250
- if (!allocatedItemsCnt && location.status !== LOCATION_STATUS.EMPTY) {
251
- location = await locationRepo.save({
252
- ...location,
253
- status: LOCATION_STATUS.EMPTY,
254
- updater
255
- })
256
- } else if (allocatedItemsCnt && location.status === LOCATION_STATUS.EMPTY) {
257
- location = await locationRepo.save({
258
- ...location,
259
- status: LOCATION_STATUS.OCCUPIED,
260
- updater
261
- })
262
- }
263
-
264
- return location
265
- }
266
-
267
- export async function checkPalletDuplication(
268
- domain: Domain,
269
- bizplace: Bizplace,
270
- palletId: string,
271
- trxMgr?: EntityManager
272
- ): Promise<boolean> {
273
- const invRepo: Repository<Inventory> = trxMgr?.getRepository(Inventory) || getRepository(Inventory)
274
- const duplicatedPalletCnt: number = await invRepo.countBy({
275
- domain: { id: domain.id },
276
- bizplace: { id: bizplace.id },
277
- palletId
278
- })
279
-
280
- return Boolean(duplicatedPalletCnt)
281
- }
282
-
283
- /**
284
- * @description Check whether inventory is same with passed conditions
285
- * @param {Domain} domain
286
- * @param {Bizplace} bizplace
287
- * @param {String} palletId
288
- * @param {String} batchId
289
- * @param {String | Product} product
290
- * @param {String} packingType
291
- * @param {EntityManager} trxMgr
292
- */
293
- export async function checkPalletIdenticallity(
294
- domain: Domain,
295
- bizplace: Bizplace,
296
- palletId: string,
297
- batchId: string,
298
- product: string | Product,
299
- packingType: string,
300
- trxMgr?: EntityManager
301
- ): Promise<{ identicallity: boolean; errorMessage?: string }> {
302
- const productRepo: Repository<Product> = trxMgr?.getRepository(Product) || getRepository(Product)
303
- const invRepo: Repository<Inventory> = trxMgr?.getRepository(Inventory) || getRepository(Inventory)
304
-
305
- if (typeof product === 'string') {
306
- const foundProduct: Product = await productRepo.findOneBy({ id: product }) /* TODO check migration typeorm 0.3 */
307
- if (!foundProduct) throw new Error(`Failed to find product with ${product}`)
308
- product = foundProduct
309
- }
310
-
311
- const inv: Inventory = await invRepo.findOne({
312
- where: { domain: { id: domain.id }, bizplace: { id: bizplace.id }, palletId },
313
- relations: ['product']
314
- })
315
-
316
- if (batchId !== inv.batchId) return { identicallity: false, errorMessage: `Batch ID is not matched with ${batchId}` }
317
-
318
- if (product?.id !== inv?.product?.id)
319
- return { identicallity: false, errorMessage: `Product is not matched with ${product.name}` }
320
-
321
- if (packingType !== inv.packingType)
322
- return { identicallity: false, errorMessage: `Packing Type is not matched with ${packingType}` }
323
-
324
- return { identicallity: true }
325
- }
326
-
327
- /**
328
- * @description Check whether inventory is same with passed conditions
329
- * @param {Domain} domain
330
- * @param {Domain} productOwnerDomain
331
- * @param {OrderProduct} bizplace *
332
- * @param {EntityManager} trxMgr
333
- */
334
- export async function getProductBundleInventory(
335
- domain: Domain,
336
- productOwnerDomain: Domain,
337
- orderProducts: any[],
338
- trxMgr: EntityManager
339
- ): Promise<any> {
340
- let orderProductsJson = JSON.stringify(
341
- orderProducts.map(itm => {
342
- return {
343
- ...itm,
344
- product_id: itm.product.id,
345
- packing_type: itm.packingType,
346
- packing_size: itm.packingSize,
347
- uom: itm.uom
348
- }
349
- }) || []
350
- )
351
-
352
- const result: any[] = await trxMgr.query(
353
- `
354
- select product_bundle_id, sku, name, min(available_qty) as qty from (
355
- select
356
- pb.sku, pb.name, pbs.product_bundle_id, pbs.bundle_qty, pd.product_id, pd.packing_type, pd.packing_size, pd.uom,
357
- floor(coalesce(sum(inv.qty - coalesce(inv.locked_qty,0)),0)/pbs.bundle_qty) as available_qty,
358
- floor(coalesce(sum(inv.uom_value - coalesce(inv.locked_uom_value,0)),0)/pbs.bundle_qty) as available_uom_value
359
- from (
360
- select pb.id, pb.sku, pb.name
361
- from json_populate_recordset(NULL::order_products,'${orderProductsJson}') src
362
- inner join product_details pd ON src.product_id = pd.product_id and src.packing_type = pd.packing_type and src.packing_size = pd.packing_size and src.uom = pd.uom
363
- inner join product_bundle_settings pbs on pbs.product_detail_id = pd.id
364
- inner join product_bundles pb on pb.id = pbs.product_bundle_id and pb.status = 'ACTIVATED'
365
- where pb.domain_id = $1
366
- group by pb.id, pb.sku, pb.name
367
- ) pb
368
- inner join product_bundle_settings pbs on pbs.product_bundle_id = pb.id
369
- inner join product_details pd on pd.id = pbs.product_detail_id
370
- left join inventories inv on ((inv.status <> 'TERMINATED' and (inv.qty - coalesce(inv.locked_qty,0)) > 0) or (inv.status = 'TERMINATED' and (inv.qty - coalesce(inv.locked_qty,0)) = 0)) and inv.product_id = pd.product_id and inv.packing_type = pd.packing_type and inv.packing_size = pd.packing_size and inv.uom = pd.uom
371
- where inv.domain_id = $2
372
- group by pb.sku, pb.name, pbs.product_bundle_id, pbs.bundle_qty, pd.product_id, pd.packing_type, pd.packing_size, pd.uom
373
- ) foo group by product_bundle_id, sku, name
374
- `,
375
- [productOwnerDomain.id, domain.id]
376
- )
377
-
378
- return result
379
- }
380
-
381
- /**
382
- * @description This function will return multiple products
383
- * and it is different with @inventoriesByStrategy that returns
384
- * inventories for one product only
385
- * @param {string} bizplaceId
386
- * @param {string} worksheetId
387
- * @param {any[]} orderProducts
388
- * @param {string} pickingStrategy
389
- * @param {[Object]} locationSortingRules
390
- * @param {EntityManager} trxMgr
391
- * @returns inventories for multiple products
392
- */
393
- export async function getInventoriesByStrategy(
394
- domainId: string,
395
- bizplaceId: string,
396
- worksheetId: string,
397
- orderProducts: any[],
398
- locationSortingRules: any[],
399
- trxMgr: EntityManager
400
- ): Promise<Inventory[]> {
401
- let orderProductsJSON: string = JSON.stringify(orderProducts)
402
- let locationSorting: string = (locationSortingRules || [])
403
- .map((rule: { name: string; descOrder: boolean }) => {
404
- return `l.${rule.name}${rule.descOrder ? 'DESC' : ''}`
405
- })
406
- .join(', ')
407
-
408
- if (locationSorting === '') locationSorting = 'l.name'
409
-
410
- await trxMgr.query(
411
- `
412
- CREATE TEMP TABLE temp_op2(
413
- "productId" VARCHAR(50),
414
- "batchId" VARCHAR(50),
415
- "packingType" VARCHAR(50),
416
- "packingSize" INT,
417
- "uom" VARCHAR(10),
418
- "releaseQty" INT,
419
- "pickingStrategy" VARCHAR(25),
420
- "orderProductId" VARCHAR(50)
421
- );
422
- `
423
- )
424
-
425
- await trxMgr.query(
426
- `
427
- INSERT INTO temp_op2
428
- SELECT "productId", "batchId", "packingType", "packingSize", "uom", "releaseQty", "pickingStrategy", "orderProductId"
429
- FROM JSON_POPULATE_RECORDSET(NULL::temp_op2, $1) js
430
- `,
431
- [orderProductsJSON]
432
- )
433
-
434
- await trxMgr.query(
435
- `
436
- CREATE TEMP TABLE acc_oi2 AS (
437
- SELECT oi.inventory_id, SUM(oi.release_qty) AS total_release_qty, SUM(oi.release_uom_value) AS total_release_uom_value
438
- FROM order_inventories oi
439
- WHERE oi.status IN ('PENDING','PENDING_RECEIVE','PENDING_WORKSHEET','PENDING_SPLIT')
440
- AND oi.bizplace_id = $1
441
- AND oi.inventory_id NOTNULL
442
- AND oi.ref_worksheet_id != $2
443
- GROUP BY oi.inventory_id
444
- )
445
- `,
446
- [bizplaceId, worksheetId]
447
- )
448
-
449
- // get inventories
450
- let inventories = await trxMgr.query(
451
- `
452
- SELECT
453
- i.id,
454
- op."productId",
455
- op."batchId",
456
- i.qty - COALESCE(i.locked_qty,0) - COALESCE(foo.total_release_qty,0) AS "remainQty",
457
- i.uom_value - COALESCE(i.locked_uom_value,0) - COALESCE(foo.total_release_uom_value,0) AS "remainUomValue",
458
- op."packingType",
459
- op."packingSize",
460
- op."uom",
461
- op."orderProductId",
462
- ROW_NUMBER() OVER (
463
- PARTITION BY op."productId", op."batchId", op."packingType", op."packingSize", op."uom"
464
- ORDER BY
465
- CASE WHEN op."pickingStrategy" = 'FIFO' THEN i.created_at END,
466
- CASE WHEN op."pickingStrategy" = 'FEFO' THEN i.expiration_date END,
467
- CASE WHEN op."pickingStrategy" = 'LIFO' THEN i.created_at END DESC,
468
- CASE WHEN op."pickingStrategy" = 'FMFO' THEN i.manufacture_date END,
469
- ${locationSorting}
470
- ) AS rn
471
- FROM inventories i
472
- INNER JOIN locations l ON i.location_id = l.id
473
- AND l.TYPE NOT IN ($1, $2)
474
- INNER JOIN temp_op2 op ON i.product_id = op."productId"::uuid
475
- AND i.batch_id = op."batchId"
476
- AND i.packing_type = op."packingType"
477
- AND i.packing_size = op."packingSize"
478
- LEFT JOIN acc_oi2 foo ON i.id = foo.inventory_id
479
- WHERE i.domain_id = $3
480
- AND i.bizplace_id = $4
481
- AND i.status = $5
482
- ORDER BY op."productId", rn
483
- `,
484
- [LOCATION_TYPE.QUARANTINE, LOCATION_TYPE.RESERVE, domainId, bizplaceId, INVENTORY_STATUS.STORED]
485
- )
486
-
487
- await trxMgr.query('DROP TABLE temp_op2, acc_oi2')
488
-
489
- return inventories
490
- }