@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.
- package/dist-server/constants/validation-error-code.js +2 -1
- package/dist-server/constants/validation-error-code.js.map +1 -1
- package/dist-server/entities/release-good.js +4 -0
- package/dist-server/entities/release-good.js.map +1 -1
- package/dist-server/graphql/resolvers/arrival-notice/update-arrival-notice-details.js +28 -0
- package/dist-server/graphql/resolvers/arrival-notice/update-arrival-notice-details.js.map +1 -0
- package/dist-server/graphql/resolvers/release-good/bulk-add-release-goods.js +213 -0
- package/dist-server/graphql/resolvers/release-good/bulk-add-release-goods.js.map +1 -0
- package/dist-server/graphql/resolvers/release-good/bulk-release-goods-available-items.js +163 -0
- package/dist-server/graphql/resolvers/release-good/bulk-release-goods-available-items.js.map +1 -0
- package/dist-server/graphql/resolvers/release-good/generate-release-good.js +2 -1
- package/dist-server/graphql/resolvers/release-good/generate-release-good.js.map +1 -1
- package/dist-server/graphql/resolvers/release-good/index.js +5 -3
- package/dist-server/graphql/resolvers/release-good/index.js.map +1 -1
- package/dist-server/graphql/resolvers/release-good/release-good-requests.js +17 -0
- package/dist-server/graphql/resolvers/release-good/release-good-requests.js.map +1 -1
- package/dist-server/graphql/resolvers/release-good/update-release-good-details.js +4 -5
- package/dist-server/graphql/resolvers/release-good/update-release-good-details.js.map +1 -1
- package/dist-server/graphql/resolvers/return-order/generate-return-order.js +2 -4
- package/dist-server/graphql/resolvers/return-order/generate-return-order.js.map +1 -1
- package/dist-server/graphql/types/release-good/index.js +14 -0
- package/dist-server/graphql/types/release-good/index.js.map +1 -1
- package/dist-server/graphql/types/release-good/new-raw-release-good.js +62 -0
- package/dist-server/graphql/types/release-good/new-raw-release-good.js.map +1 -0
- package/dist-server/graphql/types/release-good/raw-release-good.js +65 -0
- package/dist-server/graphql/types/release-good/raw-release-good.js.map +1 -0
- package/dist-server/graphql/types/release-good/release-good.js +1 -0
- package/dist-server/graphql/types/release-good/release-good.js.map +1 -1
- package/dist-server/utils/inventory-util.js +5 -0
- package/dist-server/utils/inventory-util.js.map +1 -1
- package/package.json +12 -12
- package/server/constants/validation-error-code.ts +3 -2
- package/server/entities/release-good.ts +3 -0
- package/server/graphql/resolvers/arrival-notice/update-arrival-notice-details.ts +32 -0
- package/server/graphql/resolvers/release-good/bulk-add-release-goods.ts +343 -0
- package/server/graphql/resolvers/release-good/bulk-release-goods-available-items.ts +207 -0
- package/server/graphql/resolvers/release-good/generate-release-good.ts +3 -2
- package/server/graphql/resolvers/release-good/index.ts +5 -1
- package/server/graphql/resolvers/release-good/release-good-requests.ts +23 -0
- package/server/graphql/resolvers/release-good/update-release-good-details.ts +8 -5
- package/server/graphql/resolvers/return-order/generate-return-order.ts +6 -6
- package/server/graphql/types/release-good/index.ts +14 -0
- package/server/graphql/types/release-good/new-raw-release-good.ts +56 -0
- package/server/graphql/types/release-good/raw-release-good.ts +59 -0
- package/server/graphql/types/release-good/release-good.ts +1 -0
- 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,
|
|
31
|
+
where: { id: releaseGood.id, domain },
|
|
32
32
|
relations: ['shippingOrder']
|
|
33
33
|
})
|
|
34
34
|
|
|
35
35
|
if (!foundReleaseGood) {
|
|
36
|
-
throw new Error(`Release
|
|
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).
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
foundReleaseGood = await tx.getRepository(ReleaseGood).save({
|
|
59
|
+
...foundReleaseGood,
|
|
60
|
+
...releaseGood
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
return foundReleaseGood
|
|
61
64
|
}
|