@things-factory/sales-base 4.3.782 → 4.3.784

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.
@@ -106,6 +106,69 @@ export class DeliveryOrderQuery {
106
106
  x.name != 'orderProductsApi'
107
107
  )
108
108
 
109
+ // ── Separate count query (minimal JOINs — only those needed for WHERE conditions) ──
110
+ const countQb: any = getRepository(DeliveryOrder).createQueryBuilder('do')
111
+ buildQuery(countQb, params, context)
112
+
113
+ if (refNoFilter?.value || refNo2Filter?.value || refNo3Filter?.value || orderInfoFilter?.value || businessRestDayFilter?.value || orderProductsApiFilter?.value) {
114
+ countQb.leftJoin('do.releaseGood', 'releaseGood')
115
+ }
116
+ if (businessRestDayFilter?.value) {
117
+ countQb.leftJoin('releaseGood.deliverTo', 'deliverTo')
118
+ }
119
+ if (orderProductsApiFilter?.value) {
120
+ countQb.innerJoin('releaseGood.orderProducts', 'orderProducts')
121
+ }
122
+
123
+ if (refNoFilter?.value) {
124
+ countQb.andWhere('releaseGood.ref_no ilike :refNo', { refNo: refNoFilter.value })
125
+ }
126
+ if (refNo2Filter?.value) {
127
+ countQb.andWhere('releaseGood.ref_no_2 ilike :refNo2', { refNo2: refNo2Filter.value })
128
+ }
129
+ if (refNo3Filter?.value) {
130
+ countQb.andWhere('releaseGood.ref_no_3 ilike :refNo3', { refNo3: refNo3Filter.value })
131
+ }
132
+ if (orderInfoFilter?.value) {
133
+ let removeSymbolCount = orderInfoFilter.value
134
+ .split('')
135
+ .filter(res => res !== '%')
136
+ .join('')
137
+ let orderInfosCount = removeSymbolCount
138
+ .toLowerCase()
139
+ .split(',')
140
+ .map(prod => {
141
+ return "'%" + prod.trim().replace(/'/g, "''") + "%'"
142
+ })
143
+ .join(',')
144
+ countQb.andWhere(
145
+ `(
146
+ lower(releaseGood.name) like any(array[${orderInfosCount}])
147
+ or lower(releaseGood.ref_no) like any(array[${orderInfosCount}])
148
+ or lower(releaseGood.ref_no_2) like any(array[${orderInfosCount}])
149
+ or lower(releaseGood.ref_no_3) like any(array[${orderInfosCount}])
150
+ )`
151
+ )
152
+ }
153
+ if (businessRestDayFilter?.value) {
154
+ const todayCount = new Date()
155
+ const dayOfWeekCount = todayCount.getDay()
156
+ const dayNamesCount = ['SUNDAY', 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY']
157
+ const currentDayNameCount = dayNamesCount[dayOfWeekCount]
158
+ if (businessRestDayFilter.value === 'within') {
159
+ countQb.andWhere(`deliverTo.business_rest_day IS NOT NULL AND deliverTo.business_rest_day ILIKE :currentDay`, {
160
+ currentDay: `%${currentDayNameCount}%`
161
+ })
162
+ } else if (businessRestDayFilter.value === 'not_within') {
163
+ countQb.andWhere(`(deliverTo.business_rest_day IS NULL OR deliverTo.business_rest_day NOT ILIKE :currentDay)`, {
164
+ currentDay: `%${currentDayNameCount}%`
165
+ })
166
+ }
167
+ }
168
+
169
+ const total: number = await countQb.getCount()
170
+
171
+ // ── Data query (full JOINs for SELECT — paginated, only processes 'limit' rows) ──
109
172
  const qb: any = getRepository(DeliveryOrder).createQueryBuilder('do')
110
173
  buildQuery(qb, params, context)
111
174
  qb.addSelect('COALESCE("cc".rank, 99999)', 'rank')
@@ -206,7 +269,7 @@ export class DeliveryOrderQuery {
206
269
 
207
270
  qb.orderBy(sort)
208
271
 
209
- let [items, total] = await qb.getManyAndCount()
272
+ let items = await qb.getMany()
210
273
 
211
274
  items = items.map(itm => {
212
275
  let refNo2 = itm.refNo2 // default
@@ -296,7 +359,8 @@ export class DeliveryOrderQuery {
296
359
  }
297
360
  convertedParams.bizplace = In(await getPermittedBizplaceIds(domain, user))
298
361
 
299
- const [items, total] = await getRepository(DeliveryOrder).findAndCount({
362
+ const total = await getRepository(DeliveryOrder).count(convertedParams)
363
+ const items = await getRepository(DeliveryOrder).find({
300
364
  ...convertedParams,
301
365
  relations: ['domain', 'bizplace', 'releaseGood', 'transportDriver', 'transportVehicle', 'creator', 'updater']
302
366
  })
@@ -580,6 +644,26 @@ export class DeliveryOrderQuery {
580
644
 
581
645
  params.filters = params.filters.filter(x => x.name != 'refNo' && x.name != 'refNo2' && x.name != 'refNo3')
582
646
 
647
+ // ── Separate count query (minimal JOINs — only those needed for WHERE conditions) ──
648
+ const countQb: any = getRepository(DeliveryOrder).createQueryBuilder('do')
649
+ buildQuery(countQb, params, context)
650
+
651
+ if (refNoFilter?.value || refNo2Filter?.value || refNo3Filter?.value) {
652
+ countQb.leftJoin('do.releaseGood', 'releaseGood')
653
+ }
654
+ if (refNoFilter?.value) {
655
+ countQb.andWhere('releaseGood.ref_no ilike :refNo', { refNo: refNoFilter.value })
656
+ }
657
+ if (refNo2Filter?.value) {
658
+ countQb.andWhere('releaseGood.ref_no_2 ilike :refNo2', { refNo2: refNo2Filter.value })
659
+ }
660
+ if (refNo3Filter?.value) {
661
+ countQb.andWhere('releaseGood.ref_no_3 ilike :refNo3', { refNo3: refNo3Filter.value })
662
+ }
663
+
664
+ const total: number = await countQb.getCount()
665
+
666
+ // ── Data query (full JOINs for SELECT — paginated, only processes 'limit' rows) ──
583
667
  const qb: any = getRepository(DeliveryOrder).createQueryBuilder('do')
584
668
  buildQuery(qb, params, context)
585
669
  qb.addSelect('COALESCE("cc".rank, 99999)', 'rank')
@@ -634,7 +718,7 @@ export class DeliveryOrderQuery {
634
718
 
635
719
  qb.orderBy(sort)
636
720
 
637
- const [items, total] = await qb.getManyAndCount()
721
+ const items = await qb.getMany()
638
722
  return { items, total }
639
723
  } catch (error) {
640
724
  debug('deliveryOrders', error.toString())
@@ -662,7 +746,8 @@ export async function deliveryOrderByReleaseGood(releaseGood: ReleaseGood, trxMg
662
746
  const doRepo: Repository<DeliveryOrder> = trxMgr?.getRepository(DeliveryOrder) || getRepository(DeliveryOrder)
663
747
  const oiRepo: Repository<OrderInventory> = trxMgr?.getRepository(OrderInventory) || getRepository(OrderInventory)
664
748
 
665
- let [items, total] = await doRepo.findAndCount({
749
+ const total = await doRepo.count({ where: { releaseGood } })
750
+ let items = await doRepo.find({
666
751
  where: { releaseGood },
667
752
  relations: ['domain', 'bizplace', 'releaseGood', 'transportDriver', 'transportVehicle', 'creator', 'updater']
668
753
  })
@@ -128,6 +128,8 @@ export class ReleaseGoodMutation {
128
128
  let releaseGoods: Partial<ReleaseGood[]> = extractRawReleaseGoods(rawReleaseGoods)
129
129
 
130
130
  let errorsCaught: any[] = []
131
+ let successCaught: string[] = []
132
+ let failedCaught: string[] = []
131
133
  for (let i = 0, l = releaseGoods.length; i < l; i++) {
132
134
  // generate release good by group to avoid duplication
133
135
  // if this function is called simultaneously by different users
@@ -172,9 +174,31 @@ export class ReleaseGoodMutation {
172
174
 
173
175
  createdReleaseGoods.push(createdReleaseGood)
174
176
  })
177
+ // track successfully created order labels for toast message
178
+ const rg = releaseGoods[i] as any
179
+ const label = rg.refNo2 ? `${rg.refNo} / ${rg.refNo2}` : rg.refNo
180
+ successCaught.push(label)
175
181
  } catch (error) {
176
- let rawReleaseGoods = formRawReleaseGoods(releaseGoods[i], error.message)
177
- errorsCaught.push(...rawReleaseGoods)
182
+ // track failed order labels for toast message
183
+ const failedRg = releaseGoods[i] as any
184
+ const failedLabel = failedRg.refNo2 ? `${failedRg.refNo} / ${failedRg.refNo2}` : failedRg.refNo
185
+ failedCaught.push(failedLabel)
186
+ // for insufficient stock errors, use per-item error messages from availableItems
187
+ if (error?.detail?.data) {
188
+ try {
189
+ const perItemData: any[] = JSON.parse(error.detail.data)
190
+ const flatRows = perItemData.map((item: any) => {
191
+ const row = { ...releaseGoods[i], ...item, errorMsg: item.errorMsg || error.message }
192
+ delete row.orderInventories
193
+ return row
194
+ })
195
+ errorsCaught.push(...flatRows)
196
+ } catch {
197
+ errorsCaught.push(...formRawReleaseGoods(releaseGoods[i], error.message))
198
+ }
199
+ } else {
200
+ errorsCaught.push(...formRawReleaseGoods(releaseGoods[i], error.message))
201
+ }
178
202
  }
179
203
  }
180
204
 
@@ -218,7 +242,7 @@ export class ReleaseGoodMutation {
218
242
  if (errorsCaught.length)
219
243
  throw new ValidationError({
220
244
  ...ValidationError.ERROR_CODES.INVALID_DATA_FOUND,
221
- detail: { data: JSON.stringify(errorsCaught) }
245
+ detail: { data: JSON.stringify(errorsCaught), successOrders: successCaught, failedOrders: failedCaught }
222
246
  })
223
247
 
224
248
  return confirmedReleaseGoods
@@ -2164,7 +2188,14 @@ function extractRawReleaseGoods(rawReleaseGoods): Partial<ReleaseGood[]> {
2164
2188
 
2165
2189
  if (idx >= 0) {
2166
2190
  const duplicateSkuIdx: number = releaseGoods[idx].orderInventories.findIndex(
2167
- oi => oi.sku === item.sku && oi.packingType === item.packingType && oi.packingSize === item.packingSize
2191
+ oi =>
2192
+ oi.sku === item.sku &&
2193
+ oi.packingType === item.packingType &&
2194
+ oi.packingSize === item.packingSize &&
2195
+ oi.uom === item.uom &&
2196
+ oi.batchId === item.batchId &&
2197
+ oi.cartonId === item.cartonId &&
2198
+ oi.expirationDate === item.expirationDate
2168
2199
  )
2169
2200
 
2170
2201
  // if there is duplicated SKU, merge them and sum up the releaseQty
@@ -2182,7 +2213,10 @@ function extractRawReleaseGoods(rawReleaseGoods): Partial<ReleaseGood[]> {
2182
2213
  packingSize: item.packingSize,
2183
2214
  uom: item.uom,
2184
2215
  releaseQty: Math.round(parseFloat(item.releaseQty) * 1000) / 1000,
2185
- releaseUomValue: Math.round(parseFloat(item.releaseUomValue) * 1000) / 1000
2216
+ releaseUomValue: Math.round(parseFloat(item.releaseUomValue) * 1000) / 1000,
2217
+ batchId: item?.batchId || null,
2218
+ cartonId: item?.cartonId || null,
2219
+ expirationDate: item?.expirationDate || null
2186
2220
  })
2187
2221
  }
2188
2222
  } else {
@@ -1097,22 +1097,24 @@ export async function bulkReleaseGoodsAvailableItemsFunction(
1097
1097
  ${useDetailedQuery ? ' i.batch_id, i.carton_id, i.expiration_date,' : ''}
1098
1098
  SUM(i.qty - COALESCE(i.locked_qty, 0)) - COALESCE(
1099
1099
  (
1100
- SELECT SUM(oi.release_qty) FROM order_inventories oi
1100
+ SELECT SUM(oi.release_qty) FROM order_inventories oi
1101
1101
  WHERE oi.status IN ('PENDING', 'PENDING_RECEIVE', 'PENDING_WORKSHEET', 'PENDING_SPLIT')
1102
1102
  AND oi.inventory_id IS null
1103
1103
  AND oi.product_id = i.product_id::uuid
1104
1104
  AND oi.packing_type = i.packing_type
1105
+ AND oi.packing_size = i.packing_size
1105
1106
  AND oi.uom = i.uom
1106
1107
  AND oi.domain_id = $1
1107
1108
  AND oi.bizplace_id = $2
1108
1109
  ), 0) as "remain_qty",
1109
1110
  SUM(i.uom_value - COALESCE(i.locked_uom_value, 0)) - COALESCE(
1110
1111
  (
1111
- SELECT SUM(oi.release_uom_value) FROM order_inventories oi
1112
+ SELECT SUM(oi.release_uom_value) FROM order_inventories oi
1112
1113
  WHERE oi.status IN ('PENDING', 'PENDING_RECEIVE', 'PENDING_WORKSHEET', 'PENDING_SPLIT')
1113
1114
  AND oi.inventory_id IS null
1114
1115
  AND oi.product_id = i.product_id::uuid
1115
1116
  AND oi.packing_type = i.packing_type
1117
+ AND oi.packing_size = i.packing_size
1116
1118
  AND oi.uom = i.uom
1117
1119
  AND oi.domain_id = $1
1118
1120
  AND oi.bizplace_id = $2
@@ -1240,7 +1242,6 @@ function _extractData(rawData, validatedData) {
1240
1242
 
1241
1243
  return val.sku.toLowerCase() == raw.sku.toLowerCase() && a === b
1242
1244
  })
1243
-
1244
1245
  let releaseUomValue = 0
1245
1246
 
1246
1247
  // if sku is matched, assign qty and product id