@things-factory/warehouse-base 4.2.12 → 4.3.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.
Files changed (41) 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/tote.js +9 -0
  4. package/dist-server/constants/tote.js.map +1 -0
  5. package/dist-server/index.js +3 -1
  6. package/dist-server/index.js.map +1 -1
  7. package/dist-server/service/index.js +7 -2
  8. package/dist-server/service/index.js.map +1 -1
  9. package/dist-server/service/inventory/inventory-query.js +2 -1
  10. package/dist-server/service/inventory/inventory-query.js.map +1 -1
  11. package/dist-server/service/inventory-change/inventory-change-mutation.js +334 -273
  12. package/dist-server/service/inventory-change/inventory-change-mutation.js.map +1 -1
  13. package/dist-server/service/inventory-history/inventory-history-query.js +23 -2
  14. package/dist-server/service/inventory-history/inventory-history-query.js.map +1 -1
  15. package/dist-server/service/tote/index.js +9 -0
  16. package/dist-server/service/tote/index.js.map +1 -0
  17. package/dist-server/service/tote/tote-mutation.js +192 -0
  18. package/dist-server/service/tote/tote-mutation.js.map +1 -0
  19. package/dist-server/service/tote/tote-query.js +146 -0
  20. package/dist-server/service/tote/tote-query.js.map +1 -0
  21. package/dist-server/service/tote/tote-types.js +75 -0
  22. package/dist-server/service/tote/tote-types.js.map +1 -0
  23. package/dist-server/service/tote/tote.js +98 -0
  24. package/dist-server/service/tote/tote.js.map +1 -0
  25. package/dist-server/utils/inventory-util.js +5 -3
  26. package/dist-server/utils/inventory-util.js.map +1 -1
  27. package/package.json +8 -8
  28. package/server/constants/index.ts +1 -0
  29. package/server/constants/tote.ts +5 -0
  30. package/server/index.ts +2 -0
  31. package/server/service/index.ts +7 -2
  32. package/server/service/inventory/inventory-query.ts +2 -1
  33. package/server/service/inventory-change/index.ts +1 -1
  34. package/server/service/inventory-change/inventory-change-mutation.ts +471 -407
  35. package/server/service/inventory-history/inventory-history-query.ts +23 -2
  36. package/server/service/tote/index.ts +6 -0
  37. package/server/service/tote/tote-mutation.ts +200 -0
  38. package/server/service/tote/tote-query.ts +102 -0
  39. package/server/service/tote/tote-types.ts +44 -0
  40. package/server/service/tote/tote.ts +77 -0
  41. package/server/utils/inventory-util.ts +5 -3
