WIP quickbooks testing.

This commit is contained in:
Patrick Fic
2025-03-27 11:57:57 -07:00
parent e2ccbf7007
commit 7d59796f49
10 changed files with 755 additions and 1040 deletions

1597
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -25,7 +25,8 @@
"@electron-toolkit/utils": "^4.0.0",
"electron-log": "^5.3.2",
"electron-store": "^8.2.0",
"electron-updater": "^6.3.9"
"electron-updater": "^6.3.9",
"winax": "^3.6.1"
},
"devDependencies": {
"@ant-design/v5-patch-for-react-19": "^1.0.3",

Binary file not shown.

Binary file not shown.

BIN
resources/QBFC16.dll Normal file

Binary file not shown.

View File

@@ -2,6 +2,8 @@ import cors from "cors";
import { app } from "electron";
import log from "electron-log/main";
import express from "express";
import { handleQuickBookRequest } from "../quickbooks-desktop/quickbooks-desktop";
import errorTypeCheck from "../../util/errorTypeCheck";
export default class LocalServer {
private app: express.Application;
@@ -94,7 +96,7 @@ export default class LocalServer {
private configureRoutes(): void {
// Basic health check endpoint
this.app.get("/health", (req, res) => {
this.app.get("/health", (req: express.Request, res: express.Response) => {
res.status(200).json({ status: "ok" });
});
this.app.post("/ping", (req, res) => {
@@ -103,13 +105,25 @@ export default class LocalServer {
qbPath: app.getPath("userData"), //TODO: Resolve to actual QB file path.
});
});
this.app.post("/qb", handleQuickBookRequest);
// Add more routes as needed
}
public start(): void {
this.server = this.app.listen(this.PORT, () => {
log.info(`[HTTP Server] Local HTTP server running on port ${this.PORT}`);
});
try {
this.server = this.app.listen(this.PORT, (error: Error) => {
if (error) {
log.error(`[HTTP Server] Error starting server: ${error}`);
} else {
log.info(
`[HTTP Server] Local HTTP server running on port ${this.PORT}`,
);
}
});
} catch (error: unknown) {
log.error("[HTTP Server] Error starting server", errorTypeCheck(error));
}
}
public stop(): void {

View File

@@ -1,16 +1,19 @@
import { electronApp, is, optimizer } from "@electron-toolkit/utils";
import { app, BrowserWindow, Menu, shell, nativeImage, Tray } from "electron";
import { app, BrowserWindow, Menu, nativeImage, shell, Tray } from "electron";
import log from "electron-log/main";
import { autoUpdater } from "electron-updater";
import path, { join } from "path";
import appIcon from "../../resources/diamond.png?asset";
import icon from "../../resources/icon.png?asset";
import ErrorTypeCheck from "../util/errorTypeCheck";
import {
default as ErrorTypeCheck,
default as errorTypeCheck,
} from "../util/errorTypeCheck";
import ipcTypes from "../util/ipcTypes.json";
import client from "./graphql/graphql-client";
import store from "./store/store";
import appIcon from "../../resources/diamond.png?asset";
import LocalServer from "./http-server/http-server";
import errorTypeCheck from "../util/errorTypeCheck";
import store from "./store/store";
import { TestQB } from "./quickbooks-desktop/quickbooks-desktop";
log.initialize();
const isMac = process.platform === "darwin";
@@ -171,20 +174,9 @@ function createWindow(): void {
type: "separator",
},
{
label: "Temp Test Action - Get Token from Renderer",
label: "Temp Test Action",
click: (): void => {
client
.request(
`
query jobs{
jobs
{
id}}
`,
)
.then((data) => {
log.info("Data from graffle", data);
});
TestQB();
},
},
],

View File

@@ -0,0 +1,30 @@
using System;
using Interop.QBFC16; // Ensure this matches your DLL version
public class QuickBooksConnector
{
public string ProcessQBXML(string qbxmlRequest)
{
try
{
QBSessionManager sessionManager = new QBSessionManager();
sessionManager.OpenConnection("", "YourAppName");
sessionManager.BeginSession("", ENOpenMode.omDontCare);
IMsgSetRequest requestMsgSet = sessionManager.CreateMsgSetRequest("US", 13, 0);
requestMsgSet.AppendXML(qbxmlRequest);
IMsgSetResponse responseMsgSet = sessionManager.DoRequests(requestMsgSet);
string qbxmlResponse = responseMsgSet.ToXMLString();
sessionManager.EndSession();
sessionManager.CloseConnection();
return qbxmlResponse;
}
catch (Exception ex)
{
return $"Error: {ex.Message}";
}
}
}

View File

@@ -0,0 +1,114 @@
import * as Winax from "winax";
import log from "electron-log/main";
import { Request, Response } from "express";
import { UUID } from "crypto";
import errorTypeCheck from "../../util/errorTypeCheck";
import _ from "lodash";
import store from "../store/store";
export async function handleQuickBookRequest(
req: Request,
res: Response,
): Promise<void> {
//TODO: Add OS sysstem checking. This can only happen on windows machines.
const QbFilePath: string = `C:\\Users\\PatrickFic\\Development\\FRODO COLLISION.QBW`;
// ||
// (store.get("settings.qbFilePath") as string) F
if (_.isEmpty(QbFilePath)) {
res.status(400).json({ error: "Quickbooks file path not set" });
return;
}
const qbxmlRequestList = req.body as Array<{
id: UUID;
okStatusCodes: Array<string>;
qbxml: string;
}>;
const returnResponse: Array<{
Id: UUID;
Success: boolean;
ErrorMessage: string;
}> = [];
//Connect to the QuickBooks File
let requestProcessor;
try {
requestProcessor = new Winax.Object("QBXMLRP2.RequestProcessor.2");
requestProcessor.OpenConnection(QbFilePath, "ShopPartnerActualRequest");
} catch (error) {
log.error(
"Error instnatiating QuickBooks Request Processor",
QbFilePath,
errorTypeCheck(error),
);
res.status(500).json({ error: "Error connecting to QuickBooks" });
return;
}
const ticket = requestProcessor.BeginSession(QbFilePath, 2); //2 indicated qbFileOpenModeDoNotCare
log.info("Quickbooks Ticket", ticket);
for (const qbxmlRequest of qbxmlRequestList) {
try {
//TODO: Refactor to not create a new connection every time.
const QuickBooksResponse = requestProcessor.ProcessRequest(
ticket,
qbxmlRequest.qbxml,
);
log.info("QuickBooks Raw Response: ", QuickBooksResponse);
returnResponse.push({
Id: qbxmlRequest.id,
Success:
QuickBooksResponse.StatusCode === "0" ||
qbxmlRequest.okStatusCodes.includes(QuickBooksResponse.StatusCode),
ErrorMessage: QuickBooksResponse,
});
} catch (error) {
log.error(
"Error running transaction",
ticket,
qbxmlRequest,
errorTypeCheck(error),
);
}
}
requestProcessor.EndSession(ticket);
requestProcessor.CloseConnection();
res.json(qbxmlRequestList);
}
//This set of functions works.
export function TestQB(): void {
let requestProcessor, ticket;
try {
requestProcessor = new Winax.Object("QBXMLRP.RequestProcessor.1");
const connection = requestProcessor.OpenConnection("", "ShopPartnerOneoFf");
ticket = requestProcessor.BeginSession("", 2); //2 indicated qbFileOFpenModeDoNotCare
const qbre = requestProcessor.ProcessRequest(
ticket,
`<?qbxml version="16.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<AccountQueryRq requestID="1"> </AccountQueryRq>
</QBXMLMsgsRq>
</QBXML>`,
);
} catch (error) {
log.error(
"Error instnatiating QuickBooks Request Processor",
errorTypeCheck(error),
);
return;
}
log.log("Ticket", ticket);
requestProcessor.EndSession(ticket);
requestProcessor.CloseConnection();
return;
}

View File

@@ -4,6 +4,7 @@ const store = new Store({
defaults: {
settings: {
filepaths: [],
qbFilePath: "",
runWatcherOnStartup: true,
polling: {
enabled: false,