-
Notifications
You must be signed in to change notification settings - Fork 84
Re-enabled bulk csv upload #849
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
base: inventory-count-3.0
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| <template> | ||
| <ion-header> | ||
| <ion-toolbar> | ||
| <ion-buttons slot="start"> | ||
| <ion-button @click="closeModal"> | ||
| <ion-icon :icon="close" /> | ||
| </ion-button> | ||
| </ion-buttons> | ||
| <ion-title>{{ translate("CSV Mapping") }}</ion-title> | ||
| </ion-toolbar> | ||
| </ion-header> | ||
|
|
||
| <ion-item> | ||
| <ion-input :label="translate('Mapping name')" :placeholder="translate('Field mapping name')" v-model="mappingName" /> | ||
| </ion-item> | ||
|
|
||
| <ion-content> | ||
| <div> | ||
| <ion-list> | ||
| <ion-item-divider> | ||
| <ion-label>{{ translate("Required") }} </ion-label> | ||
| </ion-item-divider> | ||
| <ion-item :key="field" v-for="(fieldValues, field) in getFields(fields, true)"> | ||
| <ion-select :label="translate(fieldValues.label)" interface="popover" :placeholder = "translate('Select')" v-model="fieldMapping[field]"> | ||
| <ion-select-option :key="index" v-for="(prop, index) in fileColumns">{{ prop }}</ion-select-option> | ||
| </ion-select> | ||
| </ion-item> | ||
| <ion-item-divider> | ||
| <ion-label>{{ translate("Optional") }} </ion-label> | ||
| </ion-item-divider> | ||
| <ion-item :key="field" v-for="(fieldValues, field) in getFields(fields, false)"> | ||
| <ion-select :label="translate(fieldValues.label)" interface="popover" :placeholder = "translate('Select')" v-model="fieldMapping[field]"> | ||
| <ion-select-option :key="index" v-for="(prop, index) in fileColumns">{{ prop }}</ion-select-option> | ||
| </ion-select> | ||
| </ion-item> | ||
| </ion-list> | ||
| </div> | ||
| <ion-fab vertical="bottom" horizontal="end" slot="fixed"> | ||
| <ion-fab-button @click="saveMapping"> | ||
| <ion-icon :icon="saveOutline" /> | ||
| </ion-fab-button> | ||
| </ion-fab> | ||
| </ion-content> | ||
| </template> | ||
|
|
||
| <script setup> | ||
| import { | ||
| IonButtons, | ||
| IonButton, | ||
| IonContent, | ||
| IonFab, | ||
| IonFabButton, | ||
| IonHeader, | ||
| IonIcon, | ||
| IonInput, | ||
| IonItem, | ||
| IonItemDivider, | ||
| IonLabel, | ||
| IonSelect, | ||
| IonSelectOption, | ||
| IonTitle, | ||
| IonToolbar, | ||
| IonList, | ||
| modalController | ||
| } from '@ionic/vue'; | ||
| import { close, save, saveOutline } from "ionicons/icons"; | ||
| import { computed, defineProps, onMounted, ref } from "vue"; | ||
| import { useStore } from "vuex"; | ||
| import { showToast } from '@/utils'; | ||
| import { translate } from "@hotwax/dxp-components"; | ||
| const store = useStore(); | ||
| const props = defineProps(["content", "seletedFieldMapping", "mappingType"]) | ||
| const fieldMappings = computed(() => store.getters["user/getFieldMappings"]) | ||
| let mappingName = ref(null) | ||
| let fieldMapping = ref ({}) | ||
| let fileColumns = ref([]) | ||
| let identificationTypeId = ref('SKU') | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| const fields = process.env["VUE_APP_MAPPING_INVCOUNT"] ? JSON.parse(process.env["VUE_APP_MAPPING_INVCOUNT"]) : {} | ||
| onMounted(() => { | ||
| fieldMapping.value = { ...props.seletedFieldMapping } | ||
| fileColumns.value = Object.keys(props.content[0]); | ||
| }) | ||
| function getFields(fields, required = true) { | ||
| return Object.keys(fields).reduce((result, key) => { | ||
| if (fields[key].required === required) { | ||
| result[key] = fields[key]; | ||
| } | ||
| return result; | ||
| }, {}); | ||
| } | ||
| function closeModal() { | ||
| modalController.dismiss({ dismissed: true }); | ||
| } | ||
| async function saveMapping() { | ||
| if(!mappingName.value || !mappingName.value.trim()) { | ||
| showToast(translate("Enter mapping name")); | ||
| return | ||
| } | ||
| if (!areAllFieldsSelected()) { | ||
| showToast(translate("Map all required fields")); | ||
| return | ||
| } | ||
| const id = generateUniqueMappingPrefId(); | ||
| await store.dispatch("user/createFieldMapping", { id, name: mappingName.value, value: fieldMapping.value, mappingType: props.mappingType }) | ||
| closeModal(); | ||
| } | ||
| function areAllFieldsSelected() { | ||
| const requiredFields = Object.keys(getFields(fields, true)); | ||
| const selectedFields = Object.keys(fieldMapping.value).filter(key => fieldMapping.value[key] !== '') | ||
| return requiredFields.every(field => selectedFields.includes(field)); | ||
| } | ||
| //Todo: Generating unique identifiers as we are currently storing in local storage. Need to remove it as we will be storing data on server. | ||
| function generateUniqueMappingPrefId() { | ||
| const id = Math.floor(Math.random() * 1000); | ||
| return !fieldMappings.value[id] ? id : this.generateUniqueMappingPrefId(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| } | ||
| </script> | ||
| <style scoped> | ||
| ion-content { | ||
| --padding-bottom: 80px; | ||
| } | ||
| </style> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| <template> | ||
| <ion-header> | ||
| <ion-toolbar> | ||
| <ion-buttons slot="start"> | ||
| <ion-button @click="closeModal"> | ||
| <ion-icon :icon="close" /> | ||
| </ion-button> | ||
| </ion-buttons> | ||
| <ion-title>{{ translate("CSV Mapping") }}</ion-title> | ||
| </ion-toolbar> | ||
| </ion-header> | ||
|
|
||
| <ion-item> | ||
| <ion-input :label="translate('Mapping name')" :placeholder="translate('Field mapping name')" v-model="mappingName" /> | ||
| </ion-item> | ||
|
|
||
| <ion-content> | ||
| <div> | ||
| <ion-list> | ||
| <ion-item-divider> | ||
| <ion-label>{{ translate("Required") }} </ion-label> | ||
| </ion-item-divider> | ||
| <ion-item :key="field" v-for="(fieldValues, field) in getFields(fields, true)"> | ||
| <ion-select :label="translate(fieldValues.label)" interface="popover" :placeholder = "translate('Select')" v-model="fieldMapping[field]"> | ||
| <ion-select-option :key="index" v-for="(prop, index) in fileColumns">{{ prop }}</ion-select-option> | ||
| </ion-select> | ||
| </ion-item> | ||
| <ion-item-divider> | ||
| <ion-label>{{ translate("Optional") }} </ion-label> | ||
| </ion-item-divider> | ||
| <ion-item :key="field" v-for="(fieldValues, field) in getFields(fields, false)"> | ||
| <ion-select :label="translate(fieldValues.label)" interface="popover" :placeholder = "translate('Select')" v-model="fieldMapping[field]"> | ||
| <ion-select-option :key="index" v-for="(prop, index) in fileColumns">{{ prop }}</ion-select-option> | ||
| </ion-select> | ||
| </ion-item> | ||
| </ion-list> | ||
| </div> | ||
| <ion-fab vertical="bottom" horizontal="end" slot="fixed"> | ||
| <ion-fab-button @click="saveMapping"> | ||
| <ion-icon :icon="saveOutline" /> | ||
| </ion-fab-button> | ||
| </ion-fab> | ||
| </ion-content> | ||
| </template> | ||
|
|
||
| <script setup> | ||
| import { | ||
| IonButtons, | ||
| IonButton, | ||
| IonContent, | ||
| IonFab, | ||
| IonFabButton, | ||
| IonHeader, | ||
| IonIcon, | ||
| IonInput, | ||
| IonItem, | ||
| IonItemDivider, | ||
| IonLabel, | ||
| IonSelect, | ||
| IonSelectOption, | ||
| IonTitle, | ||
| IonToolbar, | ||
| IonList, | ||
| modalController | ||
| } from '@ionic/vue'; | ||
| import { close, save, saveOutline } from "ionicons/icons"; | ||
| import { computed, defineProps, onMounted, ref } from "vue"; | ||
| import { useStore } from "vuex"; | ||
| import { showToast } from '@/utils'; | ||
| import { translate } from "@hotwax/dxp-components"; | ||
| const store = useStore(); | ||
| const props = defineProps(["content", "seletedFieldMapping", "mappingType"]) | ||
| const fieldMappings = computed(() => store.getters["user/getFieldMappings"]) | ||
| let mappingName = ref(null) | ||
| let fieldMapping = ref ({}) | ||
| let fileColumns = ref([]) | ||
| let identificationTypeId = ref('SKU') | ||
| const fields = process.env["VUE_APP_MAPPING_INVCOUNT"] ? JSON.parse(process.env["VUE_APP_MAPPING_INVCOUNT"]) : {} | ||
| onMounted(() => { | ||
| fieldMapping.value = { ...props.seletedFieldMapping } | ||
| fileColumns.value = Object.keys(props.content[0]); | ||
| }) | ||
| function getFields(fields, required = true) { | ||
| return Object.keys(fields).reduce((result, key) => { | ||
| if (fields[key].required === required) { | ||
| result[key] = fields[key]; | ||
| } | ||
| return result; | ||
| }, {}); | ||
| } | ||
| function closeModal() { | ||
| modalController.dismiss({ dismissed: true }); | ||
| } | ||
| async function saveMapping() { | ||
| if(!mappingName.value || !mappingName.value.trim()) { | ||
| showToast(translate("Enter mapping name")); | ||
| return | ||
| } | ||
| if (!areAllFieldsSelected()) { | ||
| showToast(translate("Map all required fields")); | ||
| return | ||
| } | ||
| const id = generateUniqueMappingPrefId(); | ||
| await store.dispatch("user/createFieldMapping", { id, name: mappingName.value, value: fieldMapping.value, mappingType: props.mappingType }) | ||
| closeModal(); | ||
| } | ||
| function areAllFieldsSelected() { | ||
| const requiredFields = Object.keys(getFields(fields, true)); | ||
| const selectedFields = Object.keys(fieldMapping.value).filter(key => fieldMapping.value[key] !== '') | ||
| return requiredFields.every(field => selectedFields.includes(field)); | ||
| } | ||
| //Todo: Generating unique identifiers as we are currently storing in local storage. Need to remove it as we will be storing data on server. | ||
| function generateUniqueMappingPrefId() { | ||
| const id = Math.floor(Math.random() * 1000); | ||
| return !fieldMappings.value[id] ? id : this.generateUniqueMappingPrefId(); | ||
| } | ||
| </script> | ||
| <style scoped> | ||
| ion-content { | ||
| --padding-bottom: 80px; | ||
| } | ||
| </style> | ||
|
Comment on lines
+1
to
+132
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This component is an exact copy of |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -62,6 +62,12 @@ export default defineComponent({ | |
| const store = useStore(); | ||
| const router = useRouter(); | ||
| const appPages = [ | ||
| { | ||
| title: "Bulk Upload", | ||
| url: "/bulkUpload", | ||
| iosIcon: createOutline, | ||
| mdIcon: createOutline | ||
| }, | ||
|
Comment on lines
+65
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The new "Bulk Upload" menu item is missing the |
||
| { | ||
| title: "Draft", | ||
| url: "/draft", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,8 +28,26 @@ const getInventoryCountImportSession = async (params: { workEffortId: string; in | |
| }); | ||
| } | ||
|
|
||
| const bulkUploadInventoryCounts = async (payload: any): Promise <any> => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| return api({ | ||
| url: `inventory-cycle-count/cycleCounts/upload`, | ||
| method: "post", | ||
| ...payload | ||
| }); | ||
| } | ||
|
|
||
| const fetchCycleCountImportSystemMessages = async (payload: any): Promise <any> => { | ||
| return api({ | ||
| url: `inventory-cycle-count/cycleCounts/systemMessages`, | ||
| method: "get", | ||
| params: payload | ||
| }); | ||
| } | ||
|
|
||
| export const CountService = { | ||
| getAssignedWorkEfforts, | ||
| getInventoryCountImportsByWorkEffort, | ||
| getInventoryCountImportSession | ||
| getInventoryCountImportSession, | ||
| bulkUploadInventoryCounts, | ||
| fetchCycleCountImportSystemMessages | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -59,6 +59,26 @@ const actions: ActionTree<CountState, RootState> = { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| commit(types.COUNT_ASSIGNED_WORK_EFFORTS_UPDATED, { assignedWorkEfforts, total, isScrollable }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async fetchCycleCountImportSystemMessages({commit} ,payload) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let systemMessages; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const twentyFourHoursEarlier = DateTime.now().minus({ hours: 24 }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const resp = await CountService.fetchCycleCountImportSystemMessages({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| systemMessageTypeId: "ImportInventoryCounts", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| initDate_from: twentyFourHoursEarlier.toMillis(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| orderByField: 'initDate desc, processedDate desc', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pageSize: 100 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!hasError(resp)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| systemMessages = resp.data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw resp.data; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (err: any) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.error(err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| commit(types.COUNT_IMPORT_SYSTEM_MESSAGES_UPDATED, systemMessages) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+62
to
+81
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setCountDetailPageActive({ commit }, isPageActive) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| commit(types.COUNT_DETAIL_PAGE_ACTIVE_UPDATED, isPageActive); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| export const SN_COUNT = "count" | ||
| export const COUNT_DETAIL_PAGE_ACTIVE_UPDATED = SN_COUNT + '/DETAIL_PAGE_ACTIVE_UPDATED' | ||
| export const COUNT_ASSIGNED_WORK_EFFORTS_UPDATED = SN_COUNT + "/ASSIGNED_WORK_EFFORTS_UPDATED" | ||
| export const COUNT_ASSIGNED_WORK_EFFORTS_UPDATED = SN_COUNT + "/ASSIGNED_WORK_EFFORTS_UPDATED" | ||
| export const COUNT_IMPORT_SYSTEM_MESSAGES_UPDATED = SN_COUNT + "/IMPORT_SYSTEM_MESSAGES_UPDATED" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a typo in the prop name
seletedFieldMapping. It should beselectedFieldMapping. This typo is also present where the prop is used (e.g., line 85).