Skip to content

Commit

Permalink
Merge pull request #539 from amansinghbais/#528-hard-count-creation
Browse files Browse the repository at this point in the history
Implemented: support for hard counts creation (#528)
  • Loading branch information
ymaheshwari1 authored Dec 19, 2024
2 parents d4a1e11 + 9628330 commit 59bfcdc
Show file tree
Hide file tree
Showing 21 changed files with 500 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
VUE_APP_I18N_LOCALE=en
VUE_APP_I18N_FALLBACK_LOCALE=en
VUE_APP_CACHE_MAX_AGE=3600
VUE_APP_VIEW_SIZE=10
VUE_APP_VIEW_SIZE=20
VUE_APP_PERMISSION_ID="INVCOUNT_APP_VIEW"
VUE_APP_DEFAULT_LOG_LEVEL="error"
VUE_APP_PRDT_IDENT=["productId", "groupId", "groupName", "internalName", "parentProductName", "primaryProductCategoryName", "title"]
Expand Down
2 changes: 1 addition & 1 deletion src/components/Menu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default defineComponent({
url: "/draft",
iosIcon: createOutline,
mdIcon: createOutline,
childRoutes: ["/draft/", "/bulkUpload"],
childRoutes: ["/draft/", "/bulkUpload", "/hard-count"],
meta: {
permissionId: "APP_DRAFT_VIEW"
}
Expand Down
12 changes: 12 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"Added product to count": "Added product to count",
"App": "App",
"Assigned count": "Assigned count",
"Auto assign to stores": "Auto assign to stores",
"Average variance": "Average variance",
"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 want to download the cycle counts?": "Are you sure you want to download the cycle counts?",
Expand Down Expand Up @@ -64,6 +65,7 @@
"Cycle count": "Cycle count",
"Cycle count cancelled successfully.": "Cycle count cancelled successfully.",
"Cycle count not found": "Cycle count not found",
"Cycle counts created successfully.": "Cycle counts created successfully.",
"Current on hand": "Current on hand",
"Defaults to 'Draft'": "Defaults to 'Draft'",
"Due date": "Due date",
Expand Down Expand Up @@ -102,6 +104,8 @@
"Failed to complete cycle count": "Failed to complete cycle count",
"Failed to cancel uploaded cycle count.": "Failed to cancel uploaded cycle count.",
"Failed to create cycle count": "Failed to create cycle count",
"Failed to create cycle counts.": "Failed to create cycle counts.",
"Failed to create cycle counts due to missing association of facilities.": "Failed to create cycle counts due to missing association of facilities.",
"Failed to add product to count": "Failed to add product to count",
"Failed to add products to count, as some products are not found.": "Failed to add products to count, as some products are not found.",
"Failed to change the cycle count status": "Failed to change the cycle count status",
Expand All @@ -120,9 +124,14 @@
"Force scan": "Force scan",
"Go to Launchpad": "Go to Launchpad",
"Go to OMS": "Go to OMS",
"Group": "Group",
"Hard Count": "Hard Count",
"HARD COUNT": "HARD COUNT",
"Hard counts are used when conducting large scale full counts at facilities. Products are not added to hard counts before they’re assigned. Facilities will count everything they have in stock. Anything they don’t count will defaulted to 0 on hand.": "Hard counts are used when conducting large scale full counts at facilities. Products are not added to hard counts before they’re assigned. Facilities will count everything they have in stock. Anything they don’t count will defaulted to 0 on hand.",
"If a file includes multiple facilities, a count is created for every facility. All items with no facility location will be added to the same count.": "If a file includes multiple facilities, a count is created for every facility. All items with no facility location will be added to the same count.",
"Import CSV": "Import CSV",
"Import Error": "Import Error",
"Individual": "Individual",
"In stock": "In stock",
"inventory variance": "inventory variance",
"Instance Url": "Instance Url",
Expand Down Expand Up @@ -231,6 +240,7 @@
"Scanned quantity": "Scanned quantity",
"selected": "selected",
"Select": "Select",
"Search facilities": "Search facilities",
"Select fields": "Select fields",
"Select store": "Select store",
"Select the following columns from the uploaded CSV": "Select the following columns from the uploaded CSV",
Expand All @@ -241,8 +251,10 @@
"Searching on SKU": "Searching on SKU",
"Secondary": "Secondary",
"secondary identifier": "secondary identifier",
"Select a facility group to hard count": "Select a facility group to hard count",
"Select all the required fields to continue": "Select all the required fields to continue",
"Select date": "Select date",
"Select facilities to hard count": "Select facilities to hard count",
"Select the column containing products": "Select the column containing products",
"Secondary product ID": "Secondary product ID",
"Select facility": "Select facility",
Expand Down
10 changes: 10 additions & 0 deletions src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import Closed from "@/views/Closed.vue";
import StorePermissions from "@/views/StorePermissions.vue";
import Settings from "@/views/Settings.vue";
import BulkUpload from "@/views/BulkUpload.vue"
import HardCount from "@/views/HardCount.vue"

// Defining types for the meta values
declare module 'vue-router' {
Expand Down Expand Up @@ -107,6 +108,15 @@ const routes: Array<RouteRecordRaw> = [
permissionId: "APP_DRAFT_VIEW"
}
},
{
path: '/hard-count',
name: 'HardCount',
component: HardCount,
beforeEnter: authGuard,
meta: {
permissionId: "APP_DRAFT_VIEW"
}
},
{
path: "/draft/:inventoryCountImportId",
name: "DraftDetail",
Expand Down
58 changes: 57 additions & 1 deletion src/services/UtilService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { api } from '@/adapter';
import api, {client} from '@/api';
import store from '@/store';

const fetchVarianceReasons = async (payload: any): Promise<any> => {
return api({
Expand All @@ -16,7 +17,62 @@ function getOrdinalSuffix(day: any) {
return 'th';
}

const fetchFacilities = async (payload: any): Promise<any> => {
return api({
url: "facilities",
method: "GET",
params: payload
})
}

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

const fetchFacilityGroups = async (payload: any): Promise<any> => {
const token = store.getters["user/getUserToken"]
const url = store.getters["user/getBaseUrl"]
const baseURL = url.startsWith('http') ? url.includes('/rest/s1/inventory-cycle-count') ? url.replace("inventory-cycle-count", "available-to-promise") : `${url}/rest/s1/available-to-promise/` : `https://${url}.hotwax.io/rest/s1/available-to-promise/`;

return client({
url: "facilityGroups",
baseURL,
method: "GET",
params: payload,
headers: {
"api_key": token,
"Content-Type": "application/json"
}
})
}

const fetchGroupFacilities = async (payload: any): Promise<any> => {
const token = store.getters["user/getUserToken"]
const url = store.getters["user/getBaseUrl"]

const baseURL = url.startsWith('http') ? url.includes('/rest/s1/inventory-cycle-count') ? url.replace("inventory-cycle-count", "available-to-promise") : `${url}/rest/s1/available-to-promise/` : `https://${url}.hotwax.io/rest/s1/available-to-promise/`;

return client({
url: `facilityGroups/${payload.facilityGroupId}/facilities`,
baseURL,
method: "GET",
params: payload,
headers: {
"api_key": token,
"Content-Type": "application/json"
}
})
}

export const UtilService = {
createBulkCycleCounts,
fetchFacilities,
fetchFacilityGroups,
fetchGroupFacilities,
fetchVarianceReasons,
getOrdinalSuffix
}
2 changes: 2 additions & 0 deletions src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import actions from "./actions";
import userModule from "./modules/user";
import productModule from "./modules/product";
import countModule from "./modules/count";
import utilModule from "./modules/util";
import { setPermissions } from "@/authorization"


Expand All @@ -32,6 +33,7 @@ const store = createStore<RootState>({
user: userModule,
product: productModule,
count: countModule,
util: utilModule,
},
})

Expand Down
3 changes: 3 additions & 0 deletions src/store/modules/util/UtilState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default interface UtilState {
facilityGroups: any;
}
28 changes: 28 additions & 0 deletions src/store/modules/util/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ActionTree } from 'vuex'
import RootState from '@/store/RootState'
import * as types from './mutation-types'
import { hasError } from '@/utils';
import logger from '@/logger'
import { UtilService } from '@/services/UtilService'
import UtilState from './UtilState';

const actions: ActionTree<UtilState, RootState> = {

async fetchFacilityGroups ( { commit }) {
let facilityGroups = [];

try {
const resp = await UtilService.fetchFacilityGroups({ pageSize: 200 })
if(!hasError(resp)) {
facilityGroups = resp.data;
} else {
throw resp
}
} catch(err) {
logger.error("Failed to fetch facility groups", err)
}
commit(types.UTIL_FACILITY_GROUPS_UPDATED, facilityGroups);
}
}

export default actions;
10 changes: 10 additions & 0 deletions src/store/modules/util/getters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { GetterTree } from "vuex";
import RootState from "../../RootState";
import UtilState from "./UtilState";

const getters: GetterTree<UtilState, RootState> = {
getFacilityGroups(state) {
return state.facilityGroups
}
};
export default getters;
18 changes: 18 additions & 0 deletions src/store/modules/util/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import actions from './actions'
import getters from './getters'
import mutations from './mutations'
import { Module } from 'vuex'
import RootState from '../../RootState'
import UtilState from './UtilState'

const utilModule: Module<UtilState, RootState> = {
namespaced: true,
state: {
facilityGroups: []
},
getters,
actions,
mutations,
}

export default utilModule;
2 changes: 2 additions & 0 deletions src/store/modules/util/mutation-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const SN_UTIL = 'util'
export const UTIL_FACILITY_GROUPS_UPDATED = SN_UTIL + '/FACILITY_GROUPS_UPDATED'
10 changes: 10 additions & 0 deletions src/store/modules/util/mutations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { MutationTree } from 'vuex'
import * as types from './mutation-types'
import UtilState from './UtilState';

const mutations: MutationTree <UtilState> = {
[types.UTIL_FACILITY_GROUPS_UPDATED] (state, payload) {
state.facilityGroups = payload
}
}
export default mutations;
1 change: 1 addition & 0 deletions src/views/Assigned.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<ion-item lines="none">
<ion-icon :icon="storefrontOutline" slot="start"></ion-icon>
<ion-label>
<p class="overline" v-if="count.countTypeEnumId === 'HARD_COUNT'">{{ translate("HARD COUNT") }}</p>
{{ count.countImportName }}
<p>{{ count.inventoryCountImportId }}</p>
</ion-label>
Expand Down
1 change: 1 addition & 0 deletions src/views/AssignedDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<div class="search ion-padding">
<ion-item lines="none">
<ion-label slot="start">
<p class="overline" v-if="currentCycleCount.countTypeEnumId === 'HARD_COUNT'">{{ translate("HARD COUNT") }}</p>
<h1 v-show="!isCountNameUpdating">{{ countName }}</h1>
<!-- Added class as we can't change the background of ion-input with css property, and we need to change the background to show the user that now this value is editable -->
<ion-input ref="countNameRef" :class="isCountNameUpdating ? 'name' : ''" v-show="isCountNameUpdating" aria-label="group name" v-model="countName"></ion-input>
Expand Down
1 change: 1 addition & 0 deletions src/views/Closed.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<ion-item lines="none">
<ion-icon :icon="storefrontOutline" slot="start"></ion-icon>
<ion-label>
<p class="overline" v-if="count.countTypeEnumId === 'HARD_COUNT'">{{ translate("HARD COUNT") }}</p>
{{ count.countImportName }}
<p>{{ count.inventoryCountImportId }}</p>
</ion-label>
Expand Down
29 changes: 18 additions & 11 deletions src/views/Count.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,21 @@
</template>
<section v-else-if="cycleCount.length">
<template v-if="selectedSegment === 'assigned'">
<ion-card v-for="count in cycleCount" :key="count.inventoryCountImportId" @click="navigateToStoreView(count.inventoryCountImportId)" button>
<ion-card v-for="count in cycleCount" :key="count.inventoryCountImportId" @click="navigateToStoreView(count)" button>
<ion-card-header>
<ion-card-title>
{{ count.countImportName }}
<ion-label>
<p>{{ getDateWithOrdinalSuffix(count.createdDate) }}</p>
</ion-label>
</ion-card-title>
<div>
<ion-card-subtitle v-if="count.countTypeEnumId === 'HARD_COUNT'">
<ion-label color="warning" class="overline">
{{ translate("HARD COUNT") }}
</ion-label>
</ion-card-subtitle>
<ion-card-title>
{{ count.countImportName }}
<ion-label>
<p>{{ getDateWithOrdinalSuffix(count.createdDate) }}</p>
</ion-label>
</ion-card-title>
</div>
<ion-note>{{ cycleCountStats(count.inventoryCountImportId)?.totalItems }} {{ translate("items") }}</ion-note>
</ion-card-header>
<ion-item lines="none">
Expand All @@ -43,7 +50,7 @@
</ion-card>
</template>
<template v-else-if="selectedSegment === 'pendingReview'">
<ion-card button v-for="count in cycleCount" :key="count.inventoryCountImportId" @click="navigateToStoreView(count.inventoryCountImportId)">
<ion-card button v-for="count in cycleCount" :key="count.inventoryCountImportId" @click="navigateToStoreView(count)">
<ion-card-header>
<ion-card-title>
{{ count.countImportName }}
Expand All @@ -68,7 +75,7 @@
</ion-card>
</template>
<template v-else>
<ion-card v-for="count in cycleCount" :key="count.inventoryCountImportId" @click="navigateToStoreView(count.inventoryCountImportId)" button>
<ion-card v-for="count in cycleCount" :key="count.inventoryCountImportId" @click="navigateToStoreView(count)" button>
<ion-card-header>
<ion-card-title>
{{ count.countImportName }}
Expand Down Expand Up @@ -228,8 +235,8 @@ async function segmentChanged(value) {
isLoading.value = false;
}
function navigateToStoreView(countId) {
router.push(`/tabs/count-detail/${countId}`)
function navigateToStoreView(count) {
router.push((count.countTypeEnumId === "HARD_COUNT") ? `/tabs/hard-count-detail/${count.inventoryCountImportId}` : `/tabs/count-detail/${count.inventoryCountImportId}`);
}
function getStatusIdForCountsToBeFetched() {
Expand Down
6 changes: 5 additions & 1 deletion src/views/Draft.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<ion-list v-else class="list">
<ion-item lines="full" v-for="count in cycleCounts" :key="count.inventoryCountImportId" button detail @click="router.push(`/draft/${count.inventoryCountImportId}`)">
<ion-label>
<p class="overline" v-if="count.countTypeEnumId === 'HARD_COUNT'">{{ translate("HARD COUNT") }}</p>
{{ count.countImportName }}
<p>{{ count.inventoryCountImportId }}</p>
</ion-label>
Expand All @@ -38,6 +39,9 @@
<ion-fab-button @click="router.push('/bulkUpload')">
<ion-icon :icon="documentsOutline" />
</ion-fab-button>
<ion-fab-button @click="router.push('/hard-count')">
<ion-icon color="warning" :icon="shieldCheckmarkOutline" />
</ion-fab-button>
</ion-fab-list>
</ion-fab>

Expand Down Expand Up @@ -66,7 +70,7 @@ import {
onIonViewDidEnter,
onIonViewWillLeave
} from "@ionic/vue";
import { addOutline, documentOutline, documentsOutline, filterOutline } from "ionicons/icons";
import { addOutline, documentOutline, documentsOutline, filterOutline, shieldCheckmarkOutline } from "ionicons/icons";
import { computed } from "vue"
import { translate } from "@/i18n";
import Filters from "@/components/Filters.vue"
Expand Down
1 change: 1 addition & 0 deletions src/views/DraftDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<div class="search">
<ion-item lines="none" class="ion-padding">
<ion-label slot="start">
<p class="overline" v-if="currentCycleCount.countTypeEnumId === 'HARD_COUNT'">{{ translate("HARD COUNT") }}</p>
<h1 v-show="!isCountNameUpdating">{{ countName }}</h1>
<!-- Added class as we can't change the background of ion-input with css property, and we need to change the background to show the user that now this value is editable -->
<ion-input ref="countNameRef" :class="isCountNameUpdating ? 'name' : ''" v-show="isCountNameUpdating" aria-label="group name" v-model="countName"></ion-input>
Expand Down
Loading

0 comments on commit 59bfcdc

Please sign in to comment.