@things-factory/product-ui 4.3.159 → 4.3.163

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.
@@ -341,6 +341,13 @@ export class ProductDetailsPopup extends localize(i18next)(LitElement) {
341
341
  header: i18next.t('field.volume'),
342
342
  width: 70
343
343
  },
344
+ {
345
+ type: 'float',
346
+ name: 'costPrice',
347
+ record: { editable: true, options: { min: 0 } },
348
+ header: i18next.t('field.unit_cost'),
349
+ width: 70
350
+ },
344
351
  {
345
352
  type: 'string',
346
353
  name: 'auxUnit1',
@@ -533,6 +540,13 @@ export class ProductDetailsPopup extends localize(i18next)(LitElement) {
533
540
 
534
541
  let data = this._updateRowOption(response.data.productDetails.items)
535
542
 
543
+ data.map(item => {
544
+ item.costPrice === null ? (item.costPrice = 0) : item.costPrice
545
+ if (item.costPrice == 0 || item.costPrice) {
546
+ item.costPrice = item.costPrice.toFixed(2)
547
+ }
548
+ })
549
+
536
550
  if (!response.errors) {
537
551
  this._data = {
538
552
  total: response.data.productDetails.total || 0,
@@ -597,7 +611,7 @@ export class ProductDetailsPopup extends localize(i18next)(LitElement) {
597
611
  auxValue5: itm.auxValue5,
598
612
  isTrackedAsInventory: itm.isTrackedAsInventory,
599
613
  discountId: itm.discountId,
600
- costPrice: itm.costPrice,
614
+ costPrice: parseFloat(itm.costPrice),
601
615
  mrpPrice: itm.mrpPrice,
602
616
  sellPrice: itm.sellPrice,
603
617
  afterTaxCostPrice: itm.afterTaxCostPrice,
@@ -646,7 +660,9 @@ export class ProductDetailsPopup extends localize(i18next)(LitElement) {
646
660
 
647
661
  _validate() {
648
662
  let errors = []
649
-
663
+ if (this.dataGrist.dirtyRecords.length < 1) {
664
+ throw new Error(i18next.t('text.nothing_changed'))
665
+ }
650
666
  if (!this.dataGrist._data.records.find(x => x.isDefault)) {
651
667
  errors.push({ type: 'isDefault', value: 'Must have 1 default' })
652
668
  }
@@ -693,6 +709,9 @@ export class ProductDetailsPopup extends localize(i18next)(LitElement) {
693
709
  if (!errors.find(err => err.type == 'uomValue'))
694
710
  errors.push({ type: 'uomValue', value: 'UOM Value is required' })
695
711
  }
712
+ if (itm.costPrice < 0) {
713
+ throw new Error(i18next.t('text.unit_cost_cannot_be_negative_value'))
714
+ }
696
715
  return itm
697
716
  })
698
717
 
@@ -707,6 +726,7 @@ export class ProductDetailsPopup extends localize(i18next)(LitElement) {
707
726
  }
708
727
 
709
728
  _fieldChange(e) {
729
+ let unitCostError = ''
710
730
  var { after, before, column, record, row } = e.detail
711
731
  let updatedRecords = {
712
732
  ...this.dataGrist._data,
@@ -736,6 +756,17 @@ export class ProductDetailsPopup extends localize(i18next)(LitElement) {
736
756
  updatedRecords.records[row].uomValue = 1
737
757
  }
738
758
  break
759
+
760
+ case 'costPrice':
761
+ if (isNaN(after) === true) {
762
+ unitCostError = 'not a number'
763
+ updatedRecords.records[row].costPrice = updatedRecords.records[row].__dirtyfields__.costPrice.before
764
+ this._showToast({ type: 'error', message: `Invalid value in Unit Cost (${unitCostError})` })
765
+ }
766
+ if (after < 0) {
767
+ unitCostError = 'negative value'
768
+ }
769
+ break
739
770
  default:
740
771
  break
741
772
  }
@@ -746,7 +777,11 @@ export class ProductDetailsPopup extends localize(i18next)(LitElement) {
746
777
  ...this.dataGrist._data
747
778
  }
748
779
 
749
- this._showToast({ type: 'error', message: `Minimum value of ${column.record.options.min} is required.` })
780
+ if (column.name == 'costPrice') {
781
+ this._showToast({ type: 'error', message: `Invalid value in Unit Cost (${unitCostError})` })
782
+ } else {
783
+ this._showToast({ type: 'error', message: `Minimum value of ${column.record.options.min} is required.` })
784
+ }
750
785
  }
751
786
 
752
787
  this._data = { ...updatedRecords }
@@ -86,6 +86,9 @@ class ProductList extends localize(i18next)(PageView) {
86
86
  },
87
87
  importable: {
88
88
  handler: records => {
89
+ records.map(record => {
90
+ record.costPrice = record.costPrice == null ? '0.00' : parseFloat(record.costPrice).toFixed(2)
91
+ })
89
92
  const config = {
90
93
  rows: this.productGristConfig.rows,
91
94
  columns: [
@@ -359,6 +362,15 @@ class ProductList extends localize(i18next)(PageView) {
359
362
  sortable: true,
360
363
  width: 140
361
364
  },
365
+ {
366
+ type: 'integer',
367
+ name: 'shelfLife',
368
+ record: { editable: true, options: { min: 0 } },
369
+ imex: { header: i18next.t('field.shelf_life'), key: 'shelfLife', width: 30, type: 'integer' },
370
+ header: i18next.t('field.shelf_life'),
371
+ sortable: true,
372
+ width: 140
373
+ },
362
374
  {
363
375
  type: 'boolean',
364
376
  name: 'isRequiredCheckExpiry',
@@ -571,6 +583,14 @@ class ProductList extends localize(i18next)(PageView) {
571
583
  header: i18next.t('field.volume_size'),
572
584
  width: 100
573
585
  },
586
+ {
587
+ type: 'float',
588
+ name: 'costPrice',
589
+ record: { editable: true },
590
+ imex: { header: `${i18next.t('field.unit_cost')}`, key: 'costPrice', width: 20, type: 'number' },
591
+ header: `${i18next.t('field.unit_cost')}`,
592
+ width: 100
593
+ },
574
594
  {
575
595
  type: 'string',
576
596
  name: 'auxUnit1',
@@ -722,6 +742,7 @@ class ProductList extends localize(i18next)(PageView) {
722
742
  inventoryAccountCode
723
743
  cogsAccountCode
724
744
  expirationPeriod
745
+ shelfLife
725
746
  isRequiredCheckExpiry
726
747
  isRequireSerialNumberScanning
727
748
  isRequireSerialNumberScanningInbound
@@ -780,9 +801,13 @@ class ProductList extends localize(i18next)(PageView) {
780
801
  total: response.data.myBizplaceProducts.total || 0,
781
802
  records:
782
803
  response.data.myBizplaceProducts.items.map(itm => {
804
+ if (itm.costPrice == NaN || itm.costPrice == null) {
805
+ itm.costPrice = 0
806
+ }
783
807
  return {
784
808
  ...itm,
785
- productRef: { name: itm?.productRef ? '(' + itm.productRef.sku + ') ' + itm.productRef.name : '' }
809
+ productRef: { name: itm?.productRef ? '(' + itm.productRef.sku + ') ' + itm.productRef.name : '' },
810
+ costPrice: parseFloat(itm.costPrice).toFixed(2)
786
811
  }
787
812
  }) || []
788
813
  }
@@ -856,17 +881,20 @@ class ProductList extends localize(i18next)(PageView) {
856
881
  return this.showToast(i18next.t('text.nothing_changed'))
857
882
  }
858
883
 
884
+ this._validate(this.dataGrist.dirtyRecords)
885
+
859
886
  patches = patches.map(patch => {
860
887
  return {
861
888
  ...patch,
862
- expirationPeriod: patch?.expirationPeriod ? parseInt(patch.expirationPeriod) : undefined,
889
+ costPrice: patch?.costPrice || patch.costPrice == 0 ? parseFloat(patch.costPrice) : undefined,
890
+ expirationPeriod:
891
+ patch?.expirationPeriod || patch?.expirationPeriod == 0 ? parseInt(patch.expirationPeriod) : undefined,
892
+ shelfLife: patch?.shelfLife || patch?.shelfLife == 0 ? parseInt(patch.shelfLife) : undefined,
863
893
  productRef: patch.productRef?.id ? { id: patch.productRef?.id } : undefined,
864
894
  parentProductRef: patch.parentProductRef?.id ? { id: patch.parentProductRef?.id } : undefined
865
895
  }
866
896
  })
867
897
 
868
- this._validate(this.dataGrist.dirtyRecords)
869
-
870
898
  const response = await client.mutate({
871
899
  mutation: gql`
872
900
  mutation updateMultipleProduct($patches: [ProductPatch!]!) {
@@ -893,16 +921,19 @@ class ProductList extends localize(i18next)(PageView) {
893
921
  if (!patches?.length) {
894
922
  return this.showToast(i18next.t('text.nothing_changed'))
895
923
  }
896
-
897
924
  patches = patches.map(patch => {
925
+ patch.costPrice = patch.costPrice == null ? 0 : patch.costPrice
926
+
898
927
  return {
899
928
  ...patch,
929
+ costPrice: patch?.costPrice ? parseFloat(patch.costPrice) : undefined,
900
930
  uomValue: patch?.uomValue ? parseFloat(patch.uomValue) : undefined,
901
931
  bufferQty: patch?.bufferQty ? parseInt(patch.bufferQty) : undefined,
902
932
  minQty: patch?.minQty ? parseInt(patch.minQty) : undefined,
903
933
  maxQty: patch?.maxQty ? parseInt(patch.maxQty) : undefined,
904
934
  packingSize: patch?.packingSize ? parseInt(patch.packingSize) : undefined,
905
935
  expirationPeriod: patch?.expirationPeriod ? parseInt(patch.expirationPeriod) : undefined,
936
+ shelfLife: patch?.shelfLife ? parseInt(patch.shelfLife) : undefined,
906
937
  productRef: patch.productRef?.id ? { id: patch.productRef?.id } : undefined,
907
938
  pickingStrategy: patch?.pickingStrategy ? patch.pickingStrategy.toUpperCase() : undefined
908
939
  }
@@ -954,6 +985,23 @@ class ProductList extends localize(i18next)(PageView) {
954
985
  if (!errors.find(err => err.type == 'uomValue'))
955
986
  errors.push({ type: 'uomValue', value: 'UOM Value is required' })
956
987
  }
988
+ if (itm?.shelfLife < 0) {
989
+ if (!errors.find(err => err.type == 'shelfLife'))
990
+ errors.push({ type: 'shelfLife', value: 'Shelf Life cannot be negative' })
991
+ }
992
+ if (itm?.expirationPeriod < 0) {
993
+ if (!errors.find(err => err.type == 'expirationPeriod'))
994
+ errors.push({ type: 'expirationPeriod', value: 'Expiration period cannot be negative' })
995
+ }
996
+
997
+ if (isNaN(itm.costPrice) && itm.costPrice !== undefined) {
998
+ errors.push({ type: 'costPrice', value: 'invalid unit cost (not a number)' })
999
+ }
1000
+
1001
+ if (itm?.costPrice && itm?.costPrice < 0) {
1002
+ errors.push({ type: 'costPrice', value: 'invalid unit cost (negative value)' })
1003
+ }
1004
+
957
1005
  return itm
958
1006
  })
959
1007
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/product-ui",
3
- "version": "4.3.159",
3
+ "version": "4.3.163",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "client/index.js",
6
6
  "things-factory": true,
@@ -28,8 +28,8 @@
28
28
  "@things-factory/i18n-base": "^4.3.159",
29
29
  "@things-factory/import-ui": "^4.3.159",
30
30
  "@things-factory/layout-base": "^4.3.159",
31
- "@things-factory/product-base": "^4.3.159",
31
+ "@things-factory/product-base": "^4.3.163",
32
32
  "@things-factory/shell": "^4.3.159"
33
33
  },
34
- "gitHead": "4ef9913b22e5b7baee27d9057fb04c707f7f49ec"
34
+ "gitHead": "082339ccf43992dc550c7078c605cc2794758c7f"
35
35
  }
@@ -51,6 +51,7 @@
51
51
  "field.require_serial_number_scanning_outbound": "require serial number scanning outbound",
52
52
  "field.require_serial_number_scanning": "require serial number scanning",
53
53
  "field.required_checking_expiry": "required checking expiry",
54
+ "field.shelf_life": "shelf life",
54
55
  "field.sku": "SKU",
55
56
  "field.sub_brand": "sub brand",
56
57
  "field.threshold_qty": "threshold qty",
@@ -63,6 +64,7 @@
63
64
  "field.weight_unit": "weight unit",
64
65
  "field.weight": "weight",
65
66
  "field.width": "width",
67
+ "field.unit_cost": "unit cost",
66
68
  "label.fefo": "FEFO",
67
69
  "label.fmfo": "FMFO",
68
70
  "label.fifo": "FIFO",
@@ -77,5 +77,7 @@
77
77
  "title.product_bundle": "[ko]product bundle",
78
78
  "title.product_set": "[ko]product set",
79
79
  "title.product": "[ko]product",
80
- "field.child_product_detail": "[ko] child product detail"
80
+ "field.child_product_detail": "[ko] child product detail",
81
+ "field.unit_cost": "[ko] unit cost",
82
+ "field.shelf_life": "[ko] shelf life"
81
83
  }
@@ -77,5 +77,7 @@
77
77
  "title.product_bundle": "[ms]product bundle",
78
78
  "title.product_set": "[ms]product set",
79
79
  "title.product": "[ms]product",
80
- "field.child_product_detail": "[ms] child product detail"
80
+ "field.child_product_detail": "[ms] child product detail",
81
+ "field.unit_cost": "[ms] unit cost",
82
+ "field.shelf_life": "[ms] shelf life"
81
83
  }
@@ -77,5 +77,7 @@
77
77
  "title.product_bundle": "[zh]product bundle",
78
78
  "title.product_set": "[zh]product set",
79
79
  "title.product": "[zh]product",
80
- "field.child_product_detail": "[zh] child product detail"
80
+ "field.child_product_detail": "[zh] child product detail",
81
+ "field.unit_cost": "[zh] unit cost",
82
+ "field.shelf_life": "[zh] shelf life"
81
83
  }