Compare commits

..

1 Commits

Author SHA1 Message Date
Allan Carr
542c95c395 IO-3335 QBO Payment Logging
Signed-off-by: Allan Carr <allan@imexsystems.ca>
2025-08-13 16:35:52 -07:00
4 changed files with 57 additions and 81 deletions

View File

@@ -46,8 +46,8 @@ function JobsDocumentsImgproxyComponent({
const [modalState, setModalState] = useState({ open: false, index: 0 });
const fetchThumbnails = useCallback(() => {
fetchImgproxyThumbnails({ setStateCallback: setGalleryImages, jobId, billId });
}, [jobId, billId, setGalleryImages]);
fetchImgproxyThumbnails({ setStateCallback: setGalleryImages, jobId });
}, [jobId, setGalleryImages]);
useEffect(() => {
if (data) {
@@ -208,8 +208,8 @@ function JobsDocumentsImgproxyComponent({
export default connect(mapStateToProps, mapDispatchToProps)(JobsDocumentsImgproxyComponent);
export const fetchImgproxyThumbnails = async ({ setStateCallback, jobId, billId, imagesOnly }) => {
const result = await axios.post("/media/imgproxy/thumbnails", { jobid: jobId, billid: billId });
export const fetchImgproxyThumbnails = async ({ setStateCallback, jobId, imagesOnly }) => {
const result = await axios.post("/media/imgproxy/thumbnails", { jobid: jobId });
const documents = result.data.reduce(
(acc, value) => {
if (value.type.startsWith("image")) {

View File

@@ -10,7 +10,6 @@ const queries = require("../../graphql-client/queries");
const { refresh: refreshOauthToken, setNewRefreshToken } = require("./qbo-callback");
const OAuthClient = require("intuit-oauth");
const moment = require("moment-timezone");
const GraphQLClient = require("graphql-request").GraphQLClient;
const {
QueryInsuranceCo,
InsertInsuranceCo,
@@ -28,7 +27,7 @@ exports.default = async (req, res) => {
clientId: process.env.QBO_CLIENT_ID,
clientSecret: process.env.QBO_SECRET,
environment: process.env.NODE_ENV === "production" ? "production" : "sandbox",
redirectUri: process.env.QBO_REDIRECT_URI,
redirectUri: process.env.QBO_REDIRECT_URI
});
try {
//Fetch the API Access Tokens & Set them for the session.
@@ -131,22 +130,20 @@ exports.default = async (req, res) => {
// //No error. Mark the payment exported & insert export log.
if (elgen) {
const result = await client
.setHeaders({ Authorization: BearerToken })
.request(queries.QBO_MARK_PAYMENT_EXPORTED, {
paymentId: payment.id,
payment: {
exportedat: moment().tz(bodyshop.timezone)
},
logs: [
{
bodyshopid: bodyshop.id,
paymentid: payment.id,
successful: true,
useremail: req.user.email
}
]
});
await client.setHeaders({ Authorization: BearerToken }).request(queries.QBO_MARK_PAYMENT_EXPORTED, {
paymentId: payment.id,
payment: {
exportedat: moment().tz(bodyshop.timezone)
},
logs: [
{
bodyshopid: bodyshop.id,
paymentid: payment.id,
successful: true,
useremail: req.user.email
}
]
});
}
ret.push({ paymentid: payment.id, success: true });
@@ -156,7 +153,7 @@ exports.default = async (req, res) => {
});
//Add the export log error.
if (elgen) {
const result = await client.setHeaders({ Authorization: BearerToken }).request(queries.INSERT_EXPORT_LOG, {
await client.setHeaders({ Authorization: BearerToken }).request(queries.INSERT_EXPORT_LOG, {
logs: [
{
bodyshopid: bodyshop.id,
@@ -190,7 +187,7 @@ exports.default = async (req, res) => {
}
};
async function InsertPayment(oauthClient, qbo_realmId, req, payment, parentRef, bodyshop) {
async function InsertPayment(oauthClient, qbo_realmId, req, payment, parentRef) {
const { paymentMethods, invoices } = await QueryMetaData(
oauthClient,
qbo_realmId,
@@ -227,20 +224,20 @@ async function InsertPayment(oauthClient, qbo_realmId, req, payment, parentRef,
PaymentRefNum: payment.transactionid,
...(invoices && invoices.length === 1 && invoices[0]
? {
Line: [
{
Amount: Dinero({
amount: Math.round(payment.amount * 100)
}).toFormat(DineroQbFormat),
LinkedTxn: [
{
TxnId: invoices[0].Id,
TxnType: "Invoice"
}
]
}
]
}
Line: [
{
Amount: Dinero({
amount: Math.round(payment.amount * 100)
}).toFormat(DineroQbFormat),
LinkedTxn: [
{
TxnId: invoices[0].Id,
TxnType: "Invoice"
}
]
}
]
}
: {})
};
logger.log("qbo-payments-objectlog", "DEBUG", req.user.email, payment.id, {
@@ -263,7 +260,7 @@ async function InsertPayment(oauthClient, qbo_realmId, req, payment, parentRef,
status: result.response?.status,
bodyshopid: payment.job.shopid,
email: req.user.email
})
});
setNewRefreshToken(req.user.email, result);
return result && result.Bill;
} catch (error) {
@@ -291,7 +288,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM
status: invoice.response?.status,
bodyshopid,
email: req.user.email
})
});
const paymentMethods = await oauthClient.makeApiCall({
url: urlBuilder(qbo_realmId, "query", `select * From PaymentMethod`),
method: "POST",
@@ -306,7 +303,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM
status: paymentMethods.response?.status,
bodyshopid,
email: req.user.email
})
});
setNewRefreshToken(req.user.email, paymentMethods);
// const classes = await oauthClient.makeApiCall({
@@ -358,7 +355,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM
status: taxCodes.response?.status,
bodyshopid,
email: req.user.email
})
});
const items = await oauthClient.makeApiCall({
url: urlBuilder(qbo_realmId, "query", `select * From Item`),
method: "POST",
@@ -373,7 +370,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM
status: items.response?.status,
bodyshopid,
email: req.user.email
})
});
setNewRefreshToken(req.user.email, items);
const itemMapping = {};
@@ -412,8 +409,8 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM
};
}
async function InsertCreditMemo(oauthClient, qbo_realmId, req, payment, parentRef, bodyshop) {
const { paymentMethods, invoices, items, taxCodes } = await QueryMetaData(
async function InsertCreditMemo(oauthClient, qbo_realmId, req, payment, parentRef) {
const { invoices, items, taxCodes } = await QueryMetaData(
oauthClient,
qbo_realmId,
req,
@@ -449,14 +446,14 @@ async function InsertCreditMemo(oauthClient, qbo_realmId, req, payment, parentRe
TaxCodeRef: {
value:
taxCodes[
findTaxCode(
{
local: false,
federal: false,
state: false
},
payment.job.bodyshop.md_responsibility_centers.sales_tax_codes
)
findTaxCode(
{
local: false,
federal: false,
state: false
},
payment.job.bodyshop.md_responsibility_centers.sales_tax_codes
)
]
}
}
@@ -483,12 +480,14 @@ async function InsertCreditMemo(oauthClient, qbo_realmId, req, payment, parentRe
status: result.response?.status,
bodyshopid: req.user.bodyshopid,
email: req.user.email
})
});
setNewRefreshToken(req.user.email, result);
return result && result.Bill;
} catch (error) {
logger.log("qbo-payables-error", "DEBUG", req.user.email, payment.id, {
error: error && error.message,
error: error,
validationError: JSON.stringify(error?.response?.data),
accountmeta: JSON.stringify({ items, taxCodes }),
method: "InsertCreditMemo"
});
throw error;

View File

@@ -2846,26 +2846,6 @@ exports.GET_DOCUMENTS_BY_JOB = `
}
}
}`;
exports.GET_DOCUMENTS_BY_BILL = `
query GET_DOCUMENTS_BY_BILL($billId: uuid!) {
documents_aggregate(where: {billid: {_eq: $billId}}) {
aggregate {
sum {
size
}
}
}
documents(order_by: {takenat: desc}, where: {billid: {_eq: $billId}}) {
id
name
key
type
size
takenat
extension
}
}
`;
exports.QUERY_TEMPORARY_DOCS = ` query QUERY_TEMPORARY_DOCS {
documents(where: { jobid: { _is_null: true } }, order_by: { takenat: desc }) {

View File

@@ -18,7 +18,6 @@ const {
GET_DOCUMENTS_BY_JOB,
QUERY_TEMPORARY_DOCS,
GET_DOCUMENTS_BY_IDS,
GET_DOCUMENTS_BY_BILL,
DELETE_MEDIA_DOCUMENTS
} = require("../graphql-client/queries");
const yazl = require("yazl");
@@ -91,11 +90,9 @@ const getThumbnailUrls = async (req, res) => {
//Delayed as the key structure may change slightly from what it is currently and will require evaluating mobile components.
const client = req.userGraphQLClient;
//If there's no jobid and no billid, we're in temporary documents.
const data = await (
billid ? client.request(GET_DOCUMENTS_BY_BILL, { billId: billid }) :
jobid
? client.request(GET_DOCUMENTS_BY_JOB, { jobId: jobid })
: client.request(QUERY_TEMPORARY_DOCS));
const data = await (jobid
? client.request(GET_DOCUMENTS_BY_JOB, { jobId: jobid })
: client.request(QUERY_TEMPORARY_DOCS));
const thumbResizeParams = `rs:fill:250:250:1/g:ce`;
const s3client = new S3Client({ region: InstanceRegion() });