const logger = require("../utils/logger"); const queries = require("../graphql-client/queries"); const moment = require("moment"); const { captureFixture } = require("./utils/seralizeHelper"); const { TotalsServerSide: totalsServerSideCA } = require("./job-totals"); // Canadian version (imex) const { TotalsServerSide: totalsServerSideUS } = require("./job-totals-USA"); const InstanceMgr = require("../utils/instanceMgr").default; const { uploadFileToS3 } = require("../utils/s3"); // requires two buckets be made per env, job-totals-test, job-totals-production, locally it will // use `job-totals` in the owncloud stack /** * Returns the environment prefix based on NODE_ENV * @returns {string} */ const getEnvPrefix = () => { switch (process.env?.NODE_ENV) { case "test": return "test"; case "production": return "production"; default: return "test"; } }; const envPrefix = getEnvPrefix(); const S3_BUCKET_NAME = process.env?.NODE_ENV === "development" ? "imex-job-totals" : `job-totals-${envPrefix}`; /** * Generates a unique S3 key for the job totals file * @param {string} jobId - The job ID * @returns {string} - S3 key with timestamp */ const generateS3Key = (jobId) => `${jobId}-${moment().toISOString()}.json`; /** * Uploads job totals data to S3 * @param {object} data - The data to upload * @param {string} jobId - The job ID * @param {object} userInfo - User information for logging * @returns {Promise} - The S3 key */ const uploadJobTotalsToS3 = async (data, jobId, userInfo) => { const key = generateS3Key(jobId); try { await uploadFileToS3({ bucketName: S3_BUCKET_NAME, key: key, content: JSON.stringify(data, null, 2), contentType: "application/json" }); logger.log(`Job totals uploaded successfully to ${key}`, "info", userInfo.email, jobId); return key; } catch (error) { logger.log("Failed to upload job totals to S3", "error", userInfo.email, jobId, { error: error?.message, stack: error?.stack }); throw error; // Re-throw for the main handler to catch } }; /** * Fetches job data using GraphQL * @param {object} client - GraphQL client * @param {string} token - Bearer token * @param {string} jobId - Job ID to fetch * @returns {Promise} - Job data */ const fetchJobData = async (client, token, jobId) => { return client .setHeaders({ Authorization: token }) .request(queries.GET_JOB_BY_PK, { id: jobId }) .then((response) => response.jobs_by_pk); }; /** * This function is used to capture job totals json files. * @param {object} req - Express request * @param {object} res - Express response * @returns {Promise} */ const jobTotalsRecorder = async (req, res) => { const { id: jobId } = req.body; const bearerToken = req.BearerToken; const client = req.userGraphQLClient; const userEmail = req?.user?.email; logger.log("Starting job totals recording", "debug", userEmail, jobId); try { // Fetch job data const jobData = await fetchJobData(client, bearerToken, jobId); // Get the appropriate totals function based on instance const totalsFunction = InstanceMgr({ imex: totalsServerSideCA, rome: totalsServerSideUS }); // Calculate the totals const calculatedTotals = await totalsFunction({ body: { job: jobData, client }, req }, res, true); // Prepare data for storage const dataToSave = captureFixture(jobData, calculatedTotals); // Upload to S3 await uploadJobTotalsToS3(dataToSave, jobId, { email: userEmail }); res.status(200).json({ success: true, message: "Job totals recorded successfully" }); } catch (error) { logger.log("Failed to record job totals", "error", userEmail, jobId, { error: error?.message, stack: error?.stack }); // Avoid sending response if it's already been sent if (!res.headersSent) { res.status(503).json({ success: false, message: "Error processing job totals", error: error.message }); } } }; module.exports = jobTotalsRecorder;