diff --git a/package-lock.json b/package-lock.json index fe760406..d3e5c437 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "receiving", - "version": "2.22.0", + "version": "2.24.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "receiving", - "version": "2.22.0", + "version": "2.24.0", "dependencies": { "@capacitor/android": "^2.4.7", "@capacitor/core": "^2.4.7", "@casl/ability": "^6.0.0", "@hotwax/app-version-info": "^1.0.0", "@hotwax/apps-theme": "^1.2.6", - "@hotwax/dxp-components": "^1.11.0", + "@hotwax/dxp-components": "^1.12.1", "@hotwax/oms-api": "^1.10.0", "@ionic/core": "^7.6.0", "@ionic/vue": "^7.6.0", @@ -2797,63 +2797,32 @@ "integrity": "sha512-zpUjGoY7LBlKeiP0V7tonrmoey8HQ5THQmyixQ+IDtrjmEJNBjynW/Ef3gC0FUNNPuVqxWPZdT5CVgaETLGTwg==" }, "node_modules/@hotwax/dxp-components": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@hotwax/dxp-components/-/dxp-components-1.11.0.tgz", - "integrity": "sha512-z9UNzi1veT8Aj8Y1WWAGBGOR+I0s6A58qrsFj+L3LkpxTkq6zGN/JS80tTv29obEeeOfONm6XyLHvNOM6TFKyA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@hotwax/dxp-components/-/dxp-components-1.12.1.tgz", + "integrity": "sha512-5soKaVBFd7klZnHBCi68j4CZwTlrBCzvPsyd+wHMbenezU+lOwMK0ftdWXrQcQPedeGdVtQXvvgSPWnLL310bg==", "dependencies": { "@hotwax/oms-api": "^1.8.1", - "@ionic/core": "^6.7.5", - "@ionic/vue": "^6.7.5", - "@types/vue-barcode-reader": "^0.0.0", + "@ionic/core": "^7.6.0", + "@ionic/vue": "^7.6.0", "firebase": "^10.3.1", "luxon": "^3.3.0", "pinia": "2.0.36", "pinia-plugin-persistedstate": "^3.1.0", "register-service-worker": "^1.7.2", "vue": "^3.3.4", - "vue-barcode-reader": "^1.0.3", "vue-i18n": "^9.2.2" } }, "node_modules/@hotwax/dxp-components/node_modules/@ionic/core": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-6.7.5.tgz", - "integrity": "sha512-zRkRn+h/Vs3xt/EVgBdShMKDyeGOM4RU31NPF2icfu3CUTH+VrMV569MUnNjYvd1Lu2xK90pYy4TaicSWmC1Pw==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.7.4.tgz", + "integrity": "sha512-zThio3ZfbTu+3eM6QBdyeEk5OBc7M0ApFwSlP/G7rrFVcTPm12FNvG9VPD+aN5NwnYy0EsV3hlMkxbawoqjVLw==", "dependencies": { - "@stencil/core": "^2.18.0", - "ionicons": "^6.1.3", + "@stencil/core": "^4.12.2", + "ionicons": "^7.2.2", "tslib": "^2.1.0" } }, - "node_modules/@hotwax/dxp-components/node_modules/@ionic/vue": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-6.7.5.tgz", - "integrity": "sha512-6JBEaHCT2vVUzYqyfBiEUN8Wo7FezxY5Y3n+HGqI61J4qVay+8IxZRTYeX+O72QglbYOkzvfjE6SgS25oS+S9A==", - "dependencies": { - "@ionic/core": "6.7.5", - "ionicons": "^6.1.3" - } - }, - "node_modules/@hotwax/dxp-components/node_modules/@stencil/core": { - "version": "2.22.3", - "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.22.3.tgz", - "integrity": "sha512-kmVA0M/HojwsfkeHsifvHVIYe4l5tin7J5+DLgtl8h6WWfiMClND5K3ifCXXI2ETDNKiEk21p6jql3Fx9o2rng==", - "bin": { - "stencil": "bin/stencil" - }, - "engines": { - "node": ">=12.10.0", - "npm": ">=6.0.0" - } - }, - "node_modules/@hotwax/dxp-components/node_modules/ionicons": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-6.1.3.tgz", - "integrity": "sha512-ptzz38dd/Yq+PgjhXegh7yhb/SLIk1bvL9vQDtLv1aoSc7alO6mX2DIMgcKYzt9vrNWkRu1f9Jr78zIFFyOXqw==", - "dependencies": { - "@stencil/core": "^2.18.0" - } - }, "node_modules/@hotwax/dxp-components/node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -2954,12 +2923,12 @@ } }, "node_modules/@ionic/core": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.6.0.tgz", - "integrity": "sha512-pDX8G915puz8OcLhxfb9MwuvpYZsUOCngJdd+61ibJ6UF+NA2mGatsMqHKzcgelTXtwcHDpi9ZLUD/HNmupqaQ==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.8.0.tgz", + "integrity": "sha512-rogQw6lWH367E5XQnovbAIB4pT1YmuTz7OvyQm0cp4pO2/64faKyTGteSxc99stG01CoARW+pjJN1K09hfKFPw==", "dependencies": { - "@stencil/core": "^4.8.1", - "ionicons": "^7.2.1", + "@stencil/core": "^4.12.2", + "ionicons": "^7.2.2", "tslib": "^2.1.0" } }, @@ -2969,20 +2938,20 @@ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/@ionic/vue": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-7.6.0.tgz", - "integrity": "sha512-2CWLcVNS8kLQ6BK4UmRdc7a0HSsS6MqyTQh7+0qT88z+Ih05dCcZ3CiJ27F3F2a7jsOi48ggXt97zOpBbZENlg==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-7.8.0.tgz", + "integrity": "sha512-IXOUO9SQHXU3Ec/9u6u2JPNcu9VL8jamvM+elzBam7e0GDSQ56cyYDRnptROBdfBYop2EGiNJvzjWxAuZnM6kw==", "dependencies": { - "@ionic/core": "7.6.0", + "@ionic/core": "7.8.0", "ionicons": "^7.0.0" } }, "node_modules/@ionic/vue-router": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@ionic/vue-router/-/vue-router-7.6.0.tgz", - "integrity": "sha512-grzMyURlZX3EqkQFBXeKuhxN2psbNKAI8CVwPi56xRPwCvSp32KFYtGxj20k1QBl+Kzg7/RbxTERArxZRtPWJw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@ionic/vue-router/-/vue-router-7.8.0.tgz", + "integrity": "sha512-eoBznpasYngVCdeU1PiYdzbUGPXP85IZlduJrSa/B+UkZVTx33WTjTNP/GYC2NhMYVrei8eS/fmg7pafIWZHPQ==", "dependencies": { - "@ionic/vue": "7.6.0" + "@ionic/vue": "7.8.0" } }, "node_modules/@isaacs/cliui": { @@ -3492,9 +3461,9 @@ "dev": true }, "node_modules/@stencil/core": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.9.0.tgz", - "integrity": "sha512-aWSkhBmk3yPwRAkUwBbzRwmdhb8hKiQ/JMr9m5jthpBZLjtppYbzz6PN2MhSMDfRp6K93eQw5WogSEH4HHuB6w==", + "version": "4.12.6", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.12.6.tgz", + "integrity": "sha512-15JO2TdaxGVKNdLZb/2TtDa+juj3XGD/V0y/disgdzYYSnajgSh06nwODfdHz9eTUh1Hisz+KIo857I1rCZrfg==", "bin": { "stencil": "bin/stencil" }, @@ -3781,33 +3750,6 @@ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "dev": true }, - "node_modules/@types/vue-barcode-reader": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@types/vue-barcode-reader/-/vue-barcode-reader-0.0.0.tgz", - "integrity": "sha512-yngQhd35qGjCxMXWIqsAtF7qmxe0qUYRVd9qW5I/CcRPWDdBpqVkHnQSh6ro5BIBl3NQ3ppky7kMKS4pr+XwCQ==", - "dependencies": { - "vue": "^2.0.0" - } - }, - "node_modules/@types/vue-barcode-reader/node_modules/@vue/compiler-sfc": { - "version": "2.7.15", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.15.tgz", - "integrity": "sha512-FCvIEevPmgCgqFBH7wD+3B97y7u7oj/Wr69zADBf403Tui377bThTjBvekaZvlRr4IwUAu3M6hYZeULZFJbdYg==", - "dependencies": { - "@babel/parser": "^7.18.4", - "postcss": "^8.4.14", - "source-map": "^0.6.1" - } - }, - "node_modules/@types/vue-barcode-reader/node_modules/vue": { - "version": "2.7.15", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.15.tgz", - "integrity": "sha512-a29fsXd2G0KMRqIFTpRgpSbWaNBK3lpCTOLuGLEDnlHWdjB8fwl6zyYZ8xCrqkJdatwZb4mGHiEfJjnw0Q6AwQ==", - "dependencies": { - "@vue/compiler-sfc": "2.7.15", - "csstype": "^3.1.0" - } - }, "node_modules/@types/webpack-env": { "version": "1.18.4", "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.4.tgz", @@ -14821,6 +14763,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, "engines": { "node": ">=0.10.0" } diff --git a/package.json b/package.json index 38d6e6d3..00aa904b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "receiving", - "version": "2.22.0", + "version": "2.24.0", "private": true, "description": "HotWax Commerce Receiving App", "scripts": { @@ -16,7 +16,7 @@ "@casl/ability": "^6.0.0", "@hotwax/app-version-info": "^1.0.0", "@hotwax/apps-theme": "^1.2.6", - "@hotwax/dxp-components": "^1.11.0", + "@hotwax/dxp-components": "^1.12.1", "@hotwax/oms-api": "^1.10.0", "@ionic/core": "^7.6.0", "@ionic/vue": "^7.6.0", diff --git a/src/App.vue b/src/App.vue index 17fefaeb..c69c1636 100644 --- a/src/App.vue +++ b/src/App.vue @@ -61,6 +61,16 @@ export default defineComponent({ if (this.loader) { this.loader.dismiss(); this.loader = null as any; + } else { + // Added this else case as there are some scenarios in which the loader is not created and before that the dismissLoader gets called, resulting in the loader not getting dismissed + // So checking that when the loader is not found then try dismissing the loader again after 3 secs. + // The above case appears when directly hitting the shipment detail page and then the receive shipment api throws error + // TODO: need to find a more better approach to dismiss the loader in such case + setTimeout(() => { + if (this.loader) { + this.dismissLoader(); + } + }, 3000) } }, async unauthorized() { diff --git a/src/adapter/index.ts b/src/adapter/index.ts index 43354254..85e559f7 100644 --- a/src/adapter/index.ts +++ b/src/adapter/index.ts @@ -1,10 +1,11 @@ -import { api, client, getConfig, getUserFacilities, initialise, logout, resetConfig, updateInstanceUrl, updateToken } from '@hotwax/oms-api' +import { api, client, getConfig, getUserFacilities, hasError, initialise, logout, resetConfig, updateInstanceUrl, updateToken } from '@hotwax/oms-api' export { api, client, getConfig, getUserFacilities, + hasError, initialise, logout, resetConfig, diff --git a/src/assets/images/empty-state-add-product-modal.png b/src/assets/images/empty-state-add-product-modal.png new file mode 100644 index 00000000..148618b6 Binary files /dev/null and b/src/assets/images/empty-state-add-product-modal.png differ diff --git a/src/components/ClosePurchaseOrderModal.vue b/src/components/ClosePurchaseOrderModal.vue index e259f95e..aa84d48f 100644 --- a/src/components/ClosePurchaseOrderModal.vue +++ b/src/components/ClosePurchaseOrderModal.vue @@ -20,7 +20,7 @@ - +

{{ productHelpers.getProductIdentificationValue(productIdentificationPref.primaryId, getProduct(item.productId)) }}

@@ -66,7 +66,7 @@ import { defineComponent } from 'vue'; import { mapGetters, useStore } from 'vuex' import { OrderService } from "@/services/OrderService"; import { productHelpers } from '@/utils'; -import { ShopifyImg, translate } from '@hotwax/dxp-components'; +import { DxpShopifyImg, translate } from '@hotwax/dxp-components'; import { useRouter } from 'vue-router'; export default defineComponent({ @@ -87,7 +87,7 @@ export default defineComponent({ IonTitle, IonThumbnail, IonToolbar, - ShopifyImg + DxpShopifyImg }, computed: { ...mapGetters({ diff --git a/src/components/ImageModal.vue b/src/components/ImageModal.vue index 95c78d14..0f404de0 100644 --- a/src/components/ImageModal.vue +++ b/src/components/ImageModal.vue @@ -11,7 +11,7 @@ - + @@ -29,7 +29,7 @@ import { } from '@ionic/vue'; import { defineComponent } from 'vue'; import { closeOutline } from 'ionicons/icons'; -import { ShopifyImg } from '@hotwax/dxp-components'; +import { DxpShopifyImg } from '@hotwax/dxp-components'; export default defineComponent({ name: 'ImageModal', @@ -41,7 +41,7 @@ export default defineComponent({ IonIcon, IonTitle, IonToolbar, - ShopifyImg + DxpShopifyImg }, props: ["imageUrl", "productName"], methods: { diff --git a/src/components/ShipmentListItem.vue b/src/components/ShipmentListItem.vue index 2e0f1460..3f805b44 100644 --- a/src/components/ShipmentListItem.vue +++ b/src/components/ShipmentListItem.vue @@ -1,11 +1,14 @@ @@ -13,8 +16,7 @@ import { defineComponent } from 'vue' import { IonItem, - IonLabel, - IonNote + IonLabel } from '@ionic/vue' import { useRouter } from 'vue-router' import { useStore } from 'vuex'; @@ -24,7 +26,7 @@ export default defineComponent({ components: { IonItem, IonLabel, - IonNote, + }, props: ["shipment"], methods: { diff --git a/src/locales/en.json b/src/locales/en.json index 55d072a1..75e5fc16 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -5,28 +5,32 @@ "App": "App", "Authenticating": "Authenticating", "Are you sure you have received the purchase order for the selected items? Once closed, the shipments for the selected items wont be available for receiving later.": "Are you sure you have received the purchase order for the selected items? { space } Once closed, the shipments for the selected items won't be available for receiving later.", - "Are you sure you want to change the time zone to?": "Are you sure you want to change the time zone to {timeZoneId}?", "Arrival date": "Arrival date", + "Built: ": "Built: {builtDateTime}", "Cancel": "Cancel", "Change": "Change", "Choosing a product identifier allows you to view products with your preferred identifiers.": "Choosing a product identifier allows you to view products with your preferred identifiers.", "Click the backdrop to dismiss.": "Click the backdrop to dismiss.", "Complete": "Complete", "Completed": "Completed", - "COMPLETED: ITEM": "COMPLETED: {itemsCount} ITEM", - "COMPLETED: ITEMS": "COMPLETED: {itemsCount} ITEMS", + "Completed: item": "Completed: {itemsCount} item", + "Completed: items": "Completed: {itemsCount} items", "Confirm": "Confirm", "Copied": "Copied { value }", "Close purchase order items": "Close purchase order items", "eCom Store": "eCom Store", "Enter a custom date time format that you want to use when uploading documents to HotWax Commerce.": "Enter a custom date time format that you want to use when uploading documents to HotWax Commerce.", + "Enter a SKU, or product name to search a product": "Enter a SKU, or product name to search a product", "External ID": "External ID", "Facility": "Facility", "Location": "Location", + "Failed to receive shipment": "Failed to receive shipment", "Failed to receive some of the items": "Failed to receive some of the items", + "Failed to scan:": "Failed to scan: {itemName}", "Failed to update product identifier preference": "Failed to update product identifier preference", "facility location": "facility location", "Facility locations were not found corresponding to destination facility of return shipment. Please add facility locations to avoid receive return shipment failure.": "Facility locations were not found corresponding to destination facility of return shipment. Please add facility locations to avoid receive return shipment failure.", + "Fetching time zones": "Fetching time zones", "Go to Launchpad": "Go to Launchpad", "Go to OMS": "Go to OMS", "History": "History", @@ -54,12 +58,11 @@ "ordered": "ordered", "Orders not found": "Orders not found", "Password": "Password", - "PENDING: ITEM": "PENDING: {itemsCount} ITEM", - "PENDING: ITEMS": "PENDING: {itemsCount} ITEMS", + "Pending: item": "Pending: {itemsCount} item", + "Pending: items": "Pending: {itemsCount} items", "primary identifier": "primary identifier", "Primary Product Identifier": "Primary Product Identifier", "Proceed": "Proceed", - "Product not found": "Product not found", "Product Identifier": "Product Identifier", "Product identifier preference updated": "Product identifier preference updated", "Purchase Order": "Purchase Order", @@ -86,9 +89,11 @@ "Scan ASN to start receiving": "Scan ASN to start receiving", "Scan barcodes to receive them": "Scan barcodes to receive them", "Scan items": "Scan items", + "Scanned successfully.": "Scanned {itemName} successfully.", "secondary identifier": "secondary identifier", "Search": "Search", "Search purchase orders": "Search purchase orders", + "Search returns": "Search returns", "Search time zones": "Search time zones", "Search SKU or product name": "Search SKU or product name", "Secondary Product Identifier": "Secondary Product Identifier", @@ -102,6 +107,7 @@ "Shipments": "Shipments", "Shipments not found": "Shipments not found", "Shipped": "Shipped", + "shipped": "shipped", "Shop eCommerce": "Shop eCommerce", "Something went wrong": "Something went wrong", "Something went wrong while login. Please contact administrator": "Something went wrong while login. Please contact administrator.", @@ -117,8 +123,8 @@ "Time zone updated successfully": "Time zone updated successfully", "To close the purchase order, select all.": "To close the purchase order, select all.", "Unable to update product identifier preference": "Unable to update product identifier preference", - "Update time zone": "Update time zone", "Username": "Username", + "Version: ": "Version: {appVersion}", "You do not have permission to access this page": "You do not have permission to access this page", "ZeroQuantity": "ZeroQuantity" } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 1330d839..4a726fba 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,7 +2,6 @@ import { createApp } from 'vue' import App from './App.vue' import router from './router'; import { DateTime } from 'luxon'; -import './registerServiceWorker'; import { IonicVue } from '@ionic/vue'; diff --git a/src/registerServiceWorker.ts b/src/registerServiceWorker.ts deleted file mode 100644 index 69e95fe6..00000000 --- a/src/registerServiceWorker.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { register } from 'register-service-worker' - -if (process.env.NODE_ENV === 'production') { - register(`${process.env.BASE_URL}service-worker.js`, { - ready () { - console.log( - 'App is being served from cache by a service worker.\n' + - 'For more details, visit https://goo.gl/AFskqB' - ) - }, - registered () { - console.log('Service worker has been registered.') - }, - cached () { - console.log('Content has been cached for offline use.') - }, - updatefound () { - console.log('New content is downloading.') - }, - updated () { - console.log('New content is available; please refresh.') - }, - offline () { - console.log('No internet connection found. App is running in offline mode.') - }, - error (error) { - console.error('Error during service worker registration:', error) - } - }) -} \ No newline at end of file diff --git a/src/services/ShipmentService.ts b/src/services/ShipmentService.ts index 93ecfe0a..8a5753f8 100644 --- a/src/services/ShipmentService.ts +++ b/src/services/ShipmentService.ts @@ -1,4 +1,4 @@ -import { api } from '@/adapter'; +import { api, hasError } from '@/adapter'; const fetchShipments = async (query: any): Promise => { return api({ @@ -41,9 +41,83 @@ const addShipmentItem = async (query: any): Promise =>{ }) } +const fetchTrackingCodes = async (shipmentIds: Array): Promise => { + let shipmentTrackingCodes = {}; + const params = { + "entityName": "ShipmentRouteSegment", + "inputFields": { + "shipmentId": shipmentIds, + "shipmentId_op": "in", + }, + "fieldList": ["shipmentId", "trackingIdNumber"], + "viewSize": 250, // maximum records we could have + "distinct": "Y" + } + + try { + const resp = await api({ + url: "performFind", + method: "get", + params + }) + + if (!hasError(resp)) { + shipmentTrackingCodes = resp?.data.docs.reduce((codes:any, item:any) => (codes[item.shipmentId] = item.trackingIdNumber, codes), {}); + + } else if (!resp?.data.error || (resp.data.error && resp.data.error !== "No record found")) { + return Promise.reject(resp?.data.error); + } + } catch (err) { + console.error('Failed to fetch tracking codes for shipments', err) + } + + return shipmentTrackingCodes; +} + +const fetchShipmentAttributes = async (shipmentIds: Array): Promise => { + const shipmentAttributes = {} as any; + const params = { + "entityName": "ShipmentAttribute", + "inputFields": { + "shipmentId": shipmentIds, + "shipmentId_op": "in", + }, + "fieldList": ["shipmentId", "attrName", "attrValue"], + "viewSize": 250, // maximum records we could have + "distinct": "Y" + } + + try { + const resp = await api({ + url: "performFind", + method: "get", + params + }) + + if (!hasError(resp)) { + resp?.data.docs.forEach((attribute:any) => { + const { shipmentId, attrName, attrValue } = attribute; + if (!shipmentAttributes[shipmentId]) { + shipmentAttributes[shipmentId] = {}; + } + shipmentAttributes[shipmentId][attrName] = attrValue; + }); + + } else if (!resp?.data.error || (resp.data.error && resp.data.error !== "No record found")) { + return Promise.reject(resp?.data.error); + } + } catch (err) { + console.error('Failed to fetch shipment attributes', err) + } + + return shipmentAttributes; +} + export const ShipmentService = { fetchShipments, + fetchShipmentAttributes, + fetchTrackingCodes, getShipmentDetail, receiveShipmentItem, receiveShipment, diff --git a/src/store/modules/order/actions.ts b/src/store/modules/order/actions.ts index 5474f691..513741fe 100644 --- a/src/store/modules/order/actions.ts +++ b/src/store/modules/order/actions.ts @@ -41,12 +41,15 @@ const actions: ActionTree = { return resp; }, async updateProductCount({ commit, state }, payload ) { - state.current.items.find((item: any) => { - if (item.internalName === payload) { - item.quantityAccepted = item.quantityAccepted + 1; - } - }); - commit(types.ORDER_CURRENT_UPDATED, state.current ) + const item = state.current.items.find((item: any) => item.internalName === payload); + + if (item) { + item.quantityAccepted = item.quantityAccepted ? parseInt(item.quantityAccepted) + 1 : 1; + commit(types.ORDER_CURRENT_UPDATED, state.current ) + showToast(translate("Scanned successfully.", { itemName: payload })) + } else { + showToast(translate("Failed to scan:", { itemName: payload })) + } }, async addOrderItem ({ commit }, payload) { const product = { @@ -68,7 +71,7 @@ const actions: ActionTree = { return orders.some((order: any) => { if (order.doclist.docs[0]?.orderId === orderId) { this.dispatch('product/fetchProductInformation', { order: order.doclist.docs }); - commit(types.ORDER_CURRENT_UPDATED, { ...state.current, orderId: order.doclist.docs[0]?.orderId, externalOrderId: order.doclist.docs[0]?.externalOrderId, orderStatusId: order.doclist.docs[0]?.orderStatusId, orderStatusDesc: order.doclist.docs[0]?.orderStatusDesc, items: order.doclist.docs }) + commit(types.ORDER_CURRENT_UPDATED, { ...state.current, orderId: order.doclist.docs[0]?.orderId, externalOrderId: order.doclist.docs[0]?.externalOrderId, orderStatusId: order.doclist.docs[0]?.orderStatusId, orderStatusDesc: order.doclist.docs[0]?.orderStatusDesc, items: JSON.parse(JSON.stringify(order.doclist.docs)) }) return current; } }) @@ -195,7 +198,6 @@ const actions: ActionTree = { } catch(error){ console.error(error) current.poHistory.items = []; - showToast(translate("Something went wrong")); } commit(types.ORDER_CURRENT_UPDATED, current); return resp; diff --git a/src/store/modules/return/actions.ts b/src/store/modules/return/actions.ts index 0a0df3cf..8bdbb01c 100644 --- a/src/store/modules/return/actions.ts +++ b/src/store/modules/return/actions.ts @@ -33,12 +33,15 @@ const actions: ActionTree = { return resp; }, async updateReturnProductCount ({ commit, state }, payload) { - await state.current.items.find((item: any) => { - if(item.sku === payload){ - item.quantityAccepted = parseInt(item.quantityAccepted) + 1; - } - }); - commit(types.RETURN_CURRENT_UPDATED, state); + const item = state.current.items.find((item: any) => item.sku === payload); + + if (item) { + item.quantityAccepted = item.quantityAccepted ? parseInt(item.quantityAccepted) + 1 : 1; + commit(types.RETURN_CURRENT_UPDATED, state); + showToast(translate("Scanned successfully.", { itemName: payload })) + } else { + showToast(translate("Failed to scan:", { itemName: payload })) + } }, async setCurrent ({ commit, state }, payload) { let resp; diff --git a/src/store/modules/shipment/actions.ts b/src/store/modules/shipment/actions.ts index 0bfa860c..7f563a1a 100644 --- a/src/store/modules/shipment/actions.ts +++ b/src/store/modules/shipment/actions.ts @@ -17,9 +17,18 @@ const actions: ActionTree = { let shipments = resp.data.docs; const statusIds = [...new Set(shipments.map((shipment: any) => shipment.statusId))] const statuses = await this.dispatch('util/fetchStatus', statusIds); + + const shipmentIds = shipments.map((shipment: any) => shipment.shipmentId); + const shipmentAttributes = await ShipmentService.fetchShipmentAttributes(shipmentIds) + const trackingCodes = await ShipmentService.fetchTrackingCodes(shipmentIds) + shipments.map(async (shipment: any) => { shipment.statusDesc = statuses[shipment.statusId] + shipment.externalOrderId = shipmentAttributes[shipment.shipmentId]?.['EXTERNAL_ORDER_ID'] + shipment.externalOrderName = shipmentAttributes[shipment.shipmentId]?.['EXTERNAL_ORDER_NAME'] + shipment.trackingIdNumber = trackingCodes?.[shipment.shipmentId]; }); + if (payload.viewIndex && payload.viewIndex > 0) shipments = state.shipments.list.concat(shipments); commit(types.SHIPMENT_LIST_UPDATED, { shipments }) } else { @@ -34,18 +43,26 @@ const actions: ActionTree = { }, async updateShipmentProductCount ({ commit, state }, payload) { - await state.current.items.find((item: any) => { - if(item.sku === payload){ - item.quantityAccepted = parseInt(item.quantityAccepted) + 1; - } - }); - commit(types.SHIPMENT_CURRENT_UPDATED, state); + const item = state.current.items.find((item: any) => item.sku === payload); + + if (item) { + item.quantityAccepted = item.quantityAccepted ? parseInt(item.quantityAccepted) + 1 : 1; + commit(types.SHIPMENT_CURRENT_UPDATED, state); + showToast(translate("Scanned successfully.", { itemName: payload })) + } else { + showToast(translate("Failed to scan:", { itemName: payload })) + } }, async setCurrent ({ commit }, payload) { let resp; try { resp = await ShipmentService.getShipmentDetail(payload); if (resp.status === 200 && resp.data.items&& !hasError(resp)) { + const shipmentDetail = resp.data; + const shipmentAttributes = await ShipmentService.fetchShipmentAttributes([shipmentDetail.shipmentId]) + shipmentDetail.externalOrderId = shipmentAttributes?.[shipmentDetail.shipmentId]?.['EXTERNAL_ORDER_ID'] + shipmentDetail.externalOrderName = shipmentAttributes?.[shipmentDetail.shipmentId]?.['EXTERNAL_ORDER_NAME'] + const facilityLocations = await this.dispatch('user/getFacilityLocations', this.state.user.currentFacility.facilityId); if(facilityLocations.length){ const locationSeqId = facilityLocations[0].locationSeqId @@ -55,7 +72,7 @@ const actions: ActionTree = { } else { showToast(translate("Facility locations were not found corresponding to destination facility of return shipment. Please add facility locations to avoid receive return shipment failure.")) } - commit(types.SHIPMENT_CURRENT_UPDATED, { current: resp.data }) + commit(types.SHIPMENT_CURRENT_UPDATED, { current: shipmentDetail }) let productIds: any = new Set(); resp.data.items.map((item: any) => { productIds.add(item.productId) @@ -79,6 +96,10 @@ const actions: ActionTree = { }, receiveShipmentItem ({ commit }, payload) { return Promise.all(payload.items.map(async (item: any) => { + if(!item.locationSeqId) { + return Promise.reject("Missing locationSeqId on item") + } + const params = { shipmentId: payload.shipmentId, facilityId: this.state.user.currentFacility.facilityId, @@ -111,6 +132,7 @@ const actions: ActionTree = { emitter.emit("dismissLoader"); return resp; }).catch(err => { + emitter.emit("dismissLoader"); console.error(err) return err; }); diff --git a/src/store/modules/user/UserState.ts b/src/store/modules/user/UserState.ts index f99eaa68..05dae63f 100644 --- a/src/store/modules/user/UserState.ts +++ b/src/store/modules/user/UserState.ts @@ -7,4 +7,5 @@ export default interface UserState { facilityLocationsByFacilityId: any; productIdentificationPref: any; permissions: any; + pwaState: any; } \ No newline at end of file diff --git a/src/store/modules/user/actions.ts b/src/store/modules/user/actions.ts index 974f5b43..0c292d6e 100644 --- a/src/store/modules/user/actions.ts +++ b/src/store/modules/user/actions.ts @@ -33,7 +33,7 @@ const actions: ActionTree = { if (permissionId) serverPermissionsFromRules.push(permissionId); const serverPermissions = await UserService.getUserPermissions({ - permissionIds: serverPermissionsFromRules + permissionIds: [...new Set(serverPermissionsFromRules)] }, token); const appPermissions = prepareAppPermissions(serverPermissions); @@ -97,7 +97,7 @@ const actions: ActionTree = { // TODO Check if handling of specific status codes is required. showToast(translate('Something went wrong while login. Please contact administrator')); console.error("error", err); - return Promise.reject(new Error(err)) + return Promise.reject(err instanceof Object ? err : new Error(err)) } }, @@ -108,11 +108,11 @@ const actions: ActionTree = { // store the url on which we need to redirect the user after logout api completes in case of SSO enabled let redirectionUrl = '' - emitter.emit('presentLoader', { message: 'Logging out', backdropDismiss: false }) - // Calling the logout api to flag the user as logged out, only when user is authorised // if the user is already unauthorised then not calling the logout api as it returns 401 again that results in a loop, thus there is no need to call logout api if the user is unauthorised if(!payload?.isUserUnauthorised) { + emitter.emit('presentLoader', { message: 'Logging out', backdropDismiss: false }) + let resp; // wrapping the parsing logic in try catch as in some case the logout api makes redirection, and then we are unable to parse the resp and thus the logout process halts @@ -177,14 +177,16 @@ const actions: ActionTree = { /** * Update user timeZone */ - async setUserTimeZone ( { state, commit }, payload) { - const resp = await UserService.setUserTimeZone(payload) - if (resp.status === 200 && !hasError(resp)) { - const current: any = state.current; - current.userTimeZone = payload.timeZoneId; - commit(types.USER_INFO_UPDATED, current); - Settings.defaultZone = current.userTimeZone; - showToast(translate("Time zone updated successfully")); + async setUserTimeZone({ state, commit }, payload) { + const current: any = state.current; + if(current.userTimeZone !== payload.tzId) { + const resp = await UserService.setUserTimeZone(payload) + if(resp.status === 200 && !hasError(resp)) { + current.userTimeZone = payload.tzId; + commit(types.USER_INFO_UPDATED, current); + Settings.defaultZone = current.userTimeZone; + showToast(translate("Time zone updated successfully")); + } } }, @@ -346,6 +348,10 @@ const actions: ActionTree = { } catch(err) { console.error(err) } + }, + + updatePwaState({ commit }, payload) { + commit(types.USER_PWA_STATE_UPDATED, payload); } } diff --git a/src/store/modules/user/getters.ts b/src/store/modules/user/getters.ts index cab45d09..9ced635f 100644 --- a/src/store/modules/user/getters.ts +++ b/src/store/modules/user/getters.ts @@ -38,6 +38,9 @@ const getters: GetterTree = { }, getProductIdentificationPref: (state) => { return state.productIdentificationPref; + }, + getPwaState(state) { + return state.pwaState; } } export default getters; \ No newline at end of file diff --git a/src/store/modules/user/index.ts b/src/store/modules/user/index.ts index bb2c8058..b2ac1a25 100644 --- a/src/store/modules/user/index.ts +++ b/src/store/modules/user/index.ts @@ -18,6 +18,10 @@ const userModule: Module = { productIdentificationPref: { primaryId: 'productId', secondaryId: '' + }, + pwaState: { + updateExists: false, + registration: null, } }, getters, diff --git a/src/store/modules/user/mutation-types.ts b/src/store/modules/user/mutation-types.ts index 765ea606..34385352 100644 --- a/src/store/modules/user/mutation-types.ts +++ b/src/store/modules/user/mutation-types.ts @@ -7,4 +7,5 @@ export const USER_INSTANCE_URL_UPDATED = SN_USER + '/INSTANCE_URL_UPDATED' export const USER_CURRENT_ECOM_STORE_UPDATED = SN_USER + '/CURRENT_ECOM_STORE_UPDATED' export const USER_FACILITY_LOCATIONS_BY_FACILITY_ID = SN_USER + '/FACILITY_LOCATIONS_BY_FACILITY_ID' export const USER_PREF_PRODUCT_IDENT_CHANGED = SN_USER + '/PREF_PRODUCT_IDENT_CHANGED' -export const USER_PERMISSIONS_UPDATED = SN_USER + '/PERMISSIONS_UPDATED' \ No newline at end of file +export const USER_PERMISSIONS_UPDATED = SN_USER + '/PERMISSIONS_UPDATED' +export const USER_PWA_STATE_UPDATED = SN_USER + '/PWA_STATE_UPDATED' \ No newline at end of file diff --git a/src/store/modules/user/mutations.ts b/src/store/modules/user/mutations.ts index 21f80965..206a09ef 100644 --- a/src/store/modules/user/mutations.ts +++ b/src/store/modules/user/mutations.ts @@ -33,6 +33,10 @@ const mutations: MutationTree = { }, [types.USER_PERMISSIONS_UPDATED] (state, payload) { state.permissions = payload + }, + [types.USER_PWA_STATE_UPDATED](state, payload) { + state.pwaState.registration = payload.registration; + state.pwaState.updateExists = payload.updateExists; } } export default mutations; \ No newline at end of file diff --git a/src/views/AddProductModal.vue b/src/views/AddProductModal.vue index b54c255e..c489d52c 100644 --- a/src/views/AddProductModal.vue +++ b/src/views/AddProductModal.vue @@ -12,24 +12,30 @@ - - - - - - - -

{{ product[productIdentificationPref.primaryId] }}

-

{{ product[productIdentificationPref.secondaryId] }}

-
- - {{ translate("Add to Shipment") }} -
-
+ +
+ empty-state +

{{ translate("Enter a SKU, or product name to search a product") }}

+
@@ -55,7 +61,7 @@ import { defineComponent } from 'vue'; import { closeOutline, checkmarkCircle } from 'ionicons/icons'; import { mapGetters } from 'vuex' import { useStore } from "@/store"; -import { ShopifyImg, translate } from '@hotwax/dxp-components'; +import { DxpShopifyImg, translate } from '@hotwax/dxp-components'; import { showToast } from '@/utils' export default defineComponent({ @@ -75,7 +81,7 @@ export default defineComponent({ IonThumbnail, IonTitle, IonToolbar, - ShopifyImg + DxpShopifyImg }, data() { return { @@ -87,7 +93,9 @@ export default defineComponent({ products: 'product/getProducts', isScrollable: 'product/isScrollable', isProductAvailableInShipment: 'product/isProductAvailableInShipment', - productIdentificationPref: 'user/getProductIdentificationPref' + productIdentificationPref: 'user/getProductIdentificationPref', + currentFacility: 'user/getCurrentFacility', + facilityLocationsByFacilityId: 'user/getFacilityLocationsByFacilityId' }) }, methods: { @@ -115,6 +123,7 @@ export default defineComponent({ }) }, async addtoShipment (product: any) { + product.locationSeqId = this.facilityLocationsByFacilityId(this.currentFacility.facilityId) ? this.facilityLocationsByFacilityId(this.currentFacility.facilityId)[0]?.locationSeqId : '' this.store.dispatch('shipment/addShipmentItem', product) }, closeModal() { diff --git a/src/views/AddProductToPOModal.vue b/src/views/AddProductToPOModal.vue index 57d2f73b..bc69a42c 100644 --- a/src/views/AddProductToPOModal.vue +++ b/src/views/AddProductToPOModal.vue @@ -11,25 +11,30 @@ - - - - - - - - -

{{ product[productIdentificationPref.primaryId] }}

-

{{ product[productIdentificationPref.secondaryId] }}

-
- - {{ translate("Add to Purchase Order") }} -
-
+ +
+ empty-state +

{{ translate("Enter a SKU, or product name to search a product") }}

+
@@ -55,7 +60,7 @@ import { defineComponent } from 'vue'; import { closeOutline, checkmarkCircle } from 'ionicons/icons'; import { mapGetters } from 'vuex' import { useStore } from "@/store"; -import { ShopifyImg, translate } from '@hotwax/dxp-components'; +import { DxpShopifyImg, translate } from '@hotwax/dxp-components'; import { showToast } from '@/utils' export default defineComponent({ @@ -75,7 +80,7 @@ export default defineComponent({ IonThumbnail, IonTitle, IonToolbar, - ShopifyImg + DxpShopifyImg }, data() { return { @@ -87,7 +92,9 @@ export default defineComponent({ products: 'product/getProducts', isScrollable: 'product/isScrollable', isProductAvailableInOrder: 'order/isProductAvailableInOrder', - productIdentificationPref: 'user/getProductIdentificationPref' + productIdentificationPref: 'user/getProductIdentificationPref', + currentFacility: 'user/getCurrentFacility', + facilityLocationsByFacilityId: 'user/getFacilityLocationsByFacilityId' }) }, methods: { @@ -115,6 +122,7 @@ export default defineComponent({ }) }, async addtoOrder (product: any) { + product.locationSeqId = this.facilityLocationsByFacilityId(this.currentFacility.facilityId) ? this.facilityLocationsByFacilityId(this.currentFacility.facilityId)[0]?.locationSeqId : '' this.store.dispatch('order/addOrderItem', product) }, closeModal() { diff --git a/src/views/PurchaseOrderDetail.vue b/src/views/PurchaseOrderDetail.vue index c177e67a..e306b945 100644 --- a/src/views/PurchaseOrderDetail.vue +++ b/src/views/PurchaseOrderDetail.vue @@ -41,10 +41,10 @@ - {{ translate("PENDING: ITEMS", { itemsCount: getPOItems('pending').length }) }} + {{ translate("Pending: items", { itemsCount: getPOItems('pending').length }) }} - {{ translate("PENDING: ITEM", { itemsCount: getPOItems('pending').length }) }} + {{ translate("Pending: item", { itemsCount: getPOItems('pending').length }) }} @@ -53,7 +53,7 @@
- +

{{ productHelpers.getProductIdentificationValue(productIdentificationPref.primaryId, getProduct(item.productId)) }}

@@ -82,7 +82,7 @@
- +
@@ -100,13 +100,13 @@ - {{ translate("COMPLETED: ITEMS", { itemsCount: getPOItems('completed').length }) }} + {{ translate("Completed: items", { itemsCount: getPOItems('completed').length }) }} - {{ translate("COMPLETED: ITEM", { itemsCount: getPOItems('completed').length }) }} + {{ translate("Completed: item", { itemsCount: getPOItems('completed').length }) }} - - + + @@ -115,7 +115,7 @@
- +

{{ productHelpers.getProductIdentificationValue(productIdentificationPref.primaryId, getProduct(item.productId)) }}

@@ -144,10 +144,10 @@ - - {{ translate("Receive And Close") }} - {{ translate("Receive") }} - + + {{ translate("Receive And Close") }} + {{ translate("Receive") }} + @@ -180,7 +180,7 @@ import { import { defineComponent } from 'vue'; import { addOutline, cameraOutline, checkmarkDone, copyOutline, eyeOffOutline, eyeOutline, locationOutline, saveOutline, timeOutline } from 'ionicons/icons'; import ReceivingHistoryModal from '@/views/ReceivingHistoryModal.vue' -import { ShopifyImg, translate } from '@hotwax/dxp-components'; +import { DxpShopifyImg, translate } from '@hotwax/dxp-components'; import { useStore, mapGetters } from 'vuex'; import { useRouter } from 'vue-router'; import Scanner from "@/components/Scanner.vue" @@ -194,7 +194,7 @@ import { Actions, hasPermission } from '@/authorization' export default defineComponent({ name: "PurchaseOrderDetails", components: { - ShopifyImg, + DxpShopifyImg, IonBackButton, IonBadge, IonButton, @@ -250,7 +250,9 @@ export default defineComponent({ }); modal.onDidDismiss() .then((result) => { - this.updateProductCount(result.role); + if (result.role) { + this.updateProductCount(result.role); + } }) return modal.present(); }, diff --git a/src/views/ReceivingHistoryModal.vue b/src/views/ReceivingHistoryModal.vue index 8feb89ee..f02c7f6e 100644 --- a/src/views/ReceivingHistoryModal.vue +++ b/src/views/ReceivingHistoryModal.vue @@ -13,7 +13,7 @@ - + {{ item.receiversFullName }} @@ -52,14 +52,14 @@ import { } from '@ionic/vue'; import { defineComponent } from 'vue'; import { closeOutline } from 'ionicons/icons'; -import { ShopifyImg, translate } from '@hotwax/dxp-components'; +import { DxpShopifyImg, translate } from '@hotwax/dxp-components'; import { mapGetters, useStore } from "vuex"; import { DateTime } from 'luxon'; export default defineComponent({ name: "ReceivingHistoryModal", components: { - ShopifyImg, + DxpShopifyImg, IonButton, IonButtons, IonContent, diff --git a/src/views/ReturnDetails.vue b/src/views/ReturnDetails.vue index 21717924..002bebf8 100644 --- a/src/views/ReturnDetails.vue +++ b/src/views/ReturnDetails.vue @@ -38,7 +38,7 @@
- +

{{ productHelpers.getProductIdentificationValue(productIdentificationPref.primaryId, getProduct(item.productId)) }}

@@ -68,7 +68,7 @@ {{ translate("Receive All") }} - +

{{ item.quantityOrdered }} {{ translate("returned") }}

@@ -110,7 +110,7 @@ import { defineComponent } from 'vue'; import { checkmarkDone, barcodeOutline, locationOutline } from 'ionicons/icons'; import { mapGetters, useStore } from "vuex"; import AddProductModal from '@/views/AddProductModal.vue' -import { ShopifyImg, translate } from '@hotwax/dxp-components'; +import { DxpShopifyImg, translate } from '@hotwax/dxp-components'; import { useRouter } from 'vue-router'; import Scanner from "@/components/Scanner.vue"; import ImageModal from '@/components/ImageModal.vue'; @@ -139,7 +139,7 @@ export default defineComponent({ IonThumbnail, IonTitle, IonToolbar, - ShopifyImg, + DxpShopifyImg, }, props: ["shipment"], data() { @@ -257,7 +257,9 @@ export default defineComponent({ }); modal.onDidDismiss() .then((result) => { - this.updateProductCount(result.role); + if(result.role) { + this.updateProductCount(result.role); + } }); return modal.present(); }, diff --git a/src/views/Returns.vue b/src/views/Returns.vue index 58ee787b..ae3522ca 100644 --- a/src/views/Returns.vue +++ b/src/views/Returns.vue @@ -8,7 +8,7 @@
- + @@ -77,6 +77,7 @@ export default defineComponent({ computed: { ...mapGetters({ returns: 'return/getReturns', + currentFacility: 'user/getCurrentFacility' }) }, data () { @@ -100,7 +101,9 @@ export default defineComponent({ const viewIndex = vIndex ? vIndex : 0; const payload = { "entityName": "SalesReturnShipmentView", - "inputFields": {}, + "inputFields": { + "destinationFacilityId": this.currentFacility.facilityId + }, "fieldList" : [ "shipmentId","externalId","statusId","shopifyOrderName","hcOrderId","trackingCode", "destinationFacilityId" ], "noConditionFind": "Y", "viewSize": viewSize, diff --git a/src/views/Settings.vue b/src/views/Settings.vue index f23f23b6..a3e5b2a1 100644 --- a/src/views/Settings.vue +++ b/src/views/Settings.vue @@ -36,7 +36,7 @@

{{ translate('OMS') }}

- + @@ -56,13 +56,8 @@

-
-

- {{ translate('App') }} -

{{ "Version: " + appVersion }}

-

-

{{ "Built: " + getDateTime(appInfo.builtTime) }}

-
+ +
diff --git a/src/views/ShipmentDetails.vue b/src/views/ShipmentDetails.vue index 42623672..b3865126 100644 --- a/src/views/ShipmentDetails.vue +++ b/src/views/ShipmentDetails.vue @@ -4,7 +4,7 @@ {{ translate("Shipment Details") }} - + @@ -14,20 +14,20 @@
-

{{ current.externalOrderId }}

+

{{ current.externalOrderName ? current.externalOrderName : current.externalOrderId }}

{{ translate("External ID") }}: {{ current.externalId }}

{{ translate("Shipment ID") }}: {{ current.shipmentId }}

{{current.trackingIdNumber}}
-
+
- {{ translate("Scan") }} + {{ translate("Scan") }}
@@ -36,7 +36,7 @@
- +

{{ productHelpers.getProductIdentificationValue(productIdentificationPref.primaryId, getProduct(item.productId)) }}

@@ -46,29 +46,40 @@
- + + + + {{ item.locationSeqId }} +
- + +
+ + {{ item.quantityOrdered }} {{ translate("ordered") }} + {{ item.quantityAccepted }} {{ translate("received") }} + +
- + {{ translate("Receive All") }} - + -

{{ item.quantityOrdered }}

+

{{ item.quantityOrdered }} {{ translate("shipped") }}

- + + @@ -80,6 +91,7 @@