@things-factory/sales-base 3.7.15 → 3.8.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 (46) hide show
  1. package/dist-server/constants/validation-error-code.js +2 -1
  2. package/dist-server/constants/validation-error-code.js.map +1 -1
  3. package/dist-server/entities/release-good.js +4 -0
  4. package/dist-server/entities/release-good.js.map +1 -1
  5. package/dist-server/graphql/resolvers/arrival-notice/update-arrival-notice-details.js +28 -0
  6. package/dist-server/graphql/resolvers/arrival-notice/update-arrival-notice-details.js.map +1 -0
  7. package/dist-server/graphql/resolvers/release-good/bulk-add-release-goods.js +213 -0
  8. package/dist-server/graphql/resolvers/release-good/bulk-add-release-goods.js.map +1 -0
  9. package/dist-server/graphql/resolvers/release-good/bulk-release-goods-available-items.js +163 -0
  10. package/dist-server/graphql/resolvers/release-good/bulk-release-goods-available-items.js.map +1 -0
  11. package/dist-server/graphql/resolvers/release-good/generate-release-good.js +2 -1
  12. package/dist-server/graphql/resolvers/release-good/generate-release-good.js.map +1 -1
  13. package/dist-server/graphql/resolvers/release-good/index.js +5 -3
  14. package/dist-server/graphql/resolvers/release-good/index.js.map +1 -1
  15. package/dist-server/graphql/resolvers/release-good/release-good-requests.js +17 -0
  16. package/dist-server/graphql/resolvers/release-good/release-good-requests.js.map +1 -1
  17. package/dist-server/graphql/resolvers/release-good/update-release-good-details.js +4 -5
  18. package/dist-server/graphql/resolvers/release-good/update-release-good-details.js.map +1 -1
  19. package/dist-server/graphql/resolvers/return-order/generate-return-order.js +2 -4
  20. package/dist-server/graphql/resolvers/return-order/generate-return-order.js.map +1 -1
  21. package/dist-server/graphql/types/release-good/index.js +14 -0
  22. package/dist-server/graphql/types/release-good/index.js.map +1 -1
  23. package/dist-server/graphql/types/release-good/new-raw-release-good.js +62 -0
  24. package/dist-server/graphql/types/release-good/new-raw-release-good.js.map +1 -0
  25. package/dist-server/graphql/types/release-good/raw-release-good.js +65 -0
  26. package/dist-server/graphql/types/release-good/raw-release-good.js.map +1 -0
  27. package/dist-server/graphql/types/release-good/release-good.js +1 -0
  28. package/dist-server/graphql/types/release-good/release-good.js.map +1 -1
  29. package/dist-server/utils/inventory-util.js +5 -0
  30. package/dist-server/utils/inventory-util.js.map +1 -1
  31. package/package.json +12 -12
  32. package/server/constants/validation-error-code.ts +3 -2
  33. package/server/entities/release-good.ts +3 -0
  34. package/server/graphql/resolvers/arrival-notice/update-arrival-notice-details.ts +32 -0
  35. package/server/graphql/resolvers/release-good/bulk-add-release-goods.ts +343 -0
  36. package/server/graphql/resolvers/release-good/bulk-release-goods-available-items.ts +207 -0
  37. package/server/graphql/resolvers/release-good/generate-release-good.ts +3 -2
  38. package/server/graphql/resolvers/release-good/index.ts +5 -1
  39. package/server/graphql/resolvers/release-good/release-good-requests.ts +23 -0
  40. package/server/graphql/resolvers/release-good/update-release-good-details.ts +8 -5
  41. package/server/graphql/resolvers/return-order/generate-return-order.ts +6 -6
  42. package/server/graphql/types/release-good/index.ts +14 -0
  43. package/server/graphql/types/release-good/new-raw-release-good.ts +56 -0
  44. package/server/graphql/types/release-good/raw-release-good.ts +59 -0
  45. package/server/graphql/types/release-good/release-good.ts +1 -0
  46. package/server/utils/inventory-util.ts +7 -0
