@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,1845 +0,0 @@
1
- import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'
2
- import { Between, Brackets, EntityManager, In, IsNull, Raw, SelectQueryBuilder } from 'typeorm'
3
-
4
- import { User } from '@things-factory/auth-base'
5
- import { Bizplace, getMyBizplace, getPermittedBizplaceIds } from '@things-factory/biz-base'
6
- import { Product, ProductDetail } from '@things-factory/product-base'
7
- import {
8
- buildQuery,
9
- convertListParams,
10
- Domain,
11
- Filter,
12
- getRepository,
13
- ListParam,
14
- Pagination,
15
- Sorting
16
- } from '@things-factory/shell'
17
-
18
- import { RawInventoryHistoryList } from '../'
19
- import { InventoryList } from '../inventory/inventory-types'
20
- import { Location } from '../location/location'
21
- import { Warehouse } from '../warehouse/warehouse'
22
- import { InventoryHistory } from './inventory-history'
23
- import {
24
- InventoryHistoryList,
25
- InventoryHistoryPalletReportList,
26
- InventoryHistoryPatch,
27
- InventoryHistorySummaryList,
28
- InventoryHistoryVolumeSummaryReportList
29
- } from './inventory-history-types'
30
-
31
- @Resolver(InventoryHistory)
32
- export class InventoryHistoryQuery {
33
- @Query(returns => InventoryHistoryList)
34
- async inventoryHistories(
35
- @Args(type => ListParam) params: ListParam,
36
- @Ctx() context: ResolverContext
37
- ): Promise<InventoryHistoryList> {
38
- const { domain, user } = context.state
39
-
40
- if (!params.filters.find((filter: any) => filter.name === 'bizplace')) {
41
- params.filters.push({
42
- name: 'bizplace',
43
- operator: 'in',
44
- value: await getPermittedBizplaceIds(domain, user)
45
- })
46
- }
47
-
48
- const convertedParams = convertListParams(params)
49
- let [items, total] = await getRepository(InventoryHistory).findAndCount({
50
- ...convertedParams,
51
- relations: ['domain', 'bizplace', 'product', 'location', 'warehouse', 'creator', 'updater'],
52
- order: {
53
- ...convertedParams.order,
54
- palletId: 'DESC',
55
- createdAt: 'ASC'
56
- }
57
- })
58
-
59
- items = (await Promise.all(
60
- items.map(async item => {
61
- switch (item.transactionType) {
62
- case 'UNLOADING':
63
- item.description = 'Inbound'
64
- break
65
- case 'UNDO_UNLOADING':
66
- item.description = 'Undo Unloading'
67
- item.orderRefNo = ''
68
- break
69
- case 'LOADING':
70
- item.description = 'Loading'
71
- break
72
- case 'UNDO_LOADING':
73
- item.description = 'Undo Loading'
74
- break
75
- default:
76
- item.description = String(item.transactionType)
77
- break
78
- }
79
- item.description = item.description.toUpperCase()
80
- return {
81
- ...item,
82
- orderRefNo: item.orderRefNo,
83
- orderNo: item.orderNo,
84
- qty: item.qty,
85
- openingQty: item.openingQty
86
- }
87
- })
88
- )) as any
89
-
90
- return { items, total }
91
- }
92
-
93
- @Query(returns => InventoryHistoryList)
94
- async renewInventoryHistories(
95
- @Args(type => ListParam) params: ListParam,
96
- @Ctx() context: ResolverContext
97
- ): Promise<InventoryHistoryList> {
98
- const { domain, user } = context.state
99
-
100
- if (!params.filters.find((filter: any) => filter.name === 'bizplace')) {
101
- params.filters.push({
102
- name: 'bizplace',
103
- operator: 'in',
104
- value: await getPermittedBizplaceIds(domain, user)
105
- })
106
- }
107
-
108
- const convertedParams = convertListParams(params)
109
- let [items, total] = await getRepository(InventoryHistory).findAndCount({
110
- ...convertedParams,
111
- relations: ['domain', 'bizplace', 'product', 'location', 'inventory', 'warehouse', 'creator', 'updater'],
112
- order: {
113
- ...convertedParams.order,
114
- palletId: 'DESC',
115
- createdAt: 'ASC'
116
- }
117
- })
118
-
119
- return { items, total }
120
- }
121
-
122
- @Query(returns => InventoryHistory)
123
- async inventoryHistory(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<InventoryHistory> {
124
- const { domain } = context.state
125
-
126
- return await getRepository(InventoryHistory).findOne({
127
- where: { domain: { id: domain.id }, name },
128
- relations: ['domain', 'creator', 'updater']
129
- })
130
- }
131
-
132
- @Directive('@transaction')
133
- @Query(returns => InventoryHistoryList)
134
- async bizplaceInventoryHistories(
135
- @Ctx() context: ResolverContext,
136
- @Arg('inventoryHistory', type => InventoryHistoryPatch, { nullable: true })
137
- inventoryHistory?: InventoryHistoryPatch,
138
- @Arg('filters', type => [Filter], { nullable: true }) filters?: Filter[],
139
- @Arg('pagination', type => Pagination, { nullable: true }) pagination?: Pagination,
140
- @Arg('sortings', type => [Sorting], { nullable: true }) sortings?: Sorting[]
141
- ): Promise<InventoryHistoryList> {
142
- const { domain, user, tx } = context.state
143
-
144
- const ownerBizplace: Bizplace = await getMyBizplace(domain, user)
145
- const customerBizplace: Bizplace = await tx.getRepository(Bizplace).findOneBy({ id: inventoryHistory.bizplace.id })
146
-
147
- const productFilters = filters.find(x => x.name == 'product_info')
148
- filters = filters.filter(x => x.name != 'product_info')
149
-
150
- const fromDate: Date = new Date(inventoryHistory.fromDate)
151
- const toDate: Date = new Date(inventoryHistory.toDate)
152
-
153
- const convertedParams = convertListParams({ filters, pagination, sortings })
154
- let where = { domain: domain }
155
-
156
- if (productFilters) {
157
- let productFilterValue = `%${productFilters.value.toLowerCase()}%`
158
- const productQb: SelectQueryBuilder<Product> = getRepository(Product).createQueryBuilder('prd')
159
-
160
- productQb.where(
161
- new Brackets(qb => {
162
- qb.where('Lower(prd.sku) LIKE :productInfo', { productInfo: productFilterValue })
163
- .orWhere('Lower(prd.name) LIKE :productInfo', { productInfo: productFilterValue })
164
- .orWhere('Lower(prd.description) LIKE :productInfo', { productInfo: productFilterValue })
165
- .orWhere('Lower(prd.brand) LIKE :productInfo', { productInfo: productFilterValue })
166
- })
167
- )
168
-
169
- const _products = await productQb.getMany()
170
-
171
- where['product'] = In(_products.map((product: Product) => product.id))
172
- }
173
-
174
- if (inventoryHistory && inventoryHistory.warehouseName) {
175
- const _warehouses: Warehouse[] = await tx.getRepository(Warehouse).findBy({
176
- domain: { id: domain.id },
177
- name: Raw(alias => `LOWER(${alias}) LIKE '${inventoryHistory.warehouseName.toLowerCase()}'`)
178
- })
179
- where['warehouse'] = In(_warehouses.map((warehouse: Warehouse) => warehouse.id))
180
- }
181
-
182
- if (inventoryHistory && inventoryHistory.locationName) {
183
- const _locations = await tx.getRepository(Location).find({
184
- where: {
185
- domain: { id: domain.id },
186
- name: Raw(alias => `LOWER(${alias}) LIKE '${inventoryHistory.locationName.toLowerCase()}'`)
187
- }
188
- })
189
- where['location'] = In(_locations.map((location: Location) => location.id))
190
- }
191
-
192
- where['createdAt'] = Between(fromDate, toDate)
193
-
194
- convertedParams.where = {
195
- ...convertedParams.where,
196
- ...where,
197
- bizplace: customerBizplace
198
- } as any
199
-
200
- const [items, total] = await tx.getRepository(InventoryHistory).findAndCount({
201
- ...convertedParams,
202
- relations: ['domain', 'product', 'warehouse', 'location', 'bizplace', 'updater'],
203
- order: {
204
- palletId: 'ASC',
205
- seq: 'ASC'
206
- }
207
- })
208
-
209
- return { items, total }
210
- }
211
-
212
- @Directive('@transaction')
213
- @Query(returns => [InventoryHistory])
214
- async inventoryHistoryReport(
215
- @Args(type => ListParam) params: ListParam,
216
- @Ctx() context: ResolverContext
217
- ): Promise<InventoryHistory[]> {
218
- try {
219
- const { domain, tx } = context.state
220
-
221
- let bizplaceFilter: Filter = { name: '', operator: '', value: '' }
222
- let userFilter = params.filters.find(data => data.name === 'user')
223
- let fromDate = params.filters.find(data => data.name === 'fromDate')
224
- let toDate = params.filters.find(data => data.name === 'toDate')
225
- let batchNo = params.filters.find(data => data.name === 'batchNo')
226
- let product = params.filters.find(data => data.name === 'product')
227
- let productDesc = params.filters.find(data => data.name === 'productDescription')
228
- let hasTransactionOrBalanceFilter = params.filters.find(data => data.name === 'hasTransactionOrBalance')
229
- let tzoffset = params.filters.find(data => data.name === 'tzoffset').value + ' seconds'
230
-
231
- if (userFilter) {
232
- const user = (await tx.getRepository(User).findOne({
233
- where: { id: userFilter.value },
234
- relations: ['bizplaces']
235
- })) as User & { bizplaces: Bizplace[] }
236
-
237
- const bizplace: Bizplace = user.bizplaces[0]
238
-
239
- if (!bizplace) throw 'Invalid input'
240
-
241
- bizplaceFilter = { name: 'bizplace', operator: 'eq', value: bizplace.id }
242
- } else {
243
- bizplaceFilter = params.filters.find(data => data.name === 'bizplace')
244
- }
245
-
246
- if (!bizplaceFilter || !fromDate || !toDate) throw 'Invalid input'
247
-
248
- const bizplace: Bizplace = await tx.getRepository(Bizplace).findOneBy({
249
- id: bizplaceFilter.value
250
- })
251
-
252
- let batchNoQuery = ''
253
- if (batchNo) {
254
- batchNoQuery =
255
- 'AND Lower(invh.batch_id) LIKE ANY(ARRAY[' +
256
- batchNo.value
257
- .toLowerCase()
258
- .split(',')
259
- .map(prod => {
260
- return "'%" + prod.trim().replace(/'/g, "''") + "%'"
261
- })
262
- .join(',') +
263
- '])'
264
- }
265
-
266
- let productQuery = ''
267
- if (product) {
268
- let productValue = product.value
269
- .toLowerCase()
270
- .split(',')
271
- .map(prod => {
272
- return "'%" + prod.trim().replace(/'/g, "''") + "%'"
273
- })
274
- .join(',')
275
- productQuery = `AND (
276
- Lower(prd.name) LIKE ANY(ARRAY[${productValue}])
277
- OR Lower(prd.sku) LIKE ANY(ARRAY[${productValue}])
278
- OR Lower(prd.description) LIKE ANY(ARRAY[${productValue}])
279
- )`
280
- }
281
-
282
- let productDescQuery = ''
283
- if (productDesc) {
284
- productDescQuery = "AND Lower(description) LIKE '%" + productDesc.value.toLowerCase() + "%'"
285
- }
286
-
287
- let hasTransactionOrBalanceQuery = ''
288
- if (hasTransactionOrBalanceFilter && hasTransactionOrBalanceFilter.value) {
289
- hasTransactionOrBalanceQuery = 'and (src.totalRow > 1 or src.totalQty <> 0)'
290
- }
291
-
292
- await tx.query(
293
- `
294
- create temp table temp_products AS
295
- (
296
- select prd.*, prd.id::varchar as product_id from products prd
297
- inner join bizplaces b on b.id = prd.bizplace_id
298
- inner join companies c on c.domain_id = b.domain_id
299
- inner join bizplaces b2 on b2.company_id = c.id
300
- where b2.id = $1
301
- ${productQuery}
302
- )`,
303
- [bizplace.id]
304
- )
305
-
306
- await tx.query(
307
- `
308
- create temp table temp_data_src AS
309
- (
310
- SELECT prd.sku as sku, prd.name AS product_name, prd.description AS product_description, prd.type as product_type, prd.aux_value_1 AS product_aux_value_1, trim(invh.batch_id) as batch_id, invh.product_id,
311
- invh.packing_type, invh.bizplace_id, invh.domain_id,
312
- invh.ref_order_id, invh.order_no, invh.order_ref_no, invh.transaction_type, invh.status, invh.created_at,
313
- invh.qty, invh.opening_qty,
314
- invh.uom, COALESCE(invh.uom_value, 0) as uom_value, COALESCE(invh.opening_uom_value, 0) as opening_uom_value
315
- FROM reduced_inventory_histories invh
316
- INNER JOIN temp_products prd ON prd.id = invh.product_id::uuid
317
- WHERE
318
- invh.domain_id = $1
319
- AND invh.bizplace_id = $2
320
- AND invh.created_at <= $3::timestamp
321
- ${batchNoQuery}
322
- )
323
- `,
324
- [domain.id, bizplace.id, toDate.value]
325
- )
326
-
327
- await tx.query(
328
- `
329
- create temp table temp_inv_history as (
330
- SELECT src.sku, src.product_name, src.product_description, src.product_type, src.product_aux_value_1, src.batch_id, src.product_id, src.packing_type, src.uom,
331
- src.bizplace_id, src.domain_id,
332
- SUM(COALESCE(src.qty,0)) AS qty,
333
- SUM(COALESCE(src.opening_qty,0)) AS opening_qty,
334
- SUM(COALESCE(src.uom_value,0)) AS uom_value,
335
- SUM(COALESCE(src.opening_uom_value,0)) AS opening_uom_value,
336
- 'Opening Balance' AS order_name,
337
- '-' AS ref_no,
338
- 0 AS rn,
339
- $1::timestamp AS created_at,
340
- $1::date AS created_date
341
- FROM temp_data_src src
342
- WHERE src.created_at < $1::timestamp
343
- GROUP BY src.sku, src.product_name, src.product_description, src.product_type, src.product_aux_value_1, src.batch_id, src.product_id, src.packing_type, src.uom,
344
- src.bizplace_id, src.domain_id
345
- UNION ALL
346
- SELECT sku, product_name, product_description, product_type, product_aux_value_1, batch_id, product_id, packing_type, uom, bizplace_id,
347
- domain_id, sum(qty) as qty, sum(opening_qty) as opening_qty, sum(uom_value) as uom_value, sum(opening_uom_value) as opening_uom_value,
348
- order_name, ref_no, 1 AS rn, MIN(created_at) - $2::interval as created_at, (MIN(created_at) - $2::interval)::DATE as created_date
349
- FROM (
350
- SELECT invh.sku, invh.product_name, invh.product_description, invh.product_type, invh.product_aux_value_1, invh.batch_id, invh.product_id, invh.packing_type, invh.bizplace_id,
351
- invh.domain_id,
352
- invh.qty, invh.opening_qty, invh.uom_value, invh.uom, invh.opening_uom_value,
353
- COALESCE(order_no, '-') AS order_name,
354
- COALESCE(order_ref_no, '-') AS ref_no,
355
- invh.created_at,
356
- invh.created_at::date as created_date
357
- FROM temp_data_src invh
358
- WHERE (invh.qty <> 0 OR invh.uom_value <> 0) AND
359
- invh.transaction_type <> 'ADJUSTMENT' AND
360
- invh.transaction_type <>'NEW'
361
- AND invh.created_at >= $1::timestamp
362
- ) AS inv_movement
363
- GROUP BY sku, product_name, product_description, product_type, product_aux_value_1, batch_id, product_id, packing_type, uom, bizplace_id,
364
- domain_id, order_name, ref_no, rn
365
- UNION ALL
366
- SELECT sku, product_name, product_description, product_type, product_aux_value_1, batch_id, product_id, packing_type, uom, bizplace_id,
367
- domain_id, sum(qty) as qty, sum(opening_qty) as opening_qty, sum(uom_value) as uom_value, sum(opening_uom_value) as opening_uom_value,
368
- order_name, ref_no, 1 AS rn, created_at - $2::interval as created_at, created_at::date as created_date
369
- FROM (
370
- SELECT invh.sku, invh.product_name, invh.product_description, invh.product_type, invh.product_aux_value_1, invh.batch_id, invh.product_id, invh.packing_type, invh.uom, invh.bizplace_id,
371
- invh.domain_id,
372
- invh.qty, invh.opening_qty, invh.uom_value, invh.opening_uom_value,
373
- invh.transaction_type AS order_name,
374
- invh.transaction_type AS ref_no,
375
- invh.created_at,
376
- invh.created_at:: date as created_date
377
- FROM temp_data_src invh
378
- WHERE (invh.qty <> 0 OR invh.uom_value <> 0) AND
379
- (invh.transaction_type = 'ADJUSTMENT' OR
380
- invh.transaction_type = 'NEW')
381
- AND invh.created_at >= $1::timestamp
382
- ) AS inv_movement
383
- GROUP BY sku, product_name, product_description, product_type, product_aux_value_1, batch_id, product_id, packing_type, uom, bizplace_id,
384
- domain_id, order_name, ref_no, rn, created_at
385
- UNION ALL
386
- SELECT sku, product_name, product_description, product_type, product_aux_value_1, batch_id, product_id, packing_type, uom, bizplace_id,
387
- domain_id, sum(-opening_qty) as qty, sum(opening_qty) as opening_qty, sum(-opening_uom_value) as uom_value, sum(opening_uom_value) as opening_uom_value,
388
- order_name, ref_no, 1 AS rn, created_at - $2::interval as created_at, created_at::date as created_date
389
- FROM (
390
- SELECT invh.sku, invh.product_name, invh.product_description, invh.product_type, invh.product_aux_value_1, invh.batch_id, invh.product_id, invh.packing_type, invh.uom, invh.bizplace_id,
391
- invh.domain_id,
392
- invh.qty, invh.opening_qty, invh.uom_value, invh.opening_uom_value,
393
- invh.transaction_type AS order_name,
394
- invh.transaction_type AS ref_no,
395
- invh.created_at,
396
- invh.created_at:: date as created_date
397
- FROM temp_data_src invh
398
- WHERE
399
- invh.transaction_type = 'ADJUSTMENT' AND
400
- invh.status = 'MISSING'
401
- AND invh.created_at >= $1::timestamp
402
- ) AS inv_movement
403
- GROUP BY sku, product_name, product_description, product_type, product_aux_value_1, batch_id, product_id, packing_type, uom, bizplace_id,
404
- domain_id, order_name, ref_no, rn, created_at
405
-
406
- )`,
407
- [fromDate.value, tzoffset]
408
- )
409
-
410
- const result: any = await tx.query(
411
- `
412
- select sku, product_name, product_description, product_type, product_aux_value_1, batch_id, product_id, packing_type, uom, bizplace_id,
413
- domain_id, qty, opening_qty, round(uom_value::decimal,2) as uom_value, opening_uom_value, order_name, ref_no, created_at::date
414
- from temp_inv_history invh where
415
- exists (
416
- select * from (
417
- select sku, batch_id, product_name, packing_type, sum(qty) as totalQty, count(*) as totalRow from temp_inv_history ih2
418
- group by sku, batch_id, product_name, packing_type
419
- ) src
420
- where src.sku = invh.sku and src.batch_id = invh.batch_id and src.product_name = invh.product_name and src.packing_type = invh.packing_type
421
- ${hasTransactionOrBalanceQuery}
422
- )
423
- ORDER BY invh.sku asc, invh.product_name asc, invh.product_description asc, invh.packing_type asc, invh.batch_id asc, invh.uom asc, invh.rn asc, invh.created_at asc
424
- `
425
- )
426
-
427
- tx.query(
428
- `
429
- drop table temp_products, temp_data_src, temp_inv_history
430
- `
431
- )
432
-
433
- let items = result as any
434
- items = items.map(item => {
435
- return {
436
- batchId: item.batch_id,
437
- bizplace: bizplace,
438
- packingType: item.packing_type,
439
- product: {
440
- id: item.product_id,
441
- sku: item.sku,
442
- name:
443
- item.product_name +
444
- ' ( ' +
445
- item.product_description +
446
- ' ) ' +
447
- (item.product_aux_value_1 === null ? '' : ' [ ' + item.product_aux_value_1 + ' ] '),
448
- type: item.product_type
449
- },
450
- qty: item.qty,
451
- uom: item.uom,
452
- uomValue: item.uom_value,
453
- openingQty: item.opening_qty,
454
- openingUomValue: item.opening_uom_value,
455
- orderNo: item.order_name,
456
- orderRefNo: item.ref_no,
457
- createdAt: item.created_at,
458
- palletId: ''
459
- }
460
- })
461
-
462
- return items
463
- } catch (error) {
464
- throw error
465
- }
466
- }
467
-
468
- @Directive('@transaction')
469
- @Query(returns => [InventoryHistory])
470
- async inventoryHistoryPalletReport(
471
- @Args(type => ListParam) params: ListParam,
472
- @Ctx() context: ResolverContext
473
- ): Promise<InventoryHistory[]> {
474
- try {
475
- const { domain, tx } = context.state
476
- let userFilter = params.filters.find(data => data.name === 'user')
477
-
478
- let bizplaceFilter: Filter = { name: '', operator: '', value: '' }
479
-
480
- if (userFilter) {
481
- const user = (await tx.getRepository(User).findOne({
482
- where: { id: userFilter.value },
483
- relations: ['bizplaces']
484
- })) as User & { bizplaces: Bizplace[] }
485
-
486
- const bizplace: Bizplace = user.bizplaces[0]
487
-
488
- if (!bizplace) throw 'Invalid input'
489
-
490
- bizplaceFilter = { name: 'bizplace', operator: 'eq', value: bizplace.id }
491
- } else {
492
- bizplaceFilter = params.filters.find(data => data.name === 'bizplace')
493
- }
494
-
495
- let fromDate = params.filters.find(data => data.name === 'fromDate')
496
- let toDate = params.filters.find(data => data.name === 'toDate')
497
- let product = params.filters.find(data => data.name === 'product')
498
-
499
- if (!fromDate || !toDate) throw 'Invalid input'
500
-
501
- let bizplaceQuery = ''
502
- if (bizplaceFilter) {
503
- const bizplace: Bizplace = await tx.getRepository(Bizplace).findOneBy({
504
- id: bizplaceFilter.value
505
- })
506
-
507
- if (bizplace) {
508
- bizplaceQuery = "AND i2.bizplace_id = '" + bizplace.id + "'"
509
- } else {
510
- throw 'Invalid input'
511
- }
512
- }
513
-
514
- let productQuery = ''
515
- if (product) {
516
- productQuery =
517
- 'AND prd.name ILIKE ANY(ARRAY[' +
518
- product.value
519
- .split(',')
520
- .map(prod => {
521
- return "'%" + prod.trim().replace(/'/g, "''") + "%'"
522
- })
523
- .join(',') +
524
- '])'
525
- }
526
-
527
- const result = await tx.getRepository(InventoryHistory).query(`
528
- with invHistory as (
529
- select case when ar.name is null then 'NEW' else ar.name end as arrival_notice_name,
530
- case when js.container_size is null then '' else js.container_size end as container_size,
531
- i2.batch_id,
532
- bzp.name as bizplace_name,
533
- i2.pallet_id, ih.seq, ih.status, ih.transaction_type, i2.product_id, prd.name as product_name,
534
- prd.description as product_description, ih.id as inventory_history_id, ih.packing_type, ih.qty, ih.opening_qty,
535
- ih.created_at::date
536
- from inventories i2
537
- inner join reduced_inventory_histories ih on ih.pallet_id = i2.pallet_id and ih.domain_id = i2.domain_id
538
- inner join products prd on prd.id = i2.product_id
539
- inner join bizplaces bzp on bzp.id = ih.bizplace_id
540
- left join order_inventories oi on oi.inventory_id = i2.id and oi.arrival_notice_id is not null
541
- left join arrival_notices ar on ar.id = oi.arrival_notice_id
542
- left join job_sheets js on js.id = ar.job_sheet_id
543
- where
544
- i2.domain_id = '${domain.id}'
545
- and (
546
- (ih.status = 'STORED' and ih.transaction_type = 'NEW')
547
- or (ih.status = 'STORED' and ih.transaction_type = 'CANCEL_ORDER')
548
- or (ih.status = 'STORED' and ih.transaction_type = 'RETURN')
549
- or (ih.status = 'STORED' and ih.transaction_type = 'PUTAWAY')
550
- or (ih.status = 'TERMINATED' and ih.transaction_type = 'TERMINATED')
551
- )
552
- ${bizplaceQuery}
553
- ${productQuery}
554
- order by ih.pallet_id, ih.seq
555
- ), inventoryHistoryMovement as (
556
- select bizplace_name, container_size, pallet_id, seq, status, transaction_type, product_id, product_name, product_description, batch_id,
557
- inventory_history_id, packing_type, qty, opening_qty, created_at, arrival_notice_name from (
558
- select row_number() over(partition by pallet_id order by created_at asc) as rn, * from invHistory where status = 'STORED'
559
- )as invIn where rn = 1
560
- union all
561
- select bizplace_name, container_size, pallet_id, seq, status, transaction_type, product_id, product_name, product_description, batch_id,
562
- inventory_history_id, packing_type, qty, opening_qty, created_at, arrival_notice_name from (
563
- select row_number() over(partition by pallet_id order by created_at desc) as rn, * from invHistory
564
- )as invOut where rn = 1 and status = 'TERMINATED'
565
- ), inventoryHistoriesByPallet as (
566
- select invHistory.bizplace_name, invHistory.container_size, invHistory.product_name, invHistory.product_description, invHistory.arrival_notice_name, invHistory.batch_id,
567
- SUM(case when invHistory.created_at <= '${new Date(fromDate.value).toLocaleDateString()} 00:00:00' then
568
- case when invHistory.status = 'STORED' then 1 else -1 end
569
- else 0 end) as opening_balance,
570
- SUM(case when invHistory.created_at >= '${new Date(fromDate.value).toLocaleDateString()} 00:00:00'
571
- and invHistory.created_at <= '${new Date(toDate.value).toLocaleDateString()} 23:59:59' then
572
- case when invHistory.status = 'STORED' then 1 else 0 end
573
- else 0 end) as in_balance,
574
- SUM(case when invHistory.created_at >= '${new Date(fromDate.value).toLocaleDateString()} 00:00:00'
575
- and invHistory.created_at <= '${new Date(toDate.value).toLocaleDateString()} 23:59:59' then
576
- case when invHistory.status = 'TERMINATED' then 1 else 0 end
577
- else 0 end) as out_balance
578
- from(
579
- select * from inventoryHistoryMovement
580
- ) as invHistory group by bizplace_name, container_size, product_name, product_description, arrival_notice_name, batch_id
581
- )
582
- select invh.*, invh.opening_balance + invh.in_balance - invh.out_balance as closing_balance
583
- , (
584
- select json_agg(json_build_object('created_at', created_at, 'in_balance', in_balance, 'out_balance', out_balance)) as jsonData from
585
- (
586
- select bizplace_name, product_name, batch_id, arrival_notice_name, created_at,
587
- SUM(case when status = 'STORED' then 1 else 0 end) as in_balance,
588
- SUM(case when status = 'TERMINATED' then 1 else 0 end) as out_balance
589
- from inventoryHistoryMovement
590
- where created_at >= '${new Date(fromDate.value).toLocaleDateString()} 00:00:00' and
591
- created_at <= '${new Date(toDate.value).toLocaleDateString()} 23:59:59' and
592
- bizplace_name = invh.bizplace_name and product_name = invh.product_name and
593
- batch_id = invh.batch_id and arrival_notice_name = invh.arrival_notice_name
594
- group by bizplace_name, product_name, batch_id, arrival_notice_name, created_at
595
- order by created_at
596
- )
597
- as t
598
- )::varchar as json_date_movement
599
- from inventoryHistoriesByPallet invh
600
- where invh.opening_balance >= 0
601
- and invh.in_balance >= 0
602
- and invh.out_balance >= 0
603
- and (invh.opening_balance > 0 or invh.in_balance > 0)
604
- order by invh.bizplace_name, invh.product_name, invh.batch_id;
605
- `)
606
-
607
- let items = result as any
608
- items = items.map(item => {
609
- return {
610
- bizplace: { name: item.bizplace_name },
611
- product: {
612
- name: item.product_name.trim() + ' ( ' + (item.product_description || '-').trim() + ' )'
613
- },
614
- arrivalNoticeName: item.arrival_notice_name,
615
- batchId: item.batch_id,
616
- openingBalance: item.opening_balance,
617
- inBalance: item.in_balance,
618
- outBalance: item.out_balance,
619
- closingBalance: item.closing_balance,
620
- jsonDateMovement: item.json_date_movement,
621
- containerSize: item.container_size
622
- }
623
- })
624
-
625
- return items
626
- } catch (error) {
627
- throw error
628
- }
629
- }
630
-
631
- @Directive('@transaction')
632
- @Query(returns => [InventoryHistory])
633
- async inventoryHistoryPalletDetailReport(
634
- @Args(type => ListParam) params: ListParam,
635
- @Ctx() context: ResolverContext
636
- ): Promise<InventoryHistory[]> {
637
- try {
638
- const { domain, tx } = context.state
639
- let userFilter = params.filters.find(data => data.name === 'user')
640
-
641
- let bizplaceFilter: Filter = { name: '', operator: '', value: '' }
642
-
643
- if (userFilter) {
644
- const user = (await tx.getRepository(User).findOne({
645
- where: { id: userFilter.value },
646
- relations: ['bizplaces']
647
- })) as User & { bizplaces: Bizplace[] }
648
-
649
- const bizplace: Bizplace = user.bizplaces[0]
650
-
651
- if (!bizplace) throw 'Invalid input'
652
-
653
- bizplaceFilter = { name: 'bizplace', operator: 'eq', value: bizplace.id }
654
- } else {
655
- bizplaceFilter = params.filters.find(data => data.name === 'bizplace')
656
- }
657
-
658
- let fromDate = params.filters.find(data => data.name === 'fromDate')
659
- let toDate = params.filters.find(data => data.name === 'toDate')
660
- let product = params.filters.find(data => data.name === 'product')
661
-
662
- if (!fromDate || !toDate) throw 'Invalid input'
663
-
664
- let bizplaceQuery = ''
665
- if (bizplaceFilter) {
666
- const bizplace: Bizplace = await tx.getRepository(Bizplace).findOneBy({
667
- id: bizplaceFilter.value
668
- })
669
-
670
- if (bizplace) {
671
- bizplaceQuery = "AND i2.bizplace_id = '" + bizplace.id + "'"
672
- } else {
673
- throw 'Invalid input'
674
- }
675
- }
676
-
677
- let productQuery = ''
678
- if (product) {
679
- productQuery =
680
- 'AND prd.name ILIKE ANY(ARRAY[' +
681
- product.value
682
- .split(',')
683
- .map(prod => {
684
- return "'%" + prod.trim().replace(/'/g, "''") + "%'"
685
- })
686
- .join(',') +
687
- '])'
688
- }
689
-
690
- const result = await tx.getRepository(InventoryHistory).query(`
691
- with invHistory as (
692
- select case when ar.name is null then 'NEW' else ar.name end as arrival_notice_name,
693
- case when js.container_size is null then '' else js.container_size end as container_size,
694
- i2.batch_id,
695
- bzp.name as bizplace_name,
696
- i2.pallet_id, ih.seq, ih.status, ih.transaction_type, i2.product_id, prd.name as product_name,
697
- prd.description as product_description, ih.id as inventory_history_id, ih.packing_type, ih.qty, ih.opening_qty,
698
- ih.created_at::date
699
- from inventories i2
700
- inner join reduced_inventory_histories ih on ih.pallet_id = i2.pallet_id and ih.domain_id = i2.domain_id
701
- inner join products prd on prd.id = i2.product_id
702
- inner join bizplaces bzp on bzp.id = ih.bizplace_id
703
- left join order_inventories oi on oi.inventory_id = i2.id and oi.arrival_notice_id is not null
704
- left join arrival_notices ar on ar.id = oi.arrival_notice_id
705
- left join job_sheets js on js.id = ar.job_sheet_id
706
- where
707
- i2.domain_id = '${domain.id}'
708
- and (
709
- (ih.status = 'STORED' and ih.transaction_type = 'NEW')
710
- or (ih.status = 'STORED' and ih.transaction_type = 'CANCEL_ORDER')
711
- or (ih.status = 'STORED' and ih.transaction_type = 'RETURN')
712
- or (ih.status = 'STORED' and ih.transaction_type = 'PUTAWAY')
713
- or (ih.status = 'TERMINATED' and ih.transaction_type = 'TERMINATED')
714
- )
715
- ${bizplaceQuery}
716
- ${productQuery}
717
- order by ih.pallet_id, ih.seq
718
- ), inventoryHistoryMovement as (
719
- select bizplace_name, container_size, pallet_id, seq, status, transaction_type, product_id, product_name, product_description, batch_id,
720
- inventory_history_id, packing_type, qty, opening_qty, created_at, arrival_notice_name from (
721
- select row_number() over(partition by pallet_id order by created_at asc) as rn, * from invHistory where status = 'STORED'
722
- )as invIn where rn = 1
723
- union all
724
- select bizplace_name, container_size, pallet_id, seq, status, transaction_type, product_id, product_name, product_description, batch_id,
725
- inventory_history_id, packing_type, qty, opening_qty, created_at, arrival_notice_name from (
726
- select row_number() over(partition by pallet_id order by created_at desc) as rn, * from invHistory
727
- )as invOut where rn = 1 and status = 'TERMINATED'
728
- ), inventoryHistoriesByPallet as (
729
- select invHistory.bizplace_name, invHistory.container_size, invHistory.product_name, invHistory.product_description, invHistory.arrival_notice_name, invHistory.batch_id,
730
- SUM(case when invHistory.created_at <= '${new Date(fromDate.value).toLocaleDateString()} 00:00:00' then
731
- case when invHistory.status = 'STORED' then 1 else -1 end
732
- else 0 end) as opening_balance,
733
- SUM(case when invHistory.created_at >= '${new Date(fromDate.value).toLocaleDateString()} 00:00:00'
734
- and invHistory.created_at <= '${new Date(toDate.value).toLocaleDateString()} 23:59:59' then
735
- case when invHistory.status = 'STORED' then 1 else 0 end
736
- else 0 end) as in_balance,
737
- SUM(case when invHistory.created_at >= '${new Date(fromDate.value).toLocaleDateString()} 00:00:00'
738
- and invHistory.created_at <= '${new Date(toDate.value).toLocaleDateString()} 23:59:59' then
739
- case when invHistory.status = 'TERMINATED' then 1 else 0 end
740
- else 0 end) as out_balance
741
- from(
742
- select * from inventoryHistoryMovement
743
- ) as invHistory group by bizplace_name, container_size, product_name, product_description, arrival_notice_name, batch_id
744
- )
745
- select invh.*, invh.opening_balance + invh.in_balance - invh.out_balance as closing_balance
746
- , (
747
- select json_agg(json_build_object('created_at', created_at, 'in_balance', in_balance, 'out_balance', out_balance)) as jsonData from
748
- (
749
- select bizplace_name, product_name, batch_id, arrival_notice_name, created_at,
750
- SUM(case when status = 'STORED' then 1 else 0 end) as in_balance,
751
- SUM(case when status = 'TERMINATED' then 1 else 0 end) as out_balance
752
- from inventoryHistoryMovement
753
- where created_at >= '${new Date(fromDate.value).toLocaleDateString()} 00:00:00' and
754
- created_at <= '${new Date(toDate.value).toLocaleDateString()} 23:59:59' and
755
- bizplace_name = invh.bizplace_name and product_name = invh.product_name and
756
- batch_id = invh.batch_id and arrival_notice_name = invh.arrival_notice_name
757
- group by bizplace_name, product_name, batch_id, arrival_notice_name, created_at
758
- order by created_at
759
- )
760
- as t
761
- )::varchar as json_date_movement
762
- from inventoryHistoriesByPallet invh
763
- where invh.opening_balance >= 0
764
- and invh.in_balance >= 0
765
- and invh.out_balance >= 0
766
- and (invh.opening_balance > 0 or invh.in_balance > 0)
767
- order by invh.bizplace_name, invh.product_name, invh.batch_id;
768
- `)
769
-
770
- let items = result as any
771
- items = items.map(item => {
772
- return {
773
- bizplace: { name: item.bizplace_name },
774
- product: {
775
- name: item.product_name.trim() + ' ( ' + (item.product_description || '-').trim() + ' )'
776
- },
777
- arrivalNoticeName: item.arrival_notice_name,
778
- batchId: item.batch_id,
779
- openingBalance: item.opening_balance,
780
- inBalance: item.in_balance,
781
- outBalance: item.out_balance,
782
- closingBalance: item.closing_balance,
783
- jsonDateMovement: item.json_date_movement,
784
- containerSize: item.container_size
785
- }
786
- })
787
-
788
- return items
789
- } catch (error) {
790
- throw error
791
- }
792
- }
793
-
794
- @Directive('@transaction')
795
- @Query(returns => InventoryHistoryPalletReportList)
796
- async inventoryHistoryPalletStorageReport(
797
- @Args(type => ListParam) params: ListParam,
798
- @Ctx() context: ResolverContext
799
- ): Promise<InventoryHistoryPalletReportList> {
800
- try {
801
- const { domain, tx } = context.state
802
-
803
- let userFilter = params.filters.find(data => data.name === 'user')
804
-
805
- let bizplaceFilter: Filter = { name: '', operator: '', value: '' }
806
-
807
- if (userFilter) {
808
- const user = (await tx.getRepository(User).findOne({
809
- where: { id: userFilter.value },
810
- relations: ['bizplaces']
811
- })) as User & { bizplaces: Bizplace[] }
812
-
813
- const bizplace: Bizplace = user.bizplaces[0]
814
-
815
- if (!bizplace) throw 'Invalid input'
816
-
817
- bizplaceFilter = { name: 'bizplace', operator: 'eq', value: bizplace.id }
818
- } else {
819
- bizplaceFilter = params.filters.find(data => data.name === 'bizplace')
820
- }
821
-
822
- let fromDate = params.filters.find(data => data.name === 'fromDate')
823
- let toDate = params.filters.find(data => data.name === 'toDate')
824
-
825
- if (!bizplaceFilter || !fromDate || !toDate) throw 'Invalid input'
826
-
827
- const bizplace: Bizplace = await tx.getRepository(Bizplace).findOneBy({
828
- id: bizplaceFilter.value
829
- })
830
-
831
- let queryFilter = ``
832
- let queryParams = [fromDate.value, toDate.value]
833
- let locationType = params.filters.find(data => data.name === 'locationType')
834
- if (locationType) {
835
- queryFilter = queryFilter + `AND location_type = $` + (queryParams.length + 1)
836
- queryParams.push(locationType.value)
837
- }
838
-
839
- let zone = params.filters.find(data => data.name === 'zone')
840
- if (zone) {
841
- queryFilter = queryFilter + `AND LOWER(location_zone) like $` + (queryParams.length + 1)
842
- queryParams.push(zone.value.toLowerCase())
843
- }
844
-
845
- await tx.query(
846
- `
847
- create temp table temp_history as (
848
- select distinct on (ih.pallet_id)
849
- ih.pallet_id, ih.created_at as in_at, loc.name as location_name, loc."type" as location_type, loc."zone" as location_zone,
850
- bz.name as bizplace_name
851
- from reduced_inventory_histories ih
852
- inner join inventories inv on inv.pallet_id = ih.pallet_id and inv.domain_id = ih.domain_id
853
- inner join locations loc on loc.id = inv.location_id
854
- inner join bizplaces bz on bz.id = inv.bizplace_id
855
- where ih.domain_id = $1
856
- and inv.bizplace_id = $2
857
- and not exists(
858
- SELECT domain_id, pallet_id
859
- FROM reduced_inventory_histories ih2
860
- where ih2.domain_id = $1
861
- and ih2.created_at < $3
862
- and ih2.transaction_type = 'TERMINATED' and ih2.status ='TERMINATED'
863
- and ih2.pallet_id = ih.pallet_id
864
- group by ih2.domain_id , ih2.pallet_id
865
- )
866
- and ih.created_at <= $4
867
- order by ih.pallet_id , ih.seq
868
- )
869
- `,
870
- [domain.id, bizplace.id, fromDate.value, toDate.value]
871
- )
872
-
873
- await tx.query(
874
- `
875
- create temp table temp_pallet_storage_history as (
876
- select * from (
877
- select bizplace_name, location_type, location_zone, location_name,
878
- COUNT(pallet_id) filter (where in_at between $1 and $2) as inbound_qty,
879
- COUNT(*) as total_qty,
880
- string_agg(case when in_at between $1 and $2 then pallet_id end, ', ') as inbound_pallet_id,
881
- string_agg(case when in_at not between $1 and $2 then pallet_id end, ', ') as pallet_id
882
- from temp_history where location_type = 'SHELF'
883
- group by bizplace_name, location_name, location_type, location_zone
884
- union
885
- select bizplace_name, location_type, location_zone, location_name,
886
- case when in_at between $1 and $2 then 1 else 0 end as inbound_qty,
887
- 1 as total_qty,
888
- case when in_at between $1 and $2 then pallet_id end as inbound_pallet_id,
889
- case when in_at not between $1 and $2 then pallet_id end pallet_id
890
- from temp_history where location_type = 'FLOOR'
891
- ) as src where 1 = 1
892
- ${queryFilter}
893
- )
894
- `,
895
- queryParams
896
- )
897
-
898
- const total: any = await tx.query(`select count(*) from temp_pallet_storage_history`)
899
-
900
- const totalWithOpeningBalance: any = await tx.query(
901
- `select count(*) from temp_pallet_storage_history where pallet_id notnull`
902
- )
903
-
904
- const result: any = await tx.query(
905
- `
906
- select * from temp_pallet_storage_history order by location_type OFFSET $1 LIMIT $2
907
- `,
908
- [(params.pagination.page - 1) * params.pagination.limit, params.pagination.limit]
909
- )
910
-
911
- tx.query(`
912
- drop table temp_history, temp_pallet_storage_history
913
- `)
914
-
915
- let items = result.map(itm => {
916
- return {
917
- ...itm,
918
- bizplace: {
919
- name: itm.bizplace_name
920
- },
921
- location: {
922
- name: itm.location_name,
923
- type: itm.location_type,
924
- zone: itm.location_zone
925
- },
926
- palletId: itm.pallet_id,
927
- inboundPalletId: itm.inbound_pallet_id,
928
- inboundQty: itm.inbound_qty,
929
- totalQty: itm.total_qty
930
- }
931
- })
932
-
933
- return { items, total: total[0].count, totalWithOpeningBalance: totalWithOpeningBalance[0].count }
934
- } catch (ex) {
935
- throw ex
936
- }
937
- }
938
-
939
- @Directive('@transaction')
940
- @Query(returns => InventoryHistorySummaryList)
941
- async inventoryHistorySummaryReport(
942
- @Args(type => ListParam) params: ListParam,
943
- @Ctx() context: ResolverContext
944
- ): Promise<InventoryHistorySummaryList> {
945
- try {
946
- const { tx } = context.state
947
-
948
- let bizplaceFilter: Filter = { name: '', operator: '', value: '' }
949
-
950
- let userFilter = params.filters.find(data => data.name === 'user')
951
- let fromDate = params.filters.find(data => data.name === 'fromDate')
952
- let toDate = params.filters.find(data => data.name === 'toDate')
953
- let byPallet = params.filters.find(data => data.name === 'byPallet')
954
-
955
- if (userFilter) {
956
- const user = (await tx.getRepository(User).findOne({
957
- where: { id: userFilter.value },
958
- relations: ['bizplaces']
959
- })) as User & { bizplaces: Bizplace[] }
960
-
961
- const bizplace: Bizplace = user.bizplaces[0]
962
-
963
- if (!bizplace) throw 'Invalid input'
964
-
965
- bizplaceFilter = { name: 'bizplace', operator: 'eq', value: bizplace.id }
966
- } else {
967
- bizplaceFilter = params.filters.find(data => data.name === 'bizplace')
968
- }
969
-
970
- if (!bizplaceFilter || !fromDate || !toDate) throw 'Invalid input'
971
-
972
- const bizplace: Bizplace = await tx.getRepository(Bizplace).findOneBy({
973
- id: bizplaceFilter.value
974
- })
975
-
976
- let [result, total] = byPallet.value
977
- ? await massageInventoryPalletSummary(tx, params, bizplace, context)
978
- : await massageInventorySummary(tx, params, bizplace, context)
979
-
980
- let items = result.map(itm => {
981
- return {
982
- ...itm,
983
- batchId: itm.batch_id,
984
- packingType: itm.packing_type,
985
- packingSize: itm.packing_size,
986
- openingQty: itm.opening_qty,
987
- missingQty: itm.missing_qty,
988
- adjustmentQty: itm.adjustment_qty,
989
- closingQty: itm.closing_qty,
990
- totalInQty: itm.total_in_qty,
991
- totalOutQty: itm.total_out_qty,
992
- product: {
993
- id: itm.product_id,
994
- sku: itm.product_sku,
995
- name: itm.product_name,
996
- description: itm.product_description,
997
- type: itm.product_type
998
- }
999
- }
1000
- })
1001
-
1002
- return {
1003
- items,
1004
- total: total[0].count,
1005
- totalInboundQty: total[0].totalinqty || 0,
1006
- totalOpeningBal: total[0].totalopeningbal || 0
1007
- }
1008
- } catch (error) {
1009
- throw error
1010
- }
1011
- }
1012
-
1013
- @Directive('@transaction')
1014
- @Query(returns => InventoryList)
1015
- async onhandInventories(
1016
- @Ctx() context: ResolverContext,
1017
- @Arg('filters', type => [Filter], { nullable: true }) filters?: Filter[],
1018
- @Arg('pagination', type => Pagination, { nullable: true }) pagination?: Pagination,
1019
- @Arg('sortings', type => [Sorting], { nullable: true }) sortings?: Sorting[],
1020
- @Arg('locationSortingRules', type => [Sorting], { nullable: true }) locationSortingRules?: Sorting[],
1021
- @Arg('setPagination', type => Boolean, { defaultValue: true }) setPagination?: Boolean
1022
- ): Promise<InventoryList> {
1023
- const { domain, user, tx } = context.state
1024
-
1025
- // define all inputs
1026
- let userFilter = filters.find(data => data.name === 'user')
1027
- let product = filters.find(data => data.name === 'product')
1028
- let createdAt = filters.find(data => data.name === 'created_at')
1029
- let location = filters.find(data => data.name === 'location')
1030
- let batchId = filters.find(data => data.name === 'batchId')
1031
- let palletId = filters.find(data => data.name === 'palletId')
1032
- let cartonId = filters.find(data => data.name === 'cartonId')
1033
- let packingType = filters.find(data => data.name === 'packingType')
1034
- let timezoneOffset = filters.find(data => data.name === 'timezoneOffset').value + ' minutes'
1035
-
1036
- // expiration date filter
1037
- let expiration = filters.find(data => data.name === 'expiration').value
1038
- let expFromDate = filters.find(data => data.name === 'expFromDate')
1039
- let expToDate = filters.find(data => data.name === 'expToDate')
1040
-
1041
- let bizplaceFilter = { name: '', operator: '', value: [] }
1042
-
1043
- // prepare query filters
1044
- if (userFilter) {
1045
- const user = (await tx.getRepository(User).findOne({
1046
- where: { id: userFilter.value },
1047
- relations: ['bizplaces']
1048
- })) as User & { bizplaces: Bizplace[] }
1049
-
1050
- const bizplace: Bizplace = user.bizplaces[0]
1051
-
1052
- if (!bizplace) throw 'Invalid input'
1053
-
1054
- bizplaceFilter = { name: 'bizplace', operator: 'eq', value: [bizplace.id] }
1055
- } else {
1056
- bizplaceFilter = !filters.find((filter: any) => filter.name === 'bizplace')
1057
- ? ({
1058
- name: 'bizplace',
1059
- operator: 'in',
1060
- value: await getPermittedBizplaceIds(domain, user),
1061
- relation: true
1062
- } as any)
1063
- : {
1064
- ...filters.find(data => data.name === 'bizplace'),
1065
- value: [filters.find(data => data.name === 'bizplace').value]
1066
- }
1067
- }
1068
-
1069
- let queryFilter = ``
1070
- let bizplaces = bizplaceFilter.value.map(id => `('${id}')`).join(',')
1071
-
1072
- if (product) {
1073
- let products = product.value
1074
- .toLowerCase()
1075
- .split(',')
1076
- .map(prod => {
1077
- return "'%" + prod.trim().replace(/'/g, "''") + "%'"
1078
- })
1079
- .join(',')
1080
-
1081
- queryFilter =
1082
- queryFilter +
1083
- ` and exists (
1084
- select prd.id as product_id from products prd
1085
- inner join bizplaces b on b.id = prd.bizplace_id
1086
- inner join companies c on c.domain_id = b.domain_id
1087
- inner join bizplaces b2 on b2.company_id = c.id
1088
- where exists (
1089
- SELECT * FROM tmp_bizfilter bizFilter
1090
- WHERE bizFilter.bizplace_id = "b2"."id"
1091
- )
1092
- and (lower(prd.name) like any(array[${products}])
1093
- or lower(prd.description) like any(array[${products}])
1094
- or lower(prd.sku) like any(array[${products}])
1095
- or lower(prd.brand) like any(array[${products}]))
1096
- and prd.id = rih.product_id
1097
- group by prd.id
1098
- )`
1099
- }
1100
-
1101
- if (location) {
1102
- let locations = location.value
1103
- .map(loc => {
1104
- return "'" + loc + "'"
1105
- })
1106
- .join(',')
1107
-
1108
- queryFilter =
1109
- queryFilter +
1110
- `and exists (
1111
- select loc.id from locations loc where
1112
- loc.id = any(array[${locations}]::uuid[])
1113
- and loc.id = rih.location_id
1114
- )`
1115
- }
1116
-
1117
- // default sorting
1118
- let queryOrder = 'order by created_at desc'
1119
- if (sortings && sortings.length > 0) {
1120
- const arrObjectMap = [
1121
- { name: 'palletId', value: 'rih.pallet_id' },
1122
- { name: 'cartonId', value: 'rih.carton_id' },
1123
- { name: 'batchId', value: 'rih.batch_id' },
1124
- { name: 'initialInboundAt', value: 'rih.initial_inbound_at' },
1125
- { name: 'bizplace|name', value: 'bz.name' },
1126
- { name: 'product|name', value: 'prd.sku' },
1127
- { name: 'remainQty', value: 'rih.qty' },
1128
- { name: 'location|name', value: 'loc.name' }
1129
- ]
1130
- sortings.forEach((sorting, idx) => {
1131
- let itmIndex = arrObjectMap.findIndex(x => x.name === sorting.name)
1132
-
1133
- queryOrder = `${idx === 0 ? 'order by' : queryOrder + ','} ${
1134
- itmIndex >= 0 ? arrObjectMap[itmIndex].value : sorting.name
1135
- } ${sorting.desc ? 'DESC' : 'ASC'}`
1136
- })
1137
- }
1138
-
1139
- if (batchId) queryFilter = `${queryFilter} and lower(rih.batch_id) like '${batchId.value.toLowerCase()}' `
1140
-
1141
- if (palletId) queryFilter = `${queryFilter} and rih.pallet_id like '${palletId.value}' `
1142
-
1143
- if (cartonId) queryFilter = `${queryFilter} and rih.carton_id like '${cartonId.value}' `
1144
-
1145
- if (packingType) queryFilter = `${queryFilter} and rih.packing_type like '${packingType.value}' `
1146
-
1147
- let expirationQueryFilter = ``
1148
- if (expiration)
1149
- expirationQueryFilter = ` and iv.expiration_date >= '${expFromDate.value}'::timestamp + '${timezoneOffset}'::INTERVAL and
1150
- iv.expiration_date <= '${expToDate.value}'::timestamp + '${timezoneOffset}'::INTERVAL + '1 day'::INTERVAL`
1151
-
1152
- // query the results
1153
- await tx.query(`
1154
- CREATE TEMP TABLE tmp_bizfilter on commit drop AS (
1155
- SELECT bizplace_id::uuid FROM (VALUES ${bizplaces}) AS bizFilter(bizplace_id)
1156
- );
1157
- `)
1158
-
1159
- await tx.query(
1160
- `
1161
- create temp table tmp_src on commit drop as (
1162
- select domain_id, pallet_id, carton_id, seq, qty, uom_value, packing_type, batch_id, batch_id_ref, created_at, status, unit_cost,
1163
- product_id::uuid as product_id, bizplace_id::uuid as bizplace_id, location_id::uuid as location_id
1164
- from reduced_inventory_histories rih
1165
- where domain_id = $1 and created_at < $2::timestamp + $3::INTERVAL + '1 day'::INTERVAL
1166
- );
1167
- `,
1168
- [domain.id, createdAt.value, timezoneOffset]
1169
- )
1170
-
1171
- await tx.query(
1172
- `
1173
- CREATE TEMP TABLE tmp_src_group on commit drop AS (
1174
- select ih.domain_id, ih.pallet_id, sum(ih.qty) as qty, sum(ih.uom_value) as uom_value, max(ih.seq) as last_seq, max(ih.created_at) as created_at,
1175
- min(ih.created_at) as initial_inbound_at
1176
- from tmp_src ih
1177
- group by ih.domain_id, ih.pallet_id
1178
- );
1179
- `
1180
- )
1181
-
1182
- await tx.query(
1183
- `
1184
- create temp table tmp_data on commit drop as (
1185
- select dt.*, rih.carton_id, rih.batch_id, rih.batch_id_ref, rih.product_id, rih.packing_type, rih.bizplace_id, rih.location_id, rih.unit_cost,iv.id as inventory_id, iv.uom,
1186
- iv.expiration_date, iv.manufacture_date, iv.reusable_pallet_id, iv.remark
1187
- from
1188
- (
1189
- SELECT ih.*, ih2.status FROM tmp_src_group ih
1190
- INNER JOIN inventory_histories ih2
1191
- ON ih.domain_id = ih2.domain_id
1192
- AND ih.pallet_id = ih2.pallet_id
1193
- AND ih.last_seq = ih2.seq
1194
- ) dt
1195
- inner join tmp_src rih on dt.domain_id = rih.domain_id and dt.pallet_id = rih.pallet_id and dt.last_seq = rih.seq and rih.status <> 'TERMINATED'
1196
- inner join inventories iv on iv.domain_id = dt.domain_id and iv.pallet_id = dt.pallet_id and iv.status <> 'MISSING'
1197
- where exists (
1198
- SELECT * FROM tmp_bizfilter bizFilter
1199
- WHERE bizFilter.bizplace_id = "rih"."bizplace_id"
1200
- )
1201
- ${queryFilter}
1202
- ${expirationQueryFilter}
1203
- );
1204
- `
1205
- )
1206
-
1207
- const total: any = await tx.query(`select count(*) from tmp_data`)
1208
-
1209
- const result: any = await tx.query(
1210
- `
1211
- select
1212
- rih.domain_id, rih.pallet_id as "palletId", rih.carton_id as "cartonId", rih.qty as "remainQty",
1213
- TRUNC(rih.uom_value::numeric,2) as "uomValue", rih.uom, rih.last_seq, rih.created_at,
1214
- rih.initial_inbound_at as "initialInboundAt", rih.unit_cost as "unitCost",
1215
- case when rih.reusable_pallet_id is not null then concat(rih.batch_id, ' (', plt.name, ')') else rih.batch_id end as "batchId",
1216
- rih.batch_id_ref as "batchIdRef", rih.product_id, rih.packing_type as "packingType", rih.bizplace_id, rih.location_id,
1217
- prd.id as product_id, prd.name as product_name, prd.sku as product_sku, prd.brand as product_brand, prd.description as product_description, prd.volume as product_volume,
1218
- bz.id as bizplace_id, bz.name as bizplace_name,
1219
- loc.id as location_id, loc.name as location_name, loc."zone" as location_zone, loc."row" as location_row, loc."column" as location_column, loc.shelf as location_shelf,
1220
- wh.name as warehouse_name, plt.name as reusable_pallet_name,
1221
- rih.remark,
1222
- rih.manufacture_date as "manufactureDate",
1223
- rih.expiration_date as "expirationDate",
1224
- coalesce((
1225
- select sum(oi1.release_qty) as nonLoadedQty from order_inventories oi1
1226
- inner join release_goods rg1 on rg1.id = oi1.release_good_id
1227
- where rg1.status in ('PICKING', 'LOADING')
1228
- and oi1.inventory_id = rih.inventory_id
1229
- and oi1.status in ('PICKED', 'LOADING')
1230
- and rg1.domain_id = '${domain.id}'
1231
- group by oi1.inventory_id
1232
- ),0) as "nonLoadedQty",
1233
- TRUNC(coalesce((
1234
- select sum(oi1.release_uom_value) as nonLoadedUomValue from order_inventories oi1
1235
- inner join release_goods rg1 on rg1.id = oi1.release_good_id
1236
- where rg1.status in ('PICKING', 'LOADING')
1237
- and oi1.inventory_id = rih.inventory_id
1238
- and oi1.status in ('PICKED', 'LOADING')
1239
- and rg1.domain_id = '${domain.id}'
1240
- group by oi1.inventory_id
1241
- ),0)::numeric,2) as "nonLoadedUomValue"
1242
- from tmp_data rih
1243
- left join pallets plt on plt.id = rih.reusable_pallet_id
1244
- inner join products prd on prd.id = rih.product_id
1245
- inner join bizplaces bz on bz.id = rih.bizplace_id
1246
- inner join locations loc on loc.id = rih.location_id
1247
- inner join warehouses wh on wh.id = loc.warehouse_id
1248
- WHERE 1 = 1
1249
- ${queryOrder}
1250
- ${setPagination ? 'OFFSET ' + (pagination.page - 1) * pagination.limit + ' LIMIT ' + pagination.limit : ''}
1251
- `
1252
- )
1253
-
1254
- // map all results
1255
- let items = result.map(itm => {
1256
- return {
1257
- ...itm,
1258
- bizplace: {
1259
- id: itm.bizplace_id,
1260
- name: itm.bizplace_name
1261
- },
1262
- location: {
1263
- id: itm.location_id,
1264
- name: itm.location_name,
1265
- type: itm.location_type,
1266
- zone: itm.location_zone
1267
- },
1268
- product: {
1269
- id: itm.product_id,
1270
- name: itm.product_name,
1271
- description: itm.product_description,
1272
- sku: itm.product_sku,
1273
- brand: itm.product_brand,
1274
- volume: itm.product_volume
1275
- }
1276
- }
1277
- })
1278
-
1279
- return { items, total: total[0].count }
1280
- }
1281
-
1282
- @Directive('@transaction')
1283
- @Query(returns => RawInventoryHistoryList)
1284
- async bizplaceInventoryHistoriesForExport(
1285
- @Ctx() context: ResolverContext,
1286
- @Arg('inventoryHistory', type => InventoryHistoryPatch, { nullable: true })
1287
- inventoryHistory?: InventoryHistoryPatch,
1288
- @Arg('filters', type => [Filter], { nullable: true }) filters?: Filter[]
1289
- ): Promise<RawInventoryHistoryList> {
1290
- const { domain, tx } = context.state
1291
-
1292
- const customerBizplace: Bizplace = await tx.getRepository(Bizplace).findOneBy({ id: inventoryHistory.bizplace.id })
1293
-
1294
- const productFilters = filters.find(x => x.name == 'product_info')
1295
- filters = filters.filter(x => x.name != 'product_info')
1296
-
1297
- const fromDate: Date = new Date(inventoryHistory.fromDate)
1298
- const toDate: Date = new Date(inventoryHistory.toDate)
1299
-
1300
- if (productFilters) {
1301
- let productFilterValue = `%${productFilters.value.toLowerCase()}%`
1302
- const productQb: SelectQueryBuilder<Product> = getRepository(Product).createQueryBuilder('prd')
1303
-
1304
- productQb.where(
1305
- new Brackets(qb => {
1306
- qb.where('Lower(prd.sku) LIKE :productInfo', { productInfo: productFilterValue })
1307
- .orWhere('Lower(prd.name) LIKE :productInfo', { productInfo: productFilterValue })
1308
- .orWhere('Lower(prd.description) LIKE :productInfo', { productInfo: productFilterValue })
1309
- .orWhere('Lower(prd.brand) LIKE :productInfo', { productInfo: productFilterValue })
1310
- })
1311
- )
1312
-
1313
- const _products = await productQb.getMany()
1314
-
1315
- filters.push({
1316
- name: 'product_id',
1317
- operator: 'in',
1318
- value: _products.map((product: Product) => product.id)
1319
- })
1320
- }
1321
-
1322
- if (inventoryHistory && inventoryHistory.warehouseName) {
1323
- const _warehouses: Warehouse[] = await tx.getRepository(Warehouse).findBy({
1324
- domain: { id: domain.id },
1325
- name: Raw(alias => `LOWER(${alias}) LIKE '${inventoryHistory.warehouseName.toLowerCase()}'`)
1326
- })
1327
-
1328
- filters.push({
1329
- name: 'warehouse_id',
1330
- operator: 'in',
1331
- value: _warehouses.map((warehouse: Warehouse) => warehouse.id)
1332
- })
1333
- }
1334
-
1335
- if (inventoryHistory && inventoryHistory.locationName) {
1336
- const _locations = await tx.getRepository(Location).find({
1337
- where: {
1338
- domain: { id: domain.id },
1339
- name: Raw(alias => `LOWER(${alias}) LIKE '${inventoryHistory.locationName.toLowerCase()}'`)
1340
- }
1341
- })
1342
-
1343
- filters.push({
1344
- name: 'location_id',
1345
- operator: 'in',
1346
- value: _locations.map((location: Location) => location.id)
1347
- })
1348
- }
1349
-
1350
- filters.push(
1351
- {
1352
- name: 'createdAt',
1353
- operator: 'between',
1354
- value: [fromDate, toDate]
1355
- },
1356
- {
1357
- name: 'bizplace_id',
1358
- operator: 'eq',
1359
- value: customerBizplace.id
1360
- }
1361
- )
1362
-
1363
- const qb: SelectQueryBuilder<InventoryHistory> = getRepository(InventoryHistory).createQueryBuilder('ih')
1364
- buildQuery(qb, { filters }, context)
1365
-
1366
- qb.select('prd.sku', 'sku')
1367
- .addSelect('prd.name', 'productName')
1368
- .addSelect('prd.description', 'productDescription')
1369
- .addSelect('prd.brand', 'brand')
1370
- .addSelect('ih.seq', 'seq')
1371
- .addSelect('ih.pallet_id', 'palletId')
1372
- .addSelect('ih.carton_id', 'cartonId')
1373
- .addSelect('ih.batch_id', 'batchId')
1374
- .addSelect('ih.batch_id_ref', 'batchIdRef')
1375
- .addSelect('ih.opening_qty', 'openingQty')
1376
- .addSelect('ih.qty', 'qty')
1377
- .addSelect('ih.opening_uom_value', 'openingUomValue')
1378
- .addSelect('ih.uom_value', 'uomValue')
1379
- .addSelect('ih.uom', 'uom')
1380
- .addSelect('ih.zone', 'zone')
1381
- .addSelect('ih.order_no', 'orderNo')
1382
- .addSelect('ih.order_ref_no', 'refNo')
1383
- .addSelect('ih.status', 'status')
1384
- .addSelect('ih.transaction_type', 'transactionType')
1385
- .addSelect('bzp.name', 'bizplace')
1386
- .addSelect('wh.name', 'warehouse')
1387
- .addSelect('lc.name', 'location')
1388
- .addSelect('ih.created_at', 'createdAt')
1389
- .addSelect('ih.updated_at', 'updatedAt')
1390
- .addSelect('up.name', 'updater')
1391
- .leftJoin('ih.product', 'prd')
1392
- .leftJoin('ih.warehouse', 'wh')
1393
- .leftJoin('ih.location', 'lc')
1394
- .leftJoin('ih.bizplace', 'bzp')
1395
- .leftJoin('ih.updater', 'up')
1396
- .orderBy('ih.pallet_id')
1397
- .addOrderBy('ih.seq')
1398
-
1399
- const [items, total] = await Promise.all([qb.getRawMany(), qb.getCount()])
1400
-
1401
- return { items, total }
1402
- }
1403
-
1404
- @Directive('@transaction')
1405
- @Query(returns => InventoryHistoryVolumeSummaryReportList)
1406
- async inventoryHistoryVolumeSummaryReport(
1407
- @Args(type => ListParam) params: ListParam,
1408
- @Ctx() context: ResolverContext
1409
- ): Promise<InventoryHistoryVolumeSummaryReportList> {
1410
- try {
1411
- const { domain, user, tx } = context.state
1412
-
1413
- let bizplaceFilter: Filter = { name: '', operator: '', value: '' }
1414
-
1415
- let userFilter = params.filters.find(data => data.name === 'user')
1416
- let fromDate = params.filters.find(data => data.name === 'fromDate')
1417
- let toDate = params.filters.find(data => data.name === 'toDate')
1418
-
1419
- if (userFilter) {
1420
- const user = (await tx.getRepository(User).findOne({
1421
- where: { id: userFilter.value },
1422
- relations: ['bizplaces']
1423
- })) as User & { bizplaces: Bizplace[] }
1424
-
1425
- const bizplace: Bizplace = user.bizplaces[0]
1426
-
1427
- if (!bizplace) throw 'Invalid input'
1428
-
1429
- bizplaceFilter = { name: 'bizplace', operator: 'eq', value: bizplace.id }
1430
- } else {
1431
- bizplaceFilter = params.filters.find(data => data.name === 'bizplace')
1432
- }
1433
-
1434
- if (!bizplaceFilter || !fromDate || !toDate) throw 'Invalid input'
1435
-
1436
- const bizplace: Bizplace = await tx.getRepository(Bizplace).findOneBy({
1437
- id: bizplaceFilter.value
1438
- })
1439
-
1440
- //check if all product details got volume
1441
- let foundPermittedBizplace: Bizplace
1442
-
1443
- if (bizplace) {
1444
- foundPermittedBizplace = await tx.getRepository(Bizplace).findOne({
1445
- where: { id: bizplace.id },
1446
- relations: ['company', 'company.domain']
1447
- })
1448
-
1449
- const companyDomain: Domain = foundPermittedBizplace.company.domain
1450
-
1451
- let foundProductDetail = await tx
1452
- .getRepository(ProductDetail)
1453
- .findOne({ where: { domain: { id: companyDomain.id }, volume: IsNull() || 0 } })
1454
-
1455
- if (foundProductDetail) {
1456
- throw new Error('there is product master with empty volume')
1457
- }
1458
- }
1459
-
1460
- await tx.query(
1461
- `
1462
- create temp table temp_reduced_inventory_histories ON COMMIT drop as (
1463
- select
1464
- row_number() over (order by cast(rih.created_at + (interval '8 hour') as DATE) ASC) as row,
1465
- SUM(case when rih.transaction_type in ('UNLOADING', 'RETURN') then rih.qty end) as "inboundQty",
1466
- round(cast(SUM(case when rih.transaction_type in ('UNLOADING', 'RETURN') then rih.qty * pd.volume end) as numeric), 2) as "inboundVolume",
1467
- SUM(case when rih.transaction_type in ('ADJUSTMENT', 'NEW', 'CC_ADJUSTMENT') then rih.qty end) as "adjustedQty",
1468
- round(cast(SUM(case when rih.transaction_type in ('ADJUSTMENT', 'NEW', 'CC_ADJUSTMENT') and rih.status <> 'MISSING' then rih.qty * pd.volume end) as numeric), 2) as "adjustedVolume",
1469
- SUM(case when rih.transaction_type = 'ADJUSTMENT' and status = 'MISSING' then rih.opening_qty end) as "missingQty",
1470
- round(cast(SUM(case when rih.transaction_type = 'ADJUSTMENT' and status = 'MISSING' then rih.opening_qty * pd.volume end) as numeric), 2) as "missingVolume",
1471
- SUM(case when rih.transaction_type = 'PICKING' then -(rih.qty) end) as "outboundQty",
1472
- round(cast(SUM(case when rih.transaction_type = 'PICKING' then -(rih.qty) * pd.volume end) as numeric), 2) as "outboundVolume",
1473
- SUM(case when rih.transaction_type in ('UNLOADING', 'ADJUSTMENT', 'PICKING', 'NEW', 'RETURN', 'CC_ADJUSTMENT') then rih.qty end) - SUM(case when rih.transaction_type = 'ADJUSTMENT' and status = 'MISSING' then rih.opening_qty else 0 end) as "tempTotal",
1474
- round(cast(SUM(case when rih.transaction_type in ('UNLOADING', 'ADJUSTMENT', 'PICKING', 'NEW', 'RETURN', 'CC_ADJUSTMENT') then rih.qty * pd.volume end) - round(cast(SUM(case when rih.transaction_type = 'ADJUSTMENT' and status = 'MISSING' then rih.opening_qty * pd.volume else 0 end) as numeric), 2) as numeric), 2) as "tempTotalVolume",
1475
- rih.bizplace_id as bizplace_id,
1476
- cast(rih.created_at + (interval '8 hour') as DATE) as "tempDate"
1477
- from reduced_inventory_histories rih
1478
- left join product_details pd on pd.product_id = rih.product_id and pd.packing_type = rih.packing_type
1479
- where rih.status not like 'TERMINATED' and rih.bizplace_id = $1
1480
- group by CAST(rih.created_at + (interval '8 hour') as DATE), rih.bizplace_id
1481
- )
1482
- `,
1483
- [bizplace.id]
1484
- )
1485
-
1486
- await tx.query(
1487
- `
1488
- create temp table temp_reduced_inventory_histories_with_date_range ON COMMIT drop as (
1489
- select
1490
- coalesce(tmp."tempDate", dr.range_date) as date,
1491
- row_number() over (order by coalesce(tmp."tempDate", dr.range_date) ASC) as row,
1492
- coalesce(tmp."inboundQty", 0) as "inboundQty",
1493
- coalesce(tmp."inboundVolume", 0) as "inboundVolume",
1494
- coalesce(tmp."adjustedQty", 0) as "adjustedQty",
1495
- coalesce(tmp."adjustedVolume", 0) as "adjustedVolume",
1496
- coalesce(tmp."missingQty", 0) as "missingQty",
1497
- coalesce(tmp."missingVolume", 0) as "missingVolume",
1498
- coalesce(tmp."outboundQty", 0) as "outboundQty",
1499
- coalesce(tmp."outboundVolume", 0) as "outboundVolume",
1500
- '${bizplace.id}' as bizplace_id,
1501
- (case when tmp."tempTotal" isnull then 0 else tmp."tempTotal" end) as total, (case when tmp."tempTotalVolume" isnull then 0 else tmp."tempTotalVolume" end) as "totalVolume"
1502
- from temp_reduced_inventory_histories tmp
1503
- full join (
1504
- select date_trunc('day', dd):: date as range_date
1505
- from generate_series
1506
- ( $1::timestamp
1507
- , $2::timestamp
1508
- , '1 day'::interval) dd
1509
- ) dr on dr.range_date = tmp."tempDate" order by date
1510
- )
1511
- `,
1512
- [fromDate.value, toDate.value]
1513
- )
1514
-
1515
- await tx.query(
1516
- `
1517
- create temp table temp_result ON COMMIT drop as(
1518
- select lag(sub."closingQty", 1, 0) over (partition by sub.bizplace_id order by sub.date) as "openingQty",
1519
- lag(sub."closingVolume", 1, 0) over (partition by sub.bizplace_id order by sub.date) as "openingVolume", sub.* from(
1520
- select (select sum(tmp2.total) from temp_reduced_inventory_histories_with_date_range tmp2 where tmp2.row <= tmp.row) as "closingQty",
1521
- (select sum(tmp2."totalVolume") from temp_reduced_inventory_histories_with_date_range tmp2 where tmp2.row <= tmp.row) as "closingVolume", tmp.* from
1522
- temp_reduced_inventory_histories_with_date_range tmp) sub
1523
- )
1524
- `
1525
- )
1526
-
1527
- await tx.query(
1528
- `
1529
- create temp table temp_final ON COMMIT drop as(
1530
- select * from temp_result tr where tr.date between $1 and $2 OFFSET $3 LIMIT $4
1531
- )
1532
- `,
1533
- [fromDate.value, toDate.value, (params.pagination.page - 1) * params.pagination.limit, params.pagination.limit]
1534
- )
1535
-
1536
- const result: any = await tx.query(
1537
- `
1538
- select * from temp_final
1539
- `
1540
- )
1541
-
1542
- const total: any = await tx.query(
1543
- `
1544
- select count(*), sum(tmp."inboundQty") as "totalInboundQty", sum(tmp."inboundVolume") as "totalInboundVolume",
1545
- sum(tmp."adjustedQty") as "totalAdjustedQty", sum(tmp."adjustedVolume") as "totalAdjustedVolume",
1546
- sum(tmp."missingQty") as "totalMissingQty", sum(tmp."missingVolume") as "totalMissingVolume",
1547
- sum(tmp."outboundQty") as "totalOutboundQty", sum(tmp."outboundVolume") as "totalOutboundVolume" from temp_final tmp
1548
- `
1549
- )
1550
-
1551
- return {
1552
- items: result,
1553
- total: total[0].count,
1554
- totalOpeningQty: result?.length > 0 ? result[0].openingQty : 0,
1555
- totalOpeningVolume: result?.length > 0 ? result[0].openingVolume : 0,
1556
- totalInboundQty: result?.length > 0 ? total[0].totalInboundQty : 0,
1557
- totalInboundVolume: result?.length > 0 ? total[0].totalInboundVolume : 0,
1558
- totalAdjustedQty: result?.length > 0 ? total[0].totalAdjustedQty : 0,
1559
- totalAdjustedVolume: result?.length > 0 ? total[0].totalAdjustedVolume : 0,
1560
- totalMissingQty: result?.length > 0 ? total[0].totalMissingQty : 0,
1561
- totalMissingVolume: result?.length > 0 ? total[0].totalMissingVolume : 0,
1562
- totalOutboundQty: result?.length > 0 ? total[0].totalOutboundQty : 0,
1563
- totalOutboundVolume: result?.length > 0 ? total[0].totalOutboundVolume : 0,
1564
- totalClosingQty: result?.length > 0 ? result[result.length - 1].closingQty : 0,
1565
- totalClosingVolume: result?.length > 0 ? result[result.length - 1].closingVolume : 0
1566
- }
1567
- } catch (error) {
1568
- throw error
1569
- }
1570
- }
1571
-
1572
- @FieldResolver(type => Domain)
1573
- async domain(@Root() inventoryHistory: InventoryHistory) {
1574
- return await getRepository(Domain).findOneBy({ id: inventoryHistory.domainId })
1575
- }
1576
-
1577
- @FieldResolver(type => User)
1578
- async updater(@Root() inventoryHistory: InventoryHistory) {
1579
- return await getRepository(User).findOneBy({ id: inventoryHistory.updaterId })
1580
- }
1581
-
1582
- @FieldResolver(type => User)
1583
- async creator(@Root() inventoryHistory: InventoryHistory) {
1584
- return await getRepository(User).findOneBy({ id: inventoryHistory.creatorId })
1585
- }
1586
- }
1587
-
1588
- async function massageInventorySummary(
1589
- tx: EntityManager,
1590
- params: ListParam,
1591
- bizplace: Bizplace,
1592
- context: ResolverContext
1593
- ) {
1594
- await productsQuery(tx, params, bizplace)
1595
- await filterInventoryQuery(tx, params, bizplace, context)
1596
-
1597
- let fromDate = params.filters.find(data => data.name === 'fromDate')
1598
- let hasTransactionOrBalanceFilter = params.filters.find(data => data.name === 'hasTransactionOrBalance')
1599
-
1600
- let hasTransactionOrBalanceQuery = ''
1601
- if (hasTransactionOrBalanceFilter && hasTransactionOrBalanceFilter.value) {
1602
- hasTransactionOrBalanceQuery = 'and (opening_qty > 0 or total_in_qty > 0 or adjustment_qty > 0)'
1603
- }
1604
- await tx.query(
1605
- `
1606
- create temp table temp_inventory_summary ON COMMIT DROP as (
1607
- select src.*,
1608
- opening_qty + adjustment_qty + total_in_qty + total_out_qty + missing_qty as closing_qty
1609
- from (
1610
- select prd.sku AS product_sku, prd.name as product_name, prd.description as product_description, prd.type AS product_type, ih.packing_type, ih.packing_size,
1611
- sum(case when ih.created_at >= $1 and ih.transaction_type = 'ADJUSTMENT' then ih.qty else 0 end) as adjustment_qty,
1612
- sum(case when ih.created_at < $1 then qty else 0 end) as opening_qty,
1613
- sum(case when ih.status = 'MISSING' then -ih.opening_qty else 0 end) as missing_qty,
1614
- sum(case when ih.created_at >= $1 then case when ih.qty > 0 and ih.transaction_type <> 'ADJUSTMENT' then ih.qty else 0 end else 0 end) as total_in_qty,
1615
- sum(case when ih.created_at >= $1 then case when ih.qty < 0 and ih.transaction_type <> 'ADJUSTMENT' then ih.qty else 0 end else 0 end) as total_out_qty,
1616
- ih.product_id
1617
- from temp_inv_history ih
1618
- inner join temp_products prd on prd.id = ih.product_id
1619
- group by prd.sku, prd.name, prd.description, prd.type, ih.product_id, ih.packing_type, ih.packing_size
1620
- ) src
1621
- where 1=1
1622
- ${hasTransactionOrBalanceQuery}
1623
- )
1624
- `,
1625
- [fromDate.value]
1626
- )
1627
-
1628
- const total: any = await tx.query(`select count(*) from temp_inventory_summary`)
1629
-
1630
- const result: any = await tx.query(
1631
- `
1632
- select * from temp_inventory_summary ORDER BY product_name, product_description, product_type, packing_type, packing_size OFFSET $1 LIMIT $2
1633
- `,
1634
- [(params.pagination.page - 1) * params.pagination.limit, params.pagination.limit]
1635
- )
1636
-
1637
- return [result, total]
1638
- }
1639
-
1640
- async function massageInventoryPalletSummary(
1641
- tx: EntityManager,
1642
- params: ListParam,
1643
- bizplace: Bizplace,
1644
- context: ResolverContext
1645
- ) {
1646
- await productsQuery(tx, params, bizplace)
1647
- await filterInventoryQuery(tx, params, bizplace, context)
1648
-
1649
- let fromDate = params.filters.find(data => data.name === 'fromDate')
1650
- let toDate = params.filters.find(data => data.name === 'toDate')
1651
- let hasTransactionOrBalanceFilter = params.filters.find(data => data.name === 'hasTransactionOrBalance')
1652
-
1653
- let hasTransactionOrBalanceQuery = ''
1654
- if (hasTransactionOrBalanceFilter && hasTransactionOrBalanceFilter.value) {
1655
- hasTransactionOrBalanceQuery = 'and (opening_qty > 0 or total_in_qty > 0 or adjustment_qty > 0)'
1656
- }
1657
- await tx.query(
1658
- `
1659
- create temp table temp_inventory_pallet_summary ON COMMIT DROP as (
1660
- select invh.*,
1661
- invh.opening_qty + invh.total_in_qty + invh.total_out_qty + invh.adjustment_qty as closing_qty from (
1662
- select product_sku, product_id, product_name, product_description, product_type,
1663
- SUM(case when invHistory.created_at < $1 then
1664
- case when invHistory.status = 'STORED' then 1
1665
- when invhistory.status = 'TERMINATED' then -1
1666
- else 0 end
1667
- else 0 end) as opening_qty,
1668
- SUM(case when invHistory.created_at >= $1 and invHistory.created_at <= $2 then
1669
- case when (invHistory.transaction_type = 'UNLOADING' or invHistory.transaction_type = 'NEW') then 1 else 0 end
1670
- else 0 end) as total_in_qty,
1671
- SUM(case when invHistory.created_at >= $1 and invHistory.created_at <= $2 then
1672
- case when invHistory.status = 'TERMINATED' AND invHistory.transaction_type <> 'ADJUSTMENT' then -1 else 0 end
1673
- else 0 end) as total_out_qty,
1674
- SUM(case when invHistory.created_at >= $1 and invHistory.created_at <= $2 then
1675
- case when invHistory.status = 'TERMINATED' AND invHistory.transaction_type = 'ADJUSTMENT' then -1
1676
- when invHistory.status = 'STORED' AND invHistory.transaction_type = 'ADJUSTMENT' then 1 else 0 end
1677
- else 0 end) as adjustment_qty
1678
- from(
1679
- select pallet_id, seq, status, transaction_type, product_sku, product_id, product_name, product_description, product_type,
1680
- inventory_history_id, packing_type, packing_size, qty, opening_qty, created_at from (
1681
- select row_number() over(partition by invh.pallet_id order by invh.created_at asc) as rn, invh.* ,
1682
- prd.sku as product_sku, prd.name as product_name, prd.description as product_description, prd.type AS product_type
1683
- from temp_inv_history invh
1684
- inner join temp_products prd on prd.id = invh.product_id
1685
- where (transaction_type = 'UNLOADING' or invh.transaction_type = 'NEW')
1686
- and invh.created_at >= $1
1687
- ) as invIn where rn = 1
1688
- union all
1689
- select pallet_id, seq, status, transaction_type, product_sku, product_id, product_name, product_description, product_type,
1690
- inventory_history_id, packing_type, packing_size, qty, opening_qty, created_at from (
1691
- SELECT row_number() over(partition by pallet_id, invh.product_id order by seq asc) as rn,
1692
- invh.pallet_id, invh.product_id, invh.packing_type, invh.packing_size,
1693
- invh.batch_id, invh.inventory_history_id,
1694
- invh.seq, 'STORED' AS status, invh.transaction_type, invh.qty, invh.opening_qty,
1695
- invh.created_at,
1696
- prd.sku as product_sku, prd.name as product_name, prd.description as product_description, prd.type AS product_type
1697
- from temp_inv_history invh
1698
- inner join temp_products prd on prd.id = invh.product_id
1699
- where invh.created_at < $1
1700
- and (invh.status = 'STORED' or invh.status = 'UNLOADED')
1701
- ) as invStored where rn = 1
1702
- union all
1703
- select pallet_id, seq, status, transaction_type, product_sku, product_id, product_name, product_description, product_type,
1704
- inventory_history_id, packing_type, packing_size, qty, opening_qty, started_at as created_at from (
1705
- select row_number() over(partition by invh.pallet_id, invh.product_id order by invh.seq desc) as rn, invh.*,
1706
- prd.sku as product_sku, prd.name as product_name, prd.description as product_description, prd.type AS product_type, repeatedGroup.started_at
1707
- from temp_inv_history invh
1708
- inner join (
1709
- select pallet_id, min(created_at) as started_at, max(created_at) as ended_at, min(seq) as min_seq, max(seq) as max_seq, status from (
1710
- select startData.*, sum(startflag) over (partition by pallet_id order by seq) as grp from (
1711
- select s.*,
1712
- (case when lag(status) over (partition by pallet_id order by seq) = status then 0 else 1 end) as startflag
1713
- from temp_inv_history s
1714
- ) startData
1715
- ) endData
1716
- group by pallet_id, grp, status
1717
- ) repeatedGroup on repeatedGroup.pallet_id = invh.pallet_id and repeatedGroup.min_seq <= invh.seq and repeatedGroup.max_seq >= invh.seq
1718
- inner join temp_products prd on prd.id = invh.product_id
1719
- ) as invOut where rn = 1 AND status ='TERMINATED'
1720
- union all
1721
- SELECT invh.pallet_id, invh.seq, invh.status, invh.transaction_type,
1722
- prd.sku AS product_sku, invh.product_id, prd.name AS product_name, prd.description AS product_description, prd.type AS product_type,
1723
- invh.inventory_history_id, invh.packing_type, invh.packing_size, invh.qty, invh.opening_qty, invh.created_at
1724
- FROM temp_inv_history invh
1725
- INNER JOIN (
1726
- SELECT invh.pallet_id, invh.seq AS stored_seq, invh2.seq AS terminated_seq FROM temp_inv_history invh
1727
- INNER JOIN temp_inv_history invh2 ON invh2.pallet_id = invh.pallet_id AND invh2.status='STORED' AND invh2.seq = invh.seq + 1 AND invh2.product_id <> invh.product_id
1728
- WHERE invh.transaction_type = 'ADJUSTMENT'
1729
- ) dt ON dt.pallet_id = invh.pallet_id AND (dt.stored_seq = invh.seq OR dt.terminated_seq = invh.seq)
1730
- inner join temp_products prd on prd.id = invh.product_id
1731
- where invh.created_at >= $1
1732
- ORDER BY product_name, pallet_id, seq
1733
- ) as invHistory
1734
- group by product_sku, product_id, product_name, product_description, product_type
1735
- ) invh
1736
- where 1=1
1737
- ${hasTransactionOrBalanceQuery}
1738
- )
1739
- `,
1740
- [fromDate.value, toDate.value]
1741
- )
1742
-
1743
- const total: any = await tx.query(
1744
- `select count(*) as count, sum(total_in_qty) as totalInQty, sum(opening_qty) as totalOpeningBal from temp_inventory_pallet_summary`
1745
- )
1746
-
1747
- const result: any = await tx.query(
1748
- `
1749
- select *, 'PALLET' as packing_type from temp_inventory_pallet_summary ORDER BY product_name, product_description OFFSET $1 LIMIT $2
1750
- `,
1751
- [(params.pagination.page - 1) * params.pagination.limit, params.pagination.limit]
1752
- )
1753
-
1754
- return [result, total]
1755
- }
1756
-
1757
- async function productsQuery(tx: EntityManager, params: ListParam, bizplace: Bizplace) {
1758
- let product = params.filters.find(data => data.name === 'product')
1759
- let productDesc = params.filters.find(data => data.name === 'productDescription')
1760
- let productType = params.filters.find(data => data.name === 'productType')
1761
-
1762
- let productQuery = ''
1763
- if (product) {
1764
- let productValue = product.value
1765
- .toLowerCase()
1766
- .split(',')
1767
- .map(prod => {
1768
- return "'%" + prod.trim().replace(/'/g, "''") + "%'"
1769
- })
1770
- .join(',')
1771
- productQuery = `AND (
1772
- Lower(prd.name) LIKE ANY(ARRAY[${productValue}])
1773
- OR Lower(prd.sku) LIKE ANY(ARRAY[${productValue}])
1774
- OR Lower(prd.description) LIKE ANY(ARRAY[${productValue}])
1775
- )`
1776
- }
1777
-
1778
- let productDescQuery = ''
1779
- if (productDesc) {
1780
- productDescQuery = "AND Lower(prd.description) LIKE '%" + productDesc.value.toLowerCase() + "%'"
1781
- }
1782
-
1783
- let productTypeQuery = ''
1784
- if (productType) {
1785
- productTypeQuery = "AND prd.type = '" + productType.value + "'"
1786
- }
1787
-
1788
- await tx.query(
1789
- `
1790
- create temp table temp_products ON COMMIT DROP AS
1791
- (
1792
- select prd.id, prd.name, prd.sku, prd.description, prd.id::varchar as product_id, prd.type from products prd
1793
- inner join bizplaces b on b.id = prd.bizplace_id
1794
- inner join companies c on c.domain_id = b.domain_id
1795
- inner join bizplaces b2 on b2.company_id = c.id
1796
- where b2.id = $1
1797
- ${productQuery}
1798
- ${productDescQuery}
1799
- ${productTypeQuery}
1800
- GROUP BY prd.id, prd.sku, prd.name, prd.description
1801
- )`,
1802
- [bizplace.id]
1803
- )
1804
- }
1805
-
1806
- async function filterInventoryQuery(
1807
- tx: EntityManager,
1808
- params: ListParam,
1809
- bizplace: Bizplace,
1810
- context: ResolverContext
1811
- ) {
1812
- let toDate = params.filters.find(data => data.name === 'toDate')
1813
- let batchNo = params.filters.find(data => data.name === 'batchNo')
1814
-
1815
- let batchNoQuery = ''
1816
- if (batchNo) {
1817
- batchNoQuery =
1818
- 'AND Lower(ih.batch_id) LIKE ANY(ARRAY[' +
1819
- batchNo.value
1820
- .toLowerCase()
1821
- .split(',')
1822
- .map(prod => {
1823
- return "'%" + prod.trim().replace(/'/g, "''") + "%'"
1824
- })
1825
- .join(',') +
1826
- '])'
1827
- }
1828
-
1829
- await tx.query(
1830
- `
1831
- create temp table temp_inv_history ON COMMIT DROP as (
1832
- select i2.pallet_id, ih.product_id::uuid, ih.packing_type, i2.packing_size, ih.batch_id,
1833
- ih.id as inventory_history_id, ih.seq, ih.status, ih.transaction_type, ih.qty, ih.opening_qty, ih.created_at
1834
- from inventories i2
1835
- inner join reduced_inventory_histories ih on ih.pallet_id = i2.pallet_id and ih.domain_id = i2.domain_id
1836
- where
1837
- ih.domain_id = $1
1838
- and ih.bizplace_id = $2
1839
- and ih.created_at <= $3
1840
- ${batchNoQuery}
1841
- )
1842
- `,
1843
- [context.state.domain.id, bizplace.id, toDate.value]
1844
- )
1845
- }