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: order details page on packed tab (#284) #330

Merged
merged 12 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from 6 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
4 changes: 4 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"Failed to update configuration": "Failed to update configuration",
"First name": "First name",
"Generate packing slips": "Generate packing slips",
"Generate shipping documents": "Generate shipping documents",
"Go to OMS": "Go to OMS",
"Go to Launchpad": "Go to Launchpad",
"Handover": "Handover",
Expand Down Expand Up @@ -88,6 +89,8 @@
"Order details": "Order details",
"Order edit permissions": "Order edit permissions",
"Order is now ready to handover.": "Order is now ready to handover.",
"Order is successfully handed over to customer.": "Order is successfully handed over to customer.",
"Order is successfully shipped.": "Order is successfully shipped.",
"Order has been rejected.": "Order has been rejected.",
"Order marked as ready for pickup, an email notification has been sent to the customer": "Order marked as ready for pickup, an email notification has been sent to the customer",
"Order marked as ready for pickup but something went wrong while sending the email notification": "Order marked as ready for pickup but something went wrong while sending the email notification",
Expand Down Expand Up @@ -120,6 +123,7 @@
"Reject Order Item": "Reject Order Item",
"Reason": "Reason",
"Report an issue": "Report an issue",
"Resend customer email": "Resend customer email",
"Resend ready for pickup email": "Resend ready for pickup email",
"Search": "Search",
"Search Orders": "Search Orders",
Expand Down
2 changes: 1 addition & 1 deletion src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const routes: Array<RouteRecordRaw> = [
beforeEnter: loginGuard
},
{
path: "/orderdetail/:orderId/:orderPartSeqId",
path: "/orderdetail/:orderType/:orderId/:orderPartSeqId",
name: "OrderDetail",
component: OrderDetail,
beforeEnter: authGuard,
Expand Down
32 changes: 25 additions & 7 deletions src/store/modules/order/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,21 @@
return resp;
},

async getOrderDetail( { dispatch, state }, payload ) {
async getOrderDetail( { dispatch, state }, { payload, orderType } ) {
if(orderType === 'open') {
payload['orderStatusId']= "ORDER_APPROVED"
payload['-shipmentStatusId']= "*"
} else if(orderType === 'packed') {
payload['shipmentStatusId']= "SHIPMENT_PACKED"
} else {
dispatch('order/updateCurrent', { order: {} })
return;
}

const current = state.current as any
const orders = JSON.parse(JSON.stringify(state.open.list)) as any
// As one order can have multiple parts thus checking orderId and partSeq as well before making any api call
if(current.orderId === payload.orderId && current.part?.orderPartSeqId === payload.orderPartSeqId) {
if(current.orderId === payload.orderId && current.orderType === orderType && current.part?.orderPartSeqId === payload.orderPartSeqId) {
this.dispatch('product/getProductInformation', { orders: [ current ] })
return current
}
Expand All @@ -114,12 +124,12 @@
return order;
}
}


const orderQueryPayload = prepareOrderQuery({
...payload,
shipmentMethodTypeId: !store.state.user.preference.showShippingOrders ? 'STOREPICKUP' : '',
'-shipmentStatusId': '*',
'-fulfillmentStatus': '(Cancelled OR Rejected)',
orderStatusId: 'ORDER_APPROVED',
orderTypeId: 'SALES_ORDER'
})

Expand Down Expand Up @@ -166,7 +176,8 @@
return arr
}, []),
placedDate: orderItem.orderDate,
shippingInstructions: orderItem.shippingInstructions
shippingInstructions: orderItem.shippingInstructions,
orderType: orderType
}
})

Expand Down Expand Up @@ -338,7 +349,7 @@
return resp;
},

async deliverShipment ({ state, commit }, order) {
async deliverShipment ({ state, dispatch, commit }, order) {
emitter.emit("presentLoader");
const params = {
shipmentId: order.shipmentId,
Expand All @@ -362,7 +373,14 @@
state.packed.list.splice(orderIndex, 1);
commit(types.ORDER_PACKED_UPDATED, { orders: state.packed.list, total: state.packed.total -1 })
}
showToast(translate('Order delivered to', {customerName: order.customer.name}))

if(order.part.shipmentMethodEnum.shipmentMethodEnumId === 'STOREPICKUP'){
order = { ...order, handovered: true }
}else {
order = { ...order, shipped: true }
}

dispatch('updateCurrent', { order })
} else {
showToast(translate("Something went wrong"))
}
Expand All @@ -376,7 +394,7 @@
return resp;
},

