@things-factory/sales-base 4.3.1 → 4.3.4

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,13 +1,12 @@
1
1
  import { FileUpload, GraphQLUpload } from 'graphql-upload'
2
2
  import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
3
- import { EntityManager, getConnection, getRepository, In, Repository } from 'typeorm'
3
+ import { EntityManager, getConnection, getRepository, In, IsNull, Repository } from 'typeorm'
4
4
 
5
5
  import { Attachment, createAttachments, deleteAttachmentsByRef } from '@things-factory/attachment-base'
6
6
  import { User } from '@things-factory/auth-base'
7
- import { InventoryUtil } from '../../utils'
8
- import { Bizplace, ContactPoint, getPermittedBizplaces, getPermittedBizplaceIds } from '@things-factory/biz-base'
7
+ import { Bizplace, getPermittedBizplaces } from '@things-factory/biz-base'
9
8
  import { generateId } from '@things-factory/id-rule-base'
10
- import { Product, ProductBundle } from '@things-factory/product-base'
9
+ import { Product, ProductBundle, ProductDetail } from '@things-factory/product-base'
11
10
  import { Setting } from '@things-factory/setting-base'
12
11
  import { Domain } from '@things-factory/shell'
13
12
 
@@ -20,8 +19,12 @@ import {
20
19
  ORDER_NUMBER_SETTING_KEY,
21
20
  ORDER_STATUS
22
21
  } from '../../constants'
23
- import { OrderNoGenerator } from '../../utils'
22
+ import { ValidationError } from '../../errors'
23
+ import { InventoryUtil, OrderNoGenerator } from '../../utils'
24
24
  import { OrderProductPatch } from '../order-product/order-product-types'
25
+ import { ReleaseGood } from '../release-good/release-good'
26
+ import { bulkGenerateReleaseGood, confirmReleaseGood } from '../release-good/release-good-mutation'
27
+ import { bulkReleaseGoodsAvailableItemsFunction } from '../release-good/release-good-query'
25
28
  import { ShippingOrder } from '../shipping-order/shipping-order'
26
29
  import { ShippingOrderPatch } from '../shipping-order/shipping-order-types'
27
30
  // import {
@@ -31,10 +34,6 @@ import { ShippingOrderPatch } from '../shipping-order/shipping-order-types'
31
34
  // receiveArrivalNoticeFunction
32
35
  // } from '../arrival-notice/arrival-notice-mutation'
33
36
  import { getDraftReleaseGoodFunction } from './draft-release-good-query'
34
- import { ReleaseGood } from '../release-good/release-good'
35
- import { bulkReleaseGoodsAvailableItemsFunction } from '../release-good/release-good-query'
36
- import { confirmReleaseGood, bulkGenerateReleaseGood } from '../release-good/release-good-mutation'
37
- import { ValidationError } from '../../errors'
38
37
 
39
38
  @Resolver(DraftReleaseGood)