@@ -262,7 +262,7 @@ export class InventoryHistoryQuery {
262
262
  (
263
263
  SELECT prd.name AS product_name, prd.description AS product_description, prd.type as product_type, prd.aux_value_1 AS product_aux_value_1, trim(invh.batch_id) as batch_id, invh.product_id,
264
264
  invh.packing_type, invh.bizplace_id, invh.domain_id,
265
- invh.ref_order_id, invh.order_no, invh.order_ref_no, invh.transaction_type, invh.created_at,
265
+ invh.ref_order_id, invh.order_no, invh.order_ref_no, invh.transaction_type, invh.status, invh.created_at,
266
266
  invh.qty, invh.opening_qty,
267
267
  invh.uom, COALESCE(invh.uom_value, 0) as uom_value, COALESCE(invh.opening_uom_value, 0) as opening_uom_value
268
268
  FROM reduced_inventory_histories invh
@@ -335,6 +335,27 @@ export class InventoryHistoryQuery {
335
335
  ) AS inv_movement
336
336
  GROUP BY product_name, product_description, product_type, product_aux_value_1, batch_id, product_id, packing_type, uom, bizplace_id,
337
337
  domain_id, order_name, ref_no, rn, created_at
338
+ UNION ALL
339
+ SELECT product_name, product_description, product_type, product_aux_value_1, batch_id, product_id, packing_type, uom, bizplace_id,
340
+ domain_id, sum(-opening_qty) as qty, sum(opening_qty) as opening_qty, sum(-opening_uom_value) as uom_value, sum(opening_uom_value) as opening_uom_value,
341
+ order_name, ref_no, 1 AS rn, created_at - $2::interval as created_at, created_at::date as created_date
342
+ FROM (
343
+ SELECT invh.product_name, invh.product_description, invh.product_type, invh.product_aux_value_1, invh.batch_id, invh.product_id, invh.packing_type, invh.uom, invh.bizplace_id,
344
+ invh.domain_id,
345
+ invh.qty, invh.opening_qty, invh.uom_value, invh.opening_uom_value,
346
+ invh.transaction_type AS order_name,
347
+ invh.transaction_type AS ref_no,
348
+ invh.created_at,
349
+ invh.created_at:: date as created_date
350
+ FROM temp_data_src invh
351
+ WHERE
352
+ invh.transaction_type = 'ADJUSTMENT' AND
353
+ invh.status = 'MISSING'
354
+ AND invh.created_at >= $1::timestamp
355
+ ) AS inv_movement
356
+ GROUP BY product_name, product_description, product_type, product_aux_value_1, batch_id, product_id, packing_type, uom, bizplace_id,
357
+ domain_id, order_name, ref_no, rn, created_at
358
+
338
359
  )`,
339
360
  [fromDate.value, tzoffset]
340
361
  )
@@ -1108,7 +1129,7 @@ export class InventoryHistoryQuery {
1108
1129
  group by ih.domain_id, ih.pallet_id
1109
1130
  ) dt
1110
1131
  inner join tmp_src rih on dt.domain_id = rih.domain_id and dt.pallet_id = rih.pallet_id and dt.last_seq = rih.seq and rih.status <> 'TERMINATED'
1111
- inner join inventories iv on iv.domain_id = dt.domain_id and iv.pallet_id = dt.pallet_id
1132
+ inner join inventories iv on iv.domain_id = dt.domain_id and iv.pallet_id = dt.pallet_id and iv.status <> 'MISSING'
1112
1133
  where exists (
1113
1134
  SELECT * FROM tmp_bizfilter bizFilter
1114
1135
  WHERE bizFilter.bizplace_id = "rih"."bizplace_id"
@@ -0,0 +1,6 @@
1
+ import { Tote } from './tote'
2
+ import { ToteMutation } from './tote-mutation'
3
+ import { ToteQuery } from './tote-query'
4
+
5
+ export const entities = [Tote]
6
+ export const resolvers = [ToteQuery, ToteMutation]
@@ -0,0 +1,200 @@
1
+ import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
2
+ import { EntityManager, In } from 'typeorm'
3
+
4
+ import { User } from '@things-factory/auth-base'
5
+ import { Bizplace } from '@things-factory/biz-base'
6
+ import { Domain } from '@things-factory/shell'
7
+
8
+ import { PalletHistory } from '../pallet-history/pallet-history'
9
+ import { Tote } from './tote'
10
+ import { NewTote, TotePatch } from './tote-types'
11
+
12
+ @Resolver(Tote)
13
+ export class ToteMutation {
14
+ @Directive('@transaction')
15
+ @Mutation(returns => Tote)
16
+ async createTote(@Arg('pallet') tote: NewTote, @Ctx() context: any): Promise<Tote> {
17
+ const { domain, user, tx }: { domain: Domain; user: User; tx: EntityManager } = context.state
18
+
19
+ const existingTote: string[] = (await tx.getRepository(Tote).find({ relations: ['user'] })).map(tote => tote.name)
20
+ if (existingTote.includes(tote.name)) throw new Error('tote box already exists')
21
+
22
+ return await tx.getRepository(Tote).save({
23
+ ...tote,
24
+ domain: domain,
25
+ creator: user,
26
+ updater: user
27
+ })
28
+ }
29
+
30
+ @Directive('@transaction')
31
+ @Mutation(returns => Tote)
32
+ async updateTote(@Arg('name') name: string, @Arg('patch') patch: TotePatch, @Ctx() context: any): Promise<Tote> {
33
+ const { domain, user, tx }: { domain: Domain; user: User; tx: EntityManager } = context.state
34
+
35
+ const repository = tx.getRepository(Tote)
36
+ const tote = await repository.findOne({
37
+ where: { domain: domain, name }
38
+ })
39
+
40
+ return await repository.save({
41
+ ...tote,
42
+ ...patch,
43
+ updater: user
44
+ })
45
+ }
46
+
47
+ @Directive('@transaction')
48
+ @Mutation(returns => [Tote])
49
+ async updateMultipleTote(
50
+ @Arg('patches', type => [TotePatch]) patches: TotePatch[],
51
+ @Ctx() context: any
52
+ ): Promise<Tote[]> {
53
+ const { domain, user, tx }: { domain: Domain; user: User; tx: EntityManager } = context.state
54
+
55
+ let results = []
56
+ const _createRecords = patches.filter((patch: any) => patch.cuFlag === '+')
57
+ const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')
58
+
59
+ if (_createRecords.length > 0) {
60
+ for (let i = 0; i < _createRecords.length; i++) {
61
+ const newRecord = _createRecords[i]
62
+
63
+ if (newRecord.bizplace && newRecord.bizplace.id) {
64
+ newRecord.bizplace = await tx.getRepository(Bizplace).findOne(newRecord.bizplace.id)
65
+ }
66
+
67
+ let foundTote = await tx
68
+ .getRepository(Tote)
69
+ .findOne({ where: { domain, name: newRecord.name, bizplace: newRecord.bizplace } })
70
+
71
+ if (foundTote) {
72
+ throw new Error('Duplicated tote found')
73
+ }
74
+
75
+ const result: Tote = await tx.getRepository(Tote).save({
76
+ domain: domain,
77
+ creator: user,
78
+ updater: user,
79
+ ...newRecord
80
+ })
81
+
82
+ results.push({ ...result, cuFlag: '+' })
83
+ }
84
+ }
85
+
86
+ if (_updateRecords.length > 0) {
87
+ for (let i = 0; i < _updateRecords.length; i++) {
88
+ const newRecord = _updateRecords[i]
89
+ const tote = await tx.getRepository(Tote).findOne({
90
+ where: { id: newRecord.id },
91
+ relations: ['bizplace']
92
+ })
93
+
94
+ if (newRecord.bizplace && newRecord.bizplace.id) {
95
+ newRecord.bizplace = await tx.getRepository(Bizplace).findOne(newRecord.bizplace.id)
96
+ }
97
+
98
+ let foundTote = await tx
99
+ .getRepository(Tote)
100
+ .findOne({ where: { domain, name: newRecord.name, bizplace: newRecord.bizplace } })
101
+
102
+ if (foundTote) {
103
+ throw new Error('Duplicated tote found')
104
+ }
105
+
106
+ const result = await tx.getRepository(Tote).save({
107
+ ...tote,
108
+ ...newRecord,
109
+ updater: user
110
+ })
111
+
112
+ results.push({ ...result, cuFlag: 'M' })
113
+ }
114
+ }
115
+
116
+ return results
117
+ }
118
+
119
+ @Directive('@transaction')
120
+ @Mutation(returns => Boolean)
121
+ async deleteTote(@Arg('name') id: string, @Ctx() context: any): Promise<Boolean> {
122
+ const { domain, user, tx }: { domain: Domain; user: User; tx: EntityManager } = context.state
123
+
124
+ const foundTote = await tx.getRepository(Tote).find({ where: { id } })
125
+
126
+ await tx.getRepository(Tote).save({
127
+ ...foundTote,
128
+ deletedAt: new Date(),
129
+ updater: user
130
+ })
131
+ return true
132
+ }
133
+
134
+ @Directive('@transaction')
135
+ @Mutation(returns => Boolean)
136
+ async deleteTotes(@Arg('ids', type => [String]) ids: string[], @Ctx() context: any): Promise<Boolean> {
137
+ const { domain, user, tx }: { domain: Domain; user: User; tx: EntityManager } = context.state
138
+
139
+ const totes = await tx.getRepository(Tote).find({
140
+ where: {
141
+ domain: domain,
142
+ id: In(ids)
143
+ },
144
+ relations: ['bizplace']
145
+ })
146
+
147
+ await Promise.all(
148
+ totes.map(async (tote: Tote) => {
149
+ await tx.getRepository(Tote).save({
150
+ ...tote,
151
+ deletedAt: new Date(),
152
+ updater: user
153
+ })
154
+ })
155
+ )
156
+ return true
157
+ }
158
+
159
+ @Directive('@transaction')
160
+ @Mutation(returns => Boolean)
161
+ async undeleteTotes(@Arg('ids', type => [String]) ids: string[], @Ctx() context: any): Promise<Boolean> {
162
+ const { tx, user }: { tx: EntityManager; user: User } = context.state
163
+ const toteRepo = tx.getRepository(Tote)
164
+
165
+ await toteRepo.update(
166
+ {
167
+ id: In(ids)
168
+ },
169
+ {
170
+ deletedAt: null,
171
+ updater: user
172
+ }
173
+ )
174
+
175
+ return true
176
+ }
177
+
178
+ @Directive('@transaction')
179
+ @Mutation(returns => Boolean)
180
+ async bulkUpdateToteStatus(
181
+ @Arg('ids', type => [String]) ids: string[],
182
+ @Arg('status', type => String) status: string,
183
+ @Ctx() context: any
184
+ ): Promise<Boolean> {
185
+ const { tx, user }: { tx: EntityManager; user: User } = context.state
186
+ const toteRepo = tx.getRepository(Tote)
187
+
188
+ await toteRepo.update(
189
+ {
190
+ id: In(ids)
191
+ },
192
+ {
193
+ status,
194
+ updater: user
195
+ }
196
+ )
197
+
198
+ return true
199
+ }
200
+ }
@@ -0,0 +1,102 @@
1
+ import { Arg, Ctx, FieldResolver, Query, Resolver, Root } from 'type-graphql'
2
+ import { getRepository, IsNull } from 'typeorm'
3
+
4
+ import { User } from '@things-factory/auth-base'
5
+ import { Bizplace } from '@things-factory/biz-base'
6
+ import { buildQuery, Domain, Filter, Pagination, Sorting } from '@things-factory/shell'
7
+
8
+ import { Tote } from './tote'
9
+ import { ToteList } from './tote-types'
10
+
11
+ @Resolver(Tote)
12
+ export class ToteQuery {
13
+ @Query(returns => ToteList)
14
+ async totes(
15
+ @Ctx() context: any,
16
+ @Arg('filters', type => [Filter], { nullable: true }) filters?: Filter[],
17
+ @Arg('pagination', type => Pagination, { nullable: true }) pagination?: Pagination,
18
+ @Arg('sortings', type => [Sorting], { nullable: true }) sortings?: Sorting[]
19
+ ): Promise<ToteList> {
20
+ const { domain }: { domain: Domain } = context.state
21
+
22
+ const deletedFilter: any = filters.find((filter: any) => filter.name === 'deleted' && filter.value === true)
23
+
24
+ const queryBuilder = getRepository(Tote).createQueryBuilder()
25
+ buildQuery(queryBuilder, { filters, pagination, sortings }, context)
26
+
27
+ queryBuilder
28
+ .leftJoinAndSelect('Tote.domain', 'Domain')
29
+ .leftJoinAndSelect('Tote.bizplace', 'Bizplace')
30
+ .leftJoinAndSelect('Tote.creator', 'Creator')
31
+ .leftJoinAndSelect('Tote.updater', 'Updater')
32
+ .where('Domain.id = :domainId', { domainId: domain.id })
33
+
34
+ if (deletedFilter) {
35
+ queryBuilder.andWhere('Tote.deletedAt IS NOT NULL')
36
+ } else {
37
+ queryBuilder.andWhere('Tote.deletedAt IS NULL')
38
+ }
39
+
40
+ const [items, total] = await queryBuilder.getManyAndCount()
41
+
42
+ return { items, total }
43
+ }
44
+
45
+ @Query(returns => Tote)
46
+ async tote(@Arg('name') name: string, @Arg('bizplace') bizplace: string, @Ctx() context: any): Promise<Tote> {
47
+ const { domain }: { domain: Domain } = context.state
48
+ let foundBizplace = await getRepository(Bizplace).findOne({ where: { name: bizplace } })
49
+
50
+ let foundTote = await getRepository(Tote).findOne({
51
+ where: { domain, bizplace: foundBizplace, name, deletedAt: IsNull() },
52
+ relations: ['domain', 'bizplace', 'creator', 'updater']
53
+ })
54
+
55
+ if (!foundTote) {
56
+ throw new Error('Tote not found')
57
+ } else {
58
+ return foundTote
59
+ }
60
+ }
61
+
62
+ @Query(returns => String)
63
+ async checkToteStatus(
64
+ @Arg('name') name: string,
65
+ @Arg('bizplace') bizplace: string,
66
+ @Ctx() context: any
67
+ ): Promise<String> {
68
+ const { domain }: { domain: Domain } = context.state
69
+ let foundBizplace = await getRepository(Bizplace).findOne({ where: { name: bizplace } })
70
+
71
+ let foundTote = await getRepository(Tote).findOne({
72
+ where: { domain, bizplace: foundBizplace, name, deletedAt: IsNull() },
73
+ relations: ['domain', 'bizplace', 'creator', 'updater']
74
+ })
75
+
76
+ if (!foundTote) {
77
+ return ''
78
+ } else {
79
+ return foundTote.status
80
+ }
81
+ }
82
+
83
+ @FieldResolver()
84
+ async domain(@Root() tote: Tote) {
85
+ return await getRepository(Domain).findOne(tote.domainId)
86
+ }
87
+
88
+ @FieldResolver()
89
+ async bizplace(@Root() tote: Tote) {
90
+ return await getRepository(Bizplace).findOne(tote.bizplaceId)
91
+ }
92
+
93
+ @FieldResolver()
94
+ async updater(@Root() tote: Tote) {
95
+ return await getRepository(User).findOne(tote.updaterId)
96
+ }
97
+
98
+ @FieldResolver()
99
+ async creator(@Root() tote: Tote) {
100
+ return await getRepository(User).findOne(tote.creatorId)
101
+ }
102
+ }
@@ -0,0 +1,44 @@
1
+ import { Field, InputType, Int, ObjectType } from 'type-graphql'
2
+
3
+ import { ObjectRef } from '@things-factory/shell'
4
+
5
+ import { Tote } from './tote'
6
+
7
+ @InputType()
8
+ export class NewTote {
9
+ @Field()
10
+ name: string
11
+
12
+ @Field(type => ObjectRef, { nullable: true })
13
+ bizplace?: ObjectRef
14
+
15
+ @Field({ nullable: true })
16
+ status?: string
17
+ }
18
+
19
+ @ObjectType()
20
+ export class ToteList {
21
+ @Field(type => [Tote], { nullable: true })
22
+ items?: Tote[]
23
+
24
+ @Field(type => Int, { nullable: true })
25
+ total?: number
26
+ }
27
+
28
+ @InputType()
29
+ export class TotePatch {
30
+ @Field({ nullable: true })
31
+ id?: string
32
+
33
+ @Field({ nullable: true })
34
+ name?: string
35
+
36
+ @Field(type => ObjectRef, { nullable: true })
37
+ bizplace?: ObjectRef
38
+
39
+ @Field({ nullable: true })
40
+ status?: string
41
+
42
+ @Field({ nullable: true })
43
+ cuFlag?: string
44
+ }
@@ -0,0 +1,77 @@
1
+ import { Field, ObjectType } from 'type-graphql'
2
+ import {
3
+ Column,
4
+ CreateDateColumn,
5
+ Entity,
6
+ Index,
7
+ ManyToOne,
8
+ PrimaryGeneratedColumn,
9
+ RelationId,
10
+ UpdateDateColumn
11
+ } from 'typeorm'
12
+
13
+ import { User } from '@things-factory/auth-base'
14
+ import { Bizplace } from '@things-factory/biz-base'
15
+ import { Domain } from '@things-factory/shell'
16
+
17
+ @Entity()
18
+ @Index('ix_tote_0', (tote: Tote) => [tote.bizplace, tote.name], { unique: true })
19
+ @ObjectType()
20
+ export class Tote {
21
+ @PrimaryGeneratedColumn('uuid')
22
+ @Field()
23
+ id: string
24
+
25
+ @ManyToOne(type => Domain)
26
+ @Field()
27
+ domain: Domain
28
+
29
+ @RelationId((tote: Tote) => tote.domain)
30
+ domainId: string
31
+
32
+ @Column()
33
+ @Field()
34
+ name: string
35
+
36
+ @ManyToOne(type => Bizplace)
37
+ @ManyToOne(type => Bizplace)
38
+ @Field(type => Bizplace)
39
+ bizplace: Bizplace
40
+
41
+ @RelationId((tote: Tote) => tote.bizplace)
42
+ bizplaceId: string
43
+
44
+ @Column()
45
+ @Field()
46
+ status: string
47
+
48
+ @CreateDateColumn()
49
+ @Field({ nullable: true })
50
+ createdAt: Date
51
+
52
+ @UpdateDateColumn()
53
+ @Field({ nullable: true })
54
+ updatedAt: Date
55
+
56
+ @ManyToOne(type => User, {
57
+ nullable: true
58
+ })
59
+ @Field({ nullable: true })
60
+ creator: User
61
+
62
+ @RelationId((tote: Tote) => tote.creator)
63
+ creatorId: string
64
+
65
+ @ManyToOne(type => User, {
66
+ nullable: true
67
+ })
68
+ @Field({ nullable: true })
69
+ updater: User
70
+
71
+ @RelationId((tote: Tote) => tote.updater)
72
+ updaterId: string
73
+
74
+ @Column({ nullable: true })
75
+ @Field({ nullable: true })
76
+ deletedAt: Date
77
+ }
@@ -355,7 +355,7 @@ export async function getProductBundleInventory(
355
355
  ) pb
356
356
  inner join product_bundle_settings pbs on pbs.product_bundle_id = pb.id
357
357
  inner join product_details pd on pd.id = pbs.product_detail_id
358
- left join inventories inv on inv.status <> 'TERMINATED' and (inv.qty - coalesce(inv.locked_qty,0)) > 0 and inv.product_id = pd.product_id and inv.packing_type = pd.packing_type and inv.packing_size = pd.packing_size and inv.uom = pd.uom
358
+ left join inventories inv on ((inv.status <> 'TERMINATED' and (inv.qty - coalesce(inv.locked_qty,0)) > 0) or (inv.status = 'TERMINATED' and (inv.qty - coalesce(inv.locked_qty,0)) = 0)) and inv.product_id = pd.product_id and inv.packing_type = pd.packing_type and inv.packing_size = pd.packing_size and inv.uom = pd.uom
359
359
  where inv.domain_id = $2
360
360
  group by pb.sku, pb.name, pbs.product_bundle_id, pbs.bundle_qty, pd.product_id, pd.packing_type, pd.packing_size, pd.uom
361
361
  ) foo group by product_bundle_id, sku, name
@@ -404,7 +404,8 @@ export async function getInventoriesByStrategy(
404
404
  "packingSize" INT,
405
405
  "uom" VARCHAR(10),
406
406
  "releaseQty" INT,
407
- "pickingStrategy" VARCHAR(25)
407
+ "pickingStrategy" VARCHAR(25),
408
+ "orderProductId" VARCHAR(50)
408
409
  );
409
410
  `
410
411
  )
@@ -412,7 +413,7 @@ export async function getInventoriesByStrategy(
412
413
  await trxMgr.query(
413
414
  `
414
415
  INSERT INTO temp_op2
415
- SELECT "productId", "batchId", "packingType", "packingSize", "uom", "releaseQty", "pickingStrategy"
416
+ SELECT "productId", "batchId", "packingType", "packingSize", "uom", "releaseQty", "pickingStrategy", "orderProductId"
416
417
  FROM JSON_POPULATE_RECORDSET(NULL::temp_op2, $1) js
417
418
  `,
418
419
  [orderProductsJSON]
@@ -445,6 +446,7 @@ export async function getInventoriesByStrategy(
445
446
  op."packingType",
446
447
  op."packingSize",
447
448
  op."uom",
449
+ op."orderProductId",
448
450
  ROW_NUMBER() OVER (
449
451
  PARTITION BY op."productId", op."batchId", op."packingType", op."packingSize", op."uom"
450
452
  ORDER BY