IO-3515 Minimally functional form fill out.
This commit is contained in:
@@ -434,7 +434,7 @@ function BillEnterModalContainer({ billEnterModal, toggleModalVisible, bodyshop,
|
|||||||
formdata.append("jobid", billEnterModal.context.job.id);
|
formdata.append("jobid", billEnterModal.context.job.id);
|
||||||
formdata.append("bodyshopid", bodyshop.id);
|
formdata.append("bodyshopid", bodyshop.id);
|
||||||
formdata.append("partsorderid", "3dd26419-a139-4399-af4e-43eeb6f0dbad");
|
formdata.append("partsorderid", "3dd26419-a139-4399-af4e-43eeb6f0dbad");
|
||||||
// formdata.append("skipTextract", "true"); // For testing purposes
|
//formdata.append("skipTextract", "true"); // For testing purposes
|
||||||
axios
|
axios
|
||||||
.post("/ai/bill-ocr", formdata)
|
.post("/ai/bill-ocr", formdata)
|
||||||
.then(({ data }) => {
|
.then(({ data }) => {
|
||||||
@@ -451,6 +451,17 @@ function BillEnterModalContainer({ billEnterModal, toggleModalVisible, bodyshop,
|
|||||||
e.target.value = "";
|
e.target.value = "";
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
form.setFieldsValue({ vendorid: "72634cde-8dfa-457c-8c04-08621e712d67" });
|
||||||
|
form.setFieldsValue({ vendorid: "72634cde-8dfa-457c-8c04-08621e712d67" });
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log("Form Values", form.getFieldsValue());
|
||||||
|
}, 1000);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Test form
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
console.log("Fields Object", form.getFieldsValue());
|
console.log("Fields Object", form.getFieldsValue());
|
||||||
|
|||||||
@@ -11,8 +11,13 @@ const VendorSearchSelect = ({ value, onChange, options, onSelect, disabled, pref
|
|||||||
const [option, setOption] = useState(value);
|
const [option, setOption] = useState(value);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.log("*** ~ VendorSearchSelect ~ USEEFFECT:", value, option);
|
||||||
if (value !== option && onChange) {
|
if (value !== option && onChange) {
|
||||||
onChange(option);
|
if (value && !option) {
|
||||||
|
onChange(value);
|
||||||
|
} else {
|
||||||
|
onChange(option);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [value, option, onChange]);
|
}, [value, option, onChange]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
const client = require("../../graphql-client/graphql-client").client;
|
|
||||||
const Fuse = require('fuse.js');
|
const Fuse = require('fuse.js');
|
||||||
const { has } = require("lodash");
|
const { has } = require("lodash");
|
||||||
|
|
||||||
@@ -50,8 +50,9 @@ const mergeResults = (resultsArray, weights = []) => {
|
|||||||
.slice(0, 5); // Return top 5 results
|
.slice(0, 5); // Return top 5 results
|
||||||
};
|
};
|
||||||
|
|
||||||
async function generateBillFormData({ processedData, jobid, bodyshopid, partsorderid }) {
|
async function generateBillFormData({ processedData, jobid, bodyshopid, partsorderid, req }) {
|
||||||
//TODO: Should this be using the client auth token to limit results? Most likely.
|
const client = req.userGraphQLClient;
|
||||||
|
|
||||||
//TODO: Add in vendor data.
|
//TODO: Add in vendor data.
|
||||||
const jobData = await client.request(`
|
const jobData = await client.request(`
|
||||||
query QUERY_BILL_OCR_DATA($jobid: uuid!, $partsorderid: uuid!) {
|
query QUERY_BILL_OCR_DATA($jobid: uuid!, $partsorderid: uuid!) {
|
||||||
@@ -61,6 +62,10 @@ async function generateBillFormData({ processedData, jobid, bodyshopid, partsord
|
|||||||
}
|
}
|
||||||
jobs_by_pk(id: $jobid) {
|
jobs_by_pk(id: $jobid) {
|
||||||
id
|
id
|
||||||
|
bodyshop{
|
||||||
|
id
|
||||||
|
md_responsibility_centers
|
||||||
|
}
|
||||||
joblines {
|
joblines {
|
||||||
id
|
id
|
||||||
line_desc
|
line_desc
|
||||||
@@ -121,6 +126,22 @@ async function generateBillFormData({ processedData, jobid, bodyshopid, partsord
|
|||||||
const joblineMatches = joblineFuzzySearch({ fuseToSearch: jobLineDescFuse, processedData });
|
const joblineMatches = joblineFuzzySearch({ fuseToSearch: jobLineDescFuse, processedData });
|
||||||
console.log("*** ~ generateBillFormData ~ joblineMatches:", joblineMatches);
|
console.log("*** ~ generateBillFormData ~ joblineMatches:", joblineMatches);
|
||||||
|
|
||||||
|
const vendorFuse = new Fuse(
|
||||||
|
jobData.vendors,
|
||||||
|
{
|
||||||
|
keys: ['name'],
|
||||||
|
threshold: 0.4, //Adjust as needed for matching sensitivity,
|
||||||
|
includeScore: true,
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const vendorMatches = vendorFuse.search(processedData.summary?.NAME?.value || processedData.summary?.VENDOR_NAME?.value);
|
||||||
|
console.log("*** ~ generateBillFormData ~ vendorMatches:", vendorMatches);
|
||||||
|
let vendorid;
|
||||||
|
if (vendorMatches.length > 0) {
|
||||||
|
vendorid = vendorMatches[0].item.id;
|
||||||
|
}
|
||||||
const { jobs_by_pk: job, parts_orders_by_pk: partsOrder } = jobData;
|
const { jobs_by_pk: job, parts_orders_by_pk: partsOrder } = jobData;
|
||||||
if (!job) {
|
if (!job) {
|
||||||
throw new Error('Job not found for bill form data generation.');
|
throw new Error('Job not found for bill form data generation.');
|
||||||
@@ -132,7 +153,7 @@ async function generateBillFormData({ processedData, jobid, bodyshopid, partsord
|
|||||||
//Create the form data structure for the bill posting screen.
|
//Create the form data structure for the bill posting screen.
|
||||||
const billFormData = {
|
const billFormData = {
|
||||||
"jobid": jobid,
|
"jobid": jobid,
|
||||||
"vendorid": null,
|
"vendorid": vendorid,
|
||||||
"invoice_number": processedData.summary?.INVOICE_RECEIPT_ID?.value,
|
"invoice_number": processedData.summary?.INVOICE_RECEIPT_ID?.value,
|
||||||
"date": processedData.summary?.INVOICE_RECEIPT_DATE?.value,
|
"date": processedData.summary?.INVOICE_RECEIPT_DATE?.value,
|
||||||
"is_credit_memo": false,
|
"is_credit_memo": false,
|
||||||
@@ -145,7 +166,7 @@ async function generateBillFormData({ processedData, jobid, bodyshopid, partsord
|
|||||||
//if there isn't then we can do the below.
|
//if there isn't then we can do the below.
|
||||||
|
|
||||||
let actualPrice, actualCost;
|
let actualPrice, actualCost;
|
||||||
|
//TODO: What is several match on the normalized name? We need to pick the most likely one.
|
||||||
const hasNormalizedActualPrice = Object.keys(textractLineItem).find(key => textractLineItem[key].normalizedLabel === 'actual_price');
|
const hasNormalizedActualPrice = Object.keys(textractLineItem).find(key => textractLineItem[key].normalizedLabel === 'actual_price');
|
||||||
const hasNormalizedActualCost = Object.keys(textractLineItem).find(key => textractLineItem[key].normalizedLabel === 'actual_cost');
|
const hasNormalizedActualCost = Object.keys(textractLineItem).find(key => textractLineItem[key].normalizedLabel === 'actual_cost');
|
||||||
|
|
||||||
@@ -190,8 +211,9 @@ async function generateBillFormData({ processedData, jobid, bodyshopid, partsord
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: Do we need to verify the lines to see if it is a unit price or total price (i.e. quantity * price)
|
||||||
const lineObject = {
|
const lineObject = {
|
||||||
"line_desc": matchToUse.item?.line_desc,
|
"line_desc": matchToUse?.item?.line_desc || textractLineItem.ITEM?.value || "NO DESCRIPTION",
|
||||||
"quantity": textractLineItem.QUANTITY?.value, // convert to integer?
|
"quantity": textractLineItem.QUANTITY?.value, // convert to integer?
|
||||||
"actual_price": normalizePrice(actualPrice),
|
"actual_price": normalizePrice(actualPrice),
|
||||||
"actual_cost": normalizePrice(actualCost),
|
"actual_cost": normalizePrice(actualCost),
|
||||||
@@ -201,7 +223,7 @@ async function generateBillFormData({ processedData, jobid, bodyshopid, partsord
|
|||||||
"state": false,
|
"state": false,
|
||||||
"local": false
|
"local": false
|
||||||
},
|
},
|
||||||
"joblineid": matchToUse.item?.id || "noline",
|
"joblineid": matchToUse?.item?.id || "noline",
|
||||||
}
|
}
|
||||||
return lineObject
|
return lineObject
|
||||||
})
|
})
|
||||||
@@ -213,7 +235,14 @@ async function generateBillFormData({ processedData, jobid, bodyshopid, partsord
|
|||||||
|
|
||||||
function joblineFuzzySearch({ fuseToSearch, processedData }) {
|
function joblineFuzzySearch({ fuseToSearch, processedData }) {
|
||||||
const matches = []
|
const matches = []
|
||||||
processedData.lineItems.forEach(lineItem => {
|
const searchStats = []; // Track search statistics
|
||||||
|
|
||||||
|
processedData.lineItems.forEach((lineItem, lineIndex) => {
|
||||||
|
const lineStats = {
|
||||||
|
lineNumber: lineIndex + 1,
|
||||||
|
searches: []
|
||||||
|
};
|
||||||
|
|
||||||
// Refined ITEM search (multi-word description)
|
// Refined ITEM search (multi-word description)
|
||||||
const refinedItemResults = (() => {
|
const refinedItemResults = (() => {
|
||||||
if (!lineItem.ITEM?.value) return [];
|
if (!lineItem.ITEM?.value) return [];
|
||||||
@@ -223,13 +252,19 @@ function joblineFuzzySearch({ fuseToSearch, processedData }) {
|
|||||||
|
|
||||||
// 1: Full string search
|
// 1: Full string search
|
||||||
const fullSearch = fuseToSearch.search(normalized);
|
const fullSearch = fuseToSearch.search(normalized);
|
||||||
|
lineStats.searches.push({ type: 'ITEM - Full String', term: normalized, results: fullSearch.length });
|
||||||
|
|
||||||
// 2: Search individual significant words (3+ chars)
|
// 2: Search individual significant words (3+ chars)
|
||||||
const words = normalized.split(' ').filter(w => w.length >= 3);
|
const words = normalized.split(' ').filter(w => w.length >= 3);
|
||||||
const wordSearches = words.map(word => fuseToSearch.search(word));
|
const wordSearches = words.map(word => {
|
||||||
|
const results = fuseToSearch.search(word);
|
||||||
|
lineStats.searches.push({ type: 'ITEM - Individual Word', term: word, results: results.length });
|
||||||
|
return results;
|
||||||
|
});
|
||||||
|
|
||||||
// 3: Search without spaces entirely
|
// 3: Search without spaces entirely
|
||||||
const noSpaceSearch = fuseToSearch.search(normalized.replace(/\s+/g, ''));
|
const noSpaceSearch = fuseToSearch.search(normalized.replace(/\s+/g, ''));
|
||||||
|
lineStats.searches.push({ type: 'ITEM - No Spaces', term: normalized.replace(/\s+/g, ''), results: noSpaceSearch.length });
|
||||||
|
|
||||||
// Merge results with weights (full search weighted higher)
|
// Merge results with weights (full search weighted higher)
|
||||||
return mergeResults(
|
return mergeResults(
|
||||||
@@ -247,18 +282,23 @@ function joblineFuzzySearch({ fuseToSearch, processedData }) {
|
|||||||
|
|
||||||
// 1: Normalized search (no spaces/special chars)
|
// 1: Normalized search (no spaces/special chars)
|
||||||
const normalizedSearch = fuseToSearch.search(normalized);
|
const normalizedSearch = fuseToSearch.search(normalized);
|
||||||
|
lineStats.searches.push({ type: 'PRODUCT_CODE - Normalized', term: normalized, results: normalizedSearch.length });
|
||||||
|
|
||||||
// 2: Original with minimal cleaning
|
// 2: Original with minimal cleaning
|
||||||
const minimalClean = productCode.replace(/\s+/g, '').toUpperCase();
|
const minimalClean = productCode.replace(/\s+/g, '').toUpperCase();
|
||||||
const minimalSearch = fuseToSearch.search(minimalClean);
|
const minimalSearch = fuseToSearch.search(minimalClean);
|
||||||
|
lineStats.searches.push({ type: 'PRODUCT_CODE - Minimal Clean', term: minimalClean, results: minimalSearch.length });
|
||||||
|
|
||||||
// 3: Search with dashes (common in part numbers)
|
// 3: Search with dashes (common in part numbers)
|
||||||
const withDashes = productCode.replace(/[^a-zA-Z0-9-]/g, '').toUpperCase();
|
const withDashes = productCode.replace(/[^a-zA-Z0-9-]/g, '').toUpperCase();
|
||||||
const dashSearch = fuseToSearch.search(withDashes);
|
const dashSearch = fuseToSearch.search(withDashes);
|
||||||
|
lineStats.searches.push({ type: 'PRODUCT_CODE - With Dashes', term: withDashes, results: dashSearch.length });
|
||||||
|
|
||||||
|
// 4: Search letters only (remove numbers and special chars)
|
||||||
|
|
||||||
return mergeResults(
|
return mergeResults(
|
||||||
[normalizedSearch, minimalSearch, dashSearch],
|
[normalizedSearch, minimalSearch, dashSearch],
|
||||||
[1.0, 1.1, 1.2] // Prefer fully normalized
|
[1.0, 1.1, 1.2] // Prefer fully normalized, letters-only weighted less
|
||||||
);
|
);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@@ -270,12 +310,14 @@ function joblineFuzzySearch({ fuseToSearch, processedData }) {
|
|||||||
|
|
||||||
// 1: Exact price match
|
// 1: Exact price match
|
||||||
const exactSearch = fuseToSearch.search(price);
|
const exactSearch = fuseToSearch.search(price);
|
||||||
|
lineStats.searches.push({ type: 'PRICE - Exact', term: price, results: exactSearch.length });
|
||||||
|
|
||||||
// 2: Price with 2 decimal places
|
// 2: Price with 2 decimal places
|
||||||
const priceFloat = parseFloat(price);
|
const priceFloat = parseFloat(price);
|
||||||
if (!isNaN(priceFloat)) {
|
if (!isNaN(priceFloat)) {
|
||||||
const formattedPrice = priceFloat.toFixed(2);
|
const formattedPrice = priceFloat.toFixed(2);
|
||||||
const formattedSearch = fuseToSearch.search(formattedPrice);
|
const formattedSearch = fuseToSearch.search(formattedPrice);
|
||||||
|
lineStats.searches.push({ type: 'PRICE - Formatted (2 decimals)', term: formattedPrice, results: formattedSearch.length });
|
||||||
|
|
||||||
return mergeResults([exactSearch, formattedSearch], [1.0, 1.1]);
|
return mergeResults([exactSearch, formattedSearch], [1.0, 1.1]);
|
||||||
}
|
}
|
||||||
@@ -291,12 +333,14 @@ function joblineFuzzySearch({ fuseToSearch, processedData }) {
|
|||||||
|
|
||||||
// 1: Exact price match
|
// 1: Exact price match
|
||||||
const exactSearch = fuseToSearch.search(unitPrice);
|
const exactSearch = fuseToSearch.search(unitPrice);
|
||||||
|
lineStats.searches.push({ type: 'UNIT_PRICE - Exact', term: unitPrice, results: exactSearch.length });
|
||||||
|
|
||||||
// 2: Price with 2 decimal places
|
// 2: Price with 2 decimal places
|
||||||
const priceFloat = parseFloat(unitPrice);
|
const priceFloat = parseFloat(unitPrice);
|
||||||
if (!isNaN(priceFloat)) {
|
if (!isNaN(priceFloat)) {
|
||||||
const formattedPrice = priceFloat.toFixed(2);
|
const formattedPrice = priceFloat.toFixed(2);
|
||||||
const formattedSearch = fuseToSearch.search(formattedPrice);
|
const formattedSearch = fuseToSearch.search(formattedPrice);
|
||||||
|
lineStats.searches.push({ type: 'UNIT_PRICE - Formatted (2 decimals)', term: formattedPrice, results: formattedSearch.length });
|
||||||
|
|
||||||
return mergeResults([exactSearch, formattedSearch], [1.0, 1.1]);
|
return mergeResults([exactSearch, formattedSearch], [1.0, 1.1]);
|
||||||
}
|
}
|
||||||
@@ -371,7 +415,48 @@ function joblineFuzzySearch({ fuseToSearch, processedData }) {
|
|||||||
hasMatch: finalMatches.length > 0
|
hasMatch: finalMatches.length > 0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
searchStats.push(lineStats);
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Output search statistics table
|
||||||
|
console.log('\n═══════════════════════════════════════════════════════════════════════');
|
||||||
|
console.log(' FUSE.JS SEARCH STATISTICS');
|
||||||
|
console.log('═══════════════════════════════════════════════════════════════════════\n');
|
||||||
|
|
||||||
|
searchStats.forEach(lineStat => {
|
||||||
|
console.log(`📄 Line Item #${lineStat.lineNumber}:`);
|
||||||
|
console.log('─'.repeat(75));
|
||||||
|
|
||||||
|
if (lineStat.searches.length > 0) {
|
||||||
|
const tableData = lineStat.searches.map(search => ({
|
||||||
|
'Search Type': search.type,
|
||||||
|
'Search Term': search.term.substring(0, 40) + (search.term.length > 40 ? '...' : ''),
|
||||||
|
'Results': search.results
|
||||||
|
}));
|
||||||
|
console.table(tableData);
|
||||||
|
} else {
|
||||||
|
console.log(' No searches performed for this line item.\n');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Summary statistics
|
||||||
|
const totalSearches = searchStats.reduce((sum, stat) => sum + stat.searches.length, 0);
|
||||||
|
const totalResults = searchStats.reduce((sum, stat) =>
|
||||||
|
sum + stat.searches.reduce((s, search) => s + search.results, 0), 0);
|
||||||
|
const avgResultsPerSearch = totalSearches > 0 ? (totalResults / totalSearches).toFixed(2) : 0;
|
||||||
|
|
||||||
|
console.log('═══════════════════════════════════════════════════════════════════════');
|
||||||
|
console.log(' SUMMARY');
|
||||||
|
console.log('═══════════════════════════════════════════════════════════════════════');
|
||||||
|
console.table({
|
||||||
|
'Total Line Items': processedData.lineItems.length,
|
||||||
|
'Total Searches Performed': totalSearches,
|
||||||
|
'Total Results Found': totalResults,
|
||||||
|
'Average Results per Search': avgResultsPerSearch
|
||||||
|
});
|
||||||
|
console.log('═══════════════════════════════════════════════════════════════════════\n');
|
||||||
|
|
||||||
return matches
|
return matches
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,18 +38,21 @@ function normalizeLabelName(labelText) {
|
|||||||
'part_no': standardizedFieldsnames.part_no,
|
'part_no': standardizedFieldsnames.part_no,
|
||||||
'part_num': standardizedFieldsnames.part_no,
|
'part_num': standardizedFieldsnames.part_no,
|
||||||
'part_number': standardizedFieldsnames.part_no,
|
'part_number': standardizedFieldsnames.part_no,
|
||||||
|
'item_no': standardizedFieldsnames.part_no,
|
||||||
'price': standardizedFieldsnames.actual_price,
|
'price': standardizedFieldsnames.actual_price,
|
||||||
'amount': standardizedFieldsnames.actual_price,
|
//'amount': standardizedFieldsnames.actual_price,
|
||||||
'list_price': standardizedFieldsnames.actual_price,
|
'list_price': standardizedFieldsnames.actual_price,
|
||||||
'unit_price': standardizedFieldsnames.actual_price,
|
'unit_price': standardizedFieldsnames.actual_price,
|
||||||
'list': standardizedFieldsnames.actual_price,
|
'list': standardizedFieldsnames.actual_price,
|
||||||
'retail_price': standardizedFieldsnames.actual_price,
|
'retail_price': standardizedFieldsnames.actual_price,
|
||||||
'net': standardizedFieldsnames.actual_cost,
|
'net': standardizedFieldsnames.actual_cost,
|
||||||
'selling_price': standardizedFieldsnames.actual_cost,
|
'selling_price': standardizedFieldsnames.actual_cost,
|
||||||
|
'net_price': standardizedFieldsnames.actual_cost,
|
||||||
|
'net_cost': standardizedFieldsnames.actual_cost
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return labelMap[normalized] || `UNKNOWN_${normalized}`; // TODO: Should we monitor unmapped labels?
|
return labelMap[normalized] || `NOT_MAPPED => ${normalized}`; // TODO: Should we monitor unmapped labels?
|
||||||
}
|
}
|
||||||
|
|
||||||
function processScanData(invoiceData) {
|
function processScanData(invoiceData) {
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ async function handleBillOcr(request, response) {
|
|||||||
response.status(200).send({
|
response.status(200).send({
|
||||||
success: true,
|
success: true,
|
||||||
status: 'COMPLETED',
|
status: 'COMPLETED',
|
||||||
data: await generateBillFormData({ processedData: null, jobid, bodyshopid, partsorderid }), //This is broken if the processedData is not overwritten in the function for testing.
|
data: await generateBillFormData({ processedData: null, jobid, bodyshopid, partsorderid, req: request }), //This is broken if the processedData is not overwritten in the function for testing.
|
||||||
message: 'Invoice processing completed'
|
message: 'Invoice processing completed'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -84,7 +84,7 @@ async function handleBillOcr(request, response) {
|
|||||||
if (fileType === 'image') {
|
if (fileType === 'image') {
|
||||||
console.log('Image => 1 page, processing synchronously');
|
console.log('Image => 1 page, processing synchronously');
|
||||||
const processedData = await processSinglePageDocument(uploadedFile.buffer);
|
const processedData = await processSinglePageDocument(uploadedFile.buffer);
|
||||||
const billForm = await generateBillFormData({ processedData: processedData, jobid, bodyshopid, partsorderid });
|
const billForm = await generateBillFormData({ processedData: processedData, jobid, bodyshopid, partsorderid, req: request });
|
||||||
response.status(200).send({
|
response.status(200).send({
|
||||||
success: true,
|
success: true,
|
||||||
status: 'COMPLETED',
|
status: 'COMPLETED',
|
||||||
@@ -100,7 +100,7 @@ async function handleBillOcr(request, response) {
|
|||||||
// Process synchronously for single-page documents
|
// Process synchronously for single-page documents
|
||||||
console.log('PDF => 1 page, processing synchronously');
|
console.log('PDF => 1 page, processing synchronously');
|
||||||
const processedData = await processSinglePageDocument(uploadedFile.buffer);
|
const processedData = await processSinglePageDocument(uploadedFile.buffer);
|
||||||
const billForm = await generateBillFormData({ processedData: processedData, jobid, bodyshopid, partsorderid });
|
const billForm = await generateBillFormData({ processedData: processedData, jobid, bodyshopid, partsorderid, req: request });
|
||||||
//const billResult = await generateBillFormData({ result, });
|
//const billResult = await generateBillFormData({ result, });
|
||||||
response.status(200).send({
|
response.status(200).send({
|
||||||
success: true,
|
success: true,
|
||||||
|
|||||||
@@ -2,13 +2,15 @@ const express = require("express");
|
|||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const multer = require("multer");
|
const multer = require("multer");
|
||||||
const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
|
const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
|
||||||
|
const withUserGraphQLClientMiddleware = require("../middleware/withUserGraphQLClientMiddleware");
|
||||||
const { handleBillOcr, handleBillOcrStatus } = require("../ai/bill-ocr/bill-ocr");
|
const { handleBillOcr, handleBillOcrStatus } = require("../ai/bill-ocr/bill-ocr");
|
||||||
const { generateBillFormData } = require("../ai/bill-ocr/bill-ocr-generator");
|
const { generateBillFormData } = require("../ai/bill-ocr/bill-ocr-generator");
|
||||||
|
|
||||||
// Configure multer for form data parsing
|
// Configure multer for form data parsing
|
||||||
const upload = multer();
|
const upload = multer();
|
||||||
|
|
||||||
//router.use(validateFirebaseIdTokenMiddleware);
|
router.use(validateFirebaseIdTokenMiddleware);
|
||||||
|
router.use(withUserGraphQLClientMiddleware);
|
||||||
|
|
||||||
router.post("/bill-ocr", upload.single('billScan'), handleBillOcr);
|
router.post("/bill-ocr", upload.single('billScan'), handleBillOcr);
|
||||||
router.get("/bill-ocr/status/:jobId", handleBillOcrStatus);
|
router.get("/bill-ocr/status/:jobId", handleBillOcrStatus);
|
||||||
|
|||||||
Reference in New Issue
Block a user