IO-3515 add client side polling for now, cost centers.

This commit is contained in:
Patrick Fic
2026-02-10 11:59:53 -08:00
parent c59acb1b72
commit 64454dce2a
4 changed files with 186 additions and 25 deletions

View File

@@ -162,6 +162,9 @@ async function generateBillFormData({ processedData, jobid, bodyshopid, partsord
bodyshop{
id
md_responsibility_centers
cdk_dealerid
pbs_serialnumber
rr_dealerid
}
joblines {
id
@@ -171,6 +174,7 @@ async function generateBillFormData({ processedData, jobid, bodyshopid, partsord
db_price
oem_partno
alt_partno
part_type
}
}
parts_orders_by_pk(id: $partsorderid) {
@@ -186,6 +190,7 @@ async function generateBillFormData({ processedData, jobid, bodyshopid, partsord
act_price
oem_partno
alt_partno
part_type
}
}
}
@@ -325,13 +330,21 @@ async function generateBillFormData({ processedData, jobid, bodyshopid, partsord
}
}
const responsibilityCenters = job.bodyshop.md_responsibility_centers
//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 = {
"line_desc": matchToUse?.item?.line_desc || textractLineItem.ITEM?.value || "NO DESCRIPTION",
"quantity": textractLineItem.QUANTITY?.value, // convert to integer?
"actual_price": normalizePrice(actualPrice),
"actual_cost": normalizePrice(actualCost),
"cost_center": "SETBYCLIENT", //Needs to get set by client side.
"cost_center": matchToUse?.item?.part_type
? bodyshopHasDmsKey(job.bodyshop)
? matchToUse?.item?.part_type !== "PAE"
? matchToUse?.item?.part_type
: null
: responsibilityCenters.defaults &&
(responsibilityCenters.defaults.costs[matchToUse?.item?.part_type] || null)
: null, //Needs to get set by client side.
"applicable_taxes": { //Not sure what to do with these?
"federal": false,
"state": false,
@@ -579,6 +592,10 @@ function joblineFuzzySearch({ fuseToSearch, processedData }) {
return matches
}
const bodyshopHasDmsKey = (bodyshop) =>
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber || bodyshop.rr_dealerid;
module.exports = {
generateBillFormData
}

View File

@@ -111,7 +111,7 @@ async function handleBillOcr(request, response) {
} else {
// Start the Textract job (non-blocking) for multi-page documents
console.log('PDF => 2+ pages, processing asynchronously');
const jobInfo = await startTextractJob(uploadedFile.buffer);
const jobInfo = await startTextractJob(uploadedFile.buffer, { jobid, bodyshopid, partsorderid });
response.status(202).send({
success: true,
@@ -154,13 +154,50 @@ async function handleBillOcrStatus(request, response) {
}
if (jobStatus.status === 'COMPLETED') {
//TODO: This needs to be stored in the redis cache and pulled when it's processed.
//const billForm = await generateBillFormData({ jobid, bodyshopid, partsorderid });
// Generate billForm on-demand if not already generated
let billForm = jobStatus.data?.billForm;
if (!billForm && jobStatus.context) {
try {
console.log('Generating bill form data on-demand...');
billForm = await generateBillFormData({
processedData: jobStatus.data,
jobid: jobStatus.context.jobid,
bodyshopid: jobStatus.context.bodyshopid,
partsorderid: jobStatus.context.partsorderid,
req: request // Now we have request context!
});
// Cache the billForm back to Redis for future requests
await setTextractJob({
redisPubClient,
textractJobId,
jobData: {
...jobStatus,
data: {
...jobStatus.data,
billForm
}
}
});
} catch (error) {
console.error('Error generating bill form data:', error);
response.status(500).send({
status: 'COMPLETED',
error: 'Data processed but failed to generate bill form',
message: error.message,
data: jobStatus.data // Still return the raw processed data
});
return;
}
}
response.status(200).send({
status: 'COMPLETED',
data: jobStatus.data
// data: { ...jobStatus.data, billForm }
data: {
...jobStatus.data,
billForm
}
});
} else if (jobStatus.status === 'FAILED') {
response.status(500).send({
@@ -199,7 +236,7 @@ async function processSinglePageDocument(pdfBuffer) {
};
}
async function startTextractJob(pdfBuffer) {
async function startTextractJob(pdfBuffer, context = {}) {
// Upload PDF to S3 temporarily for Textract async processing
const s3Bucket = process.env.AWS_AI_BUCKET;
const snsTopicArn = process.env.AWS_TEXTRACT_SNS_TOPIC_ARN;
@@ -254,7 +291,8 @@ async function startTextractJob(pdfBuffer) {
status: 'IN_PROGRESS',
s3Key: s3Key,
uploadId: uploadId,
startedAt: new Date().toISOString()
startedAt: new Date().toISOString(),
context: context // Store the context for later use
}
}
);
@@ -349,6 +387,7 @@ async function handleTextractNotification(message) {
// Retrieve the results
const { processedData, originalResponse } = await retrieveTextractResults(textractJobId);
// Store the processed data - billForm will be generated on-demand in the status endpoint
await setTextractJob(
{
redisPubClient,