@@ -0,0 +1,343 @@
1
+ import { EntityManager, getRepository, In, Repository } from 'typeorm'
2
+
3
+ import { Role, User } from '@things-factory/auth-base'
4
+ import { Bizplace } from '@things-factory/biz-base'
5
+ import { generateId } from '@things-factory/id-rule-base'
6
+ import { sendNotification } from '@things-factory/notification'
7
+ import { Product } from '@things-factory/product-base'
8
+ import { Setting } from '@things-factory/setting-base'
9
+ import { Domain } from '@things-factory/shell'
10
+
11
+ import { ORDER_STATUS } from '../../../constants'
12
+ import {
13
+ ORDER_INVENTORY_STATUS,
14
+ ORDER_NUMBER_RULE_TYPE,
15
+ ORDER_NUMBER_SETTING_KEY,
16
+ ORDER_PRODUCT_STATUS
17
+ } from '../../../constants/order'
18
+ import { OrderInventory, OrderProduct, ReleaseGood } from '../../../entities'
19
+ import { ValidationError } from '../../../errors'
20
+ import { OrderNoGenerator } from '../../../utils/order-no-generator'
21
+ import { bulkReleaseGoodsAvailableItemsFunction } from './bulk-release-goods-available-items'
22
+
23
+ export const bulkAddReleaseGoods = {
24
+ async bulkAddReleaseGoods(_: any, { rawReleaseGoods, bizplaceId }, context: any) {
25
+ const { domain, user, tx }: { domain: Domain; user: User; tx: EntityManager } = context.state
26
+
27
+ if (!bizplaceId) throw new Error('company ID is not provided')
28
+
29
+ let createdReleaseGoods: ReleaseGood[] = []
30
+ const settingRepo: Repository<Setting> = tx?.getRepository(Setting) || getRepository(Setting)
31
+
32
+ const roNoSetting: Setting = await settingRepo.findOne({
33
+ where: {
34
+ domain,
35
+ name: ORDER_NUMBER_SETTING_KEY.RO_NUMBER_RULE
36
+ }
37
+ })
38
+
39
+ let releaseGoods: Partial<ReleaseGood[]> = extractRawReleaseGoods(rawReleaseGoods)
40
+
41
+ for (let i = 0, l = releaseGoods.length; i < l; i++) {
42
+ // generate release good by group to avoid duplication
43
+ // if this function is called simultaneously by different users
44
+ let availableItems: any[] = await bulkReleaseGoodsAvailableItemsFunction(
45
+ _,
46
+ [...releaseGoods[i].orderInventories],
47
+ bizplaceId,
48
+ context,
49
+ tx
50
+ )
51
+
52
+ if (availableItems.some(item => !item.releaseQty || item.releaseQty > item.assignedQty))
53
+ throw new ValidationError({
54
+ ...ValidationError.ERROR_CODES.INSUFFICIENT_STOCK,
55
+ detail: { data: JSON.stringify(availableItems) }
56
+ })
57
+
58
+ // update orderInventories if availableItems are valid
59
+ releaseGoods[i].orderInventories = availableItems
60
+
61
+ const createdReleaseGood: ReleaseGood = await bulkGenerateReleaseGoods(
62
+ _,
63
+ releaseGoods[i],
64
+ bizplaceId,
65
+ roNoSetting,
66
+ domain,
67
+ user,
68
+ tx
69
+ )
70
+
71
+ createdReleaseGoods.push(createdReleaseGood)
72
+ }
73
+
74
+ let confirmedReleaseGoods: ReleaseGood[] = await bulkConfirmReleaseGoods(
75
+ createdReleaseGoods.map(rg => rg.name),
76
+ domain,
77
+ user,
78
+ context,
79
+ tx
80
+ )
81
+
82
+ return confirmedReleaseGoods
83
+ }
84
+ }
85
+
86
+ async function bulkGenerateReleaseGoods(
87
+ _: any,
88
+ releaseGood: any,
89
+ bizplaceId: string,
90
+ roNoSetting: any,
91
+ domain: Domain,
92
+ user: User,
93
+ tx?: EntityManager
94
+ ): Promise<ReleaseGood> {
95
+ try {
96
+ let warehouseDomain: Domain = domain
97
+ let { orderInventories } = releaseGood
98
+
99
+ let bizplace: Bizplace = await tx.getRepository(Bizplace).findOne(bizplaceId)
100
+
101
+ let newReleaseGood: ReleaseGood = {
102
+ ...releaseGood,
103
+ name: roNoSetting
104
+ ? await generateId({ domain, type: ORDER_NUMBER_RULE_TYPE.RO_NUMBER, seed: {} })
105
+ : OrderNoGenerator.releaseGood(),
106
+ domain: warehouseDomain,
107
+ bizplace: bizplace,
108
+ deliveryAddress1: releaseGood?.deliveryAddress1 || null,
109
+ deliveryAddress2: releaseGood?.deliveryAddress2 || null,
110
+ deliveryAddress3: releaseGood?.deliveryAddress3 || null,
111
+ deliveryAddress4: releaseGood?.deliveryAddress4 || null,
112
+ deliveryAddress5: releaseGood?.deliveryAddress5 || null,
113
+ attentionTo: releaseGood?.attentionTo || null,
114
+ attentionCompany: releaseGood?.attentionCompany || null,
115
+ city: releaseGood?.city || null,
116
+ state: releaseGood?.state || null,
117
+ postalCode: releaseGood?.postalCode || null,
118
+ country: releaseGood?.country || null,
119
+ phone1: releaseGood?.phone1 || null,
120
+ phone2: releaseGood?.phone2 || null,
121
+ email: releaseGood?.email || null,
122
+ airwayBill: releaseGood?.airwayBill,
123
+ refNo: releaseGood.refNo,
124
+ refNo2: releaseGood.refNo2,
125
+ refNo3: releaseGood.refNo3,
126
+ releaseDate: releaseGood.releaseDate,
127
+ ownTransport: releaseGood?.ownTransport || false,
128
+ status: ORDER_STATUS.PENDING,
129
+ creator: user,
130
+ updater: user
131
+ }
132
+
133
+ newReleaseGood = await tx.getRepository(ReleaseGood).save(newReleaseGood)
134
+
135
+ for (let oi of orderInventories) {
136
+ delete oi.sku
137
+
138
+ let newOrderInv: OrderInventory = Object.assign(new OrderInventory(), oi)
139
+ newOrderInv = {
140
+ ...newOrderInv,
141
+ domain: warehouseDomain,
142
+ bizplace: bizplace,
143
+ status: ORDER_INVENTORY_STATUS.PENDING,
144
+ name: OrderNoGenerator.orderInventory(),
145
+ batchId: oi?.batchId || '',
146
+ releaseGood: newReleaseGood,
147
+ product: await tx.getRepository(Product).findOne(oi.productId),
148
+ creator: user,
149
+ updater: user
150
+ }
151
+
152
+ let newOrderProduct: OrderProduct = Object.assign(new OrderProduct(), newOrderInv)
153
+ newOrderProduct = {
154
+ ...newOrderProduct,
155
+ packQty: 0,
156
+ actualPackQty: 0,
157
+ palletQty: 0,
158
+ actualPalletQty: 0,
159
+ status: ORDER_PRODUCT_STATUS.PENDING_ASSIGN
160
+ }
161
+
162
+ newOrderProduct = await tx.getRepository(OrderProduct).save(newOrderProduct)
163
+
164
+ await tx.getRepository(OrderInventory).save({ ...newOrderInv, orderProduct: newOrderProduct })
165
+ }
166
+
167
+ // Change the status to PENDING_RECEIVE
168
+
169
+ return newReleaseGood
170
+ } catch (error) {
171
+ throw error
172
+ }
173
+ }
174
+
175
+ async function bulkConfirmReleaseGoods(
176
+ releaseGoodsNo: string[],
177
+ domain: Domain,
178
+ user: User,
179
+ context: any,
180
+ tx?: EntityManager
181
+ ): Promise<ReleaseGood[]> {
182
+ let foundReleaseGoods: ReleaseGood[] = await tx.getRepository(ReleaseGood).find({
183
+ where: { name: In(releaseGoodsNo), status: ORDER_STATUS.PENDING },
184
+ relations: [
185
+ 'domain',
186
+ 'bizplace',
187
+ 'bizplace.domain',
188
+ 'bizplace.company',
189
+ 'bizplace.company.domain',
190
+ 'orderProducts',
191
+ 'orderProducts.product',
192
+ 'orderInventories',
193
+ 'orderInventories.product',
194
+ 'orderVass'
195
+ ]
196
+ })
197
+
198
+ if (!foundReleaseGoods.length) throw new Error(`Release good order doesn't exists.`)
199
+ let customerBizplace: Bizplace = foundReleaseGoods[0].bizplace
200
+
201
+ let foundOrderInventories: OrderInventory[] = foundReleaseGoods
202
+ .map((releaseGood: ReleaseGood) => releaseGood.orderInventories)
203
+ .reduce((orderInventories, currOIs) => {
204
+ orderInventories.push(...currOIs)
205
+ return orderInventories
206
+ }, [])
207
+
208
+ await tx
209
+ .getRepository(ReleaseGood)
210
+ .update({ id: In(foundReleaseGoods.map(rg => rg.id)) }, { status: ORDER_STATUS.PENDING_RECEIVE, updater: user })
211
+
212
+ await tx
213
+ .getRepository(OrderInventory)
214
+ .update(
215
+ { id: In(foundOrderInventories.map(oi => oi.id)) },
216
+ { status: ORDER_INVENTORY_STATUS.PENDING_RECEIVE, updater: user }
217
+ )
218
+
219
+ if (context?.state?.type != 'api') {
220
+ const users: any[] = await tx
221
+ .getRepository('users_roles')
222
+ .createQueryBuilder('ur')
223
+ .select('ur.users_id', 'id')
224
+ .where(qb => {
225
+ const subQuery = qb
226
+ .subQuery()
227
+ .select('role.id')
228
+ .from(Role, 'role')
229
+ .where("role.name = 'Office Admin'")
230
+ .andWhere('role.domain_id = :domain', { domain: domain.id })
231
+ .getQuery()
232
+ return 'ur.roles_id IN ' + subQuery
233
+ })
234
+ .getRawMany()
235
+
236
+ // send notification to Office Admin Users
237
+ if (users?.length) {
238
+ const receivers: any[] = users.map(user => user.id)
239
+ const msg = {
240
+ title: `New Release Order from ${customerBizplace.name}`,
241
+ body: `New incoming bulk release orders are pending for receiving`,
242
+ url: context.header.referer,
243
+ data: { url: context.header.referer }
244
+ }
245
+ await sendNotification({
246
+ receivers,
247
+ message: { ...msg }
248
+ })
249
+ }
250
+ }
251
+
252
+ return foundReleaseGoods.map((releaseGood: ReleaseGood) => {
253
+ return {
254
+ ...releaseGood,
255
+ status: ORDER_STATUS.PENDING_RECEIVE,
256
+ updater: user
257
+ }
258
+ })
259
+ }
260
+
261
+ function extractRawReleaseGoods(rawReleaseGoods): Partial<ReleaseGood[]> {
262
+ return rawReleaseGoods.reduce((releaseGoods, item) => {
263
+ const idx: number = releaseGoods.findIndex(rg => {
264
+ // consider these attributes if they are exist in "item"
265
+ const comparison = [
266
+ 'refNo2',
267
+ 'refNo3',
268
+ 'attentionTo',
269
+ 'phone1',
270
+ 'deliveryAddress1',
271
+ 'deliveryAddress2',
272
+ 'deliveryAddress3',
273
+ 'deliveryAddress4',
274
+ 'postalCode'
275
+ ]
276
+
277
+ let a: any = {},
278
+ b: any = {}
279
+
280
+ comparison.forEach(cc => {
281
+ if (item[cc]) {
282
+ a[cc] = item[cc]
283
+ b[cc] = rg[cc]
284
+ }
285
+ })
286
+
287
+ a = JSON.stringify(Object.fromEntries(Object.entries(a).sort()))
288
+ b = JSON.stringify(Object.fromEntries(Object.entries(b).sort()))
289
+
290
+ return rg.refNo == item.refNo && rg.releaseDate == item.releaseDate && a === b
291
+ })
292
+
293
+ if (idx >= 0) {
294
+ const duplicateSkuIdx: number = releaseGoods[idx].orderInventories.findIndex(
295
+ oi => oi.sku === item.sku && oi.packingType === item.packingType && oi.packingSize === item.packingSize
296
+ )
297
+
298
+ if (duplicateSkuIdx >= 0) {
299
+ releaseGoods[idx].orderInventories[duplicateSkuIdx].releaseQty += item.releaseQty
300
+ } else {
301
+ releaseGoods[idx].orderInventories.push({
302
+ sku: item.sku,
303
+ productId: item.productId,
304
+ packingType: item.packingType,
305
+ packingSize: item.packingSize,
306
+ uom: item.uom,
307
+ releaseQty: item.releaseQty,
308
+ releaseUomValue: item.releaseUomValue
309
+ })
310
+ }
311
+ } else {
312
+ releaseGoods.push({
313
+ releaseDate: item.releaseDate,
314
+ refNo: item.refNo,
315
+ refNo2: item.refNo2,
316
+ refNo3: item.refNo3,
317
+ attentionTo: item.attentionTo,
318
+ phone1: item.phone1,
319
+ deliveryAddress1: item.deliveryAddress1,
320
+ deliveryAddress2: item.deliveryAddress2,
321
+ deliveryAddress3: item.deliveryAddress3,
322
+ deliveryAddress4: item.deliveryAddress4,
323
+ city: item.city,
324
+ postalCode: item.postalCode,
325
+ state: item.state,
326
+ country: item.country,
327
+ orderInventories: [
328
+ {
329
+ sku: item.sku,
330
+ productId: item.productId,
331
+ packingType: item.packingType,
332
+ packingSize: item.packingSize,
333
+ uom: item.uom,
334
+ releaseQty: item.releaseQty,
335
+ releaseUomValue: item.releaseUomValue
336
+ }
337
+ ]
338
+ })
339
+ }
340
+
341
+ return releaseGoods
342
+ }, [])
343
+ }
@@ -0,0 +1,207 @@
1
+ import { EntityManager } from 'typeorm'
2
+
3
+ import { Bizplace, getCompanyBizplace } from '@things-factory/biz-base'
4
+ import { Domain } from '@things-factory/shell'
5
+
6
+ export const bulkReleaseGoodsAvailableItems = {
7
+ async bulkReleaseGoodsAvailableItems(_: any, { rawReleaseGoods, bizplaceId }, context: any) {
8
+ const { tx }: { tx: EntityManager } = context.state
9
+ const availableItems: any[] = await bulkReleaseGoodsAvailableItemsFunction(
10
+ _,
11
+ rawReleaseGoods,
12
+ bizplaceId,
13
+ context,
14
+ tx
15
+ )
16
+
17
+ return availableItems
18
+ }
19
+ }
20
+
21
+ export async function bulkReleaseGoodsAvailableItemsFunction(
22
+ _: any,
23
+ rawReleaseGoods: any[],
24
+ bizplaceId: string,
25
+ context: any,
26
+ tx?: EntityManager
27
+ ): Promise<any[]> {
28
+ const { domain }: { domain: Domain } = context.state
29
+ const companyBizplaceId: Bizplace = await getCompanyBizplace(null, null, bizplaceId)
30
+
31
+ if (!rawReleaseGoods) return
32
+
33
+ const json_oi = JSON.stringify(
34
+ rawReleaseGoods.map(raw => {
35
+ return {
36
+ sku: raw.sku,
37
+ packing_type: raw.packingType,
38
+ packing_size: raw.packingSize,
39
+ uom: raw.uom,
40
+ release_qty: raw.releaseQty
41
+ }
42
+ })
43
+ )
44
+
45
+ await tx.query(
46
+ `
47
+ CREATE TEMP TABLE temp_order_products(
48
+ product_id VARCHAR(50),
49
+ sku VARCHAR(150),
50
+ packing_type VARCHAR(50),
51
+ packing_size INT,
52
+ uom VARCHAR(10),
53
+ release_qty INT
54
+ );
55
+ `
56
+ )
57
+
58
+ await tx.query(
59
+ `
60
+ INSERT INTO temp_order_products
61
+ SELECT p.id AS product_id, js.sku,
62
+ CASE WHEN js.packing_type NOTNULL AND js.packing_size NOTNULL THEN js.packing_type ELSE pd.packing_type END,
63
+ CASE WHEN js.packing_type NOTNULL AND js.packing_size NOTNULL THEN js.packing_size ELSE pd.packing_size END,
64
+ CASE WHEN js.uom NOTNULL THEN js.uom ELSE pd.uom END,
65
+ js.release_qty
66
+ FROM JSON_POPULATE_RECORDSET(NULL::temp_order_products,'${json_oi}') js
67
+ LEFT JOIN products p ON js.sku = p.sku AND p.bizplace_id = $1
68
+ LEFT JOIN product_details pd ON p.id = pd.product_id AND pd.is_default = TRUE;
69
+ `,
70
+ [companyBizplaceId.id]
71
+ )
72
+
73
+ let availableItems = await tx.query(
74
+ `
75
+ SELECT i.product_id, foo.sku, i.batch_id, i.packing_type, i.packing_size, i.uom,
76
+ SUM(i.qty - COALESCE(i.locked_qty, 0)) - COALESCE(
77
+ (
78
+ SELECT SUM(oi.release_qty) FROM order_inventories oi
79
+ WHERE (
80
+ oi.status = 'PENDING'
81
+ OR oi.status = 'PENDING_RECEIVE'
82
+ OR oi.status = 'PENDING_WORKSHEET'
83
+ OR oi.status = 'PENDING_SPLIT'
84
+ )
85
+ AND oi.inventory_id IS null
86
+ AND oi.product_id = i.product_id::uuid
87
+ AND oi.packing_type = i.packing_type
88
+ AND oi.uom = i.uom
89
+ AND oi.domain_id = $1
90
+ AND oi.bizplace_id = $2
91
+ ), 0) as "remain_qty",
92
+ SUM(i.uom_value - COALESCE(i.locked_uom_value, 0)) - COALESCE(
93
+ (
94
+ SELECT SUM(oi.release_uom_value) FROM order_inventories oi
95
+ WHERE (
96
+ oi.status = 'PENDING'
97
+ OR oi.status = 'PENDING_RECEIVE'
98
+ OR oi.status = 'PENDING_WORKSHEET'
99
+ OR oi.status = 'PENDING_SPLIT'
100
+ )
101
+ AND oi.inventory_id IS null
102
+ AND oi.product_id = i.product_id::uuid
103
+ AND oi.packing_type = i.packing_type
104
+ AND oi.uom = i.uom
105
+ AND oi.domain_id = $1
106
+ AND oi.bizplace_id = $2
107
+ ), 0) as "remain_uom_value"
108
+ FROM inventories i
109
+ INNER JOIN (
110
+ SELECT top.product_id, top.sku, top.packing_type, top.packing_size, top.uom
111
+ FROM temp_order_products top
112
+ GROUP BY top.product_id, top.sku, top.packing_type, top.packing_size, top.uom
113
+ ) AS foo
114
+ ON i.product_id = foo.product_id::uuid
115
+ AND i.packing_type = foo.packing_type
116
+ AND i.packing_size = foo.packing_size
117
+ AND i.uom = foo.uom
118
+ AND i.domain_id = $1
119
+ AND i.bizplace_id = $2
120
+ GROUP BY i.product_id, foo.sku, i.batch_id, i.packing_type, i.packing_size, i.uom
121
+ ORDER BY foo.sku, remain_qty
122
+ `,
123
+ [domain.id, bizplaceId]
124
+ )
125
+
126
+ await tx.query('DROP TABLE temp_order_products')
127
+
128
+ availableItems = availableItems.map(item => {
129
+ return {
130
+ productId: item.product_id,
131
+ sku: item.sku,
132
+ batchId: item.batch_id,
133
+ packingType: item.packing_type,
134
+ packingSize: item.packing_size,
135
+ uom: item.uom,
136
+ remainQty: item.remain_qty,
137
+ remainUomValue: item.remain_uom_value
138
+ }
139
+ })
140
+
141
+ return _extractData(rawReleaseGoods, availableItems)
142
+ }
143
+
144
+ function _extractData(rawData, validatedData) {
145
+ return rawData.map(raw => {
146
+ const idx = validatedData.findIndex(val => {
147
+ const comparison = ['packingType', 'packingSize', 'uom']
148
+
149
+ let a: any = {},
150
+ b: any = {}
151
+
152
+ comparison.forEach(cc => {
153
+ if (raw[cc]) {
154
+ a[cc] = raw[cc]
155
+ b[cc] = val[cc]
156
+ }
157
+ })
158
+
159
+ a = JSON.stringify(Object.fromEntries(Object.entries(a).sort()))
160
+ b = JSON.stringify(Object.fromEntries(Object.entries(b).sort()))
161
+
162
+ return val.sku == raw.sku && a === b
163
+ })
164
+
165
+ let releaseUomValue = 0
166
+
167
+ // if sku is matched, assign qty and product id
168
+ if (idx >= 0) {
169
+ // assign qty to rawData as much as possible
170
+ releaseUomValue =
171
+ (Math.round((validatedData[idx]?.remainUomValue / validatedData[idx]?.remainQty) * 100) / 100) * raw.releaseQty
172
+
173
+ raw.assignedQty =
174
+ validatedData[idx].remainQty >= raw.releaseQty
175
+ ? raw.releaseQty > 0
176
+ ? raw.releaseQty
177
+ : 0
178
+ : validatedData[idx].remainQty
179
+
180
+ raw.assignedUomValue =
181
+ validatedData[idx].remainUomValue >= releaseUomValue
182
+ ? releaseUomValue > 0
183
+ ? releaseUomValue
184
+ : 0
185
+ : validatedData[idx].remainUomValue
186
+
187
+ // deduct qty & uomValue from validateData
188
+ validatedData[idx].remainQty -= raw.assignedQty
189
+ validatedData[idx].remainUomValue -= raw.assignedUomValue
190
+
191
+ raw.productId = validatedData[idx].productId
192
+ raw.packingType = validatedData[idx].packingType
193
+ raw.packingSize = validatedData[idx].packingSize
194
+ raw.uom = validatedData[idx].uom
195
+ raw.batchId = validatedData[idx].batchId
196
+ } else {
197
+ raw.assignedQty = 0
198
+ raw.assignedUomValue = 0
199
+ raw.productId = null
200
+ }
201
+
202
+ return {
203
+ ...raw,
204
+ releaseUomValue
205
+ }
206
+ })
207
+ }
@@ -216,8 +216,6 @@ export async function generateReleaseGoodFunction(
216
216
  newReleaseGood.arrivalNotice = crossDockingGAN
217
217
  }
