Merge remote-tracking branch 'origin/feature/IO-2460-Node-18-Server' into rome/test

This commit is contained in:
Patrick Fic
2023-11-22 15:58:10 -08:00
26 changed files with 7680 additions and 5936 deletions

View File

@@ -9,7 +9,7 @@ const logger = require("../../utils/logger");
const OAuthClient = require("intuit-oauth");
const client = require("../../graphql-client/graphql-client").client;
const queries = require("../../graphql-client/queries");
const queryString = require("query-string");
const {parse, stringify} = require("querystring");
const oauthClient = new OAuthClient({
clientId: process.env.QBO_CLIENT_ID,
@@ -30,7 +30,8 @@ if (process.env.NODE_ENV === "production") {
}
exports.default = async (req, res) => {
const params = queryString.parse(req.url.split("?").reverse()[0]);
const queryString = req.url.split("?").reverse()[0];
const params = parse(queryString);
try {
logger.log("qbo-callback-create-token", "DEBUG", params.state, null, null);
const authResponse = await oauthClient.createToken(req.url);
@@ -58,7 +59,7 @@ exports.default = async (req, res) => {
);
res.redirect(
`${url}/manage/accounting/qbo?${queryString.stringify(params)}`
`${url}/manage/accounting/qbo?${stringify(params)}`
);
}
} catch (e) {

View File

@@ -7,12 +7,16 @@ require("dotenv").config({
});
const axios = require("axios");
let nodemailer = require("nodemailer");
let aws = require("aws-sdk");
let aws = require("@aws-sdk/client-ses");
let { defaultProvider } = require("@aws-sdk/credential-provider-node");
const logger = require("../utils/logger");
const client = require("../graphql-client/graphql-client").client;
const queries = require("../graphql-client/queries");
const ses = new aws.SES({
// The key apiVersion is no longer supported in v3, and can be removed.
// @deprecated The client uses the "latest" apiVersion.
apiVersion: "latest",
region: "us-east-2",
@@ -48,7 +52,6 @@ exports.sendServerEmail = async function ({ subject, text }) {
} catch (error) {
console.log(error);
logger.log("server-email-failure", "error", null, null, error);
res.status(500).json(error);
}
};
exports.sendTaskEmail = async function ({ to, subject, text, attachments }) {

View File

@@ -1,6 +1,6 @@
"use strict";
const AWS = require("aws-sdk");
const awsSecretManager = require("@aws-sdk/client-secrets-manager");
class SecretsManager {
/**
@@ -8,11 +8,10 @@ class SecretsManager {
*/
static async getSecret(secretName, region) {
const config = { region: region };
let secretsManager = new AWS.SecretsManager(config);
let secretsManager = new awsSecretManager.SecretsManager(config);
try {
let secretValue = await secretsManager
.getSecretValue({ SecretId: secretName })
.promise();
.getSecretValue({ SecretId: secretName });
if ("SecretString" in secretValue) {
return secretValue.SecretString;
} else {

View File

@@ -1,121 +1,122 @@
const Dinero = require("dinero.js");
const queries = require("../graphql-client/queries");
//const client = require("../graphql-client/graphql-client").client;
const _ = require("lodash");
const {pick} = require("lodash");
const GraphQLClient = require("graphql-request").GraphQLClient;
const logger = require("../utils/logger");
//const client = require("../graphql-client/graphql-client").client;
const path = require("path");
const client = require("../graphql-client/graphql-client").client;
require("dotenv").config({
path: path.resolve(
process.cwd(),
`.env.${process.env.NODE_ENV || "development"}`
),
path: path.resolve(
process.cwd(),
`.env.${process.env.NODE_ENV || "development"}`
),
});
const { Client, Connection } = require("@opensearch-project/opensearch");
const { defaultProvider } = require("@aws-sdk/credential-provider-node");
const {Client, Connection} = require("@opensearch-project/opensearch");
const {defaultProvider} = require("@aws-sdk/credential-provider-node");
const aws4 = require("aws4");
const { gql } = require("graphql-request");
const {gql} = require("graphql-request");
var host = process.env.OPEN_SEARCH_HOST;
const createAwsConnector = (credentials, region) => {
class AmazonConnection extends Connection {
buildRequestObject(params) {
const request = super.buildRequestObject(params);
request.service = "es";
request.region = region;
request.headers = request.headers || {};
request.headers["host"] = request.hostname;
return aws4.sign(request, credentials);
const createAwsConnector = (credentials, region) => {
class AmazonConnection extends Connection {
buildRequestObject(params) {
const request = super.buildRequestObject(params);
request.service = "es";
request.region = region;
request.headers = request.headers || {};
request.headers["host"] = request.hostname;
return aws4.sign(request, credentials);
}
}
}
return {
Connection: AmazonConnection,
};
return {
Connection: AmazonConnection,
};
};
const getClient = async () => {
const credentials = await defaultProvider()();
return new Client({
...createAwsConnector(credentials, "ca-central-1"),
node: host,
});
const credentials = await defaultProvider()();
return new Client({
...createAwsConnector(credentials, "ca-central-1"),
node: host,
});
};
async function OpenSearchUpdateHandler(req, res) {
if (req.headers["event-secret"] !== process.env.EVENT_SECRET) {
res.status(401).send("Unauthorized");
return;
}
try {
var osClient = await getClient();
// const osClient = new Client({
// node: `https://imex:<password>@search-imexonline-search-ixp2stfvwp6qocjsowzjzyreoy.ca-central-1.es.amazonaws.com/`,
// });
if (req.headers["event-secret"] !== process.env.EVENT_SECRET) {
res.status(401).send("Unauthorized");
return;
}
try {
var osClient = await getClient();
// const osClient = new Client({
// node: `https://imex:<password>@search-imexonline-search-ixp2stfvwp6qocjsowzjzyreoy.ca-central-1.es.amazonaws.com/`,
// });
if (req.body.event.op === "DELETE") {
let response;
response = await osClient.delete({
id: req.body.event.data.old.id,
index: req.body.table.name,
});
res.status(200).json(response.body);
} else {
let document;
if (req.body.event.op === "DELETE") {
let response;
response = await osClient.delete({
id: req.body.event.data.old.id,
index: req.body.table.name,
});
res.status(200).json(response.body);
} else {
let document;
switch (req.body.table.name) {
case "jobs":
document = _.pick(req.body.event.data.new, [
"id",
"bodyshopid",
"clm_no",
"clm_total",
"comment",
"ins_co_nm",
"owner_owing",
"ownr_co_nm",
"ownr_fn",
"ownr_ln",
"ownr_ph1",
"ownr_ph2",
"plate_no",
"ro_number",
"status",
"v_model_yr",
"v_make_desc",
"v_model_desc",
"v_vin",
]);
document.bodyshopid = req.body.event.data.new.shopid;
break;
case "vehicles":
document = _.pick(req.body.event.data.new, [
"id",
"v_model_yr",
"v_model_desc",
"v_make_desc",
"v_color",
"v_vin",
"plate_no",
]);
document.bodyshopid = req.body.event.data.new.shopid;
break;
case "owners":
document = _.pick(req.body.event.data.new, [
"id",
"ownr_fn",
"ownr_ln",
"ownr_co_nm",
"ownr_ph1",
"ownr_ph2",
]);
document.bodyshopid = req.body.event.data.new.shopid;
break;
case "bills":
const bill = await client.request(
`query ADMIN_GET_BILL_BY_ID($billId: uuid!) {
switch (req.body.table.name) {
case "jobs":
document = pick(req.body.event.data.new, [
"id",
"bodyshopid",
"clm_no",
"clm_total",
"comment",
"ins_co_nm",
"owner_owing",
"ownr_co_nm",
"ownr_fn",
"ownr_ln",
"ownr_ph1",
"ownr_ph2",
"plate_no",
"ro_number",
"status",
"v_model_yr",
"v_make_desc",
"v_model_desc",
"v_vin",
]);
document.bodyshopid = req.body.event.data.new.shopid;
break;
case "vehicles":
document = pick(req.body.event.data.new, [
"id",
"v_model_yr",
"v_model_desc",
"v_make_desc",
"v_color",
"v_vin",
"plate_no",
]);
document.bodyshopid = req.body.event.data.new.shopid;
break;
case "owners":
document = pick(req.body.event.data.new, [
"id",
"ownr_fn",
"ownr_ln",
"ownr_co_nm",
"ownr_ph1",
"ownr_ph2",
]);
document.bodyshopid = req.body.event.data.new.shopid;
break;
case "bills":
const bill = await client.request(
`query ADMIN_GET_BILL_BY_ID($billId: uuid!) {
bills_by_pk(id: $billId) {
id
job {
@@ -130,26 +131,26 @@ async function OpenSearchUpdateHandler(req, res) {
}
}
`,
{ billId: req.body.event.data.new.id }
);
document = {
..._.pick(req.body.event.data.new, [
"id",
"date",
"exported",
"exported_at",
"invoice_number",
"is_credit_memo",
"total",
]),
...bill.bills_by_pk,
bodyshopid: bill.bills_by_pk.job.shopid,
};
break;
case "payments":
//Query to get the job and RO number
const payment = await client.request(
`query ADMIN_GET_PAYMENT_BY_ID($paymentId: uuid!) {
{billId: req.body.event.data.new.id}
);
document = {
...pick(req.body.event.data.new, [
"id",
"date",
"exported",
"exported_at",
"invoice_number",
"is_credit_memo",
"total",
]),
...bill.bills_by_pk,
bodyshopid: bill.bills_by_pk.job.shopid,
};
break;
case "payments":
//Query to get the job and RO number
const payment = await client.request(
`query ADMIN_GET_PAYMENT_BY_ID($paymentId: uuid!) {
payments_by_pk(id: $paymentId) {
id
job {
@@ -170,154 +171,156 @@ async function OpenSearchUpdateHandler(req, res) {
}
}
`,
{ paymentId: req.body.event.data.new.id }
);
document = {
..._.pick(req.body.event.data.new, [
"id",
"amount",
"created_at",
"date",
"exportedat",
"memo",
"payer",
"paymentnum",
"transactionid",
"type",
]),
...payment.payments_by_pk,
bodyshopid: payment.payments_by_pk.job.shopid,
};
break;
}
const payload = {
id: req.body.event.data.new.id,
index: req.body.table.name,
body: document,
};
{paymentId: req.body.event.data.new.id}
);
document = {
...pick(req.body.event.data.new, [
"id",
"amount",
"created_at",
"date",
"exportedat",
"memo",
"payer",
"paymentnum",
"transactionid",
"type",
]),
...payment.payments_by_pk,
bodyshopid: payment.payments_by_pk.job.shopid,
};
break;
}
const payload = {
id: req.body.event.data.new.id,
index: req.body.table.name,
body: document,
};
let response;
response = await osClient.index(payload);
console.log(response.body);
res.status(200).json(response.body);
let response;
response = await osClient.index(payload);
console.log(response.body);
res.status(200).json(response.body);
}
} catch (error) {
res.status(400).json(JSON.stringify(error));
} finally {
}
} catch (error) {
res.status(400).json(JSON.stringify(error));
} finally {
}
}
async function OpensearchSearchHandler(req, res) {
try {
const { search, bodyshopid, index } = req.body;
if (!req.user) {
res.sendStatus(401);
return;
}
logger.log("os-search", "DEBUG", req.user.email, null, {
search,
});
async function OpenSearchSearchHandler(req, res) {
try {
const {search, bodyshopid, index} = req.body;
const BearerToken = req.headers.authorization;
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
headers: {
Authorization: BearerToken,
},
});
if (!req.user) {
res.sendStatus(401);
return;
}
const assocs = await client
.setHeaders({ Authorization: BearerToken })
.request(queries.ACTIVE_SHOP_BY_USER, {
user: req.user.email,
});
logger.log("os-search", "DEBUG", req.user.email, null, {
search,
});
if (assocs.length === 0) {
res.sendStatus(401);
}
var osClient = await getClient();
const { body } = await osClient.search({
...(index ? { index } : {}),
body: {
size: 100,
query: {
bool: {
must: [
{
match: {
bodyshopid: assocs.associations[0].shopid,
},
},
{
bool: {
should: [
{
multi_match: {
query: search,
type: "cross_fields",
fields: ["*ownr_fn", "*ownr_ln"],
},
},
{
multi_match: {
query: search,
type: "most_fields",
fields: [
"*v_model_yr",
"*v_make_desc^2",
"*v_model_desc^3",
],
},
},
{
query_string: {
query: `*${search}*`,
fields: [
"*ro_number^20",
"*clm_no^14",
"*v_vin^12",
"*plate_no^12",
"*ownr_ln^10",
"transactionid^10",
"paymentnum^10",
"invoice_number^10",
"*ownr_fn^8",
"*ownr_co_nm^8",
"*ownr_ph1^8",
"*ownr_ph2^8",
"*",
],
},
},
],
minimum_should_match: 1,
},
},
],
},
},
sort: [
{
_score: {
order: "desc",
const BearerToken = req.headers.authorization;
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
headers: {
Authorization: BearerToken,
},
},
],
},
});
});
res.json(body);
} catch (error) {
console.log(error);
logger.log("os-search-error", "ERROR", req.user.email, null, {
error: JSON.stringify(error),
});
res.status(400).json(error);
} finally {
}
const assocs = await client
.setHeaders({Authorization: BearerToken})
.request(queries.ACTIVE_SHOP_BY_USER, {
user: req.user.email,
});
if (assocs.length === 0) {
res.sendStatus(401);
}
const osClient = await getClient();
const {body} = await osClient.search({
...(index ? {index} : {}),
body: {
size: 100,
query: {
bool: {
must: [
{
match: {
bodyshopid: assocs.associations[0].shopid,
},
},
{
bool: {
should: [
{
multi_match: {
query: search,
type: "cross_fields",
fields: ["*ownr_fn", "*ownr_ln"],
},
},
{
multi_match: {
query: search,
type: "most_fields",
fields: [
"*v_model_yr",
"*v_make_desc^2",
"*v_model_desc^3",
],
},
},
{
query_string: {
query: `*${search}*`,
// Weighted Fields
fields: [
"*ro_number^20",
"*clm_no^14",
"*v_vin^12",
"*plate_no^12",
"*ownr_ln^10",
"transactionid^10",
"paymentnum^10",
"invoice_number^10",
"*ownr_fn^8",
"*ownr_co_nm^8",
"*ownr_ph1^8",
"*ownr_ph2^8",
"*",
],
},
},
],
minimum_should_match: 1,
},
},
],
},
},
sort: [
{
_score: {
order: "desc",
},
},
],
},
});
res.json(body);
} catch (error) {
console.log(error);
logger.log("os-search-error", "ERROR", req.user.email, null, {
error: JSON.stringify(error),
});
res.status(400).json(error);
} finally {
}
}
exports.handler = OpenSearchUpdateHandler;
exports.search = OpensearchSearchHandler;
exports.search = OpenSearchSearchHandler;

View File

@@ -1,79 +1,46 @@
const GraphQLClient = require("graphql-request").GraphQLClient;
const path = require("path");
const queries = require("../graphql-client/queries");
const Dinero = require("dinero.js");
require("dotenv").config({
path: path.resolve(
process.cwd(),
`.env.${process.env.NODE_ENV || "development"}`
),
path: path.resolve(
process.cwd(),
`.env.${process.env.NODE_ENV || "development"}`
),
});
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);
exports.payment = async (req, res) => {
const { amount, stripe_acct_id } = req.body;
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
try {
await stripe.paymentIntents
.create(
{
payment_method_types: ["card"],
amount: amount,
currency: "cad",
application_fee_amount: 50,
},
{
stripeAccount: stripe_acct_id,
}
)
.then(function (paymentIntent) {
try {
return res.send({
clientSecret: paymentIntent.client_secret,
});
} catch (err) {
return res.status(500).send({
error: err.message,
});
}
});
} catch (error) {
console.log("error", error);
res.status(400).send(error);
}
const processor = async (req, res) => {
const {amount, stripe_acct_id} = req.body;
try {
await stripe.paymentIntents
.create(
{
payment_method_types: ["card"],
amount: amount,
currency: "cad",
application_fee_amount: 50,
},
{
stripeAccount: stripe_acct_id,
}
)
.then(function (paymentIntent) {
try {
return res.send({
clientSecret: paymentIntent.client_secret,
});
} catch (err) {
return res.status(500).send({
error: err.message,
});
}
});
} catch (error) {
console.log("error", error);
res.status(400).send(error);
}
};
exports.mobile_payment = async (req, res) => {
const { amount, stripe_acct_id } = req.body;
try {
await stripe.paymentIntents
.create(
{
//Pull the amounts from the payment request.
payment_method_types: ["card"],
amount: amount,
currency: "cad",
application_fee_amount: 50,
},
{
stripeAccount: stripe_acct_id,
}
)
.then(function (paymentIntent) {
try {
return res.send({
clientSecret: paymentIntent.client_secret,
});
} catch (err) {
return res.status(500).send({
error: err.message,
});
}
});
} catch (error) {
console.log("error", error);
res.status(400).send(error);
}
};
exports.payment = processor;
exports.mobile_payment = processor;

View File

@@ -1,92 +1,84 @@
const path = require("path");
require("dotenv").config({
path: path.resolve(
process.cwd(),
`.env.${process.env.NODE_ENV || "development"}`
),
path: path.resolve(
process.cwd(),
`.env.${process.env.NODE_ENV || "development"}`
),
});
const axios = require("axios");
const client = require("../graphql-client/graphql-client").client;
const emailer = require("../email/sendemail");
const logger = require("../utils/logger");
const moment = require("moment-timezone");
const converter = require("json-2-csv");
exports.taskHandler = async (req, res) => {
try {
const { bodyshopid, query, variables, text, to, subject, timezone } =
req.body;
//Run the query
try {
const {bodyshopid, query, variables, text, to, subject, timezone} = req.body;
//Check the variables to see if they are an object.
Object.keys(variables).forEach((key) => {
if (typeof variables[key] === "object") {
if (variables[key].function) {
variables[key] = functionMapper(variables[key].function, timezone);
}
}
});
//Check the variables to see if they are an object.
Object.keys(variables).forEach((key) => {
if (typeof variables[key] === "object") {
if (variables[key].function) {
variables[key] = functionMapper(variables[key].function, timezone);
}
}
});
const response = await client.request(query, variables);
//Massage the data
//Send the email
const rootElement = response[Object.keys(response)[0]]; //This element shoudl always be an array.
let converter = require("json-2-csv");
converter.json2csv(
rootElement,
(err, csv) => {
if (err) {
res.status(500).json(err);
}
const response = await client.request(query, variables);
const rootElement = response[Object.keys(response)[0]]; //This element should always be an array.
const csv = converter.json2csv(rootElement, {emptyFieldValue: ""});
emailer.sendTaskEmail({
to,
subject,
text,
attachments: [{ filename: "query.csv", content: csv }],
to,
subject,
text,
attachments: [{filename: "query.csv", content: csv}],
}).catch(err => {
console.error('Errors sending CSV Email.')
});
res.status(200).send(csv);
},
{ emptyFieldValue: "" }
);
} catch (error) {
res.status(500).json({ error: error.message, stack: error.stackTrace });
}
return res.status(200).send(csv);
} catch (error) {
res.status(500).json({error: error.message, stack: error.stackTrace});
}
};
const isoformat = "YYYY-MM-DD";
function functionMapper(f, timezone) {
switch (f) {
case "date.today":
return moment().tz(timezone).format(isoformat);
case "date.now":
return moment().tz(timezone);
case "date.yesterday":
return moment().tz(timezone).subtract(1, "day").format(isoformat);
case "date.3daysago":
return moment().tz(timezone).subtract(3, "days").format(isoformat);
case "date.7daysago":
return moment().tz(timezone).subtract(7, "days").format(isoformat);
case "date.tomorrow":
return moment().tz(timezone).add(1, "day").format(isoformat);
case "date.3daysfromnow":
return moment().tz(timezone).add(3, "days").format(isoformat);
case "date.7daysfromnow":
return moment().tz(timezone).add(7, "days").format(isoformat);
case "date.yesterdaytz":
return moment().tz(timezone).subtract(1, "day");
case "date.3daysagotz":
return moment().tz(timezone).subtract(3, "days");
case "date.7daysagotz":
return moment().tz(timezone).subtract(7, "days");
case "date.tomorrowtz":
return moment().tz(timezone).add(1, "day");
case "date.3daysfromnowtz":
return moment().tz(timezone).add(3, "days");
case "date.7daysfromnowtz":
return moment().tz(timezone).add(7, "days");
const isoFormat = "YYYY-MM-DD";
case "date.now":
return moment().tz(timezone);
default:
return f;
}
function functionMapper(f, timezone) {
switch (f) {
case "date.today":
return moment().tz(timezone).format(isoFormat);
case "date.now":
return moment().tz(timezone);
case "date.yesterday":
return moment().tz(timezone).subtract(1, "day").format(isoFormat);
case "date.3daysago":
return moment().tz(timezone).subtract(3, "days").format(isoFormat);
case "date.7daysago":
return moment().tz(timezone).subtract(7, "days").format(isoFormat);
case "date.tomorrow":
return moment().tz(timezone).add(1, "day").format(isoFormat);
case "date.3daysfromnow":
return moment().tz(timezone).add(3, "days").format(isoFormat);
case "date.7daysfromnow":
return moment().tz(timezone).add(7, "days").format(isoFormat);
case "date.yesterdaytz":
return moment().tz(timezone).subtract(1, "day");
case "date.3daysagotz":
return moment().tz(timezone).subtract(3, "days");
case "date.7daysagotz":
return moment().tz(timezone).subtract(7, "days");
case "date.tomorrowtz":
return moment().tz(timezone).add(1, "day");
case "date.3daysfromnowtz":
return moment().tz(timezone).add(3, "days");
case "date.7daysfromnowtz":
return moment().tz(timezone).add(7, "days");
case "date.now":
return moment().tz(timezone);
default:
return f;
}
}