@things-factory/sales-base 4.3.333 → 4.3.336

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.
@@ -1,9 +1,37 @@
1
- import { FileUpload, GraphQLUpload } from 'graphql-upload'
2
- import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
3
- import { EntityManager, getConnection, getRepository, In, Not, Repository } from 'typeorm'
1
+ import {
2
+ FileUpload,
3
+ GraphQLUpload
4
+ } from 'graphql-upload'
5
+ import {
6
+ Arg,
7
+ Ctx,
8
+ Directive,
9
+ Mutation,
10
+ Resolver
11
+ } from 'type-graphql'
12
+ import {
13
+ Brackets,
14
+ EntityManager,
15
+ getConnection,
16
+ getRepository,
17
+ ILike,
18
+ In,
19
+ Not,
20
+ Repository,
21
+ SelectQueryBuilder
22
+ } from 'typeorm'
4
23
 
5
- import { Attachment, createAttachments } from '@things-factory/attachment-base'
6
- import { Application, ApplicationType, Partner, Role, User } from '@things-factory/auth-base'
24
+ import {
25
+ Attachment,
26
+ createAttachments
27
+ } from '@things-factory/attachment-base'
28
+ import {
29
+ Application,
30
+ ApplicationType,
31
+ Partner,
32
+ Role,
33
+ User
34
+ } from '@things-factory/auth-base'
7
35
  import {
8
36
  Bizplace,
9
37
  getCompanyBizplace,
@@ -14,15 +42,27 @@ import {
14
42
  } from '@things-factory/biz-base'
15
43
  import { GeoCountry } from '@things-factory/geography'
16
44
  import { generateId } from '@things-factory/id-rule-base'
45
+ import { LastMileDelivery } from '@things-factory/integration-lmd'
17
46
  import { MarketplaceStore } from '@things-factory/integration-marketplace'
18
- import { Sellercraft, SellercraftStatus } from '@things-factory/integration-sellercraft'
47
+ import {
48
+ Sellercraft,
49
+ SellercraftStatus
50
+ } from '@things-factory/integration-sellercraft'
19
51
  import { MarketplaceOrder } from '@things-factory/marketplace-base'
20
52
  // import { sendNotification } from '@things-factory/notification'
21
- import { Product, ProductBundleSetting, ProductDetail } from '@things-factory/product-base'
22
- import { PartnerSetting, Setting } from '@things-factory/setting-base'
53
+ import {
54
+ ProductBundleSetting,
55
+ ProductDetail
56
+ } from '@things-factory/product-base'
57
+ import {
58
+ PartnerSetting,
59
+ Setting
60
+ } from '@things-factory/setting-base'
23
61
  import { Domain } from '@things-factory/shell'
24
- import { Inventory, ProductDetailStock } from '@things-factory/warehouse-base'
25
- import { editVas } from '../vas'
62
+ import {
63
+ Inventory,
64
+ ProductDetailStock
65
+ } from '@things-factory/warehouse-base'
26
66
 
27
67
  // import { NewOrderProduct } from '../order-product/order-product-types'
28
68
  import {
@@ -33,27 +73,40 @@ import {
33
73
  ORDER_NUMBER_SETTING_KEY,
34
74
  ORDER_PRODUCT_STATUS,
35
75
  ORDER_STATUS,
36
- ORDER_TYPES,
37
76
  ORDER_VAS_STATUS,
38
77
  PRODUCT_GROUP_TYPE
39
78
  } from '../../constants'
40
- import { EcommerceController, PowrupController, SellercraftController } from '../../controllers'
79
+ import {
80
+ EcommerceController,
81
+ PowrupController,
82
+ SellercraftController
83
+ } from '../../controllers'
41
84
  import { ValidationError } from '../../errors'
42
- import { InventoryUtil, OrderNoGenerator } from '../../utils'
85
+ import {
86
+ InventoryUtil,
87
+ OrderNoGenerator
88
+ } from '../../utils'
43
89
  import { ArrivalNotice } from '../arrival-notice/arrival-notice'
44
- import { confirmArrivalNoticeFunction, deleteArrivalNotice } from '../arrival-notice/arrival-notice-mutation'
90
+ import {
91
+ confirmArrivalNoticeFunction,
92
+ deleteArrivalNotice
93
+ } from '../arrival-notice/arrival-notice-mutation'
45
94
  import { OrderInventory } from '../order-inventory/order-inventory'
46
95
  import { OrderPackage } from '../order-package/order-package'
47
96
  import { OrderProduct } from '../order-product/order-product'
48
97
  import { OrderVasItem } from '../order-vas-item/order-vas-item'
49
98
  import { OrderVas } from '../order-vas/order-vas'
50
- import { NewReleaseGood, ReleaseGoodPatch, ShippingOrderInfoPatch } from '../release-good/release-good-types'
99
+ import { OrderVasPatch } from '../order-vas/order-vas-types'
100
+ import {
101
+ NewReleaseGood,
102
+ ReleaseGoodPatch,
103
+ ShippingOrderInfoPatch
104
+ } from '../release-good/release-good-types'
51
105
  import { ShippingOrder } from '../shipping-order/shipping-order'
52
106
  import { ShippingOrderPatch } from '../shipping-order/shipping-order-types'
53
- import { Vas } from '../vas/vas'
107
+ import { editVas } from '../vas'
54
108
  import { ReleaseGood } from './release-good'
55
109
  import { bulkReleaseGoodsAvailableItemsFunction } from './release-good-query'
56
- import { OrderVasPatch } from '../order-vas/order-vas-types'
57
110
 
58
111
  @Resolver(ReleaseGood)
59
112
  export class ReleaseGoodMutation {
@@ -203,6 +256,8 @@ export class ReleaseGoodMutation {
203
256
  async generateReleaseGood(
204
257
  @Ctx() context: any,
205
258
  @Arg('attachments', type => [GraphQLUpload], { nullable: true }) attachments?: FileUpload[],
259
+ @Arg('invoiceAttachment', type => [GraphQLUpload], { nullable: true }) invoiceAttachment?: FileUpload[],
260
+ @Arg('awbAttachment', type => [GraphQLUpload], { nullable: true }) awbAttachment?: FileUpload[],
206
261
  @Arg('releaseGood', type => NewReleaseGood, { nullable: true }) releaseGood?: NewReleaseGood,
207
262
  @Arg('orderVasPatch', type => [OrderVasPatch], { nullable: true }) orderVasPatch?: OrderVasPatch[],
208
263
  @Arg('shippingOrder', type => ShippingOrderPatch, { nullable: true }) shippingOrder?: ShippingOrderPatch,
@@ -218,7 +273,9 @@ export class ReleaseGoodMutation {
218
273
  attachments,
219
274
  context,
220
275
  tx,
221
- orderVasPatch
276
+ orderVasPatch,
277
+ invoiceAttachment,
278
+ awbAttachment
222
279
  )
223
280
 
224
281
  return createdReleaseGood
@@ -501,7 +558,9 @@ export async function generateReleaseGoodFunction(
501
558
  attachments: FileUpload[],
502
559
  context: any,
503
560
  tx?: EntityManager,
504
- orderVasPatch?: OrderVasPatch[]
561
+ orderVasPatch?: OrderVasPatch[],
562
+ invoiceAttachment?: FileUpload[],
563
+ awbAttachment?: FileUpload[]
505
564
  ): Promise<ReleaseGood> {
506
565
  try {
507
566
  const { domain, user }: { domain: Domain; user: User } = context.state
@@ -643,6 +702,19 @@ export async function generateReleaseGoodFunction(
643
702
  }
644
703
  })
645
704
 
705
+ let lmd: any = null
706
+ if (releaseGood?.lmdOption) {
707
+ const geoCountryRepo: Repository<GeoCountry> = tx?.getRepository(GeoCountry) || getRepository(GeoCountry)
708
+ let deliveryCountry: GeoCountry = releaseGood?.country
709
+ ? await geoCountryRepo.findOne({
710
+ where: [{ name: ILike(releaseGood?.country) }, { description: ILike(releaseGood?.country) }]
711
+ })
712
+ : null
713
+
714
+ //Assign LMD
715
+ lmd = await autoAssignLmd(domain, deliveryCountry?.id, releaseGood?.postalCode, bizplace)
716
+ }
717
+
646
718
  newReleaseGood = {
647
719
  ...newReleaseGood,
648
720
  name: roNoSetting
@@ -653,7 +725,7 @@ export async function generateReleaseGoodFunction(
653
725
  collectionOrderNo: releaseGood.collectionOrderNo,
654
726
  courierOption: releaseGood.courierOption,
655
727
  exportOption: releaseGood.exportOption,
656
- ownTransport: releaseGood.ownTransport,
728
+ ownTransport: releaseGood.ownTransport || false,
657
729
  packingOption: releaseGood.packingOption,
658
730
  recall: releaseGood.recall,
659
731
  marketplaceOrderStatus: releaseGood?.marketplaceOrderStatus || null,
@@ -684,6 +756,7 @@ export async function generateReleaseGoodFunction(
684
756
  : shippingOrderInfo.billingPostalCode || null,
685
757
  billingState:
686
758
  releaseGood.type == 'b2c' ? releaseGood?.billingState || null : shippingOrderInfo.billingState || null,
759
+ district: releaseGood.type == 'b2c' ? releaseGood?.city : null,
687
760
  transporter: releaseGood?.transporter,
688
761
  trackingNo: releaseGood?.trackingNo,
689
762
  airwayBill: releaseGood?.airwayBill,
@@ -708,6 +781,8 @@ export async function generateReleaseGoodFunction(
708
781
  storeId: releaseGood?.storeId,
709
782
  routeId: releaseGood?.routeId,
710
783
  stopId: releaseGood?.stopId,
784
+ lmdOption: releaseGood?.lmdOption || null,
785
+ lastMileDelivery: lmd || null,
711
786
  creator: user,
712
787
  updater: user
713
788
  }
@@ -892,10 +967,13 @@ export async function generateReleaseGoodFunction(
892
967
  }
893
968
 
894
969
  // VAS
895
- orderVasPatch = orderVasPatch.map(itm => {
896
- return { ...itm, releaseGood: newReleaseGood }
897
- })
898
- await editVas(orderVasPatch, null, context)
970
+ if (orderVasPatch) {
971
+ orderVasPatch = orderVasPatch.map(itm => {
972
+ return { ...itm, releaseGood: newReleaseGood }
973
+ })
974
+ await editVas(orderVasPatch, null, context)
975
+ }
976
+
899
977
  // if (orderVass?.length) {
900
978
  // orderVass = await Promise.all(
901
979
  // orderVass.map(async orderVas => {
@@ -938,6 +1016,28 @@ export async function generateReleaseGoodFunction(
938
1016
  await createAttachments(_, { attachments: files }, context)
939
1017
  }
940
1018
 
1019
+ if (invoiceAttachment && invoiceAttachment.length > 0) {
1020
+ const file: Attachment = {
1021
+ file: invoiceAttachment[0],
1022
+ refBy: newReleaseGood.id,
1023
+ category: ATTACHMENT_TYPE.INVOICE
1024
+ }
1025
+ const invoiceAttachmentResult = await createAttachments(_, { attachments: [file] }, context)
1026
+ await tx
1027
+ .getRepository(ReleaseGood)
1028
+ .update({ id: newReleaseGood.id }, { invoice: invoiceAttachmentResult[0].path })
1029
+ }
1030
+
1031
+ if (awbAttachment && awbAttachment.length > 0) {
1032
+ const file: Attachment = {
1033
+ file: awbAttachment[0],
1034
+ refBy: newReleaseGood.id,
1035
+ category: ATTACHMENT_TYPE.AWB
1036
+ }
1037
+ const awbAttachmentResult = await createAttachments(_, { attachments: [file] }, context)
1038
+ await tx.getRepository(ReleaseGood).update({ id: newReleaseGood.id }, { airwayBill: awbAttachmentResult[0].path })
1039
+ }
1040
+
941
1041
  const directReceiveSetting: Setting = await tx.getRepository(Setting).findOne({
942
1042
  where: { domain, category: 'id-rule', name: 'enable-direct-receive-release-order' }
943
1043
  })
@@ -1826,3 +1926,68 @@ function formRawReleaseGoods(releaseGood, errorMsg) {
1826
1926
  }
1827
1927
  return rawReleaseGoods
1828
1928
  }
1929
+
1930
+ async function autoAssignLmd(domain, countryId, postalCode, bizplace) {
1931
+ let lmdResult: LastMileDelivery
1932
+ const qb: SelectQueryBuilder<LastMileDelivery> = getRepository(LastMileDelivery)
1933
+ .createQueryBuilder('lmd')
1934
+ .leftJoinAndSelect('lmd.lastMileDeliverySettings', 'lmds')
1935
+ .innerJoinAndSelect('lmds.geoCountry', 'gc')
1936
+ .leftJoinAndSelect(`lmd.lastMileDeliveryBizplaces`, `lmdb`)
1937
+ .leftJoinAndSelect('lmdb.bizplace', 'bz')
1938
+ .where('lmd.domain_id = :domainId', { domainId: domain.id })
1939
+ .andWhere('lower(lmd.status) = :status', { status: 'active' })
1940
+ .andWhere('gc.id = :gcId', { gcId: countryId })
1941
+ .andWhere(
1942
+ new Brackets(qb => {
1943
+ qb.where(`lmds.include_postal_code = ''`)
1944
+ .orWhere('lmds.include_postal_code is null')
1945
+ .orWhere('lmds.include_postal_code like :includePostCode', { includePostCode: `%${postalCode}%` })
1946
+ })
1947
+ )
1948
+ .andWhere(
1949
+ new Brackets(qb => {
1950
+ qb.where(`lmds.exclude_postal_code = ''`)
1951
+ .orWhere('lmds.exclude_postal_code is null')
1952
+ .orWhere('lmds.exclude_postal_code not like :excludePostCode', { excludePostCode: `%${postalCode}%` })
1953
+ })
1954
+ )
1955
+ .andWhere('lmdb.bizplace_id = :bzId', { bzId: bizplace.id })
1956
+ .orderBy('lmdb.bizplace_id', 'ASC')
1957
+ .addOrderBy('lmds.include_postal_code')
1958
+ .addOrderBy('lmd.rank', 'ASC')
1959
+
1960
+ lmdResult = await qb.getOne()
1961
+
1962
+ if (!lmdResult) {
1963
+ const newQb: SelectQueryBuilder<LastMileDelivery> = getRepository(LastMileDelivery)
1964
+ .createQueryBuilder('lmd')
1965
+ .leftJoinAndSelect('lmd.lastMileDeliverySettings', 'lmds')
1966
+ .innerJoinAndSelect('lmds.geoCountry', 'gc')
1967
+ .leftJoinAndSelect(`lmd.lastMileDeliveryBizplaces`, `lmdb`)
1968
+ .leftJoinAndSelect('lmdb.bizplace', 'bz')
1969
+ .where('lmd.domain_id = :domainId', { domainId: domain.id })
1970
+ .andWhere('lower(lmd.status) = :status', { status: 'active' })
1971
+ .andWhere('gc.id = :gcId', { gcId: countryId })
1972
+ .andWhere(
1973
+ new Brackets(qb => {
1974
+ qb.where(`lmds.include_postal_code = ''`)
1975
+ .orWhere('lmds.include_postal_code is null')
1976
+ .orWhere('lmds.include_postal_code like :includePostCode', { includePostCode: `%${postalCode}%` })
1977
+ })
1978
+ )
1979
+ .andWhere(
1980
+ new Brackets(qb => {
1981
+ qb.where(`lmds.exclude_postal_code = ''`)
1982
+ .orWhere('lmds.exclude_postal_code is null')
1983
+ .orWhere('lmds.exclude_postal_code not like :excludePostCode', { excludePostCode: `%${postalCode}%` })
1984
+ })
1985
+ )
1986
+ .orderBy('lmds.include_postal_code')
1987
+ .addOrderBy('lmd.rank', 'ASC')
1988
+
1989
+ lmdResult = await newQb.getOne()
1990
+ }
1991
+
1992
+ return lmdResult
1993
+ }
@@ -1,19 +1,60 @@
1
- import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'
2
- import { EntityManager, getRepository, In, Repository, SelectQueryBuilder } from 'typeorm'
1
+ import {
2
+ Arg,
3
+ Args,
4
+ Ctx,
5
+ Directive,
6
+ FieldResolver,
7
+ Query,
8
+ Resolver,
9
+ Root
10
+ } from 'type-graphql'
11
+ import {
12
+ EntityManager,
13
+ getRepository,
14
+ In,
15
+ Repository,
16
+ SelectQueryBuilder
17
+ } from 'typeorm'
3
18
 
4
19
  import { Attachment } from '@things-factory/attachment-base'
5
- import { checkUserBelongsDomain, User } from '@things-factory/auth-base'
6
- import { Bizplace, getCompanyBizplace, getMyBizplace, getPermittedBizplaceIds } from '@things-factory/biz-base'
20
+ import {
21
+ checkUserBelongsDomain,
22
+ User
23
+ } from '@things-factory/auth-base'
24
+ import {
25
+ Bizplace,
26
+ getCompanyBizplace,
27
+ getMyBizplace,
28
+ getPermittedBizplaceIds
29
+ } from '@things-factory/biz-base'
7
30
  import { logger } from '@things-factory/env'
8
- import { buildQuery, Domain, Filter, ListParam, Pagination, Sorting } from '@things-factory/shell'
9
- import { Inventory, LOCATION_TYPE } from '@things-factory/warehouse-base'
10
-
11
- import { ATTACHMENT_TYPE, ORDER_INVENTORY_STATUS, ORDER_STATUS } from '../../constants'
31
+ import {
32
+ buildQuery,
33
+ Domain,
34
+ Filter,
35
+ ListParam,
36
+ Pagination,
37
+ Sorting
38
+ } from '@things-factory/shell'
39
+ import {
40
+ Inventory,
41
+ LOCATION_TYPE
42
+ } from '@things-factory/warehouse-base'
43
+
44
+ import {
45
+ ATTACHMENT_TYPE,
46
+ ORDER_INVENTORY_STATUS,
47
+ ORDER_STATUS
48
+ } from '../../constants'
12
49
  import { OrderInventory } from '../order-inventory/order-inventory'
13
50
  import { OrderPackage } from '../order-package/order-package'
14
51
  import { ShippingOrder } from '../shipping-order/shipping-order'
15
52
  import { ReleaseGood } from './release-good'
16
- import { NewReleaseGood, ReleasableInventoryList, ReleaseGoodList } from './release-good-types'
53
+ import {
54
+ NewReleaseGood,
55
+ ReleasableInventoryList,
56
+ ReleaseGoodList
57
+ } from './release-good-types'
17
58
 
18
59
  @Resolver(ReleaseGood)
19
60
  export class ReleaseGoodQuery {
@@ -224,6 +265,20 @@ export class ReleaseGoodQuery {
224
265
  category: ATTACHMENT_TYPE.DELIVERY_ORDER
225
266
  }
226
267
  })
268
+ const foundInvoiceAttachments: Attachment = await tx.getRepository(Attachment).findOne({
269
+ where: {
270
+ domain,
271
+ refBy: releaseGood.id,
272
+ category: ATTACHMENT_TYPE.INVOICE
273
+ }
274
+ })
275
+ const foundAwbAttachments: Attachment = await tx.getRepository(Attachment).findOne({
276
+ where: {
277
+ domain,
278
+ refBy: releaseGood.id,
279
+ category: ATTACHMENT_TYPE.AWB
280
+ }
281
+ })
227
282
 
228
283
  let invInfos = await Promise.all(
229
284
  orderInventories.map(async (orderInv: OrderInventory) => {
@@ -260,6 +315,8 @@ export class ReleaseGoodQuery {
260
315
  const result = {
261
316
  ...releaseGood,
262
317
  attachment: foundAttachments,
318
+ invoiceAttachment: foundInvoiceAttachments,
319
+ awbAttachment: foundAwbAttachments,
263
320
  shippingOrderInfo: {
264
321
  containerNo: shippingOrder?.containerNo || '',
265
322
  containerSize: shippingOrder?.containerSize || '',
@@ -298,6 +355,7 @@ export class ReleaseGoodQuery {
298
355
  const manifestedFilter = params.filters.find(param => param.name === 'manifested')
299
356
  const orderInfoFilter = params.filters.find(param => param.name === 'name')
300
357
  const typeFilter = params.filters.find(param => param.name === 'type')?.value
358
+ const lmdFilter = params.filters.find(param => param.name === 'lmdOption')
301
359
 
302
360
  if (await checkUserBelongsDomain(domain, user)) {
303
361
  if (!statusFilter && !params.filters.some(e => e.name === 'name')) {
@@ -382,6 +440,27 @@ export class ReleaseGoodQuery {
382
440
  }
383
441
  }
384
442
 
443
+ if (lmdFilter) {
444
+ const lmdIdx = params.filters.findIndex(param => param.name === 'lmdOption')
445
+ if (lmdFilter.value == true) {
446
+ params.filters.splice(lmdIdx, 1)
447
+ params.filters.push({
448
+ name: 'lmdOption',
449
+ operator: 'is_not_null',
450
+ value: null,
451
+ relation: false
452
+ })
453
+ } else {
454
+ params.filters.splice(lmdIdx, 1)
455
+ params.filters.push({
456
+ name: 'lmdOption',
457
+ operator: 'is_null',
458
+ value: null,
459
+ relation: false
460
+ })
461
+ }
462
+ }
463
+
385
464
  const fromDateParamIdx = params.filters.findIndex(param => param.name === 'fromDate')
386
465
  if (fromDateParamIdx >= 0) {
387
466
  let fromDateVal = new Date(params.filters[fromDateParamIdx].value)
@@ -1,6 +1,15 @@
1
- import { Field, Float, InputType, Int, ObjectType } from 'type-graphql'
2
-
3
- import { Product, ProductDetail } from '@things-factory/product-base'
1
+ import {
2
+ Field,
3
+ Float,
4
+ InputType,
5
+ Int,
6
+ ObjectType
7
+ } from 'type-graphql'
8
+
9
+ import {
10
+ Product,
11
+ ProductDetail
12
+ } from '@things-factory/product-base'
4
13
  import { ObjectRef } from '@things-factory/shell'
5
14
  import { Location } from '@things-factory/warehouse-base'
6
15
 
@@ -398,6 +407,9 @@ export class NewReleaseGood {
398
407
 
399
408
  @Field({ nullable: true })
400
409
  ward: string
410
+
411
+ @Field({ nullable: true })
412
+ lmdOption: Boolean
401
413
  }
402
414
 
403
415
  @InputType()
@@ -1,4 +1,8 @@
1
- import { Field, ID, ObjectType } from 'type-graphql'
1
+ import {
2
+ Field,
3
+ ID,
4
+ ObjectType
5
+ } from 'type-graphql'
2
6
  import {
3
7
  Column,
4
8
  CreateDateColumn,
@@ -15,7 +19,10 @@ import {
15
19
 
16
20
  import { Attachment } from '@things-factory/attachment-base'
17
21
  import { User } from '@things-factory/auth-base'
18
- import { Bizplace, ContactPoint } from '@things-factory/biz-base'
22
+ import {
23
+ Bizplace,
24
+ ContactPoint
25
+ } from '@things-factory/biz-base'
19
26
  import { config } from '@things-factory/env'
20
27
  import { LastMileDelivery } from '@things-factory/integration-lmd'
21
28
  import { Domain } from '@things-factory/shell'
@@ -411,6 +418,12 @@ export class ReleaseGood {
411
418
  @Field(type => [Attachment], { nullable: true })
412
419
  attachment?: Attachment[]
413
420
 
421
+ @Field(type => Attachment, { nullable: true })
422
+ invoiceAttachment?: Attachment[]
423
+
424
+ @Field(type => Attachment, { nullable: true })
425
+ awbAttachment?: Attachment[]
426
+
414
427
  @Field(type => [InventoryInfos], { nullable: true })
415
428
  inventoryInfos?: InventoryInfos[]
416
429
 
@@ -103,7 +103,10 @@ export const InventoryUtil = {
103
103
  coalesce(p.brand, '') AS "productBrand",
104
104
  p.id AS "productId",
105
105
  pd.id AS "productDetailId",
106
- COALESCE(SUM(COALESCE(i.qty, 0)) - SUM(COALESCE(i.locked_qty, 0)) - COALESCE(pds.unassigned_qty, 0) - MAX(COALESCE(oi.release_qty, 0)) - MAX(COALESCE(bp.bundle_product_release_qty, 0)),0) AS "remainQty",
106
+ (
107
+ CASE WHEN (COALESCE(SUM(COALESCE(i.qty, 0)) - GREATEST(SUM(COALESCE(i.locked_qty, 0)), 0) - GREATEST(COALESCE(pds.unassigned_qty, 0), 0) - MAX(COALESCE(oi.release_qty, 0)) - MAX(COALESCE(bp.bundle_product_release_qty, 0)),0)) < 0 THEN 0
108
+ ELSE COALESCE(SUM(COALESCE(i.qty, 0)) - GREATEST(SUM(COALESCE(i.locked_qty, 0)), 0) - GREATEST(COALESCE(pds.unassigned_qty, 0), 0) - MAX(COALESCE(oi.release_qty, 0)) - MAX(COALESCE(bp.bundle_product_release_qty, 0)),0) END
109
+ ) AS "remainQty",
107
110
  COALESCE(SUM(COALESCE(i.uom_value, 0)) - SUM(COALESCE(i.locked_uom_value, 0)) - COALESCE(pds.unassigned_uom_value, 0) - MAX(COALESCE(oi.release_uom_value, 0)) - MAX(COALESCE(bp.bundle_product_release_uom_value, 0)),0) AS "remainUomValue",
108
111
  concat(SUM(COALESCE(i.uom_value, 0)) - SUM(COALESCE(i.locked_uom_value, 0)) - COALESCE(pds.unassigned_uom_value, 0) - MAX(COALESCE(oi.release_uom_value, 0)) - MAX(COALESCE(bp.bundle_product_release_uom_value, 0)), ' ', pd.uom) AS "remainUomValueWithUom",
109
112
  COALESCE(SUM(COALESCE(i.transfer_qty, 0)), 0) AS "transferQty",
@@ -159,7 +162,10 @@ export const InventoryUtil = {
159
162
  FROM product_bundles pb
160
163
  LEFT JOIN (
161
164
  SELECT pbs.product_id, pbs.product_bundle_id, min(pbs.bundle_qty),
162
- (SUM(COALESCE(i2.qty, 0)) - SUM(COALESCE(i2.locked_qty, 0)) - COALESCE(pds2.unassigned_qty, 0) - MAX(COALESCE(oi.release_qty, 0))) / min(pbs.bundle_qty) AS "availableQty",
165
+ (
166
+ CASE WHEN ((SUM(COALESCE(i2.qty, 0)) - GREATEST(SUM(COALESCE(i2.locked_qty, 0)), 0) - GREATEST(COALESCE(pds2.unassigned_qty, 0), 0) - MAX(COALESCE(oi.release_qty, 0))) / min(pbs.bundle_qty)) < 0 THEN 0
167
+ ELSE (SUM(COALESCE(i2.qty, 0)) - GREATEST(SUM(COALESCE(i2.locked_qty, 0)), 0) - GREATEST(COALESCE(pds2.unassigned_qty, 0), 0) - MAX(COALESCE(oi.release_qty, 0))) / min(pbs.bundle_qty) END
168
+ ) AS "availableQty",
163
169
  (SUM(COALESCE(i2.uom_value, 0)) - SUM(COALESCE(i2.locked_uom_value, 0)) - COALESCE(pds2.unassigned_uom_value, 0) - MAX(COALESCE(oi.release_uom_value, 0))) / min(pbs.bundle_qty) AS "availableUomValue",
164
170
  (SUM(COALESCE(i2.transfer_qty, 0)) / min(pbs.bundle_qty)) AS "transferQty",
165
171
  (SUM(COALESCE(i2.transfer_uom_value, 0)) / min(pbs.bundle_qty)) AS "transferUomValue",
@@ -292,7 +298,7 @@ export const InventoryUtil = {
292
298
  coalesce(p.brand, '') AS "productBrand",
293
299
  p.id AS "productId",
294
300
  i.product_detail_id AS "productDetailId",
295
- SUM(COALESCE(i.qty, 0)) - SUM(COALESCE(i.locked_qty, 0)) - MAX(COALESCE(oi.release_qty, 0)) - MAX(COALESCE(bp.bundle_product_release_qty, 0)) - SUM(COALESCE(pds.unassigned_qty, 0)) AS "remainQty",
301
+ SUM(COALESCE(i.qty, 0)) - GREATEST(SUM(COALESCE(i.locked_qty, 0)), 0) - MAX(COALESCE(oi.release_qty, 0)) - MAX(COALESCE(bp.bundle_product_release_qty, 0)) - GREATEST(SUM(COALESCE(pds.unassigned_qty, 0)), 0) AS "remainQty",
296
302
  SUM(COALESCE(i.uom_value, 0)) - SUM(COALESCE(i.locked_uom_value, 0)) - MAX(COALESCE(oi.release_uom_value, 0)) - MAX(COALESCE(bp.bundle_product_release_uom_value, 0)) - SUM(COALESCE(pds.unassigned_uom_value, 0)) AS "remainUomValue",
297
303
  concat(SUM(COALESCE(i.uom_value, 0)) - SUM(COALESCE(i.locked_uom_value, 0)) - MAX(COALESCE(oi.release_uom_value, 0)) - MAX(COALESCE(bp.bundle_product_release_uom_value, 0)) - SUM(COALESCE(pds.unassigned_uom_value, 0)), ' ', i.uom) AS "remainUomValueWithUom",
298
304
  'SINGLE' AS "groupType"
@@ -332,7 +338,7 @@ export const InventoryUtil = {
332
338
  FROM product_bundles pb
333
339
  INNER JOIN (
334
340
  SELECT pbs.product_id, pbs.product_bundle_id, min(pbs.bundle_qty),
335
- (SUM(COALESCE(i2.qty, 0)) - SUM(COALESCE(i2.locked_qty, 0)) - MAX(COALESCE(oi.release_qty, 0))) / min(pbs.bundle_qty) AS "availableQty",
341
+ (SUM(COALESCE(i2.qty, 0)) - GREATEST(SUM(COALESCE(i2.locked_qty, 0)), 0) - MAX(COALESCE(oi.release_qty, 0))) / min(pbs.bundle_qty) AS "availableQty",
336
342
  (SUM(COALESCE(i2.uom_value, 0)) - SUM(COALESCE(i2.locked_uom_value, 0)) - MAX(COALESCE(oi.release_uom_value, 0))) / min(pbs.bundle_qty) AS "availableUomValue",
337
343
  pbs.product_detail_id
338
344
  FROM product_bundle_settings pbs