Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented: the use of api to clone the group, route and rules(#183) #193

Merged
merged 4 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"auto cancel days": "auto cancel days",
"Brokering": "Brokering",
"Brokering Runs": "Brokering Runs",
"Brokering run cloned": "Brokering run cloned",
"Brokering run created": "Brokering run created",
"Brokering safety stock": "Brokering safety stock",
"Built:": "Built: ",
Expand All @@ -44,6 +45,8 @@
"Enter a valid value": "Enter a valid value",
"Error getting user profile": "Error getting user profile",
"Execution history": "Execution history",
"Failed to clone brokering run": "Failed to clone brokering run",
"Failed to clone rule": "Failed to clone rule",
"Failed to clone the rule": "Failed to clone the rule",
"Failed to create brokering run": "Failed to create brokering run",
"Failed to create inventory rule": "Failed to create inventory rule",
Expand Down
27 changes: 27 additions & 0 deletions src/services/RoutingService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ const updateRoutingGroup = async (payload: any): Promise<any> => {
})
}

const cloneGroup = async (payload: any): Promise<any> => {
return api({
url: `groups/${payload.routingGroupId}/clone`,
method: "POST",
data: payload
})
}

const fetchOrderRouting = async (orderRoutingId: string): Promise<any> => {
return api({
url: `routings/${orderRoutingId}`,
Expand All @@ -77,6 +85,14 @@ const createOrderRouting = async (payload: any): Promise<any> => {
})
}

const cloneRouting = async (payload: any): Promise<any> => {
return await api({
url: `routings/${payload.orderRoutingId}/clone`,
method: "POST",
data: payload
})
}

const updateRouting = async (payload: any): Promise<any> => {
return api({
url: `routings/${payload.orderRoutingId}`,
Expand Down Expand Up @@ -116,6 +132,14 @@ const fetchRule = async (routingRuleId: string): Promise<any> => {
});
}

const cloneRule = async (payload: any): Promise<any> => {
return await api({
url: `rules/${payload.routingRuleId}/clone`,
method: "POST",
data: payload
})
}

const updateRule = async (payload: any): Promise<any> => {
return api({
url: `rules/${payload.routingRuleId}`,
Expand All @@ -140,7 +164,10 @@ const runNow = async (routingGroupId: string): Promise<any> => {
}

export const OrderRoutingService = {
cloneGroup,
createOrderRouting,
cloneRouting,
cloneRule,
createRoutingGroup,
createRoutingRule,
deleteRoutingFilter,
Expand Down
26 changes: 26 additions & 0 deletions src/store/modules/orderRouting/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,32 @@
return orderRoutingId;
},

async cloneOrderRouting({ dispatch }, payload) {
let orderRoutingId = ""

try {
const resp = await OrderRoutingService.cloneRouting({
orderRoutingId: payload.orderRoutingId,
newRoutingName: `${payload.orderRoutingName} copy`,
newRoutingGroupId: payload.routingGroupId // group in which this routing needs to be cloned
})

if(!hasError(resp) && resp?.data.newOrderRoutingId) {
orderRoutingId = resp.data.newOrderRoutingId
showToast(translate("Routing cloned"))

// TODO: check if we can get all the information in response so we do not need to make an api call here
// Fetching the group information again as we do not have the complete information for the cloned route
await dispatch("fetchCurrentRoutingGroup", payload.routingGroupId)
}
} catch(err) {
showToast(translate("Failed to clone order routing"))
logger.error(err)
}

return orderRoutingId;
},

async fetchCurrentOrderRouting({ dispatch }, orderRoutingId) {
let currentRoute = {} as any

Expand Down Expand Up @@ -217,7 +243,7 @@
commit(types.ORDER_ROUTING_HISTORY_UPDATED, routingHistory)
},

async deleteRoutingFilters({ dispatch }, payload) {

Check warning on line 246 in src/store/modules/orderRouting/actions.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

'dispatch' is defined but never used

Check warning on line 246 in src/store/modules/orderRouting/actions.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

'dispatch' is defined but never used
let hasAllFiltersDeletedSuccessfully = true;
try {
// As discussed, we can't make parallel api calls, hence using for loop to make api calls
Expand All @@ -237,7 +263,7 @@
return hasAllFiltersDeletedSuccessfully
},

async updateRouting({ dispatch }, payload) {

Check warning on line 266 in src/store/modules/orderRouting/actions.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

'dispatch' is defined but never used

Check warning on line 266 in src/store/modules/orderRouting/actions.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

'dispatch' is defined but never used
let orderRoutingId = ''
try {
const resp = await OrderRoutingService.updateRouting(payload)
Expand Down Expand Up @@ -288,7 +314,7 @@
return routingRuleId;
},

async deleteRuleConditions({ dispatch }, payload) {

Check warning on line 317 in src/store/modules/orderRouting/actions.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

'dispatch' is defined but never used

Check warning on line 317 in src/store/modules/orderRouting/actions.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

'dispatch' is defined but never used
// TODO: check if we can call request in parallel for delete operation
let hasAllConditionsDeletedSuccessfully = true;
try {
Expand All @@ -308,7 +334,7 @@
return hasAllConditionsDeletedSuccessfully
},

async deleteRuleActions({ dispatch }, payload) {

Check warning on line 337 in src/store/modules/orderRouting/actions.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

'dispatch' is defined but never used

Check warning on line 337 in src/store/modules/orderRouting/actions.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

'dispatch' is defined but never used
// TODO: check if we can call request in parallel for delete operation
let hasAllActionsDeletedSuccessfully = true;
try {
Expand Down Expand Up @@ -371,7 +397,7 @@
return rulesInformation[routingRuleId] ? JSON.parse(JSON.stringify(rulesInformation[routingRuleId])) : {}
},

async updateRule({ dispatch }, payload) {

Check warning on line 400 in src/store/modules/orderRouting/actions.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

'dispatch' is defined but never used

Check warning on line 400 in src/store/modules/orderRouting/actions.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

'dispatch' is defined but never used
let routingRuleId = ''
try {
const resp = await OrderRoutingService.updateRule(payload)
Expand Down
77 changes: 16 additions & 61 deletions src/views/BrokeringQuery.vue
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@
<ion-icon slot="start" :icon="isRuleNameUpdating ? saveOutline : pencilOutline" />
{{ isRuleNameUpdating ? translate("Save") : translate("Rename") }}
</ion-button>
<ion-button size="small" @click="cloneRule" fill="outline">
<!-- <ion-button size="small" @click="cloneRule" fill="outline">
<ion-icon slot="start" :icon="copyOutline"/>
{{ translate("Clone") }}
</ion-button>
</ion-button> -->
</div>
</ion-item>
</div>
Expand Down Expand Up @@ -307,7 +307,7 @@

<script setup lang="ts">
import { IonBackButton, IonButton, IonButtons, IonCard, IonCardContent, IonCardHeader, IonCardTitle, IonChip, IonContent, IonFab, IonFabButton, IonHeader, IonIcon, IonInput, IonItem, IonItemDivider, IonItemGroup, IonLabel, IonList, IonNote, IonPage, IonReorder, IonReorderGroup, IonSelect, IonSelectOption, IonTitle, IonToggle, IonToolbar, alertController, modalController, onIonViewWillEnter, popoverController } from "@ionic/vue";
import { addCircleOutline, bookmarkOutline, closeCircleOutline, copyOutline, filterOutline, golfOutline, optionsOutline, pencilOutline, playForwardOutline, pulseOutline, saveOutline, swapVerticalOutline, timeOutline } from "ionicons/icons"

Check warning on line 310 in src/views/BrokeringQuery.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

'copyOutline' is defined but never used

Check warning on line 310 in src/views/BrokeringQuery.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

'copyOutline' is defined but never used
import { onBeforeRouteLeave, useRouter } from "vue-router";
import { computed, defineProps, nextTick, ref } from "vue";
import store from "@/store";
Expand Down Expand Up @@ -945,70 +945,25 @@
isRuleNameUpdating.value = false;
}

async function cloneRule() {

Check warning on line 948 in src/views/BrokeringQuery.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

'cloneRule' is defined but never used

Check warning on line 948 in src/views/BrokeringQuery.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

'cloneRule' is defined but never used
emitter.emit("presentLoader", { message: `Cloning rule ${selectedRoutingRule.value.ruleName}`, backdropDismiss: false })

const payload = {
routingRuleId: "",
orderRoutingId: props.orderRoutingId,
ruleName: selectedRoutingRule.value.ruleName + ' copy',
statusId: "RULE_DRAFT", // by default when cloning the rule the new rule will be in draft status
sequenceNum: inventoryRules.value.length && inventoryRules.value[inventoryRules.value.length - 1].sequenceNum >= 0 ? inventoryRules.value[inventoryRules.value.length - 1].sequenceNum + 5 : 0, // added check for `>= 0` as sequenceNum can be 0, that will result in again setting the new route seqNum to 0,
assignmentEnumId: selectedRoutingRule.value.assignmentEnumId,
createdDate: DateTime.now().toMillis()
}

const routingRuleId = await store.dispatch("orderRouting/createRoutingRule", payload)

if(!routingRuleId) {
showToast(translate("Failed to clone the rule"))
emitter.emit("dismissLoader")
return;
}

const sortOptions = rulesInformation.value[selectedRoutingRule.value.routingRuleId]["inventoryFilters"]?.["ENTCT_SORT_BY"] ? rulesInformation.value[selectedRoutingRule.value.routingRuleId]["inventoryFilters"]["ENTCT_SORT_BY"] : {}
const filterOptions = rulesInformation.value[selectedRoutingRule.value.routingRuleId]["inventoryFilters"]?.["ENTCT_FILTER"] ? rulesInformation.value[selectedRoutingRule.value.routingRuleId]["inventoryFilters"]["ENTCT_FILTER"] : {}
const actionOptions = rulesInformation.value[selectedRoutingRule.value.routingRuleId]["actions"] ? rulesInformation.value[selectedRoutingRule.value.routingRuleId]["actions"] : {}

let inventoryFilters = [] as any, actions = [] as any
emitter.emit("presentLoader", { message: `Cloning ${selectedRoutingRule.value.ruleName}`, backdropDismiss: false })

Object.values(sortOptions).map((option: any) => {
inventoryFilters.push({
createdDate: DateTime.now().toMillis(),
conditionTypeEnumId: option.conditionTypeEnumId,
fieldName: option.fieldName,
sequenceNum: option.sequenceNum
try {
const resp = await OrderRoutingService.cloneRule({
routingRuleId: selectedRoutingRule.value.routingRuleId,
newOrderRoutingId: props.orderRoutingId,
newRuleName: `${selectedRoutingRule.value.ruleName} copy`
})
})

Object.values(filterOptions).map((option: any) => {
inventoryFilters.push({
createdDate: DateTime.now().toMillis(),
conditionTypeEnumId: option.conditionTypeEnumId,
fieldName: option.fieldName,
fieldValue: option.fieldValue,
operator: option.operator,
sequenceNum: option.sequenceNum
})
})

Object.values(actionOptions).map((option: any) => {
actions.push({
actionTypeEnumId: option.actionTypeEnumId,
actionValue: option.actionValue,
createdDate: DateTime.now().toMillis(),
})
})

await store.dispatch("orderRouting/updateRule", {
routingRuleId,
orderRoutingId: props.orderRoutingId,
inventoryFilters,
actions
})
if(hasError(resp) || !resp.data.newRoutingRuleId) {
throw resp.data
}

inventoryRules.value = JSON.parse(JSON.stringify(currentRouting.value["rules"]))
fetchRuleInformation(routingRuleId)
await store.dispatch("orderRouting/fetchCurrentOrderRouting", props.orderRoutingId)
} catch (err) {
logger.error(err)
showToast(translate("Failed to clone rule"))
}

emitter.emit("dismissLoader")
}
Expand Down
141 changes: 22 additions & 119 deletions src/views/BrokeringRoute.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
<ion-icon slot="start" :icon="saveOutline" />
{{ translate("Save") }}
</ion-button>
<!-- <ion-button fill="outline" size="small">
<ion-button fill="outline" size="small" @click="cloneGroup()">
<ion-icon slot="start" :icon="copyOutline" />
{{ translate("Clone") }}
</ion-button> -->
</ion-button>
</div>
</div>
<div>
Expand Down Expand Up @@ -741,136 +741,39 @@ async function editGroupDescription() {
descRef.value.$el.setFocus();
}

async function cloneRouting(routing: any) {
emitter.emit("presentLoader", { message: "Cloning route", backdropDismiss: false })

// payload for creating the cloned copy of current routing
async function cloneGroup() {
const payload = {
orderRoutingId: "",
routingGroupId: props.routingGroupId,
statusId: "ROUTING_DRAFT", // when cloning a routing, the new routing will be in draft status
routingName: routing.routingName + " copy",
sequenceNum: orderRoutings.value.length && orderRoutings.value[orderRoutings.value.length - 1].sequenceNum >= 0 ? orderRoutings.value[orderRoutings.value.length - 1].sequenceNum + 5 : 0, // added check for `>= 0` as sequenceNum can be 0 which will result in again setting the new route seqNum to 0, also considering archivedRouting when calculating new seqNum
description: "",
createdDate: DateTime.now().toMillis()
}

const orderRoutingId = await store.dispatch("orderRouting/createOrderRouting", payload)

// No need to perform any action if we do not get routingId in return after routing creation
if(!orderRoutingId) {
showToast(translate("Failed to clone order routing"))
emitter.emit("dismissLoader")
return;
routingGroupId: currentRoutingGroup.value.routingGroupId,
newGroupName: `${currentRoutingGroup.value.groupName} copy`
}

let parentRouting = {} as any;

// Fetch rules and order filters for the parent routing, as we need to create copy of the rules and filters
try {
const resp = await OrderRoutingService.fetchOrderRouting(routing.orderRoutingId);
const resp = await OrderRoutingService.cloneGroup(payload)

if(!hasError(resp) && resp.data) {
parentRouting = resp.data
if(!hasError(resp)) {
// Not fetching the groups list as after cloning as we do not need any information from the newly cloned group
showToast(translate("Brokering run cloned"))
} else {
throw resp.data
}
} catch(err) {
showToast(translate("Failed to clone the routing filters and rules"))
logger.error(err);
emitter.emit("dismissLoader");
return;
}

if(parentRouting?.rules?.length) {
const parentRoutingRules = await Promise.all(parentRouting.rules.map((rule: any) => OrderRoutingService.fetchRule(rule.routingRuleId)))
parentRouting["rulesInformation"] = parentRoutingRules.reduce((rulesInformation: any, rule: any) => {
rulesInformation[rule.data.ruleName] = rule.data
return rulesInformation
}, {})
}

// Payload for applying routing filters and rules in the cloned routing
const routingPayload = {
orderRoutingId,
routingGroupId: parentRouting.routingGroupId,
orderFilters: parentRouting.orderFilters?.length ? parentRouting.orderFilters.reduce((filters: any, filter: any) => {
filters.push({
conditionTypeEnumId: filter.conditionTypeEnumId,
fieldName: filter.fieldName,
fieldValue: filter.fieldValue,
operator: filter.operator,
sequenceNum: filter.sequenceNum,
createdDate: DateTime.now().toMillis(),
orderRoutingId
})
return filters
}, []) : [],
rules: parentRouting.rules?.length ? parentRouting.rules.reduce((rules: any, rule: any) => {
rules.push({
assignmentEnumId: rule.assignmentEnumId,
createdDate: DateTime.now().toMillis(),
ruleName: rule.ruleName,
sequenceNum: rule.sequenceNum,
statusId: "RULE_DRAFT",
orderRoutingId
})
return rules
}, []) : []
}

if(!routingPayload.orderFilters.length && !routingPayload.rules.length) {
emitter.emit("dismissLoader")
return;
showToast(translate("Failed to clone brokering run"))
logger.error(err)
}
}

await store.dispatch("orderRouting/updateRouting", routingPayload)

let clonedRoutingRules = {} as any;

// As we do not have routingRuleId's for the rules created inside the cloned routing, hence fetching the rule ids
if(Object.keys(parentRouting["rulesInformation"])?.length) {
try {
const resp = await OrderRoutingService.fetchOrderRouting(orderRoutingId);
if(!hasError(resp) && resp.data?.rules?.length) {
clonedRoutingRules = resp.data.rules.reduce((rules: any, rule: any) => {
rules[rule.ruleName] = rule.routingRuleId
return rules
}, {})
} else {
throw resp.data
}
} catch(err) {
logger.error(err)
}
}
async function cloneRouting(routing: any) {
emitter.emit("presentLoader", { message: "Cloning route", backdropDismiss: false })

if(Object.keys(clonedRoutingRules).length) {
await Promise.all(Object.values(parentRouting["rulesInformation"]).map((rule: any) => {
store.dispatch("orderRouting/updateRule", {
routingRuleId: clonedRoutingRules[rule.ruleName],
orderRoutingId,
inventoryFilters: rule.inventoryFilters?.length ? rule.inventoryFilters.map((filter: any) => ({
createdDate: DateTime.now().toMillis(),
conditionTypeEnumId: filter.conditionTypeEnumId,
fieldName: filter.fieldName,
fieldValue: filter.fieldValue,
operator: filter.operator,
sequenceNum: filter.sequenceNum,
})) : [],
actions: rule.actions?.length ? rule.actions.map((filter: any) => ({
actionTypeEnumId: filter.actionTypeEnumId,
actionValue: filter.actionValue,
createdDate: DateTime.now().toMillis(),
})) : []
})
}))
}
const orderRoutingId = await store.dispatch("orderRouting/cloneOrderRouting", {
orderRoutingId: routing.orderRoutingId,
orderRoutingName: routing.routingName,
routingGroupId: props.routingGroupId
})

// update the routing order for reordering and the cloned updated routings again
// Updating the order routings as we have created a new route that needs to be added on the UI
if(orderRoutingId) {
orderRoutings.value = JSON.parse(JSON.stringify(currentRoutingGroup.value))["routings"]
initializeOrderRoutings();
orderRoutings.value = currentRoutingGroup.value["routings"] ? JSON.parse(JSON.stringify(currentRoutingGroup.value))["routings"] : []
initializeOrderRoutings()
}

emitter.emit("dismissLoader")
Expand Down
Loading