Integrated old with new classes. Header Correction not working. Can't hold selected value.

associator_rewrite
Griffiths Lott 3 years ago
parent 0d29079c30
commit 72113dc863
  1. 230
      FILUPLOAD_DIFF
  2. 4
      backend/appsettings.json
  3. 15
      src/App.vue
  4. 120
      src/components/FileUpload.vue
  5. 63
      src/components/HeaderCorrection.vue
  6. 2
      src/components/MissingHeaderBox.vue
  7. 4
      src/headerTemplate.js
  8. 8
      src/helpers.js

@ -0,0 +1,230 @@
<template> <template>
<form> <form>
<input type="file" id="uploadInput" accept=".xlsx" @chang <input type="file" id="uploadInput" accept=".xlsx" @chang
<button type="submit" @click.prevent="parseUpload" :disab <button type="submit" @click.prevent="parseUpload" :disab
</form> </form>
</template> </template>
<script> <script>
import { read, utils } from "xlsx"; import { read, utils } from "xlsx";
import { store } from '../store.js' | import { store, clearStore } from '../store.js'
import { HeaderAssociator } from '../helpers.js' | import { UserHeader } from "@/userHeader";
> import { HeaderTemplate, associateHeaders } from "@/headerTem
>
function findFirstNonBlankRow(worksheet) { function findFirstNonBlankRow(worksheet) {
const range = utils.decode_range(worksheet['!ref']); const range = utils.decode_range(worksheet['!ref']);
// We'll check at most of 20 rows // We'll check at most of 20 rows
for (let row = range.s.r; row <= Math.min(range.e.r,20); ro for (let row = range.s.r; row <= Math.min(range.e.r,20); ro
var headerRow = true; var headerRow = true;
for (let col = 0; col < 20; col++) { for (let col = 0; col < 20; col++) {
const cell = worksheet[utils.encode_cell({ r: row, c: c const cell = worksheet[utils.encode_cell({ r: row, c: c
if (!cell || cell.v === '') { if (!cell || cell.v === '') {
headerRow = false; headerRow = false;
break; break;
} }
} }
if (headerRow) { if (headerRow) {
return row; return row;
} }
} }
return null; return null;
} }
export default { export default {
name: 'FileUpload', name: 'FileUpload',
data() { data() {
return { return {
// User uploaded file // User uploaded file
userFile: null, userFile: null,
// Header Template provided by server // Header Template provided by server
headerTemplateList: [], | headerTemplateList: null,
> userHeaders: [],
// Defines whether data row is checked agianst value re // Defines whether data row is checked agianst value re
validateData: true, | invalidData: [],
// Store data for access by other components // Store data for access by other components
store, store,
// Controls whether or not the user can submit a file // Controls whether or not the user can submit a file
// - When a file is selected, then disabled when submit // - When a file is selected, then disabled when submit
canSubmit: false, canSubmit: false,
} }
}, },
async mounted() { async mounted() {
// We want to get the lastest template header specificati // We want to get the lastest template header specificati
try { try {
const configRequestOptions = { const configRequestOptions = {
method: 'GET', method: 'GET',
redirect: 'follow', redirect: 'follow',
}; };
const resp = await fetch(process.env.VUE_APP_TEMPLATE_H const resp = await fetch(process.env.VUE_APP_TEMPLATE_H
let respJson = await resp.json(); let respJson = await resp.json();
console.log(respJson); | console.info("RespJ: ", respJson);
this.headerTemplateList = respJson["HeaderTemplate"]; <
//FIXME: This is only for testing purposes, REMOVE THIS //FIXME: This is only for testing purposes, REMOVE THIS
this.validateData = true;//respJson["ValidateData"]; this.validateData = true;//respJson["ValidateData"];
console.log(this.headerTemplateList); | this.headerTemplateList = respJson["HeaderTemplate"].ma
console.log(this.validateData); | return new HeaderTemplate (headerTemplate["Header"],h
> this.validateData, headerTemplate["ValueRegex"], he
> });
> // Sort this list to make association faster
> this.headerTemplateList.sort((a,b) => {
> const ha = a.header.toLowerCase();
> const hb = b.header.toLowerCase();
> if (ha < hb) return -1;
> if (ha > hb) return 1;
> return 0;
> });
> console.info("Recieved HeaderTemplateList: ", this.head
} catch (error) { } catch (error) {
//FIXME: emit error internal issues //FIXME: emit error internal issues
console.error(error); console.error(error);
} }
}, },
methods: { methods: {
fileSelected(event) { fileSelected(event) {
// Make sure the user can't still act on the old file // Make sure the user can't still act on the old file
this.$emit('parsed-upload', null); | this.$emit('parsed-upload', null, []);
// Clear old file data // Clear old file data
store.missingHeaders = []; | this.invalidData = [];
store.documentHeaders = []; | this.userHeaders = [];
> clearStore();
>
> // If the user had previously selected a file,
> // we need to clear the old header associations
> if (this.userFile !== null) {
> this.headerTemplateList.map(headerTemplate => {
> headerTemplate.userHeader = null;
> })
> }
>
this.userFile = event.target.files[0]; this.userFile = event.target.files[0];
this.canSubmit = true; this.canSubmit = true;
}, },
getHeaders(worksheet, sheetName, headerIndex) { getHeaders(worksheet, sheetName, headerIndex) {
// Store the found headers // Store the found headers
var combinedHeadersString = ""; <
// Use the range to make sure we don't go out of bounds // Use the range to make sure we don't go out of bounds
const range = utils.decode_range(worksheet['!ref']); const range = utils.decode_range(worksheet['!ref']);
for (let col = 0; col < range.e.c; col++){ for (let col = 0; col < range.e.c; col++){
let cellAddress = utils.encode_cell({c: col, r: heade let cellAddress = utils.encode_cell({c: col, r: heade
let cellObj = worksheet[cellAddress]; let cellObj = worksheet[cellAddress];
// n represents number type (which is probably the st // n represents number type (which is probably the st
if (cellObj === undefined || cellObj.t === 'n') { bre if (cellObj === undefined || cellObj.t === 'n') { bre
// Add the header to the combined headers string | let dataAddress = utils.encode_cell({c: col, r: heade
combinedHeadersString += cellObj.v; | let dataValue = worksheet[dataAddress] ? worksheet[da
let headerAssociator = new HeaderAssociator(cellObj.v |
if (!this.validateData) {headerAssociator.isValidData | // Record the user header
store.documentHeaders.push(headerAssociator); | let userHeader = new UserHeader(cellObj.v, sheetName,
> this.userHeaders.push(userHeader);
} }
return combinedHeadersString; <
}, },
async parseUpload() { async parseUpload() {
this.canSubmit = false; this.canSubmit = false;
const fileBuffer = await this.userFile.arrayBuffer(); const fileBuffer = await this.userFile.arrayBuffer();
var workbook = await read(fileBuffer, {type: 'array'}); var workbook = await read(fileBuffer, {type: 'array'});
if (workbook === null) { if (workbook === null) {
//FIXME: Emit bad spreadsheet to app //FIXME: Emit bad spreadsheet to app
console.error(`No workbook found! Could not parse fil console.error(`No workbook found! Could not parse fil
return; return;
} }
var validWorksheets = [] | let validWorksheets = false;
var combinedHeadersString = ''; <
// Go through each worksheet // Go through each worksheet
for (let sheetName of workbook.SheetNames) { for (let sheetName of workbook.SheetNames) {
// Open the actual worksheet // Open the actual worksheet
let worksheet = workbook.Sheets[sheetName]; let worksheet = workbook.Sheets[sheetName];
// Find the first non-blank row of 20 // Find the first non-blank row of 20
var headerIndex = findFirstNonBlankRow(worksheet); var headerIndex = findFirstNonBlankRow(worksheet);
if (headerIndex === null) { if (headerIndex === null) {
// Probably not a sheet we need to process // Probably not a sheet we need to process
console.warn(`${sheetName} | No header row found!`) console.warn(`${sheetName} | No header row found!`)
} }
// Add the header to the combined headers string | // getHeaders will created the UserHeader objects
// getHeaders will created the AssociatedHeaders obje | this.getHeaders(worksheet, sheetName, headerIndex);
combinedHeadersString += this.getHeaders(worksheet, s | validWorksheets = true;
// Note which worksheets are actually being processed <
validWorksheets.push(sheetName); <
} }
if (validWorksheets.length === 0) { | if (!validWorksheets) {
//FIXME: emit bad spreadsheet to App //FIXME: emit bad spreadsheet to App
console.error("No worksheets found!"); console.error("No worksheets found!");
return; return;
} }
// Check each template regex against the combined heade | // Sort the user headers to make association faster
for (const headerTemplate of this.headerTemplateList) { | this.userHeaders.sort((a,b) => {
// 'i' option means ignore case | const ha = a.label.toLowerCase();
let headerRegex = RegExp(headerTemplate["HeaderRegex" | const hb = b.label.toLowerCase();
let headerName = headerTemplate["Header"]; | if (ha < hb) return -1;
| if (ha > hb) return 1;
// Check to see if the template header is present in | return 0;
let searchResults = headerRegex.exec(combinedHeadersS | });
if (searchResults === null) { |
store.missingHeaders.push(headerName); | // console.log("User Headers:", this.userHeaders);
continue; | // console.log("Template Headers:", this.headerTemplate
} | let processedArrays = associateHeaders(this.userHeaders
let docHeader = searchResults[0]; |
> store.unassociatedUserHeaders = processedArrays[0];
> store.unassociatedTemplateHeaders = this.headerTemplate
> !headerTemplate.isAssociated();
> });
> this.invalidData = processedArrays[1];
> console.log("Invalid Data:", this.invalidData);
> console.log("Unassociated:", store.unAssociated);
>
> console.log("Updated Template Headers:", this.headerTem
// Find the associated header <
for (let headerAssociator of store.documentHeaders) { <
if (headerAssociator.isSet()) {continue} <
if (headerAssociator.documentHeader === docHeader) <
// Set the associated template header <
headerAssociator.swapTemplateHeader(headerName); <
<
if (this.validateData) { <
// If we want to validate the data, then check <
let isNullable = headerTemplate["Nullable"]; <
let headerAddress = utils.decode_cell(headerAss <
// Now we can get the value of the cell below t <
let valueCellAddress = utils.encode_cell(header <
// We need to know which worksheet this cell be <
let worksheet = workbook.Sheets[headerAssociato <
let valueObj = worksheet[valueCellAddress]; <
// Check if the cell is null, if so does it mat <
if (valueObj !== undefined ) { <
// Test the value against regex <
let valueRegex = RegExp(headerTemplate["Value <
let dataValue = valueObj.v.toString(); <
let isValid = valueRegex.test(dataValue); <
if (!isValid) { <
// record the invalid data and set isValidD <
headerAssociator.invalidData(dataValue); <
} <
} else { <
// isValid matches isNullable <
headerAssociator.isValidData = isNullable; <
} <
} <
// We found the header and processed it so stop l <
break; <
} <
} <
} <
//TODO: Remove logs <
console.log(`Document headers (${store.documentHeaders. <
console.log(`Missing headers (${store.missingHeaders.le <
// emit the uploaded file & parsed data up to parent // emit the uploaded file & parsed data up to parent
this.$emit('parsed-upload', this.userFile); | this.$emit('parsed-upload', this.userFile, this.invalid
} }
} }
} }
</script> </script>

@ -19,7 +19,7 @@
{"Header": "Customer Physical City", "HeaderRegex": "(cust(omers?)?\\s?\\w*\\s?city)" ,"ValueRegex": "(\\w+\\s?)+", "Nullable": true}, {"Header": "Customer Physical City", "HeaderRegex": "(cust(omers?)?\\s?\\w*\\s?city)" ,"ValueRegex": "(\\w+\\s?)+", "Nullable": true},
{"Header": "Customer Physical State", "HeaderRegex": "(cust(omers?)?\\s?\\w*\\s?state)" ,"ValueRegex": "\\w+", "Nullable": true}, {"Header": "Customer Physical State", "HeaderRegex": "(cust(omers?)?\\s?\\w*\\s?state)" ,"ValueRegex": "\\w+", "Nullable": true},
{"Header": "Customer Physical Zip", "HeaderRegex": "(cust(omers?)?\\s?\\w*\\s?zip\\s?(code)?)" ,"ValueRegex": "\\d{5}-?(\\d{4})?", "Nullable": true}, {"Header": "Customer Physical Zip", "HeaderRegex": "(cust(omers?)?\\s?\\w*\\s?zip\\s?(code)?)" ,"ValueRegex": "\\d{5}-?(\\d{4})?", "Nullable": true},
{"Header": "Date Booked", "HeaderRegex": "(date\\s?booked)" ,"ValueRegex": "[1-2]?\\d\\/\\d{1,2}\\/(20)?\\d{2}", "Nullable": true}, {"Header": "Date Booked", "HeaderRegex": "DATEVALUE" ,"ValueRegex": "[1-2]?\\d\\/\\d{1,2}\\/(20)?\\d{2}", "Nullable": true},
{"Header": "Term (Months)", "HeaderRegex": "(term\\s?(\\(?months\\)?)?)" ,"ValueRegex": "\\d{1,3}", "Nullable": true}, {"Header": "Term (Months)", "HeaderRegex": "(term\\s?(\\(?months\\)?)?)" ,"ValueRegex": "\\d{1,3}", "Nullable": true},
{"Header": "Payment Amount", "HeaderRegex": "(pa?yme?n?t\\s?am(oun)?t)" ,"ValueRegex": "(\\d{1,2},?)*\\d+(.\\d{2})?", "Nullable": true}, {"Header": "Payment Amount", "HeaderRegex": "(pa?yme?n?t\\s?am(oun)?t)" ,"ValueRegex": "(\\d{1,2},?)*\\d+(.\\d{2})?", "Nullable": true},
{"Header": "Financed Amount", "HeaderRegex": "(financed\\s?am(oun)?t)" ,"ValueRegex": "(\\d{1,2},?)*\\d+(.\\d{2})?", "Nullable": true}, {"Header": "Financed Amount", "HeaderRegex": "(financed\\s?am(oun)?t)" ,"ValueRegex": "(\\d{1,2},?)*\\d+(.\\d{2})?", "Nullable": true},
@ -34,7 +34,7 @@
{"Header": "PG State", "HeaderRegex": "((pg|guarantor)\\s?state)" ,"ValueRegex": "\\d{5}-?(\\d{4})?", "Nullable": true}, {"Header": "PG State", "HeaderRegex": "((pg|guarantor)\\s?state)" ,"ValueRegex": "\\d{5}-?(\\d{4})?", "Nullable": true},
{"Header": "PG Zip", "HeaderRegex": "((pg|guarantor)\\s?zip)" ,"ValueRegex": "\\d{3}-?\\d{2}-?\\d{3}", "Nullable": true}, {"Header": "PG Zip", "HeaderRegex": "((pg|guarantor)\\s?zip)" ,"ValueRegex": "\\d{3}-?\\d{2}-?\\d{3}", "Nullable": true},
{"Header": "PG SSN", "HeaderRegex": "((pg|guarantor)\\s?ssn)" ,"ValueRegex": "[0-2]?\\d\\/\\d{1,2}\\/(19|20)?\\d{2}", "Nullable": true}, {"Header": "PG SSN", "HeaderRegex": "((pg|guarantor)\\s?ssn)" ,"ValueRegex": "[0-2]?\\d\\/\\d{1,2}\\/(19|20)?\\d{2}", "Nullable": true},
{"Header": "DOB", "HeaderRegex": "(dob|date of birth)" ,"ValueRegex": "\\d{3}", "Nullable": true}, {"Header": "DOB", "HeaderRegex": "DATEVALUE" ,"ValueRegex": "\\d{3}", "Nullable": true},
{"Header": "PG1 FICO", "HeaderRegex": "(pg\\d?\\s?FICO)" ,"ValueRegex": "(\\d{1,2},?)*\\d+(.\\d{2})?", "Nullable": true} {"Header": "PG1 FICO", "HeaderRegex": "(pg\\d?\\s?FICO)" ,"ValueRegex": "(\\d{1,2},?)*\\d+(.\\d{2})?", "Nullable": true}
] ]
} }

@ -1,9 +1,9 @@
<template> <template>
<div v-if="invalidDataHeaders.length > 0"> <div v-if="invalidDataHeaders.length > 1000">
<h2>Invalid Headers</h2> <h2>Invalid Headers</h2>
<ul> <ul>
<li v-for="header in invalidDataHeaders" :key="header.documentHeader"> <li v-for="header in invalidDataHeaders" :key="header.label">
{{ header.documentHeader }} {{ header.label }}
</li> </li>
</ul> </ul>
</div> </div>
@ -42,8 +42,7 @@ export default {
}; };
}, },
methods: { methods: {
processUpload(userFile) { processUpload(userFile, invalidHeaders) {
console.log(store.documentHeaders);
// handle null // handle null
if (userFile === null) { if (userFile === null) {
this.invalidDataHeaders = []; this.invalidDataHeaders = [];
@ -55,10 +54,8 @@ export default {
this.userFile = userFile; this.userFile = userFile;
// filter the documentHeaders to get the invalid headers // filter the documentHeaders to get the invalid headers
this.invalidDataHeaders = this.store.documentHeaders.filter( this.invalidDataHeaders = invalidHeaders;
(header) => !header.isValidData //console.log(this.invalidDataHeaders);
);
console.log(this.invalidDataHeaders);
// set isUploaded to true // set isUploaded to true
this.isUploaded = true; this.isUploaded = true;

@ -9,7 +9,8 @@
import { read, utils } from "xlsx"; import { read, utils } from "xlsx";
import { store } from '../store.js' import { store } from '../store.js'
import { HeaderAssociator } from '../helpers.js' import { UserHeader } from "@/userHeader";
import { HeaderTemplate, associateHeaders } from "@/headerTemplate";
function findFirstNonBlankRow(worksheet) { function findFirstNonBlankRow(worksheet) {
const range = utils.decode_range(worksheet['!ref']); const range = utils.decode_range(worksheet['!ref']);
@ -58,10 +59,21 @@ export default {
const resp = await fetch(process.env.VUE_APP_TEMPLATE_HEADERS_ENDPOINT, configRequestOptions); const resp = await fetch(process.env.VUE_APP_TEMPLATE_HEADERS_ENDPOINT, configRequestOptions);
let respJson = await resp.json(); let respJson = await resp.json();
console.log(respJson); console.log(respJson);
this.headerTemplateList = respJson["HeaderTemplate"]; this.headerTemplateList = respJson["HeaderTemplate"].map(headerTemplate => {
return new HeaderTemplate (headerTemplate["Header"],headerTemplate["HeaderRegex"],
this.validateData, headerTemplate["ValueRegex"], headerTemplate["Nullable"]);
});
// Sort this list to make association faster
this.headerTemplateList.sort((a,b) => {
const ha = a.header.toLowerCase();
const hb = b.header.toLowerCase();
if (ha < hb) return -1;
if (ha > hb) return 1;
return 0;
});
console.info("Recieved HeaderTemplateList: ", this.headerTemplateList);
//FIXME: This is only for testing purposes, REMOVE THIS //FIXME: This is only for testing purposes, REMOVE THIS
this.validateData = true;//respJson["ValidateData"]; this.validateData = true;//respJson["ValidateData"];
console.log(this.headerTemplateList);
console.log(this.validateData); console.log(this.validateData);
} catch (error) { } catch (error) {
//FIXME: emit error internal issues //FIXME: emit error internal issues
@ -76,6 +88,14 @@ export default {
// Clear old file data // Clear old file data
store.missingHeaders = []; store.missingHeaders = [];
store.documentHeaders = []; store.documentHeaders = [];
// If the user had previously selected a file,
// we need to clear the old header associations
if (this.userFile !== null) {
this.headerTemplateList.map(headerTemplate => {
headerTemplate.userHeader = null;
})
}
this.userFile = event.target.files[0]; this.userFile = event.target.files[0];
this.canSubmit = true; this.canSubmit = true;
@ -83,7 +103,6 @@ export default {
getHeaders(worksheet, sheetName, headerIndex) { getHeaders(worksheet, sheetName, headerIndex) {
// Store the found headers // Store the found headers
var combinedHeadersString = "";
// Use the range to make sure we don't go out of bounds // Use the range to make sure we don't go out of bounds
const range = utils.decode_range(worksheet['!ref']); const range = utils.decode_range(worksheet['!ref']);
for (let col = 0; col < range.e.c; col++){ for (let col = 0; col < range.e.c; col++){
@ -91,13 +110,13 @@ export default {
let cellObj = worksheet[cellAddress]; let cellObj = worksheet[cellAddress];
// n represents number type (which is probably the start of cashflow dates) // n represents number type (which is probably the start of cashflow dates)
if (cellObj === undefined || cellObj.t === 'n') { break } if (cellObj === undefined || cellObj.t === 'n') { break }
// Add the header to the combined headers string let dataAddress = utils.encode_cell({c: col, r: headerIndex + 1});
combinedHeadersString += cellObj.v; let dataValue = worksheet[dataAddress] ? worksheet[dataAddress].v : null;
let headerAssociator = new HeaderAssociator(cellObj.v, sheetName, cellAddress);
if (!this.validateData) {headerAssociator.isValidData = true;} // Record the user header
store.documentHeaders.push(headerAssociator); let userHeader = new UserHeader(cellObj.v, sheetName, cellAddress, dataValue);
store.documentHeaders.push(userHeader);
} }
return combinedHeadersString;
}, },
async parseUpload() { async parseUpload() {
@ -111,8 +130,7 @@ export default {
return; return;
} }
var validWorksheets = [] let validWorksheets = false;
var combinedHeadersString = '';
// Go through each worksheet // Go through each worksheet
for (let sheetName of workbook.SheetNames) { for (let sheetName of workbook.SheetNames) {
// Open the actual worksheet // Open the actual worksheet
@ -123,73 +141,39 @@ export default {
// Probably not a sheet we need to process // Probably not a sheet we need to process
console.warn(`${sheetName} | No header row found!`); console.warn(`${sheetName} | No header row found!`);
} }
// Add the header to the combined headers string // getHeaders will created the UserHeader objects
// getHeaders will created the AssociatedHeaders objects this.getHeaders(worksheet, sheetName, headerIndex);
combinedHeadersString += this.getHeaders(worksheet, sheetName, headerIndex); validWorksheets = true;
// Note which worksheets are actually being processed
validWorksheets.push(sheetName);
} }
if (validWorksheets.length === 0) { if (!validWorksheets) {
//FIXME: emit bad spreadsheet to App //FIXME: emit bad spreadsheet to App
console.error("No worksheets found!"); console.error("No worksheets found!");
return; return;
} }
// Check each template regex against the combined headers string // Sort the user headers to make association faster
for (const headerTemplate of this.headerTemplateList) { store.documentHeaders.sort((a,b) => {
// 'i' option means ignore case const ha = a.label.toLowerCase();
let headerRegex = RegExp(headerTemplate["HeaderRegex"],"i"); const hb = b.label.toLowerCase();
let headerName = headerTemplate["Header"]; if (ha < hb) return -1;
if (ha > hb) return 1;
return 0;
});
// Check to see if the template header is present in the combined headers string console.log("User Headers:", this.userHeaders);
let searchResults = headerRegex.exec(combinedHeadersString); console.log("Template Headers:", this.headerTemplateList);
if (searchResults === null) { let processedArrays = associateHeaders(store.documentHeaders, this.headerTemplateList);
store.missingHeaders.push(headerName); console.log("UPDATED Template Headers:", this.headerTemplateList);
continue; store.missingHeaders = this.headerTemplateList.filter(headerTemplate => !headerTemplate.isAssociated());
} store.documentHeaders = processedArrays[0];
let docHeader = searchResults[0]; //TODO: Deal with invalid headers
let invalidHeaders = processedArrays[1];
// Find the associated header
for (let headerAssociator of store.documentHeaders) {
if (headerAssociator.isSet()) {continue}
if (headerAssociator.documentHeader === docHeader) {
// Set the associated template header
headerAssociator.swapTemplateHeader(headerName);
if (this.validateData) {
// If we want to validate the data, then check the data against the regex
let isNullable = headerTemplate["Nullable"];
let headerAddress = utils.decode_cell(headerAssociator.docHeaderAddress);
// Now we can get the value of the cell below the header
let valueCellAddress = utils.encode_cell(headerAddress.r + 1);
// We need to know which worksheet this cell belongs to
let worksheet = workbook.Sheets[headerAssociator.docWorksheetName];
let valueObj = worksheet[valueCellAddress];
// Check if the cell is null, if so does it matter?
if (valueObj !== undefined ) {
// Test the value against regex
let valueRegex = RegExp(headerTemplate["ValueRegex"],'i');
let dataValue = valueObj.v.toString();
let isValid = valueRegex.test(dataValue);
if (!isValid) {
// record the invalid data and set isValidData to false
headerAssociator.invalidData(dataValue);
}
} else {
// isValid matches isNullable
headerAssociator.isValidData = isNullable;
}
}
// We found the header and processed it so stop looking
break;
}
}
}
//TODO: Remove logs //TODO: Remove logs
console.log(`Document headers (${store.documentHeaders.length}): ${store.documentHeaders}`); console.log(`Document headers (${store.documentHeaders.length}): ${store.documentHeaders}`);
console.log(`Missing headers (${store.missingHeaders.length}): ${store.missingHeaders}`); console.log(`Missing headers (${store.missingHeaders.length})`, store.missingHeaders);
// emit the uploaded file & parsed data up to parent // emit the uploaded file & parsed data up to parent
this.$emit('parsed-upload', this.userFile); this.$emit('parsed-upload', this.userFile, invalidHeaders);
} }
} }
} }

@ -4,11 +4,11 @@
<h3 class="text-center">{{itemText}}</h3> <h3 class="text-center">{{itemText}}</h3>
</div> </div>
<div class="box-body"> <div class="box-body">
<select class="form-control" @change="updateSelectedDocHeader($event)"> <select id="sel" class="form-control" @change="changeSelectedHeader($event)">
<option>{{firstValue}}</option> <option :value="itemText"></option>
<option v-for="headerIndex in filteredHeaders" :key="headerIndex" :value="headerIndex">{{store.documentHeaders[headerIndex].documentHeader}}</option> <option v-for="({ label }, index) in store.documentHeaders" :key="itemText+index" :value="index">{{ label }}</option>
</select> </select>
<button type="button" class="btn btn-primary" @click="changeA" :disabled="this.selectedDocHeaderIndex === null">Confirm Choice</button> <button type="button" class="btn btn-primary" @click="changeA" :disabled="isConfirmed">Confirm Choice</button>
</div> </div>
</div> </div>
</template> </template>
@ -22,51 +22,52 @@ export default {
type: String, type: String,
required: true required: true
}, },
headerTemplateIndex: Number,
}, },
data() { data() {
return { return {
selectedDocHeaderIndex: null, selectedHeader: "",
confirmedHeader: null,
isConfirmed: false, isConfirmed: false,
store store
} }
}, },
methods: { methods: {
updateSelectedDocHeader(event) { changeSelectedHeader(event) {
// If a correction was previously made, update the parent a correction was unmade this.selectedHeader = event.target.value;
if (this.isConfirmed) { this.$emit('header-change', -1); }
this.isConfirmed = false;
// If the old index is not null, we need to update it's docHeader to be null
if (this.selectedDocHeaderIndex !== null) {
this.store.documentHeaders[this.selectedDocHeaderIndex].swapTemplateHeader(null);
}
// Set the new index of the doc header
this.selectedDocHeaderIndex = event.target.value;
console.log(this.selectedDocHeaderIndex);
}, },
changeA() { changeA() {
// Change the templateHeader in the docHeader at selectedDocHeader console.warn("BEFORE ",store.documentHeaders);
this.confirmedHeader = this.selectedHeader !== "" ? store.documentHeaders.splice(this.selectedHeader,1)[0] : null;
console.info("confirmedHeader ",this.confirmedHeader);
let oldHeader = store.missingHeaders[this.headerTemplateIndex]
.swapUserHeader(this.confirmedHeader);
this.isConfirmed = true; this.isConfirmed = true;
this.store.documentHeaders[this.selectedDocHeaderIndex].templateHeader = this.itemText; console.warn("AFTER ",store.documentHeaders);
if (oldHeader) {
store.documentHeaders.push(oldHeader);
store.documentHeaders.sort((a,b) => {
const ha = a.label.toLowerCase();
const hb = b.label.toLowerCase();
if (ha < hb) return -1;
if (ha > hb) return 1;
return 0;
});
}
console.warn("AFTER 2",store.documentHeaders);
document.getElementById('sel').value = this.itemText;
this.$emit('header-change', 1); this.$emit('header-change', 1);
} }
}, },
computed: { computed: {
filteredHeaders() {
// Get the index of headers that are invalid
return store.documentHeaders.reduce((acc, header, index) => {
if (!header.isSet()) {
acc.push(index);
}
return acc;
}, []);
},
firstValue() { firstValue() {
// When a doc header is confirmed it is removed from the list, we need to set it here return this.isConfirmed ? store.missingHeaders[this.headerTemplateIndex].userHeader.label : null;
// If no doc header is confirmed, allow the user to select a null
return this.isConfirmed ? this.store.documentHeaders[this.selectedDocHeaderIndex].documentHeader : null
} }
} }
} }
</script> </script>

@ -2,7 +2,7 @@
<div v-if="store.missingHeaders.length > 0" class="missing-headers" :style="isFixed ? {'background-color': '#0a6e11'} : {'background-color': '#990b0b'}" > <div v-if="store.missingHeaders.length > 0" class="missing-headers" :style="isFixed ? {'background-color': '#0a6e11'} : {'background-color': '#990b0b'}" >
<h1>Missing Headers:</h1> <h1>Missing Headers:</h1>
<div class="grid" :style="isFixed ? {'background-color': '#0b3b0e'} : {'background-color': '#800000'}"> <div class="grid" :style="isFixed ? {'background-color': '#0b3b0e'} : {'background-color': '#800000'}">
<HeaderCorrection @header-change="itemChanged" v-for="header in store.missingHeaders" :key="header" :itemText="header"/> <HeaderCorrection @header-change="itemChanged" v-for="({header}, index) in store.missingHeaders" :key="header.header" :itemText="header" :header-template-index="index"/>
</div> </div>
<button v-if="this.isFixed" class="submit-button" @click="submitCorrections">Submit Corrections</button> <button v-if="this.isFixed" class="submit-button" @click="submitCorrections">Submit Corrections</button>
</div> </div>

@ -2,6 +2,8 @@
* Represents a HeaderTemplate for associating UserHeaders in an uploaded Excel file. * Represents a HeaderTemplate for associating UserHeaders in an uploaded Excel file.
*/ */
export class HeaderTemplate { export class HeaderTemplate {
userHeader = null;
/** /**
* Creates a new HeaderTemplate. * Creates a new HeaderTemplate.
* @param {string} header - The label for this HeaderTemplate. * @param {string} header - The label for this HeaderTemplate.
@ -97,7 +99,7 @@ export class HeaderTemplate {
* Checks if this HeaderTemplate is associated with a UserHeader. * Checks if this HeaderTemplate is associated with a UserHeader.
* @returns {boolean} - Returns true if associated, false otherwise. * @returns {boolean} - Returns true if associated, false otherwise.
*/ */
isAssociated() { typeof this.userHeaders!== 'undefined' && this.userHeaders!== null; } isAssociated() { return this.userHeader !== null }
swapUserHeader(newUserHeader = null) { swapUserHeader(newUserHeader = null) {
let oldUserHeader = this.userHeader; let oldUserHeader = this.userHeader;

@ -38,12 +38,12 @@ export class HeaderAssociator {
this.docHeaderAddress = address this.docHeaderAddress = address
} }
set isValidData(newValidData) { set validAssociatedData(newValidData) {
if (typeof newValidData !== 'boolean') { if (typeof newValidData !== 'boolean') {
console.error(`${this.documentHeader} | HeaderAssociator.validData must be a boolean: ${newValidData}`); console.error(`${this.documentHeader} | HeaderAssociator.validData must be a boolean: ${newValidData}`);
this.isValidData = false; this.validAssociatedData = false;
} }
else this.isValidData = newValidData; else this.validAssociatedData = newValidData;
} }
swapTemplateHeader(newTemplateHeader) { swapTemplateHeader(newTemplateHeader) {
@ -58,7 +58,7 @@ export class HeaderAssociator {
invalidData(dataSample) { invalidData(dataSample) {
// If data is found to be invalid, set isValidData to false and record the data // If data is found to be invalid, set isValidData to false and record the data
this.docData = dataSample this.docData = dataSample
this.isValidData = false this.validAssociatedData = false
} }
isSet() { isSet() {

Loading…
Cancel
Save