@things-factory/warehouse-base 4.0.9 → 4.0.13

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 (55) hide show
  1. package/dist-server/constants/index.js +1 -0
  2. package/dist-server/constants/index.js.map +1 -1
  3. package/dist-server/constants/location.js +3 -2
  4. package/dist-server/constants/location.js.map +1 -1
  5. package/dist-server/constants/rule-type.js +8 -0
  6. package/dist-server/constants/rule-type.js.map +1 -0
  7. package/dist-server/service/inventory/inventory-mutation.js +68 -28
  8. package/dist-server/service/inventory/inventory-mutation.js.map +1 -1
  9. package/dist-server/service/inventory/inventory-query.js +119 -86
  10. package/dist-server/service/inventory/inventory-query.js.map +1 -1
  11. package/dist-server/service/inventory/inventory-types.js +16 -0
  12. package/dist-server/service/inventory/inventory-types.js.map +1 -1
  13. package/dist-server/service/inventory/inventory.js +13 -9
  14. package/dist-server/service/inventory/inventory.js.map +1 -1
  15. package/dist-server/service/inventory-change/inventory-change-mutation.js +7 -9
  16. package/dist-server/service/inventory-change/inventory-change-mutation.js.map +1 -1
  17. package/dist-server/service/inventory-change/inventory-change.js +5 -1
  18. package/dist-server/service/inventory-change/inventory-change.js.map +1 -1
  19. package/dist-server/service/inventory-history/inventory-history-query.js +28 -26
  20. package/dist-server/service/inventory-history/inventory-history-query.js.map +1 -1
  21. package/dist-server/service/inventory-history/inventory-history-types.js +4 -4
  22. package/dist-server/service/inventory-history/inventory-history-types.js.map +1 -1
  23. package/dist-server/service/inventory-history/inventory-history.js +1 -1
  24. package/dist-server/service/inventory-history/inventory-history.js.map +1 -1
  25. package/dist-server/service/location/location-query.js +1 -1
  26. package/dist-server/service/location/location-query.js.map +1 -1
  27. package/dist-server/service/location/location-types.js +24 -0
  28. package/dist-server/service/location/location-types.js.map +1 -1
  29. package/dist-server/service/location/location.js +2 -2
  30. package/dist-server/service/location/location.js.map +1 -1
  31. package/dist-server/utils/datetime-util.js +49 -0
  32. package/dist-server/utils/datetime-util.js.map +1 -0
  33. package/dist-server/utils/index.js +1 -0
  34. package/dist-server/utils/index.js.map +1 -1
  35. package/dist-server/utils/inventory-util.js +104 -37
  36. package/dist-server/utils/inventory-util.js.map +1 -1
  37. package/package.json +8 -8
  38. package/server/constants/index.ts +1 -0
  39. package/server/constants/location.ts +3 -2
  40. package/server/constants/rule-type.ts +4 -0
  41. package/server/service/inventory/inventory-mutation.ts +65 -20
  42. package/server/service/inventory/inventory-query.ts +151 -107
  43. package/server/service/inventory/inventory-types.ts +12 -0
  44. package/server/service/inventory/inventory.ts +13 -10
  45. package/server/service/inventory-change/inventory-change-mutation.ts +10 -11
  46. package/server/service/inventory-change/inventory-change.ts +6 -2
  47. package/server/service/inventory-history/inventory-history-query.ts +27 -28
  48. package/server/service/inventory-history/inventory-history-types.ts +2 -2
  49. package/server/service/inventory-history/inventory-history.ts +2 -2
  50. package/server/service/location/location-query.ts +1 -1
  51. package/server/service/location/location-types.ts +18 -0
  52. package/server/service/location/location.ts +2 -2
  53. package/server/utils/datetime-util.ts +54 -0
  54. package/server/utils/index.ts +1 -0
  55. package/server/utils/inventory-util.ts +162 -39
@@ -117,6 +117,7 @@ export class InventoryHistoryQuery {
117
117
  qb.where('Lower(prd.sku) LIKE :productInfo', { productInfo: productFilterValue })
118
118
  .orWhere('Lower(prd.name) LIKE :productInfo', { productInfo: productFilterValue })
119
119
  .orWhere('Lower(prd.description) LIKE :productInfo', { productInfo: productFilterValue })
120
+ .orWhere('Lower(prd.brand) LIKE :productInfo', { productInfo: productFilterValue })
120
121
  })
