@things-factory/sales-base 4.3.656 → 4.3.660

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.
@@ -51,7 +51,7 @@ export class ArrivalNoticeQuery {
51
51
  //separate query to improve typeorm mapping performance. Search for Related Order Product
52
52
  let orderProducts = await getRepository(OrderProduct).find({
53
53
  where: { arrivalNotice: foundGAN },
54
- relations: ['product', 'productDetail', 'productDetail.productBarcodes']
54
+ relations: ['product', 'productDetail', 'productDetail.productBarcodes', 'warehouse', 'location', 'adjustedWarehouse','adjustedLocation']
55
55
  })
56
56
  foundGAN.orderProducts = await Promise.all(
57
57
  orderProducts.map(async orderProduct => {
@@ -59,6 +59,10 @@ export class ArrivalNoticeQuery {
59
59
  orderProduct.adjustedUnitPrice = orderProduct?.adjustedUnitPrice
60
60
  ? parseFloat(orderProduct.adjustedUnitPrice.toFixed(2))
61
61
  : null
62
+ orderProduct.warehouse = orderProduct?.warehouse
63
+ orderProduct.location = orderProduct?.location
64
+ orderProduct.adjustedWarehouse = orderProduct?.adjustedWarehouse
65
+ orderProduct.adjustedLocation = orderProduct?.adjustedLocation
62
66
  return orderProduct
63
67
  })
64
68
  )
@@ -4,6 +4,8 @@ import { ObjectRef, ScalarDate } from '@things-factory/shell'
4
4
 
5
5
  import { OrderProduct } from './order-product'
6
6
 
7
+ import { Warehouse, Location } from '@things-factory/warehouse-base'
8
+
7
9
  @ObjectType()
8
10
  export class OrderProductList {
9
11
  @Field(type => [OrderProduct], { nullable: true })
@@ -197,6 +199,25 @@ export class OrderProductPatch {
197
199
 
198
200
  @Field({ nullable: true })
199
201
  cuFlag: string
202
+
203
+ @Field(type => ScalarDate, { nullable: true })
204
+ expDate: Date
205
+
206
+ @Field(type =>ScalarDate, { nullable: true })
207
+ adjustedExpDate: Date
208
+
209
+ @Field(type => ObjectRef, { nullable: true })
210
+ warehouse: ObjectRef
211
+
212
+ @Field(type => ObjectRef, { nullable: true })
213
+ location: ObjectRef
214
+
215
+ @Field(type => ObjectRef, { nullable: true })
216
+ adjustedWarehouse: ObjectRef
217
+
218
+ @Field(type => ObjectRef, { nullable: true })
219
+ adjustedLocation: ObjectRef
220
+
200
221
  }
201
222
 
202
223
  @InputType()
@@ -342,6 +363,12 @@ export class NewOrderProduct {
342
363
  @Field({ nullable: true })
343
364
  status: string
344
365
 
366
+ @Field(type => ScalarDate, { nullable: true })
367
+ expDate: Date
368
+
369
+ @Field(type => ScalarDate, { nullable: true })
370
+ adjustedExpDate: Date
371
+
345
372
  @Field(type => ScalarDate, { nullable: true })
346
373
  manufactureDate: Date
347
374
 
@@ -350,4 +377,22 @@ export class NewOrderProduct {
350
377
 
351
378
  @Field(type => Float, { nullable: true })
352
379
  paidAmount: number
380
+
381
+ @Field(type => ObjectRef, { nullable: true })
382
+ warehouse: ObjectRef
383
+
384
+ @Field(type => ObjectRef, { nullable: true })
385
+ adjustedWarehouse: ObjectRef
386
+
387
+ @Field(type => String, { nullable: true })
388
+ warehouseName: String
389
+
390
+ @Field(type => ObjectRef, { nullable: true })
391
+ location: ObjectRef
392
+
393
+ @Field(type => ObjectRef, { nullable: true })
394
+ adjustedLocation: ObjectRef
395
+
396
+ @Field(type => String, { nullable: true })
397
+ locationName: String
353
398
  }
@@ -15,7 +15,7 @@ import { User } from '@things-factory/auth-base'
15
15
  import { Bizplace } from '@things-factory/biz-base'
16
16
  import { Product, ProductBundle, ProductDetail } from '@things-factory/product-base'
17
17
  import { Domain, ScalarDate } from '@things-factory/shell'
18
- import { Inventory } from '@things-factory/warehouse-base'
18
+ import { Inventory, Warehouse, Location } from '@things-factory/warehouse-base'
19
19
 
20
20
  import { ArrivalNotice } from '../arrival-notice/arrival-notice'
21
21
  import { CollectionOrder } from '../collection-order/collection-order'
@@ -238,6 +238,42 @@ export class OrderProduct {
238
238
  @Field(type => ScalarDate, { nullable: true })
239
239
  manufactureDate: Date
240
240
 
241
+ @Column('date', { nullable: true })
242
+ @Field(type => ScalarDate, { nullable: true })
243
+ expDate: Date
244
+
245
+ @Column('date', { nullable: true })
246
+ @Field( type => ScalarDate, { nullable: true })
247
+ adjustedExpDate: Date
248
+
249
+ @ManyToOne(type => Warehouse, { nullable: true })
250
+ @Field(type => Warehouse, { nullable: true })
251
+ warehouse: Warehouse
252
+
253
+ @RelationId((orderProduct: OrderProduct) => orderProduct.warehouse)
254
+ warehouseId: string
255
+
256
+ @ManyToOne(type=> Warehouse, { nullable: true })
257
+ @Field(type=> Warehouse, { nullable: true })
258
+ adjustedWarehouse: Warehouse
259
+
260
+ @RelationId((orderProduct: OrderProduct) => orderProduct.adjustedWarehouse)
261
+ adjustedWarehouseId: string
262
+
263
+ @ManyToOne(type => Location, { nullable: true })
264
+ @Field(type => Location, { nullable: true })
265
+ location: Location
266
+
267
+ @RelationId((orderProduct: OrderProduct) => orderProduct.location)
268
+ locationId: string
269
+
270
+ @ManyToOne(type => Location, { nullable: true })
271
+ @Field(type => Location, { nullable: true })
272
+ adjustedLocation: Location
273
+
274
+ @RelationId((orderProduct: OrderProduct) => orderProduct.adjustedLocation)
275
+ adjustedLocationId: string
276
+
241
277
  @Column({ nullable: true })
242
278
  @Field({ nullable: true })
243
279
  uom: string
@@ -18,6 +18,7 @@ import {
18
18
  OrderProduct
19
19
  } from '../'
20
20
  import { InventoryUtil } from '../../utils'
21
+ import { Location } from '@things-factory/warehouse-base'
21
22
 
22
23
  @Resolver()
23
24
  export class OtherQuery {
@@ -292,8 +293,8 @@ export class OtherQuery {
292
293
  @Query(returns => [InventoryProductGroup])
293
294
  async bulkUploadValidateOrderProducts(
294
295
  @Ctx() context: any,
295
- @Arg('partnerBizplaceId') partnerBizplaceId: string,
296
- @Arg('orderProducts', type => [NewOrderProduct], { nullable: true }) orderProducts: NewOrderProduct[]
296
+ @Arg('orderProducts', type => [NewOrderProduct], { nullable: true }) orderProducts: NewOrderProduct[],
297
+ @Arg('partnerBizplaceId', { nullable: true }) partnerBizplaceId?: string
297
298
  ): Promise<OrderProduct[]> {
298
299
  try {
299
300
  const { domain, user, tx, bizplace }: { domain: Domain; user: User; tx: EntityManager; bizplace: Bizplace } =
@@ -334,8 +335,16 @@ export class OtherQuery {
334
335
 
335
336
  if (partnerStrictProductSelectionSetting) strictProduct = partnerStrictProductSelectionSetting.value
336
337
 
338
+ const directGanOrderSetting: Setting = await tx.getRepository(Setting).findOne({
339
+ where: { domain, category: 'id-rule', name: 'enable-direct-gan-order' }
340
+ })
341
+
342
+ let directGanOrder = 'false'
343
+ if (directGanOrderSetting) directGanOrder = directGanOrderSetting.value
344
+
337
345
  const json_op = JSON.stringify(
338
346
  orderProducts.map(orderProduct => {
347
+
339
348
  return {
340
349
  sku: orderProduct.productSKU,
341
350
  packing_type: orderProduct.packingType,
@@ -348,7 +357,12 @@ export class OtherQuery {
348
357
  uom_value: orderProduct.uomValue,
349
358
  manufacture_date: orderProduct.manufactureDate,
350
359
  batch_id_ref: orderProduct.batchIdRef,
351
- remark: orderProduct.remark
360
+ remark: orderProduct.remark,
361
+ ...(directGanOrder && {
362
+ warehouse_name: orderProduct.warehouseName,
363
+ location_name: orderProduct.location ? orderProduct.location.name : orderProduct.locationName,
364
+ location_id: orderProduct.location? orderProduct.location.id : ''
365
+ })
352
366
  }
353
367
  })
354
368
  )
@@ -366,6 +380,13 @@ export class OtherQuery {
366
380
  uom VARCHAR(10),
367
381
  uom_value FLOAT,
368
382
  manufacture_date DATE,
383
+ ${
384
+ directGanOrder.toLocaleLowerCase() === 'true'
385
+ ? `warehouse_name VARCHAR(150),
386
+ location_name VARCHAR(150),
387
+ location_id VARCHAR(150),`
388
+ : ``
389
+ }
369
390
  batch_id_ref VARCHAR(50),
370
391
  remark VARCHAR(50)
371
392
  );
@@ -380,6 +401,61 @@ export class OtherQuery {
380
401
  [json_op]
381
402
  )
382
403
 
404
+ //validate and show error message in popup
405
+ if (directGanOrder && partnerBizplaceId == undefined) {
406
+ let results = await tx.query(
407
+ `
408
+ SELECT
409
+ rop.*,
410
+ TRIM(BOTH ' | ' FROM -- Trim leading/trailing ' | ' from the concatenated error messages
411
+ COALESCE(CASE WHEN p.sku IS NULL THEN 'Invalid SKU or Packing Type | ' ELSE '' END, '') ||
412
+ COALESCE(CASE WHEN pd.uom IS NULL THEN 'Invalid UOM or UOM Value | ' ELSE '' END, '') ||
413
+ COALESCE(CASE WHEN rop.manufacture_date > CURRENT_DATE THEN 'Manufacture Date in Future | ' ELSE '' END, '') ||
414
+ COALESCE(CASE WHEN rop.unit_price <= 0 THEN 'Unit Price must be greater than 0 | ' ELSE '' END, '') ||
415
+ COALESCE(CASE WHEN rop.pack_qty <= 0 THEN 'Pack Quantity must be greater than 0 | ' ELSE '' END, '') ||
416
+ COALESCE(CASE WHEN rop.pallet_qty < 0 THEN 'Pallet Quantity must be positive | ' ELSE '' END, '') ||
417
+ COALESCE(CASE WHEN w.name IS NULL THEN 'Location not found in Master Data | ' ELSE '' END, '') ||
418
+ COALESCE(CASE WHEN l.name IS NULL OR l.warehouse_id IS DISTINCT FROM w.id THEN 'Location-Warehouse Mismatch | ' ELSE '' END, '')
419
+ ) AS error_message -- The new column containing concatenated error messages
420
+ FROM
421
+ raw_order_products rop
422
+ LEFT JOIN
423
+ products p ON LOWER(rop.sku) = LOWER(p.sku) AND rop.packing_type = p.packing_type
424
+ LEFT JOIN
425
+ product_details pd ON pd.product_id = p.id AND rop.uom = pd.uom AND rop.uom_value = pd.uom_value
426
+ LEFT JOIN
427
+ warehouses w ON rop.warehouse_name = w.name and w.domain_id = $1
428
+ LEFT JOIN
429
+ locations l ON l.warehouse_id = w.id AND rop.location_name = l.name
430
+ `,
431
+ [domain.id]
432
+ )
433
+
434
+ await tx.query(`DROP TABLE raw_order_products`)
435
+
436
+ const newOrderProducts: any[] = results.map(result => {
437
+ return {
438
+ // Remapping keys to the new spelling
439
+ packingType: result.packing_type,
440
+ uom: result.uom,
441
+ uomValue: result.uom_value,
442
+ packQty: result.pack_qty,
443
+ palletQty: result.pallet_qty,
444
+ manufactureDate: result.manufacture_date,
445
+ batchId: result.batch_id,
446
+ batchIdRef: result.batch_id_ref,
447
+ unitPrice: result.unit_price,
448
+ remark: result.remark,
449
+ productSKU: result.sku, // 'sku' from results maps to 'productSKU'
450
+ errMsg: result.error_message, // 'error_message' from results maps to 'errMsg'
451
+ pallet_id: result.pallet_id, // Keeping original key for pallet_id as it's not in new key spelling list
452
+ warehouseName: result.warehouse_name,
453
+ location: {name:result.location_name, id:result.location_id }
454
+ }
455
+ })
456
+
457
+ return newOrderProducts
458
+ }
383
459
  // find closest matching product details from input data
384
460
  await tx.query(
385
461
  `
@@ -450,6 +526,24 @@ export class OtherQuery {
450
526
  await tx.query(`DROP TABLE matching_product_details`)
451
527
  await tx.query(`DROP TABLE raw_order_products`)
452
528
 
529
+ if (directGanOrder == 'true') {
530
+ let location: Location
531
+ for (let i = 0; i < results.length; i++) {
532
+ location = await tx.getRepository(Location).findOne({
533
+ where: {
534
+ domain: domain,
535
+ name: orderProducts[i].location.name
536
+ },
537
+ relations: ['warehouse']
538
+ })
539
+ results[i].location = location
540
+ results[i].warehouse = location.warehouse
541
+ if (!location) {
542
+ throw new Error(`Location not found for ${orderProducts[i]?.location?.name} `)
543
+ }
544
+ }
545
+ }
546
+
453
547
  // build output structure
454
548
  const newOrderProducts: any[] = results.map(result => {
455
549
  return {
@@ -1,5 +1,7 @@
1
1
  import { Field, Float, Int, ObjectType } from 'type-graphql'
2
2
  import { Product, ProductDetail } from '@things-factory/product-base'
3
+ import { Location, Warehouse } from '@things-factory/warehouse-base'
4
+
3
5
  import { ScalarDate } from '@things-factory/shell'
4
6
 
5
7
  @ObjectType()
@@ -120,4 +122,16 @@ export class InventoryProductGroup {
120
122
 
121
123
  @Field(type => ProductDetail, { nullable: true })
122
124
  productDetail: ProductDetail
125
+
126
+ @Field(type => Location, { nullable: true })
127
+ location: Location
128
+
129
+ @Field(type => Warehouse, { nullable: true })
130
+ warehouse: Warehouse
131
+
132
+ @Field(type => String, { nullable: true })
133
+ warehouseName: String
134
+
135
+ @Field(type => String, { nullable: true })
136
+ errMsg: String
123
137
  }
@@ -1048,6 +1048,7 @@ export async function bulkReleaseGoodsAvailableItemsFunction(
1048
1048
  AND i.domain_id = $1
1049
1049
  AND i.bizplace_id = $2
1050
1050
  WHERE l.type NOT IN ($3, $4)
1051
+ AND i.status = 'STORED'
1051
1052
  AND i.obsolete = false
1052
1053
  AND i.transfer_qty <= 0
1053
1054
  AND i.transfer_uom_value <= 0