diff --git a/.env.example b/.env.example index a69ec6838..f907afd87 100644 --- a/.env.example +++ b/.env.example @@ -10,3 +10,4 @@ VUE_APP_PERMISSION_ID= VUE_APP_LOCALES={"en": "English", "ja": "日本語", "es": "Español"} VUE_APP_ALIAS= VUE_APP_CURRENCY_FORMATS={"en": {"currency": {"style": "currency","currency": "USD"}}, "ja": {"currency": {"style": "currency", "currency": "JPY"}}, "es": {"currency": {"style": "currency","currency": "ESP"}}} +VUE_APP_RF_CNFG_MPNG={ "allowDeliveryMethodUpdate": "CUST_DLVRMTHD_UPDATE", "allowDeliveryAddressUpdate": "CUST_DLVRADR_UPDATE", "allowPickupUpdate": "CUST_PCKUP_UPDATE", "allowCancel": "CUST_ALLOW_CNCL", "shippingMethod": "RF_SHIPPING_METHOD"} \ No newline at end of file diff --git a/src/locales/en.json b/src/locales/en.json index e8aa049fa..004f15e18 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -6,7 +6,9 @@ "Assign Pickers": "Assign Pickers", "Catalog": "Catalog", "Cancel": "Cancel", + "Cancel order before fulfillment": "Cancel order before fulfillment", "canceled from the order": "canceled from the order", + "Control what your customers are allowed to edit on their order when they are editing their order on Re-route Fulfillment.": "Control what your customers are allowed to edit on their order when they are editing their order on Re-route Fulfillment.", "Change": "Change", "Choose language": "Choose language", "City": "City", @@ -14,16 +16,20 @@ "Color": "Color", "Colors": "Colors", "Completed": "Completed", + "Configuration updated": "Configuration updated", "Configure Picker": "Configure Picker", "Configuration to assign picker to orders.": "Configuration to assign picker to orders.", "Confirm": "Confirm", "Copied": "Copied { text }", "Copy": "Copy", "Depending on the reason you select for not fulfulling an item, an inventory variance will be recorded and all sales channels will be updated with new inventory levels. For example, by selecting “Not in stock” HotWax Commerce will stop routing orders for it to your store and customers will not be able to place BOPIS orders for it at your store on Shopify.": "Depending on the reason you select for not fulfulling an item, an inventory variance will be recorded and all sales channels will be updated with new inventory levels.{ space } For example, by selecting “Not in stock” HotWax Commerce will stop routing orders for it to your store and customers will not be able to place BOPIS orders for it at your store on Shopify.", + "Delivery address": "Delivery address", + "Delivery method": "Delivery method", "Dismiss": "Dismiss", "eCom Store": "eCom Store", "Facility": "Facility", "Failed to load packing slip": "Failed to load packing slip", + "Failed to update configuration": "Failed to update configuration", "First name": "First name", "Generate packing slips": "Generate packing slips", "Go to OMS": "Go to OMS", @@ -56,6 +62,7 @@ "Order": "Order", "Order delivered to": "Order delivered to { customerName }", "Order details": "Order details", + "Order edit permissions": "Order edit permissions", "Order not found": "Order not found", "Order packed and ready for delivery": "Order packed and ready for delivery", "Orders": "Orders", @@ -66,9 +73,11 @@ "Packing slips help customer reconcile their order against the delivered items.": "Packing slips help customer reconcile their order against the delivered items.", "Password": "Password", "pending approval": "pending approval", + "Pick up location": "Pick up location", "Product details": "Product details", "Product not found": "Product not found", "Products not found": "Products not found", + "Re-route Fulfillment": "Re-route Fulfillment", "Ready for pickup": "Ready for pickup", "Ready to create an app?": "Ready to create an app?", "Ready to ship": "Ready to ship", @@ -83,6 +92,7 @@ "Settings": "Settings", "Select a picker": "Select a picker", "Ship": "Ship", + "Shipment method": "Shipment method", "Shipping method": "Shipping method", "Shipping orders": "Shipping orders", "Ship to customer": "Ship to customer", diff --git a/src/services/UserService.ts b/src/services/UserService.ts index 3f1c6096b..535a85d0d 100644 --- a/src/services/UserService.ts +++ b/src/services/UserService.ts @@ -82,14 +82,32 @@ const getEComStores = async (facilityId: string): Promise => { console.error(err) } } +const getRerouteFulfillmentConfig = async (payload: any): Promise => { + return api({ + url: "performFind", + method: "get", + params: payload, + }); +} + +const updateRerouteFulfillmentConfig = async (payload: any): Promise => { + return api({ + url: "service/updateProductStoreSetting", + method: "post", + data: payload + }); +} + export const UserService = { login, getAvailableTimeZones, getProfile, + getRerouteFulfillmentConfig, setUserTimeZone, getUserPreference, setUserPreference, checkPermission, - getEComStores + getEComStores, + updateRerouteFulfillmentConfig } \ No newline at end of file diff --git a/src/store/modules/user/getters.ts b/src/store/modules/user/getters.ts index b26f98988..c642fced3 100644 --- a/src/store/modules/user/getters.ts +++ b/src/store/modules/user/getters.ts @@ -36,6 +36,9 @@ const getters: GetterTree = { }, getCurrency (state) { return state.currentEComStore.defaultCurrencyUomId ? state.currentEComStore.defaultCurrencyUomId : 'USD'; + }, + getCurrentEComStore(state) { + return state.currentEComStore; } } export default getters; \ No newline at end of file diff --git a/src/views/Settings.vue b/src/views/Settings.vue index 5984602cd..677d65267 100644 --- a/src/views/Settings.vue +++ b/src/views/Settings.vue @@ -62,6 +62,42 @@ + + + + {{ $t("Re-route Fulfillment") }} + + + {{ $t("Order edit permissions") }} + + + + {{ $t('Control what your customers are allowed to edit on their order when they are editing their order on Re-route Fulfillment.') }} + + + {{ $t("Delivery method") }} + + + + {{ $t("Delivery address") }} + + + + {{ $t("Pick up location") }} + + + + {{ $t("Cancel order before fulfillment") }} + + + + + {{ $t("Shipment method") }} + + {{ shipmentMethod.description }} + + + @@ -148,7 +184,7 @@ {{ $t("Configure Picker") }} - + @@ -165,6 +201,9 @@ import { useRouter } from 'vue-router'; import TimeZoneModal from './TimezoneModal.vue'; import Image from '@/components/Image.vue'; import { DateTime } from 'luxon'; +import { UserService } from '@/services/UserService' +import { hasError, showToast } from '@/utils'; +import { translate } from "@/i18n"; export default defineComponent({ name: 'Settings', @@ -195,12 +234,23 @@ export default defineComponent({ appInfo: (process.env.VUE_APP_VERSION_INFO ? JSON.parse(process.env.VUE_APP_VERSION_INFO) : {}) as any, appVersion: "", locales: process.env.VUE_APP_LOCALES ? JSON.parse(process.env.VUE_APP_LOCALES) : {"en": "English"}, + rerouteFulfillmentConfig: { + // TODO Remove fromDate and directly store values making it loosely coupled with OMS + allowDeliveryMethodUpdate: {}, + allowDeliveryAddressUpdate: {}, + allowPickupUpdate: {}, + allowCancel: {}, + shippingMethod: {} + } as any, + availableShipmentMethods: [] as any, + rerouteFulfillmentConfigMapping: (process.env.VUE_APP_RF_CNFG_MPNG? JSON.parse(process.env.VUE_APP_RF_CNFG_MPNG) : {}) as any } }, computed: { ...mapGetters({ userProfile: 'user/getUserProfile', currentFacility: 'user/getCurrentFacility', + currentEComStore: 'user/getCurrentEComStore', instanceUrl: 'user/getInstanceUrl', configurePicker: "user/configurePicker", showShippingOrders: 'user/showShippingOrders', @@ -211,6 +261,13 @@ export default defineComponent({ mounted() { this.appVersion = this.appInfo.branch ? (this.appInfo.branch + "-" + this.appInfo.revision) : this.appInfo.tag; }, + ionViewWillEnter() { + // Only fetch configuration when environment mapping exists + if (Object.keys(this.rerouteFulfillmentConfigMapping).length > 0) { + this.getAvailableShipmentMethods(); + this.getRerouteFulfillmentConfiguration(); + } + }, methods: { setFacility (facility: any) { if (this.userProfile) @@ -235,7 +292,7 @@ export default defineComponent({ setShowPackingSlipPreference (ev: any){ this.store.dispatch('user/setUserPreference', { showPackingSlip: ev.detail.checked }) }, - setCongigurePickerPreference (ev: any){ + setConfigurePickerPreference (ev: any){ this.store.dispatch('user/setUserPreference', { configurePicker: ev.detail.checked }) }, goToOms(){ @@ -246,6 +303,86 @@ export default defineComponent({ }, setLocale(locale: string) { this.store.dispatch('user/setLocale',locale) + }, + async getAvailableShipmentMethods () { + this.availableShipmentMethods = []; + try { + const resp = await UserService.getRerouteFulfillmentConfig({ + "inputFields": { + "productStoreId": this.currentEComStore?.productStoreId, + "shipmentMethodTypeId": "STOREPICKUP", + "shipmentMethodTypeId_op": "notEqual" + }, + "filterByDate": 'Y', + "entityName": "ProductStoreShipmentMethView", + "fieldList": ["shipmentMethodTypeId", "description"], + "viewSize": 10 + }) as any; + if (!hasError(resp) && resp.data?.docs) { + this.availableShipmentMethods = resp.data.docs; + } + } catch(err) { + console.error(err) + } + }, + async getRerouteFulfillmentConfiguration(settingTypeEnumId?: any) { + try { + const payload = { + "inputFields": { + "productStoreId": this.currentEComStore?.productStoreId, + settingTypeEnumId + }, + "filterByDate": 'Y', + "entityName": "ProductStoreSetting", + "fieldList": ["settingTypeEnumId", "settingValue", "fromDate"], + "viewSize": 5 + } as any + + // get all values + if (!payload.inputFields.settingTypeEnumId) { + payload.inputFields.settingTypeEnumId = Object.values(this.rerouteFulfillmentConfigMapping); + payload.inputFields.settingTypeEnumId_op = "in" + + } + + const resp = await UserService.getRerouteFulfillmentConfig(payload) as any + if (!hasError(resp) && resp.data?.docs) { + const rerouteFulfillmentConfigMappingFlipped = Object.fromEntries(Object.entries(this.rerouteFulfillmentConfigMapping).map(([key, value]) => [value, key])) as any; + resp.data.docs.map((config: any) => { + this.rerouteFulfillmentConfig[rerouteFulfillmentConfigMappingFlipped[config.settingTypeEnumId]] = config; + }) + } + } catch(err) { + console.error(err) + } + }, + async updateRerouteFulfillmentConfiguration(config: any, value: any) { + // Handled initial programmatical update + // When storing boolean values, it is stored as string. Further comparison needs conversion + if (config.settingValue === value || (typeof value === 'boolean' && (config.settingValue == 'true') === value)) { + return; + } + + const params = { + "fromDate": config.fromDate, + "productStoreId": this.currentEComStore?.productStoreId, + "settingTypeEnumId": config.settingTypeEnumId, + "settingValue": value + } + + try { + const resp = await UserService.updateRerouteFulfillmentConfig(params) as any + if(!hasError(resp)) { + showToast(translate('Configuration updated')) + } else { + showToast(translate('Failed to update configuration')) + } + } catch(err) { + showToast(translate('Failed to update configuration')) + console.error(err) + } + // Fetch the updated configuration + await this.getRerouteFulfillmentConfiguration(config.settingTypeEnumId); } }, setup () {