-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Improved: support for adding tracking details while packing (#704)
- Loading branch information
Showing
6 changed files
with
346 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,283 @@ | ||
<template> | ||
<ion-header> | ||
<ion-toolbar> | ||
<ion-buttons slot="start"> | ||
<ion-button @click="closeModal"> | ||
<ion-icon slot="icon-only" :icon="closeOutline" /> | ||
</ion-button> | ||
</ion-buttons> | ||
<ion-title>{{ translate("Pack order") }}</ion-title> | ||
</ion-toolbar> | ||
</ion-header> | ||
|
||
<ion-content> | ||
<ion-list> | ||
<ion-item lines="none"> | ||
<ion-label>{{ translate(isTrackingRequired ? "Tracking details are required in order to pack this shipment. Try generating a label from the selected carrier or enter a tracking code manually." : "Tracking details are missing in order to pack this shipment. Try generating a label from the selected carrier or enter a tracking code manually.") }}</ion-label> | ||
</ion-item> | ||
|
||
<ion-item> | ||
<ion-select :disabled="!order.missingLabelImage" :label="translate('Carrier')" v-model="carrierPartyId" interface="popover" @ionChange="updateCarrier(carrierPartyId)"> | ||
<ion-select-option v-for="carrier in facilityCarriers" :key="carrier.partyId" :value="carrier.partyId">{{ translate(carrier.groupName) }}</ion-select-option> | ||
</ion-select> | ||
</ion-item> | ||
<ion-item> | ||
<ion-select :disabled="!order.missingLabelImage" :label="translate('Method')" v-model="shipmentMethodTypeId" interface="popover"> | ||
<ion-select-option v-for="method in carrierMethods" :key="method.productStoreShipMethId" :value="method.shipmentMethodTypeId">{{ translate(method.description) }}</ion-select-option> | ||
</ion-select> | ||
</ion-item> | ||
<ion-item> | ||
<ion-input :label="translate('Tracking code')" :placeholder="translate('enter code')" v-model="trackingCode" /> | ||
</ion-item> | ||
<ion-item> | ||
<ion-label>{{ translate("Tracking URL:", { trackingUrl: generateTrackingUrl() }) }}</ion-label> | ||
<ion-button slot="end" fill="clear" size="default" :disabled="!trackingCode.trim() || !getCarrierTrackingUrl()" @click="redirectToTrackingUrl()"> | ||
{{ translate("Test") }} | ||
<ion-icon :icon="openOutline" slot="end" /> | ||
</ion-button> | ||
</ion-item> | ||
</ion-list> | ||
</ion-content> | ||
|
||
<ion-fab vertical="bottom" horizontal="end" slot="fixed"> | ||
<ion-fab-button :disabled="isTrackingRequired ? !shipmentMethodTypeId: ''" @click="confirmSave()"> | ||
<ion-icon :icon="isForceScanEnabled ? barcodeOutline : saveOutline" /> | ||
</ion-fab-button> | ||
</ion-fab> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import { | ||
IonButton, | ||
IonButtons, | ||
IonContent, | ||
IonFab, | ||
IonFabButton, | ||
IonHeader, | ||
IonIcon, | ||
IonInput, | ||
IonItem, | ||
IonLabel, | ||
IonList, | ||
IonSelect, | ||
IonSelectOption, | ||
IonTitle, | ||
IonToolbar, | ||
modalController, | ||
} from "@ionic/vue"; | ||
import { defineComponent } from "vue"; | ||
import { barcodeOutline, closeOutline, copyOutline, openOutline, saveOutline } from "ionicons/icons"; | ||
import { translate } from "@hotwax/dxp-components"; | ||
import { mapGetters, useStore } from "vuex"; | ||
import { OrderService } from '@/services/OrderService'; | ||
import logger from "@/logger"; | ||
import { showToast } from "@/utils"; | ||
import { hasError } from "@/adapter"; | ||
export default defineComponent({ | ||
name: "GenerateTrackingCodeModal", | ||
components: { | ||
IonButton, | ||
IonButtons, | ||
IonContent, | ||
IonFab, | ||
IonFabButton, | ||
IonHeader, | ||
IonIcon, | ||
IonInput, | ||
IonItem, | ||
IonLabel, | ||
IonList, | ||
IonSelect, | ||
IonSelectOption, | ||
IonTitle, | ||
IonToolbar, | ||
}, | ||
computed: { | ||
...mapGetters({ | ||
facilityCarriers: 'carrier/getFacilityCarriers', | ||
isForceScanEnabled: 'util/isForceScanEnabled', | ||
productStoreShipmentMethods: 'carrier/getProductStoreShipmentMethods', | ||
productStoreShipmentMethCount: 'util/getProductStoreShipmentMethCount', | ||
}) | ||
}, | ||
data() { | ||
return { | ||
isTrackingRequired: false, | ||
carrierMethods:[] as any, | ||
carrierPartyId: "", | ||
shipmentMethodTypeId: "", | ||
trackingCode: "", | ||
isGeneratingShippingLabel: false | ||
} | ||
}, | ||
props: ["order", "updateCarrierShipmentDetails"], | ||
async mounted() { | ||
this.isTrackingRequired = this.isTrackingRequiredForAnyShipmentPackage() | ||
if(this.facilityCarriers) { | ||
const shipmentPackage = this.order.shipmentPackages?.[0]; | ||
this.carrierPartyId = shipmentPackage?.carrierPartyId ? shipmentPackage?.carrierPartyId : this.facilityCarriers[0].partyId; | ||
this.carrierMethods = await this.getProductStoreShipmentMethods(this.carrierPartyId); | ||
this.shipmentMethodTypeId = shipmentPackage?.shipmentMethodTypeId; | ||
} | ||
}, | ||
methods: { | ||
closeModal(payload = {}) { | ||
modalController.dismiss({ dismissed: true, ...payload }); | ||
}, | ||
isTrackingRequiredForAnyShipmentPackage() { | ||
return this.order.shipmentPackages?.some((shipmentPackage: any) => shipmentPackage.isTrackingRequired === 'Y') | ||
}, | ||
async getProductStoreShipmentMethods(carrierPartyId: string) { | ||
return this.productStoreShipmentMethods?.filter((method: any) => method.partyId === carrierPartyId) || []; | ||
}, | ||
async updateCarrier(carrierPartyId: string) { | ||
this.carrierMethods = await this.getProductStoreShipmentMethods(carrierPartyId); | ||
this.shipmentMethodTypeId = this.carrierMethods?.[0]?.shipmentMethodTypeId; | ||
}, | ||
async confirmSave() { | ||
let order = this.order | ||
let isRegenerated = false as any; | ||
// if the request to print shipping label is not yet completed, then clicking multiple times on the button | ||
// should not do anything | ||
if(this.isGeneratingShippingLabel) { | ||
return; | ||
} | ||
this.isGeneratingShippingLabel = true; | ||
const isUpdated = await this.updateCarrierAndShippingMethod(this.carrierPartyId, this.shipmentMethodTypeId) | ||
if(!isUpdated) { | ||
showToast(translate("Failed to update shipment method detail.")); | ||
return; | ||
} | ||
if(this.trackingCode.trim()) { | ||
isRegenerated = await this.addTrackingCode(order); | ||
} else if(this.shipmentMethodTypeId) { | ||
isRegenerated = await this.regenerateShippingLabel(order) | ||
} | ||
//fetching updated shipment packages | ||
await this.store.dispatch('order/updateShipmentPackageDetail', order) | ||
if(isRegenerated || !this.isTrackingRequired) { | ||
this.closeModal({ moveToNext: true }); | ||
} | ||
this.isGeneratingShippingLabel = false; | ||
}, | ||
async addTrackingCode(order: any) { | ||
try { | ||
for (const shipmentPackage of order.shipmentPackages) { | ||
await OrderService.addTrackingCode({ | ||
"shipmentId": shipmentPackage.shipmentId, | ||
"shipmentRouteSegmentId": shipmentPackage.shipmentRouteSegmentId, | ||
"shipmentPackageSeqId": shipmentPackage.shipmentPackageSeqId, | ||
"trackingCode": this.trackingCode.trim() | ||
}); | ||
} | ||
} catch (error: any) { | ||
logger.error('Failed to add tracking code', error); | ||
showToast(translate("Failed to add tracking code.")); | ||
return false; | ||
} | ||
return true; | ||
}, | ||
async regenerateShippingLabel(order: any) { | ||
// If there are no product store shipment method configured, then not generating the label and displaying an error toast | ||
if(this.productStoreShipmentMethCount <= 0) { | ||
showToast(translate("Unable to generate shipping label due to missing product store shipping method configuration")) | ||
return false; | ||
} | ||
// Getting all the shipmentIds from shipmentPackages for which label is missing | ||
const shipmentIds = order.shipmentPackages | ||
?.filter((shipmentPackage: any) => !shipmentPackage.trackingCode) | ||
.map((shipmentPackage: any) => shipmentPackage.shipmentId); | ||
if(!shipmentIds?.length) { | ||
showToast(translate("Failed to generate shipping label")) | ||
return false; | ||
} | ||
try { | ||
const resp = await OrderService.retryShippingLabel(shipmentIds) | ||
if(hasError(resp)) { | ||
throw resp.data; | ||
} | ||
} catch(error: any) { | ||
logger.error(error); | ||
showToast(translate("Failed to generate shipping label")) | ||
return false; | ||
} | ||
return true; | ||
}, | ||
getCarrierTrackingUrl() { | ||
return this.facilityCarriers.find((carrier: any) => carrier.partyId === this.carrierPartyId)?.trackingUrl | ||
}, | ||
generateTrackingUrl() { | ||
if(this.getCarrierTrackingUrl()) { | ||
return this.getCarrierTrackingUrl()?.replace("${trackingNumber}", this.trackingCode) | ||
} | ||
return translate("A tracking URL not configured for", { carrierName: this.getCarrierName() }) | ||
}, | ||
getCarrierName() { | ||
return this.facilityCarriers.find((carrier: any) => carrier.partyId === this.carrierPartyId)?.groupName | ||
}, | ||
async updateCarrierAndShippingMethod(carrierPartyId: string, shipmentMethodTypeId: string) { | ||
let resp; | ||
try{ | ||
const carrierShipmentMethods = await this.getProductStoreShipmentMethods(carrierPartyId); | ||
shipmentMethodTypeId = shipmentMethodTypeId ? shipmentMethodTypeId : carrierShipmentMethods?.[0]?.shipmentMethodTypeId; | ||
const params = { | ||
orderId: this.order.orderId, | ||
shipGroupSeqId: this.order.shipGroupSeqId, | ||
shipmentMethodTypeId : shipmentMethodTypeId ? shipmentMethodTypeId : "", | ||
carrierPartyId | ||
} | ||
resp = await OrderService.updateOrderItemShipGroup(params) | ||
if(!hasError(resp)) { | ||
for (const shipmentPackage of this.order.shipmentPackages) { | ||
resp = await OrderService.updateShipmentRouteSegment({ | ||
"shipmentId": shipmentPackage.shipmentId, | ||
"shipmentRouteSegmentId": shipmentPackage.shipmentRouteSegmentId, | ||
"carrierPartyId": carrierPartyId, | ||
"shipmentMethodTypeId" : shipmentMethodTypeId ? shipmentMethodTypeId : "", | ||
}) as any; | ||
if(hasError(resp)) { | ||
throw resp.data; | ||
} | ||
} | ||
} else { | ||
throw resp.data; | ||
} | ||
} catch(error: any) { | ||
logger.error("Failed to update carrier and method", error); | ||
return false; | ||
} | ||
this.updateCarrierShipmentDetails && this.updateCarrierShipmentDetails(carrierPartyId, shipmentMethodTypeId); | ||
return true; | ||
}, | ||
redirectToTrackingUrl() { | ||
window.open(this.getCarrierTrackingUrl().replace("${trackingNumber}", this.trackingCode), "_blank"); | ||
} | ||
}, | ||
setup() { | ||
const store = useStore(); | ||
return { | ||
barcodeOutline, | ||
closeOutline, | ||
copyOutline, | ||
openOutline, | ||
saveOutline, | ||
store, | ||
translate | ||
}; | ||
}, | ||
}); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.