@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,284 @@
1
+ import { Field, ID, ObjectType } from 'type-graphql'
2
+ import {
3
+ Column,
4
+ CreateDateColumn,
5
+ Entity,
6
+ Index,
7
+ JoinColumn,
8
+ ManyToOne,
9
+ OneToMany,
10
+ OneToOne,
11
+ PrimaryGeneratedColumn,
12
+ RelationId,
13
+ UpdateDateColumn
14
+ } from 'typeorm'
15
+
16
+ import { Attachment } from '@things-factory/attachment-base'
17
+ import { User } from '@things-factory/auth-base'
18
+ import { Bizplace, ContactPoint } from '@things-factory/biz-base'
19
+ import { config } from '@things-factory/env'
20
+ import { Domain } from '@things-factory/shell'
21
+
22
+ import { OrderProduct, ReleaseGood, ShippingOrder, ShippingOrderInfo } from '../'
23
+ import { ReleaseOrderType } from '../../constants'
24
+
25
+ const ORMCONFIG = config.get('ormconfig', {})
26
+ const DATABASE_TYPE = ORMCONFIG.type
27
+
28
+ // export enum DraftReleaseGoodStatus {
29
+ // STATUS_A = 'STATUS_A',
30
+ // STATUS_B = 'STATUS_B'
31
+ // }
32
+
33
+ // registerEnumType(DraftReleaseGoodStatus, {
34
+ // name: 'DraftReleaseGoodStatus',
35
+ // description: 'state enumeration of a draftReleaseGood'
36
+ // })
37
+
38
+ @Entity()
39
+ @Index(
40
+ 'ix_draft_release_good_0',
41
+ (draftReleaseGood: DraftReleaseGood) => [draftReleaseGood.domain, draftReleaseGood.name],
42
+ { unique: true }
43
+ )
44
+ @ObjectType({ description: 'Entity for DraftReleaseGood' })
45
+ export class DraftReleaseGood {
46
+ @PrimaryGeneratedColumn('uuid')
47
+ @Field(type => ID)
48
+ readonly id: string
49
+
50
+ @ManyToOne(type => Domain)
51
+ @Field(type => Domain, { nullable: true })
52
+ domain: Domain
53
+
54
+ @RelationId((draftReleaseGood: DraftReleaseGood) => draftReleaseGood.domain)
55
+ domainId: string
56
+
57
+ @ManyToOne(type => Bizplace)
58
+ @Field(type => Bizplace, { nullable: true })
59
+ bizplace: Bizplace
60
+
61
+ @RelationId((draftReleaseGood: DraftReleaseGood) => draftReleaseGood.bizplace)
62
+ bizplaceId: string
63
+
64
+ @Column({ nullable: true })
65
+ @Field({ nullable: true })
66
+ name: string
67
+
68
+ @OneToOne(type => ReleaseGood)
69
+ @JoinColumn()
70
+ @Field(type => ReleaseGood, { nullable: true })
71
+ releaseGood: ReleaseGood
72
+
73
+ @RelationId((draftReleaseGood: DraftReleaseGood) => draftReleaseGood.releaseGood)
74
+ releaseGoodId: string
75
+
76
+ @OneToOne(type => ShippingOrder)
77
+ @JoinColumn()
78
+ @Field(type => ShippingOrder, { nullable: true })
79
+ shippingOrder: ShippingOrder
80
+
81
+ @RelationId((releaseGood: ReleaseGood) => releaseGood.shippingOrder)
82
+ shippingOrderId: string
83
+
84
+ @Column({ nullable: true })
85
+ @Field({ nullable: true })
86
+ collectionOrderNo: string
87
+
88
+ @Column({ nullable: true })
89
+ @Field({ nullable: true })
90
+ description: string
91
+
92
+ @Column({ nullable: true })
93
+ @Field({ nullable: true })
94
+ truckNo: string
95
+
96
+ @Column({
97
+ type:
98
+ DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'
99
+ ? 'enum'
100
+ : DATABASE_TYPE == 'oracle'
101
+ ? 'varchar2'
102
+ : DATABASE_TYPE == 'mssql'
103
+ ? 'nvarchar'
104
+ : 'varchar',
105
+ enum:
106
+ DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'
107
+ ? ReleaseOrderType
108
+ : undefined,
109
+ length: DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb' ? undefined : 32,
110
+ default: ReleaseOrderType.B2B
111
+ })
112
+ @Field()
113
+ type: ReleaseOrderType
114
+
115
+ @Column({ default: false })
116
+ @Field()
117
+ exportOption: Boolean
118
+
119
+ @Column({ default: false })
120
+ @Field()
121
+ courierOption: Boolean
122
+
123
+ @Column({ default: false })
124
+ @Field()
125
+ packingOption: Boolean
126
+
127
+ @Column()
128
+ @Field()
129
+ ownTransport: Boolean
130
+
131
+ @Field(type => ShippingOrderInfo, { nullable: true })
132
+ shippingOrderInfo?: ShippingOrderInfo
133
+
134
+ @OneToMany(type => OrderProduct, orderProduct => orderProduct.draftReleaseGood)
135
+ @Field(type => [OrderProduct], { nullable: true })
136
+ orderProducts: OrderProduct[]
137
+
138
+ @Column()
139
+ @Field()
140
+ status: string
141
+
142
+ @Column({ nullable: true })
143
+ @Field({ nullable: true })
144
+ refNo: String
145
+
146
+ @Column({ nullable: true })
147
+ @Field({ nullable: true })
148
+ refNo2: String
149
+
150
+ @Column({ nullable: true })
151
+ @Field({ nullable: true })
152
+ refNo3: String
153
+
154
+ @Column({ nullable: true })
155
+ @Field({ nullable: true })
156
+ releaseDate: string
157
+
158
+ @Column({ nullable: true })
159
+ @Field({ nullable: true })
160
+ remark: string
161
+
162
+ @Column({ nullable: true })
163
+ @Field({ nullable: true })
164
+ marketplaceOrderStatus: string
165
+
166
+ @Column({ nullable: true })
167
+ @Field({ nullable: true })
168
+ billingAddress: string
169
+
170
+ @Column({ nullable: true })
171
+ @Field({ nullable: true })
172
+ pickupAddress: string
173
+
174
+ @Column({ nullable: true })
175
+ @Field({ nullable: true })
176
+ pickupTime: Date
177
+
178
+ @Column({ nullable: true })
179
+ @Field({ nullable: true })
180
+ handoverType: string
181
+
182
+ @Column({ nullable: true })
183
+ @Field({ nullable: true })
184
+ dropoffAddress: string
185
+
186
+ @Column({ nullable: true })
187
+ @Field({ nullable: true })
188
+ deliveryAddress1: string
189
+
190
+ @Column({ nullable: true })
191
+ @Field({ nullable: true })
192
+ deliveryAddress2: string
193
+
194
+ @Column({ nullable: true })
195
+ @Field({ nullable: true })
196
+ deliveryAddress3: string
197
+
198
+ @Column({ nullable: true })
199
+ @Field({ nullable: true })
200
+ deliveryAddress4: string
201
+
202
+ @Column({ nullable: true })
203
+ @Field({ nullable: true })
204
+ deliveryAddress5: string
205
+
206
+ @Column({ nullable: true })
207
+ @Field({ nullable: true })
208
+ attentionTo: string
209
+
210
+ @Column({ nullable: true })
211
+ @Field({ nullable: true })
212
+ attentionCompany: string
213
+
214
+ @Column({ nullable: true })
215
+ @Field({ nullable: true })
216
+ city: string
217
+
218
+ @Column({ nullable: true })
219
+ @Field({ nullable: true })
220
+ state: string
221
+
222
+ @Column({ nullable: true })
223
+ @Field({ nullable: true })
224
+ postalCode: string
225
+
226
+ @Column({ nullable: true })
227
+ @Field({ nullable: true })
228
+ country: string
229
+
230
+ @Column({ nullable: true })
231
+ @Field({ nullable: true })
232
+ phone1: string
233
+
234
+ @Column({ nullable: true })
235
+ @Field({ nullable: true })
236
+ phone2: string
237
+
238
+ @Column({ nullable: true })
239
+ @Field({ nullable: true })
240
+ email: string
241
+
242
+ @Column({ nullable: true })
243
+ @Field({ nullable: true })
244
+ packageId: string
245
+
246
+ @Column({ nullable: true })
247
+ @Field({ nullable: true })
248
+ source: string
249
+
250
+ @ManyToOne(type => ContactPoint)
251
+ @Field(type => ContactPoint, { nullable: true })
252
+ deliverTo: ContactPoint
253
+
254
+ @RelationId((draftReleaseGood: DraftReleaseGood) => draftReleaseGood.deliverTo)
255
+ deliverToId: string
256
+
257
+ @Field(type => [Attachment], { nullable: true })
258
+ attachment?: Attachment[]
259
+
260
+ @CreateDateColumn()
261
+ @Field()
262
+ createdAt: Date
263
+
264
+ @UpdateDateColumn()
265
+ @Field()
266
+ updatedAt: Date
267
+
268
+ @ManyToOne(type => User)
269
+ @Field(type => User, { nullable: true })
270
+ creator: User
271
+
272
+ @RelationId((draftReleaseGood: DraftReleaseGood) => draftReleaseGood.creator)
273
+ creatorId: string
274
+
275
+ @ManyToOne(type => User)
276
+ @Field(type => User, { nullable: true })
277
+ updater: User
278
+
279
+ @RelationId((draftReleaseGood: DraftReleaseGood) => draftReleaseGood.updater)
280
+ updaterId: string
281
+
282
+ @Field()
283
+ computedStatus: string
284
+ }
@@ -0,0 +1,9 @@
1
+ import { DraftReleaseGood } from './draft-release-good'
2
+ import { DraftReleaseGoodQuery } from './draft-release-good-query'
3
+ import { DraftReleaseGoodMutation } from './draft-release-good-mutation'
4
+
5
+ export const entities = [DraftReleaseGood]
6
+ export const resolvers = [DraftReleaseGoodQuery, DraftReleaseGoodMutation]
7
+
8
+ export * from './draft-release-good-mutation'
9
+ export * from './draft-release-good-query'
@@ -0,0 +1,129 @@
1
+ import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
2
+ import { EntityManager, In, Repository } from 'typeorm'
3
+
4
+ import { User } from '@things-factory/auth-base'
5
+ import { Bizplace } from '@things-factory/biz-base'
6
+ import { generateId } from '@things-factory/id-rule-base'
7
+ import { Setting } from '@things-factory/setting-base'
8
+ import { Domain, getRepository } from '@things-factory/shell'
9
+
10
+ import { ArrivalNotice, NewGoodsReceivalNote } from '../'
11
+ import { GRN_STATUS, ORDER_NUMBER_RULE_TYPE, ORDER_NUMBER_SETTING_KEY } from '../../constants'
12
+ import { OrderNoGenerator } from '../../utils/order-no-generator'
13
+ import { GoodsReceivalNote } from './goods-receival-note'
14
+
15
+ @Resolver(GoodsReceivalNote)
16
+ export class GoodsReceivalNoteMutation {
17
+ @Mutation(returns => GoodsReceivalNote)
18
+ @Directive('@privilege(category: "order_warehouse", privilege: "mutation")')
19
+ @Directive('@transaction')
20
+ async generateGoodsReceivalNote(
21
+ @Ctx() context: ResolverContext,
22
+ @Arg('grn', type => NewGoodsReceivalNote, { nullable: true }) grn?: NewGoodsReceivalNote
23
+ ): Promise<GoodsReceivalNote> {
24
+ const { tx, domain, user } = context.state
25
+ return await generateGoodsReceivalNote(grn, domain, user, tx)
26
+ }
27
+
28
+ @Mutation(returns => Boolean)
29
+ @Directive('@privilege(category: "order_warehouse", privilege: "mutation")')
30
+ @Directive('@transaction')
31
+ async deleteGoodsReceivalNote(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<boolean> {
32
+ const { tx, domain } = context.state
33
+ await tx.getRepository(GoodsReceivalNote).delete({ domain: { id: domain.id }, name })
34
+ return true
35
+ }
36
+
37
+ @Mutation(returns => Boolean)
38
+ @Directive('@privilege(category: "order_warehouse", privilege: "mutation")')
39
+ @Directive('@transaction')
40
+ async deleteGoodsReceivalNotes(
41
+ @Arg('names', type => [String]) names: string[],
42
+ @Ctx() context: ResolverContext
43
+ ): Promise<boolean> {
44
+ const { tx, domain } = context.state
45
+ await tx.getRepository(GoodsReceivalNote).delete({
46
+ domain: { id: domain.id },
47
+ name: In(names)
48
+ })
49
+ return true
50
+ }
51
+
52
+ @Mutation(returns => GoodsReceivalNote)
53
+ @Directive('@transaction')
54
+ async receivedGoodsReceivalNote(
55
+ @Arg('name') name: string,
56
+ @Ctx() context: ResolverContext
57
+ ): Promise<GoodsReceivalNote> {
58
+ const { tx, domain, user } = context.state
59
+
60
+ const goodsReceivalNote = await tx.getRepository(GoodsReceivalNote).findOne({
61
+ where: { domain: { id: domain.id }, name }
62
+ })
63
+
64
+ return await tx.getRepository(GoodsReceivalNote).save({
65
+ ...goodsReceivalNote,
66
+ status: GRN_STATUS.RECEIVED,
67
+ customerStatus: GRN_STATUS.RECEIVED,
68
+ updater: user
69
+ })
70
+ }
71
+
72
+ @Mutation(returns => GoodsReceivalNote)
73
+ @Directive('@transaction')
74
+ async sendGoodsReceivalNote(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<GoodsReceivalNote> {
75
+ const { tx, domain, user } = context.state
76
+
77
+ const goodsReceivalNote = await tx.getRepository(GoodsReceivalNote).findOne({
78
+ where: { domain: { id: domain.id }, name }
79
+ })
80
+
81
+ return await tx.getRepository(GoodsReceivalNote).save({
82
+ ...goodsReceivalNote,
83
+ status: GRN_STATUS.SENT,
84
+ customerStatus: GRN_STATUS.PENDING_RECEIVE,
85
+ updater: user
86
+ })
87
+ }
88
+ }
89
+
90
+ export async function generateGoodsReceivalNote(
91
+ grn: { refNo: string; customer: string },
92
+ domain: Domain,
93
+ user: User,
94
+ tx?: EntityManager
95
+ ): Promise<GoodsReceivalNote> {
96
+ // 1. Create grn
97
+ const grnRepo: Repository<GoodsReceivalNote> =
98
+ tx?.getRepository(GoodsReceivalNote) || getRepository(GoodsReceivalNote)
99
+ const bizplaceRepo: Repository<Bizplace> = tx?.getRepository(Bizplace) || getRepository(Bizplace)
100
+ const ganRepo: Repository<ArrivalNotice> = tx?.getRepository(ArrivalNotice) || getRepository(ArrivalNotice)
101
+ const settingRepo: Repository<Setting> = tx?.getRepository(Setting) || getRepository(Setting)
102
+ let orderNo: string = ''
103
+
104
+ const bizplace: Bizplace = await bizplaceRepo.findOne({ where: { id: grn.customer } })
105
+ const arrivalNotice: ArrivalNotice = await ganRepo.findOne({ where: { domain: { id: domain.id }, name: grn.refNo } })
106
+ const grnNoSetting: Setting = await settingRepo.findOne({
107
+ where: {
108
+ domain: { id: domain.id },
109
+ name: ORDER_NUMBER_SETTING_KEY.GRN_NUMBER_RULE
110
+ }
111
+ })
112
+
113
+ if (grnNoSetting) {
114
+ orderNo = await generateId({ domain, type: ORDER_NUMBER_RULE_TYPE.GRN_NUMBER, seed: {} })
115
+ } else {
116
+ orderNo = OrderNoGenerator.goodsReceiveNote()
117
+ }
118
+
119
+ return await grnRepo.save({
120
+ ...grn,
121
+ name: orderNo,
122
+ domain,
123
+ bizplace,
124
+ arrivalNotice,
125
+ status: GRN_STATUS.PENDING_RECEIVE,
126
+ creator: user,
127
+ updater: user
128
+ })
129
+ }
@@ -0,0 +1,280 @@
1
+ import { Arg, Args, Ctx, FieldResolver, Query, Resolver, Root } from 'type-graphql'
2
+ import { IsNull, Not, OrderByCondition, SelectQueryBuilder } from 'typeorm'
3
+
4
+ import { Partner, User } from '@things-factory/auth-base'
5
+ import { Bizplace, ContactPoint, getPermittedBizplaceIds } from '@things-factory/biz-base'
6
+ import { buildQuery, Domain, getRepository, ListParam } from '@things-factory/shell'
7
+ import { ReducedInventoryHistory } from '@things-factory/warehouse-base'
8
+
9
+ import { GoodsReceivalNoteList } from '../'
10
+ import { DateTimeConverter } from '../../utils/datetime-util'
11
+ import { ArrivalNotice } from '../arrival-notice/arrival-notice'
12
+ import { OrderProduct } from '../order-product/order-product'
13
+ import { GoodsReceivalNote } from './goods-receival-note'
14
+
15
+ @Resolver(GoodsReceivalNote)
16
+ export class GoodsReceivalNoteQuery {
17
+ @Query(returns => GoodsReceivalNoteList)
18
+ async goodsReceivalNotes(
19
+ @Ctx() context: ResolverContext,
20
+ @Args(type => ListParam) params: ListParam
21
+ ): Promise<GoodsReceivalNoteList> {
22
+ const { domain, user } = context.state
23
+
24
+ const fromDateParamIdx = params.filters.findIndex(param => param.name === 'fromDate')
25
+ if (fromDateParamIdx >= 0) {
26
+ let fromDateVal = new Date(params.filters[fromDateParamIdx].value)
27
+ params.filters.splice(fromDateParamIdx, 1)
28
+
29
+ params.filters.push({
30
+ name: 'createdAt',
31
+ operator: 'gte',
32
+ value: fromDateVal.toISOString(),
33
+ relation: false
34
+ })
35
+ }
36
+
37
+ const toDateParamIdx = params.filters.findIndex(param => param.name === 'toDate')
38
+ if (toDateParamIdx >= 0) {
39
+ let toDateVal = new Date(params.filters[toDateParamIdx].value)
40
+ params.filters.splice(toDateParamIdx, 1)
41
+
42
+ params.filters.push({
43
+ name: 'createdAt',
44
+ operator: 'lt',
45
+ value: new Date(toDateVal.setDate(toDateVal.getDate() + 1)).toISOString(),
46
+ relation: false
47
+ })
48
+ }
49
+
50
+ let refNoFilter = params.filters.find(x => x.name == 'refNo')
51
+ let refNo2Filter = params.filters.find(x => x.name == 'refNo2')
52
+ let refNo3Filter = params.filters.find(x => x.name == 'refNo3')
53
+ let ganNameFilter = params.filters.find(x => x.name == 'arrivalNoticeNo')
54
+ let bizplaceFilter = params.filters.find(x => x.name == 'bizplaceName')
55
+ let ganStatusFilter = params.filters.find(x => x.name == 'ganStatus')
56
+ let grnStatusFilter = params.filters.find(x => x.name == 'grnStatus')
57
+ let orderProductsApiFilter = params.filters.find(x => x.name == 'orderProductsApi')
58
+
59
+ params.filters = params.filters.filter(
60
+ x =>
61
+ x.name != 'refNo' &&
62
+ x.name != 'refNo2' &&
63
+ x.name != 'refNo3' &&
64
+ x.name != 'arrivalNoticeNo' &&
65
+ x.name != 'bizplaceName' &&
66
+ x.name != 'ganStatus' &&
67
+ x.name != 'grnStatus'
68
+ )
69
+
70
+ const qb: SelectQueryBuilder<GoodsReceivalNote> = getRepository(GoodsReceivalNote).createQueryBuilder('grn')
71
+ buildQuery(qb, params, context)
72
+ qb.addSelect('COALESCE("cc".rank, 9999)', 'rank')
73
+ qb.leftJoinAndSelect('grn.domain', 'domain')
74
+ qb.leftJoinAndSelect('grn.bizplace', 'bizplace')
75
+ qb.leftJoinAndSelect('grn.creator', 'creator')
76
+ qb.leftJoinAndSelect('grn.updater', 'updater')
77
+ qb.innerJoinAndSelect('grn.arrivalNotice', 'arrivalNotice')
78
+ if (orderProductsApiFilter?.value) {
79
+ qb.innerJoinAndSelect('arrivalNotice.orderProducts', 'orderProducts')
80
+ qb.innerJoinAndSelect('orderProducts.product', 'product')
81
+ }
82
+ qb.leftJoin(
83
+ subQuery => {
84
+ return subQuery
85
+ .select(`ccd.rank`, 'rank')
86
+ .addSelect(`ccd.name`, 'status')
87
+ .from(`common_code_details`, 'ccd')
88
+ .innerJoin(`ccd.commonCode`, 'cc')
89
+ .where(`ccd.domain_id = :domainId`, { domainId: domain.id })
90
+ .andWhere(`cc.name = 'GRN_STATUS'`)
91
+ .andWhere(`cc.name = 'GAN_REQUESTS_STATUS'`)
92
+ },
93
+ 'cc',
94
+ 'cc.status = arrivalNotice.status'
95
+ )
96
+
97
+ let permittedBizplaceIds = await getPermittedBizplaceIds(domain, user)
98
+ qb.andWhere('grn.bizplace_id IN (:...bizplaceIds)', { bizplaceIds: permittedBizplaceIds })
99
+
100
+ if (refNoFilter?.value) {
101
+ qb.andWhere('arrivalNotice.ref_no ilike :refNo', { refNo: refNoFilter.value })
102
+ }
103
+ if (refNo2Filter?.value) {
104
+ qb.andWhere('arrivalNotice.ref_no_2 ilike :refNo2', { refNo2: refNo2Filter.value })
105
+ }
106
+ if (refNo3Filter?.value) {
107
+ qb.andWhere('arrivalNotice.ref_no_3 ilike :refNo3', { refNo3: refNo3Filter.value })
108
+ }
109
+ if (ganNameFilter?.value) {
110
+ qb.andWhere('arrivalNotice.name ilike :ganName', { ganName: ganNameFilter.value })
111
+ }
112
+ if (bizplaceFilter?.value) {
113
+ qb.andWhere('bizplace.name ilike :bizName', { bizName: bizplaceFilter.value })
114
+ }
115
+
116
+ if (ganStatusFilter?.value) {
117
+ qb.andWhere('arrivalNotice.status ilike :ganStatus', { ganStatus: ganStatusFilter.value })
118
+ }
119
+ if (grnStatusFilter?.value) {
120
+ qb.andWhere('grn.status ilike :grnStatus', { grnStatus: grnStatusFilter.value })
121
+ }
122
+
123
+ const arrChildSortData = ['refNo', 'refNo2', 'refNo3']
124
+ const arrNameSortData = ['bizplace', 'arrivalNotice', 'updater']
125
+ const arrGanStatusSortData = ['ganStatus']
126
+ const arrGrnStatuSortData = ['status']
127
+ const sort: OrderByCondition = (params.sortings || []).reduce(
128
+ (acc, sort) => ({
129
+ ...acc,
130
+ [arrChildSortData.indexOf(sort.name) >= 0
131
+ ? 'arrivalNotice.' + sort.name
132
+ : arrNameSortData.indexOf(sort.name) >= 0
133
+ ? sort.name + '.name'
134
+ : arrGanStatusSortData.indexOf(sort.name) >= 0
135
+ ? 'arrivalNotice.status'
136
+ : arrGrnStatuSortData.indexOf(sort.name) >= 0
137
+ ? 'grn.status'
138
+ : 'grn.' + sort.name]: sort.desc ? 'DESC' : 'ASC'
139
+ }),
140
+ !params.sortings.some(e => e.name === 'status') ? { rank: 'ASC' } : {}
141
+ )
142
+
143
+ qb.orderBy(sort)
144
+
145
+ const [items, total] = await qb.getManyAndCount()
146
+
147
+ return { items, total }
148
+ }
149
+
150
+ @Query(returns => GoodsReceivalNote)
151
+ async goodsReceivalNote(
152
+ @Arg('name') name: string,
153
+ @Arg('timezoneOffSet') timezoneOffSet: string,
154
+ @Ctx() context: ResolverContext
155
+ ): Promise<any> {
156
+ const { domain } = context.state
157
+
158
+ const foundGRN: GoodsReceivalNote = await getRepository(GoodsReceivalNote).findOne({
159
+ where: { domain: { id: domain.id }, name },
160
+ relations: [
161
+ 'domain',
162
+ 'bizplace',
163
+ 'bizplace.domain',
164
+ 'bizplace.company',
165
+ 'arrivalNotice',
166
+ 'arrivalNotice.purchaseOrder'
167
+ ]
168
+ })
169
+
170
+ const foundGAN: ArrivalNotice = foundGRN.arrivalNotice
171
+ const ownRefNo = foundGAN.refNo
172
+
173
+ const partnerBiz: Bizplace = foundGRN.bizplace
174
+
175
+ const partnerDomain: Partner = await getRepository(Partner).findOne({
176
+ where: { partnerDomain: { id: partnerBiz.domain.id }, domain: { id: domain.id } },
177
+ relations: ['domain']
178
+ })
179
+
180
+ const domainOwner: Domain = partnerDomain.domain
181
+ const domainBizplace: Bizplace = await getRepository(Bizplace).findOne({
182
+ where: { domain: { id: domainOwner.id } },
183
+ relations: ['company']
184
+ })
185
+
186
+ const qbReducedInventory = await getRepository(ReducedInventoryHistory)
187
+ .createQueryBuilder('ivh')
188
+ .select('product_id', 'productId')
189
+ .addSelect('batch_id', 'batchId')
190
+ .addSelect('reusable_pallet_id', 'reusablePalletId')
191
+ .addSelect('packing_type', 'packingType')
192
+ .addSelect('sum(qty)', 'qty')
193
+ .addSelect('sum(uom_value)', 'uomValue')
194
+ .addSelect('uom', 'uom')
195
+ .addSelect('count(distinct pallet_id)', 'pallet')
196
+ .addSelect(`string_agg(distinct expiration_date::varchar,', ' order by expiration_date::varchar)`, 'expiryDate')
197
+ .addSelect(`string_agg(distinct pallet_id::varchar,', ' order by pallet_id::varchar)`, 'palletId')
198
+ .where('ivh.domain_id = :domainId', { domainId: domain.id })
199
+ .andWhere('ivh.ref_order_id = :refOrderId', { refOrderId: foundGAN.id })
200
+ .andWhere(`ivh.transaction_type = 'UNLOADING'`)
201
+ .groupBy('reusable_pallet_id')
202
+ .addGroupBy('product_id')
203
+ .addGroupBy('batch_id')
204
+ .addGroupBy('packing_type')
205
+ .addGroupBy('uom')
206
+ .getRawMany()
207
+
208
+ // 5. find domain contact point
209
+ const foundCP: ContactPoint = await getRepository(ContactPoint).findOne({
210
+ where: { domain: { id: domain.id }, bizplace: { id: domainBizplace.id } }
211
+ })
212
+
213
+ const inboundInventories: any[] = await qbReducedInventory
214
+
215
+ const targetProducts: OrderProduct[] = await getRepository(OrderProduct).find({
216
+ where: {
217
+ domain: { id: domain.id },
218
+ arrivalNotice: { id: foundGAN.id },
219
+ actualPalletQty: Not(IsNull()),
220
+ actualPackQty: Not(IsNull())
221
+ },
222
+ relations: ['product', 'arrivalNotice', 'arrivalNotice.purchaseOrder']
223
+ })
224
+
225
+ const data = {
226
+ grnNo: foundGRN.name,
227
+ ganNo: foundGAN.name,
228
+ refGANNo: foundGAN.refNo || '',
229
+ refGANNo2: foundGAN.refNo2 || '',
230
+ refGANNo3: foundGAN.refNo3 || '',
231
+ companyDomain: domainBizplace.company.name,
232
+ supplier: foundCP.name || '',
233
+ date: foundGAN.acceptedAt ? DateTimeConverter.datetime(foundGAN.acceptedAt, timezoneOffSet) : '',
234
+ productLists: targetProducts.map((item, idx) => {
235
+ let unloadInvHistory = inboundInventories.find(
236
+ ih =>
237
+ ih.productId == item.product.id &&
238
+ ih.batchId == item.batchId &&
239
+ ih.packingType == item.packingType &&
240
+ ih.uom == item.uom
241
+ )
242
+
243
+ return {
244
+ list_no: idx + 1,
245
+ po: item?.arrivalNotice?.purchaseOrder?.name ? item?.arrivalNotice?.purchaseOrder.name : '',
246
+ batchNo: item.batchId || '',
247
+ productSKU: `${item.product.sku}`,
248
+ productName: `${item.product.name}(${item.product.description})`,
249
+ productType: item.packingType,
250
+ productBatch: item.batchId,
251
+ expectedQty: item.packQty,
252
+ actualQty: unloadInvHistory.qty || item.actualPackQty,
253
+ actualUomValue: item.uomValue * item.actualPackQty,
254
+ productUom: `${unloadInvHistory.uom || item.uom}`,
255
+ expiryDate: unloadInvHistory.expiryDate || '',
256
+ unitPrice: item.unitPrice.toFixed(2) || 0.0,
257
+ manufactureDate: item.manufactureDate || '',
258
+ remark: (item.remark ? item.remark : '') + (item.issue ? ' [Issue]: ' + item.issue : '')
259
+ }
260
+ })
261
+ }
262
+
263
+ return data
264
+ }
265
+
266
+ @FieldResolver(type => Domain)
267
+ async domain(@Root() goodsReceivalNote: GoodsReceivalNote): Promise<Domain> {
268
+ return await getRepository(Domain).findOneBy({ id: goodsReceivalNote.domainId })
269
+ }
270
+
271
+ @FieldResolver(type => User)
272
+ async creator(@Root() goodsReceivalNote: GoodsReceivalNote): Promise<User> {
273
+ return await getRepository(User).findOneBy({ id: goodsReceivalNote.creatorId })
274
+ }
275
+
276
+ @FieldResolver(type => User)
277
+ async updater(@Root() goodsReceivalNote: GoodsReceivalNote): Promise<User> {
278
+ return await getRepository(User).findOneBy({ id: goodsReceivalNote.updaterId })
279
+ }
280
+ }