diff --git a/src/components/AddLocationModal.vue b/src/components/AddLocationModal.vue index 0993a396..e08e8b54 100644 --- a/src/components/AddLocationModal.vue +++ b/src/components/AddLocationModal.vue @@ -13,35 +13,34 @@ {{ translate("Type") }} - - {{ "pick/primary" }} - {{ "bulk" }} + + {{ description }} {{ translate("Area") }} * - + {{ translate("Aisle") }} * - + {{ translate("Section") }} * - + {{ translate("Level") }} * - + {{ translate("Sequence") }} - + - + @@ -69,6 +68,11 @@ import { import { defineComponent } from "vue"; import { closeOutline, saveOutline } from "ionicons/icons"; import { translate } from '@hotwax/dxp-components' +import { FacilityService } from "@/services/FacilityService"; +import { mapGetters } from 'vuex' +import { hasError } from "@/adapter"; +import { showToast } from "@/utils"; +import logger from "@/logger"; export default defineComponent({ name: "AddLocationModal", @@ -89,11 +93,80 @@ export default defineComponent({ IonTitle, IonToolbar }, - methods: { - closeModal() { - modalController.dismiss() + props: ["location"], + data() { + return { + locationInfo: {} as any } }, + mounted() { + this.locationInfo = this.location ? JSON.parse(JSON.stringify(this.location)) : {} + }, + computed: { + ...mapGetters({ + current: 'facility/getCurrent', + locationTypes: 'util/getLocationTypes' + }) + }, + methods: { + closeModal(result?: string) { + modalController.dismiss({ result }); + }, + saveFacilityLocation() { + if(!this.locationInfo.aisleId?.trim() || !this.locationInfo.areaId?.trim() || !this.locationInfo.positionId?.trim() || !this.locationInfo.sectionId?.trim() || !this.locationInfo.levelId?.trim()) { + showToast(translate('Please fill all the required fields')) + return; + } + + // checking for locationSeqId as when adding new facility we won't be having locationSeqId + if(this.location.locationSeqId) { + this.updateFacilityLocation() + } else { + this.addFacilityLocation() + } + }, + async addFacilityLocation() { + const params = { + facilityId: this.current.facilityId, + ...this.locationInfo + } + + try { + const resp = await FacilityService.createFacilityLocation(params) + + if(!hasError(resp)) { + showToast(translate('Facility location created successfully')) + this.closeModal('success'); + } else { + throw resp.data + } + } catch(err) { + showToast(translate('Failed to create facility location')) + logger.error('Failed to create facility location', err) + } + }, + + async updateFacilityLocation() { + const params = { + facilityId: this.current.facilityId, + ...this.locationInfo + } + + try { + const resp = await FacilityService.updateFacilityLocation(params) + + if(!hasError(resp)) { + showToast(translate('Facility location updated successfully')) + this.closeModal('success'); + } else { + throw resp.data + } + } catch(err) { + showToast(translate('Failed to update facility location')) + logger.error('Failed to update facility location', err) + } + }, + }, setup() { return { closeOutline, diff --git a/src/components/LocationDetailsPopover.vue b/src/components/LocationDetailsPopover.vue index 82c079f9..2a05110c 100644 --- a/src/components/LocationDetailsPopover.vue +++ b/src/components/LocationDetailsPopover.vue @@ -5,7 +5,7 @@ {{ translate("Edit location") }} - + {{ translate("Remove location") }} @@ -18,11 +18,17 @@ import { IonItem, IonList, IonListHeader, - modalController + modalController, +popoverController } from "@ionic/vue"; import { defineComponent } from "vue"; import { translate } from "@hotwax/dxp-components"; import AddLocationModal from "./AddLocationModal.vue"; +import { mapGetters, useStore } from "vuex"; +import { FacilityService } from "@/services/FacilityService"; +import { hasError } from "@/adapter"; +import { showToast } from "@/utils"; +import logger from "@/logger"; export default defineComponent({ name: "LocationDetailsPopover", @@ -32,17 +38,53 @@ export default defineComponent({ IonList, IonListHeader }, + computed: { + ...mapGetters({ + current: 'facility/getCurrent' + }) + }, + props: ["location"], methods: { async addLocationModal() { const addLocationModal = await modalController.create({ - component: AddLocationModal + component: AddLocationModal, + componentProps: { location: this.location } }) addLocationModal.present() + + addLocationModal.onDidDismiss().then((result: any) => { + if(result.data?.result) { + popoverController.dismiss(); + } + }) + }, + async removeLocation() { + const params = { + facilityId: this.location.facilityId, + locationSeqId: this.location.locationSeqId + } + + try { + const resp = await FacilityService.deleteFacilityLocation(params) + + if(!hasError(resp)) { + this.store.dispatch('facility/fetchFacilityLocation') + popoverController.dismiss(); + } else { + throw resp.data + } + } catch(err) { + showToast(translate('Failed to remove facility location')) + logger.error('Failed to remove facility location', err) + } } }, setup() { + const store = useStore(); + return { + store, translate }; } diff --git a/src/locales/en.json b/src/locales/en.json index 41070341..824f3c78 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -7,14 +7,14 @@ "Address": "Address", "Address line 1": "Address line 1", "Address line 2": "Address line 2", - "aisle": "aisle", "Aisle": "Aisle", + "aisle": "aisle", "All": "All", "Allow pickup": "Allow pickup", "App": "App", "Apply": "Apply", - "area": "area", "Area": "Area", + "area": "area", "Back to Launchpad": "Back to Launchpad", "Built: ": "Built: { builtDateTime }", "Cancel": "Cancel", @@ -40,9 +40,15 @@ "Facility": "Facility", "Facility details": "Facility details", "Facility ID": "Facility ID", + "Facility location created successfully": "Facility location created successfully", + "Facility location updated successfully": "Facility location updated successfully", "Facility name": "Facility name", "Facility Management": "Facility Management", + "Failed to create facility location": "Failed to create facility location", "Failed to fetch facility information": "Failed to fetch facility information", + "Failed to find the facility locations": "Failed to find the facility locations", + "Failed to remove facility location": "Failed to remove facility location", + "Failed to update facility location": "Failed to update facility location", "Fetching TimeZones": "Fetching TimeZones", "Find Facilities": "Find Facilities", "Friday": "Friday", @@ -59,8 +65,8 @@ "Language": "Language", "Latitude": "Latitude", "Latitude & Longitude": "Latitude & Longitude", - "level": "level", "Level": "Level", + "level": "level", "Loading": "Loading", "Location": "Location", "Location details": "Location details", @@ -92,10 +98,11 @@ "orders allocated today": "{orderCount} orders allocated today", "orders in fulfillment queue": "{orderCount} orders in fulfillment queue", "Parking": "Parking", - "party id": "party id", "Party Id": "Party Id", + "party id": "party id", "Password": "Password", "Please contact the administrator.": "Please contact the administrator.", + "Please fill all the required fields": "Please fill all the required fields", "primary store": "primary store", "Product Store": "Product Store", "Product Stores": "Product Stores", @@ -103,12 +110,12 @@ "Reset": "Reset", "Remove": "Remove", "Remove location": "Remove location", - "role": "role", "Role": "Role", + "role": "role", "Saturday": "Saturday", "Save": "Save", - "section": "section", "Section": "Section", + "section": "section", "Select": "Select", "Search facilities": "Search facilities", "Search time zones": "Search time zones", @@ -120,8 +127,8 @@ "Select your preferred language.": "Select your preferred language.", "Sell Online": "Sell Online", "Sell Inventory Online": "Sell Inventory Online", - "sequence": "sequence", "Sequence": "Sequence", + "sequence": "sequence", "Settings": "Settings", "Setting fulfillment capacity to 0 disables new order from being allocated to this facility. Leave this empty if this facility's fulfillment capacity is unrestricted.": "Setting fulfillment capacity to 0 disables new order from being allocated to this facility. Leave this empty if this facility's fulfillment capacity is unrestricted.", "Shopify": "Shopify", @@ -132,8 +139,8 @@ "Specify which facility you want to operate from. Order, inventory and other configuration data will be specific to the facility you select.": "Specify which facility you want to operate from. Order, inventory and other configuration data will be specific to the facility you select.", "Staff": "Staff", "State": "State", - "Store": "Store", "store name": "store name", + "Store": "Store", "Sunday": "Sunday", "The timezone you select is used to ensure automations you schedule are always accurate to the time you select.": "The timezone you select is used to ensure automations you schedule are always accurate to the time you select.", "These values are used to help customers lookup how close they are to your stores when they are finding nearby stores.": "These values are used to help customers lookup how close they are to your stores when they are finding nearby stores.", diff --git a/src/services/FacilityService.ts b/src/services/FacilityService.ts index 368f177a..d2bde0d1 100644 --- a/src/services/FacilityService.ts +++ b/src/services/FacilityService.ts @@ -134,6 +134,14 @@ const updateFacility = async (payload: any): Promise => { }) } +const fetchFacilityLocations = async(payload: any): Promise => { + return api({ + url: "performFind", + method: "post", + data: payload + }) +} + const addFacilityToGroup = async (payload: any): Promise => { return api({ url: "service/addFacilityToGroup", @@ -142,6 +150,30 @@ const addFacilityToGroup = async (payload: any): Promise => { }) } +const createFacilityLocation = async(payload: any): Promise => { + return api({ + url: "service/createFacilityLocation", + method: "post", + data: payload + }) +} + +const updateFacilityLocation = async(payload: any): Promise => { + return api({ + url: "service/updateFacilityLocation", + method: "post", + data: payload + }) +} + +const deleteFacilityLocation = async(payload: any): Promise => { + return api({ + url: "service/deleteFacilityLocation", + method: "post", + data: payload + }) +} + const updateFacilityToGroup = async (payload: any): Promise => { return api({ url: "service/updateFacilityToGroup", @@ -151,11 +183,15 @@ const updateFacilityToGroup = async (payload: any): Promise => { } export const FacilityService = { + createFacilityLocation, + deleteFacilityLocation, + fetchFacilityLocations, addFacilityToGroup, fetchFacilityGroupInformation, fetchFacilityOrderCounts, fetchFacilitiesOrderCount, fetchFacilities, updateFacility, + updateFacilityLocation, updateFacilityToGroup } \ No newline at end of file diff --git a/src/services/UtilService.ts b/src/services/UtilService.ts index 85365974..67c53bc1 100644 --- a/src/services/UtilService.ts +++ b/src/services/UtilService.ts @@ -18,8 +18,18 @@ const fetchProductStores = async (payload: any): Promise => { }) } +const fetchLocationTypes = async (payload: any): Promise => { + return api({ + url: "performFind", + method: "POST", + data: payload, + cache: true + }) +} + export const UtilService = { fetchFacilityTypes, + fetchLocationTypes, fetchProductStores } diff --git a/src/store/modules/facility/FacilityState.ts b/src/store/modules/facility/FacilityState.ts index 2b9f8839..89006344 100644 --- a/src/store/modules/facility/FacilityState.ts +++ b/src/store/modules/facility/FacilityState.ts @@ -4,7 +4,6 @@ export default interface FacilityState { productStoreId: string, facilityTypeId: string }; - selectedFacility: object; facilities: { list: Array, total: number diff --git a/src/store/modules/facility/actions.ts b/src/store/modules/facility/actions.ts index c543654b..60de955b 100644 --- a/src/store/modules/facility/actions.ts +++ b/src/store/modules/facility/actions.ts @@ -169,6 +169,30 @@ const actions: ActionTree = { facilityTypeId: '' }) commit(types.FACILITY_LIST_UPDATED , { facilities: [], total: 0 }); + commit(types.FACILITY_CURRENT_UPDATED, {}); + }, + + async fetchFacilityLocations({ commit }, payload) { + try { + const params = { + inputFields: { + facilityId: payload.facilityId + }, + entityName: "FacilityLocation", + fieldList: ["facilityId", "locationSeqId", "locationTypeEnumId", "areaId", "aisleId", "sectionId", "levelId", "positionId"], + viewSize: 100 + } + + const resp = await FacilityService.fetchFacilityLocations(params) + + if(!hasError(resp) && resp.data.count > 0) { + commit(types.FACILITY_CURRENT_LOCATION_UPDATED, resp.data.docs) + } else { + throw resp.data + } + } catch(err) { + logger.error('Failed to find the facility locations', err) + } } } diff --git a/src/store/modules/facility/index.ts b/src/store/modules/facility/index.ts index bc563c53..5d4a24e0 100644 --- a/src/store/modules/facility/index.ts +++ b/src/store/modules/facility/index.ts @@ -13,7 +13,6 @@ const facilityModule: Module = { productStoreId: '', facilityTypeId: '' }, - selectedFacility: {}, facilities: { list: [], total: 0 diff --git a/src/store/modules/facility/mutation-types.ts b/src/store/modules/facility/mutation-types.ts index 4676bdb0..45007698 100644 --- a/src/store/modules/facility/mutation-types.ts +++ b/src/store/modules/facility/mutation-types.ts @@ -1,4 +1,5 @@ export const SN_FACILITY = 'facility' export const FACILITY_LIST_UPDATED = SN_FACILITY + '/LIST_UPDATED' export const FACILITY_QUERY_UPDATED = SN_FACILITY + '/QUERY_UPDATED' -export const FACILITY_CURRENT_UPDATED = SN_FACILITY + '/CURRENT_UPDATED' \ No newline at end of file +export const FACILITY_CURRENT_UPDATED = SN_FACILITY + '/CURRENT_UPDATED' +export const FACILITY_CURRENT_LOCATION_UPDATED = SN_FACILITY + '/CURRENT_LOCATION_UPDATED' \ No newline at end of file diff --git a/src/store/modules/facility/mutations.ts b/src/store/modules/facility/mutations.ts index fab0e52c..c6e11f6b 100644 --- a/src/store/modules/facility/mutations.ts +++ b/src/store/modules/facility/mutations.ts @@ -12,6 +12,9 @@ const mutations: MutationTree = { }, [types.FACILITY_CURRENT_UPDATED](state, payload) { state.current = payload + }, + [types.FACILITY_CURRENT_LOCATION_UPDATED](state, payload) { + state.current.locations = payload } } export default mutations; \ No newline at end of file diff --git a/src/store/modules/util/UtilState.ts b/src/store/modules/util/UtilState.ts index d6f63851..63ded06e 100644 --- a/src/store/modules/util/UtilState.ts +++ b/src/store/modules/util/UtilState.ts @@ -1,4 +1,5 @@ export default interface UtilState { productStores: any[]; facilityTypes: object; + locationTypes: object; } \ No newline at end of file diff --git a/src/store/modules/util/actions.ts b/src/store/modules/util/actions.ts index 5375800b..158c7581 100644 --- a/src/store/modules/util/actions.ts +++ b/src/store/modules/util/actions.ts @@ -62,6 +62,43 @@ const actions: ActionTree = { commit(types.UTIL_FACILITY_TYPES_UPDATED, facilityTypes) }, + async fetchLocationTypes({ commit, state }) { + const cachedLocationTypes = JSON.parse(JSON.stringify(state.locationTypes)) + + // not fetching location type information again if already present, as it will not be changed so frequently + if(cachedLocationTypes.length) { + return; + } + + let locationTypes = [] + const params = { + inputFields: { + enumTypeId: 'FACLOC_TYPE' + }, + viewSize: 100, + noConditionFind: 'Y', + entityName: 'Enumeration', + fieldList: ['enumId', 'description'] + } as any + + try { + const resp = await UtilService.fetchLocationTypes(params) + if (!hasError(resp)) { + locationTypes = resp.data.docs.reduce((locationType: any, type: any) => { + locationType[type.enumId] = type.description + + return locationType + }, {}) + } else { + throw resp.data + } + } catch (error) { + logger.error(error) + } + + commit(types.UTIL_LOCATION_TYPES_UPDATED, locationTypes) + }, + clearUtilState({ commit }) { commit(types.UTIL_PRODUCT_STORES_UPDATED, []) commit(types.UTIL_FACILITY_TYPES_UPDATED, []) diff --git a/src/store/modules/util/getters.ts b/src/store/modules/util/getters.ts index 0b2f9c6d..73b01c5f 100644 --- a/src/store/modules/util/getters.ts +++ b/src/store/modules/util/getters.ts @@ -8,6 +8,9 @@ const getters: GetterTree = { }, getFacilityTypes(state) { return state.facilityTypes + }, + getLocationTypes(state) { + return state.locationTypes } } export default getters; \ No newline at end of file diff --git a/src/store/modules/util/index.ts b/src/store/modules/util/index.ts index 5470f963..b152ff86 100644 --- a/src/store/modules/util/index.ts +++ b/src/store/modules/util/index.ts @@ -9,7 +9,8 @@ const utilModule: Module = { namespaced: true, state: { productStores: [], - facilityTypes: {} + facilityTypes: {}, + locationTypes: {} }, getters, actions, diff --git a/src/store/modules/util/mutation-types.ts b/src/store/modules/util/mutation-types.ts index 0901fa26..f5a7f1b6 100644 --- a/src/store/modules/util/mutation-types.ts +++ b/src/store/modules/util/mutation-types.ts @@ -1,3 +1,4 @@ export const SN_UTIL = 'util' export const UTIL_PRODUCT_STORES_UPDATED = SN_UTIL + '/PRODUCT_STORES_UPDATED' -export const UTIL_FACILITY_TYPES_UPDATED = SN_UTIL + '/FACILITY_TYPES_UPDATED' \ No newline at end of file +export const UTIL_FACILITY_TYPES_UPDATED = SN_UTIL + '/FACILITY_TYPES_UPDATED' +export const UTIL_LOCATION_TYPES_UPDATED = SN_UTIL + '/LOCATION_TYPES_UPDATED' \ No newline at end of file diff --git a/src/store/modules/util/mutations.ts b/src/store/modules/util/mutations.ts index 5d84d496..10531900 100644 --- a/src/store/modules/util/mutations.ts +++ b/src/store/modules/util/mutations.ts @@ -8,6 +8,9 @@ const mutations: MutationTree = { }, [types.UTIL_FACILITY_TYPES_UPDATED](state, payload) { state.facilityTypes = payload + }, + [types.UTIL_LOCATION_TYPES_UPDATED](state, payload) { + state.locationTypes = payload } } export default mutations; \ No newline at end of file diff --git a/src/views/FacilityDetails.vue b/src/views/FacilityDetails.vue index 21377cea..6e402450 100644 --- a/src/views/FacilityDetails.vue +++ b/src/views/FacilityDetails.vue @@ -325,41 +325,41 @@ {{ translate("Add locations to facility") }} -
+
- {{ "locations id" }} -

{{ "pick/primary" }}

+ {{ location.locationSeqId }} +

{{ locationTypes[location.locationTypeEnumId] }}

- AI + {{ location.areaId }}

{{ translate("area") }}

- AL + {{ location.aisleId }}

{{ translate("aisle") }}

- SI + {{ location.sectionId }}

{{ translate("section") }}

- SI + {{ location.levelId }}

{{ translate("level") }}

- 1 + {{ location.positionId }}

{{ translate("sequence") }}

- +
@@ -472,12 +472,14 @@ export default defineComponent({ }, computed: { ...mapGetters({ - current: 'facility/getCurrent' + current: 'facility/getCurrent', + locationTypes: 'util/getLocationTypes' }) }, props: ["facilityId"], async ionViewWillEnter() { await this.store.dispatch('facility/fetchCurrentFacility', { facilityId: this.facilityId }) + await Promise.all([this.store.dispatch('facility/fetchFacilityLocations', { facilityId: this.facilityId }), this.store.dispatch('util/fetchLocationTypes')]) this.defaultDaysToShip = this.current.defaultDaysToShip this.isLoading = false }, @@ -532,9 +534,10 @@ export default defineComponent({ selectOperatingTimeModal.present() }, - async openLocationDetailsPopover(ev: Event) { + async openLocationDetailsPopover(ev: Event, location: any) { const locationDetailsPopover = await popoverController.create({ component: LocationDetailsPopover, + componentProps: { location }, event: ev, showBackdrop: false });