218
218
 
219
- newReleaseGood = await tx.getRepository(ReleaseGood).save(newReleaseGood)
220
-
221
219
  // Make relation with RO for cross docking
222
220
  if (newReleaseGood.crossDocking) {
223
221
  crossDockingGAN.releaseGood = newReleaseGood
@@ -267,6 +265,9 @@ export async function generateReleaseGoodFunction(
267
265
 
268
266
  orderInventories = [...singleProductOIs, ...splitBundleOIs]
269
267
 
268
+ newReleaseGood.noOfItems = orderInventories.length
269
+ newReleaseGood = await tx.getRepository(ReleaseGood).save(newReleaseGood)
270
+
270
271
  for (let oi of orderInventories) {
271
272
  let newOrderInv: OrderInventory = Object.assign({}, oi)
272
273
  newOrderInv = {
@@ -1,5 +1,7 @@
1
- import { confirmReleaseGoodResolver } from './confirm-release-good'
2
1
  import { addReleaseGood } from './add-release-good'
2
+ import { bulkAddReleaseGoods } from './bulk-add-release-goods'
3
+ import { bulkReleaseGoodsAvailableItems } from './bulk-release-goods-available-items'
4
+ import { confirmReleaseGoodResolver } from './confirm-release-good'
3
5
  import { deleteReleaseGoodResolver } from './delete-release-good'
4
6
  import { deleteReleaseGoods } from './delete-release-goods'
5
7
  import { generateReleaseGood } from './generate-release-good'
@@ -13,6 +15,7 @@ import { releaseGoodsResolver } from './release-goods'
13
15
  import { updateReleaseGoodDetailsResolver } from './update-release-good-details'
14
16
 
15
17
  export const Query = {
18
+ ...bulkReleaseGoodsAvailableItems,
16
19
  ...releaseGoodsResolver,
17
20
  ...releaseGoodResolver,
18
21
  ...releaseGoodRequestsResolver,
@@ -21,6 +24,7 @@ export const Query = {
21
24
  }
22
25
 
23
26
  export const Mutation = {
27
+ ...bulkAddReleaseGoods,
24
28
  ...deleteReleaseGoodResolver,
25
29
  ...deleteReleaseGoods,
26
30
  ...confirmReleaseGoodResolver,
@@ -14,6 +14,8 @@ export const releaseGoodRequestsResolver = {
14
14
 
15
15
  const statusFilter = params.filters.some(e => e.name === 'status')
16
16
  const bizplaceFilter = params.filters.find(param => param.name === 'bizplaceId')
17
+ const noOfItemsFilter = params.filters.find(param => param.name === 'noOfItems')
18
+ const skuFilter = params.filters.find(param => param.name === 'sku')
17
19
 
18
20
  if (!statusFilter) {
19
21
  params.filters.push({
@@ -33,6 +35,10 @@ export const releaseGoodRequestsResolver = {
33
35
  })
34
36
  }
35
37
 
38
+ if (skuFilter) {
39
+ params.filters = params.filters.filter(param => param.name !== 'sku')
40
+ }
41
+
36
42
  const fromDateParamIdx = params.filters.findIndex(param => param.name === 'fromDate')
37
43
  if (fromDateParamIdx >= 0) {
38
44
  let fromDateVal = new Date(params.filters[fromDateParamIdx].value)
@@ -59,6 +65,10 @@ export const releaseGoodRequestsResolver = {
59
65
  })
60
66
  }
61
67
 
68
+ if (noOfItemsFilter && noOfItemsFilter.value == 1) {
69
+ params.filters.find(param => param.name === 'noOfItems').operator = 'eq'
70
+ }
71
+
62
72
  const qb: SelectQueryBuilder<ReleaseGood> = getRepository(ReleaseGood).createQueryBuilder('rg')
63
73
  buildQuery(qb, params, context)
64
74
  qb.addSelect('COALESCE("cc".rank, 99999)', 'rank')
@@ -83,6 +93,19 @@ export const releaseGoodRequestsResolver = {
83
93
  'cc.status = rg.status'
84
94
  )
85
95
 
96
+ if (skuFilter) {
97
+ qb.andWhere(
98
+ `
99
+ exists (select * from order_inventories oi
100
+ inner join products p on oi.product_id = p.id
101
+ inner join inventories i on i.product_id = p.id
102
+ where oi.release_good_id = rg.id
103
+ and lower(p.sku) like :sku)
104
+ `,
105
+ { sku: skuFilter.value.toLowerCase() }
106
+ )
107
+ }
108
+
86
109
  const arrChildSortData = ['bizplace', 'creator']
87
110
  const sort = (params.sortings || []).reduce(
88
111
  (acc, sort) => ({
@@ -28,12 +28,12 @@ export async function updateReleaseGoodFunction(
28
28
  ) {
29
29
  const { domain, user }: { domain: Domain; user: User } = context.state
30
30
  let foundReleaseGood = await tx.getRepository(ReleaseGood).findOne({
31
- where: { id: releaseGood.id, name: releaseGood.name, domain },
31
+ where: { id: releaseGood.id, domain },
32
32
  relations: ['shippingOrder']
33
33
  })
34
34
 
35
35
  if (!foundReleaseGood) {
36
- throw new Error(`Release Order ${releaseGood.name} is not found.`)
36
+ throw new Error(`Release order ${releaseGood.name} is not found.`)
37
37
  }
38
38
 
39
39
  // case to update existing shippingOrder
@@ -55,7 +55,10 @@ export async function updateReleaseGoodFunction(
55
55
  releaseGood.shippingOrder = newShippingOrder
56
56
  }
57
57
 
58
- await tx.getRepository(ReleaseGood).update(foundReleaseGood.id, releaseGood)
59
- // return updated Release Good
60
- return await tx.getRepository(ReleaseGood).findOne(foundReleaseGood.id)
58
+ foundReleaseGood = await tx.getRepository(ReleaseGood).save({
59
+ ...foundReleaseGood,
60
+ ...releaseGood
61
+ })
62
+
63
+ return foundReleaseGood
61
64
  }