Skip to content

Commit

Permalink
Merge pull request #191 from ymaheshwari1/#2ftb11u
Browse files Browse the repository at this point in the history
Implemented: code to add functionality to subscribe or unsubscribe a webhook(#2ftb11u)
  • Loading branch information
adityasharma7 authored Jun 17, 2022
2 parents 092381a + eb7eda4 commit a4d0943
Show file tree
Hide file tree
Showing 13 changed files with 360 additions and 13 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ VUE_APP_JOB_TITLES={"JOB_IMP_PROD_NEW":"Import products","JOB_IMP_PROD_UPD":"Syn
VUE_APP_INITIAL_JOB_TYPES={"JOB_IMP_PROD_NEW_BLK":"products","JOB_IMP_ORD_BLK":"orders"}
VUE_APP_BASE_URL=
VUE_APP_BATCH_JOB_ENUMS={"JOB_BKR_ORD_UNF":{"id":"JOB_BKR_ORD_UNF","facilityId":"_NA_","unfillable": true},"JOB_BKR_ORD":{"id": "JOB_BKR_ORD","facilityId":"_NA_","unfillable": false},"JOB_BKR_PREORD_UNF":{"id":"JOB_BKR_PREORD_UNF","facilityId":"PRE_ORDER_PARKING","unfillable":true},"JOB_BKR_PREORD":{"id":"JOB_BKR_PREORD","facilityId":"PRE_ORDER_PARKING","unfillable":false},"JOB_BKR_BACKORD_UNF":{"id":"JOB_BKR_BACKORD_UNF","facilityId":"BACKORDER_PARKING","unfillable":true},"JOB_BKR_BACKORD":{"id":"JOB_BKR_BACKORD","facilityId":"BACKORDER_PARKING","unfillable":false}}
VUE_APP_WEBHOOK_ENUMS={"NEW_PRODUCTS":"products/create","DELETE_PRODUCTS":"products/update","NEW_ORDERS":"orders/create","CANCELLED_ORDERS":"orders/cancelled","PAYMENT_STATUS":"orders/paid","RETURNS":"","BULK_OPERATIONS_FINISH":"bulk_operations/finish"}
6 changes: 6 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"Daily": "Daily",
"Dashoard": "Dashoard",
"Days": "Days",
"Delete products": "Delete products",
"Disable": "Disable",
"Dismiss": "Dismiss",
"Disabled": "Disabled",
Expand All @@ -53,6 +54,7 @@
"Every 5 minutes": "Every 5 minutes",
"Every 15 minutes": "Every 15 minutes",
"Every 30 minutes": "Every 30 minutes",
"File upload status": "File upload status",
"Fulfilled": "Fulfilled",
"Fulfillment status": "Fulfillment status",
"Hard sync": "Hard sync",
Expand All @@ -78,6 +80,7 @@
"More options": "More options",
"New broker run": "New broker run",
"New orders": "New orders",
"New products": "New products",
"No jobs have run yet": "No jobs have run yet",
"No previous occurrence": "No previous occurrence",
"Notes": "Notes",
Expand Down Expand Up @@ -173,10 +176,13 @@
"Update time zone": "Update time zone",
"Use POs to manage catalog": "Use POs to manage catalog",
"Username": "Username",
"Webhook subscribed successfully": "Webhook subscribed successfully",
"Webhook unsubscribed successfully": "Webhook unsubscribed successfully",
"Would you like to update your time zone to . Your profile is currently set to . This setting can always be changed from the settings menu.": "Would you like to update your time zone to {localTimeZone}. Your profile is currently set to {profileTimeZone}. This setting can always be changed from the settings menu.",
"Unfillable": "Unfillable",
"Unfillable orders": "Unfillable orders",
"Unfulfilled orders that pass their auto cancelation date will be canceled automatically in HotWax Commerce. They will also be canceled in Shopify if upload for canceled orders is enabled.": "Unfulfilled orders that pass their auto cancelation date will be canceled automatically in HotWax Commerce. They will also be canceled in Shopify if upload for canceled orders is enabled.",
"Webhooks": "Webhooks",
"Upload Pending Process": "Upload Pending Process",
"Update shipping dates in Shopify": "Update shipping dates in Shopify",
"When importing historical completed orders, this should be turned off.": "When importing historical completed orders, this should be turned off.",
Expand Down
90 changes: 90 additions & 0 deletions src/services/WebhookService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import api from '@/api'

const fetchShopifyWebhooks = async (payload?: any): Promise <any> => {
return api({
url: "/service/getShopifyWebhooks",
method: "post",
data: payload
});
}

// TODO: add the service endpoint for the new order webhook
const subscribeNewOrderWebhook = async (payload?: any): Promise <any> => {
return api ({
url: '',
method: 'post',
data: payload
})
}

// TODO: add the service endpoint for the cancelled order webhook
const subscribeCancelledOrderWebhook = async (payload?: any): Promise <any> => {
return api ({
url: '',
method: 'post',
data: payload
})
}

// TODO: add the service endpoint for the payment status webhook
const subscribePaymentStatusWebhook = async (payload?: any): Promise <any> => {
return api ({
url: '',
method: 'post',
data: payload
})
}

// TODO: add the service endpoint for the order return webhook
const subscribeReturnWebhook = async (payload?: any): Promise <any> => {
return api ({
url: '',
method: 'post',
data: payload
})
}

// TODO: add the service endpoint for the new product webhook
const subscribeNewProductsWebhook = async (payload?: any): Promise <any> => {
return api ({
url: '',
method: 'post',
data: payload
})
}

const subscribeDeleteProductsWebhook = async (payload?: any): Promise <any> => {
return api ({
url: 'service/subscribeProductDeleteWebhook',
method: 'post',
data: payload
})
}

const subscribeFileStatusUpdateWebhook = async (payload?: any): Promise <any> => {
return api ({
url: 'service/subscribeFileStatusUpdateWebhook',
method: 'post',
data: payload
})
}

const unsubscribeWebhook = async (payload?: any): Promise <any> => {
return api ({
url: 'service/removeShopifyWebhook',
method: 'post',
data: payload
})
}

export const WebhookService = {
fetchShopifyWebhooks,
subscribeNewOrderWebhook,
subscribeCancelledOrderWebhook,
subscribeFileStatusUpdateWebhook,
subscribePaymentStatusWebhook,
subscribeReturnWebhook,
subscribeNewProductsWebhook,
subscribeDeleteProductsWebhook,
unsubscribeWebhook
}
4 changes: 3 additions & 1 deletion src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import userModule from './modules/user';
import productModule from "./modules/product"
import jobModule from "./modules/job"
import utilModule from "./modules/util"
import webhookModule from "./modules/webhook"


// TODO check how to register it from the components only
Expand Down Expand Up @@ -35,7 +36,8 @@ const store = createStore<RootState>({
'user': userModule,
'product': productModule,
'job': jobModule,
'util': utilModule
'util': utilModule,
'webhook': webhookModule
},
})

Expand Down
3 changes: 3 additions & 0 deletions src/store/modules/webhook/WebhookState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default interface WebhookState {
cached: any
}
78 changes: 78 additions & 0 deletions src/store/modules/webhook/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { ActionTree } from "vuex";
import RootState from "@/store/RootState";
import WebhookState from "./WebhookState";
import { WebhookService } from "@/services/WebhookService";
import { hasError, showToast } from "@/utils";
import * as types from './mutations-types'
import { translate } from '@/i18n'

const actions: ActionTree<WebhookState, RootState> = {
async fetchWebhooks({ commit }) {
await WebhookService.fetchShopifyWebhooks({ shopifyConfigId: this.state.user.shopifyConfig }).then(resp => {
if (resp.status == 200 && resp.data.webhooks?.length > 0 && !hasError(resp)) {
const webhooks = resp.data.webhooks;
const topics: any = {}
webhooks.map((webhook: any) => {
topics[webhook.topic] = webhook
})
commit(types.WEBHOOK_UPDATED, topics)
}
}).catch(err => console.error(err))
},
async unsubscribeWebhook({ dispatch }, payload: any) {

let resp;

try {
resp = await WebhookService.unsubscribeWebhook(payload)
if (resp.status === 200 && !hasError(resp)) {
showToast(translate("Webhook unsubscribed successfully"));
}
} catch(err) {
console.log(err)
showToast(translate("Something went wrong"));
} finally {
dispatch('fetchWebhooks')
}
},
async subscribeWebhook({ dispatch }, id: string) {

// stores the webhook service that needs to be called on the basis of current webhook selected, doing
// so as we have defined separate service for different webhook subscription
const webhookMethods = {
'NEW_ORDERS': WebhookService.subscribeNewOrderWebhook,
'CANCELLED_ORDERS': WebhookService.subscribeCancelledOrderWebhook,
'PAYMENT_STATUS':WebhookService.subscribePaymentStatusWebhook,
'RETURNS': WebhookService.subscribeReturnWebhook,
'NEW_PRODUCTS': WebhookService.subscribeNewProductsWebhook,
'DELETE_PRODUCTS': WebhookService.subscribeDeleteProductsWebhook,
'BULK_OPERATIONS_FINISH': WebhookService.subscribeFileStatusUpdateWebhook
} as any
const webhookMethod: any = webhookMethods[id];

if (!webhookMethod) {
showToast(translate("Configuration missing"));
return;
}

let resp;

try {
resp = await webhookMethod({ shopifyConfigId: this.state.user.shopifyConfig })

if (resp.status == 200 && !hasError(resp)) {
showToast(translate('Webhook subscribed successfully'))
} else {
showToast(translate('Something went wrong'))
console.error(resp)
}
} catch (err) {
showToast(translate('Something went wrong'))
console.error(err);
} finally {
await dispatch('fetchWebhooks')
}
}
}

export default actions
9 changes: 9 additions & 0 deletions src/store/modules/webhook/getters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { GetterTree } from "vuex";
import RootState from "@/store/RootState";
import WebhookState from "./WebhookState";

const getters: GetterTree<WebhookState, RootState> = {
getCachedWebhook: (state) => state.cached
}

export default getters
18 changes: 18 additions & 0 deletions src/store/modules/webhook/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Module } from 'vuex'
import WebhookState from './WebhookState'
import RootState from '@/store/RootState'
import getters from './getters'
import mutations from './mutations'
import actions from './actions'

