Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented: Show quantity on hand inventory during receiving(#416) #417

Merged
merged 6 commits into from
Nov 12, 2024
Merged
1 change: 1 addition & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
30 changes: 28 additions & 2 deletions src/services/ProductService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { api } from '@/adapter';
import { api, hasError } from '@/adapter';
import store from '@/store';

const fetchProducts = async (query: any): Promise <any> => {
return api({
Expand All @@ -9,6 +10,31 @@ const fetchProducts = async (query: any): Promise <any> => {
})
}

const getInventoryAvailableByFacility = async (productId: any): Promise<any> => {
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
}
45 changes: 38 additions & 7 deletions src/views/ReturnDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
</div>

<ion-card v-for="item in current.items" :key="item.id" :class="item.sku === lastScannedId ? 'scanned-item' : ''" :id="item.sku">
<div class="product">
<div class="product" :data-product-id="item.productId">
<div class="product-info">
<ion-item lines="none">
<ion-thumbnail slot="start" @click="openImage(getProduct(item.productId).mainImageUrl, getProduct(item.productId).productName)">
Expand All @@ -48,9 +48,12 @@
</div>

<div class="location">
<ion-chip outline :disabled="true">
<ion-icon :icon="locationOutline" />
<ion-label>{{ current.locationSeqId }}</ion-label>
<ion-button v-if="!(productQoh[item.productId] >= 0)" fill="clear" @click.stop="fetchQuantityOnHand(item.productId)">
<ion-icon color="medium" slot="icon-only" :icon="cubeOutline" />
</ion-button>
<ion-chip v-else outline>
{{ translate("on hand", { qoh: productQoh[item.productId] }) }}
<ion-icon color="medium" :icon="cubeOutline"/>
</ion-chip>
</div>

Expand Down Expand Up @@ -107,7 +110,7 @@
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';
Expand All @@ -117,6 +120,7 @@
import { hasError } from '@/utils';
import { showToast } from '@/utils'
import { Actions, hasPermission } from '@/authorization'
import { ProductService } from '@/services/ProductService';

export default defineComponent({
name: "ReturnDetails",
Expand Down Expand Up @@ -152,11 +156,13 @@
'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 })

Check warning on line 164 in src/views/ReturnDetails.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

'current' is assigned a value but never used

Check warning on line 164 in src/views/ReturnDetails.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

'current' is assigned a value but never used
this.observeProductVisibility();
},
computed: {
...mapGetters({
Expand Down Expand Up @@ -201,7 +207,31 @@
}
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"),
Expand Down Expand Up @@ -305,6 +335,7 @@
Actions,
barcodeOutline,
checkmarkDone,
cubeOutline,
hasPermission,
locationOutline,
store,
Expand Down
53 changes: 41 additions & 12 deletions src/views/ShipmentDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
</div>

<ion-card v-for="item in current.items" :key="item.id" :class="item.sku === lastScannedId ? 'scanned-item' : ''" :id="item.sku">
<div class="product">
<div class="product" :data-product-id="item.productId">
<div class="product-info">
<ion-item lines="none">
<ion-thumbnail slot="start" @click="openImage(getProduct(item.productId).mainImageUrl, getProduct(item.productId).productName)">
Expand All @@ -48,10 +48,12 @@
</div>

<div class="location">
<LocationPopover v-if="!isShipmentReceived() && item.quantityReceived === 0" :item="item" type="shipment" :facilityId="currentFacility.facilityId" />
<ion-chip :disabled="true" outline v-else>
<ion-icon :icon="locationOutline"/>
<ion-label>{{ item.locationSeqId }}</ion-label>
<ion-button v-if="!(productQoh[item.productId] >= 0)" fill="clear" @click.stop="fetchQuantityOnHand(item.productId)">
<ion-icon color="medium" slot="icon-only" :icon="cubeOutline" />
</ion-button>
<ion-chip v-else outline>
{{ translate("on hand", { qoh: productQoh[item.productId] }) }}
<ion-icon color="medium" :icon="cubeOutline"/>
</ion-chip>
</div>

Expand Down Expand Up @@ -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",
Expand All @@ -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({
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -334,6 +362,7 @@ export default defineComponent({
cameraOutline,
checkmarkDone,
checkmarkDoneCircleOutline,
cubeOutline,
hasPermission,
locationOutline,
store,
Expand Down
Loading