@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.
- package/dist-server/constants/index.js +1 -0
- package/dist-server/constants/index.js.map +1 -1
- package/dist-server/constants/location.js +3 -2
- package/dist-server/constants/location.js.map +1 -1
- package/dist-server/constants/rule-type.js +8 -0
- package/dist-server/constants/rule-type.js.map +1 -0
- package/dist-server/service/inventory/inventory-mutation.js +68 -28
- package/dist-server/service/inventory/inventory-mutation.js.map +1 -1
- package/dist-server/service/inventory/inventory-query.js +119 -86
- package/dist-server/service/inventory/inventory-query.js.map +1 -1
- package/dist-server/service/inventory/inventory-types.js +16 -0
- package/dist-server/service/inventory/inventory-types.js.map +1 -1
- package/dist-server/service/inventory/inventory.js +13 -9
- package/dist-server/service/inventory/inventory.js.map +1 -1
- package/dist-server/service/inventory-change/inventory-change-mutation.js +7 -9
- package/dist-server/service/inventory-change/inventory-change-mutation.js.map +1 -1
- package/dist-server/service/inventory-change/inventory-change.js +5 -1
- package/dist-server/service/inventory-change/inventory-change.js.map +1 -1
- package/dist-server/service/inventory-history/inventory-history-query.js +28 -26
- package/dist-server/service/inventory-history/inventory-history-query.js.map +1 -1
- package/dist-server/service/inventory-history/inventory-history-types.js +4 -4
- package/dist-server/service/inventory-history/inventory-history-types.js.map +1 -1
- package/dist-server/service/inventory-history/inventory-history.js +1 -1
- package/dist-server/service/inventory-history/inventory-history.js.map +1 -1
- package/dist-server/service/location/location-query.js +1 -1
- package/dist-server/service/location/location-query.js.map +1 -1
- package/dist-server/service/location/location-types.js +24 -0
- package/dist-server/service/location/location-types.js.map +1 -1
- package/dist-server/service/location/location.js +2 -2
- package/dist-server/service/location/location.js.map +1 -1
- package/dist-server/utils/datetime-util.js +49 -0
- package/dist-server/utils/datetime-util.js.map +1 -0
- package/dist-server/utils/index.js +1 -0
- package/dist-server/utils/index.js.map +1 -1
- package/dist-server/utils/inventory-util.js +104 -37
- package/dist-server/utils/inventory-util.js.map +1 -1
- package/package.json +8 -8
- package/server/constants/index.ts +1 -0
- package/server/constants/location.ts +3 -2
- package/server/constants/rule-type.ts +4 -0
- package/server/service/inventory/inventory-mutation.ts +65 -20
- package/server/service/inventory/inventory-query.ts +151 -107
- package/server/service/inventory/inventory-types.ts +12 -0
- package/server/service/inventory/inventory.ts +13 -10
- package/server/service/inventory-change/inventory-change-mutation.ts +10 -11
- package/server/service/inventory-change/inventory-change.ts +6 -2
- package/server/service/inventory-history/inventory-history-query.ts +27 -28
- package/server/service/inventory-history/inventory-history-types.ts +2 -2
- package/server/service/inventory-history/inventory-history.ts +2 -2
- package/server/service/location/location-query.ts +1 -1
- package/server/service/location/location-types.ts +18 -0
- package/server/service/location/location.ts +2 -2
- package/server/utils/datetime-util.ts +54 -0
- package/server/utils/index.ts +1 -0
- 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
|
-
|
|
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
|
|
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 => [
|
|
22
|
-
items?:
|
|
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
|
|
|
@@ -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
|
+
}
|
package/server/utils/index.ts
CHANGED
|
@@ -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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
61
|
-
|
|
62
|
-
inventoryHistory
|
|
63
|
-
|
|
64
|
-
inventoryHistory
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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:
|
|
220
|
+
lastSeq: newInventoryHistory.seq,
|
|
98
221
|
updater: user
|
|
99
222
|
})
|
|
100
223
|
}
|
|
101
224
|
|
|
102
225
|
await switchLocationStatus(domain, location, user, trxMgr)
|
|
103
|
-
return
|
|
226
|
+
return newInventoryHistory
|
|
104
227
|
}
|
|
105
228
|
|
|
106
229
|
/**
|