WIP Fortellis work.

This commit is contained in:
Patrick Fic
2025-03-13 14:06:07 -07:00
parent 6ecc67184d
commit 8623172aa1
4 changed files with 8622 additions and 89 deletions

View File

@@ -11,6 +11,11 @@ Department ID
- May have multiple departments. Appears that financial stuff goes to Accounting, History will go to Service. - May have multiple departments. Appears that financial stuff goes to Accounting, History will go to Service.
- TODO: How do we handle the multiple departments that may come up. - TODO: How do we handle the multiple departments that may come up.
###Internal Questions
* Overview of the redis storing mechanism to cache this data.
*
# GL Wip Posting # GL Wip Posting
## Org Helper Return Data ## Org Helper Return Data

File diff suppressed because it is too large Load Diff

View File

@@ -1,46 +1,34 @@
const path = require('path'); const path = require("path");
const Dinero = require('dinero.js'); const AxiosLib = require("axios").default;
const { gql } = require('graphql-request');
const queries = require('./server/graphql-client/queries');
const GraphQLClient = require('graphql-request').GraphQLClient;
const logger = require('./server/utils/logger');
const { header } = require('./server/email/html');
const { Transaction } = require('firebase-admin/firestore');
const AxiosLib = require('axios').default;
const axios = AxiosLib.create(); const axios = AxiosLib.create();
const uuid = require('uuid').v4; const uuid = require("uuid").v4;
const FORTELLIS_KEY = 'X1FxzLyOk3kjHvMbzdPQXFZShkdbgzuo'; const FORTELLIS_KEY = "X1FxzLyOk3kjHvMbzdPQXFZShkdbgzuo";
const FORTELLIS_SECRET = '7Yvs0wpQeHcUS5r95ht8pqOaAvBq7dHV'; const FORTELLIS_SECRET = "7Yvs0wpQeHcUS5r95ht8pqOaAvBq7dHV";
const FORTELLIS_AUTH_URL = 'https://identity.fortellis.io/oauth2/aus1p1ixy7YL8cMq02p7/v1/token'; const FORTELLIS_AUTH_URL = "https://identity.fortellis.io/oauth2/aus1p1ixy7YL8cMq02p7/v1/token";
const FORTELLIS_URL = 'https://api.fortellis.io'; const FORTELLIS_URL = "https://api.fortellis.io";
const ENVSubscriptionID = '5b527d7d-baf3-40bc-adae-e7a541e37363'; const ENVSubscriptionID = "5b527d7d-baf3-40bc-adae-e7a541e37363"; //Given to us by CDK it seems.
let SubscriptionMeta = null; let SubscriptionMeta = null;
//const ENVSubscriptionID = 'cb59fa04-e53e-4b57-b071-80a48ebc346c'; //const ENVSubscriptionID = 'cb59fa04-e53e-4b57-b071-80a48ebc346c';
function sleep(time, callback) {
var stop = new Date().getTime();
while (new Date().getTime() < stop + time) {}
callback();
}
async function GetAuthToken() { async function GetAuthToken() {
//Done with Authorization Code Flow //Done with Authorization Code Flow
//https://docs.fortellis.io/docs/tutorials/solution-integration/authorization-code-flow/ //https://docs.fortellis.io/docs/tutorials/solution-integration/authorization-code-flow/
const { const {
data: { access_token, expires_in, token_type }, data: { access_token, expires_in, token_type }
} = await axios.post( } = await axios.post(
FORTELLIS_AUTH_URL, FORTELLIS_AUTH_URL,
{}, {},
{ {
auth: { auth: {
username: FORTELLIS_KEY, username: FORTELLIS_KEY,
password: FORTELLIS_SECRET, password: FORTELLIS_SECRET
}, },
params: { params: {
grant_type: 'client_credentials', grant_type: "client_credentials",
scope: 'anonymous', scope: "anonymous"
}, }
}, }
); );
return access_token; return access_token;
} }
@@ -48,52 +36,40 @@ async function GetAuthToken() {
async function FetchSubscriptions() { async function FetchSubscriptions() {
const access_token = await GetAuthToken(); const access_token = await GetAuthToken();
try { try {
const subscriptions = await axios.get( const subscriptions = await axios.get(`https://subscriptions.fortellis.io/v1/solution/subscriptions`, {
`https://subscriptions.fortellis.io/v1/solution/subscriptions`, headers: { Authorization: `Bearer ${access_token}` }
{ });
headers: { Authorization: `Bearer ${access_token}` }, SubscriptionMeta = subscriptions.data.subscriptions.find((s) => s.subscriptionId === ENVSubscriptionID);
},
);
SubscriptionMeta = subscriptions.data.subscriptions.find(
(s) => s.subscriptionId === ENVSubscriptionID,
);
return SubscriptionMeta; return SubscriptionMeta;
} catch (error) { } catch (error) {
console.log('🚀 ~ FetchSubscriptions ~ error:', error); console.log("🚀 ~ FetchSubscriptions ~ error:", error);
} }
} }
async function GetDepartmentId({ apiName, debug = false }) { async function GetDepartmentId({ apiName, debug = false }) {
if (!apiName) throw new Error('apiName not provided. Unable to get department without apiName.'); if (!apiName) throw new Error("apiName not provided. Unable to get department without apiName.");
if (debug) { if (debug) {
console.log('API Names & Departments '); console.log("API Names & Departments ");
console.log('==========='); console.log("===========");
console.log( console.log(
JSON.stringify( JSON.stringify(
SubscriptionMeta.apiDmsInfo.map((a) => ({ SubscriptionMeta.apiDmsInfo.map((a) => ({
name: a.name, name: a.name,
departments: a.departments.map((d) => d.id), departments: a.departments.map((d) => d.id)
})), })),
null, null,
4, 4
), )
); );
console.log('==========='); console.log("===========");
} }
const departmentIds2 = SubscriptionMeta.apiDmsInfo //Get the subscription object. 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. .find((info) => info.name === apiName)?.departments; //Departments are categorized by API name and have an array of departments.
return departmentIds2[0].id; return departmentIds2[0].id; //TODO: This makes the assumption that there is only 1 department.
} }
async function MakeFortellisCall({ async function MakeFortellisCall({ apiName, url, headers = {}, body = {}, type = "post", debug = false }) {
apiName,
url,
headers = {},
body = {},
type = 'post',
debug = false,
}) {
if (debug) console.log(`Executing ${type} to ${url}`); if (debug) console.log(`Executing ${type} to ${url}`);
const ReqId = uuid(); const ReqId = uuid();
const access_token = await GetAuthToken(); const access_token = await GetAuthToken();
@@ -101,7 +77,7 @@ async function MakeFortellisCall({
if (debug) { if (debug) {
console.log( console.log(
`ReqID: ${ReqId} | SubscriptionID: ${SubscriptionMeta.subscriptionId} | DepartmentId: ${DepartmentId}`, `ReqID: ${ReqId} | SubscriptionID: ${SubscriptionMeta.subscriptionId} | DepartmentId: ${DepartmentId}`
); );
console.log(`Body Contents: ${JSON.stringify(body, null, 4)}`); console.log(`Body Contents: ${JSON.stringify(body, null, 4)}`);
} }
@@ -109,27 +85,27 @@ async function MakeFortellisCall({
try { try {
let result; let result;
switch (type) { switch (type) {
case 'post': case "post":
default: default:
result = await axios.post(url, body, { result = await axios.post(url, body, {
headers: { headers: {
Authorization: `Bearer ${access_token}`, Authorization: `Bearer ${access_token}`,
'Subscription-Id': SubscriptionMeta.subscriptionId, "Subscription-Id": SubscriptionMeta.subscriptionId,
'Request-Id': ReqId, "Request-Id": ReqId,
'Department-Id': DepartmentId, "Department-Id": DepartmentId,
...headers, ...headers
}, }
}); });
break; break;
case 'get': case "get":
result = await axios.get(url, { result = await axios.get(url, {
headers: { headers: {
Authorization: `Bearer ${access_token}`, Authorization: `Bearer ${access_token}`,
'Subscription-Id': SubscriptionMeta.subscriptionId, "Subscription-Id": SubscriptionMeta.subscriptionId,
'Request-Id': ReqId, "Request-Id": ReqId,
'Department-Id': DepartmentId, "Department-Id": DepartmentId,
...headers, ...headers
}, }
}); });
break; break;
} }
@@ -138,39 +114,84 @@ async function MakeFortellisCall({
console.log(`ReqID: ${ReqId} Data`); console.log(`ReqID: ${ReqId} Data`);
console.log(JSON.stringify(result.data, null, 4)); 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; return result.data;
} catch (error) { } catch (error) {
console.log(`ReqID: ${ReqId} Error`, error.response?.data); console.log(`ReqID: ${ReqId} Error`, error.response?.data);
//console.log(`ReqID: ${ReqId} Full Error`, JSON.stringify(error, null, 4)); //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() { async function GetCOA() {
console.log('Executing GetCOA'); console.log("Executing GetCOA");
await MakeFortellisCall({ await MakeFortellisCall({
debug: true, debug: true,
type: 'get', type: "get",
apiName: 'CDK Drive Post Accounts GL WIP', apiName: "CDK Drive Post Accounts GL WIP",
url: `https://api.fortellis.io/cdk-test/drive/chartofaccounts/v2/bulk`, url: `https://api.fortellis.io/cdk-test/drive/chartofaccounts/v2/bulk`,
waitForResult: true
}); });
} }
async function StartWIP() { async function StartWIP() {
const TransactionWip = MakeFortellisCall({ const TransactionWip = MakeFortellisCall({
url: 'https://api.fortellis.io/cdk-test/drive/glwippost/startWIP', url: "https://api.fortellis.io/cdk-test/drive/glwippost/startWIP",
apiName: 'CDK Drive Post Accounts GL WIP', apiName: "CDK Drive Post Accounts GL WIP",
body: { body: {
acctgDate: '2023-09-26', //job.invoice acctgDate: "2023-09-26", //job.invoice
desc: 'TEST TRANSACTION', desc: "TEST TRANSACTION",
docType: '3', //pulled from Doc Type workbook docType: "3", //pulled from Doc Type workbook
m13Flag: '0', // Is this a M13 entry. Presumanbly always 0 m13Flag: "0", // Is this a M13 entry. Presumanbly always 0
refer: 'RO12345', //Supposed to be a doc reference number. Presumably the RO? refer: "RO12345", //Supposed to be a doc reference number. Presumably the RO?
srcCo: '77', srcCo: "77",
srcJrnl: '80', srcJrnl: "80",
userID: 'csr', //bodyshop user userID: "csr", //bodyshop user
userName: 'PROGRAM, PARTNER*ADP', //Can leave blank to have this return to default. userName: "PROGRAM, PARTNER*ADP" //Can leave blank to have this return to default.
}, },
debug: true, debug: true
}); });
return TransactionWip; return TransactionWip;
@@ -178,30 +199,30 @@ async function StartWIP() {
async function InsertBatch({ transID }) { async function InsertBatch({ transID }) {
const TransactionWip = MakeFortellisCall({ const TransactionWip = MakeFortellisCall({
url: 'https://api.fortellis.io/cdk-test/drive/glwippost/transWIP', url: "https://api.fortellis.io/cdk-test/drive/glwippost/transWIP",
apiName: 'CDK Drive Post Accounts GL WIP', apiName: "CDK Drive Post Accounts GL WIP",
body: [ body: [
{ {
acct: '', acct: "",
cntl: '', cntl: "",
cntl2: null, cntl2: null,
credtMemoNo: null, credtMemoNo: null,
postAmt: Math.round(payer.amount * 100), postAmt: Math.round(payer.amount * 100),
postDesc: '', //Required if required by the DMS setup postDesc: "", //Required if required by the DMS setup
prod: null, //Productivity Number prod: null, //Productivity Number
statCnt: 1, //Auto count, leave as 1. statCnt: 1, //Auto count, leave as 1.
transID: transID, transID: transID,
trgtCoID: '77', //Add this to read from the header trgtCoID: "77" //Add this to read from the header
}, }
], ],
debug: true, debug: true
}); });
} }
async function DoTheThings() { async function DoTheThings() {
await FetchSubscriptions(); await FetchSubscriptions();
//What do we have access to? //What do we have access to?
console.log('Sub Access : ', SubscriptionMeta.apiDmsInfo.map((i) => i.name).join(', ')); console.log("Sub Access : ", SubscriptionMeta.apiDmsInfo.map((i) => i.name).join(", "));
await GetCOA(); await GetCOA();
return; return;

View File

@@ -16,9 +16,12 @@ const moment = require("moment-timezone");
const replaceSpecialRegex = /[^a-zA-Z0-9 .,\n #]+/g; const replaceSpecialRegex = /[^a-zA-Z0-9 .,\n #]+/g;
exports.default = async function (socket, { txEnvelope, jobid }) { exports.default = async function (socket, { txEnvelope, jobid }) {
////Store the following information into the redis store for this transaction.
socket.logEvents = []; socket.logEvents = [];
socket.recordid = jobid; socket.recordid = jobid;
socket.txEnvelope = txEnvelope; socket.txEnvelope = txEnvelope;
////
try { try {
CdkBase.createLogEvent(socket, "DEBUG", `Received Job export request for id ${jobid}`); CdkBase.createLogEvent(socket, "DEBUG", `Received Job export request for id ${jobid}`);