121
122
  )
122
123
 
@@ -384,7 +385,7 @@ export class InventoryHistoryQuery {
384
385
  uomValue: item.uom_value,
385
386
  openingQty: item.opening_qty,
386
387
  openingUomValue: item.opening_uom_value,
387
- orderName: item.order_name,
388
+ orderNo: item.order_name,
388
389
  orderRefNo: item.ref_no,
389
390
  createdAt: item.created_at
390
391
  }
@@ -944,7 +945,8 @@ export class InventoryHistoryQuery {
944
945
  @Arg('filters', type => [Filter], { nullable: true }) filters?: Filter[],
945
946
  @Arg('pagination', type => Pagination, { nullable: true }) pagination?: Pagination,
946
947
  @Arg('sortings', type => [Sorting], { nullable: true }) sortings?: Sorting[],
947
- @Arg('locationSortingRules', type => [Sorting], { nullable: true }) locationSortingRules?: Sorting[]
948
+ @Arg('locationSortingRules', type => [Sorting], { nullable: true }) locationSortingRules?: Sorting[],
949
+ @Arg('setPagination', type => Boolean, { defaultValue: true }) setPagination?: Boolean
948
950
  ): Promise<InventoryList> {
949
951
  const { domain, user, tx }: { domain: Domain; user: User; tx: EntityManager } = context.state
950
952
 
@@ -1017,7 +1019,8 @@ export class InventoryHistoryQuery {
1017
1019
  )
1018
1020
  and (lower(prd.name) like any(array[${products}])
1019
1021
  or lower(prd.description) like any(array[${products}])
1020
- or lower(prd.sku) like any(array[${products}]))
1022
+ or lower(prd.sku) like any(array[${products}])
1023
+ or lower(prd.brand) like any(array[${products}]))
1021
1024
  and prd.id = rih.product_id
1022
1025
  group by prd.id
1023
1026
  )`
@@ -1076,14 +1079,14 @@ export class InventoryHistoryQuery {
1076
1079
 
1077
1080
  // query the results
1078
1081
  await tx.query(`
