@things-factory/sales-base 4.3.677 → 4.3.679
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/service/draft-release-good/draft-release-good-create.js +35 -12
- package/dist-server/service/draft-release-good/draft-release-good-create.js.map +1 -1
- package/dist-server/service/draft-release-good/draft-release-good-mutation.js +3 -1
- package/dist-server/service/draft-release-good/draft-release-good-mutation.js.map +1 -1
- package/dist-server/service/draft-release-good/draft-release-good-query.js +39 -24
- package/dist-server/service/draft-release-good/draft-release-good-query.js.map +1 -1
- package/dist-server/service/order-product/order-product.js +5 -0
- package/dist-server/service/order-product/order-product.js.map +1 -1
- package/dist-server/service/release-good/release-good-query.js +27 -9
- package/dist-server/service/release-good/release-good-query.js.map +1 -1
- package/dist-server/utils/inventory-util.js +40 -3
- package/dist-server/utils/inventory-util.js.map +1 -1
- package/package.json +3 -3
- package/server/service/draft-release-good/draft-release-good-create.ts +54 -54
- package/server/service/draft-release-good/draft-release-good-mutation.ts +2 -1
- package/server/service/draft-release-good/draft-release-good-query.ts +51 -22
- package/server/service/order-product/order-product.ts +8 -4
- package/server/service/release-good/release-good-query.ts +36 -13
- package/server/utils/inventory-util.ts +41 -3
|
@@ -1,53 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
Ctx,
|
|
4
|
-
Directive,
|
|
5
|
-
Mutation,
|
|
6
|
-
Resolver
|
|
7
|
-
} from 'type-graphql'
|
|
8
|
-
import {
|
|
9
|
-
EntityManager,
|
|
10
|
-
getConnection,
|
|
11
|
-
getRepository,
|
|
12
|
-
In,
|
|
13
|
-
Repository
|
|
14
|
-
} from 'typeorm'
|
|
1
|
+
import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
|
|
2
|
+
import { EntityManager, getConnection, getRepository, In, Repository } from 'typeorm'
|
|
15
3
|
|
|
16
4
|
import { Bizplace } from '@things-factory/biz-base'
|
|
17
5
|
import { logger } from '@things-factory/env'
|
|
18
|
-
import {
|
|
19
|
-
WebhookEventsEnum,
|
|
20
|
-
webhookHandler
|
|
21
|
-
} from '@things-factory/integration-base'
|
|
6
|
+
import { WebhookEventsEnum, webhookHandler } from '@things-factory/integration-base'
|
|
22
7
|
import { ProductBundle } from '@things-factory/product-base'
|
|
23
|
-
import {
|
|
24
|
-
PartnerSetting,
|
|
25
|
-
Setting
|
|
26
|
-
} from '@things-factory/setting-base'
|
|
8
|
+
import { PartnerSetting, Setting } from '@things-factory/setting-base'
|
|
27
9
|
import { Domain } from '@things-factory/shell'
|
|
28
10
|
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
DraftReleaseGood,
|
|
32
|
-
DraftReleaseGoodInfos,
|
|
33
|
-
OrderProduct
|
|
34
|
-
} from '../'
|
|
35
|
-
import {
|
|
36
|
-
DRAFT_RELEASE_ORDER_STATUS,
|
|
37
|
-
ORDER_NUMBER_SETTING_KEY,
|
|
38
|
-
ORDER_STATUS
|
|
39
|
-
} from '../../constants'
|
|
11
|
+
import { bulkReleaseGoodsAvailableItemsFunction, DraftReleaseGood, DraftReleaseGoodInfos, OrderProduct } from '../'
|
|
12
|
+
import { DRAFT_RELEASE_ORDER_STATUS, ORDER_NUMBER_SETTING_KEY, ORDER_STATUS } from '../../constants'
|
|
40
13
|
import { ValidationError } from '../../errors'
|
|
41
|
-
import {
|
|
42
|
-
InventoryUtil,
|
|
43
|
-
OrderNoGenerator
|
|
44
|
-
} from '../../utils'
|
|
14
|
+
import { InventoryUtil, OrderNoGenerator } from '../../utils'
|
|
45
15
|
import { ReleaseGood } from '../release-good/release-good'
|
|
46
|
-
import {
|
|
47
|
-
bulkGenerateReleaseGood,
|
|
48
|
-
confirmReleaseGood,
|
|
49
|
-
receiveReleaseGood
|
|
50
|
-
} from '../release-good/release-good-mutation'
|
|
16
|
+
import { bulkGenerateReleaseGood, confirmReleaseGood, receiveReleaseGood } from '../release-good/release-good-mutation'
|
|
51
17
|
import { SuccessReleasedDraftOrder } from './draft-release-good-type'
|
|
52
18
|
|
|
53
19
|
@Resolver(DraftReleaseGood)
|
|
@@ -171,18 +137,42 @@ export async function generateReleaseGoods(_generateReleaseGoodsRecord, context:
|
|
|
171
137
|
}
|
|
172
138
|
}
|
|
173
139
|
|
|
174
|
-
|
|
175
|
-
|
|
140
|
+
// Derive common warehouseCode across lines (if any) and collect batchIds
|
|
141
|
+
const warehouseCodes = Array.from(
|
|
142
|
+
new Set(
|
|
143
|
+
draftOrder.orderProducts
|
|
144
|
+
.map((op: any) => (op?.warehouseCode ? String(op.warehouseCode).trim() : ''))
|
|
145
|
+
.filter(Boolean)
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
const commonWarehouseCode = warehouseCodes.length === 1 ? warehouseCodes[0] : undefined
|
|
149
|
+
const batchIds = Array.from(
|
|
150
|
+
new Set(
|
|
151
|
+
draftOrder.orderProducts
|
|
152
|
+
.map((op: any) => (op?.batchId ? String(op.batchId).trim() : ''))
|
|
153
|
+
.filter(Boolean)
|
|
154
|
+
)
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
const filters: any[] = [
|
|
176
158
|
{
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
operator: 'in',
|
|
181
|
-
value: productIds
|
|
182
|
-
},
|
|
183
|
-
{ name: 'deleted_at', operator: 'eq', value: true }
|
|
184
|
-
]
|
|
159
|
+
name: 'productId',
|
|
160
|
+
operator: 'in',
|
|
161
|
+
value: productIds
|
|
185
162
|
},
|
|
163
|
+
{ name: 'deleted_at', operator: 'eq', value: true }
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
if (commonWarehouseCode) {
|
|
167
|
+
filters.push({ name: 'warehouseCode', operator: 'eq', value: commonWarehouseCode })
|
|
168
|
+
if (batchIds.length > 0) {
|
|
169
|
+
filters.push({ name: 'batchId', operator: 'in', value: batchIds })
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
let productInventory = await InventoryUtil.bizplaceProductInventory(
|
|
174
|
+
bizplaces,
|
|
175
|
+
{ filters },
|
|
186
176
|
context,
|
|
187
177
|
innerTx1
|
|
188
178
|
)
|
|
@@ -268,7 +258,12 @@ export async function generateReleaseGoods(_generateReleaseGoodsRecord, context:
|
|
|
268
258
|
releaseQty: itm.releaseQty,
|
|
269
259
|
assignedQty: undefined,
|
|
270
260
|
assignedUomValue: undefined,
|
|
271
|
-
releaseUomValue: itm.releaseUomValue
|
|
261
|
+
releaseUomValue: itm.releaseUomValue,
|
|
262
|
+
refNo: draftOrder.refNo || '',
|
|
263
|
+
releaseDate: draftOrder.releaseDate || null,
|
|
264
|
+
// propagate filters to availability function
|
|
265
|
+
batchId: itm?.batchId || null,
|
|
266
|
+
warehouseCode: itm?.warehouseCode ? String(itm.warehouseCode).trim() : null
|
|
272
267
|
}
|
|
273
268
|
]
|
|
274
269
|
}
|
|
@@ -631,7 +626,12 @@ export async function generatePartialReleaseGoods(_generatePartialReleaseGoodsRe
|
|
|
631
626
|
releaseQty: itm.releaseQty,
|
|
632
627
|
assignedQty: undefined,
|
|
633
628
|
assignedUomValue: undefined,
|
|
634
|
-
releaseUomValue: itm.releaseUomValue
|
|
629
|
+
releaseUomValue: itm.releaseUomValue,
|
|
630
|
+
refNo: draftOrder.refNo || '',
|
|
631
|
+
releaseDate: draftOrder.releaseDate || null,
|
|
632
|
+
// propagate filters to availability function
|
|
633
|
+
batchId: itm?.batchId || null,
|
|
634
|
+
warehouseCode: itm?.warehouseCode ? String(itm.warehouseCode).trim() : null
|
|
635
635
|
}
|
|
636
636
|
]
|
|
637
637
|
}
|
|
@@ -499,7 +499,8 @@ export async function upsertDraftReleaseGoodProducts(
|
|
|
499
499
|
...existingOP,
|
|
500
500
|
...op,
|
|
501
501
|
domain,
|
|
502
|
-
batchId
|
|
502
|
+
// Preserve batchId for product lines; bundles must not carry batchId
|
|
503
|
+
batchId: op?.warehouseCode ? (op?.batchId ? String(op.batchId).trim() : existingOP?.batchId || '') : '',
|
|
503
504
|
packQty: 0,
|
|
504
505
|
actualPackQty: 0,
|
|
505
506
|
palletQty: 0,
|
|
@@ -271,35 +271,62 @@ export async function getDraftReleaseGoodFunction(_: any, context: any, id?: any
|
|
|
271
271
|
const bizplaces: Bizplace[] = [foundPermittedBizplace, companyBizplace]
|
|
272
272
|
|
|
273
273
|
let productInventory
|
|
274
|
-
if (result.orderProducts.length > 0)
|
|
274
|
+
if (result.orderProducts.length > 0) {
|
|
275
|
+
// derive common warehouseCode (assumed same across all orderProducts when provided)
|
|
276
|
+
const warehouseCodes = Array.from(
|
|
277
|
+
new Set(
|
|
278
|
+
result.orderProducts
|
|
279
|
+
.map((op: any) => (op?.warehouseCode ? String(op.warehouseCode).trim() : ''))
|
|
280
|
+
.filter(Boolean)
|
|
281
|
+
)
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
const commonWarehouseCode = warehouseCodes.length === 1 ? warehouseCodes[0] : undefined
|
|
285
|
+
|
|
286
|
+
// collect batchIds (may be different per op)
|
|
287
|
+
const batchIds = Array.from(
|
|
288
|
+
new Set(result.orderProducts.map((op: any) => (op?.batchId ? String(op.batchId).trim() : '')).filter(Boolean))
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
const baseFilters: any[] = [
|
|
292
|
+
{ name: 'bizplaceId', operator: 'eq', value: result.bizplace.id },
|
|
293
|
+
{
|
|
294
|
+
name: 'productId',
|
|
295
|
+
operator: 'in',
|
|
296
|
+
value: [
|
|
297
|
+
...result.orderProducts
|
|
298
|
+
.filter(itm => itm?.product)
|
|
299
|
+
.map(itm => {
|
|
300
|
+
return itm.product.id
|
|
301
|
+
}),
|
|
302
|
+
...result.orderProducts
|
|
303
|
+
.filter(itm => itm?.productBundle)
|
|
304
|
+
.map(itm => {
|
|
305
|
+
return itm.productBundle.productBundleSettings.map(itm => {
|
|
306
|
+
return itm.product.id
|
|
307
|
+
})
|
|
308
|
+
})
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
]
|
|
312
|
+
|
|
313
|
+
if (commonWarehouseCode) {
|
|
314
|
+
baseFilters.push({ name: 'warehouseCode', operator: 'eq', value: commonWarehouseCode })
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (batchIds.length > 0) {
|
|
318
|
+
baseFilters.push({ name: 'batchId', operator: 'in', value: batchIds })
|
|
319
|
+
}
|
|
320
|
+
|
|
275
321
|
productInventory = await InventoryUtil.bizplaceProductInventory(
|
|
276
322
|
bizplaces,
|
|
277
323
|
{
|
|
278
|
-
filters:
|
|
279
|
-
{ name: 'bizplaceId', operator: 'eq', value: result.bizplace.id },
|
|
280
|
-
{
|
|
281
|
-
name: 'productId',
|
|
282
|
-
operator: 'in',
|
|
283
|
-
value: [
|
|
284
|
-
...result.orderProducts
|
|
285
|
-
.filter(itm => itm?.product)
|
|
286
|
-
.map(itm => {
|
|
287
|
-
return itm.product.id
|
|
288
|
-
}),
|
|
289
|
-
...result.orderProducts
|
|
290
|
-
.filter(itm => itm?.productBundle)
|
|
291
|
-
.map(itm => {
|
|
292
|
-
return itm.productBundle.productBundleSettings.map(itm => {
|
|
293
|
-
return itm.product.id
|
|
294
|
-
})
|
|
295
|
-
})
|
|
296
|
-
]
|
|
297
|
-
}
|
|
298
|
-
]
|
|
324
|
+
filters: baseFilters
|
|
299
325
|
},
|
|
300
326
|
context,
|
|
301
327
|
tx
|
|
302
328
|
)
|
|
329
|
+
}
|
|
303
330
|
|
|
304
331
|
result.orderProducts = result.orderProducts
|
|
305
332
|
.map(itm => {
|
|
@@ -321,6 +348,7 @@ export async function getDraftReleaseGoodFunction(_: any, context: any, id?: any
|
|
|
321
348
|
productDetail: itm.productDetail || {
|
|
322
349
|
id: foundProductInv.productDetailId
|
|
323
350
|
},
|
|
351
|
+
batchId: itm.batchId,
|
|
324
352
|
groupType: foundProductInv ? foundProductInv.groupType : 'SINGLE',
|
|
325
353
|
remainQty: foundProductInv ? foundProductInv.remainQty : 0,
|
|
326
354
|
remainUomValue: foundProductInv ? foundProductInv.remainUomValue : 0,
|
|
@@ -352,6 +380,7 @@ export async function getDraftReleaseGoodFunction(_: any, context: any, id?: any
|
|
|
352
380
|
id: foundProductInv.productDetailId
|
|
353
381
|
},
|
|
354
382
|
groupType: 'BUNDLE',
|
|
383
|
+
batchId: itm.batchId,
|
|
355
384
|
releaseQty: itmBundleReleaseQty,
|
|
356
385
|
remainQty: foundProductInv ? foundProductInv.remainQty : 0,
|
|
357
386
|
remainUomValue: foundProductInv ? foundProductInv.remainUomValue : 0,
|
|
@@ -243,7 +243,7 @@ export class OrderProduct {
|
|
|
243
243
|
expDate: Date
|
|
244
244
|
|
|
245
245
|
@Column('date', { nullable: true })
|
|
246
|
-
@Field(
|
|
246
|
+
@Field(type => ScalarDate, { nullable: true })
|
|
247
247
|
adjustedExpDate: Date
|
|
248
248
|
|
|
249
249
|
@ManyToOne(type => Warehouse, { nullable: true })
|
|
@@ -253,13 +253,13 @@ export class OrderProduct {
|
|
|
253
253
|
@RelationId((orderProduct: OrderProduct) => orderProduct.warehouse)
|
|
254
254
|
warehouseId: string
|
|
255
255
|
|
|
256
|
-
@ManyToOne(type=> Warehouse, { nullable: true })
|
|
257
|
-
@Field(type=> Warehouse, { nullable: true })
|
|
256
|
+
@ManyToOne(type => Warehouse, { nullable: true })
|
|
257
|
+
@Field(type => Warehouse, { nullable: true })
|
|
258
258
|
adjustedWarehouse: Warehouse
|
|
259
259
|
|
|
260
260
|
@RelationId((orderProduct: OrderProduct) => orderProduct.adjustedWarehouse)
|
|
261
261
|
adjustedWarehouseId: string
|
|
262
|
-
|
|
262
|
+
|
|
263
263
|
@ManyToOne(type => Location, { nullable: true })
|
|
264
264
|
@Field(type => Location, { nullable: true })
|
|
265
265
|
location: Location
|
|
@@ -458,6 +458,10 @@ export class OrderProduct {
|
|
|
458
458
|
@Field({ nullable: true })
|
|
459
459
|
remark: string
|
|
460
460
|
|
|
461
|
+
@Column({ nullable: true })
|
|
462
|
+
@Field({ nullable: true })
|
|
463
|
+
warehouseCode: string
|
|
464
|
+
|
|
461
465
|
@Column({ nullable: true })
|
|
462
466
|
@Field({ nullable: true })
|
|
463
467
|
issue: string
|
|
@@ -951,6 +951,15 @@ export async function bulkReleaseGoodsAvailableItemsFunction(
|
|
|
951
951
|
const companyBizplaceId: Bizplace = await getCompanyBizplace(null, null, bizplaceId)
|
|
952
952
|
|
|
953
953
|
if (!rawReleaseGoods) return
|
|
954
|
+
// derive optional filters
|
|
955
|
+
const uniqueWarehouseCodes: string[] = Array.from(
|
|
956
|
+
new Set(
|
|
957
|
+
(rawReleaseGoods || []).map((r: any) => (r?.warehouseCode ? String(r.warehouseCode).trim() : '')).filter(Boolean)
|
|
958
|
+
)
|
|
959
|
+
)
|
|
960
|
+
const uniqueBatchIds: string[] = Array.from(
|
|
961
|
+
new Set((rawReleaseGoods || []).map((r: any) => (r?.batchId ? String(r.batchId).trim() : '')).filter(Boolean))
|
|
962
|
+
)
|
|
954
963
|
const json_oi = JSON.stringify(
|
|
955
964
|
rawReleaseGoods.map(raw => {
|
|
956
965
|
return {
|
|
@@ -1009,6 +1018,7 @@ export async function bulkReleaseGoodsAvailableItemsFunction(
|
|
|
1009
1018
|
`
|
|
1010
1019
|
WITH inv AS (
|
|
1011
1020
|
SELECT i.product_id, foo.product_detail_id, foo.sku, foo.product_info, i.packing_type, i.packing_size, i.uom,
|
|
1021
|
+
w.name as warehouse_name,
|
|
1012
1022
|
${useDetailedQuery ? ' i.batch_id, i.carton_id, i.expiration_date,' : ''}
|
|
1013
1023
|
SUM(i.qty - COALESCE(i.locked_qty, 0)) - COALESCE(
|
|
1014
1024
|
(
|
|
@@ -1035,6 +1045,7 @@ export async function bulkReleaseGoodsAvailableItemsFunction(
|
|
|
1035
1045
|
p.is_inventory_decimal
|
|
1036
1046
|
FROM inventories i
|
|
1037
1047
|
INNER JOIN locations l ON i.location_id = l.id
|
|
1048
|
+
INNER JOIN warehouses w ON w.id = l.warehouse_id
|
|
1038
1049
|
LEFT JOIN products p ON i.product_id = p.id
|
|
1039
1050
|
INNER JOIN (
|
|
1040
1051
|
SELECT rrg.product_id, rrg.product_detail_id, rrg.sku, rrg.product_info, rrg.packing_type, rrg.packing_size, rrg.uom
|
|
@@ -1052,12 +1063,21 @@ export async function bulkReleaseGoodsAvailableItemsFunction(
|
|
|
1052
1063
|
AND i.obsolete = false
|
|
1053
1064
|
AND i.transfer_qty <= 0
|
|
1054
1065
|
AND i.transfer_uom_value <= 0
|
|
1055
|
-
|
|
1066
|
+
AND ( $5::text IS NULL OR w.name = $5 )
|
|
1067
|
+
${`AND ( $6::text IS NULL OR i.batch_id = $6 )`}
|
|
1068
|
+
GROUP BY i.product_id, foo.product_detail_id, foo.sku, foo.product_info, i.packing_type, i.packing_size, i.uom, p.is_inventory_decimal, w.name
|
|
1056
1069
|
${useDetailedQuery ? ', i.batch_id, i.carton_id, i.expiration_date' : ''}
|
|
1057
1070
|
ORDER BY foo.sku, remain_qty DESC
|
|
1058
1071
|
) SELECT * FROM inv WHERE remain_qty > 0
|
|
1059
1072
|
`,
|
|
1060
|
-
[
|
|
1073
|
+
[
|
|
1074
|
+
domain.id,
|
|
1075
|
+
bizplaceId,
|
|
1076
|
+
LOCATION_TYPE.QUARANTINE,
|
|
1077
|
+
LOCATION_TYPE.RESERVE,
|
|
1078
|
+
uniqueWarehouseCodes.length === 1 ? uniqueWarehouseCodes[0] : null,
|
|
1079
|
+
uniqueBatchIds.length === 1 ? uniqueBatchIds[0] : null
|
|
1080
|
+
]
|
|
1061
1081
|
)
|
|
1062
1082
|
|
|
1063
1083
|
await tx.query(`DROP TABLE raw_release_goods`)
|
|
@@ -1073,6 +1093,7 @@ export async function bulkReleaseGoodsAvailableItemsFunction(
|
|
|
1073
1093
|
uom: item.uom,
|
|
1074
1094
|
remainQty: item.remain_qty,
|
|
1075
1095
|
remainUomValue: item.remain_uom_value,
|
|
1096
|
+
warehouseCode: item.warehouse_name || null,
|
|
1076
1097
|
batchId: item.batch_id ? item.batch_id : null,
|
|
1077
1098
|
cartonId: item.carton_id ? item.carton_id : null,
|
|
1078
1099
|
expirationDate: item.expiration_date ? _getStdDateStr(new Date(item.expiration_date)) : null,
|
|
@@ -1096,6 +1117,11 @@ function _extractData(rawData, validatedData) {
|
|
|
1096
1117
|
comparison.push('batchId')
|
|
1097
1118
|
if (!data.length) errMsg = errMsg ? errMsg : 'batch no not matched'
|
|
1098
1119
|
}
|
|
1120
|
+
if (raw.warehouseCode) {
|
|
1121
|
+
data = data.filter(val => val.warehouseCode === String(raw.warehouseCode).trim())
|
|
1122
|
+
comparison.push('warehouseCode')
|
|
1123
|
+
if (!data.length) errMsg = errMsg ? errMsg : 'warehouse code not matched'
|
|
1124
|
+
}
|
|
1099
1125
|
if (raw.cartonId) {
|
|
1100
1126
|
data = data.filter(val => val.cartonId === raw.cartonId)
|
|
1101
1127
|
comparison.push('cartonId')
|
|
@@ -1133,20 +1159,17 @@ function _extractData(rawData, validatedData) {
|
|
|
1133
1159
|
|
|
1134
1160
|
raw.assignedQty =
|
|
1135
1161
|
Math.round(
|
|
1136
|
-
(data[idx].remainQty >= raw.releaseQty
|
|
1137
|
-
|
|
1138
|
-
? raw.releaseQty
|
|
1139
|
-
: 0
|
|
1140
|
-
: data[idx].remainQty) * 1000
|
|
1162
|
+
(data[idx].remainQty >= raw.releaseQty ? (raw.releaseQty > 0 ? raw.releaseQty : 0) : data[idx].remainQty) *
|
|
1163
|
+
1000
|
|
1141
1164
|
) / 1000
|
|
1142
1165
|
|
|
1143
1166
|
raw.assignedUomValue =
|
|
1144
1167
|
Math.round(
|
|
1145
1168
|
(data[idx].remainUomValue >= releaseUomValue
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1169
|
+
? releaseUomValue > 0
|
|
1170
|
+
? releaseUomValue
|
|
1171
|
+
: 0
|
|
1172
|
+
: data[idx].remainUomValue) * 1000
|
|
1150
1173
|
) / 1000
|
|
1151
1174
|
|
|
1152
1175
|
// deduct qty & uomValue from validateData
|
|
@@ -1190,7 +1213,7 @@ function _extractData(rawData, validatedData) {
|
|
|
1190
1213
|
errors.push('insufficient stock')
|
|
1191
1214
|
}
|
|
1192
1215
|
if (!dateRegex.test(raw.releaseDate)) {
|
|
1193
|
-
errors.push('invalid release date format. please use dd
|
|
1216
|
+
errors.push('invalid release date format. please use yyyy-mm-dd')
|
|
1194
1217
|
}
|
|
1195
1218
|
if (raw.releaseDate === '') {
|
|
1196
1219
|
errors.push('release date is empty')
|
|
@@ -1213,7 +1236,7 @@ function _extractData(rawData, validatedData) {
|
|
|
1213
1236
|
errors.push('invalid paid amount')
|
|
1214
1237
|
}
|
|
1215
1238
|
if (raw?.expirationDate != null && !dateRegex.test(raw?.expirationDate)) {
|
|
1216
|
-
errors.push('invalid expiration date format. please use dd
|
|
1239
|
+
errors.push('invalid expiration date format. please use yyyy-mm-dd')
|
|
1217
1240
|
}
|
|
1218
1241
|
if (raw.airwayBill && raw.lmdOption === true) {
|
|
1219
1242
|
errors.push('kindly remove AWB as LMD is marked as true')
|
|
@@ -59,6 +59,25 @@ export const InventoryUtil = {
|
|
|
59
59
|
let inventoryBizplaceFilter = filters.find(itm => itm.name == 'bizplaceId')
|
|
60
60
|
let deletedAt = filters.find(filter => filter.name == 'deleted_at')
|
|
61
61
|
|
|
62
|
+
const warehouseCodeFilter = filters.find(itm => itm.name == 'warehouseCode')
|
|
63
|
+
const batchIdFilter = filters.find(itm => itm.name == 'batchId')
|
|
64
|
+
const sanitizedWarehouseCode = warehouseCodeFilter
|
|
65
|
+
? String(warehouseCodeFilter.value).trim().replace(/'/g, "''")
|
|
66
|
+
: null
|
|
67
|
+
|
|
68
|
+
let batchFilterClause = ''
|
|
69
|
+
// Apply strict batch filter only when warehouseCode is provided
|
|
70
|
+
if (sanitizedWarehouseCode && batchIdFilter) {
|
|
71
|
+
const op = (batchIdFilter.operator || '').toLowerCase()
|
|
72
|
+
const val = batchIdFilter.value
|
|
73
|
+
if (op === 'in' && Array.isArray(val)) {
|
|
74
|
+
const list = val.map(v => `'${String(v).trim().replace(/'/g, "''")}'`).join(',')
|
|
75
|
+
batchFilterClause = `AND i.batch_id IN (${list})`
|
|
76
|
+
} else if (val !== undefined && val !== null && String(val).trim() !== '') {
|
|
77
|
+
batchFilterClause = `AND i.batch_id = '${String(val).trim().replace(/'/g, "''")}'`
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
62
81
|
let queryStrings = `
|
|
63
82
|
CREATE TEMP TABLE temp_inventory_product_group ON COMMIT DROP AS (
|
|
64
83
|
SELECT * FROM (
|
|
@@ -125,12 +144,15 @@ export const InventoryUtil = {
|
|
|
125
144
|
LEFT JOIN (
|
|
126
145
|
SELECT i.* FROM inventories i
|
|
127
146
|
INNER JOIN locations l2 ON i.location_id = l2.id AND i.domain_id = l2.domain_id
|
|
147
|
+
INNER JOIN warehouses w ON w.id = l2.warehouse_id
|
|
128
148
|
WHERE l2.type NOT IN ('${LOCATION_TYPE.QUARANTINE}', '${LOCATION_TYPE.RESERVE}', '${
|
|
129
149
|
LOCATION_TYPE.DAMAGE
|
|
130
150
|
}')
|
|
131
151
|
AND i.obsolete = false
|
|
132
152
|
AND i.domain_id = $1 AND i.status = 'STORED'
|
|
133
153
|
${inventoryBizplaceFilter ? `AND i.bizplace_id = '${inventoryBizplaceFilter.value}'` : ``}
|
|
154
|
+
${sanitizedWarehouseCode ? `AND w.name = '${sanitizedWarehouseCode}'` : ``}
|
|
155
|
+
${batchFilterClause}
|
|
134
156
|
) i ON i.product_detail_id = pd.id
|
|
135
157
|
LEFT JOIN oi ON i.batch_id = oi.batch_id AND p.name = oi.product_name AND i.packing_type = oi.packing_type AND i.packing_size = oi.packing_size AND i.uom = oi.uom
|
|
136
158
|
LEFT JOIN (
|
|
@@ -189,12 +211,14 @@ export const InventoryUtil = {
|
|
|
189
211
|
LEFT JOIN inventories i2 ON i2.product_id = pbs.product_id AND i2.domain_id = $1 AND i2.status = 'STORED'
|
|
190
212
|
LEFT JOIN product_detail_stocks pds2 ON pds2.product_detail_id = pbs.product_detail_id
|
|
191
213
|
INNER JOIN locations l2 ON i2.location_id = l2.id
|
|
214
|
+
INNER JOIN warehouses w2 ON w2.id = l2.warehouse_id
|
|
192
215
|
LEFT JOIN oi ON oi.product_id = i2.product_id
|
|
193
216
|
WHERE l2.type NOT IN ('${LOCATION_TYPE.QUARANTINE}', '${LOCATION_TYPE.RESERVE}', '${
|
|
194
217
|
LOCATION_TYPE.DAMAGE
|
|
195
218
|
}')
|
|
196
219
|
and i2.obsolete = false
|
|
197
220
|
${inventoryBizplaceFilter ? `AND i2.bizplace_id = '${inventoryBizplaceFilter.value}'` : ``}
|
|
221
|
+
${sanitizedWarehouseCode ? `AND w2.name = '${sanitizedWarehouseCode}'` : ``}
|
|
198
222
|
GROUP BY
|
|
199
223
|
pbs.product_id,
|
|
200
224
|
pbs.product_bundle_id,
|
|
@@ -848,7 +872,8 @@ export const InventoryUtil = {
|
|
|
848
872
|
preferLocation: string = null,
|
|
849
873
|
recall: boolean = null,
|
|
850
874
|
cartonId?: string,
|
|
851
|
-
expirationDate?: Date
|
|
875
|
+
expirationDate?: Date,
|
|
876
|
+
warehouseName?: string
|
|
852
877
|
): Promise<OrderInventory[]> {
|
|
853
878
|
let strictProduct = 'false'
|
|
854
879
|
|
|
@@ -880,6 +905,7 @@ export const InventoryUtil = {
|
|
|
880
905
|
|
|
881
906
|
let qb: SelectQueryBuilder<Inventory> = trxMgr.getRepository(Inventory).createQueryBuilder('iv')
|
|
882
907
|
qb.innerJoinAndSelect('iv.location', 'loc')
|
|
908
|
+
.innerJoin('warehouses', 'w', 'w.id = loc.warehouse_id')
|
|
883
909
|
.innerJoin('warehouse_inventory_assignment_rankings', 'wiar', '"wiar"."location_type" = "loc"."type"')
|
|
884
910
|
.innerJoin('iv.product', 'p')
|
|
885
911
|
.andWhere('"iv"."domain_id" = :domainId')
|
|
@@ -917,6 +943,9 @@ export const InventoryUtil = {
|
|
|
917
943
|
if (preferLocation) {
|
|
918
944
|
qb.andWhere('"loc"."type" = :preferLocation', { preferLocation })
|
|
919
945
|
}
|
|
946
|
+
if (warehouseName) {
|
|
947
|
+
qb.andWhere('w.name = :warehouseName', { warehouseName: String(warehouseName).trim() })
|
|
948
|
+
}
|
|
920
949
|
if (strictProduct == 'true' || preferLocation == 'STORAGE') {
|
|
921
950
|
qb.andWhere('"iv"."product_detail_id" = :productDetailId', { productDetailId: productDetail.id })
|
|
922
951
|
} else {
|
|
@@ -1075,8 +1104,17 @@ async function getConditions(
|
|
|
1075
1104
|
break
|
|
1076
1105
|
|
|
1077
1106
|
case 'batchId':
|
|
1078
|
-
|
|
1079
|
-
|
|
1107
|
+
// Only apply to outer whereClause when the consumer's temp table includes "batchId"
|
|
1108
|
+
if (hasRemainingQty) {
|
|
1109
|
+
if (operator === 'in' && Array.isArray(value)) {
|
|
1110
|
+
const list = value.map((v: string) => `'${String(v).trim().replace(/'/g, "''")}'`).join(',')
|
|
1111
|
+
whereClause += `AND "batchId" IN (${list})`
|
|
1112
|
+
} else {
|
|
1113
|
+
let batchId = `${value}`
|
|
1114
|
+
whereClause += `AND LOWER("batchId") LIKE '${batchId.replace(`'`, `''`).toLowerCase()}'`
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
// For consumers without batchId column (e.g., bizplaceProductInventory), batch filtering is handled inside subqueries
|
|
1080
1118
|
break
|
|
1081
1119
|
|
|
1082
1120
|
case 'batchIdRef':
|