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: functionality which allows users to manually close purchase order items when they receive them. (#212) #258

Merged
merged 16 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
9df9dfc
Implemented: functionality which allows users to manually close purch…
amansinghbais Aug 29, 2023
50a4221
Improved: code for closePO's modal (#212)
amansinghbais Sep 11, 2023
556f7d1
Improved: code for close PO items (#212)
amansinghbais Sep 11, 2023
076243a
Merge branch 'main' of https://github.com/hotwax/receiving into recei…
amansinghbais Sep 18, 2023
9770a27
Improved: indentation, casing, conditions (#212)
amansinghbais Sep 18, 2023
75398ef
Improved: conditions which are not required and if syntax (#212)
amansinghbais Sep 20, 2023
3c07e28
Improved: used emitter to call parent component function from modal (…
amansinghbais Oct 9, 2023
09dd51b
Improved: logic to call changeOrderItemStatus api and show Toast acco…
amansinghbais Oct 11, 2023
57fc6b2
Improved: better alternative for statusUpdated Variable (#212)
amansinghbais Oct 12, 2023
59f1e69
Merge branch 'main' of https://github.com/hotwax/receiving into recei…
amansinghbais Oct 16, 2023
f6ea9d5
Improved: code to handle newly added items (#212)
amansinghbais Oct 17, 2023
9571d70
Improved: promise.allsettled response handling (#212)
amansinghbais Oct 17, 2023
75c5c83
Improved: code for handling item selection for status update (#212)
amansinghbais Oct 18, 2023
878850c
Fixed: removed comments from the api parameters (#212)
amansinghbais Oct 18, 2023
ac43b04
Improved: optimized way of writing conditions (#212)
amansinghbais Oct 18, 2023
6cd37f6
Improved: variable name and comments (#212)
amansinghbais Oct 18, 2023
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
6 changes: 6 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"App": "App",
"Authenticating": "Authenticating",
"Are you sure you want to change the time zone to?": "Are you sure you want to change the time zone to {timeZoneId}?",
"Are you sure you have received the purchase order for the selected items? Once closed, the shipments for the selected items wont be available for receiving later.": "Are you sure you have received the purchase order for the selected items? { space } Once closed, the shipments for the selected items won't be available for receiving later.",
"Arrival date": "Arrival date",
"Cancel": "Cancel",
"Change": "Change",
Expand All @@ -14,6 +15,7 @@
"Complete": "Complete",
"Confirm": "Confirm",
"Copied": "Copied { value }",
"Close purchase order items": "Close purchase order items",
"eCom Store": "eCom Store",
"Enter a custom date time format that you want to use when uploading documents to HotWax Commerce.": "Enter a custom date time format that you want to use when uploading documents to HotWax Commerce.",
"External ID": "External ID",
Expand Down Expand Up @@ -59,8 +61,10 @@
"Purchase Order Details": "Purchase Order Details",
"Purchase Orders": "Purchase Orders",
"Qty": "Qty",
"Receive": "Receive",
"Receive All": "Receive All",
"Receive inventory": "Receive inventory",
"Receive And Close": "Receive And Close",
"received": "received",
"Receive Shipment": "Receive Shipment",
"Receiving": "Receiving",
Expand All @@ -82,6 +86,7 @@
"Search time zones": "Search time zones",
"Search SKU or product name": "Search SKU or product name",
"Secondary Product Identifier": "Secondary Product Identifier",
"Select all": "Select all",
"Select facility": "Select facility",
"Select store": "Select store",
"Select time zone": "Select time zone",
Expand All @@ -107,6 +112,7 @@
"This return has been and cannot be edited.": "This return has been {status} and cannot be edited.",
"Timezone": "Timezone",
"Time zone updated successfully": "Time zone updated successfully",
"To close the purchase order, select all.": "To close the purchase order, select all.",
"Unable to update product identifier preference": "Unable to update product identifier preference",
"Update time zone": "Update time zone",
"Username": "Username",
Expand Down
10 changes: 9 additions & 1 deletion src/services/OrderService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,18 @@ const fetchPOHistory = async (payload: any): Promise<any> => {
})
}

const updatePOItemStatus = async (payload: any): Promise<any> => {
return api({
url: "/changeOrderItemStatus",
method: "POST",
data: payload
})
}

export const OrderService = {
fetchPurchaseOrders,
fetchPODetail,
createPurchaseShipment,
fetchPOHistory
fetchPOHistory,
updatePOItemStatus
}
33 changes: 23 additions & 10 deletions src/views/PurchaseOrderDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,16 @@
</div>
</ion-card>
</main>

<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button :disabled="!hasPermission(Actions.APP_SHIPMENT_UPDATE) || !isEligibileForCreatingShipment()" @click="savePODetails">
<ion-icon :icon="saveOutline" />
</ion-fab-button>
</ion-fab>
</ion-content>

<ion-footer>
<ion-toolbar>
<ion-item slot="end">
<ion-button :disabled="!hasPermission(Actions.APP_SHIPMENT_UPDATE)" fill="outline" class="ion-margin-end" @click="saveAndClosePODetails">{{ $t("Receive And Close") }}</ion-button>
<ion-button :disabled="!hasPermission(Actions.APP_SHIPMENT_UPDATE) || !isEligibileForCreatingShipment()" @click="savePODetails">{{ $t("Receive") }}</ion-button>
</ion-item>
</ion-toolbar>
</ion-footer>
</ion-page>
</template>

Expand All @@ -111,8 +114,7 @@ import {
IonChip,
IonContent,
IonHeader,
IonFab,
IonFabButton,
IonFooter,
IonIcon,
IonItem,
IonInput,
Expand All @@ -133,6 +135,7 @@ import { useStore, mapGetters } from 'vuex';
import { useRouter } from 'vue-router';
import Scanner from "@/components/Scanner.vue"
import AddProductToPOModal from '@/views/AddProductToPOModal.vue'
import closePurchaseOrderModal from '@/views/closePurchaseOrderModal.vue'
import LocationPopover from '@/components/LocationPopover.vue'
import ImageModal from '@/components/ImageModal.vue';
import { copyToClipboard, hasError, productHelpers } from '@/utils';
Expand All @@ -150,8 +153,7 @@ export default defineComponent({
IonChip,
IonContent,
IonHeader,
IonFab,
IonFabButton,
IonFooter,
IonIcon,
IonItem,
IonInput,
Expand Down Expand Up @@ -241,6 +243,17 @@ export default defineComponent({
});
return alert.present();
},
async saveAndClosePODetails() {
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved
const modal = await modalController.create({
component: closePurchaseOrderModal,
componentProps: {
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved
createShipment: this.createShipment,
isEligibleForCreatingShipment: this.isEligibileForCreatingShipment
}
})

return modal.present();
},
async createShipment() {
const eligibleItems = this.order.items.filter((item: any) => item.quantityAccepted > 0)
const resp = await this.store.dispatch('order/createPurchaseShipment', { items: eligibleItems, orderId: this.order.orderId })
Expand Down
171 changes: 171 additions & 0 deletions src/views/closePurchaseOrderModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
<template>
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-button @click="closeModal">
<ion-icon slot="icon-only" :icon="arrowBackOutline" />
</ion-button>
</ion-buttons>
<ion-title>{{ $t("Close purchase order items") }}</ion-title>
<ion-buttons slot="end" @click="selectAllItems">
<ion-button color="primary">{{ $t("Select all") }}</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>

<ion-content>
<ion-item lines="none">
<ion-list-header>{{ $t("To close the purchase order, select all.") }}</ion-list-header>
</ion-item>
<ion-list v-for="(item, index) in order.items" :key="index">
<ion-item>
<ion-thumbnail slot="start">
<ShopifyImg :src="getProduct(item.productId).mainImageUrl" />
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved
</ion-thumbnail>
<ion-label>
<h2>{{ productHelpers.getProductIdentificationValue(productIdentificationPref.primaryId, getProduct(item.productId)) }}</h2>
<p>{{ productHelpers.getProductIdentificationValue(productIdentificationPref.secondaryId, getProduct(item.productId)) }}</p>
</ion-label>
<ion-buttons>
<ion-badge v-if="item.orderItemStatusId === 'ITEM_COMPLETED'" slot="end">Completed</ion-badge>
<ion-badge v-else-if="item.orderItemStatusId === 'ITEM_REJECTED'" color="danger" slot="end">Rejected</ion-badge>
<ion-checkbox v-else slot="end" v-model="item.isChecked"></ion-checkbox>
</ion-buttons>
</ion-item>
</ion-list>
</ion-content>

<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button :disabled="!hasPermission(Actions.APP_SHIPMENT_UPDATE) || !isEligibleToClosePOItems()" @click="saveAndClosePODetails">
<ion-icon :icon="saveOutline" />
</ion-fab-button>
</ion-fab>
</template>

<script lang="ts">
import {
IonButton,
IonButtons,
IonBadge,
IonContent,
IonHeader,
IonIcon,
IonTitle,
IonToolbar,
IonList,
IonItem,
IonListHeader,
IonThumbnail,
IonLabel,
IonCheckbox,
IonFab,
IonFabButton,
alertController,
modalController
} from '@ionic/vue';
import { defineComponent } from 'vue';
import { closeOutline, checkmarkCircle, arrowBackOutline, saveOutline } from 'ionicons/icons';
import { mapGetters } from 'vuex'
import { ShopifyImg } from '@hotwax/dxp-components';
import { Actions, hasPermission } from '@/authorization'
import { productHelpers } from '@/utils';
import { OrderService } from "@/services/OrderService";

export default defineComponent({
name: "closePurchaseOrder",
components: {
ShopifyImg,
IonButton,
IonButtons,
IonBadge,
IonContent,
IonHeader,
IonIcon,
IonTitle,
IonToolbar,
IonThumbnail,
IonList,
IonItem,
IonListHeader,
IonLabel,
IonCheckbox,
IonFab,
IonFabButton
},
computed: {
...mapGetters({
order: 'order/getCurrent',
getProduct: 'product/getProduct',
productIdentificationPref: 'user/getProductIdentificationPref'
})
},
setup() {
return {
arrowBackOutline,
closeOutline,
saveOutline,
checkmarkCircle,
hasPermission,
Actions,
productHelpers,
OrderService
};
},
props: ['createShipment', 'isEligibileForCreatingShipment'],
methods: {
closeModal() {
modalController.dismiss({ dismissed: true });
},
async saveAndClosePODetails() {
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved
const alert = await alertController.create({
header: this.$t('Close purchase order items'),
message: this.$t('Are you sure you have received the purchase order for the selected items? Once closed, the shipments for the selected items wont be available for receiving later.', { space: '<br /><br />' }),
buttons: [{
text: this.$t('Cancel'),
role: 'cancel'
},
{
text: this.$t('Proceed'),
role: 'proceed',
handler: async () => {
if(this.isEligibileForCreatingShipment){
await this.createShipment()
}
await this.updatePOItemStatus()
}
}]
});
return alert.present();
},
async updatePOItemStatus() {
const eligibleItems = this.order.items.filter((item: any) => item.isChecked == true)
const isAllSelected = this.isAllItemSelected(eligibleItems)
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved

eligibleItems.forEach(async (item:any) => {
if(isAllSelected){
await OrderService.updatePOItemStatus({orderId: item.orderId, orderItemSeqId: item.orderItemSeqId})
.catch((err)=>{
console.error(err);
})
}else {
await OrderService.updatePOItemStatus({orderId: item.orderId, statusId: "ITEM_COMPLETED", orderItemSeqId: item.orderItemSeqId})
.catch((err)=>{
console.error(err);
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved
})
}
});
},
isAllItemSelected(eligibleItems:any) {
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved
return eligibleItems.length === this.order.items.filter((item:any) => item.orderItemStatusId != "ITEM_COMPLETED" || item.orderItemStatusId != "ITEM_REJECTED").length
},
isEligibleToClosePOItems() {
return this.order.items.some((item: any) => item.isChecked > 0)
},
selectAllItems() {
this.order.items.map((item:any) => {
if ( !(item.orderItemStatusId === "ITEM_COMPLETED") || !(item.orderItemStatusId === "ITEM_REJECTED")) item.isChecked = true;
})
}
}
});
</script>