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 8 commits
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
11 changes: 11 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@
"Add to Shipment": "Add to Shipment",
"App": "App",
"Authenticating": "Authenticating",
"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.",
"Are you sure you want to change the time zone to?": "Are you sure you want to change the time zone to {timeZoneId}?",
"Arrival date": "Arrival date",
"Cancel": "Cancel",
"Change": "Change",
"Choosing a product identifier allows you to view products with your preferred identifiers.": "Choosing a product identifier allows you to view products with your preferred identifiers.",
"Click the backdrop to dismiss.": "Click the backdrop to dismiss.",
"Complete": "Complete",
"Completed": "Completed",
"COMPLETED: ITEM": "COMPLETED: {itemsCount} ITEM",
"COMPLETED: ITEMS": "COMPLETED: {itemsCount} ITEMS",
"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 @@ -63,8 +66,12 @@
"Purchase Order": "Purchase Order",
"Purchase Order Details": "Purchase Order Details",
"Purchase Orders": "Purchase Orders",
"Purchase order update failed.": "Purchase order update failed.",
"Purchase order updated successfully.": "Purchase order updated successfully.",
"Qty": "Qty",
"Receive": "Receive",
"Receive All": "Receive All",
"Receive And Close": "Receive And Close",
"Receive inventory": "Receive inventory",
"received": "received",
"Receive Shipment": "Receive Shipment",
Expand All @@ -76,6 +83,7 @@
"Returns": "Returns",
"Returns not found": "Returns not found",
"rejected": "rejected",
"Rejected": "Rejected",
"returned": "returned",
"Scan": "Scan",
"Scan ASN to start receiving": "Scan ASN to start receiving",
Expand All @@ -87,6 +95,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 @@ -101,6 +110,7 @@
"Something went wrong": "Something went wrong",
"Something went wrong while login. Please contact administrator": "Something went wrong while login. Please contact administrator.",
"Sorry, your username or password is incorrect. Please try again.": "Sorry, your username or password is incorrect. Please try again.",
"Some purchase order items were not successfully updated, Please retry.": "Some purchase order items were not successfully updated, Please retry.",
"Specify which facility you want to operate from. Order, inventory and other configuration data will be specific to the facility you select.": "Specify which facility you want to operate from. Order, inventory and other configuration data will be specific to the facility you select.",
"store name": "store name",
"Store": "Store",
Expand All @@ -112,6 +122,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: "service/changeOrderItemStatus",
method: "POST",
data: payload
})
}

export const OrderService = {
fetchPurchaseOrders,
fetchPODetail,
createPurchaseShipment,
fetchPOHistory
fetchPOHistory,
updatePOItemStatus
}
189 changes: 189 additions & 0 deletions src/views/ClosePurchaseOrderModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
<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 size="small" :src="getProduct(item.productId).mainImageUrl" />
</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">{{ $t("Completed") }}</ion-badge>
<ion-badge v-else-if="item.orderItemStatusId === 'ITEM_REJECTED'" color="danger" slot="end">{{ $t("Rejected") }}</ion-badge>
<ion-checkbox v-else slot="end" v-model="item.isChecked" />
</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="confirmSave">
<ion-icon :icon="saveOutline" />
</ion-fab-button>
</ion-fab>
</template>

<script lang="ts">
import {
alertController,
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved
IonButton,
IonButtons,
IonBadge,
IonCheckbox,
IonContent,
IonFab,
IonFabButton,
IonHeader,
IonIcon,
IonItem,
IonLabel,
IonList,
IonListHeader,
IonTitle,
IonToolbar,
IonThumbnail,
modalController
} from '@ionic/vue';
import { Actions, hasPermission } from '@/authorization'
import { closeOutline, checkmarkCircle, arrowBackOutline, saveOutline } from 'ionicons/icons';
import { defineComponent } from 'vue';
import { mapGetters } from 'vuex'
import { OrderService } from "@/services/OrderService";
import { productHelpers, showToast } from '@/utils';
import { ShopifyImg } from '@hotwax/dxp-components';
import { translate } from '@/i18n'
import emitter from "@/event-bus"
import { useRouter } from 'vue-router';

