@things-factory/warehouse-base 5.0.14 → 6.0.0-alpha.0
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/controllers/ecommerce/ecommerce-controller.js +1 -1
- package/dist-server/controllers/ecommerce/ecommerce-controller.js.map +1 -1
- package/dist-server/controllers/ecommerce/sellercraft-controller.js +64 -60
- package/dist-server/controllers/ecommerce/sellercraft-controller.js.map +1 -1
- package/dist-server/controllers/warehouse-controller.js +7 -5
- package/dist-server/controllers/warehouse-controller.js.map +1 -1
- package/dist-server/service/inventory/inventory-mutation.js +6 -6
- package/dist-server/service/inventory/inventory-mutation.js.map +1 -1
- package/dist-server/service/inventory/inventory-query.js +217 -195
- package/dist-server/service/inventory/inventory-query.js.map +1 -1
- package/dist-server/service/inventory/inventory-types.js +14 -15
- package/dist-server/service/inventory/inventory-types.js.map +1 -1
- package/dist-server/service/inventory/inventory.js +62 -42
- package/dist-server/service/inventory/inventory.js.map +1 -1
- package/dist-server/service/inventory-change/inventory-change-mutation.js +252 -216
- package/dist-server/service/inventory-change/inventory-change-mutation.js.map +1 -1
- package/dist-server/service/inventory-change/inventory-change-query.js +6 -7
- package/dist-server/service/inventory-change/inventory-change-query.js.map +1 -1
- package/dist-server/service/inventory-change/inventory-change.js +7 -7
- package/dist-server/service/inventory-change/inventory-change.js.map +1 -1
- package/dist-server/service/inventory-history/inventory-history-mutation.js +1 -1
- package/dist-server/service/inventory-history/inventory-history-mutation.js.map +1 -1
- package/dist-server/service/inventory-history/inventory-history-query.js +89 -99
- package/dist-server/service/inventory-history/inventory-history-query.js.map +1 -1
- package/dist-server/service/inventory-history/inventory-history-types.js +3 -3
- package/dist-server/service/inventory-history/inventory-history-types.js.map +1 -1
- package/dist-server/service/inventory-history/inventory-history.js +7 -7
- package/dist-server/service/inventory-history/inventory-history.js.map +1 -1
- package/dist-server/service/inventory-item/inventory-item-mutation.js +10 -10
- package/dist-server/service/inventory-item/inventory-item-mutation.js.map +1 -1
- package/dist-server/service/inventory-item/inventory-item-query.js +18 -17
- package/dist-server/service/inventory-item/inventory-item-query.js.map +1 -1
- package/dist-server/service/inventory-item/inventory-item-type.js +4 -5
- package/dist-server/service/inventory-item/inventory-item-type.js.map +1 -1
- package/dist-server/service/inventory-item/inventory-item.js +5 -5
- package/dist-server/service/inventory-item/inventory-item.js.map +1 -1
- package/dist-server/service/inventory-item-change/inventory-item-change-mutation.js +4 -4
- package/dist-server/service/inventory-item-change/inventory-item-change-mutation.js.map +1 -1
- package/dist-server/service/inventory-item-change/inventory-item-change-query.js +7 -9
- package/dist-server/service/inventory-item-change/inventory-item-change-query.js.map +1 -1
- package/dist-server/service/inventory-item-change/inventory-item-change-type.js +6 -7
- package/dist-server/service/inventory-item-change/inventory-item-change-type.js.map +1 -1
- package/dist-server/service/inventory-item-change/inventory-item-change.js +3 -4
- package/dist-server/service/inventory-item-change/inventory-item-change.js.map +1 -1
- package/dist-server/service/inventory-product/inventory-product-mutation.js +4 -4
- package/dist-server/service/inventory-product/inventory-product-mutation.js.map +1 -1
- package/dist-server/service/inventory-product/inventory-product-query.js +7 -9
- package/dist-server/service/inventory-product/inventory-product-query.js.map +1 -1
- package/dist-server/service/inventory-product/inventory-product-type.js +1 -2
- package/dist-server/service/inventory-product/inventory-product-type.js.map +1 -1
- package/dist-server/service/inventory-product/inventory-product.js +5 -5
- package/dist-server/service/inventory-product/inventory-product.js.map +1 -1
- package/dist-server/service/location/location-mutation.js +5 -5
- package/dist-server/service/location/location-mutation.js.map +1 -1
- package/dist-server/service/location/location-query.js +17 -19
- package/dist-server/service/location/location-query.js.map +1 -1
- package/dist-server/service/location/location-types.js +3 -3
- package/dist-server/service/location/location-types.js.map +1 -1
- package/dist-server/service/location/location.js +14 -14
- package/dist-server/service/location/location.js.map +1 -1
- package/dist-server/service/movement/movement-mutation.js +6 -5
- package/dist-server/service/movement/movement-mutation.js.map +1 -1
- package/dist-server/service/movement/movement-query.js +15 -15
- package/dist-server/service/movement/movement-query.js.map +1 -1
- package/dist-server/service/movement/movement-types.js +4 -5
- package/dist-server/service/movement/movement-types.js.map +1 -1
- package/dist-server/service/movement/movement.js +5 -5
- package/dist-server/service/movement/movement.js.map +1 -1
- package/dist-server/service/pallet/pallet-mutation.js +5 -5
- package/dist-server/service/pallet/pallet-mutation.js.map +1 -1
- package/dist-server/service/pallet/pallet-query.js +9 -11
- package/dist-server/service/pallet/pallet-query.js.map +1 -1
- package/dist-server/service/pallet/pallet-types.js +5 -6
- package/dist-server/service/pallet/pallet-types.js.map +1 -1
- package/dist-server/service/pallet/pallet.js +6 -6
- package/dist-server/service/pallet/pallet.js.map +1 -1
- package/dist-server/service/pallet-count/pallet-count-mutation.js +1 -1
- package/dist-server/service/pallet-count/pallet-count-mutation.js.map +1 -1
- package/dist-server/service/pallet-count/pallet-count-query.js +6 -8
- package/dist-server/service/pallet-count/pallet-count-query.js.map +1 -1
- package/dist-server/service/pallet-count/pallet-count.js +3 -4
- package/dist-server/service/pallet-count/pallet-count.js.map +1 -1
- package/dist-server/service/pallet-history/pallet-history-mutation.js +1 -1
- package/dist-server/service/pallet-history/pallet-history-mutation.js.map +1 -1
- package/dist-server/service/pallet-history/pallet-history-query.js +6 -8
- package/dist-server/service/pallet-history/pallet-history-query.js.map +1 -1
- package/dist-server/service/pallet-history/pallet-history.js +6 -6
- package/dist-server/service/pallet-history/pallet-history.js.map +1 -1
- package/dist-server/service/reduced-inventory-history/reduced-inventory-history.js +1 -1
- package/dist-server/service/reduced-inventory-history/reduced-inventory-history.js.map +1 -1
- package/dist-server/service/tote/tote-mutation.js +4 -4
- package/dist-server/service/tote/tote-mutation.js.map +1 -1
- package/dist-server/service/tote/tote-query.js +12 -13
- package/dist-server/service/tote/tote-query.js.map +1 -1
- package/dist-server/service/tote/tote-types.js +2 -3
- package/dist-server/service/tote/tote-types.js.map +1 -1
- package/dist-server/service/tote/tote.js +5 -5
- package/dist-server/service/tote/tote.js.map +1 -1
- package/dist-server/service/warehouse/warehouse-mutation.js +1 -1
- package/dist-server/service/warehouse/warehouse-mutation.js.map +1 -1
- package/dist-server/service/warehouse/warehouse-query.js +9 -10
- package/dist-server/service/warehouse/warehouse-query.js.map +1 -1
- package/dist-server/service/warehouse/warehouse.js +12 -12
- package/dist-server/service/warehouse/warehouse.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/dist-server/utils/inventory-util.js +16 -16
- package/dist-server/utils/inventory-util.js.map +1 -1
- package/package.json +8 -8
- package/server/controllers/ecommerce/ecommerce-controller.ts +1 -1
- package/server/controllers/ecommerce/sellercraft-controller.ts +75 -65
- package/server/controllers/warehouse-controller.ts +9 -4
- package/server/service/inventory/inventory-mutation.ts +28 -24
- package/server/service/inventory/inventory-query.ts +269 -304
- package/server/service/inventory/inventory.ts +50 -35
- package/server/service/inventory-change/inventory-change-mutation.ts +305 -256
- package/server/service/inventory-change/inventory-change-query.ts +9 -9
- package/server/service/inventory-history/inventory-history-mutation.ts +12 -15
- package/server/service/inventory-history/inventory-history-query.ts +158 -133
- package/server/service/inventory-item/inventory-item-mutation.ts +20 -17
- package/server/service/inventory-item/inventory-item-query.ts +28 -18
- package/server/service/inventory-item-change/inventory-item-change-mutation.ts +12 -9
- package/server/service/inventory-item-change/inventory-item-change-query.ts +10 -8
- package/server/service/inventory-product/inventory-product-mutation.ts +16 -12
- package/server/service/inventory-product/inventory-product-query.ts +7 -8
- package/server/service/location/location-mutation.ts +24 -24
- package/server/service/location/location-query.ts +27 -23
- package/server/service/location/location.ts +11 -10
- package/server/service/movement/movement-mutation.ts +7 -8
- package/server/service/movement/movement-query.ts +18 -16
- package/server/service/pallet/pallet-mutation.ts +18 -20
- package/server/service/pallet/pallet-query.ts +13 -14
- package/server/service/pallet-count/pallet-count-mutation.ts +20 -17
- package/server/service/pallet-count/pallet-count-query.ts +6 -7
- package/server/service/pallet-history/pallet-history-mutation.ts +15 -15
- package/server/service/pallet-history/pallet-history-query.ts +7 -8
- package/server/service/reduced-inventory-history/reduced-inventory-history.ts +1 -1
- package/server/service/tote/tote-mutation.ts +23 -22
- package/server/service/tote/tote-query.ts +18 -14
- package/server/service/warehouse/warehouse-mutation.ts +21 -18
- package/server/service/warehouse/warehouse-query.ts +11 -11
- package/server/service/warehouse/warehouse.ts +7 -7
- package/server/utils/inventory-util.ts +10 -10
|
@@ -1,69 +1,64 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Arg,
|
|
3
|
-
Args,
|
|
4
|
-
Ctx,
|
|
5
|
-
Directive,
|
|
6
|
-
FieldResolver,
|
|
7
|
-
Query,
|
|
8
|
-
Resolver,
|
|
9
|
-
Root,
|
|
10
|
-
} from 'type-graphql';
|
|
1
|
+
import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'
|
|
11
2
|
import {
|
|
12
3
|
Brackets,
|
|
13
4
|
EntityManager,
|
|
14
5
|
Equal,
|
|
15
6
|
getRepository,
|
|
16
7
|
Not,
|
|
8
|
+
OrderByCondition,
|
|
17
9
|
Repository,
|
|
18
|
-
SelectQueryBuilder
|
|
19
|
-
} from 'typeorm'
|
|
10
|
+
SelectQueryBuilder
|
|
11
|
+
} from 'typeorm'
|
|
20
12
|
|
|
21
|
-
import { User } from '@things-factory/auth-base'
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
} from '@things-factory/
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
} from '
|
|
32
|
-
import { Setting } from '@things-factory/setting-base';
|
|
33
|
-
import {
|
|
34
|
-
buildQuery,
|
|
35
|
-
Domain,
|
|
36
|
-
Filter,
|
|
37
|
-
ListParam,
|
|
38
|
-
Pagination,
|
|
39
|
-
Sorting,
|
|
40
|
-
} from '@things-factory/shell';
|
|
41
|
-
|
|
42
|
-
import { INVENTORY_STATUS, LOCATION_TYPE } from '../../constants';
|
|
43
|
-
import { InventoryChange } from '../inventory-change/inventory-change';
|
|
44
|
-
import { Inventory } from './inventory';
|
|
45
|
-
import { InventoryBundleGroupDetail, InventoryList } from './inventory-types';
|
|
13
|
+
import { User } from '@things-factory/auth-base'
|
|
14
|
+
import { Bizplace, getPartnersCompanyBizplaces, getPermittedBizplaceIds } from '@things-factory/biz-base'
|
|
15
|
+
import { logger } from '@things-factory/env'
|
|
16
|
+
import { Product, ProductBundleSetting } from '@things-factory/product-base'
|
|
17
|
+
import { Setting } from '@things-factory/setting-base'
|
|
18
|
+
import { buildQuery, Domain, Filter, ListParam, Pagination, Sorting } from '@things-factory/shell'
|
|
19
|
+
|
|
20
|
+
import { INVENTORY_STATUS, LOCATION_TYPE } from '../../constants'
|
|
21
|
+
import { InventoryChange } from '../inventory-change/inventory-change'
|
|
22
|
+
import { Inventory } from './inventory'
|
|
23
|
+
import { InventoryBundleGroupDetail, InventoryList } from './inventory-types'
|
|
46
24
|
|
|
47
25
|
@Resolver(Inventory)
|
|
48
26
|
export class InventoryQuery {
|
|
27
|
+
/**
|
|
28
|
+
* Combined single query resolver to perform extraction of data with or without pagination
|
|
29
|
+
* @param context
|
|
30
|
+
* @param filters
|
|
31
|
+
* @param pagination
|
|
32
|
+
* @param sortings
|
|
33
|
+
* @param locationSortingRules
|
|
34
|
+
* @param exportItem
|
|
35
|
+
* @returns
|
|
36
|
+
*/
|
|
49
37
|
@Directive('@privilege(category: "inventory", privilege: "query")')
|
|
50
38
|
@Directive('@transaction')
|
|
51
39
|
@Query(returns => InventoryList)
|
|
52
40
|
async inventories(
|
|
53
|
-
@Ctx() context:
|
|
41
|
+
@Ctx() context: ResolverContext,
|
|
54
42
|
@Arg('filters', type => [Filter], { nullable: true }) filters?: Filter[],
|
|
55
43
|
@Arg('pagination', type => Pagination, { nullable: true }) pagination?: Pagination,
|
|
56
44
|
@Arg('sortings', type => [Sorting], { nullable: true }) sortings?: Sorting[],
|
|
57
|
-
@Arg('locationSortingRules', type => [Sorting], { nullable: true }) locationSortingRules?: Sorting[]
|
|
45
|
+
@Arg('locationSortingRules', type => [Sorting], { nullable: true }) locationSortingRules?: Sorting[],
|
|
46
|
+
@Arg('exportItem', type => Boolean, { nullable: true }) exportItem?: Boolean
|
|
58
47
|
): Promise<InventoryList> {
|
|
59
|
-
const { domain, user, tx }
|
|
48
|
+
const { domain, user, tx } = context.state
|
|
49
|
+
const { page, limit } = pagination || {}
|
|
60
50
|
|
|
61
51
|
try {
|
|
62
|
-
|
|
63
|
-
|
|
52
|
+
//Define special filters
|
|
53
|
+
const productFilters = filters.find((filter: any) => filter.name == 'productInfo')
|
|
54
|
+
const remainOnlyParam = filters.find((filter: any) => filter.name == 'remainOnly')
|
|
55
|
+
const bizplace = filters.find((filter: any) => filter.name === 'bizplace')
|
|
56
|
+
|
|
57
|
+
filters = filters.filter(x => ['productInfo', 'remainOnly'].indexOf(x.name) < 0)
|
|
58
|
+
|
|
64
59
|
const params = { filters, pagination }
|
|
65
60
|
|
|
66
|
-
if (!
|
|
61
|
+
if (!bizplace) {
|
|
67
62
|
params.filters.push({
|
|
68
63
|
name: 'bizplace',
|
|
69
64
|
operator: 'in',
|
|
@@ -72,56 +67,49 @@ export class InventoryQuery {
|
|
|
72
67
|
})
|
|
73
68
|
}
|
|
74
69
|
|
|
75
|
-
const
|
|
76
|
-
(f: { name: string; operator: string; value: any }) => f.name === 'remainOnly'
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
let remainOnly: boolean = false
|
|
80
|
-
if (typeof remainOnlyParam?.value !== 'undefined') {
|
|
81
|
-
remainOnly = remainOnlyParam.value
|
|
82
|
-
params.filters = params.filters.filter(
|
|
83
|
-
(f: { name: string; operator: string; value: any }) => f.name !== 'remainOnly'
|
|
84
|
-
)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const unlockOnlyParam: { name: string; operator: string; value: boolean } = params?.filters?.find(
|
|
88
|
-
(f: { name: string; operator: string; value: any }) => f.name === 'unlockOnly'
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
let unlockOnly: boolean = false
|
|
92
|
-
if (typeof unlockOnlyParam?.value !== 'undefined') {
|
|
93
|
-
unlockOnly = unlockOnlyParam.value
|
|
94
|
-
params.filters = params.filters.filter(
|
|
95
|
-
(f: { name: string; operator: string; value: any }) => f.name !== 'unlockOnly'
|
|
96
|
-
)
|
|
97
|
-
}
|
|
70
|
+
const remainOnly: boolean = remainOnlyParam?.value || false
|
|
98
71
|
|
|
99
|
-
|
|
72
|
+
// Define Query data
|
|
73
|
+
const qb: SelectQueryBuilder<Inventory> = tx.getRepository(Inventory).createQueryBuilder('inventory')
|
|
100
74
|
buildQuery(qb, params, context, {
|
|
101
75
|
searchables: ['warehouse', 'product', 'batchId', 'location', 'palletId']
|
|
102
76
|
})
|
|
103
77
|
|
|
104
|
-
qb.leftJoinAndSelect('
|
|
105
|
-
.leftJoinAndSelect('
|
|
106
|
-
.leftJoinAndSelect('
|
|
107
|
-
.leftJoinAndSelect('
|
|
108
|
-
.
|
|
109
|
-
.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
78
|
+
qb.leftJoinAndSelect('inventory.bizplace', 'bizplace')
|
|
79
|
+
.leftJoinAndSelect('inventory.product', 'product')
|
|
80
|
+
.leftJoinAndSelect('product.productDetails', 'productDetail', 'productDetail.id = inventory.product_detail_id')
|
|
81
|
+
.leftJoinAndSelect('inventory.warehouse', 'warehouse')
|
|
82
|
+
.leftJoinAndSelect('inventory.location', 'location')
|
|
83
|
+
.leftJoinAndSelect('inventory.creator', 'creator')
|
|
84
|
+
.leftJoinAndSelect('inventory.updater', 'updater')
|
|
85
|
+
|
|
86
|
+
// To get aggregated serial number in csv and total number of stored serial number
|
|
87
|
+
.leftJoinAndSelect(
|
|
88
|
+
subQuery => {
|
|
89
|
+
return subQuery
|
|
90
|
+
.select('inventoryItems.inventory_id', 'inventory_item_inventory_id')
|
|
91
|
+
.addSelect(
|
|
92
|
+
`SUM(case when "inventoryItems"."status" = 'STORED' then 1 else 0 end)`,
|
|
93
|
+
'inventory_item_count'
|
|
94
|
+
)
|
|
95
|
+
.addSelect(`string_agg(inventoryItems.serial_number, ', ')`, 'serial_numbers')
|
|
96
|
+
.from('inventory_items', 'inventoryItems')
|
|
97
|
+
.where(`inventoryItems.domain_id = :domainId`, { domainId: domain.id })
|
|
98
|
+
.andWhere(`inventoryItems.status = :ivicStatus`, { ivicStatus: INVENTORY_STATUS.STORED })
|
|
99
|
+
.groupBy('inventoryItems.inventory_id')
|
|
100
|
+
},
|
|
101
|
+
'inventoryItems',
|
|
102
|
+
'"inventoryItems"."inventory_item_inventory_id" = "inventory"."id"'
|
|
113
103
|
)
|
|
114
104
|
|
|
105
|
+
// To get inventory with remaining qty
|
|
115
106
|
if (remainOnly) {
|
|
116
|
-
qb.andWhere('
|
|
117
|
-
.andWhere('CASE WHEN
|
|
118
|
-
.andWhere('
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (unlockOnly) {
|
|
122
|
-
qb.andWhere('CASE WHEN iv.lockedQty IS NULL THEN 0 ELSE iv.lockedQty END = 0')
|
|
107
|
+
qb.andWhere('inventory.qty > 0')
|
|
108
|
+
.andWhere('CASE WHEN inventory.lockedQty IS NULL THEN 0 ELSE inventory.lockedQty END >= 0')
|
|
109
|
+
.andWhere('inventory.qty - CASE WHEN inventory.lockedQty IS NULL THEN 0 ELSE inventory.lockedQty END > 0')
|
|
123
110
|
}
|
|
124
111
|
|
|
112
|
+
// Filter based on multiple product parameters and allow to search in csv format
|
|
125
113
|
if (productFilters) {
|
|
126
114
|
let productFilterValue = `%${productFilters.value.toLowerCase()}%`
|
|
127
115
|
qb.andWhere(qb => {
|
|
@@ -129,7 +117,7 @@ export class InventoryQuery {
|
|
|
129
117
|
.subQuery()
|
|
130
118
|
.select()
|
|
131
119
|
.from(Product, `products`)
|
|
132
|
-
.where(`products.id =
|
|
120
|
+
.where(`products.id = Inventory.product_id`) // @chrislim Does the uppercase I in Inventory affect? I can see the rest are in lowercase i
|
|
133
121
|
.andWhere(
|
|
134
122
|
new Brackets(qb => {
|
|
135
123
|
qb.where('Lower(products.sku) LIKE :productInfo', { productInfo: productFilterValue })
|
|
@@ -143,12 +131,13 @@ export class InventoryQuery {
|
|
|
143
131
|
})
|
|
144
132
|
}
|
|
145
133
|
|
|
134
|
+
// Apply sorting based on child data
|
|
146
135
|
if (sortings?.length !== 0) {
|
|
147
136
|
const arrChildSortData = ['bizplace', 'product', 'location', 'warehouse', 'zone']
|
|
148
|
-
const sort = (sortings || []).reduce(
|
|
137
|
+
const sort: OrderByCondition = (sortings || []).reduce(
|
|
149
138
|
(acc, sort) => ({
|
|
150
139
|
...acc,
|
|
151
|
-
[arrChildSortData.indexOf(sort.name) >= 0 ? sort.name + '.name' : '
|
|
140
|
+
[arrChildSortData.indexOf(sort.name) >= 0 ? sort.name + '.name' : 'inventory.' + sort.name]: sort.desc
|
|
152
141
|
? 'DESC'
|
|
153
142
|
: 'ASC'
|
|
154
143
|
}),
|
|
@@ -158,53 +147,38 @@ export class InventoryQuery {
|
|
|
158
147
|
}
|
|
159
148
|
|
|
160
149
|
if (locationSortingRules?.length > 0) {
|
|
161
|
-
locationSortingRules.forEach(
|
|
150
|
+
locationSortingRules.forEach(rule => {
|
|
162
151
|
qb.addOrderBy(`location.${rule.name}`, rule.desc ? 'DESC' : 'ASC')
|
|
163
152
|
})
|
|
164
153
|
}
|
|
165
154
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
getRepository(ProductDetail).find({
|
|
171
|
-
where: {
|
|
172
|
-
product: item.product.id,
|
|
173
|
-
packingType: item.packingType,
|
|
174
|
-
packingSize: item.packingSize
|
|
175
|
-
}
|
|
176
|
-
}),
|
|
177
|
-
tx.query(
|
|
178
|
-
`
|
|
179
|
-
SELECT string_agg(ii.serial_number, ', ') AS "serialNumbers"
|
|
180
|
-
FROM inventory_items ii
|
|
181
|
-
WHERE ii.inventory_id = $1
|
|
182
|
-
GROUP BY ii.inventory_id
|
|
183
|
-
`,
|
|
184
|
-
[item.id]
|
|
185
|
-
)
|
|
186
|
-
])
|
|
155
|
+
// Fetch all row for exporting
|
|
156
|
+
if (exportItem != true && page && limit) {
|
|
157
|
+
qb.offset((page - 1) * limit).limit(limit)
|
|
158
|
+
}
|
|
187
159
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
})
|
|
196
|
-
)
|
|
160
|
+
let items = (await qb.getRawMany()).map(item => {
|
|
161
|
+
return {
|
|
162
|
+
...new Inventory(item),
|
|
163
|
+
serialNumbers: item.serial_numbers
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
let total = await qb.getCount()
|
|
197
167
|
|
|
198
|
-
return {
|
|
168
|
+
return {
|
|
169
|
+
items,
|
|
170
|
+
total
|
|
171
|
+
}
|
|
199
172
|
} catch (error) {
|
|
173
|
+
logger.error(`inventory-query[inventories]: ${error}`)
|
|
200
174
|
throw error
|
|
201
175
|
}
|
|
202
176
|
}
|
|
203
177
|
|
|
204
178
|
@Directive('@privilege(category: "inventory", privilege: "query")')
|
|
205
179
|
@Query(returns => Inventory)
|
|
206
|
-
async inventory(@Arg('palletId') palletId: string, @Ctx() context:
|
|
207
|
-
const { domain }
|
|
180
|
+
async inventory(@Arg('palletId') palletId: string, @Ctx() context: ResolverContext): Promise<Inventory> {
|
|
181
|
+
const { domain } = context.state
|
|
208
182
|
|
|
209
183
|
return await getRepository(Inventory).findOne({
|
|
210
184
|
where: { domain: domain, palletId },
|
|
@@ -214,11 +188,11 @@ export class InventoryQuery {
|
|
|
214
188
|
|
|
215
189
|
@Directive('@privilege(category: "inventory", privilege: "query")')
|
|
216
190
|
@Query(returns => Inventory)
|
|
217
|
-
async inventoryByPallet(@Arg('palletId') palletId: string, @Ctx() context:
|
|
218
|
-
const { domain }
|
|
191
|
+
async inventoryByPallet(@Arg('palletId') palletId: string, @Ctx() context: ResolverContext): Promise<Inventory> {
|
|
192
|
+
const { domain } = context.state
|
|
219
193
|
|
|
220
194
|
return await getRepository(Inventory).findOne({
|
|
221
|
-
where: { domain, palletId, status: Not(Equal(INVENTORY_STATUS.TERMINATED)) },
|
|
195
|
+
where: { domain: { id: domain.id }, palletId, status: Not(Equal(INVENTORY_STATUS.TERMINATED)) },
|
|
222
196
|
relations: ['domain', 'bizplace', 'product', 'location', 'warehouse', 'creator', 'updater']
|
|
223
197
|
})
|
|
224
198
|
}
|
|
@@ -226,9 +200,9 @@ export class InventoryQuery {
|
|
|
226
200
|
@Directive('@privilege(category: "inventory", privilege: "query")')
|
|
227
201
|
@Directive('@transaction')
|
|
228
202
|
@Query(returns => InventoryList)
|
|
229
|
-
async inventoriesByProduct(@Args() params: ListParam, @Ctx() context:
|
|
203
|
+
async inventoriesByProduct(@Args() params: ListParam, @Ctx() context: ResolverContext): Promise<InventoryList> {
|
|
230
204
|
try {
|
|
231
|
-
const { domain, user, tx }
|
|
205
|
+
const { domain, user, tx } = context.state
|
|
232
206
|
let permittedBizplaceIds: string[] = await getPermittedBizplaceIds(domain, user)
|
|
233
207
|
const partnersCompanyBizplaces: Bizplace[] = await getPartnersCompanyBizplaces(domain, user)
|
|
234
208
|
|
|
@@ -237,10 +211,13 @@ export class InventoryQuery {
|
|
|
237
211
|
|
|
238
212
|
let bizplaceFilter = params.filters.find(filter => filter.name == 'bizplace')
|
|
239
213
|
let productFilter = params.filters.find(filter => filter.name == 'product')
|
|
240
|
-
let
|
|
214
|
+
let packingTypeFilter = params.filters.find(filter => filter.name == 'packingType')
|
|
241
215
|
let availableStockFilter = params.filters.find(filter => filter.name == 'availableStock')
|
|
242
216
|
let lowStockFilter = params.filters.find(filter => filter.name == 'lowStock')
|
|
243
217
|
let overStockFilter = params.filters.find(filter => filter.name == 'overStock')
|
|
218
|
+
let quarantineStockFilter = params.filters.find(filter => filter.name == 'quarantineStock')
|
|
219
|
+
let reserveStockFilter = params.filters.find(filter => filter.name == 'reserveStock')
|
|
220
|
+
let productTypeFilter = params.filters.find(filter => filter.name == 'type')
|
|
244
221
|
|
|
245
222
|
if (bizplaceFilter) {
|
|
246
223
|
const bizplaceQueryBuilder: SelectQueryBuilder<Bizplace> = getRepository(Bizplace).createQueryBuilder('b')
|
|
@@ -304,31 +281,111 @@ export class InventoryQuery {
|
|
|
304
281
|
)`
|
|
305
282
|
}
|
|
306
283
|
|
|
284
|
+
let qtyStockQuery = ''
|
|
285
|
+
|
|
307
286
|
let availableStockQuery = ''
|
|
287
|
+
|
|
288
|
+
if (reserveStockFilter?.value) {
|
|
289
|
+
qtyStockQuery += `\nAND SUM("reserveQty") > 0`
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (quarantineStockFilter?.value) {
|
|
293
|
+
qtyStockQuery += `\nAND SUM("quarantineQty") > 0`
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (availableStockFilter?.value) {
|
|
297
|
+
qtyStockQuery += ` AND SUM("availableQty") > 0`
|
|
298
|
+
}
|
|
299
|
+
|
|
308
300
|
if (availableStockFilter?.value) {
|
|
309
301
|
availableStockQuery = ` AND SUM("Inventory"."qty") > 0`
|
|
310
302
|
}
|
|
311
303
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
304
|
+
if (availableStockFilter?.value && quarantineStockFilter?.value) {
|
|
305
|
+
qtyStockQuery = ''
|
|
306
|
+
qtyStockQuery += `\nAND (SUM("availableQty") > 0 \n OR SUM("quarantineQty") > 0)`
|
|
315
307
|
}
|
|
316
308
|
|
|
317
|
-
if (
|
|
318
|
-
|
|
319
|
-
|
|
309
|
+
if (availableStockFilter?.value && reserveStockFilter?.value) {
|
|
310
|
+
qtyStockQuery = ''
|
|
311
|
+
qtyStockQuery += `\nAND (SUM("availableQty") > 0 \n OR SUM("reserveQty") > 0)`
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (quarantineStockFilter?.value && reserveStockFilter?.value) {
|
|
315
|
+
qtyStockQuery = ''
|
|
316
|
+
qtyStockQuery += `\nAND (SUM("quarantineQty") > 0 \n OR SUM("reserveQty") > 0)`
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
let inventoryQuery = ''
|
|
320
|
+
if (packingTypeFilter) {
|
|
321
|
+
let packingTypeValue = packingTypeFilter.value
|
|
322
|
+
.toLowerCase()
|
|
323
|
+
.split(',')
|
|
324
|
+
.map(prod => {
|
|
325
|
+
return "'%" + prod.trim().replace(/'/g, "''") + "%'"
|
|
326
|
+
})
|
|
327
|
+
.join(',')
|
|
328
|
+
|
|
329
|
+
inventoryQuery =
|
|
330
|
+
inventoryQuery +
|
|
331
|
+
` AND (
|
|
332
|
+
Lower("Inventory"."packing_type") LIKE ANY(ARRAY[${packingTypeValue}])
|
|
333
|
+
)`
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
let thresholdQuery = ''
|
|
337
|
+
if (lowStockFilter?.value && overStockFilter?.value) {
|
|
338
|
+
throw new Error('invalid filter combination')
|
|
339
|
+
} else if (lowStockFilter?.value && !overStockFilter?.value) {
|
|
340
|
+
thresholdQuery = `AND SUM(COALESCE("minQty", 0)) > SUM("availableQty")`
|
|
341
|
+
} else if (!lowStockFilter?.value && overStockFilter?.value) {
|
|
342
|
+
thresholdQuery = `AND SUM(COALESCE("maxQty", 0)) > 0 AND SUM(COALESCE("maxQty", 0)) < SUM("availableQty")`
|
|
320
343
|
}
|
|
321
344
|
|
|
345
|
+
await tx.query(
|
|
346
|
+
`
|
|
347
|
+
CREATE TEMP TABLE order_inventories_by_products AS (
|
|
348
|
+
SELECT "product_id", "packing_type", sum("release_qty") AS "total_release_qty" FROM order_inventories oi
|
|
349
|
+
WHERE "type" = 'RELEASE_OF_GOODS'
|
|
350
|
+
AND "domain_id" = $1
|
|
351
|
+
AND "inventory_id" ISNULL
|
|
352
|
+
AND "status" IN ('PENDING','PENDING_RECEIVE','PENDING_WORKSHEET','READY_TO_PICK'/*, 'PENDING_SPLIT' kiv sebab kalau pending split, ada yang dah assign tapi belum delete*/)
|
|
353
|
+
GROUP BY "product_id", "packing_type"
|
|
354
|
+
)`,
|
|
355
|
+
[domain.id]
|
|
356
|
+
)
|
|
357
|
+
|
|
322
358
|
await tx.query(
|
|
323
359
|
`
|
|
324
360
|
create temp table temp_inv_history AS
|
|
325
361
|
(
|
|
326
362
|
SELECT "Product"."id" AS "id", "Product"."sku" AS "sku", "Product"."brand" AS "brand", "Product"."name" AS "name", "Product"."type" AS "type", "Product"."description" AS "description",
|
|
363
|
+
"Inventory"."packing_type" AS "packingType",
|
|
327
364
|
"Product"."weight" AS "weight", "ProductRef"."id" AS "productRefId",
|
|
328
365
|
"ProductRef"."description" AS "productRefDesciption", "Bizplace"."id" AS "bizplaceId", "Bizplace"."name" AS "bizplaceName", SUM("Inventory"."qty") AS "qty" ,
|
|
329
366
|
CASE WHEN SUM("Inventory"."qty") > 0 THEN SUM(COALESCE("Inventory"."unit_cost", 0) * "Inventory"."qty")/ SUM("Inventory"."qty") ELSE 0 END AS "averageUnitCost",
|
|
330
367
|
COALESCE("ProductDetailBizplaceSetting"."min_qty", "Product"."min_qty",0) AS "minQty",
|
|
331
|
-
COALESCE("ProductDetailBizplaceSetting"."max_qty", "Product"."max_qty",0) AS "maxQty"
|
|
368
|
+
COALESCE("ProductDetailBizplaceSetting"."max_qty", "Product"."max_qty",0) AS "maxQty",
|
|
369
|
+
CASE WHEN "Location"."type" NOT IN ('${LOCATION_TYPE.QUARANTINE}','${LOCATION_TYPE.RESERVE}')
|
|
370
|
+
THEN
|
|
371
|
+
CASE WHEN SUM("Inventory"."qty") > 0
|
|
372
|
+
THEN SUM("Inventory"."qty")-SUM(COALESCE("Inventory"."locked_qty", 0) + COALESCE("OrderInventoriesByProduct"."total_release_qty", 0))
|
|
373
|
+
ELSE 0 END
|
|
374
|
+
ELSE 0 END AS "availableQty",
|
|
375
|
+
SUM(COALESCE("Inventory"."locked_qty", 0) + COALESCE("OrderInventoriesByProduct"."total_release_qty", 0)) AS "releaseQty",
|
|
376
|
+
CASE WHEN "Location"."type" = '${LOCATION_TYPE.QUARANTINE}'
|
|
377
|
+
THEN
|
|
378
|
+
CASE WHEN SUM("Inventory"."qty") > 0
|
|
379
|
+
THEN SUM("Inventory"."qty")-SUM(COALESCE("Inventory"."locked_qty", 0) + COALESCE("OrderInventoriesByProduct"."total_release_qty", 0))
|
|
380
|
+
ELSE 0 END
|
|
381
|
+
ELSE 0 END AS "quarantineQty",
|
|
382
|
+
CASE WHEN "Location"."type" = '${LOCATION_TYPE.RESERVE}'
|
|
383
|
+
THEN
|
|
384
|
+
CASE WHEN SUM("Inventory"."qty") > 0
|
|
385
|
+
THEN SUM("Inventory"."qty")-SUM(COALESCE("Inventory"."locked_qty", 0) + COALESCE("OrderInventoriesByProduct"."total_release_qty", 0))
|
|
386
|
+
ELSE 0 END
|
|
387
|
+
ELSE 0 END AS "reserveQty",
|
|
388
|
+
CASE WHEN "Location"."type" = '${LOCATION_TYPE.BIN}' THEN SUM("Inventory"."qty") ELSE 0 END AS "binQty"
|
|
332
389
|
FROM "inventories" "Inventory"
|
|
333
390
|
LEFT JOIN "products" "Product" ON "Product"."id"="Inventory"."product_id"
|
|
334
391
|
LEFT JOIN "product_details" "ProductDetails" ON "ProductDetails"."product_id" = "Product"."id"
|
|
@@ -337,31 +394,53 @@ export class InventoryQuery {
|
|
|
337
394
|
AND "ProductDetailBizplaceSetting"."domain_id" = "Inventory"."domain_id"
|
|
338
395
|
LEFT JOIN "products" "ProductRef" ON "ProductRef"."id"="Product"."product_ref_id"
|
|
339
396
|
INNER JOIN "bizplaces" "Bizplace" ON "Bizplace"."id"="Inventory"."bizplace_id"
|
|
397
|
+
INNER JOIN "locations" "Location" ON "Location"."id" = "Inventory"."location_id"
|
|
398
|
+
LEFT JOIN "order_inventories_by_products" "OrderInventoriesByProduct"
|
|
399
|
+
ON "OrderInventoriesByProduct"."product_id" = "Inventory"."product_id"
|
|
400
|
+
AND "OrderInventoriesByProduct"."packing_type" = "Inventory"."packing_type"
|
|
340
401
|
WHERE "Inventory"."qty" >= 0
|
|
341
402
|
AND "Inventory"."status" <> 'MISSING'
|
|
342
403
|
AND "Inventory"."domain_id" = $1
|
|
343
404
|
${bizplaceQuery}
|
|
344
405
|
${productQuery}
|
|
345
|
-
GROUP BY "Product"."id", "
|
|
406
|
+
GROUP BY "Product"."id", "Bizplace"."id", "ProductDetailBizplaceSetting"."id", "Inventory"."packing_type", "Location"."type", "ProductRef"."id"
|
|
346
407
|
HAVING 1 = 1
|
|
347
408
|
${availableStockQuery}
|
|
348
|
-
${thresholdQuery}
|
|
349
409
|
)`,
|
|
350
410
|
[domain.id]
|
|
351
411
|
)
|
|
352
412
|
|
|
413
|
+
await tx.query(
|
|
414
|
+
`
|
|
415
|
+
CREATE TEMP TABLE grouped_inventories_product AS (
|
|
416
|
+
SELECT "id", "sku", "brand", "name", "description",
|
|
417
|
+
"packingType", "bizplaceId", "bizplaceName", sum("averageUnitCost") AS "averageUnitCost",
|
|
418
|
+
sum("minQty") AS "minQty", sum("maxQty") AS "maxQty",
|
|
419
|
+
sum("availableQty") AS "availableQty",
|
|
420
|
+
sum("quarantineQty") AS "quarantineQty",
|
|
421
|
+
sum("reserveQty") AS "reserveQty",
|
|
422
|
+
sum("releaseQty") AS "releaseQty",
|
|
423
|
+
sum("availableQty" + "quarantineQty" + "releaseQty" + "reserveQty" - "binQty") AS "warehouseQty"
|
|
424
|
+
FROM temp_inv_history
|
|
425
|
+
GROUP BY "id", "sku", "brand", "name", "description", "packingType", "bizplaceId", "bizplaceName"
|
|
426
|
+
HAVING 1=1
|
|
427
|
+
${qtyStockQuery}
|
|
428
|
+
${thresholdQuery}
|
|
429
|
+
)
|
|
430
|
+
`
|
|
431
|
+
)
|
|
353
432
|
const results: any = await tx.query(
|
|
354
433
|
`
|
|
355
|
-
SELECT * FROM
|
|
356
|
-
ORDER BY "bizplaceName", "sku"
|
|
434
|
+
SELECT * FROM grouped_inventories_product
|
|
435
|
+
ORDER BY "bizplaceName", "sku"
|
|
357
436
|
OFFSET $1 LIMIT $2
|
|
358
437
|
`,
|
|
359
438
|
[(page - 1) * limit, limit]
|
|
360
439
|
)
|
|
361
440
|
|
|
362
|
-
const total: any = await tx.query(`SELECT COUNT(*) FROM
|
|
441
|
+
const total: any = await tx.query(`SELECT COUNT(*) FROM grouped_inventories_product`)
|
|
363
442
|
|
|
364
|
-
tx.query(`drop table temp_inv_history`)
|
|
443
|
+
await tx.query(`drop table temp_inv_history, order_inventories_by_products, grouped_inventories_product`)
|
|
365
444
|
|
|
366
445
|
return {
|
|
367
446
|
items: results.map((item: any) => {
|
|
@@ -372,15 +451,20 @@ export class InventoryQuery {
|
|
|
372
451
|
sku: item.sku,
|
|
373
452
|
brand: item.brand,
|
|
374
453
|
description: item.description,
|
|
375
|
-
type: item.type,
|
|
376
|
-
weight: item.weight,
|
|
377
|
-
productRefId: item.productRefId,
|
|
378
|
-
bizplaceId: item.bizplaceId,
|
|
379
454
|
minQty: item.minQty,
|
|
380
455
|
maxQty: item.maxQty
|
|
381
456
|
},
|
|
457
|
+
bizplace: {
|
|
458
|
+
id: item.bizplaceId,
|
|
459
|
+
name: item.bizplaceName
|
|
460
|
+
},
|
|
461
|
+
packingType: item.packingType,
|
|
382
462
|
averageUnitCost: item.averageUnitCost,
|
|
383
|
-
|
|
463
|
+
availableQty: item.availableQty,
|
|
464
|
+
releaseQty: item.releaseQty,
|
|
465
|
+
quarantineQty: item.quarantineQty,
|
|
466
|
+
reserveQty: item.reserveQty,
|
|
467
|
+
warehouseQty: item.warehouseQty
|
|
384
468
|
}
|
|
385
469
|
}),
|
|
386
470
|
total: total[0].count
|
|
@@ -393,7 +477,7 @@ export class InventoryQuery {
|
|
|
393
477
|
@Directive('@transaction')
|
|
394
478
|
@Query(returns => InventoryList)
|
|
395
479
|
async inventoriesByStrategy(
|
|
396
|
-
@Ctx() context:
|
|
480
|
+
@Ctx() context: ResolverContext,
|
|
397
481
|
@Arg('worksheetId') worksheetId: string,
|
|
398
482
|
@Arg('batchId') batchId: string,
|
|
399
483
|
@Arg('productName') productName: string,
|
|
@@ -405,10 +489,10 @@ export class InventoryQuery {
|
|
|
405
489
|
@Arg('locationSortingRules', type => [Sorting], { nullable: true }) locationSortingRules?: Sorting[],
|
|
406
490
|
@Arg('bizplaceId', { nullable: true }) bizplaceId?: string
|
|
407
491
|
): Promise<InventoryList> {
|
|
408
|
-
const { domain, tx }
|
|
492
|
+
const { domain, tx } = context.state
|
|
409
493
|
|
|
410
494
|
const inventoryAssignmentSetting: Setting = await tx.getRepository(Setting).findOne({
|
|
411
|
-
where: { domain, name: 'rule-for-inventory-assignment' }
|
|
495
|
+
where: { domain: { id: domain.id }, name: 'rule-for-inventory-assignment' }
|
|
412
496
|
})
|
|
413
497
|
|
|
414
498
|
if (!locationSortingRules && inventoryAssignmentSetting) {
|
|
@@ -441,17 +525,17 @@ export class InventoryQuery {
|
|
|
441
525
|
async checkProductIdenticality(
|
|
442
526
|
@Arg('palletA') palletA: string,
|
|
443
527
|
@Arg('palletB') palletB: string,
|
|
444
|
-
@Ctx() context:
|
|
528
|
+
@Ctx() context: ResolverContext
|
|
445
529
|
): Promise<Boolean> {
|
|
446
|
-
const { tx }
|
|
530
|
+
const { tx } = context.state
|
|
447
531
|
const invRepo: Repository<Inventory> = tx.getRepository(Inventory)
|
|
448
532
|
const invA: Inventory = await invRepo.findOne({
|
|
449
|
-
where: { domain: context.state.domain, palletId: palletA, status: INVENTORY_STATUS.STORED },
|
|
533
|
+
where: { domain: { id: context.state.domain.id }, palletId: palletA, status: INVENTORY_STATUS.STORED },
|
|
450
534
|
relations: ['product']
|
|
451
535
|
})
|
|
452
536
|
|
|
453
537
|
const invB: Inventory = await invRepo.findOne({
|
|
454
|
-
where: { domain: context.state.domain, palletId: palletB, status: INVENTORY_STATUS.STORED },
|
|
538
|
+
where: { domain: { id: context.state.domain.id }, palletId: palletB, status: INVENTORY_STATUS.STORED },
|
|
455
539
|
relations: ['product']
|
|
456
540
|
})
|
|
457
541
|
|
|
@@ -467,11 +551,16 @@ export class InventoryQuery {
|
|
|
467
551
|
@Arg('cartonA') cartonA: string,
|
|
468
552
|
@Arg('palletA') palletA: string,
|
|
469
553
|
@Arg('cartonB') cartonB: string,
|
|
470
|
-
@Ctx() context:
|
|
554
|
+
@Ctx() context: ResolverContext
|
|
471
555
|
) {
|
|
472
556
|
const invRepo: Repository<Inventory> = getRepository(Inventory)
|
|
473
557
|
const invA: Inventory = await invRepo.findOne({
|
|
474
|
-
where: {
|
|
558
|
+
where: {
|
|
559
|
+
domain: { id: context.state.domain.id },
|
|
560
|
+
palletId: palletA,
|
|
561
|
+
cartonId: cartonA,
|
|
562
|
+
status: INVENTORY_STATUS.STORED
|
|
563
|
+
},
|
|
475
564
|
relations: ['product']
|
|
476
565
|
})
|
|
477
566
|
|
|
@@ -499,13 +588,13 @@ export class InventoryQuery {
|
|
|
499
588
|
async checkInventoryOwner(
|
|
500
589
|
@Arg('palletId') palletId: string,
|
|
501
590
|
@Arg('bizplaceName') bizplaceName: string,
|
|
502
|
-
@Ctx() context:
|
|
591
|
+
@Ctx() context: ResolverContext
|
|
503
592
|
): Promise<Boolean> {
|
|
504
593
|
const invRepo: Repository<Inventory> = getRepository(Inventory)
|
|
505
594
|
const bizRepo: Repository<Bizplace> = getRepository(Bizplace)
|
|
506
595
|
|
|
507
596
|
const inventory: Inventory = await invRepo.findOne({
|
|
508
|
-
where: { domain: context.state.domain, palletId, status: INVENTORY_STATUS.STORED },
|
|
597
|
+
where: { domain: { id: context.state.domain.id }, palletId, status: INVENTORY_STATUS.STORED },
|
|
509
598
|
relations: ['bizplace']
|
|
510
599
|
})
|
|
511
600
|
|
|
@@ -523,12 +612,12 @@ export class InventoryQuery {
|
|
|
523
612
|
@Directive('@privilege(category: "inventory", privilege: "query")')
|
|
524
613
|
@Query(returns => InventoryBundleGroupDetail)
|
|
525
614
|
async inventoriesByBundle(
|
|
526
|
-
@Ctx() context:
|
|
615
|
+
@Ctx() context: ResolverContext,
|
|
527
616
|
@Arg('filters', type => [Filter], { nullable: true }) filters?: Filter[],
|
|
528
617
|
@Arg('pagination', type => Pagination, { nullable: true }) pagination?: Pagination,
|
|
529
618
|
@Arg('sortings', type => [Sorting], { nullable: true }) sortings?: Sorting[]
|
|
530
619
|
): Promise<InventoryBundleGroupDetail> {
|
|
531
|
-
const { domain, user }
|
|
620
|
+
const { domain, user } = context.state
|
|
532
621
|
|
|
533
622
|
const params = { filters, pagination }
|
|
534
623
|
|
|
@@ -551,7 +640,7 @@ export class InventoryQuery {
|
|
|
551
640
|
})
|
|
552
641
|
}
|
|
553
642
|
|
|
554
|
-
const remainOnlyParam
|
|
643
|
+
const remainOnlyParam = params?.filters?.find(
|
|
555
644
|
(f: { name: string; operator: string; value: any }) => f.name === 'remainOnly'
|
|
556
645
|
)
|
|
557
646
|
|
|
@@ -563,7 +652,7 @@ export class InventoryQuery {
|
|
|
563
652
|
)
|
|
564
653
|
}
|
|
565
654
|
|
|
566
|
-
const unlockOnlyParam
|
|
655
|
+
const unlockOnlyParam = params?.filters?.find(
|
|
567
656
|
(f: { name: string; operator: string; value: any }) => f.name === 'unlockOnly'
|
|
568
657
|
)
|
|
569
658
|
|
|
@@ -687,151 +776,12 @@ export class InventoryQuery {
|
|
|
687
776
|
return { bundleGroup, bundleSetting }
|
|
688
777
|
}
|
|
689
778
|
|
|
690
|
-
@Directive('@privilege(category: "inventory", privilege: "query")')
|
|
691
|
-
@Query(returns => InventoryList)
|
|
692
|
-
async inventoriesForExport(
|
|
693
|
-
@Ctx() context: any,
|
|
694
|
-
@Arg('filters', type => [Filter], { nullable: true }) filters?: Filter[],
|
|
695
|
-
@Arg('pagination', type => Pagination, { nullable: true }) pagination?: Pagination,
|
|
696
|
-
@Arg('sortings', type => [Sorting], { nullable: true }) sortings?: Sorting[],
|
|
697
|
-
@Arg('locationSortingRules', type => [Sorting], { nullable: true }) locationSortingRules?: Sorting[]
|
|
698
|
-
): Promise<InventoryList> {
|
|
699
|
-
const { domain, user } = context.state
|
|
700
|
-
const { page, limit } = pagination
|
|
701
|
-
|
|
702
|
-
try {
|
|
703
|
-
const productFilters = filters.find(x => x.name == 'product_info')
|
|
704
|
-
filters = filters.filter(x => x.name != 'product_info')
|
|
705
|
-
const params = { filters, pagination }
|
|
706
|
-
|
|
707
|
-
if (!params.filters.find((filter: any) => filter.name === 'bizplace')) {
|
|
708
|
-
throw new Error('Please select a customer for export.')
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
const remainOnlyParam: { name: string; operator: string; value: boolean } = params?.filters?.find(
|
|
712
|
-
(f: { name: string; operator: string; value: any }) => f.name === 'remainOnly'
|
|
713
|
-
)
|
|
714
|
-
|
|
715
|
-
let remainOnly: boolean = false
|
|
716
|
-
if (typeof remainOnlyParam?.value !== 'undefined') {
|
|
717
|
-
remainOnly = remainOnlyParam.value
|
|
718
|
-
params.filters = params.filters.filter(
|
|
719
|
-
(f: { name: string; operator: string; value: any }) => f.name !== 'remainOnly'
|
|
720
|
-
)
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
const unlockOnlyParam: { name: string; operator: string; value: boolean } = params?.filters?.find(
|
|
724
|
-
(f: { name: string; operator: string; value: any }) => f.name === 'unlockOnly'
|
|
725
|
-
)
|
|
726
|
-
|
|
727
|
-
let unlockOnly: boolean = false
|
|
728
|
-
if (typeof unlockOnlyParam?.value !== 'undefined') {
|
|
729
|
-
unlockOnly = unlockOnlyParam.value
|
|
730
|
-
params.filters = params.filters.filter(
|
|
731
|
-
(f: { name: string; operator: string; value: any }) => f.name !== 'unlockOnly'
|
|
732
|
-
)
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
const qb: SelectQueryBuilder<Inventory> = getRepository(Inventory).createQueryBuilder('Inventory')
|
|
736
|
-
buildQuery(qb, params, context)
|
|
737
|
-
|
|
738
|
-
qb.leftJoinAndSelect('Inventory.bizplace', 'Bizplace')
|
|
739
|
-
.leftJoinAndSelect('Inventory.product', 'Product')
|
|
740
|
-
.leftJoinAndSelect('Inventory.warehouse', 'Warehouse')
|
|
741
|
-
.leftJoinAndSelect('Inventory.location', 'Location')
|
|
742
|
-
.leftJoinAndSelect('Inventory.creator', 'Creator')
|
|
743
|
-
.leftJoinAndSelect('Inventory.updater', 'Updater')
|
|
744
|
-
.leftJoinAndSelect(
|
|
745
|
-
subQuery => {
|
|
746
|
-
return subQuery
|
|
747
|
-
.select('ii.inventory_id', 'inventory_id')
|
|
748
|
-
.addSelect(`string_agg(ii.serial_number, ', ')`, 'serial_numbers')
|
|
749
|
-
.from('inventory_items', 'ii')
|
|
750
|
-
.where(`ii.domain_id = :domainId`, { domainId: domain.id })
|
|
751
|
-
.groupBy('ii.inventory_id')
|
|
752
|
-
},
|
|
753
|
-
'ii2',
|
|
754
|
-
'ii2.inventory_id = Inventory.id'
|
|
755
|
-
)
|
|
756
|
-
|
|
757
|
-
if (remainOnly) {
|
|
758
|
-
qb.andWhere('Inventory.qty > 0')
|
|
759
|
-
.andWhere('CASE WHEN Inventory.locked_qty IS NULL THEN 0 ELSE Inventory.locked_qty END >= 0')
|
|
760
|
-
.andWhere('Inventory.qty - CASE WHEN Inventory.locked_qty IS NULL THEN 0 ELSE Inventory.locked_qty END > 0')
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
if (unlockOnly) {
|
|
764
|
-
qb.andWhere('CASE WHEN Inventory.locked_qty IS NULL THEN 0 ELSE Inventory.locked_qty END = 0')
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
if (productFilters) {
|
|
768
|
-
let productFilterValue = `%${productFilters.value.toLowerCase()}%`
|
|
769
|
-
qb.andWhere(qb => {
|
|
770
|
-
const subQuery = qb
|
|
771
|
-
.subQuery()
|
|
772
|
-
.select()
|
|
773
|
-
.from(Product, `products`)
|
|
774
|
-
.where(`products.id = Inventory.product_id`)
|
|
775
|
-
.andWhere(
|
|
776
|
-
new Brackets(qb => {
|
|
777
|
-
qb.where('Lower(products.sku) LIKE :productInfo', { productInfo: productFilterValue })
|
|
778
|
-
.orWhere('Lower(products.name) LIKE :productInfo', { productInfo: productFilterValue })
|
|
779
|
-
.orWhere('Lower(products.description) LIKE :productInfo', { productInfo: productFilterValue })
|
|
780
|
-
.orWhere('Lower(products.brand) LIKE :productInfo', { productInfo: productFilterValue })
|
|
781
|
-
})
|
|
782
|
-
)
|
|
783
|
-
.getQuery()
|
|
784
|
-
return `EXISTS ${subQuery}`
|
|
785
|
-
})
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
if (sortings?.length !== 0) {
|
|
789
|
-
const arrChildSortData = ['bizplace', 'product', 'location', 'warehouse', 'zone']
|
|
790
|
-
const sort = (sortings || []).reduce(
|
|
791
|
-
(acc, sort) => ({
|
|
792
|
-
...acc,
|
|
793
|
-
[arrChildSortData.indexOf(sort.name) >= 0 ? sort.name + '.name' : 'Inventory.' + sort.name]: sort.desc
|
|
794
|
-
? 'DESC'
|
|
795
|
-
: 'ASC'
|
|
796
|
-
}),
|
|
797
|
-
{}
|
|
798
|
-
)
|
|
799
|
-
qb.orderBy(sort)
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
if (locationSortingRules?.length > 0) {
|
|
803
|
-
locationSortingRules.forEach((rule: { name: string; desc: boolean }) => {
|
|
804
|
-
qb.addOrderBy(`location.${rule.name}`, rule.desc ? 'DESC' : 'ASC')
|
|
805
|
-
})
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
let items = await qb
|
|
809
|
-
.offset((page - 1) * limit)
|
|
810
|
-
.limit(limit)
|
|
811
|
-
.getRawMany()
|
|
812
|
-
|
|
813
|
-
let total = await qb.getCount()
|
|
814
|
-
|
|
815
|
-
return {
|
|
816
|
-
items: items.map(item => {
|
|
817
|
-
return {
|
|
818
|
-
...new Inventory(item),
|
|
819
|
-
serialNumbers: item.serial_numbers
|
|
820
|
-
}
|
|
821
|
-
}),
|
|
822
|
-
total
|
|
823
|
-
}
|
|
824
|
-
} catch (error) {
|
|
825
|
-
throw error
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
|
|
829
779
|
@Directive('@privilege(category: "inventory", privilege: "query")')
|
|
830
780
|
@Directive('@transaction')
|
|
831
781
|
@Query(returns => InventoryList)
|
|
832
|
-
async inventoriesGroupByProduct(@Args() params: ListParam, @Ctx() context:
|
|
782
|
+
async inventoriesGroupByProduct(@Args() params: ListParam, @Ctx() context: ResolverContext): Promise<InventoryList> {
|
|
833
783
|
try {
|
|
834
|
-
const { domain, user, tx }
|
|
784
|
+
const { domain, user, tx } = context.state
|
|
835
785
|
let permittedBizplaceIds: string[] = await getPermittedBizplaceIds(domain, user)
|
|
836
786
|
const partnersCompanyBizplaces: Bizplace[] = await getPartnersCompanyBizplaces(domain, user)
|
|
837
787
|
|
|
@@ -1002,17 +952,17 @@ export class InventoryQuery {
|
|
|
1002
952
|
|
|
1003
953
|
@FieldResolver(type => Domain)
|
|
1004
954
|
async domain(@Root() inventory: Inventory): Promise<Domain> {
|
|
1005
|
-
return await getRepository(Domain).
|
|
955
|
+
return await getRepository(Domain).findOneBy({ id: inventory.domainId })
|
|
1006
956
|
}
|
|
1007
957
|
|
|
1008
958
|
@FieldResolver(type => User)
|
|
1009
959
|
async updater(@Root() inventory: Inventory): Promise<User> {
|
|
1010
|
-
return await getRepository(User).
|
|
960
|
+
return await getRepository(User).findOneBy({ id: inventory.updaterId })
|
|
1011
961
|
}
|
|
1012
962
|
|
|
1013
963
|
@FieldResolver(type => User)
|
|
1014
964
|
async creator(@Root() inventory: Inventory): Promise<User> {
|
|
1015
|
-
return await getRepository(User).
|
|
965
|
+
return await getRepository(User).findOneBy({ id: inventory.creatorId })
|
|
1016
966
|
}
|
|
1017
967
|
|
|
1018
968
|
/*
|
|
@@ -1022,7 +972,7 @@ export class InventoryQuery {
|
|
|
1022
972
|
@FieldResolver(type => Number)
|
|
1023
973
|
async changeCount(@Root() inventory: Inventory): Promise<Number> {
|
|
1024
974
|
return await getRepository(InventoryChange).count({
|
|
1025
|
-
where: { inventory }
|
|
975
|
+
where: { inventory: { id: inventory.id } }
|
|
1026
976
|
})
|
|
1027
977
|
}
|
|
1028
978
|
|
|
@@ -1071,6 +1021,19 @@ export class InventoryQuery {
|
|
|
1071
1021
|
|
|
1072
1022
|
return items[0]?.arrivalNoticeRefNo || ''
|
|
1073
1023
|
}
|
|
1024
|
+
|
|
1025
|
+
@FieldResolver(type => String)
|
|
1026
|
+
async arrivalNoticeNo(@Root() inventory: Inventory): Promise<String> {
|
|
1027
|
+
if (!inventory.refOrderId) return ''
|
|
1028
|
+
|
|
1029
|
+
let items: any = await getRepository(Inventory).query(`
|
|
1030
|
+
SELECT an.name as "arrivalNoticeNo" FROM arrival_notices an
|
|
1031
|
+
WHERE an.id = '${inventory.refOrderId}'
|
|
1032
|
+
LIMIT 1
|
|
1033
|
+
`)
|
|
1034
|
+
|
|
1035
|
+
return items[0]?.arrivalNoticeNo || ''
|
|
1036
|
+
}
|
|
1074
1037
|
}
|
|
1075
1038
|
|
|
1076
1039
|
export async function inventoriesByStrategy(
|
|
@@ -1153,6 +1116,7 @@ export async function inventoriesByStrategy(
|
|
|
1153
1116
|
|
|
1154
1117
|
case 'FEFO':
|
|
1155
1118
|
qb.orderBy('"INV"."expiration_date"', 'ASC')
|
|
1119
|
+
qb.addOrderBy('"INV"."created_at"', 'ASC')
|
|
1156
1120
|
if (locationSortingRules?.length > 0) {
|
|
1157
1121
|
locationSortingRules.forEach((rule: { name: string; desc: boolean }, idx: number) => {
|
|
1158
1122
|
qb.addOrderBy(`LOC.${rule.name}`, rule.desc ? 'DESC' : 'ASC')
|
|
@@ -1162,6 +1126,7 @@ export async function inventoriesByStrategy(
|
|
|
1162
1126
|
|
|
1163
1127
|
case 'FMFO':
|
|
1164
1128
|
qb.orderBy('"INV"."manufacture_date"', 'ASC')
|
|
1129
|
+
qb.addOrderBy('"INV"."created_at"', 'ASC')
|
|
1165
1130
|
if (locationSortingRules?.length > 0) {
|
|
1166
1131
|
locationSortingRules.forEach((rule: { name: string; desc: boolean }, idx: number) => {
|
|
1167
1132
|
qb.addOrderBy(`LOC.${rule.name}`, rule.desc ? 'DESC' : 'ASC')
|