diff --git a/src/locales/en.json b/src/locales/en.json index 77595be1..de953bc0 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -63,6 +63,7 @@ "No shipments have been received against this purchase order yet": "No shipments have been received against {lineBreak} this purchase order yet", "OMS": "OMS", "OMS instance": "OMS instance", + "on hand": "{ qoh } on hand", "Only allow received quantity to be incremented by scanning the barcode of products. If the identifier is not found, the scan will default to using the internal name.": "Only allow received quantity to be incremented by scanning the barcode of products. {space} If the identifier is not found, the scan will default to using the internal name.", "Open": "Open", "ordered": "ordered", diff --git a/src/services/ProductService.ts b/src/services/ProductService.ts index 0e7ba0c3..160f6616 100644 --- a/src/services/ProductService.ts +++ b/src/services/ProductService.ts @@ -1,4 +1,5 @@ -import { api } from '@/adapter'; +import { api, hasError } from '@/adapter'; +import store from '@/store'; const fetchProducts = async (query: any): Promise => { return api({ @@ -9,6 +10,31 @@ const fetchProducts = async (query: any): Promise => { }) } +const getInventoryAvailableByFacility = async (productId: any): Promise => { + let productQoh = '' + const payload = { + productId: productId, + facilityId: store.getters['user/getCurrentFacility']?.facilityId + } + + try { + const resp: any = await api({ + url: "service/getInventoryAvailableByFacility", + method: "post", + data: payload + }) + if (!hasError(resp)) { + productQoh = resp?.data.quantityOnHandTotal; + } else { + throw resp.data; + } + } catch (err) { + console.error(err) + } + return productQoh; +} + export const ProductService = { - fetchProducts + fetchProducts, + getInventoryAvailableByFacility } \ No newline at end of file diff --git a/src/views/ReturnDetails.vue b/src/views/ReturnDetails.vue index 24b3daa9..7ffcfd14 100644 --- a/src/views/ReturnDetails.vue +++ b/src/views/ReturnDetails.vue @@ -34,7 +34,7 @@ -
+
@@ -48,9 +48,12 @@
- - - {{ current.locationSeqId }} + + + + + {{ translate("on hand", { qoh: productQoh[item.productId] }) }} +
@@ -107,7 +110,7 @@ import { alertController, } from '@ionic/vue'; import { defineComponent, computed } from 'vue'; -import { checkmarkDone, barcodeOutline, locationOutline } from 'ionicons/icons'; +import { checkmarkDone, cubeOutline, barcodeOutline, locationOutline } from 'ionicons/icons'; import { mapGetters, useStore } from "vuex"; import AddProductModal from '@/views/AddProductModal.vue' import { DxpShopifyImg, translate, getProductIdentificationValue, useProductIdentificationStore } from '@hotwax/dxp-components'; @@ -117,6 +120,7 @@ import ImageModal from '@/components/ImageModal.vue'; import { hasError } from '@/utils'; import { showToast } from '@/utils' import { Actions, hasPermission } from '@/authorization' +import { ProductService } from '@/services/ProductService'; export default defineComponent({ name: "ReturnDetails", @@ -152,11 +156,13 @@ export default defineComponent({ 'Shipped': 'medium', 'Created': 'medium' } as any, - lastScannedId: '' + lastScannedId: '', + productQoh: {} as any } }, async ionViewWillEnter() { const current = await this.store.dispatch('return/setCurrent', { shipmentId: this.$route.params.id }) + this.observeProductVisibility(); }, computed: { ...mapGetters({ @@ -201,7 +207,31 @@ export default defineComponent({ } await this.store.dispatch("product/fetchProducts", payload); }, - + observeProductVisibility() { + const observer = new IntersectionObserver((entries: any) => { + entries.forEach((entry: any) => { + if (entry.isIntersecting) { + const productId = entry.target.getAttribute('data-product-id'); + if (productId && !(this.productQoh[productId] >= 0)) { + this.fetchQuantityOnHand(productId); + } + } + }); + }, { + root: null, + threshold: 0.4 + }); + + const products = document.querySelectorAll('.product'); + if (products) { + products.forEach((product: any) => { + observer.observe(product); + }); + } + }, + async fetchQuantityOnHand(productId: any) { + this.productQoh[productId] = await ProductService.getInventoryAvailableByFacility(productId); + }, async completeShipment() { const alert = await alertController.create({ header: translate("Receive Shipment"), @@ -305,6 +335,7 @@ export default defineComponent({ Actions, barcodeOutline, checkmarkDone, + cubeOutline, hasPermission, locationOutline, store, diff --git a/src/views/ShipmentDetails.vue b/src/views/ShipmentDetails.vue index ef39cecb..fab9dba6 100644 --- a/src/views/ShipmentDetails.vue +++ b/src/views/ShipmentDetails.vue @@ -34,7 +34,7 @@
-
+
@@ -48,10 +48,12 @@
- - - - {{ item.locationSeqId }} + + + + + {{ translate("on hand", { qoh: productQoh[item.productId] }) }} +
@@ -115,16 +117,16 @@ import { alertController, } from '@ionic/vue'; import { defineComponent, computed } from 'vue'; -import { add, checkmarkDone, checkmarkDoneCircleOutline, cameraOutline, locationOutline, warningOutline } from 'ionicons/icons'; +import { add, checkmarkDone, checkmarkDoneCircleOutline, cameraOutline, cubeOutline, locationOutline, warningOutline } from 'ionicons/icons'; import { mapGetters, useStore } from "vuex"; import AddProductModal from '@/views/AddProductModal.vue' import { DxpShopifyImg, translate, getProductIdentificationValue, useProductIdentificationStore } from '@hotwax/dxp-components'; import { useRouter } from 'vue-router'; import Scanner from "@/components/Scanner.vue"; -import LocationPopover from '@/components/LocationPopover.vue' import ImageModal from '@/components/ImageModal.vue'; -import { hasError, showToast } from '@/utils' +import { showToast } from '@/utils' import { Actions, hasPermission } from '@/authorization' +import { ProductService } from '@/services/ProductService'; export default defineComponent({ name: "ShipmentDetails", @@ -149,17 +151,18 @@ export default defineComponent({ IonToolbar, DxpShopifyImg, IonChip, - LocationPopover }, props: ["shipment"], data() { return { queryString: '', - lastScannedId: '' + lastScannedId: '', + productQoh: {} as any } }, - mounted() { - this.store.dispatch('shipment/setCurrent', { shipmentId: this.$route.params.id }) + async mounted() { + await this.store.dispatch('shipment/setCurrent', { shipmentId: this.$route.params.id }) + this.observeProductVisibility(); }, computed: { ...mapGetters({ @@ -196,6 +199,31 @@ export default defineComponent({ }) return modal.present(); }, + observeProductVisibility() { + const observer = new IntersectionObserver((entries: any) => { + entries.forEach((entry: any) => { + if (entry.isIntersecting) { + const productId = entry.target.getAttribute('data-product-id'); + if (productId && !(this.productQoh[productId] >= 0)) { + this.fetchQuantityOnHand(productId); + } + } + }); + }, { + root: null, + threshold: 0.4 + }); + + const products = document.querySelectorAll('.product'); + if (products) { + products.forEach((product: any) => { + observer.observe(product); + }); + } + }, + async fetchQuantityOnHand(productId: any) { + this.productQoh[productId] = await ProductService.getInventoryAvailableByFacility(productId); + }, async fetchProducts(vSize: any, vIndex: any) { const viewSize = vSize ? vSize : process.env.VUE_APP_VIEW_SIZE; const viewIndex = vIndex ? vIndex : 0; @@ -334,6 +362,7 @@ export default defineComponent({ cameraOutline, checkmarkDone, checkmarkDoneCircleOutline, + cubeOutline, hasPermission, locationOutline, store,