export default defineComponent({
name: "ClosePurchaseOrderModal",
components: {
IonBadge,
IonButton,
IonButtons,
IonCheckbox,
IonContent,
IonFab,
IonFabButton,
IonHeader,
IonIcon,
IonItem,
IonLabel,
IonList,
IonListHeader,
IonTitle,
IonThumbnail,
IonToolbar,
ShopifyImg
},
computed: {
...mapGetters({
getProduct: 'product/getProduct',
order: 'order/getCurrent',
productIdentificationPref: 'user/getProductIdentificationPref'
})
},
props: ['isEligibileForCreatingShipment'],
methods: {
closeModal() {
modalController.dismiss({ dismissed: true });
},
async confirmSave() {
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) {
emitter.emit('create-shipment')
}
await this.updatePOItemStatus()
modalController.dismiss()
this.router.push('/purchase-orders')
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved
}
}]
});
return alert.present();
},
async updatePOItemStatus() {
const eligibleItems = this.order.items.filter((item: any) => item.isChecked)
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved

await Promise.allSettled(eligibleItems.map(async (item:any) => {
const selectedItemDetails = {
orderId: item.orderId,
orderItemSeqId: item.orderItemSeqId,
statusId: "ITEM_COMPLETED"
}

try {
await OrderService.updatePOItemStatus(selectedItemDetails)
item.statusUpdated = true
} catch(err) {
item.statusUpdated = false
console.error(err);
}
}))

const failedItemsCount = eligibleItems.filter((item: any) => item.statusUpdated === false).length
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved

if(failedItemsCount === 0){
showToast(translate('Purchase order updated successfully.'))
} else if(failedItemsCount === eligibleItems.length){
showToast(translate("Purchase order update failed."))
} else {
showToast(translate("Some purchase order items were not successfully updated, Please retry."))
}

},
isEligibleToClosePOItems() {
return this.order.items.some((item: any) => item.isChecked)
},
selectAllItems() {
this.order.items.map((item:any) => {
if(!(item.orderItemStatusId === "ITEM_COMPLETED") || !(item.orderItemStatusId === "ITEM_REJECTED")) {
item.isChecked = true;
}
})
}
},
setup() {
const router = useRouter()
return {
arrowBackOutline,
Actions,
closeOutline,
checkmarkCircle,
hasPermission,
OrderService,
productHelpers,
router,
saveOutline
};
}
});
</script>
41 changes: 30 additions & 11 deletions src/views/PurchaseOrderDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,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="closePO">{{ $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 @@ -162,8 +165,7 @@ import {
IonChip,
IonContent,
IonHeader,
IonFab,
IonFabButton,
IonFooter,
IonIcon,
IonItem,
IonInput,
Expand All @@ -174,8 +176,8 @@ import {
IonThumbnail,
IonTitle,
IonToolbar,
modalController,
alertController,
modalController
} from '@ionic/vue';
import { defineComponent } from 'vue';
import { addOutline, cameraOutline, checkmarkDone, copyOutline, eyeOffOutline, eyeOutline, locationOutline, saveOutline, timeOutline } from 'ionicons/icons';
Expand All @@ -185,10 +187,12 @@ 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';
import { Actions, hasPermission } from '@/authorization'
import emitter from "@/event-bus"

export default defineComponent({
name: "PurchaseOrderDetails",
Expand All @@ -202,8 +206,7 @@ export default defineComponent({
IonChip,
IonContent,
IonHeader,
IonFab,
IonFabButton,
IonFooter,
IonIcon,
IonItem,
IonInput,
Expand Down Expand Up @@ -232,6 +235,9 @@ export default defineComponent({
productIdentificationPref: 'user/getProductIdentificationPref'
})
},
mounted() {
emitter.on('create-shipment', this.createShipment)
},
methods: {
getRcvdToOrderedFraction(item: any){
return (parseInt(item.quantityAccepted) + this.getPOItemAccepted(item.productId))/(item.quantity)
Expand Down Expand Up @@ -302,6 +308,16 @@ export default defineComponent({
});
return alert.present();
},
async closePO() {
const modal = await modalController.create({
component: ClosePurchaseOrderModal,
componentProps: {
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved
isEligibileForCreatingShipment: 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 All @@ -328,6 +344,9 @@ export default defineComponent({
this.store.dispatch('order/getPOHistory', { orderId: this.order.orderId })
})
},
unmounted() {
emitter.off('create-shipment', this.createShipment)
},
setup() {
const store = useStore();
const router = useRouter();
Expand Down