diff --git a/package-lock.json b/package-lock.json index 91c95a27..36c6f3c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,8 +14,8 @@ "@casl/ability": "^6.0.0", "@hotwax/app-version-info": "^1.0.0", "@hotwax/apps-theme": "^1.2.6", - "@hotwax/dxp-components": "1.13.0", - "@hotwax/oms-api": "1.14.0", + "@hotwax/dxp-components": "1.15.2", + "@hotwax/oms-api": "1.15.0", "@ionic/core": "^7.6.0", "@ionic/vue": "^7.6.0", "@ionic/vue-router": "^7.6.0", @@ -2802,9 +2802,9 @@ "integrity": "sha512-zpUjGoY7LBlKeiP0V7tonrmoey8HQ5THQmyixQ+IDtrjmEJNBjynW/Ef3gC0FUNNPuVqxWPZdT5CVgaETLGTwg==" }, "node_modules/@hotwax/dxp-components": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@hotwax/dxp-components/-/dxp-components-1.13.0.tgz", - "integrity": "sha512-AkzHpGIWYFURIAKaqioNZdkaeJBaJHs+ep+5ibLyEj+Ex+GsyMsI9L1NVO+tl91ECkCNx02QjHPhMfpo0osQ3w==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@hotwax/dxp-components/-/dxp-components-1.15.2.tgz", + "integrity": "sha512-0jF1xkRIVrDbJwUaaPwWUhp3cVBpdjgAJO/fOQ4XYjzKb8rYXgw0Xm/qHHUnSeAZW5laMnQrm1KtPZp8szu4dQ==", "dependencies": { "@hotwax/oms-api": "^1.8.1", "@ionic/core": "^7.6.0", @@ -2815,7 +2815,8 @@ "pinia-plugin-persistedstate": "^3.1.0", "register-service-worker": "^1.7.2", "vue": "^3.3.4", - "vue-i18n": "^9.2.2" + "vue-i18n": "^9.2.2", + "vue-markdown-render": "^2.2.1" } }, "node_modules/@hotwax/dxp-components/node_modules/@intlify/core-base": { @@ -2859,16 +2860,6 @@ "url": "https://github.com/sponsors/kazupon" } }, - "node_modules/@hotwax/dxp-components/node_modules/@ionic/core": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.8.2.tgz", - "integrity": "sha512-1Iwe4XSaEYD0u7U/AnnKYNRXmPxx/doTl6pExXq/nlEd7q0AykRkPEy5rClqrQcJOrgFogAx1FwSObfgm0xnNw==", - "dependencies": { - "@stencil/core": "^4.12.2", - "ionicons": "^7.2.2", - "tslib": "^2.1.0" - } - }, "node_modules/@hotwax/dxp-components/node_modules/pinia": { "version": "2.0.36", "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.0.36.tgz", @@ -2927,11 +2918,6 @@ } } }, - "node_modules/@hotwax/dxp-components/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, "node_modules/@hotwax/dxp-components/node_modules/vue-i18n": { "version": "9.10.2", "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.10.2.tgz", @@ -2952,9 +2938,9 @@ } }, "node_modules/@hotwax/oms-api": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@hotwax/oms-api/-/oms-api-1.14.0.tgz", - "integrity": "sha512-dYkrFEi0oJHKiJ/VctKmyIY4WTVV2lmljm1EflgQ/LM7BTJ9jVEeT1zgYJ5vO906kW7SWM4pl7mZI3dDCt1YCQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@hotwax/oms-api/-/oms-api-1.15.0.tgz", + "integrity": "sha512-6WXJ5z5JaAxgKith6dblLchP471xUYcFaeggN5onWZBkgGx5NqkLT0rgLWTW/UcVQMokxKtzSc+mcJ4eI1mGww==", "dependencies": { "@types/node-json-transform": "^1.0.0", "axios": "^0.21.1", @@ -11683,6 +11669,14 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "node_modules/linkify-it": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz", + "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==", + "dependencies": { + "uc.micro": "^1.0.1" + } + }, "node_modules/listr2": { "version": "3.14.0", "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", @@ -12097,6 +12091,37 @@ "semver": "bin/semver.js" } }, + "node_modules/markdown-it": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.2.tgz", + "integrity": "sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==", + "dependencies": { + "argparse": "^2.0.1", + "entities": "~3.0.1", + "linkify-it": "^4.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/md5": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", @@ -12113,6 +12138,11 @@ "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", "dev": true }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -16123,6 +16153,11 @@ "node": ">=4.2.0" } }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -17002,6 +17037,17 @@ "node": ">=8" } }, + "node_modules/vue-markdown-render": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vue-markdown-render/-/vue-markdown-render-2.2.1.tgz", + "integrity": "sha512-XkYnC0PMdbs6Vy6j/gZXSvCuOS0787Se5COwXlepRqiqPiunyCIeTPQAO2XnB4Yl04EOHXwLx5y6IuszMWSgyQ==", + "dependencies": { + "markdown-it": "^13.0.2" + }, + "peerDependencies": { + "vue": "^3.3.4" + } + }, "node_modules/vue-router": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz", diff --git a/package.json b/package.json index 5a97adf1..9b47fc9f 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ "@casl/ability": "^6.0.0", "@hotwax/app-version-info": "^1.0.0", "@hotwax/apps-theme": "^1.2.6", - "@hotwax/dxp-components": "1.13.0", - "@hotwax/oms-api": "1.14.0", + "@hotwax/dxp-components": "1.15.2", + "@hotwax/oms-api": "1.15.0", "@ionic/core": "^7.6.0", "@ionic/vue": "^7.6.0", "@ionic/vue-router": "^7.6.0", diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 75002fa3..2a16ae20 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -207,6 +207,7 @@ "Size": "Size", "Sizes": "Sizes", "sku selected": "sku selected", + "Some of the configuration of the app is missing.": "Some of the configuration of the app is missing.", "Some listing data not available": "Some listing data not available", "Something went wrong": "Something went wrong", "Something went wrong while login. Please contact administrator.": "Something went wrong while login. Please contact administrator.", diff --git a/src/services/UserService.ts b/src/services/UserService.ts index 91c30033..d0053108 100644 --- a/src/services/UserService.ts +++ b/src/services/UserService.ts @@ -13,6 +13,34 @@ const login = async (username: string, password: string): Promise => { }); } +const moquiLogin = async (omsRedirectionUrl: string, token: string): Promise => { + const baseURL = omsRedirectionUrl.startsWith('http') ? omsRedirectionUrl.includes('/rest/s1/order-routing') ? omsRedirectionUrl : `${omsRedirectionUrl}/rest/s1/order-routing/` : `https://${omsRedirectionUrl}.hotwax.io/rest/s1/order-routing/`; + let api_key = "" + + try { + const resp = await client({ + url: "login", + method: "post", + baseURL, + params: { + token + }, + headers: { + "Content-Type": "application/json" + } + }) as any; + + if(!hasError(resp) && (resp.data.api_key || resp.data.token)) { + api_key = resp.data.api_key || resp.data.token + } else { + throw "Sorry, login failed. Please try again"; + } + } catch(err) { + return Promise.resolve(""); + } + return Promise.resolve(api_key) +} + const setUserPreference = async (payload: any): Promise => { return api({ url: "service/setUserPreference", @@ -189,11 +217,116 @@ const getUserProfile = async (token: any): Promise => { } } +const runNow = async (): Promise => { + const omsRedirectionInfo = store.getters['user/getOmsRedirectionInfo']; + if(!omsRedirectionInfo.url || !omsRedirectionInfo.token) { + console.error("Maarg instance is not setup for this account."); + return; + } + + const url = omsRedirectionInfo.url + const baseURL = url.startsWith('http') ? url.includes('/rest/s1/order-routing') ? url : `${url}/rest/s1/order-routing/` : `https://${url}.hotwax.io/rest/s1/order-routing/`; + let resp = {} as any, payload = {}; + let routingGroupId = ""; + + try { + resp = await client({ + url: "checkOmsConnection", + method: "GET", + baseURL, + headers: { + "api_key": omsRedirectionInfo.token, + "Content-Type": "application/json" + } + }); + + if(hasError(resp)) { + throw resp.data; + } + + payload = { + "inputFields": { + "settingTypeEnumId": "RUN_GROUP_ID" + }, + "filterByDate": 'Y', + "entityName": "ProductStoreSetting", + "fieldList": ["settingValue", "fromDate"], + "viewSize": 1 + } + + resp = await api({ + url: "performFind", + method: "post", + data: payload + }); + + if(!hasError(resp) && resp.data.docs[0].settingValue) { + routingGroupId = resp.data.docs[0].settingValue + } else { + throw resp.data; + } + + let job; + resp = await client({ + url: `groups/${routingGroupId}/schedule`, + method: "GET", + baseURL, + headers: { + "api_key": omsRedirectionInfo.token, + "Content-Type": "application/json" + } + }) + + if(!hasError(resp)) { + job = resp.data.schedule + } else { + throw resp.data; + } + + if(!job.jobName) { + resp = await client({ + url: `groups/${routingGroupId}/schedule`, + method: "POST", + data: { + routingGroupId, + paused: "Y", // passing Y as we just need to configure the scheduler and do not need to schedule it in active state + }, + baseURL, + headers: { + "api_key": omsRedirectionInfo.token, + "Content-Type": "application/json" + } + }); + if(hasError(resp)) { + throw resp.data; + } + } + + resp = await client({ + url: `groups/${routingGroupId}/runNow`, + method: "POST", + baseURL, + headers: { + "api_key": omsRedirectionInfo.token, + "Content-Type": "application/json" + } + }); + + if(hasError(resp)) { + throw resp.data; + } + } catch(error: any) { + console.error("Failed to schedule routing.", error) + } +} + export const UserService = { getEComStores, getPreferredStore, getUserProfile, getUserPermissions, login, + moquiLogin, + runNow, setUserPreference, } \ No newline at end of file diff --git a/src/store/modules/user/UserState.ts b/src/store/modules/user/UserState.ts index 4fea94b0..7d692caf 100644 --- a/src/store/modules/user/UserState.ts +++ b/src/store/modules/user/UserState.ts @@ -5,4 +5,8 @@ export default interface UserState { pwaState: any; instanceUrl: string; currentEComStore: object; + omsRedirectionInfo: { + url: string; + token: string; + } } \ No newline at end of file diff --git a/src/store/modules/user/actions.ts b/src/store/modules/user/actions.ts index 5a10c0d3..73e42d77 100644 --- a/src/store/modules/user/actions.ts +++ b/src/store/modules/user/actions.ts @@ -18,7 +18,7 @@ const actions: ActionTree = { */ async login ({ commit, dispatch }, payload) { - const { token, oms } = payload; + const { token, oms, omsRedirectionUrl } = payload; dispatch("setUserInstanceUrl", oms); try { if (token) { @@ -66,6 +66,17 @@ const actions: ActionTree = { Settings.defaultZone = userProfile.userTimeZone; } + if(omsRedirectionUrl) { + const api_key = await UserService.moquiLogin(omsRedirectionUrl, token) + if(api_key) { + dispatch("setOmsRedirectionInfo", { url: omsRedirectionUrl, token: api_key }) + } else { + console.error("Some of the configuration of the app is missing."); + } + } else { + console.error("Some of the configuration of the app is missing.") + } + // TODO user single mutation commit(types.USER_CURRENT_ECOM_STORE_UPDATED, preferredStore); commit(types.USER_INFO_UPDATED, userProfile); @@ -83,7 +94,7 @@ const actions: ActionTree = { /** * Logout user */ - async logout ({ commit }, payload) { + async logout ({ commit, dispatch }, payload) { // store the url on which we need to redirect the user after logout api completes in case of SSO enabled let redirectionUrl = '' @@ -118,6 +129,7 @@ const actions: ActionTree = { this.dispatch("order/resetOrderQuery") this.dispatch("job/clearCtgryAndBrkrngJobs") this.dispatch("util/clearInvConfigs") + dispatch("setOmsRedirectionInfo", { url: "", token: "" }) resetPermissions(); // reset plugin state on logout @@ -157,6 +169,10 @@ const actions: ActionTree = { }); }, + setOmsRedirectionInfo({ commit }, payload) { + commit(types.USER_OMS_REDIRECTION_INFO_UPDATED, payload) + }, + /** * Set User Instance Url */ diff --git a/src/store/modules/user/getters.ts b/src/store/modules/user/getters.ts index c00ce56f..c7f18edf 100644 --- a/src/store/modules/user/getters.ts +++ b/src/store/modules/user/getters.ts @@ -32,6 +32,9 @@ const getters: GetterTree = { }, getCurrentEComStore(state) { return state.currentEComStore + }, + getOmsRedirectionInfo(state) { + return state.omsRedirectionInfo; } } 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 7b32b1b3..d83675ac 100644 --- a/src/store/modules/user/index.ts +++ b/src/store/modules/user/index.ts @@ -16,6 +16,10 @@ const userModule: Module = { pwaState: { updateExists: false, registration: null, + }, + omsRedirectionInfo: { + url: "", + token: "" } }, getters, diff --git a/src/store/modules/user/mutation-types.ts b/src/store/modules/user/mutation-types.ts index 7100ad58..059c6db7 100644 --- a/src/store/modules/user/mutation-types.ts +++ b/src/store/modules/user/mutation-types.ts @@ -6,4 +6,5 @@ export const USER_INSTANCE_URL_UPDATED = SN_USER + '/INSTANCE_URL_UPDATED' export const USER_PERMISSIONS_UPDATED = SN_USER + '/PERMISSIONS_UPDATED' export const USER_CURRENT_ECOM_STORE_UPDATED = SN_USER + '/CURRENT_ECOM_STORE_UPDATED' export const USER_STORE_RSRV_INV_STATUS_UPDATED = SN_USER + '/STORE_RSRV_INV_STATUS_UPDATED' -export const USER_PWA_STATE_UPDATED = SN_USER + '/PWA_STATE_UPDATED' \ No newline at end of file +export const USER_PWA_STATE_UPDATED = SN_USER + '/PWA_STATE_UPDATED' +export const USER_OMS_REDIRECTION_INFO_UPDATED = SN_USER + '/OMS_REDIRECTION_INFO_UPDATED' \ No newline at end of file diff --git a/src/store/modules/user/mutations.ts b/src/store/modules/user/mutations.ts index f9834596..087452d2 100644 --- a/src/store/modules/user/mutations.ts +++ b/src/store/modules/user/mutations.ts @@ -28,5 +28,8 @@ const mutations: MutationTree = { state.pwaState.registration = payload.registration; state.pwaState.updateExists = payload.updateExists; }, + [types.USER_OMS_REDIRECTION_INFO_UPDATED](state, payload) { + state.omsRedirectionInfo = payload; + } } export default mutations; \ No newline at end of file diff --git a/src/views/order-popover.vue b/src/views/order-popover.vue index a17073d3..5dace47a 100644 --- a/src/views/order-popover.vue +++ b/src/views/order-popover.vue @@ -22,6 +22,7 @@ import { defineComponent } from "vue"; import WarehouseModal from "@/views/warehouse-modal.vue"; import { useStore } from "@/store"; import PromiseDateModal from "@/views/promise-date-modal.vue"; +import { UserService } from '@/services/UserService' export default defineComponent({ name: "OrderPopover", @@ -63,6 +64,7 @@ export default defineComponent({ handler: () => { this.releaseItem(this.item).then(() => { this.store.dispatch("order/removeItem", { item: this.item }); + UserService.runNow(); }) }, } diff --git a/src/views/orders.vue b/src/views/orders.vue index f85d2297..ab0d9e78 100644 --- a/src/views/orders.vue +++ b/src/views/orders.vue @@ -230,6 +230,7 @@ import { showToast } from '@/utils' import { Plugins } from '@capacitor/core'; import { DxpShopifyImg } from "@hotwax/dxp-components"; import emitter from "@/event-bus"; +import { UserService } from '@/services/UserService' const { Clipboard } = Plugins; @@ -335,6 +336,7 @@ export default defineComponent({ }).then(() => { // TODO Find a better place to call this this.store.dispatch("order/removeItems", { items: selectedItems }); + UserService.runNow(); }).finally(() => emitter.emit("dismissLoader")) }, async cancelItems() { diff --git a/src/views/product-details.vue b/src/views/product-details.vue index 5df0ab15..fa917e24 100644 --- a/src/views/product-details.vue +++ b/src/views/product-details.vue @@ -215,6 +215,7 @@ import { DxpShopifyImg } from "@hotwax/dxp-components"; import { sizeIndex } from "@/apparel-sorter" import { DateTime } from 'luxon'; import emitter from "@/event-bus"; +import { UserService } from '@/services/UserService' export default defineComponent({ name: "product-details", @@ -454,6 +455,7 @@ export default defineComponent({ data: formData }).then(() => { this.store.dispatch("order/removeItems", { items: selectedItems }); + UserService.runNow(); }).finally(() => emitter.emit("dismissLoader")) }, async cancelItems() {