const webhookModule: Module<WebhookState, RootState> = {
namespaced: true,
state: {
cached: {}
},
getters,
actions,
mutations,
}

export default webhookModule
2 changes: 2 additions & 0 deletions src/store/modules/webhook/mutations-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const SN_WEBHOOK = 'webhook'
export const WEBHOOK_UPDATED = SN_WEBHOOK + '/WEBHOOK_UPDATED'
11 changes: 11 additions & 0 deletions src/store/modules/webhook/mutations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { MutationTree } from "vuex";
import WebhookState from "./WebhookState";
import * as types from './mutations-types'

const mutations: MutationTree<WebhookState> = {
[types.WEBHOOK_UPDATED] (state, payload: any) {
state.cached = payload
}
}

export default mutations
44 changes: 36 additions & 8 deletions src/views/InitialLoad.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
<ion-card-header>
<ion-card-title>{{ $t("Process Uploads") }}</ion-card-title>
</ion-card-header>
<ion-item>
<ion-label class="ion-text-wrap">{{ $t("File upload status") }}</ion-label>
<ion-toggle :checked="fileStatusUpdateWebhook" color="secondary" slot="end" @ionChange="updateWebhook($event['detail'].checked, 'BULK_OPERATIONS_FINISH')" />
</ion-item>
<ion-item>
<ion-label class="ion-text-wrap">{{ $t("Upload Pending Process") }}</ion-label>
<ion-checkbox slot="end" :checked="processPendingUploadsOnShopify" @ionChange="updateJob($event['detail'].checked, jobEnums['UL_PRCS'])"/>
Expand Down Expand Up @@ -69,6 +73,7 @@ import {
IonMenuButton,
IonPage,
IonTitle,
IonToggle,
IonToolbar,
isPlatform
} from '@ionic/vue';
Expand Down Expand Up @@ -96,11 +101,13 @@ export default defineComponent({
IonMenuButton,
IonPage,
IonTitle,
IonToggle,
IonToolbar
},
data() {
return {
jobEnums: JSON.parse(process.env?.VUE_APP_INITIAL_JOB_ENUMS as string) as any,
webhookEnums: JSON.parse(process.env?.VUE_APP_WEBHOOK_ENUMS as string) as any,
currentSelectedJobModal: '',
job: {} as any,
lastShopifyOrderId: '',
Expand All @@ -115,35 +122,41 @@ export default defineComponent({
"systemJobEnumId_op": "in"
}
})
this.store.dispatch('webhook/fetchWebhooks')
},
computed: {
...mapGetters({
getJobStatus: 'job/getJobStatus',
getJob: 'job/getJob',
shopifyConfigId: 'user/getShopifyConfigId',
currentEComStore: 'user/getCurrentEComStore'
currentEComStore: 'user/getCurrentEComStore',
getCachedWebhook: 'webhook/getCachedWebhook'
}),
fileStatusUpdateWebhook(): boolean {
const webhookTopic = this.webhookEnums['BULK_OPERATIONS_FINISH']
return this.getCachedWebhook[webhookTopic]
},
processPendingUploadsOnShopify(): boolean {
const status = this.getJobStatus(this.jobEnums["UL_PRCS"]);
return status && status !== "SERVICE_DRAFT";
},
}
},
methods: {
async updateJob(checked: boolean, id: string, status = 'EVERY_15_MIN') {
const job = this.getJob(id);
// added check that if the job is not present, then display a toast and then return
if (!job) {
showToast(translate('Configuration missing'))
return;
}
// TODO: added this condition to not call the api when the value of the select automatically changes
// need to handle this properly
if ((checked && job?.status === 'SERVICE_PENDING') || (!checked && job?.status === 'SERVICE_DRAFT')) {
return;
}
// added check that if the job is not present, then display a toast and then return
if (!job) {
showToast(translate('Configuration missing'))
return;
}
job['jobStatus'] = status
// if job runTime is not a valid date then making runTime as empty
Expand Down Expand Up @@ -181,6 +194,21 @@ export default defineComponent({
emitter.emit('playAnimation');
this.isJobDetailAnimationCompleted = true;
}
},
async updateWebhook(checked: boolean, enumId: string) {
const webhook = this.getCachedWebhook[this.webhookEnums[enumId]]
// TODO: added this condition to not call the api when the value of the select automatically changes
// need to handle this properly
if ((checked && webhook) || (!checked && !webhook)) {
return;
}
if (checked) {
await this.store.dispatch('webhook/subscribeWebhook', enumId)
} else {
await this.store.dispatch('webhook/unsubscribeWebhook', { webhookId: webhook?.id, shopifyConfigId: this.shopifyConfigId })
}
}
},
setup() {
Expand Down
Loading

0 comments on commit a4d0943

Please sign in to comment.