const path = require("path"); const AxiosLib = require("axios").default; const axios = AxiosLib.create(); const uuid = require("uuid").v4; const FORTELLIS_KEY = "X1FxzLyOk3kjHvMbzdPQXFZShkdbgzuo"; //TODO: Regenerate these keys after testing and move to env vars. const FORTELLIS_SECRET = "7Yvs0wpQeHcUS5r95ht8pqOaAvBq7dHV"; const FORTELLIS_AUTH_URL = "https://identity.fortellis.io/oauth2/aus1p1ixy7YL8cMq02p7/v1/token"; const FORTELLIS_URL = "https://api.fortellis.io"; const ENVSubscriptionID = "5b527d7d-baf3-40bc-adae-e7a541e37363"; //TODO: Replace with the bodyshop.cdk_dealerid let SubscriptionMeta = null; //const ENVSubscriptionID = 'cb59fa04-e53e-4b57-b071-80a48ebc346c'; async function GetAuthToken() { //Done with Authorization Code Flow //https://docs.fortellis.io/docs/tutorials/solution-integration/authorization-code-flow/ const { data: { access_token, expires_in, token_type } } = await axios.post( FORTELLIS_AUTH_URL, {}, { auth: { username: FORTELLIS_KEY, password: FORTELLIS_SECRET }, params: { grant_type: "client_credentials", scope: "anonymous" } } ); return access_token; } async function FetchSubscriptions() { const access_token = await GetAuthToken(); try { const subscriptions = await axios.get(`https://subscriptions.fortellis.io/v1/solution/subscriptions`, { headers: { Authorization: `Bearer ${access_token}` } }); SubscriptionMeta = subscriptions.data.subscriptions.find((s) => s.subscriptionId === ENVSubscriptionID); return SubscriptionMeta; } catch (error) { console.log("🚀 ~ FetchSubscriptions ~ error:", error); } } async function GetDepartmentId({ apiName, debug = false }) { if (!apiName) throw new Error("apiName not provided. Unable to get department without apiName."); if (debug) { console.log("API Names & Departments "); console.log("==========="); console.log( JSON.stringify( SubscriptionMeta.apiDmsInfo.map((a) => ({ name: a.name, departments: a.departments.map((d) => d.id) })), null, 4 ) ); console.log("==========="); } const departmentIds2 = SubscriptionMeta.apiDmsInfo //Get the subscription object. .find((info) => info.name === apiName)?.departments; //Departments are categorized by API name and have an array of departments. return departmentIds2[0].id; //TODO: This makes the assumption that there is only 1 department. } async function MakeFortellisCall({ apiName, url, headers = {}, body = {}, type = "post", debug = false }) { if (debug) console.log(`Executing ${type} to ${url}`); const ReqId = uuid(); const access_token = await GetAuthToken(); const DepartmentId = await GetDepartmentId({ apiName, debug }); if (debug) { console.log( `ReqID: ${ReqId} | SubscriptionID: ${SubscriptionMeta.subscriptionId} | DepartmentId: ${DepartmentId}` ); console.log(`Body Contents: ${JSON.stringify(body, null, 4)}`); } try { let result; switch (type) { case "post": default: result = await axios.post(url, body, { headers: { Authorization: `Bearer ${access_token}`, "Subscription-Id": SubscriptionMeta.subscriptionId, "Request-Id": ReqId, "Department-Id": DepartmentId, ...headers } }); break; case "get": result = await axios.get(url, { headers: { Authorization: `Bearer ${access_token}`, "Subscription-Id": SubscriptionMeta.subscriptionId, "Request-Id": ReqId, "Department-Id": DepartmentId, ...headers } }); break; } if (debug) { console.log(`ReqID: ${ReqId} Data`); console.log(JSON.stringify(result.data, null, 4)); } if (result.data.checkStatusAfterSeconds) { return DelayedCallback({ delayMeta: result.data, access_token, SubscriptionID: SubscriptionMeta.subscriptionId, ReqId, departmentIds: DepartmentId }); } return result.data; } catch (error) { console.log(`ReqID: ${ReqId} Error`, error.response?.data); //console.log(`ReqID: ${ReqId} Full Error`, JSON.stringify(error, null, 4)); } } //Get the status meta, then keep checking and return the result. async function DelayedCallback({ delayMeta, access_token, SubscriptionID, ReqId, departmentIds }) { for (let index = 0; index < 5; index++) { await sleep(delayMeta.checkStatusAfterSeconds * 1000); //Check to see if the call is ready. const statusResult = await axios.get(delayMeta._links.status.href, { headers: { Authorization: `Bearer ${access_token}`, "Subscription-Id": SubscriptionID, "Request-Id": ReqId, "Department-Id": departmentIds[0].id } }); //TODO: Add a check if the status result is not ready, to try again. if (statusResult.data.status === "complete") { //This may have to check again if it isn't ready. const batchResult = await axios.get(statusResult.data._links.result.href, { headers: { Authorization: `Bearer ${access_token}`, "Subscription-Id": SubscriptionID, "Request-Id": ReqId, //"Department-Id": departmentIds[0].id } }); return batchResult; } else { return "Error!!! Still need to implement batch waiting."; } } } function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } async function GetCOA() { console.log("Executing GetCOA"); await MakeFortellisCall({ debug: true, type: "get", apiName: "CDK Drive Post Accounts GL WIP", url: `https://api.fortellis.io/cdk-test/drive/chartofaccounts/v2/bulk`, waitForResult: true }); } async function StartWIP() { const TransactionWip = MakeFortellisCall({ url: "https://api.fortellis.io/cdk-test/drive/glwippost/startWIP", apiName: "CDK Drive Post Accounts GL WIP", body: { acctgDate: "2023-09-26", //job.invoice desc: "TEST TRANSACTION", docType: "3", //pulled from Doc Type workbook m13Flag: "0", // Is this a M13 entry. Presumanbly always 0 refer: "RO12345", //Supposed to be a doc reference number. Presumably the RO? srcCo: "77", srcJrnl: "80", userID: "csr", //bodyshop user userName: "PROGRAM, PARTNER*ADP" //Can leave blank to have this return to default. }, debug: true }); return TransactionWip; } async function InsertBatch({ transID }) { const TransactionWip = MakeFortellisCall({ url: "https://api.fortellis.io/cdk-test/drive/glwippost/transWIP", apiName: "CDK Drive Post Accounts GL WIP", body: [ { acct: "", cntl: "", cntl2: null, credtMemoNo: null, postAmt: Math.round(payer.amount * 100), postDesc: "", //Required if required by the DMS setup prod: null, //Productivity Number statCnt: 1, //Auto count, leave as 1. transID: transID, trgtCoID: "77" //Add this to read from the header } ], debug: true }); } async function DoTheThings() { await FetchSubscriptions(); //What do we have access to? console.log("Sub Access : ", SubscriptionMeta.apiDmsInfo.map((i) => i.name).join(", ")); await GetCOA(); return; //Insert Transactions const TransactionHeader = await StartWIP(); const BatchResult = await InsertBatch({ transID: TransactionHeader.transID }); } DoTheThings();