1079
- CREATE TEMP TABLE tmp_bizfilter AS (
1082
+ CREATE TEMP TABLE tmp_bizfilter on commit drop AS (
1080
1083
  SELECT bizplace_id::uuid FROM (VALUES ${bizplaces}) AS bizFilter(bizplace_id)
1081
1084
  );
1082
1085
  `)
1083
1086
 
1084
1087
  await tx.query(
1085
1088
  `
1086
- create temp table tmp_src as (
1089
+ create temp table tmp_src on commit drop as (
1087
1090
  select domain_id, pallet_id, carton_id, seq, qty, uom_value, packing_type, batch_id, batch_id_ref, created_at, status,
1088
1091
  product_id::uuid as product_id, bizplace_id::uuid as bizplace_id, location_id::uuid as location_id
1089
1092
  from reduced_inventory_histories rih
@@ -1095,7 +1098,7 @@ export class InventoryHistoryQuery {
1095
1098
 
1096
1099
  await tx.query(
1097
1100
  `
1098
- create temp table tmp_data as (
1101
+ create temp table tmp_data on commit drop as (
1099
1102
  select dt.*, rih.carton_id, rih.batch_id, rih.batch_id_ref, rih.product_id, rih.packing_type, rih.bizplace_id, rih.location_id, iv.uom,
1100
1103
  iv.expiration_date, iv.reusable_pallet_id, iv.remark
1101
1104
  from
@@ -1126,7 +1129,7 @@ export class InventoryHistoryQuery {
1126
1129
  rih.initial_inbound_at as "initialInboundAt",
1127
1130
  case when rih.reusable_pallet_id is not null then concat(rih.batch_id, ' (', plt.name, ')') else rih.batch_id end as "batchId",
1128
1131
  rih.batch_id_ref as "batchIdRef", rih.product_id, rih.packing_type as "packingType", rih.bizplace_id, rih.location_id,
1129
- prd.id as product_id, prd.name as product_name, prd.sku as product_sku, prd.description as product_description,
1132
+ 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,
1130
1133
  bz.id as bizplace_id, bz.name as bizplace_name,
1131
1134
  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,
1132
1135
  wh.name as warehouse_name, plt.name as reusable_pallet_name,
@@ -1140,15 +1143,10 @@ export class InventoryHistoryQuery {
1140
1143
  inner join warehouses wh on wh.id = loc.warehouse_id
1141
1144
  WHERE 1 = 1
1142
1145
  ${queryOrder}
1143
- OFFSET $1 LIMIT $2;
1144
- `,
1145
- [(pagination.page - 1) * pagination.limit, pagination.limit]
1146
+ ${setPagination ? 'OFFSET ' + (pagination.page - 1) * pagination.limit + ' LIMIT ' + pagination.limit : ''}
1147
+ `
1146
1148
  )
1147
1149
 
1148
- tx.query(`
1149
- drop table tmp_src, tmp_data, tmp_bizfilter
1150
- `)
1151
-
1152
1150
  // map all results
1153
1151
  let items = result.map(itm => {
1154
1152
  return {
@@ -1167,7 +1165,8 @@ export class InventoryHistoryQuery {
1167
1165
  id: itm.product_id,
1168
1166
  name: itm.product_name,
1169
1167
  description: itm.product_description,
1170
- sku: itm.product_sku
1168
+ sku: itm.product_sku,
1169
+ brand: itm.product_brand
1171
1170
  }
1172
1171
  }
1173
1172
  })
@@ -1204,7 +1203,7 @@ async function massageInventorySummary(tx: EntityManager, params: ListParam, biz
1204
1203
  }
1205
1204
  await tx.query(
1206
1205
  `
1207
- create temp table temp_inventory_summary as (
1206
+ create temp table temp_inventory_summary ON COMMIT DROP as (
1208
1207
  select src.*,
1209
1208
  opening_qty + adjustment_qty + total_in_qty + total_out_qty as closing_qty
1210
1209
  from (
@@ -1234,10 +1233,6 @@ async function massageInventorySummary(tx: EntityManager, params: ListParam, biz
1234
1233
  [(params.pagination.page - 1) * params.pagination.limit, params.pagination.limit]
1235
1234
  )
1236
1235
 
1237
- tx.query(`
1238
- drop table temp_products, temp_inv_history, temp_inventory_summary
1239
- `)
1240
-
1241
1236
  return [result, total]
1242
1237
  }
1243
1238
 
@@ -1255,7 +1250,7 @@ async function massageInventoryPalletSummary(tx: EntityManager, params: ListPara
1255
1250
  }
1256
1251
  await tx.query(
1257
1252
  `
1258
- create temp table temp_inventory_pallet_summary as (
1253
+ create temp table temp_inventory_pallet_summary ON COMMIT DROP as (
1259
1254
  select invh.*,
1260
1255
  invh.opening_qty + invh.total_in_qty + invh.total_out_qty + invh.adjustment_qty as closing_qty from (
1261
1256
  select product_sku, product_id, product_name, product_description, product_type,
@@ -1350,16 +1345,13 @@ async function massageInventoryPalletSummary(tx: EntityManager, params: ListPara
1350
1345
  [(params.pagination.page - 1) * params.pagination.limit, params.pagination.limit]
1351
1346
  )
1352
1347
 
1353
- tx.query(`
1354
- drop table temp_products, temp_inv_history, temp_inventory_pallet_summary
1355
- `)
1356
-
1357
1348
  return [result, total]
1358
1349
  }
1359
1350
 
1360
1351
  async function productsQuery(tx: EntityManager, params: ListParam, bizplace: Bizplace) {
1361
1352
  let product = params.filters.find(data => data.name === 'product')
1362
1353
  let productDesc = params.filters.find(data => data.name === 'productDescription')
1354
+ let productType = params.filters.find(data => data.name === 'productType')
1363
1355
 
1364
1356
  let productQuery = ''
1365
1357
  if (product) {
@@ -1379,12 +1371,17 @@ async function productsQuery(tx: EntityManager, params: ListParam, bizplace: Biz
1379
1371
 
1380
1372
  let productDescQuery = ''
1381
1373
  if (productDesc) {
1382
- productDescQuery = "AND Lower(description) LIKE '%" + productDesc.value.toLowerCase() + "%'"
1374
+ productDescQuery = "AND Lower(prd.description) LIKE '%" + productDesc.value.toLowerCase() + "%'"
1375
+ }
1376
+
1377
+ let productTypeQuery = ''
1378
+ if (productType) {
1379
+ productTypeQuery = "AND prd.type = '" + productType.value + "'"
1383
1380
  }
1384
1381
 
1385
1382
  await tx.query(
1386
1383
  `
1387
- create temp table temp_products AS
1384
+ create temp table temp_products ON COMMIT DROP AS
1388
1385
  (
1389
1386
  select prd.id, prd.name, prd.sku, prd.description, prd.id::varchar as product_id, prd.type from products prd
1390
1387
  inner join bizplaces b on b.id = prd.bizplace_id
@@ -1392,6 +1389,8 @@ async function productsQuery(tx: EntityManager, params: ListParam, bizplace: Biz
1392
1389
  inner join bizplaces b2 on b2.company_id = c.id
1393
1390
  where b2.id = $1
1394
1391
  ${productQuery}
1392
+ ${productDescQuery}
1393
+ ${productTypeQuery}
1395
1394
  GROUP BY prd.id, prd.sku, prd.name, prd.description
1396
1395
  )`,
1397
1396
  [bizplace.id]
@@ -1418,7 +1417,7 @@ async function filterInventoryQuery(tx: EntityManager, params: ListParam, bizpla
1418
1417
 
1419
1418
  await tx.query(
1420
1419
  `
1421
- create temp table temp_inv_history as (
1420
+ create temp table temp_inv_history ON COMMIT DROP as (
1422
1421
  select i2.pallet_id, ih.product_id::uuid, ih.packing_type, i2.packing_size, ih.batch_id,
1423
1422
  ih.id as inventory_history_id, ih.seq, ih.status, ih.transaction_type, ih.qty, ih.opening_qty, ih.created_at
1424
1423
  from inventories i2
@@ -18,8 +18,8 @@ export class InventoryHistoryList {
18
18
 
19
19
  @ObjectType()
20
20
  export class InventoryHistoryPalletReportList {
21
- @Field(type => [InventoryHistoryPalletReportList], { nullable: true })
22
- items?: InventoryHistoryPalletReportList[]
21
+ @Field(type => [InventoryHistoryPalletReport], { nullable: true })
22
+ items?: InventoryHistoryPalletReport[]
23
23
 
24
24
  @Field(type => Int, { nullable: true })
25
25
  total?: number
@@ -13,7 +13,7 @@ import {
13
13
  import { User } from '@things-factory/auth-base'
14
14
  import { Bizplace } from '@things-factory/biz-base'
15
15
  import { Product, ProductDetail } from '@things-factory/product-base'
16
- import { Domain } from '@things-factory/shell'
16
+ import { Domain, ScalarDate } from '@things-factory/shell'
17
17
 
18
18
  import { Inventory } from '../inventory/inventory'
19
19
  import { Location } from '../location/location'
@@ -164,7 +164,7 @@ export class InventoryHistory {
164
164
  inventory: Inventory
165
165
 
166
166
  @Column('date', { nullable: true })
167
- @Field({ nullable: true })
167
+ @Field(type => ScalarDate, { nullable: true })
168
168
  expirationDate: Date
169
169
 
170
170
  @Column('int', { nullable: true })
@@ -31,7 +31,7 @@ export class LocationQuery {
31
31
  @Query(returns => LocationOccupancy)
32
32
  async locationOccupancies(
33
33
  @Arg('warehouse') warehouse: string,
34
- @Arg('types', type => [String]) types: string[],
34
+ @Arg('types', type => [String], { nullable: true }) types: string[],
35
35
  @Ctx() context: any
36
36
  ): Promise<LocationOccupancy> {
37
37
  const { domain }: { domain: Domain } = context.state
@@ -104,6 +104,15 @@ export class LocationPatch {
104
104
  @Field({ nullable: true })
105
105
  zone?: string
106
106
 
107
+ @Field({ nullable: true })
108
+ firstDelimiter?: string
109
+
110
+ @Field({ nullable: true })
111
+ secondDelimiter?: string
112
+
113
+ @Field({ nullable: true })
114
+ thirdDelimiter?: string
115
+
107
116
  @Field({ nullable: true })
108
117
  row?: string
109
118
 
@@ -137,6 +146,15 @@ export class NewLocation {
137
146
  @Field()
138
147
  zone: string
139
148
 
149
+ @Field({ nullable: true })
150
+ firstDelimiter?: string
151
+
152
+ @Field({ nullable: true })
153
+ secondDelimiter?: string
154
+
155
+ @Field({ nullable: true })
156
+ thirdDelimiter?: string
157
+
140
158
  @Field()
141
159
  row: string
142
160
 
@@ -37,8 +37,8 @@ export class Location {
37
37
  @Field(type => Warehouse, { nullable: true })
38
38
  warehouse: Warehouse
39
39
 
40
- @Column()
41
- @Field()
40
+ @Column({ nullable: true })
41
+ @Field({ nullable: true })
42
42
  name: string
43
43
 
44
44
  @Column({
@@ -0,0 +1,54 @@
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,2 +1,3 @@
1
1
  export * from './inventory-no-generator'
2
2
  export * from './inventory-util'
3
+ export * from './datetime-util'
@@ -5,10 +5,119 @@ import { Bizplace } from '@things-factory/biz-base'
5
5
  import { Product } from '@things-factory/product-base'
6
6
  import { Domain } from '@things-factory/shell'
7
7
 
8
- import { INVENTORY_STATUS, LOCATION_STATUS } from '../constants'
8
+ import { INVENTORY_STATUS, INVENTORY_TRANSACTION_TYPE, LOCATION_STATUS } from '../constants'
9
9
  import { Inventory, InventoryHistory, Location } from '../service'
10
10
  import { InventoryNoGenerator } from '../utils'
11
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
+ ): Promise<Inventory> {
87
+ if (inventory.id) {
88
+ inventory = await this.updateInventory(inventory)
89
+ } else {
90
+ inventory = await this.createInventory(inventory)
91
+ }
92
+
93
+ await generateInventoryHistory(
94
+ inventory,
95
+ refOrder,
96
+ transactionType,
97
+ changedQty,
98
+ changedUom,
99
+ this.user,
100
+ this.trxMgr
101
+ )
102
+
103
+ return inventory
104
+ }
105
+
106
+ /**
107
+ * @summary set common stamp like domain, creator, updater
108
+ * @description Set common stamp to passed record
109
+ * If it doesn't have id it will handle it as creating one
110
+ * If it has id it will handle it as updating one
111
+ */
112
+ setStamp(record: Record<string, any>): Record<string, any> {
113
+ if (!record.domain) record.domain = this.domain
114
+ if (!record.id && !record.creator) record.creator = this.user
115
+ if (!record.updater) record.updater = this.user
116
+
117
+ return record
118
+ }
119
+ }
120
+
12
121
  /**
13
122
  * @description It will insert new record into inventory histories table.
14
123
  * seq will be calculated based on number of records for one specific pallet id (provided by inventory object)
@@ -49,58 +158,72 @@ export async function generateInventoryHistory(
49
158
 
50
159
  if (seq) {
51
160
  const lastInvHistory: InventoryHistory = await invHistoryRepo.findOne({
52
- domain: inventory.domain,
53
- palletId: inventory.palletId,
54
- seq: seq - 1
161
+ where: {
162
+ domain: inventory.domain,
163
+ palletId: inventory.palletId,
164
+ },
165
+ order: {
166
+ seq: 'DESC'
167
+ },
55
168
  })
56
169
  openingQty = lastInvHistory.openingQty + lastInvHistory.qty
57
170
  openingUomValue = lastInvHistory.openingUomValue + lastInvHistory.uomValue
58
171
  }
59
172
 
60
- let inventoryHistory: InventoryHistory = new InventoryHistory()
61
- inventoryHistory.name = InventoryNoGenerator.inventoryHistoryName()
62
- inventoryHistory.description = inventory.description
63
- inventoryHistory.seq = seq
64
- inventoryHistory.palletId = inventory.palletId
65
- inventoryHistory.cartonId = inventory.cartonId
66
- inventoryHistory.batchId = inventory.batchId
67
- inventoryHistory.batchIdRef = inventory.batchIdRef
68
- inventoryHistory.status = inventory.status
69
- inventoryHistory.transactionType = transactionType
70
- inventoryHistory.refOrderId = refOrder?.id || null
71
- inventoryHistory.orderNo = refOrder?.name || null
72
- inventoryHistory.orderRefNo = refOrder?.refNo || null
73
- inventoryHistory.inventory = inventory
74
- inventoryHistory.product = inventory.product
75
- inventoryHistory.reusablePallet = inventory.reusablePallet
76
- inventoryHistory.zone = inventory.zone
77
- inventoryHistory.warehouse = inventory.warehouse
78
- inventoryHistory.location = inventory.location
79
- inventoryHistory.expirationDate = inventory.expirationDate
80
- inventoryHistory.packingType = inventory.packingType
81
- inventoryHistory.uom = inventory.uom
82
- inventoryHistory.qty = qty
83
- inventoryHistory.openingQty = openingQty
84
- inventoryHistory.uomValue = uomValue
85
- inventoryHistory.openingUomValue = openingUomValue
86
- inventoryHistory.unitCost = inventory.unitCost
87
- inventoryHistory.domain = inventory.domain
88
- inventoryHistory.bizplace = inventory.bizplace
89
- inventoryHistory.creator = user
90
- inventoryHistory.updater = user
91
-
92
- inventoryHistory = await invHistoryRepo.save(inventoryHistory)
173
+ let remainQty = ((openingQty || 0) + (qty || 0))
174
+
175
+ let inventoryHistory: Partial<InventoryHistory> = new InventoryHistory()
176
+
177
+ inventoryHistory = {
178
+ ...inventory,
179
+ name: InventoryNoGenerator.inventoryHistoryName(),
180
+ inventory,
181
+ seq: seq - 1,
182
+ status: remainQty == 0 ? INVENTORY_STATUS.TERMINATED : inventory.status,
183
+ transactionType,
184
+ refOrderId: refOrder?.id || null,
185
+ orderNo: refOrder?.name || null,
186
+ orderRefNo: refOrder?.refNo || null,
187
+ qty,
188
+ openingQty,
189
+ uomValue,
190
+ openingUomValue: openingUomValue,
191
+ creator: user,
192
+ updater: user
193
+ }
194
+
195
+ let newInventoryHistory = await invHistoryRepo.save(inventoryHistory)
196
+
197
+ if (remainQty == 0) {
198
+ let terminatedHistory = {
199
+ ...newInventoryHistory,
200
+ name: InventoryNoGenerator.inventoryHistoryName(),
201
+ seq: seq + 1,
202
+ status: INVENTORY_STATUS.TERMINATED,
203
+ transactionType: INVENTORY_TRANSACTION_TYPE.TERMINATED,
204
+ uom: inventory.uom,
205
+ qty: 0,
206
+ openingQty: 0,
207
+ uomValue: 0,
208
+ openingUomValue: 0
209
+ }
210
+
211
+ delete terminatedHistory.id
212
+
213
+ newInventoryHistory = await invHistoryRepo.save(terminatedHistory)
214
+ inventory.status = INVENTORY_STATUS.TERMINATED
215
+ }
93
216
 
94
217
  if (inventory.lastSeq !== seq) {
95
218
  await invRepo.save({
96
219
  ...inventory,
97
- lastSeq: inventoryHistory.seq,
220
+ lastSeq: newInventoryHistory.seq,
98
221
  updater: user
99
222
  })
100
223
  }
101
224
 
102
225
  await switchLocationStatus(domain, location, user, trxMgr)
103
- return inventoryHistory
226
+ return newInventoryHistory
104
227
  }
105
228
 
106
229
  /**