@things-factory/sales-base 8.0.0-beta.9 → 8.0.1

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 (178) hide show
  1. package/dist-server/tsconfig.tsbuildinfo +1 -1
  2. package/package.json +13 -13
  3. package/server/constants/attachment-type.ts +9 -0
  4. package/server/constants/index.ts +7 -0
  5. package/server/constants/load-type.ts +4 -0
  6. package/server/constants/order.ts +203 -0
  7. package/server/constants/product-group-type.ts +4 -0
  8. package/server/constants/release-good.ts +9 -0
  9. package/server/constants/transfer-order-type.ts +6 -0
  10. package/server/constants/validation-error-code.ts +3 -0
  11. package/server/constants/vas-target-type.ts +25 -0
  12. package/server/controllers/ecommerce/ecommerce-controller.ts +122 -0
  13. package/server/controllers/ecommerce/index.ts +2 -0
  14. package/server/controllers/ecommerce/sellercraft-controller.ts +182 -0
  15. package/server/controllers/index.ts +2 -0
  16. package/server/controllers/order-controller.ts +296 -0
  17. package/server/errors/index.ts +1 -0
  18. package/server/errors/validation-error.ts +25 -0
  19. package/server/index.ts +5 -0
  20. package/server/migrations/index.ts +9 -0
  21. package/server/service/arrival-notice/arrival-notice-mutation.ts +1152 -0
  22. package/server/service/arrival-notice/arrival-notice-query.ts +549 -0
  23. package/server/service/arrival-notice/arrival-notice-types.ts +310 -0
  24. package/server/service/arrival-notice/arrival-notice.ts +202 -0
  25. package/server/service/arrival-notice/index.ts +9 -0
  26. package/server/service/claim/claim-mutation.ts +308 -0
  27. package/server/service/claim/claim-query.ts +122 -0
  28. package/server/service/claim/claim-types.ts +130 -0
  29. package/server/service/claim/claim.ts +140 -0
  30. package/server/service/claim/index.ts +9 -0
  31. package/server/service/claim-detail/claim-detail-mutation.ts +102 -0
  32. package/server/service/claim-detail/claim-detail-query.ts +55 -0
  33. package/server/service/claim-detail/claim-detail-types.ts +47 -0
  34. package/server/service/claim-detail/claim-detail.ts +69 -0
  35. package/server/service/claim-detail/index.ts +9 -0
  36. package/server/service/claim-order/claim-order-mutation.ts +101 -0
  37. package/server/service/claim-order/claim-order-query.ts +47 -0
  38. package/server/service/claim-order/claim-order-types.ts +35 -0
  39. package/server/service/claim-order/claim-order.ts +81 -0
  40. package/server/service/claim-order/index.ts +9 -0
  41. package/server/service/collection-order/collection-order-mutation.ts +245 -0
  42. package/server/service/collection-order/collection-order-query.ts +97 -0
  43. package/server/service/collection-order/collection-order-types.ts +165 -0
  44. package/server/service/collection-order/collection-order.ts +135 -0
  45. package/server/service/collection-order/index.ts +9 -0
  46. package/server/service/delivery-order/delivery-order-mutation.ts +967 -0
  47. package/server/service/delivery-order/delivery-order-query.ts +631 -0
  48. package/server/service/delivery-order/delivery-order-types.ts +268 -0
  49. package/server/service/delivery-order/delivery-order.ts +258 -0
  50. package/server/service/delivery-order/index.ts +9 -0
  51. package/server/service/draft-release-good/draft-release-good-mutation.ts +765 -0
  52. package/server/service/draft-release-good/draft-release-good-query.ts +354 -0
  53. package/server/service/draft-release-good/draft-release-good-type.ts +261 -0
  54. package/server/service/draft-release-good/draft-release-good.ts +284 -0
  55. package/server/service/draft-release-good/index.ts +9 -0
  56. package/server/service/goods-receival-note/goods-receival-note-mutation.ts +129 -0
  57. package/server/service/goods-receival-note/goods-receival-note-query.ts +280 -0
  58. package/server/service/goods-receival-note/goods-receival-note-types.ts +105 -0
  59. package/server/service/goods-receival-note/goods-receival-note.ts +127 -0
  60. package/server/service/goods-receival-note/index.ts +9 -0
  61. package/server/service/index.ts +238 -0
  62. package/server/service/inventory-check/index.ts +9 -0
  63. package/server/service/inventory-check/inventory-check-mutation.ts +149 -0
  64. package/server/service/inventory-check/inventory-check-query.ts +48 -0
  65. package/server/service/inventory-check/inventory-check-types.ts +48 -0
  66. package/server/service/inventory-check/inventory-check.ts +90 -0
  67. package/server/service/invoice/index.ts +9 -0
  68. package/server/service/invoice/invoice-mutation.ts +95 -0
  69. package/server/service/invoice/invoice-query.ts +53 -0
  70. package/server/service/invoice/invoice-types.ts +279 -0
  71. package/server/service/invoice/invoice.ts +230 -0
  72. package/server/service/invoice-product/index.ts +9 -0
  73. package/server/service/invoice-product/invoice-product-mutation.ts +54 -0
  74. package/server/service/invoice-product/invoice-product-query.ts +54 -0
  75. package/server/service/invoice-product/invoice-product-types.ts +84 -0
  76. package/server/service/invoice-product/invoice-product.ts +92 -0
  77. package/server/service/job-sheet/index.ts +9 -0
  78. package/server/service/job-sheet/job-sheet-mutation.ts +92 -0
  79. package/server/service/job-sheet/job-sheet-query.ts +112 -0
  80. package/server/service/job-sheet/job-sheet-types.ts +78 -0
  81. package/server/service/job-sheet/job-sheet.ts +102 -0
  82. package/server/service/manifest/index.ts +6 -0
  83. package/server/service/manifest/manifest-mutation.ts +190 -0
  84. package/server/service/manifest/manifest-query.ts +149 -0
  85. package/server/service/manifest/manifest-type.ts +84 -0
  86. package/server/service/manifest/manifest.ts +114 -0
  87. package/server/service/order-inventory/index.ts +9 -0
  88. package/server/service/order-inventory/order-inventory-mutation.ts +54 -0
  89. package/server/service/order-inventory/order-inventory-query.ts +722 -0
  90. package/server/service/order-inventory/order-inventory-types.ts +238 -0
  91. package/server/service/order-inventory/order-inventory.ts +401 -0
  92. package/server/service/order-product/index.ts +9 -0
  93. package/server/service/order-product/order-product-mutation.ts +48 -0
  94. package/server/service/order-product/order-product-query.ts +89 -0
  95. package/server/service/order-product/order-product-types.ts +335 -0
  96. package/server/service/order-product/order-product.ts +362 -0
  97. package/server/service/order-tote/index.ts +9 -0
  98. package/server/service/order-tote/order-tote-mutation.ts +31 -0
  99. package/server/service/order-tote/order-tote-query.ts +112 -0
  100. package/server/service/order-tote/order-tote-types.ts +47 -0
  101. package/server/service/order-tote/order-tote.ts +73 -0
  102. package/server/service/order-tote-item/index.ts +9 -0
  103. package/server/service/order-tote-item/order-tote-item-mutation.ts +31 -0
  104. package/server/service/order-tote-item/order-tote-item-query.ts +82 -0
  105. package/server/service/order-tote-item/order-tote-item-types.ts +56 -0
  106. package/server/service/order-tote-item/order-tote-item.ts +72 -0
  107. package/server/service/order-tote-seal/index.ts +9 -0
  108. package/server/service/order-tote-seal/order-tote-seal-mutation.ts +31 -0
  109. package/server/service/order-tote-seal/order-tote-seal-query.ts +59 -0
  110. package/server/service/order-tote-seal/order-tote-seal-types.ts +41 -0
  111. package/server/service/order-tote-seal/order-tote-seal.ts +46 -0
  112. package/server/service/order-vas/index.ts +9 -0
  113. package/server/service/order-vas/order-vas-mutation.ts +20 -0
  114. package/server/service/order-vas/order-vas-query.ts +72 -0
  115. package/server/service/order-vas/order-vas-types.ts +159 -0
  116. package/server/service/order-vas/order-vas.ts +207 -0
  117. package/server/service/others/index.ts +5 -0
  118. package/server/service/others/other-query.ts +563 -0
  119. package/server/service/others/other-types.ts +115 -0
  120. package/server/service/purchase-order/index.ts +9 -0
  121. package/server/service/purchase-order/purchase-order-mutation.ts +458 -0
  122. package/server/service/purchase-order/purchase-order-query.ts +90 -0
  123. package/server/service/purchase-order/purchase-order-types.ts +154 -0
  124. package/server/service/purchase-order/purchase-order.ts +172 -0
  125. package/server/service/purchase-order-other-charge/index.ts +9 -0
  126. package/server/service/purchase-order-other-charge/purchase-order-other-charge-mutation.ts +31 -0
  127. package/server/service/purchase-order-other-charge/purchase-order-other-charge-query.ts +52 -0
  128. package/server/service/purchase-order-other-charge/purchase-order-other-charge-types.ts +44 -0
  129. package/server/service/purchase-order-other-charge/purchase-order-other-charge.ts +68 -0
  130. package/server/service/release-good/index.ts +9 -0
  131. package/server/service/release-good/release-good-mutation.ts +1686 -0
  132. package/server/service/release-good/release-good-query.ts +980 -0
  133. package/server/service/release-good/release-good-types.ts +662 -0
  134. package/server/service/release-good/release-good.ts +490 -0
  135. package/server/service/retail-replenishment-order/index.ts +9 -0
  136. package/server/service/retail-replenishment-order/retail-replenishment-order-mutation.ts +382 -0
  137. package/server/service/retail-replenishment-order/retail-replenishment-order-query.ts +54 -0
  138. package/server/service/retail-replenishment-order/retail-replenishment-order-types.ts +101 -0
  139. package/server/service/retail-replenishment-order/retail-replenishment-order.ts +115 -0
  140. package/server/service/return-order/index.ts +9 -0
  141. package/server/service/return-order/return-order-mutation.ts +516 -0
  142. package/server/service/return-order/return-order-query.ts +226 -0
  143. package/server/service/return-order/return-order-types.ts +196 -0
  144. package/server/service/return-order/return-order.ts +127 -0
  145. package/server/service/reverse-kitting-order/index.ts +9 -0
  146. package/server/service/reverse-kitting-order/reverse-kitting-order-mutation.ts +500 -0
  147. package/server/service/reverse-kitting-order/reverse-kitting-order-query.ts +197 -0
  148. package/server/service/reverse-kitting-order/reverse-kitting-order-type.ts +173 -0
  149. package/server/service/reverse-kitting-order/reverse-kitting-order.ts +121 -0
  150. package/server/service/reverse-kitting-order-inventory/index.ts +9 -0
  151. package/server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory-mutation.ts +129 -0
  152. package/server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory-query.ts +52 -0
  153. package/server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory-type.ts +95 -0
  154. package/server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory.ts +143 -0
  155. package/server/service/shipping-order/index.ts +9 -0
  156. package/server/service/shipping-order/shipping-order-mutation.ts +61 -0
  157. package/server/service/shipping-order/shipping-order-query.ts +61 -0
  158. package/server/service/shipping-order/shipping-order-types.ts +89 -0
  159. package/server/service/shipping-order/shipping-order.ts +129 -0
  160. package/server/service/transfer-order/index.ts +9 -0
  161. package/server/service/transfer-order/transfer-order-mutation.ts +309 -0
  162. package/server/service/transfer-order/transfer-order-query.ts +66 -0
  163. package/server/service/transfer-order/transfer-order-types.ts +97 -0
  164. package/server/service/transfer-order/transfer-order.ts +117 -0
  165. package/server/service/vas/index.ts +9 -0
  166. package/server/service/vas/vas-mutation.ts +106 -0
  167. package/server/service/vas/vas-query.ts +60 -0
  168. package/server/service/vas/vas-types.ts +71 -0
  169. package/server/service/vas/vas.ts +77 -0
  170. package/server/service/vas-order/index.ts +9 -0
  171. package/server/service/vas-order/vas-order-mutation.ts +259 -0
  172. package/server/service/vas-order/vas-order-query.ts +119 -0
  173. package/server/service/vas-order/vas-order-types.ts +49 -0
  174. package/server/service/vas-order/vas-order.ts +81 -0
  175. package/server/utils/datetime-util.ts +54 -0
  176. package/server/utils/index.ts +3 -0
  177. package/server/utils/inventory-util.ts +1155 -0
  178. package/server/utils/order-no-generator.ts +146 -0