40
39
  export class DraftReleaseGoodMutation {
@@ -181,7 +180,7 @@ export class DraftReleaseGoodMutation {
181
180
  @Mutation(returns => Boolean, { description: 'To generate Release Goods from Draft' })
182
181
  async generateReleaseGoodsFromDraft(
183
182
  @Ctx() context: any,
184
- @Arg('ids', type => [String]) ids: string[],
183
+ @Arg('ids', type => [String]) ids: string[]
185
184
  // @Arg('rawReleaseGoods', type => [NewReleaseGood], { nullable: true }) rawReleaseGoods: NewReleaseGood[],
186
185
  // @Arg('bizplaceId', type => String) bizplaceId: string
187
186
  ): Promise<boolean> {
@@ -205,7 +204,6 @@ export class DraftReleaseGoodMutation {
205
204
  ]
206
205
  })
207
206
  if (updatableDraftOrders.length > 0) {
208
-
209
207
  let createdReleaseGoods: ReleaseGood[] = []
210
208
  const settingRepo: Repository<Setting> = tx?.getRepository(Setting) || getRepository(Setting)
211
209
 
@@ -217,7 +215,7 @@ export class DraftReleaseGoodMutation {
217
215
  })
218
216
 
219
217
  for (let index = 0; index < updatableDraftOrders.length; index++) {
220
- const draftOrder = updatableDraftOrders[index];
218
+ const draftOrder = updatableDraftOrders[index]
221
219
 
222
220
  let foundPermittedBizplace: Bizplace
223
221
  let companyBizplace: Bizplace
@@ -234,20 +232,41 @@ export class DraftReleaseGoodMutation {
234
232
 
235
233
  const bizplaces: Bizplace[] = [foundPermittedBizplace, companyBizplace]
236
234
 
237
- let productInventory = await InventoryUtil.bizplaceProductInventory(bizplaces, {
238
- filters: [{
239
- name: 'productId',
240
- operator: 'in',
241
- value: [
242
- ...draftOrder.orderProducts.filter(itm => itm?.product).map(itm => { return itm.product.id }),
243
- ...draftOrder.orderProducts.filter(itm => itm?.productBundle).map(itm => { return itm.productBundle.id })
235
+ let productInventory = await InventoryUtil.bizplaceProductInventory(
236
+ bizplaces,
237
+ {
238
+ filters: [
239
+ {
240
+ name: 'productId',
241
+ operator: 'in',
242
+ value: [
243
+ ...draftOrder.orderProducts
244
+ .filter(itm => itm?.product)
245
+ .map(itm => {
246
+ return itm.product.id
247
+ }),
248
+ ...draftOrder.orderProducts
249
+ .filter(itm => itm?.productBundle)
250
+ .map(itm => {
251
+ return itm.productBundle.id
252
+ })
253
+ ]
254
+ }
244
255
  ]
245
- }]
246
- }, context, tx)
247
-
256
+ },
257
+ context,
258
+ tx
259
+ )
248
260
 
249
261
  draftOrder.orderProducts = draftOrder.orderProducts.map(itm => {
250
- let foundProductInv = productInventory.items.find(i => (i.productId == itm?.product?.id || i.productId == itm?.productBundle?.id) && i.packingType == itm.packingType && i.packingSize == itm.packingSize && i.uom == itm.uom && itm.releaseQty <= i.remainQty)
262
+ let foundProductInv = productInventory.items.find(
263
+ i =>
264
+ (i.productId == itm?.product?.id || i.productId == itm?.productBundle?.id) &&
265
+ i.packingType == itm.packingType &&
266
+ i.packingSize == itm.packingSize &&
267
+ i.uom == itm.uom &&
268
+ itm.releaseQty <= i.remainQty
269
+ )
251
270
  return { ...itm, status: foundProductInv ? 'suffice' : 'insufficient' }
252
271
  })
253
272
 
@@ -266,13 +285,20 @@ export class DraftReleaseGoodMutation {
266
285
  let orderInventories = []
267
286
 
268
287
  for (let index = 0; index < draftOrder.orderProducts.length; index++) {
269
- const itm = draftOrder.orderProducts[index];
288
+ const itm = draftOrder.orderProducts[index]
270
289
  let data = []
271
290
  if (itm.productBundle) {
272
- let bundle = await tx.getRepository(ProductBundle).findOne({ where: { id: itm.productBundle.id }, relations: ['productBundleSettings', 'productBundleSettings.productDetail', 'productBundleSettings.product',] })
291
+ let bundle = await tx.getRepository(ProductBundle).findOne({
292
+ where: { id: itm.productBundle.id },
293
+ relations: [
294
+ 'productBundleSettings',
295
+ 'productBundleSettings.productDetail',
296
+ 'productBundleSettings.product'
297
+ ]
298
+ })
273
299
 
274
300
  for (let index2 = 0; index2 < bundle.productBundleSettings.length; index2++) {
275
- const objProductBundleSetting = bundle.productBundleSettings[index2];
301
+ const objProductBundleSetting = bundle.productBundleSettings[index2]
276
302
  data.push({
277
303
  sku: objProductBundleSetting.product.sku,
278
304
  packing_type: objProductBundleSetting.productDetail.packingType,
@@ -285,24 +311,27 @@ export class DraftReleaseGoodMutation {
285
311
  })
286
312
  }
287
313
  } else {
288
- data = [{
289
- sku: itm.product.sku,
290
- packing_type: itm.packingType,
291
- packing_size: itm.packingSize,
292
- uom: itm.uom,
293
- release_qty: itm.releaseQty,
294
- assignedQty: undefined,
295
- assignedUomValue: undefined,
296
- releaseUomValue: undefined
297
- }]
314
+ data = [
315
+ {
316
+ sku: itm.product.sku,
317
+ packing_type: itm.packingType,
318
+ packing_size: itm.packingSize,
319
+ uom: itm.uom,
320
+ release_qty: itm.releaseQty,
321
+ assignedQty: undefined,
322
+ assignedUomValue: undefined,
323
+ releaseUomValue: undefined
324
+ }
325
+ ]
298
326
  }
299
327
 
300
328
  data.forEach(data => {
301
- let existingOI = orderInventories.find(itm =>
302
- itm.sku == data.sku &&
303
- itm.packing_type == data.packing_type &&
304
- itm.packing_size == data.packing_size &&
305
- itm.uom == data.uom
329
+ let existingOI = orderInventories.find(
330
+ itm =>
331
+ itm.sku == data.sku &&
332
+ itm.packing_type == data.packing_type &&
333
+ itm.packing_size == data.packing_size &&
334
+ itm.uom == data.uom
306
335
  )
307
336
 
308
337
  if (existingOI) {
@@ -310,11 +339,10 @@ export class DraftReleaseGoodMutation {
310
339
  } else {
311
340
  orderInventories.push(data)
312
341
  }
313
- });
342
+ })
314
343
  }
315
344
  try {
316
345
  await getConnection().transaction(async (childTx: EntityManager) => {
317
-
318
346
  let availableItems: any[] = await bulkReleaseGoodsAvailableItemsFunction(
319
347
  orderInventories,
320
348
  draftOrder.bizplace.id,
@@ -347,16 +375,17 @@ export class DraftReleaseGoodMutation {
347
375
 
348
376
  await childTx
349
377
  .getRepository(DraftReleaseGood)
350
- .update({ id: draftOrder.id }, { releaseGood: createdReleaseGood, status: DRAFT_RELEASE_ORDER_STATUS.SUBMITTED })
378
+ .update(
379
+ { id: draftOrder.id },
380
+ { releaseGood: createdReleaseGood, status: DRAFT_RELEASE_ORDER_STATUS.SUBMITTED }
381
+ )
351
382
 
352
383
  createdReleaseGood = await confirmReleaseGood(createdReleaseGood.name, context, childTx)
353
-
354
384
  })
355
385
  } catch (error) {
356
386
  console.error(error)
357
387
  }
358
388
  }
359
-
360
389
  }
361
390
  }
362
391
 
@@ -585,7 +614,13 @@ export async function upsertDraftReleaseGoodProducts(
585
614
 
586
615
  draftReleaseGood = await draftReleaseGoodRepo.findOne({
587
616
  where: { id: draftReleaseGood.id },
588
- relations: ['orderProducts', 'orderProducts.product', 'orderProducts.productBundle', 'orderProducts.creator', 'orderProducts.updater']
617
+ relations: [
618
+ 'orderProducts',
619
+ 'orderProducts.product',
620
+ 'orderProducts.productBundle',
621
+ 'orderProducts.creator',
622
+ 'orderProducts.updater'
623
+ ]
589
624
  })
590
625
 
591
626
  // Remove all existing order products that do not exist in current input
@@ -648,15 +683,43 @@ export async function upsertDraftReleaseGoodProducts(
648
683
  productBundle = existingOP.productBundle
649
684
  updatePatch['product'] = existingOP.product || undefined
650
685
  updatePatch['productBundle'] = existingOP.productBundle || undefined
686
+ } else {
687
+ product = await productRepo.findOne({
688
+ where: { domain: customerCompanyDomain, sku: op.product.sku, deletedAt: IsNull() },
689
+ relations: ['productDetails']
690
+ })
691
+ if (product) {
692
+ const productDetails: ProductDetail[] = product.productDetails
693
+ let selectedProductDetail: ProductDetail[]
694
+ if (op?.product?.packingType) {
695
+ selectedProductDetail = productDetails.filter(pd => pd.packingType == op.product.packingType)
696
+ } else {
697
+ selectedProductDetail = productDetails.filter(pd => pd.isDefault)
698
+ }
699
+
700
+ product.packingType = selectedProductDetail[0].packingType
701
+ product.primaryUnit = selectedProductDetail[0].uom
702
+ product.primaryValue = selectedProductDetail[0].uomValue
703
+ }
704
+
705
+ updatePatch['product'] = product || undefined
706
+
707
+ if (!product) {
708
+ productBundle = await productBundleRepo.findOne({
709
+ where: { domain: customerCompanyDomain, sku: op.product.sku }
710
+ })
711
+ updatePatch['productBundle'] = productBundle || undefined
712
+ }
713
+
714
+ if (!product && !productBundle) throw new Error(`product not found`)
651
715
  }
652
716
  }
653
717
 
654
-
655
718
  updatePatch['packingType'] = op?.packingType
656
719
  ? op.packingType
657
720
  : product?.packingType
658
- ? product.packingType
659
- : productBundle.packingType
721
+ ? product.packingType
722
+ : productBundle.packingType
660
723
  updatePatch['uom'] = op?.uom ? op.uom : product?.primaryUnit ? product.primaryUnit : 'UNIT'
661
724
  updatePatch['uomValue'] = op?.uomValue ? op.uomValue : product?.primaryValue ? product.primaryValue : 0
662
725
 
@@ -282,7 +282,7 @@ export async function getDraftReleaseGoodFunction(_: any, name: any, context: an
282
282
 
283
283
  let productInventory
284
284
  if (result.orderProducts.length > 0)
285
- productInventory = await InventoryUtil.bizplaceProductInventory(bizplaces, { filters: [{ name: 'productId', operator: 'in', value: [...result.orderProducts.filter(itm => itm?.product).map(itm => { return itm.product.id }), ...result.orderProducts.filter(itm => itm?.productBundle).map(itm => { return itm.productBundle.id })] }] }, context, tx)
285
+ productInventory = await InventoryUtil.bizplaceProductInventory(bizplaces, { filters: [{ name: 'bizplaceId', operator: 'eq', value: result.bizplace.id }, { name: 'productId', operator: 'in', value: [...result.orderProducts.filter(itm => itm?.product).map(itm => { return itm.product.id }), ...result.orderProducts.filter(itm => itm?.productBundle).map(itm => { return itm.productBundle.id })] }] }, context, tx)
286
286
 
287
287
  result.orderProducts = result.orderProducts.map(itm => {
288
288
  let foundProductInv = productInventory?.items.find(i => (i.productId == itm?.product?.id || i.productId == itm?.productBundle?.id) && i.packingType == itm.packingType && i.packingSize == itm.packingSize && i.uom == itm.uom)
@@ -29,7 +29,7 @@ export class OtherQuery {
29
29
 
30
30
  let permittedBizplaces: Bizplace[] = await getPermittedBizplaces(domain, user)
31
31
 
32
- let bizplaceId: any = params.filters.find(filter => filter.name === 'bizplace_id').value
32
+ let bizplaceId: any = params.filters.find(filter => filter.name === 'bizplaceId').value
33
33
  let foundPermittedBizplace: Bizplace
34
34
  let companyBizplace: Bizplace
35
35
 
@@ -43,6 +43,15 @@ export class InventoryProductGroup {
43
43
  @Field(type => Int, { nullable: true })
44
44
  packQty: number
45
45
 
46
+ @Field(type => Int, { nullable: true })
47
+ totalQty: number
48
+
49
+ @Field(type => Int, { nullable: true })
50
+ totalLockedQty: number
51
+
52
+ @Field(type => Int, { nullable: true })
53
+ totalLockedUomValue: number
54
+
46
55
  @Field(type => Int, { nullable: true })
47
56
  palletQty: number
48
57
 
@@ -134,7 +134,7 @@ export class ReleaseGoodMutation {
134
134
  context,
135
135
  tx
136
136
  )
137
- } catch (error) { }
137
+ } catch (error) {}
138
138
 
139
139
  if (errorsCaught.length)
140
140
  throw new ValidationError({
@@ -797,7 +797,10 @@ export async function confirmReleaseGood(name: string, context: any, tx?: Entity
797
797
  const companyDomain: Domain = customerBizplace?.company.domain
798
798
  const sellercraft: Sellercraft = await tx
799
799
  .getRepository(Sellercraft)
800
- .findOne({ domain: foundReleaseGood.bizplace.domain, status: SellercraftStatus.ACTIVE })
800
+ .findOne({
801
+ where: { domain: foundReleaseGood.bizplace.domain, status: SellercraftStatus.ACTIVE },
802
+ relations: ['domain']
803
+ })
801
804
 
802
805
  if (foundReleaseGood.type == 'b2c') {
803
806
  if (sellercraft) {
@@ -52,6 +52,7 @@ export const InventoryUtil = {
52
52
 
53
53
  const { domain }: { domain: Domain } = context.state
54
54
 
55
+
55
56
  const { bizplaceIds, productWhereClause, bundleWhereClause, whereClause, batchBundle, productDetailWhereClause } = await getConditions(
56
57
  bizplaces,
57
58
  filters,
@@ -60,6 +61,7 @@ export const InventoryUtil = {
60
61
  )
61
62
 
62
63
  let productFilter = filters.find(itm => itm.name == 'productName')
64
+ let inventoryBizplaceFilter = filters.find(itm => itm.name == 'bizplaceId')
63
65
 
64
66
  let queryStrings = `
65
67
  CREATE TEMP TABLE temp_inventory_product_group ON COMMIT DROP AS (
@@ -111,9 +113,16 @@ export const InventoryUtil = {
111
113
  'SINGLE' AS "groupType"
112
114
  FROM products p
113
115
  INNER join product_details pd on pd.product_id = p.id
114
- LEFT JOIN inventories i ON i.product_id = p.id and i.domain_id = $1 and i.status = 'STORED'
115
- INNER JOIN locations l2 ON i.location_id = l2.id AND i.domain_id = l2.domain_id AND l2.type NOT IN ('${LOCATION_TYPE.QUARANTINE}', '${LOCATION_TYPE.RESERVE}')
116
- and i.packing_type = pd.packing_type and i.packing_size = pd.packing_size and i.uom = pd.uom
116
+ LEFT JOIN (
117
+ SELECT i.* FROM inventories i
118
+ INNER JOIN locations l2 ON i.location_id = l2.id AND i.domain_id = l2.domain_id
119
+ WHERE l2.type NOT IN ('${LOCATION_TYPE.QUARANTINE}', '${LOCATION_TYPE.RESERVE}')
120
+ AND i.domain_id = $1 AND i.status = 'STORED'
121
+ ${inventoryBizplaceFilter ? `AND i.bizplace_id = '${inventoryBizplaceFilter.value}'` : ``}
122
+ ) i ON i.product_id = pd.product_id
123
+ AND i.packing_type = pd.packing_type
124
+ and i.packing_size = pd.packing_size
125
+ and i.uom = pd.uom
117
126
  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
118
127
  LEFT JOIN (
119
128
  SELECT pbs.product_id, SUM(pbs.bundle_qty * src.release_qty) AS bundle_product_release_qty, SUM(pbs.bundle_qty * src.release_uom_value) AS bundle_product_release_uom_value
@@ -122,11 +131,11 @@ export const InventoryUtil = {
122
131
  GROUP BY pbs.product_id
123
132
  ) bp on i.product_id = bp.product_id
124
133
  WHERE p.bizplace_id IN (${bizplaceIds})
125
- ${productDetailWhereClause}
126
- ${productFilter ? `AND (
127
- lower(p.sku) ilike '${productFilter.value}'
128
- OR lower(p.name) ilike '${productFilter.value}'
129
- OR lower(p.description) ilike '${productFilter.value}'
134
+ ${productDetailWhereClause}
135
+ ${productFilter ? `AND (
136
+ lower(p.sku) ilike '${productFilter.value}'
137
+ OR lower(p.name) ilike '${productFilter.value}'
138
+ OR lower(p.description) ilike '${productFilter.value}'
130
139
  )
131
140
  ` : ``}
132
141
  GROUP BY
@@ -146,11 +155,11 @@ export const InventoryUtil = {
146
155
  (SUM(COALESCE(i2.qty, 0)) - SUM(COALESCE(i2.locked_qty, 0)) - MAX(COALESCE(oi.release_qty, 0))) / min(pbs.bundle_qty) AS "availableQty",
147
156
  (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"
148
157
  FROM product_bundle_settings pbs
149
- LEFT JOIN inventories i2 ON i2.product_id = pbs.product_id AND i2.domain_id = $1
150
- INNER JOIN locations l2 ON i2.location_id = l2.id AND i2.domain_id = l2.domain_id AND l2.type NOT IN ('${LOCATION_TYPE.QUARANTINE}', '${LOCATION_TYPE.RESERVE}')
151
- AND i2.bizplace_id IN (${bizplaceIds})
152
- AND i2.status = 'STORED'
158
+ LEFT JOIN inventories i2 ON i2.product_id = pbs.product_id AND i2.domain_id = $1 AND i2.status = 'STORED'
159
+ INNER JOIN locations l2 ON i2.location_id = l2.id
153
160
  LEFT JOIN oi ON oi.product_id = i2.product_id
161
+ WHERE l2.type NOT IN ('${LOCATION_TYPE.QUARANTINE}', '${LOCATION_TYPE.RESERVE}')
162
+ ${inventoryBizplaceFilter ? `AND i2.bizplace_id = '${inventoryBizplaceFilter.value}'` : ``}
154
163
  GROUP BY
155
164
  pbs.product_id,
156
165
  pbs.product_bundle_id
@@ -382,8 +391,8 @@ export const InventoryUtil = {
382
391
  p.id AS "productId",
383
392
  SUM(COALESCE(i.qty, 0)) - SUM(COALESCE(i.locked_qty, 0)) - MAX(COALESCE(oi.release_qty, 0)) AS "remainQty",
384
393
  SUM(COALESCE(i.uom_value, 0)) - SUM(COALESCE(i.locked_uom_value, 0)) - MAX(COALESCE(oi.release_uom_value, 0)) AS "remainUomValue",
385
- SUM(COALESCE(i.qty, 0))) AS "totalQty",
386
- SUM(COALESCE(i.uom_value, 0))) AS "totalUomValue",
394
+ SUM(COALESCE(i.qty, 0)) AS "totalQty",
395
+ SUM(COALESCE(i.uom_value, 0)) AS "totalUomValue",
387
396
  SUM(COALESCE(i.locked_qty, 0)) + MAX(COALESCE(oi.release_qty, 0)) AS "totalLockedQty",
388
397
  SUM(COALESCE(i.locked_uom_value, 0)) + MAX(COALESCE(oi.release_uom_value, 0)) AS "totalLockedUomValue",
389
398
  concat(SUM(COALESCE(i.uom_value, 0)) - SUM(COALESCE(i.locked_uom_value, 0)) - MAX(COALESCE(oi.release_uom_value, 0)), ' ', i.uom) AS "remainUomValueWithUom"