From 2c4651cb219598697bd215431e9dd5fb7d708d59 Mon Sep 17 00:00:00 2001 From: amansinghbais Date: Tue, 17 Sep 2024 11:52:58 +0530 Subject: [PATCH 01/16] Implemented: new UI of the Reroute fulfillment app (#92) --- src/i18n/index.ts | 4 +- src/i18n/locales/en.json | 1 + src/services/OrderService.ts | 87 +++- src/store/modules/user/UserState.ts | 1 + src/store/modules/user/actions.ts | 4 +- src/store/modules/user/getters.ts | 3 + src/store/modules/user/index.ts | 1 + src/store/modules/user/mutation-types.ts | 1 + src/store/modules/user/mutations.ts | 3 + src/views/AddressModal.vue | 41 +- src/views/OldOrder.vue | 628 +++++++++++++++++++++++ src/views/Order.vue | 498 ++++++++++-------- src/views/PickupLocationModal.vue | 228 +++----- 13 files changed, 1100 insertions(+), 400 deletions(-) create mode 100644 src/views/OldOrder.vue diff --git a/src/i18n/index.ts b/src/i18n/index.ts index 5e2fc7e5..d2996cc0 100644 --- a/src/i18n/index.ts +++ b/src/i18n/index.ts @@ -19,11 +19,11 @@ const i18n = createI18n({ messages: loadLocaleMessages() }) -const translate = (key: string) => { +const translate = (key: string, named?: any) => { if (!key) { return ''; } - return i18n.global.t(key); + return i18n.global.t(key, named); }; export { i18n as default, translate } \ No newline at end of file diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 986b8fed..709e0482 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -48,6 +48,7 @@ "Street": "Street", "Tracking code": "Tracking code", "Username": "Username", + "was unable to prepare your order. Please select alternate options.": "{facilityName} was unable to prepare your order. Please select alternate options.", "Your Order": "Your Order", "Zipcode": "Zipcode" } \ No newline at end of file diff --git a/src/services/OrderService.ts b/src/services/OrderService.ts index 5a34501d..a80e3c19 100644 --- a/src/services/OrderService.ts +++ b/src/services/OrderService.ts @@ -1,5 +1,6 @@ -import { api } from '@/adapter'; +import { api, client } from '@/adapter'; import store from '@/store'; +import { hasError } from '@hotwax/oms-api'; const getOrder = async (payload: any): Promise => { let baseURL = store.getters['user/getInstanceUrl']; @@ -43,7 +44,91 @@ const getProductStoreSetting = async (payload: any): Promise => { }); } +const fetchOrderFacilityChangeHistory = async (payload: any): Promise => { + let baseURL = store.getters['user/getInstanceUrl']; + baseURL = baseURL && baseURL.startsWith('http') ? baseURL : `https://${baseURL}.hotwax.io/api/`; + + + return client({ + url: "performFind", + method: "POST", + data: payload, + baseURL, + headers: { + Authorization: 'Bearer ' + process.env.VUE_APP_BASE, + 'Content-Type': 'application/json' + } + }) +} + +const fetchCustomerSavedAddress = async (orderId: any): Promise => { + let baseURL = store.getters['user/getInstanceUrl']; + baseURL = baseURL && baseURL.startsWith('http') ? baseURL : `https://${baseURL}.hotwax.io/api/`; + + let resp, contactMechId, address; + let params = { + entityName: "OrderContactMech", + inputFields: { + orderId: orderId, + contactMechPurposeTypeId: "SHIPPING_LOCATION" + }, + fieldList: ["orderId", "contactMechId"], + viewSize: 1 + } as any; + + try { + resp = await client({ + url: "performFind", + method: "POST", + data: params, + baseURL, + headers: { + Authorization: 'Bearer ' + process.env.VUE_APP_BASE, + 'Content-Type': 'application/json' + } + }) + + if(!hasError(resp)) { + contactMechId = resp.data.docs[0]?.contactMechId; + + params = { + entityName: "PostalAddress", + inputFields: { + contactMechId + }, + viewSize: 1 + }; + + resp = await client({ + url: "performFind", + method: "POST", + data: params, + baseURL, + headers: { + Authorization: 'Bearer ' + process.env.VUE_APP_BASE, + 'Content-Type': 'application/json' + } + }) + + if(!hasError(resp)) { + address = resp.data.docs[0] + } else { + throw resp.data; + } + } else { + throw resp.data; + } + } catch(error: any) { + console.error(error); + } + + return address; +} + + export const OrderService = { + fetchCustomerSavedAddress, + fetchOrderFacilityChangeHistory, getOrder, updateShippingAddress, updatePickupFacility, diff --git a/src/store/modules/user/UserState.ts b/src/store/modules/user/UserState.ts index 12e8f49a..9e3c5239 100644 --- a/src/store/modules/user/UserState.ts +++ b/src/store/modules/user/UserState.ts @@ -4,4 +4,5 @@ export default interface UserState { instanceUrl: string; deliveryMethod: string; permissions: any; + isSplitEnabled: boolean; } \ No newline at end of file diff --git a/src/store/modules/user/actions.ts b/src/store/modules/user/actions.ts index 3021eb86..25047115 100644 --- a/src/store/modules/user/actions.ts +++ b/src/store/modules/user/actions.ts @@ -120,7 +120,7 @@ const actions: ActionTree = { token, inputFields: { productStoreId, - "settingTypeEnumId": ["CUST_DLVRMTHD_UPDATE", "CUST_DLVRADR_UPDATE", "CUST_PCKUP_UPDATE", "CUST_ALLOW_CNCL", "RF_SHIPPING_METHOD"], + "settingTypeEnumId": ["CUST_DLVRMTHD_UPDATE", "CUST_DLVRADR_UPDATE", "CUST_PCKUP_UPDATE", "CUST_ALLOW_CNCL", "RF_SHIPPING_METHOD", "CUST_ORD_ITEM_SPLIT"], "settingTypeEnumId_op": "in" }, viewSize: 100 @@ -128,10 +128,12 @@ const actions: ActionTree = { if (!hasError(resp)) { const permissions = resp.data.docs.filter((permission: any) => permission.settingValue == 'true').map((permission: any) => permission.settingTypeEnumId) const deliveryMethod = resp.data.docs.find((permission: any) => permission.settingTypeEnumId === 'RF_SHIPPING_METHOD')?.settingValue + const isSplitEnabled = resp.data.docs.find((permission: any) => permission.settingTypeEnumId === 'CUST_ORD_ITEM_SPLIT')?.settingValue const appPermissions = prepareAppPermissions(permissions); setPermissions(appPermissions); commit(types.USER_DELIVERY_METHOD_UPDATED, deliveryMethod ? deliveryMethod : "STANDARD"); commit(types.USER_PERMISSIONS_UPDATED, appPermissions); + commit(types.USER_ORDER_SPLIT_CONFIG_UPDATED, isSplitEnabled === "true"); } } catch (error) { console.error(error) diff --git a/src/store/modules/user/getters.ts b/src/store/modules/user/getters.ts index 1a94d5e4..5670a1fa 100644 --- a/src/store/modules/user/getters.ts +++ b/src/store/modules/user/getters.ts @@ -24,6 +24,9 @@ const getters: GetterTree = { }, getUserPermissions (state) { return state.permissions; + }, + isSplitEnabled (state) { + return state.isSplitEnabled; } } 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 aabfd1c3..d053f51b 100644 --- a/src/store/modules/user/index.ts +++ b/src/store/modules/user/index.ts @@ -13,6 +13,7 @@ const userModule: Module = { instanceUrl: '', deliveryMethod: '', permissions: [], + isSplitEnabled: false }, getters, actions, diff --git a/src/store/modules/user/mutation-types.ts b/src/store/modules/user/mutation-types.ts index f530cd82..f0a5cfdf 100644 --- a/src/store/modules/user/mutation-types.ts +++ b/src/store/modules/user/mutation-types.ts @@ -5,3 +5,4 @@ export const USER_INFO_UPDATED = SN_USER + '/INFO_UPDATED' export const USER_INSTANCE_URL_UPDATED = SN_USER + '/INSTANCE_URL_UPDATED' export const USER_PERMISSIONS_UPDATED = SN_USER + '/PERMISSIONS_UPDATED' export const USER_DELIVERY_METHOD_UPDATED = SN_USER + '/DELIVERY_METHOD_UPDATED' +export const USER_ORDER_SPLIT_CONFIG_UPDATED = SN_USER + '/ORDER_SPLIT_CONFIG_UPDATED' diff --git a/src/store/modules/user/mutations.ts b/src/store/modules/user/mutations.ts index 3b94fcd5..01ef639f 100644 --- a/src/store/modules/user/mutations.ts +++ b/src/store/modules/user/mutations.ts @@ -22,6 +22,9 @@ const mutations: MutationTree = { }, [types.USER_DELIVERY_METHOD_UPDATED] (state, payload) { state.deliveryMethod = payload + }, + [types.USER_ORDER_SPLIT_CONFIG_UPDATED] (state, payload) { + state.isSplitEnabled = payload } } export default mutations; \ No newline at end of file diff --git a/src/views/AddressModal.vue b/src/views/AddressModal.vue index 2135cfd0..e88db756 100644 --- a/src/views/AddressModal.vue +++ b/src/views/AddressModal.vue @@ -1,39 +1,39 @@ @@ -95,11 +95,11 @@ export default defineComponent({ loader: null as any }; }, - props: ["shipGroup", "token"], + props: ["shipGroup", "token", "updatedAddress"], async mounted() { this.presentLoader() await this.getAssociatedStates() - if (this.shipGroup.shipmentMethodTypeId != 'STOREPICKUP') this.prepareAddress(); + this.prepareAddress(); this.dismissLoader() }, methods: { @@ -113,11 +113,11 @@ export default defineComponent({ // In some cases, we get a stateProvinceGeoId that does not exist in data, thus state is not displayed on the UI but originally the field has information thus toast of empty field is not displayed // thus added a check that if the geoCode is not found in the states fetched from the server, do not stop the address update process and pass the same state that was previously in the address. this.address.stateCode = state?.geoCode || this.address.stateProvinceGeoId; - this.close(this.address); + this.closeModal(this.address); }, prepareAddress() { - if(this.shipGroup?.updatedAddress) { - this.address = this.shipGroup.updatedAddress + if(this.updatedAddress) { + this.address = this.updatedAddress return; } @@ -149,13 +149,13 @@ export default defineComponent({ } }, - close(address?: any) { - modalController.dismiss({ dismissed: true }, address); + closeModal(address?: any) { + modalController.dismiss({ dismissed: true, updatedAddress: address }); }, async presentLoader() { this.loader = await loadingController .create({ - message: this.$t("Fetching address") + message: this.translate("Fetching address") }); await this.loader.present(); }, @@ -169,7 +169,12 @@ export default defineComponent({ setup() { const router = useRouter(); const store = useStore(); - return { closeOutline, router, store }; + return { + closeOutline, + router, + store, + translate + }; } }); \ No newline at end of file diff --git a/src/views/OldOrder.vue b/src/views/OldOrder.vue new file mode 100644 index 00000000..35537bc3 --- /dev/null +++ b/src/views/OldOrder.vue @@ -0,0 +1,628 @@ + + + + + \ No newline at end of file diff --git a/src/views/Order.vue b/src/views/Order.vue index 498d80f0..decc02b1 100644 --- a/src/views/Order.vue +++ b/src/views/Order.vue @@ -4,7 +4,7 @@
-

{{ $t("Your Order") }}

+

{{ translate("Your Order") }}

@@ -15,77 +15,119 @@ {{ $filters.formatDate(order.orderDate) }} +
- - - - - -

{{ item.brandName }}

-

{{ item.name }}

-

- {{ feature }}: {{ attribute }} -

-
+ + {{ translate("was unable to prepare your order. Please select alternate options.", { facilityName: getStoreName(originFacilityId) }) }} - - - - + + + {{ method.name }} - {{ $t("Add address") }} - {{ $t("Select pickup location")}} - - - {{ shipGroup.selectedFacility.facilityName }} - {{ shipGroup.selectedFacility.address1 }} - {{ shipGroup.selectedFacility.city }} {{ shipGroup.selectedFacility.stateCode }} {{ shipGroup.shipTo.postalAddress.country }} {{ shipGroup.selectedFacility.postalCode }} - - {{ $t("Change Store")}} + + + + + + {{ translate("Suggest store") }} + + + + +

{{ translate("We'll try to find a location with the most items in stock.") }}

+
- - - {{ shipGroup.updatedAddress.firstName }} {{ shipGroup.updatedAddress.lastName }} - {{ shipGroup.updatedAddress.address1 }} - {{ shipGroup.updatedAddress.city }} {{ shipGroup.updatedAddress.stateCode }} {{ shipGroup.updatedAddress.postalCode }} - - - {{ shipGroup.shipTo.postalAddress.toName }} - {{ shipGroup.shipTo.postalAddress.address1 }} - {{ shipGroup.shipTo.postalAddress.city }} {{ shipGroup.shipTo.postalAddress.stateCode }} {{ shipGroup.shipTo.postalAddress.postalCode }} - - {{ $t("Edit address") }} + + + +
+ + {{ facilityId }} + + +
+ + + + + + {{ item.name }} +

+ {{ feature }}: {{ attribute }} +

+
+ + + + +
+
+
+ + + + {{ selectedFacility.facilityName }} +

{{ selectedFacility.address1 }}

+

{{ selectedFacility.city }} {{ selectedFacility.stateCode }} {{ shipGroup.shipTo.postalAddress.country }} {{ selectedFacility.postalCode }}

+
- - - - {{ $t('Tracking code') }} - {{ shipGroup.trackingNumber }} + + + {{ updatedAddress.firstName }} {{ updatedAddress.lastName }} +

{{ updatedAddress.address1 }}

+

{{ updatedAddress.city }} {{ updatedAddress.stateCode }} {{ updatedAddress.postalCode }}

+
- - {{ $t("Save changes") }} - {{ $t("Cancel") }} + + {{ selectedFacility.facilityId ? translate("Change pickup location") : translate("Select pickup location")}} + {{ updatedAddress.address1 ? translate("Edit address") : translate("Add address") }} + +
+ {{ translate("Save changes") }} + {{ translate("Cancel") }} +
- {{ $t("An email will be sent to you when your item(s) are ready to collect at the new requested location(s).") }} + {{ translate("An email will be sent to you when your item(s) are ready to collect at the new requested location(s).") }}
- {{ $t("Order item not eligible for reroute fulfilment") }} + {{ translate("Order item not eligible for reroute fulfilment") }}
- {{ $t("Order not found") }} + {{ translate("Order not found") }}
@@ -98,13 +140,16 @@ import { IonButton, IonCard, IonContent, + IonIcon, IonItem, + IonItemDivider, IonLabel, - IonList, IonNote, IonPage, IonSelect, IonSelectOption, + IonSegment, + IonSegmentButton, IonThumbnail, loadingController, modalController, @@ -121,6 +166,9 @@ import { ProductService } from "@/services/ProductService"; import PickupLocationModal from "@/views/PickupLocationModal.vue"; import { Actions, hasPermission } from '@/authorization' import { initialise } from '@/adapter' +import { addOutline, colorWandOutline, removeCircleOutline, storefrontOutline } from "ionicons/icons"; +import { FacilityService } from '@/services/FacilityService'; +import { StockService } from '@/services/StockService'; export default defineComponent({ name: "Order", @@ -129,12 +177,15 @@ export default defineComponent({ IonButton, IonCard, IonContent, + IonIcon, IonItem, + IonItemDivider, IonLabel, - IonList, IonNote, IonSelect, IonSelectOption, + IonSegment, + IonSegmentButton, IonThumbnail, IonPage, }, @@ -154,12 +205,21 @@ export default defineComponent({ value: 'STANDARD' } ], - isOrderUpdated: false + originFacilityId: "", + selectedSegment: "separate", + customerAddress: {} as any, + nearbyStores: [] as any, + availableStores: [] as any, + storesWithInventory: [] as any, + selectedFacility: {} as any, + updatedAddress: {} as any, + selectedItemsByFacility: {} as any } }, computed: { ...mapGetters({ deliveryMethod: 'user/getDeliveryMethod', + isSplitEnabled: 'user/isSplitEnabled', }) }, props: ["token"], @@ -181,13 +241,17 @@ export default defineComponent({ }) this.store.dispatch("user/setUserInstanceUrl", `${this.$route.query.oms}/api/`) await this.getOrder(); + this.fetchOrderFacilityChangeHistory() + this.customerAddress = await OrderService.fetchCustomerSavedAddress(this.order.id); + await this.getPickupStores(); + if(!this.nearbyStores.length) this.selectedSegment = "separate" } }, methods: { async presentLoader() { this.loader = await loadingController .create({ - message: this.$t("Fetching order details."), + message: translate("Fetching order details."), translucent: true, }); await this.loader.present(); @@ -234,6 +298,57 @@ export default defineComponent({ } this.dismissLoader() }, + + async fetchOrderFacilityChangeHistory() { + try { + const resp = await OrderService.fetchOrderFacilityChangeHistory({ + entityName: "OrderFacilityChange", + inputFields: { + orderId: this.order.id, + orderItemSeqId: this.order.shipGroup[0].items[0].itemSeqId + }, + viewSize: 2, + orderBy: "changeDatetime ASC" + }) + if(!hasError(resp)) { + this.originFacilityId = resp.data.docs[0]?.facilityId + } else { + throw resp.data; + } + } catch(error: any) { + console.error(error); + } + }, + + async getPickupStores() { + try { + let stores; + let point = "" + if(this.customerAddress?.latitude) { + point = `${this.customerAddress.latitude},${this.customerAddress.longitude}` + } + + stores = await this.getStores(point ? point : '') + this.availableStores = stores; + + if (!stores?.length) return; + + const facilityIds = stores.map((store: any) => store.storeCode) + const productIds = [...new Set(this.order.shipGroup[0].items.map((item: any) => item.productId))] as any; + const storesWithInventory = await this.checkInventory(facilityIds, productIds) + this.storesWithInventory = storesWithInventory + + if (!storesWithInventory?.length) return; + + stores.map((storeData: any) => { + const inventoryDetails = storesWithInventory.filter((store: any) => store.facilityId === storeData.storeCode); + if (inventoryDetails.length === productIds.length) this.nearbyStores.push({...storeData, ...inventoryDetails[0], distance: storeData.dist }); + }); + } catch (error) { + console.error(error) + } + }, + async fetchProducts(productIds: any) { const productIdFilter = productIds.reduce((filter: string, productId: any) => { if (filter !== '') filter += ' OR ' @@ -256,197 +371,137 @@ export default defineComponent({ } }, - getProduct(productId: string) { - return this.products[productId] ? this.products[productId] : {} - }, - - async updateShippingAddress(shipGroup: any) { - let resp - const payload = { - "orderId": this.order.id, - "shipGroupSeqId": shipGroup.shipGroupSeqId, - "contactMechId": shipGroup.shipmentMethodTypeId === 'STOREPICKUP' ? "" :shipGroup.shipTo.postalAddress.id, - "shipmentMethod": `${this.deliveryMethod}@_NA_`, - "contactMechPurposeTypeId": "SHIPPING_LOCATION", - "facilityId": shipGroup.facilityId, - "toName": `${shipGroup.updatedAddress.firstName} ${shipGroup.updatedAddress.lastName}`, - "address1": shipGroup.updatedAddress.address1, - "city": shipGroup.updatedAddress.city, - "stateProvinceGeoId": shipGroup.updatedAddress.stateProvinceGeoId, - "postalCode": shipGroup.updatedAddress.postalCode, - "countryGeoId": shipGroup.updatedAddress.countryGeoId, - "token": this.token - } as any - - if (shipGroup.selectedShipmentMethodTypeId === shipGroup.shipmentMethodTypeId) { - // In case of address edit, we honour the previously selected delivery method - payload.shipmentMethod = `${shipGroup.shipmentMethodTypeId}@_NA_` - payload.isEdited = true - } - - try { - resp = await OrderService.updateShippingAddress(payload); - if (resp.status === 200 && !hasError(resp) && resp.data) { - shipGroup.shipTo.postalAddress = shipGroup.updatedAddress - shipGroup.updatedAddress = null - showToast(translate("Changes saved")) - this.isOrderUpdated = true - } else { - showToast(translate("Failed to update the shipping addess")) - } - } catch (error) { - console.error(error) - showToast(translate("Failed to update the shipping addess")) + segmentChanged(event: any, shipGroup: any) { + this.selectedSegment = event.detail.value + if(shipGroup.selectedShipmentMethodTypeId === "STOREPICKUP") { + this.selectedFacility = {} + this.selectedItemsByFacility = {} + this.order.shipGroup[0].items.map((item: any) => { + item.selectedFacilityId = "" + }) } - this.getOrder(); }, - async updatePickupFacility(shipGroup: any) { - let resp - const payload = { - "orderId": this.order.id, - "shipGroupSeqId": shipGroup.shipGroupSeqId, - "contactMechId": shipGroup.shipTo.postalAddress.id, - "shipmentMethod": "STOREPICKUP@_NA_@CARRIER", // TODO Check why CARRIER is needed - "contactMechPurposeTypeId": "SHIPPING_LOCATION", - "facilityId": shipGroup.selectedFacility.facilityId, - "token": this.token - } + getStoreName(facilityId: any) { + return this.nearbyStores.find((store: any) => store.storeCode === facilityId)?.storeName + }, - try { - resp = await OrderService.updatePickupFacility(payload); - if (resp.status === 200 && !hasError(resp)) { - shipGroup.facilityId = shipGroup.selectedFacility.facilityId - showToast(translate("Changes saved")) - this.isOrderUpdated = true - } else { - showToast(translate("Failed to update the pickup store")) - } - } catch (error) { - console.error(error) - showToast(translate("Failed to update the pickup store")) - } - this.getOrder(); + getProduct(productId: string) { + return this.products[productId] ? this.products[productId] : {} }, updateDeliveryMethod(event: any, shipGroup: any) { const group = this.order.shipGroup.find((group: any) => group.shipGroupSeqId === shipGroup.shipGroupSeqId); group.selectedShipmentMethodTypeId = event.detail.value; - // Resetting the previous changes on method change - this.resetShipGroup(shipGroup) }, - async updateDeliveryAddress(shipGroup: any) { - const modal = await modalController - .create({ - component: AddressModal, - // Adding backdropDismiss as false because on dismissing the modal through backdrop, - // backrop.role returns 'backdrop' giving unexpected result - backdropDismiss: false, - componentProps: { - shipGroup, - token: this.token - } - }) + async updatePickupLocation(isPickupForAll: boolean, selectedFacilityId: any, item?: any) { + const modal = await modalController.create({ + component: PickupLocationModal, + componentProps: { + isPickupForAll, + storesWithInventory: this.storesWithInventory, + nearbyStores: this.nearbyStores, + availableStores: this.availableStores, + selectedFacilityId, + customerAddress: this.customerAddress, + currentProductId: item?.productId + } + }) + modal.onDidDismiss().then((result) => { - if (result.role) { - // role will have the passed data - shipGroup.updatedAddress = result.role + const selectedFacilityId = result.data.selectedFacilityId; + + if (selectedFacilityId) { + if(isPickupForAll) { + this.selectedFacility = this.nearbyStores.find((store: any) => store.facilityId === selectedFacilityId); + } else { + item.selectedFacilityId = selectedFacilityId + if(this.selectedItemsByFacility[selectedFacilityId]?.length) this.selectedItemsByFacility[selectedFacilityId].push(item); + else this.selectedItemsByFacility[selectedFacilityId] = [item] + } } }); + return modal.present(); }, - async updatePickupLocation(shipGroup: any) { - const modal = await modalController - .create({ - component: PickupLocationModal, - // Adding backdropDismiss as false because on dismissing the modal through backdrop, - // backrop.role returns 'backdrop' giving unexpected result - backdropDismiss: false, - componentProps: { - shipGroup - } - }) + async updateDeliveryAddress(shipGroup: any) { + const modal = await modalController.create({ + component: AddressModal, + componentProps: { + shipGroup, + token: this.token, + updatedAddress: this.updatedAddress + } + }) + modal.onDidDismiss().then((result) => { - if (result.role) { - // role will have the passed data - shipGroup.selectedFacility = result.role + if (result.data.updatedAddress) { + this.updatedAddress = result.data.updatedAddress } }); + return modal.present(); }, - async save(shipGroup: any) { - const message = this.$t("Are you sure you want to save the changes?"); - const alert = await alertController.create({ - header: this.$t("Save changes"), - message, - buttons: [ - { - text: this.$t("Cancel"), - }, - { - text: this.$t("Confirm"), - handler: () => { - shipGroup.selectedShipmentMethodTypeId === 'STOREPICKUP' ? this.updatePickupFacility(shipGroup) : this.updateShippingAddress(shipGroup); + async checkInventory(facilityIds: Array, productIds: Array) { + let isScrollable = true, viewSize = 250, viewIndex = 0, total = 0; + let productInventoryResp = [] as any; + + try { + while(isScrollable) { + const resp = await StockService.checkInventory({ + "filters": { + "productId": productIds, + "facilityId": facilityIds + }, + "fieldsToSelect": ["productId", "atp", "facilityName", "facilityId"], + viewSize, + viewIndex + }); + + if(!hasError(resp) && resp.data.count) { + if(!productInventoryResp.length) { + productInventoryResp = resp.data.docs + total = resp.data.count; + } else { + productInventoryResp = productInventoryResp.concat(resp.data.docs) } + if(productInventoryResp.length >= total) isScrollable = false; + viewIndex++; } - ], - }); - return alert.present(); + } + return productInventoryResp.filter((store: any) => store.atp > 0) + } catch (error) { + console.error(error) + } }, - - async cancelShipGroup(shipGroup: any) { - let resp - const itemReasonMap = {} as any - shipGroup.items.map((item: any) => itemReasonMap[item.itemSeqId] = 'OICR_CHANGE_MIND') - const payload = { - "orderId": this.order.id, - "shipGroupSeqId": shipGroup.shipGroupSeqId, - "itemReasonMap": itemReasonMap, - "token": this.token + async getStores(point?: string) { + let payload = { + "viewSize": process.env.VUE_APP_VIEW_SIZE, + "filters": ["storeType: RETAIL_STORE", "pickup_pref: true"] } as any + if(point) { + payload.point = point + } + try { - resp = await OrderService.cancelOrderItem(payload); - if (resp.status === 200 && !hasError(resp) && resp.data.orderId == this.order.id) { - shipGroup.isCancelled = true; - showToast(translate("Order cancelled successfully")) - } else { - showToast(translate("Failed to cancel the order")) - } + const storeLookupResp = await FacilityService.getStores(payload) + if (storeLookupResp.status !== 200 || hasError(storeLookupResp) || !storeLookupResp.data.response.numFound) { + return []; + } + return storeLookupResp.data.response.docs } catch (error) { console.error(error) - showToast(translate("Failed~ to cancel the order")) } - this.getOrder(); }, - async cancel(shipGroup: any) { - const message = this.$t("Are you sure you want to cancel the order items?"); - const alert = await alertController.create({ - header: this.$t("Cancel items"), - message, - buttons: [ - { - text: this.$t("Don't Cancel"), - }, - { - text: this.$t("Cancel"), - handler: () => { - this.cancelShipGroup(shipGroup); - } - } - ], - }); - return alert.present(); - }, - - resetShipGroup(shipGroup: any) { - shipGroup.updatedAddress = null - shipGroup.selectedFacility = null + removeItemFromFacility(item: any, facilityId: any) { + this.selectedItemsByFacility[facilityId] = this.selectedItemsByFacility[facilityId].filter((currentItem: any) => currentItem.itemSeqId !== item.itemSeqId); + console.log(this.selectedItemsByFacility); } }, setup() { @@ -454,9 +509,14 @@ export default defineComponent({ const store = useStore(); return { Actions, + addOutline, hasPermission, + colorWandOutline, + removeCircleOutline, router, - store + store, + storefrontOutline, + translate }; } }); @@ -469,4 +529,10 @@ export default defineComponent({ margin: auto; } } + + .actions { + display: flex; + justify-content: space-between; + border-top: 1px solid var(--ion-color-light); + } \ No newline at end of file diff --git a/src/views/PickupLocationModal.vue b/src/views/PickupLocationModal.vue index 54fced91..dc6ecd9b 100644 --- a/src/views/PickupLocationModal.vue +++ b/src/views/PickupLocationModal.vue @@ -1,60 +1,72 @@ From b4b7a142b6f8f79348ca9c3bac25c312e3dd66be Mon Sep 17 00:00:00 2001 From: amansinghbais Date: Thu, 19 Sep 2024 19:17:43 +0530 Subject: [PATCH 02/16] Implemented: Logic for the reroute fulfillment v2 (#92) --- src/services/OrderService.ts | 75 ++-------- src/views/OldOrder.vue | 6 +- src/views/Order.vue | 262 +++++++++++++++++++++++++++++++++-- 3 files changed, 265 insertions(+), 78 deletions(-) diff --git a/src/services/OrderService.ts b/src/services/OrderService.ts index a80e3c19..140a1544 100644 --- a/src/services/OrderService.ts +++ b/src/services/OrderService.ts @@ -61,77 +61,28 @@ const fetchOrderFacilityChangeHistory = async (payload: any): Promise => { }) } -const fetchCustomerSavedAddress = async (orderId: any): Promise => { +const releaseOrderItem = async (payload: any): Promise => { let baseURL = store.getters['user/getInstanceUrl']; baseURL = baseURL && baseURL.startsWith('http') ? baseURL : `https://${baseURL}.hotwax.io/api/`; - let resp, contactMechId, address; - let params = { - entityName: "OrderContactMech", - inputFields: { - orderId: orderId, - contactMechPurposeTypeId: "SHIPPING_LOCATION" - }, - fieldList: ["orderId", "contactMechId"], - viewSize: 1 - } as any; - - try { - resp = await client({ - url: "performFind", - method: "POST", - data: params, - baseURL, - headers: { - Authorization: 'Bearer ' + process.env.VUE_APP_BASE, - 'Content-Type': 'application/json' - } - }) - - if(!hasError(resp)) { - contactMechId = resp.data.docs[0]?.contactMechId; - - params = { - entityName: "PostalAddress", - inputFields: { - contactMechId - }, - viewSize: 1 - }; - - resp = await client({ - url: "performFind", - method: "POST", - data: params, - baseURL, - headers: { - Authorization: 'Bearer ' + process.env.VUE_APP_BASE, - 'Content-Type': 'application/json' - } - }) - - if(!hasError(resp)) { - address = resp.data.docs[0] - } else { - throw resp.data; - } - } else { - throw resp.data; + return client({ + url: "releaseOrderItem", + method: "POST", + data: payload, + baseURL, + headers: { + Authorization: 'Bearer ' + process.env.VUE_APP_BASE, + 'Content-Type': 'application/json' } - } catch(error: any) { - console.error(error); - } - - return address; -} - + }); +} export const OrderService = { - fetchCustomerSavedAddress, fetchOrderFacilityChangeHistory, getOrder, updateShippingAddress, updatePickupFacility, cancelOrderItem, - getProductStoreSetting + getProductStoreSetting, + releaseOrderItem } \ No newline at end of file diff --git a/src/views/OldOrder.vue b/src/views/OldOrder.vue index 35537bc3..b980108b 100644 --- a/src/views/OldOrder.vue +++ b/src/views/OldOrder.vue @@ -182,7 +182,7 @@ export default defineComponent({ cutomerAddress: {} as any, nearbyStores: [] as any, availableStores: [] as any, - storesWithInventory: [] as any + storesWithInventory: [] as any, } }, computed: { @@ -211,7 +211,6 @@ export default defineComponent({ this.store.dispatch("user/setUserInstanceUrl", `${this.$route.query.oms}/api/`) await this.getOrder(); this.fetchOrderFacilityChangeHistory() - this.cutomerAddress = await OrderService.fetchCustomerSavedAddress(this.order.id); await this.getPickupStores(); if(!this.nearbyStores.length) this.selectedSegment = "separate" } @@ -247,7 +246,7 @@ export default defineComponent({ order = resp.data; const productIds: any = new Set(); order.shipGroup = order.shipGroup.filter((group: any) => { - if(group.facilityId === 'PICKUP_REJECTED') { + if(group.facilityId === 'PICKUP_REJECTED' && group.shipmentMethodTypeId === 'STOREPICKUP') { group.selectedShipmentMethodTypeId = group.shipmentMethodTypeId; group.items = group.items.filter((item: any) => { if (item.status == 'ITEM_CANCELLED') return false; @@ -257,6 +256,7 @@ export default defineComponent({ return group.items.length > 0; } }) + if (productIds.length) await this.fetchProducts([...productIds]) await this.store.dispatch("user/getConfiguration", { productStoreId: order.productStoreId, token: this.token}); this.order = order; diff --git a/src/views/Order.vue b/src/views/Order.vue index decc02b1..01696215 100644 --- a/src/views/Order.vue +++ b/src/views/Order.vue @@ -54,7 +54,7 @@ @@ -47,17 +54,17 @@ import { IonIcon, IonItem, IonInput, + IonLabel, IonList, IonSelect, IonSelectOption, + IonSpinner, IonTitle, IonToolbar, modalController, - loadingController } from '@ionic/vue'; import { defineComponent } from 'vue'; import { closeOutline } from 'ionicons/icons'; -import { useRouter } from "vue-router"; import { useStore } from "@/store"; import { translate } from '@/i18n'; import { hasError, showToast } from '@/utils'; @@ -73,9 +80,11 @@ export default defineComponent({ IonIcon, IonItem, IonInput, + IonLabel, IonList, IonSelect, IonSelectOption, + IonSpinner, IonTitle, IonToolbar }, @@ -92,15 +101,15 @@ export default defineComponent({ } as any, contactMechId: '', states: [] as any, - loader: null as any + isLoading: false }; }, props: ["shipGroup", "token", "updatedAddress"], async mounted() { - this.presentLoader() + this.isLoading = true; await this.getAssociatedStates() this.prepareAddress(); - this.dismissLoader() + this.isLoading = false; }, methods: { async updateAddress() { @@ -116,7 +125,7 @@ export default defineComponent({ this.closeModal(this.address); }, prepareAddress() { - if(this.updatedAddress) { + if(this.updatedAddress.address1) { this.address = this.updatedAddress return; } @@ -152,26 +161,11 @@ export default defineComponent({ closeModal(address?: any) { modalController.dismiss({ dismissed: true, updatedAddress: address }); }, - async presentLoader() { - this.loader = await loadingController - .create({ - message: this.translate("Fetching address") - }); - await this.loader.present(); - }, - dismissLoader() { - if (this.loader) { - this.loader.dismiss(); - this.loader = null; - } - }, }, setup() { - const router = useRouter(); const store = useStore(); return { closeOutline, - router, store, translate }; diff --git a/src/views/Order.vue b/src/views/Order.vue index d2fb838c..81734ad8 100644 --- a/src/views/Order.vue +++ b/src/views/Order.vue @@ -16,138 +16,144 @@ -
- - - {{ translate("was unable to prepare your order. Please select alternate options.", { facilityName: getStoreName(originFacilityId) }) }} - + + + {{ translate("was unable to prepare your order. Please select alternate options.", { facilityName: originFacilityName }) }} + + + + + {{ method.name }} + + - - - {{ method.name }} - + - + + - - - {{ translate("Suggest store") }} - + - + + +
+ + {{ translate("Out of stock") }} + - - -
- - {{ facilityId }} - - -
- - - - - - {{ item.name }} -

- {{ feature }}: {{ attribute }} -

-
- - - - -
-
+
+ +
+ + {{ facilityId }} + + +
+ + + + + + {{ item.name }} +

+ {{ feature }}: {{ attribute }} +

+
-
- - {{ translate("Out of stock") }} - - -
- - - - - -

{{ translate("Request Cancellation") }}

- {{ item.name }} -

- {{ feature }}: {{ attribute }} -

-
- - - - - - - - -
-
+ + + +
+
- - - {{ selectedFacility.facilityName }} -

{{ selectedFacility.address1 }}

-

{{ selectedFacility.city }} {{ selectedFacility.stateCode }} {{ shipGroup.shipTo.postalAddress.country }} {{ selectedFacility.postalCode }}

-
-
- - - {{ updatedAddress.firstName }} {{ updatedAddress.lastName }} -

{{ updatedAddress.address1 }}

-

{{ updatedAddress.city }} {{ updatedAddress.stateCode }} {{ updatedAddress.postalCode }}

-
-
+ + + {{ selectedFacility.facilityName }} +

{{ selectedFacility.address1 }}

+

{{ selectedFacility.city }} {{ selectedFacility.stateCode }} {{ order.shipGroup.shipTo.postalAddress.country }} {{ selectedFacility.postalCode }}

+
+
+ + + {{ updatedAddress.firstName }} {{ updatedAddress.lastName }} +

{{ updatedAddress.address1 }}

+

{{ updatedAddress.city }} {{ updatedAddress.stateCode }} {{ updatedAddress.postalCode }}

+
+
- {{ selectedFacility.facilityId ? translate("Change pickup location") : translate("Select pickup location")}} - {{ updatedAddress.address1 ? translate("Edit address") : translate("Add address") }} + {{ selectedFacility.facilityId ? translate("Change pickup location") : translate("Select pickup location")}} + {{ updatedAddress.address1 ? translate("Edit address") : translate("Add address") }} -
- {{ translate("Save changes") }} - {{ translate("Cancel") }} -
- -
+
+ {{ translate("Save changes") }} + {{ translate("Cancel") }} +
+
{{ translate("An email will be sent to you when your item(s) are ready to collect at the new requested location(s).") }}
@@ -234,8 +240,8 @@ export default defineComponent({ value: 'STANDARD' } ], - originFacilityId: "", - selectedSegment: "separate", + originFacilityName: "", + selectedSegment: "together", customerAddress: {} as any, nearbyStores: [] as any, availableStores: [] as any, @@ -244,7 +250,7 @@ export default defineComponent({ updatedAddress: {} as any, selectedItemsByFacility: {} as any, isOrderUpdated: false, - cancelledItems: [] as any + outOfStockItems: [] as any } }, computed: { @@ -255,7 +261,7 @@ export default defineComponent({ }, props: ["token"], async mounted() { - if (Object.keys(this.$route.query).length > 0) { + if(Object.keys(this.$route.query).length > 0) { if(!this.$route.query.oms || !this.token) { // invalid request return; @@ -273,25 +279,26 @@ export default defineComponent({ this.store.dispatch("user/setUserInstanceUrl", `${this.$route.query.oms}/api/`) await this.getOrder(); this.fetchOrderFacilityChangeHistory() - this.customerAddress = this.order.shipGroup[0].shipTo?.postalAddress ? this.order.shipGroup[0].shipTo.postalAddress : {} - await this.getPickupStores(); - if(!this.nearbyStores.length) { - this.selectedSegment = "separate"; - this.checkForOutOfStockItems(this.order.shipGroup[0]) - } + if(Object.keys(this.order.shipGroup).length){ + this.customerAddress = this.order.shipGroup.shipTo?.postalAddress ? this.order.shipGroup.shipTo.postalAddress : {} + await this.getPickupStores(); + if(!this.nearbyStores.length) { + this.selectedSegment = "separate"; + this.checkForOutOfStockItems(this.order.shipGroup) + } + } } }, methods: { async presentLoader() { - this.loader = await loadingController - .create({ - message: translate("Fetching order details."), - translucent: true, - }); + this.loader = await loadingController.create({ + message: translate("Fetching order details."), + translucent: true, + }); await this.loader.present(); }, dismissLoader() { - if (this.loader) { + if(this.loader) { this.loader.dismiss(); this.loader = null; } @@ -308,25 +315,26 @@ export default defineComponent({ resp = await OrderService.getOrder({ token: this.token }); - if (!hasError(resp) && resp.data.id) { + + if(!hasError(resp) && resp.data.id) { order = resp.data; const productIds: any = new Set(); - order.shipGroup = order.shipGroup.filter((group: any) => { - if(group.facilityId === 'PICKUP_REJECTED') { + const shipGroup = order.shipGroup.find((group: any) => { + if(group.facilityId === 'PICKUP_REJECTED' && group.shipmentMethodTypeId === "STOREPICKUP") { group.selectedShipmentMethodTypeId = group.shipmentMethodTypeId; group.items = group.items.filter((item: any) => { - if (item.status == 'ITEM_CANCELLED') return false; + if(item.status == 'ITEM_CANCELLED') return false; productIds.add(item.productId); return true; }) return group.items.length > 0; } }) - if (productIds.length) await this.fetchProducts([...productIds]) + order.shipGroup = shipGroup ? shipGroup : {} + if(productIds.length) await this.fetchProducts([...productIds]) await this.store.dispatch("user/getConfiguration", { productStoreId: order.productStoreId, token: this.token}); - console.log('updated', order); this.order = order; - if (productIds.size) await this.fetchProducts([...productIds]) + if(productIds.size) await this.fetchProducts([...productIds]) } } catch (error) { console.error(error) @@ -335,51 +343,59 @@ export default defineComponent({ }, async fetchOrderFacilityChangeHistory() { + let originFacilityName = "", resp; + try { - const resp = await OrderService.fetchOrderFacilityChangeHistory({ - entityName: "OrderFacilityChange", - inputFields: { - orderId: this.order.id, - orderItemSeqId: this.order.shipGroup[0].items[0].itemSeqId, - facilityId: "UNFILLABLE_PARKING", - facilityId_op: "notEqual" - }, - viewSize: 2, - orderBy: "changeDatetime ASC" - }) - if(!hasError(resp)) { - this.originFacilityId = resp.data.docs[0]?.facilityId + resp = await OrderService.getRerouteOrderBrokeringHistory({ "token": this.token }) + + if(!hasError(resp) && resp.data?.brokeringHistory.length) { + const oldestBrokeringHistory = resp.data.brokeringHistory.reduce((oldest: any, current: any) => { + return current.changeDatetime < oldest.changeDatetime ? current : oldest; + }); + + resp = await FacilityService.getStores({ + "viewSize": process.env.VUE_APP_VIEW_SIZE, + "filters": [`storeCode: ${oldestBrokeringHistory.facilityId}`] + }) + + if(!hasError(resp) && resp.data.response.numFound) { + originFacilityName = resp.data?.response.docs[0].storeName + } else { + throw resp.data; + } } else { throw resp.data; } } catch(error: any) { console.error(error); } + + this.originFacilityName = originFacilityName }, async getPickupStores() { try { - let stores; - let point = "" + let stores, point = ""; + if(this.customerAddress?.latitude) { point = `${this.customerAddress.latitude},${this.customerAddress.longitude}` } - stores = await this.getStores(point ? point : '') + stores = await this.getStores(point ? point : "") this.availableStores = stores; - if (!stores?.length) return; + if(!stores?.length) return; const facilityIds = stores.map((store: any) => store.storeCode) - const productIds = [...new Set(this.order.shipGroup[0].items.map((item: any) => item.productId))] as any; + const productIds = [...new Set(this.order.shipGroup.items.map((item: any) => item.productId))] as any; const storesWithInventory = await this.checkInventory(facilityIds, productIds) this.storesWithInventory = storesWithInventory - if (!storesWithInventory?.length) return; + if(!storesWithInventory?.length) return; stores.map((storeData: any) => { const inventoryDetails = storesWithInventory.filter((store: any) => store.facilityId === storeData.storeCode); - if (inventoryDetails.length === productIds.length) this.nearbyStores.push({...storeData, ...inventoryDetails[0], distance: storeData.dist }); + if(inventoryDetails.length === productIds.length) this.nearbyStores.push({...storeData, ...inventoryDetails[0], distance: storeData.dist }); }); } catch (error) { console.error(error) @@ -388,7 +404,7 @@ export default defineComponent({ async fetchProducts(productIds: any) { const productIdFilter = productIds.reduce((filter: string, productId: any) => { - if (filter !== '') filter += ' OR ' + if(filter !== '') filter += ' OR ' return filter += productId; }, ''); @@ -398,7 +414,7 @@ export default defineComponent({ "viewSize": productIds.length }) - if (resp.status === 200 && !hasError(resp) && resp.data) { + if(resp.status === 200 && !hasError(resp) && resp.data) { resp.data.response.docs.forEach((product: any) => { this.products[product.productId] = product }); @@ -413,40 +429,28 @@ export default defineComponent({ if(shipGroup.selectedShipmentMethodTypeId === "STOREPICKUP") { this.selectedFacility = {} this.selectedItemsByFacility = {} - this.order.shipGroup[0].items.map((item: any) => { + this.order.shipGroup.items.map((item: any) => { item.selectedFacilityId = "" }) } }, - getStoreName(facilityId: any) { - return this.nearbyStores.find((store: any) => store.storeCode === facilityId)?.storeName - }, - getProduct(productId: string) { return this.products[productId] ? this.products[productId] : {} }, updateDeliveryMethod(event: any, shipGroup: any) { - const group = this.order.shipGroup.find((group: any) => group.shipGroupSeqId === shipGroup.shipGroupSeqId); - group.selectedShipmentMethodTypeId = event.detail.value; + shipGroup.selectedShipmentMethodTypeId = event.detail.value; if(event.detail.value === "STOREPICKUP") this.updatedAddress = {}; }, - revertCancellation(item: any) { - item.isItemCancelled = false; - if(!item.isOutOfStock) { - this.cancelledItems = this.cancelledItems.filter((currentItem: any) => currentItem.itemSeqId !== item.itemSeqId) - } - }, - checkForOutOfStockItems(shipGroup: any) { shipGroup.items.map((item: any) => { const isInventoryAvailable = this.storesWithInventory.some((store: any) => store.productId === item.productId && Number(store.atp) > 0) if(!isInventoryAvailable) { item.isOutOfStock = true; - this.cancelledItems.push(item); + this.outOfStockItems.push(item); } }) }, @@ -466,12 +470,11 @@ export default defineComponent({ }) modal.onDidDismiss().then((result) => { - const selectedFacilityId = result.data.selectedFacilityId; + const selectedFacilityId = result.data?.selectedFacilityId; - if (selectedFacilityId) { + if(selectedFacilityId) { if(selectedFacilityId === "cancel") { - item.isItemCancelled = true; - this.cancelledItems.push(item); + item.isItemCancelled = true; } else { if(isPickupForAll) { this.selectedFacility = this.nearbyStores.find((store: any) => store.facilityId === selectedFacilityId); @@ -487,16 +490,12 @@ export default defineComponent({ return modal.present(); }, - async cancelShipGroup(shipGroup: any, cancelAllOrderItem: boolean) { + async cancelShipGroup(shipGroup: any, cancelledItems: any) { let resp const itemReasonMap = {} as any - if(cancelAllOrderItem) { + if(!cancelledItems.length) { shipGroup.items.map((item: any) => itemReasonMap[item.itemSeqId] = 'OICR_CHANGE_MIND') - } else { - shipGroup.items.map((item: any) => { - if(item.isItemCancelled) itemReasonMap[item.itemSeqId] = 'OICR_CHANGE_MIND' - }) } const payload = { @@ -506,19 +505,32 @@ export default defineComponent({ "token": this.token } as any + console.log(cancelledItems); + console.log(cancelledItems.length); + try { - resp = await OrderService.cancelOrderItem(payload); - if (resp.status === 200 && !hasError(resp) && resp.data.orderId == this.order.id) { - shipGroup.isCancelled = true; - showToast(translate("Order cancelled successfully")) + if(!cancelledItems.length) { + resp = await OrderService.cancelOrderItem(payload); + if(resp.status === 200 && !hasError(resp) && resp.data.orderId == this.order.id) { + return true; + } else { + throw resp.data; + } } else { - showToast(translate("Failed to cancel the order")) + const responses = await Promise.allSettled(cancelledItems.map(async(item: any) => await OrderService.cancelOrderItem({ + "orderId": this.order.id, + "shipGroupSeqId": shipGroup.shipGroupSeqId, + "orderItemSeqId": item.itemSeqId, + "token": this.token + }))) + + const hasFailedResponse = responses.some((response: any) => response.status === 'rejected') + return !hasFailedResponse } } catch (error) { console.error(error) - showToast(translate("Failed~ to cancel the order")) } - this.getOrder(); + return false; }, async cancelOrder(shipGroup: any) { @@ -532,8 +544,9 @@ export default defineComponent({ }, { text: translate("Cancel"), - handler: () => { - this.cancelShipGroup(shipGroup, true); + handler: async () => { + const isCancelled = await this.cancelShipGroup(shipGroup, []); + showToast(translate(isCancelled ? "Order cancelled successfully." : "Failed to cancel the order.")) } } ], @@ -552,7 +565,7 @@ export default defineComponent({ }) modal.onDidDismiss().then((result) => { - if (result.data.updatedAddress) { + if(result.data?.updatedAddress) { this.updatedAddress = result.data.updatedAddress } }); @@ -581,38 +594,78 @@ export default defineComponent({ }, async saveOrder(shipGroup: any) { + const isStorePickupSelected = (shipGroup.selectedShipmentMethodTypeId === "STOREPICKUP"); + let isUpdated = false, hasFailure = false; + if(this.selectedSegment === "together") { - if(shipGroup.selectedShipmentMethodTypeId === "STOREPICKUP") { - await this.updatePickupFacility(shipGroup); + if(isStorePickupSelected) { + isUpdated = await this.updatePickupFacility(shipGroup) + showToast(translate(isUpdated ? "Pickup facility updated successfully." : "Failed to update the pickup store.")) } else { - await this.updateShippingAddress(shipGroup); + isUpdated = await this.updateShippingAddress(shipGroup) + + if(isUpdated) { + const isUpdated = await this.brokerOrderItem(shipGroup.items, true); + if(!isUpdated) hasFailure = true; + } else { + hasFailure = true; + } + + showToast(translate(hasFailure ? "Failed to update the shipping addess." : "Shipping address updated successfully.")) } } else { - await this.cancelShipGroup(shipGroup, false); - + const itemsForCancellation = shipGroup.items.filter((item: any) => item.isItemCancelled); const itemsWithFacility = shipGroup.items.filter((item: any) => item.selectedFacilityId) - const responses = await Promise.allSettled(itemsWithFacility.map(async(item: any) => await OrderService.releaseOrderItem({ - orderId: this.order.id, - orderItemSeqId: item.itemSeqId, - fromFacilityId: this.order.facilityId, - changeReasonEnumId: "BROKERED", - toFacilityId: item.selectedFacilityId - }))) - - if(shipGroup.selectedShipmentMethodTypeId !== "STOREPICKUP" && this.updatedAddress.address1) { - const facilitiesForShipping = shipGroup.items.filter((item: any) => !(item.selectedFacilityId || item.isOutOfStock)); + const itemsForShipping = shipGroup.items.filter((item: any) => !(item.isItemCancelled || item.selectedFacilityId)) + console.log(itemsForCancellation); + console.log(itemsWithFacility); + console.log(itemsForShipping); + + + if(itemsForCancellation.length) { + isUpdated = await this.cancelShipGroup(shipGroup, itemsForCancellation) + if(!isUpdated) hasFailure = true; } - const hasFailedResponse = responses.some((response: any) => response.status === 'rejected') - if(hasFailedResponse) { - showToast(translate("Failed to reroute some items.")) - } else { - showToast(translate("Order items re-routed successfully.")) - } + if(itemsWithFacility.length) { + isUpdated = await this.brokerOrderItem(itemsWithFacility, false) + if(!isUpdated) hasFailure = true; + } + + if(shipGroup.selectedShipmentMethodTypeId !== "STOREPICKUP" && this.updatedAddress.address1 && itemsForShipping.length) { + if(await this.updateShippingAddress(shipGroup)) { + isUpdated = await this.brokerOrderItem(itemsForShipping, true); + if(!isUpdated) hasFailure = true; + } else { + hasFailure = true; + } + } + + showToast(translate(hasFailure ? "Failed to re-route some order items." : "Order items re-routed successfully.")) } this.getOrder(); }, + async brokerOrderItem(items: any, isShippingOrder: boolean) { + const responses = await Promise.allSettled(items.map(async(item: any) => await OrderService.releaseRerouteOrderItem({ + orderId: this.order.id, + orderItemSeqId: item.itemSeqId, + fromFacilityId: this.order.facilityId, + toFacilityId: isShippingOrder ? "_NA_" : item.selectedFacilityId, + token: this.token + }))) + const hasFailedResponse = responses.some((response: any) => response.status === 'rejected') + return !hasFailedResponse + }, + + isOrderItemsEligibleForUpdation(shipGroup: any) { + if(this.selectedSegment === "together") { + return shipGroup.selectedShipmentMethodTypeId === "STOREPICKUP" ? this.selectedFacility.facilityId : this.updatedAddress.address1 + } else { + return shipGroup.selectedShipmentMethodTypeId === "STOREPICKUP" ? !shipGroup.items.some((item: any) => !(item.selectedFacilityId || item.isItemCancelled)) : this.updatedAddress.address1 + } + }, + async updatePickupFacility(shipGroup: any) { let resp const payload = { @@ -627,29 +680,28 @@ export default defineComponent({ try { resp = await OrderService.updatePickupFacility(payload); - if (resp.status === 200 && !hasError(resp)) { + if(resp.status === 200 && !hasError(resp)) { shipGroup.facilityId = this.selectedFacility.facilityId - showToast(translate("Changes saved")) this.isOrderUpdated = true + return true; } else { - showToast(translate("Failed to update the pickup store")) + throw resp.data; } } catch(error) { console.error(error) - showToast(translate("Failed to update the pickup store")) } + return false; }, async updateShippingAddress(shipGroup: any) { let resp - console.log(this.updatedAddress); const payload = { "orderId": this.order.id, "shipGroupSeqId": shipGroup.shipGroupSeqId, "shipmentMethod": `${this.deliveryMethod}@_NA_`, "contactMechPurposeTypeId": "SHIPPING_LOCATION", - "facilityId": shipGroup.facilityId, + "facilityId": "_NA_", "toName": `${this.updatedAddress.firstName} ${this.updatedAddress.lastName}`, "address1": this.updatedAddress.address1, "city": this.updatedAddress.city, @@ -663,16 +715,16 @@ export default defineComponent({ resp = await OrderService.updateShippingAddress(payload); if(!hasError(resp)) { shipGroup.shipTo.postalAddress = this.updatedAddress - this.updatedAddress = null - showToast(translate("Changes saved")) + this.updatedAddress = {} this.isOrderUpdated = true + return true; } else { - showToast(translate("Failed to update the shipping addess")) + throw resp.data; } } catch (error) { console.error(error) - showToast(translate("Failed to update the shipping addess")) } + return false; }, async checkInventory(facilityIds: Array, productIds: Array) { @@ -720,7 +772,7 @@ export default defineComponent({ try { const storeLookupResp = await FacilityService.getStores(payload) - if (storeLookupResp.status !== 200 || hasError(storeLookupResp) || !storeLookupResp.data.response.numFound) { + if(storeLookupResp.status !== 200 || hasError(storeLookupResp) || !storeLookupResp.data.response.numFound) { return []; } return storeLookupResp.data.response.docs @@ -731,7 +783,7 @@ export default defineComponent({ removeItemFromFacility(item: any, facilityId: any) { this.selectedItemsByFacility[facilityId] = this.selectedItemsByFacility[facilityId].filter((currentItem: any) => currentItem.itemSeqId !== item.itemSeqId); - console.log(this.selectedItemsByFacility); + item.selectedFacilityId = ""; } }, setup() { diff --git a/src/views/PickupLocationModal.vue b/src/views/PickupLocationModal.vue index dc6ecd9b..c5db19b5 100644 --- a/src/views/PickupLocationModal.vue +++ b/src/views/PickupLocationModal.vue @@ -28,7 +28,7 @@ - + {{ translate("Request cancelation") }} From 4bda099fb8aaa66f0383255aaed0687d14dbe47b Mon Sep 17 00:00:00 2001 From: amansinghbais Date: Fri, 27 Sep 2024 11:50:11 +0530 Subject: [PATCH 05/16] Improved: reverted unused code, check in case order split not allowed (#92) --- src/services/OrderService.ts | 6 +----- src/views/Order.vue | 5 +++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/services/OrderService.ts b/src/services/OrderService.ts index 27e89d6d..d0d577c0 100644 --- a/src/services/OrderService.ts +++ b/src/services/OrderService.ts @@ -1,10 +1,6 @@ -import { api, client } from '@/adapter'; -import store from '@/store'; -import { hasError } from '@hotwax/oms-api'; +import { api } from '@/adapter'; const getOrder = async (payload: any): Promise => { - let baseURL = store.getters['user/getInstanceUrl']; - baseURL = baseURL && baseURL.startsWith('http') ? baseURL : `https://${baseURL}.hotwax.io/api/`; return api({ url: "getRerouteOrder", method: "post", diff --git a/src/views/Order.vue b/src/views/Order.vue index 81734ad8..31594135 100644 --- a/src/views/Order.vue +++ b/src/views/Order.vue @@ -27,8 +27,8 @@ -