async packDeliveryItems ({ commit }, shipmentId) {

Check warning on line 397 in src/store/modules/order/actions.ts

View workflow job for this annotation

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

'commit' is defined but never used
const params = {
shipmentId: shipmentId,
statusId: 'SHIPMENT_PACKED'
Expand Down Expand Up @@ -488,7 +506,7 @@
}).catch(err => err);
},

async rejectOrderItems ({ commit }, order) {

Check warning on line 509 in src/store/modules/order/actions.ts

View workflow job for this annotation

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

'commit' is defined but never used
const payload = {
'orderId': order.orderId
}
Expand Down
131 changes: 114 additions & 17 deletions src/views/OrderDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@
<ion-back-button default-href="/" slot="start" />
<ion-title>{{ translate("Order details") }}</ion-title>
<ion-buttons slot="end">
<ion-button v-if="orderType === 'packed' && order.part.shipmentMethodEnum.shipmentMethodEnumId === 'STOREPICKUP'" class="ion-hide-md-up" :disabled="!hasPermission(Actions.APP_ORDER_UPDATE) || order.handovered || order.shipped" @click="sendReadyForPickupEmail(order)">
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved
<ion-icon slot="icon-only" :icon="mailOutline" />
</ion-button>
<ion-button :disabled="!order?.orderId" @click="openOrderItemRejHistoryModal()">
<ion-icon slot="icon-only" :icon="timeOutline" />
</ion-button>
<ion-button class="ion-hide-md-up" :disabled="!hasPermission(Actions.APP_ORDER_UPDATE) || order?.readyToHandover || order?.rejected" @click="rejectOrder()">
<ion-button v-if="orderType === 'open'" class="ion-hide-md-up" :disabled="!hasPermission(Actions.APP_ORDER_UPDATE) || order.readyToHandover || order.rejected" @click="rejectOrder()">
<ion-icon slot="icon-only" color="danger" :icon="bagRemoveOutline" />
</ion-button>
<ion-button v-if="orderType === 'packed' && showPackingSlip" class="ion-hide-md-up" :disabled="!hasPermission(Actions.APP_ORDER_UPDATE) || order?.handovered || order?.shipped" @click="printPackingSlip(order)">
<ion-icon slot="icon-only" :icon="printOutline" />
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
Expand All @@ -22,10 +28,14 @@
</div>
<main v-else>
<aside>
<ion-item v-if="order?.readyToHandover || order?.rejected" color="light" lines="none">
<ion-item v-if="order.readyToHandover || order.rejected" color="light" lines="none">
<ion-icon :icon="order.readyToHandover ? checkmarkCircleOutline : closeCircleOutline" :color="order.readyToHandover ? 'success' : 'danger'" slot="start" />
<ion-label class="ion-text-wrap">{{ order.readyToHandover ? translate("Order is now ready to handover.") : translate("Order has been rejected.") }}</ion-label>
</ion-item>
<ion-item v-if="order.handovered || order.shipped" color="light" lines="none">
<ion-icon :icon="checkmarkCircleOutline" color="success" slot="start" />
<ion-label class="ion-text-wrap">{{ order.handovered ? translate("Order is successfully handed over to customer.") : translate("Order is successfully shipped.") }}</ion-label>
</ion-item>
<ion-item lines="none">
<ion-label class="ion-text-wrap">
<h2>{{ order?.orderName ? order?.orderName : order?.orderId }}</h2>
Expand Down Expand Up @@ -56,21 +66,35 @@
<p>{{ order.shippingInstructions }}</p>
</ion-label>
</ion-item>
<div class="ion-margin-top ion-hide-md-down">
<!-- TODO: implement functionality to change shipping address -->
<ion-button :disabled="!hasPermission(Actions.APP_ORDER_UPDATE) || order?.readyToHandover || order?.rejected" expand="block" @click.stop="readyForPickup(order, order.part)">
<ion-item v-if="orderType === 'packed'" lines="none">
<ion-label class="ion-text-wrap">
{{ translate("Picked by", { pickers: order.pickers }) }}
</ion-label>
</ion-item>
<div v-if="orderType === 'open'" class="ion-margin-top ion-hide-md-down">
<ion-button :disabled="!hasPermission(Actions.APP_ORDER_UPDATE) || order.readyToHandover || order.rejected" expand="block" @click.stop="readyForPickup(order, order.part)">
{{ order?.part?.shipmentMethodEnum?.shipmentMethodEnumId === 'STOREPICKUP' ? translate("Ready for pickup") : translate("Ready to ship") }}
</ion-button>
<ion-button :disabled="!hasPermission(Actions.APP_ORDER_UPDATE) || order?.readyToHandover || order?.rejected" expand="block" color="danger" fill="outline" @click="rejectOrder()">
<ion-button :disabled="!hasPermission(Actions.APP_ORDER_UPDATE) || order.readyToHandover || order.rejected" expand="block" color="danger" fill="outline" @click="rejectOrder()">
{{ translate("Reject Order") }}
</ion-button>
</div>

<div v-if="orderType === 'packed'" class="ion-margin-top ion-hide-md-down">
<!-- TODO: implement functionality to change shipping address -->
<ion-button :disabled="!hasPermission(Actions.APP_ORDER_UPDATE) || order.handovered || order.shipped" expand="block" fill="outline" @click.stop="order?.part?.shipmentMethodEnum?.shipmentMethodEnumId === 'STOREPICKUP' ? sendReadyForPickupEmail(order) : ''">
{{ order?.part?.shipmentMethodEnum?.shipmentMethodEnumId === 'STOREPICKUP' ? translate("Resend customer email") : translate("Generate shipping documents") }}
</ion-button>
<ion-button :disabled="!hasPermission(Actions.APP_ORDER_UPDATE) || order.handovered || order.shipped" expand="block" @click.stop="deliverShipment(order)">
{{ order.part.shipmentMethodEnum.shipmentMethodEnumId === 'STOREPICKUP' ? translate("Handover") : translate("Ship") }}
</ion-button>
</div>
</aside>
<section>
<ion-card v-for="(item, index) in order.part?.items" :key="index">
<ProductListItem :item="item" />
<!-- Checking for true as a string as the settingValue contains a string and not boolean-->
<div v-if="partialOrderRejectionConfig?.settingValue == 'true'" class="border-top">
<div v-if="partialOrderRejectionConfig?.settingValue == 'true' && orderType === 'open'" class="border-top">
<ion-button :disabled="order?.readyToHandover || order?.rejected" fill="clear" @click="openReportAnIssueModal(item)">
{{ translate("Report an issue") }}
</ion-button>
Expand All @@ -80,11 +104,16 @@
</section>
</main>

<ion-fab v-if="order?.orderId" class="ion-hide-md-up" vertical="bottom" horizontal="end" slot="fixed" @click="readyForPickup(order, order.part)">
<ion-fab-button :disabled="!hasPermission(Actions.APP_ORDER_UPDATE) || order?.readyToHandover || order?.rejected">
<ion-fab v-if="order?.orderId && orderType === 'open'" class="ion-hide-md-up" vertical="bottom" horizontal="end" slot="fixed" @click="readyForPickup(order, order.part)">
<ion-fab-button :disabled="!hasPermission(Actions.APP_ORDER_UPDATE) || order.readyToHandover || order.rejected">
<ion-icon :icon="bagHandleOutline" />
</ion-fab-button>
</ion-fab>
<ion-fab v-else-if="order?.orderId && orderType === 'packed'" class="ion-hide-md-up" vertical="bottom" horizontal="end" slot="fixed" @click="deliverShipment(order)">
<ion-fab-button :disabled="!hasPermission(Actions.APP_ORDER_UPDATE) || order.handovered || order.shipped">
<ion-icon :icon="order.part.shipmentMethodEnum.shipmentMethodEnumId === 'STOREPICKUP' ? accessibilityOutline : checkmarkOutline" />
</ion-fab-button>
</ion-fab>
</ion-content>
</ion-page>
</template>
Expand Down Expand Up @@ -114,11 +143,14 @@ import {
import { defineComponent } from "vue";
import { mapGetters, useStore } from "vuex";
import {
accessibilityOutline,
cashOutline,
copyOutline,
closeCircleOutline,
checkmarkCircleOutline,
checkmarkOutline,
mailOutline,
printOutline,
sendOutline,
bagHandleOutline,
bagRemoveOutline,
Expand All @@ -130,9 +162,9 @@ import { Actions, hasPermission } from '@/authorization'
import OrderItemRejHistoryModal from '@/components/OrderItemRejHistoryModal.vue';
import ReportAnIssueModal from '@/components/ReportAnIssueModal.vue';
import AssignPickerModal from "@/views/AssignPickerModal.vue";
import { copyToClipboard } from '@/utils'
import { copyToClipboard, showToast } from '@/utils'
import { DateTime } from "luxon";
import { hasError } from '@/adapter';
import { api, hasError } from '@/adapter';
import ShipToCustomerModal from "@/components/ShipToCustomerModal.vue";
import { OrderService } from "@/services/OrderService";
import RejectOrderModal from "@/components/RejectOrderModal.vue";
Expand Down Expand Up @@ -162,7 +194,8 @@ export default defineComponent({
},
data() {
return {
customerEmail: ''
customerEmail: '',
orderType: this.$route.params.orderType
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved
}
},
computed: {
Expand All @@ -172,7 +205,8 @@ export default defineComponent({
configurePicker: "user/configurePicker",
partialOrderRejectionConfig: 'user/getPartialOrderRejectionConfig',
getPaymentMethodDesc: 'util/getPaymentMethodDesc',
getStatusDesc: 'util/getStatusDesc'
getStatusDesc: 'util/getStatusDesc',
showPackingSlip: 'user/showPackingSlip',
})
},
methods: {
Expand All @@ -183,6 +217,9 @@ export default defineComponent({
});
return assignPickerModal.present();
},
async deliverShipment(order: any) {
await this.store.dispatch('order/deliverShipment', order)
},
async openOrderItemRejHistoryModal() {
const orderItemRejHistoryModal = await modalController.create({
component: OrderItemRejHistoryModal,
Expand All @@ -196,13 +233,13 @@ export default defineComponent({
});
return reportAnIssueModal.present();
},
async getOrderDetail(orderId: any, orderPartSeqId: any) {
async getOrderDetail(orderId: any, orderPartSeqId: any, orderType: any) {
const payload = {
facilityId: this.currentFacility.facilityId,
orderId,
orderPartSeqId
}
await this.store.dispatch("order/getOrderDetail", payload)
await this.store.dispatch("order/getOrderDetail", { payload, orderType })
await this.store.dispatch("order/fetchPaymentDetail")
},
async rejectOrder() {
Expand Down Expand Up @@ -240,6 +277,33 @@ export default defineComponent({
const timeDiff = DateTime.fromISO(time).diff(DateTime.local());
return DateTime.local().plus(timeDiff).toRelative();
},
async printPackingSlip(order: any) {
try {
// Get packing slip from the server
const response: any = await api({
method: 'get',
url: 'PackingSlip.pdf',
params: {
shipmentId: order.shipmentId
},
responseType: "blob"
})

if (!response || response.status !== 200 || hasError(response)) {
showToast(translate("Failed to load packing slip"))
return;
}

// Generate local file URL for the blob received
const pdfUrl = window.URL.createObjectURL(response.data);
// Open the file in new tab
(window as any).open(pdfUrl, "_blank").focus();
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved

} catch(err) {
showToast(translate("Failed to load packing slip"))
console.error(err)
}
},
async shipToCustomer() {
const shipmodal = await modalController.create({
component: ShipToCustomerModal,
Expand All @@ -255,10 +319,40 @@ export default defineComponent({
} catch (error) {
console.error(error)
}
}
},
async sendReadyForPickupEmail(order: any) {
const header = translate('Resend ready for pickup email')
const message = translate('An email notification will be sent to that their order is ready for pickup.', { customerName: order.customer.name });

const alert = await alertController
.create({
header: header,
message: message,
buttons: [{
text: translate('Cancel'),
role: 'cancel'
},{
text: translate('Send'),
handler: async () => {
try {
const resp = await OrderService.sendPickupScheduledNotification({ shipmentId: order.shipmentId });
if (!hasError(resp)) {
showToast(translate("Email sent successfully"))
} else {
showToast(translate("Something went wrong while sending the email."))
}
} catch (error) {
showToast(translate("Something went wrong while sending the email."))
console.error(error)
}
}
}]
});
return alert.present();
},
},
async mounted() {
await this.getOrderDetail(this.$route.params.orderId, this.$route.params.orderPartSeqId);
await this.getOrderDetail(this.$route.params.orderId, this.$route.params.orderPartSeqId, this.$route.params.orderType);

// fetch customer details and rejection reasons only when we get the orders information
if(this.order.orderId) {
Expand All @@ -272,14 +366,17 @@ export default defineComponent({

return {
Actions,
accessibilityOutline,
bagHandleOutline,
bagRemoveOutline,
cashOutline,
copyOutline,
copyToClipboard,
closeCircleOutline,
checkmarkCircleOutline,
checkmarkOutline,
hasPermission,
printOutline,
router,
store,
timeOutline,
Expand Down
Loading
Loading