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: support for hard counts creation (#528) #539

Merged
merged 6 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
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
@@ -1,4 +1,4 @@
import { createStore, useStore as useVuexStore, Store } from "vuex";

Check warning on line 1 in src/store/index.ts

View workflow job for this annotation

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

'Store' is defined but never used

Check warning on line 1 in src/store/index.ts

View workflow job for this annotation

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

'Store' is defined but never used
import createPersistedState from "vuex-persistedstate";
import RootState from "./RootState"; // Ensure this is correctly imported
import mutations from "./mutations";
Expand All @@ -7,6 +7,7 @@
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 @@
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
Loading