@@ -0,0 +1,112 @@
1
+ import { Arg, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'
2
+ import { SelectQueryBuilder } from 'typeorm'
3
+
4
+ import { User } from '@things-factory/auth-base'
5
+ import { getPermittedBizplaceIds } from '@things-factory/biz-base'
6
+ import { buildQuery, Domain, Filter, getRepository, Pagination, Sorting } from '@things-factory/shell'
7
+
8
+ import { ArrivalNotice, JobSheetList } from '../'
9
+ import { JobSheet } from './job-sheet'
10
+
11
+ @Resolver(JobSheet)
12
+ export class JobSheetQuery {
13
+ @Directive('@transaction')
14
+ @Query(returns => JobSheetList)
15
+ async jobSheets(
16
+ @Ctx() context: ResolverContext,
17
+ @Arg('filters', type => [Filter], { nullable: true }) filters?: Filter[],
18
+ @Arg('pagination', type => Pagination, { nullable: true }) pagination?: Pagination,
19
+ @Arg('sortings', type => [Sorting], { nullable: true }) sortings?: Sorting[]
20
+ ): Promise<JobSheetList> {
21
+ const { domain, user, tx } = context.state
22
+
23
+ const bizplaceFilter = filters.find(param => param.name === 'bizplaceId')
24
+ const containerNoFilter = filters.find(param => param.name === 'containerNo')
25
+ const jobSheetNoFilter = filters.find(param => param.name === 'name')
26
+ const fromDateFilter = filters.find(param => param.name === 'fromDate')
27
+ const toDateFilter = filters.find(param => param.name === 'toDate')
28
+
29
+ if (!bizplaceFilter) {
30
+ filters.push({
31
+ name: 'bizplaceId',
32
+ operator: 'in',
33
+ value: await getPermittedBizplaceIds(domain, user),
34
+ relation: false
35
+ })
36
+ }
37
+
38
+ let fromDateValue: Date = new Date(fromDateFilter.value)
39
+ let toDateValue: Date = new Date(toDateFilter.value)
40
+ toDateValue.setDate(toDateValue.getDate() + 1)
41
+
42
+ const qb: SelectQueryBuilder<JobSheet> = tx.getRepository(JobSheet).createQueryBuilder('js')
43
+ buildQuery(qb, { filters, pagination, sortings }, context)
44
+ qb.innerJoinAndSelect('js.domain', 'domain')
45
+ qb.innerJoinAndSelect('js.bizplace', 'bizplace')
46
+ qb.innerJoinAndSelect('js.creator', 'creator')
47
+ qb.innerJoinAndSelect('js.updater', 'updater')
48
+ qb.where('js.domain_id = :domainId', { domainId: domain.id })
49
+
50
+ if (fromDateFilter && toDateFilter) {
51
+ qb.andWhere('js.updatedAt >= :fromDate', { fromDate: fromDateValue.toISOString() })
52
+ qb.andWhere('js.updatedAt <= :toDate', { toDate: toDateValue.toISOString() })
53
+ }
54
+
55
+ if (containerNoFilter) {
56
+ qb.andWhere('js.container_no ILIKE :containerNo', { containerNo: containerNoFilter.value })
57
+ }
58
+
59
+ if (jobSheetNoFilter) {
60
+ qb.andWhere('js.name ILIKE :name', { name: jobSheetNoFilter.value })
61
+ }
62
+
63
+ if (bizplaceFilter) {
64
+ qb.andWhere('js.bizplace_id = :bizplaceId', { bizplaceId: bizplaceFilter.value })
65
+ }
66
+
67
+ const [items, total] = await qb.getManyAndCount()
68
+ return { items, total }
69
+ }
70
+
71
+ @Directive('transaction')
72
+ @Query(returns => JobSheet)
73
+ async jobSheet(
74
+ @Arg('arrivalNoticeRefNo') arrivalNoticeRefNo: string,
75
+ @Ctx() context: ResolverContext
76
+ ): Promise<JobSheet> {
77
+ const { domain, tx } = context.state
78
+
79
+ const jobSheet: JobSheet = await tx.getRepository(JobSheet).findOne({
80
+ where: { domain: { id: domain.id }, arrivalNoticeRefNo },
81
+ relations: ['domain', 'bizplace', 'creator', 'updater']
82
+ })
83
+
84
+ if (!jobSheet) throw new Error('No job sheet is found')
85
+
86
+ const arrivalNotice: ArrivalNotice = await tx.getRepository(ArrivalNotice).findOne({
87
+ where: { name: jobSheet.arrivalNoticeRefNo, bizplace: { id: jobSheet.bizplace.id } }
88
+ })
89
+
90
+ return {
91
+ ...jobSheet,
92
+ looseItem: arrivalNotice?.looseItem,
93
+ etaDate: arrivalNotice?.etaDate,
94
+ ata: arrivalNotice?.ata
95
+ }
96
+ }
97
+
98
+ @FieldResolver(type => Domain)
99
+ async domain(@Root() jobSheet: JobSheet): Promise<Domain> {
100
+ return await getRepository(Domain).findOneBy({ id: jobSheet.domainId })
101
+ }
102
+
103
+ @FieldResolver(type => User)
104
+ async creator(@Root() jobSheet: JobSheet): Promise<User> {
105
+ return await getRepository(User).findOneBy({ id: jobSheet.creatorId })
106
+ }
107
+
108
+ @FieldResolver(type => User)
109
+ async updater(@Root() jobSheet: JobSheet): Promise<User> {
110
+ return await getRepository(User).findOneBy({ id: jobSheet.updaterId })
111
+ }
112
+ }
@@ -0,0 +1,78 @@
1
+ import {
2
+ Field,
3
+ Float,
4
+ InputType,
5
+ Int,
6
+ ObjectType
7
+ } from 'type-graphql'
8
+
9
+ import { JobSheet } from './job-sheet'
10
+
11
+ @ObjectType()
12
+ export class JobSheetList {
13
+ @Field(type => [JobSheet], { nullable: true })
14
+ items: JobSheet[]
15
+
16
+ @Field(type => Int, { nullable: true })
17
+ total: number
18
+ }
19
+
20
+ @InputType()
21
+ export class NewJobSheet {
22
+ @Field()
23
+ name: string
24
+
25
+ @Field({ nullable: true })
26
+ description: string
27
+
28
+ @Field({ nullable: true })
29
+ containerMtDate: string
30
+
31
+ @Field({ nullable: true })
32
+ containerSize: string
33
+
34
+ @Field({ nullable: true })
35
+ adviseMtDate: string
36
+
37
+ @Field(type => Float, { nullable: true })
38
+ sumPackQty: number
39
+
40
+ @Field(type => Int, { nullable: true })
41
+ sumPalletQty: number
42
+
43
+ @Field({ nullable: true })
44
+ containerNo: string
45
+
46
+ @Field({ nullable: true })
47
+ arrivalNoticeRefNo: string
48
+ }
49
+
50
+ @InputType()
51
+ export class JobSheetPatch {
52
+ @Field({ nullable: true })
53
+ name: string
54
+
55
+ @Field({ nullable: true })
56
+ ata: string
57
+
58
+ @Field({ nullable: true })
59
+ description: string
60
+
61
+ @Field({ nullable: true })
62
+ adviseMtDate: string
63
+
64
+ @Field({ nullable: true })
65
+ containerMtDate: string
66
+
67
+ @Field(type => Float, { nullable: true })
68
+ sumPackQty: number
69
+
70
+ @Field(type => Int, { nullable: true })
71
+ sumPalletQty: number
72
+
73
+ @Field({ nullable: true })
74
+ arrivalNoticeRefNo: string
75
+
76
+ @Field({ nullable: true })
77
+ containerNo: string
78
+ }
@@ -0,0 +1,102 @@
1
+ import { User } from '@things-factory/auth-base'
2
+ import { Bizplace } from '@things-factory/biz-base'
3
+ import { Domain } from '@things-factory/shell'
4
+ import { Field, ID, ObjectType } from 'type-graphql'
5
+ import {
6
+ Column,
7
+ CreateDateColumn,
8
+ Entity,
9
+ Index,
10
+ ManyToOne,
11
+ PrimaryGeneratedColumn,
12
+ RelationId,
13
+ UpdateDateColumn
14
+ } from 'typeorm'
15
+
16
+ @Entity()
17
+ @Index('ix_job-sheet_0', (jobSheet: JobSheet) => [jobSheet.domain, jobSheet.name, jobSheet.arrivalNoticeRefNo], {
18
+ unique: true
19
+ })
20
+ @ObjectType()
21
+ export class JobSheet {
22
+ @PrimaryGeneratedColumn('uuid')
23
+ @Field(type => ID)
24
+ readonly id: string
25
+
26
+ @ManyToOne(type => Domain)
27
+ @Field(type => Domain, { nullable: true })
28
+ domain: Domain
29
+
30
+ @RelationId((jobSheet: JobSheet) => jobSheet.domain)
31
+ domainId: string
32
+
33
+ @ManyToOne(type => Bizplace)
34
+ @Field(type => Bizplace, { nullable: true })
35
+ bizplace: Bizplace
36
+
37
+ @RelationId((jobSheet: JobSheet) => jobSheet.bizplace)
38
+ bizplaceId: string
39
+
40
+ @Column()
41
+ @Field()
42
+ name: string
43
+
44
+ @Column({ nullable: true })
45
+ @Field({ nullable: true })
46
+ description: string
47
+
48
+ @Column({ nullable: true })
49
+ @Field({ nullable: true })
50
+ containerMtDate: String
51
+
52
+ @Column({ nullable: true })
53
+ @Field({ nullable: true })
54
+ adviseMtDate: Date
55
+
56
+ @Column({ nullable: true })
57
+ @Field({ nullable: true })
58
+ containerNo: String
59
+
60
+ @Column({ nullable: true })
61
+ @Field({ nullable: true })
62
+ containerSize: String
63
+
64
+ @Column({ nullable: true })
65
+ @Field({ nullable: true })
66
+ sumPalletQty: number
67
+
68
+ @Column({ nullable: true })
69
+ @Field({ nullable: true })
70
+ arrivalNoticeRefNo: string
71
+
72
+ @CreateDateColumn()
73
+ @Field()
74
+ createdAt: Date
75
+
76
+ @UpdateDateColumn()
77
+ @Field()
78
+ updatedAt: Date
79
+
80
+ @ManyToOne(type => User)
81
+ @Field(type => User, { nullable: true })
82
+ creator: User
83
+
84
+ @RelationId((jobSheet: JobSheet) => jobSheet.creator)
85
+ creatorId: string
86
+
87
+ @ManyToOne(type => User)
88
+ @Field(type => User, { nullable: true })
89
+ updater: User
90
+
91
+ @RelationId((jobSheet: JobSheet) => jobSheet.updater)
92
+ updaterId: string
93
+
94
+ @Field({ nullable: true })
95
+ looseItem: boolean
96
+
97
+ @Field({ nullable: true })
98
+ etaDate: string
99
+
100
+ @Field({ nullable: true })
101
+ ata: Date
102
+ }
@@ -0,0 +1,6 @@
1
+ import { Manifest } from './manifest'
2
+ import { ManifestQuery } from './manifest-query'
3
+ import { ManifestMutation } from './manifest-mutation'
4
+
5
+ export const entities = [Manifest]
6
+ export const resolvers = [ManifestQuery, ManifestMutation]
@@ -0,0 +1,190 @@
1
+ import i18next from 'i18next'
2
+ import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
3
+ import { In, Not } from 'typeorm'
4
+
5
+ import { DISPATCHMENT_STATUS, MANIFEST_STATUS } from '../../constants'
6
+ import { OrderNoGenerator } from '../../utils'
7
+ import { ReleaseGood } from '../release-good/release-good'
8
+ import { Manifest, ManifestStatus } from './manifest'
9
+ import { ManifestPatch, NewManifest } from './manifest-type'
10
+
11
+ @Resolver(Manifest)
12
+ export class ManifestMutation {
13
+ @Directive('@transaction')
14
+ @Mutation(returns => Boolean, { description: 'To update Manifest' })
15
+ async updateManifest(
16
+ @Arg('manifestId', { nullable: true }) manifestId: string,
17
+ @Arg('status', { nullable: true }) status: string,
18
+ @Arg('shippingProvider', { nullable: true }) shippingProvider: string,
19
+ @Arg('removeOrders', type => [String], { nullable: true }) removeOrders: string[],
20
+ @Ctx() context: ResolverContext
21
+ ): Promise<boolean> {
22
+ const { domain, tx } = context.state
23
+ const ManifestRepo = tx.getRepository(Manifest)
24
+ //update status
25
+ if (status) {
26
+ if (status == MANIFEST_STATUS.OPEN) {
27
+ //check if there is only one manifest is open, if yes update it to in queue and update current to open
28
+
29
+ let foundOpenOrder = await ManifestRepo.find({
30
+ where: { domain: { id: domain.id }, shippingProvider, status: MANIFEST_STATUS.OPEN as any }
31
+ })
32
+
33
+ if (foundOpenOrder.length == 1) {
34
+ await ManifestRepo.update({ id: foundOpenOrder[0].id }, { status: MANIFEST_STATUS.IN_QUEUE as any })
35
+ } else if (foundOpenOrder.length > 1) {
36
+ let manifestNames = foundOpenOrder.map(itm => itm.name)
37
+ throw new Error(i18next.t('error.Manifest(s) (x) already in open status', { x: manifestNames.toString() }))
38
+ }
39
+ }
40
+
41
+ await ManifestRepo.update({ id: manifestId }, { status: status as any })
42
+ }
43
+
44
+ //remove orders from manifest
45
+ if (removeOrders?.length > 0) {
46
+ //check if user removing all tracking no, if yes then delete
47
+ let totalTrackingNo = await tx.getRepository(ReleaseGood).count({ where: { manifest: { id: manifestId } } })
48
+ await tx
49
+ .getRepository(ReleaseGood)
50
+ .update(
51
+ { domain: { id: domain.id }, refNo: In(removeOrders) },
52
+ { manifest: null, manifestedBy: null, manifestedAt: null }
53
+ )
54
+ if (removeOrders.length == totalTrackingNo) {
55
+ await tx.getRepository(Manifest).delete(manifestId)
56
+ return false
57
+ }
58
+ }
59
+ return true
60
+ }
61
+
62
+ @Directive('@transaction')
63
+ @Mutation(returns => Boolean, { description: 'To delete Manifest' })
64
+ async deleteManifest(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<boolean> {
65
+ const { domain, tx } = context.state
66
+
67
+ await tx.getRepository(Manifest).delete({ domain: { id: domain.id }, name })
68
+ return true
69
+ }
70
+
71
+ @Directive('@transaction')
72
+ @Mutation(returns => Boolean, { description: 'To generate new Manifest' })
73
+ async generateManifest(@Arg('manifest') manifest: NewManifest, @Ctx() context: ResolverContext): Promise<boolean> {
74
+ const { domain, user, tx } = context.state
75
+ const manifestItems: any[] = manifest.manifestItems
76
+
77
+ // regroup array of object by transporter
78
+ let shippingProviderGrouping: any = manifestItems.reduce((a, b) => {
79
+ a[b.transporter] = [...(a[b.transporter] || []), b]
80
+ return a
81
+ }, {})
82
+
83
+ for (const transporter in shippingProviderGrouping) {
84
+ const items: any[] = shippingProviderGrouping[transporter]
85
+
86
+ const openManifest: Manifest = await tx
87
+ .getRepository(Manifest)
88
+ .findOneBy({ domain: { id: domain.id }, shippingProvider: transporter, status: ManifestStatus.OPEN })
89
+
90
+ let manifest: Manifest
91
+
92
+ if (openManifest) {
93
+ manifest = openManifest
94
+ } else {
95
+ manifest = new Manifest()
96
+ manifest.domain = domain
97
+ manifest.shippingProvider = transporter
98
+ manifest.name = OrderNoGenerator.manifest()
99
+ manifest.creator = user
100
+ manifest = await tx.getRepository(Manifest).save(manifest)
101
+ }
102
+
103
+ await Promise.all(
104
+ items.map(async item => {
105
+ let releaseOrder: ReleaseGood = await tx
106
+ .getRepository(ReleaseGood)
107
+ .findOneBy({ domain: { id: domain.id }, refNo: item.refNo, trackingNo: item.trackingNo })
108
+ releaseOrder.manifest = manifest
109
+ releaseOrder.updater = user
110
+ releaseOrder.manifestedBy = user
111
+ releaseOrder.manifestedAt = new Date()
112
+ await tx.getRepository(ReleaseGood).save(releaseOrder)
113
+ })
114
+ )
115
+ }
116
+
117
+ return true
118
+ }
119
+
120
+ @Directive('@transaction')
121
+ @Mutation(returns => Boolean, { description: 'To add tracking no into manifest' })
122
+ async addTrackingNo(
123
+ @Arg('manifestId', { nullable: true }) manifestId: string,
124
+ @Arg('trackingNo', { nullable: true }) trackingNo: string,
125
+ @Arg('shippingProvider', { nullable: true }) shippingProvider: string,
126
+ @Ctx() context: ResolverContext
127
+ ): Promise<boolean> {
128
+ const { domain, user, tx } = context.state
129
+ const releaseGoodRepo = tx.getRepository(ReleaseGood)
130
+ //check if order belongs to same shipping provider
131
+ let foundReleaseOrder = await releaseGoodRepo.findOne({ where: { trackingNo }, relations: ['manifest'] })
132
+
133
+ if (!foundReleaseOrder) {
134
+ throw new Error(i18next.t('error.release_order_not_found'))
135
+ }
136
+
137
+ if (foundReleaseOrder.manifest) {
138
+ throw new Error(i18next.t('error.tracking_no_already_scanned_before'))
139
+ }
140
+
141
+ if (foundReleaseOrder.transporter !== shippingProvider) {
142
+ throw new Error(i18next.t('error.tracking_no_belongs_to_x', { x: foundReleaseOrder.transporter }))
143
+ }
144
+
145
+ await releaseGoodRepo.update(
146
+ { id: foundReleaseOrder.id },
147
+ { manifest: { id: manifestId }, manifestedAt: new Date(), manifestedBy: user }
148
+ )
149
+
150
+ return true
151
+ }
152
+
153
+ @Directive('@transaction')
154
+ @Mutation(returns => Manifest, { description: 'To dispatch Manifest when courier service collect packages' })
155
+ async dispatchManifest(
156
+ @Arg('name') name: string,
157
+ @Arg('patch') patch: ManifestPatch,
158
+ @Ctx() context: ResolverContext
159
+ ): Promise<Manifest> {
160
+ const { domain, user, tx } = context.state
161
+
162
+ const manifest: Manifest = await tx.getRepository(Manifest).findOne({
163
+ where: { domain: { id: domain.id }, name, status: Not(MANIFEST_STATUS.CLOSED) as any }
164
+ })
165
+ if (!manifest) throw new Error(`Unable to find ${name}`)
166
+
167
+ let releaseGoods: any[] = await tx
168
+ .getRepository(ReleaseGood)
169
+ .find({ where: { domain: { id: domain.id }, manifest: { id: manifest.id } } })
170
+
171
+ releaseGoods = await Promise.all(
172
+ releaseGoods.map((releaseGood: ReleaseGood) => {
173
+ return {
174
+ ...releaseGood,
175
+ dispatchmentStatus: DISPATCHMENT_STATUS.DISPATCHED,
176
+ updater: user
177
+ }
178
+ })
179
+ )
180
+ await tx.getRepository(ReleaseGood).save(releaseGoods)
181
+
182
+ return await tx.getRepository(Manifest).save({
183
+ ...manifest,
184
+ ...patch,
185
+ status: ManifestStatus.CLOSED,
186
+ dispatchedAt: new Date(),
187
+ updater: user
188
+ })
189
+ }
190
+ }
@@ -0,0 +1,149 @@
1
+ import { Arg, Args, Ctx, FieldResolver, Query, Resolver, Root } from 'type-graphql'
2
+ import { SelectQueryBuilder } from 'typeorm'
3
+
4
+ import { User } from '@things-factory/auth-base'
5
+ import { buildQuery, convertListParams, Domain, getRepository, ListParam, Sorting } from '@things-factory/shell'
6
+
7
+ import { ReleaseGood } from '../release-good/release-good'
8
+ import { Manifest } from './manifest'
9
+ import { ManifestList } from './manifest-type'
10
+
11
+ @Resolver(Manifest)
12
+ export class ManifestQuery {
13
+ @Query(returns => Manifest, { description: 'To fetch a Manifest' })
14
+ async manifest(
15
+ @Arg('name') name: string,
16
+ @Ctx() context: ResolverContext,
17
+ @Arg('sortings', type => [Sorting], { nullable: true }) sortings?: Sorting[]
18
+ ): Promise<Manifest> {
19
+ const phoneSort = sortings.findIndex(sort => sort.name === 'phone')
20
+ if (phoneSort >= 0) {
21
+ sortings[phoneSort].name = 'phone1'
22
+ }
23
+
24
+ const deliveryAddressSort = sortings.findIndex(sort => sort.name === 'deliveryAddress')
25
+ if (deliveryAddressSort >= 0) {
26
+ sortings[deliveryAddressSort].name = 'deliveryAddress1'
27
+ }
28
+
29
+ const orderRemarkSort = sortings.findIndex(sort => sort.name === 'orderRemark')
30
+ if (orderRemarkSort >= 0) {
31
+ sortings[orderRemarkSort].name = 'remark'
32
+ }
33
+
34
+ const orderStatusSort = sortings.findIndex(sort => sort.name === 'orderStatus')
35
+ if (orderStatusSort >= 0) {
36
+ sortings[orderStatusSort].name = 'status'
37
+ }
38
+ const convertedParams = convertListParams({ sortings })
39
+ const { domain, tx } = context.state
40
+ const manifest: Manifest = await getRepository(Manifest).findOne({ where: { domain: { id: domain.id }, name } })
41
+
42
+ const releaseGoods: ReleaseGood[] = await getRepository(ReleaseGood).find({
43
+ ...convertedParams,
44
+ where: { manifest: { id: manifest.id } }
45
+ })
46
+
47
+ const trackingNos: any[] = releaseGoods.map(releaseGood => {
48
+ return {
49
+ trackingNo: releaseGood.trackingNo,
50
+ refNo: releaseGood.refNo,
51
+ deliveryAddress: releaseGood.deliveryAddress1,
52
+ attentionTo: releaseGood.attentionTo,
53
+ postalCode: releaseGood.postalCode,
54
+ city: releaseGood.city,
55
+ phone: releaseGood.phone1,
56
+ dispatchmentStatus: releaseGood.dispatchmentStatus,
57
+ orderStatus: releaseGood.status,
58
+ orderRemark: releaseGood.remark
59
+ }
60
+ })
61
+
62
+ return {
63
+ ...manifest,
64
+ trackingNos
65
+ }
66
+ }
67
+
68
+ @Query(returns => ManifestList, { description: 'To fetch multiple Manifests' })
69
+ async manifests(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<ManifestList> {
70
+ const { domain } = context.state
71
+
72
+ let orderInfoFilter
73
+ const orderInfoParamIdx = params.filters.findIndex(param => param.name === 'orderInfo')
74
+ if (orderInfoParamIdx >= 0) {
75
+ orderInfoFilter = params.filters[orderInfoParamIdx].value.toLowerCase().split(',').join('|')
76
+
77
+ params.filters.splice(orderInfoParamIdx, 1)
78
+ }
79
+
80
+ let trackingNoFilter
81
+ const trackingNoParamIdx = params.filters.findIndex(param => param.name === 'trackingNo')
82
+ if (trackingNoParamIdx >= 0) {
83
+ trackingNoFilter = params.filters[trackingNoParamIdx].value
84
+
85
+ params.filters.splice(trackingNoParamIdx, 1)
86
+ }
87
+
88
+ const fromDateParamIdx = params.filters.findIndex(param => param.name === 'fromDate')
89
+ if (fromDateParamIdx >= 0) {
90
+ let fromDateVal = new Date(params.filters[fromDateParamIdx].value)
91
+ params.filters.splice(fromDateParamIdx, 1)
92
+
93
+ params.filters.push({
94
+ name: 'createdAt',
95
+ operator: 'gte',
96
+ value: fromDateVal.toISOString(),
97
+ relation: false
98
+ })
99
+ }
100
+
101
+ const toDateParamIdx = params.filters.findIndex(param => param.name === 'toDate')
102
+ if (toDateParamIdx >= 0) {
103
+ let toDateVal = new Date(params.filters[toDateParamIdx].value)
104
+ params.filters.splice(toDateParamIdx, 1)
105
+
106
+ params.filters.push({
107
+ name: 'createdAt',
108
+ operator: 'lt',
109
+ value: new Date(toDateVal.setDate(toDateVal.getDate() + 1)).toISOString(),
110
+ relation: false
111
+ })
112
+ }
113
+
114
+ const qb: SelectQueryBuilder<Manifest> = getRepository(Manifest).createQueryBuilder('mf')
115
+ buildQuery(qb, params, context)
116
+ qb.innerJoin('release_goods', 'rg', 'rg.manifest_id = mf.id')
117
+ orderInfoFilter
118
+ ? qb.andWhere(
119
+ '(rg.name ~* :orderInfoFilter or rg.ref_no ~* :orderInfoFilter or rg.ref_no_2 ~* :orderInfoFilter or rg.ref_no_3 ~* :orderInfoFilter)',
120
+ { orderInfoFilter }
121
+ )
122
+ : ''
123
+ trackingNoFilter ? qb.andWhere('rg.tracking_no ilike :trackingNo', { trackingNo: trackingNoFilter }) : ''
124
+
125
+ const [items, total] = await qb.getManyAndCount()
126
+
127
+ await Promise.all(
128
+ items.map(async item => {
129
+ item.totalTrackingNo = await getRepository(ReleaseGood).count({ where: { manifest: { id: item.id } } })
130
+ })
131
+ )
132
+ return { items, total }
133
+ }
134
+
135
+ @FieldResolver(type => Domain)
136
+ async domain(@Root() manifest: Manifest): Promise<Domain> {
137
+ return await getRepository(Domain).findOneBy({ id: manifest.domainId })
138
+ }
139
+
140
+ @FieldResolver(type => User)
141
+ async updater(@Root() manifest: Manifest): Promise<User> {
142
+ return await getRepository(User).findOneBy({ id: manifest.updaterId })
143
+ }
144
+
145
+ @FieldResolver(type => User)
146
+ async creator(@Root() manifest: Manifest): Promise<User> {
147
+ return await getRepository(User).findOneBy({ id: manifest.creatorId })
148
+ }
149
+ }