WIP quickbooks testing.
This commit is contained in:
1597
package-lock.json
generated
1597
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,8 @@
|
|||||||
"@electron-toolkit/utils": "^4.0.0",
|
"@electron-toolkit/utils": "^4.0.0",
|
||||||
"electron-log": "^5.3.2",
|
"electron-log": "^5.3.2",
|
||||||
"electron-store": "^8.2.0",
|
"electron-store": "^8.2.0",
|
||||||
"electron-updater": "^6.3.9"
|
"electron-updater": "^6.3.9",
|
||||||
|
"winax": "^3.6.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ant-design/v5-patch-for-react-19": "^1.0.3",
|
"@ant-design/v5-patch-for-react-19": "^1.0.3",
|
||||||
|
|||||||
BIN
resources/Interop.QBFC16.dll
Normal file
BIN
resources/Interop.QBFC16.dll
Normal file
Binary file not shown.
BIN
resources/Interop.QBXMLRP2.dll
Normal file
BIN
resources/Interop.QBXMLRP2.dll
Normal file
Binary file not shown.
BIN
resources/QBFC16.dll
Normal file
BIN
resources/QBFC16.dll
Normal file
Binary file not shown.
@@ -2,6 +2,8 @@ import cors from "cors";
|
|||||||
import { app } from "electron";
|
import { app } from "electron";
|
||||||
import log from "electron-log/main";
|
import log from "electron-log/main";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
|
import { handleQuickBookRequest } from "../quickbooks-desktop/quickbooks-desktop";
|
||||||
|
import errorTypeCheck from "../../util/errorTypeCheck";
|
||||||
|
|
||||||
export default class LocalServer {
|
export default class LocalServer {
|
||||||
private app: express.Application;
|
private app: express.Application;
|
||||||
@@ -94,7 +96,7 @@ export default class LocalServer {
|
|||||||
|
|
||||||
private configureRoutes(): void {
|
private configureRoutes(): void {
|
||||||
// Basic health check endpoint
|
// 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" });
|
res.status(200).json({ status: "ok" });
|
||||||
});
|
});
|
||||||
this.app.post("/ping", (req, res) => {
|
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.
|
qbPath: app.getPath("userData"), //TODO: Resolve to actual QB file path.
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.app.post("/qb", handleQuickBookRequest);
|
||||||
// Add more routes as needed
|
// Add more routes as needed
|
||||||
}
|
}
|
||||||
|
|
||||||
public start(): void {
|
public start(): void {
|
||||||
this.server = this.app.listen(this.PORT, () => {
|
try {
|
||||||
log.info(`[HTTP Server] Local HTTP server running on port ${this.PORT}`);
|
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 {
|
public stop(): void {
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import { electronApp, is, optimizer } from "@electron-toolkit/utils";
|
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 log from "electron-log/main";
|
||||||
import { autoUpdater } from "electron-updater";
|
import { autoUpdater } from "electron-updater";
|
||||||
import path, { join } from "path";
|
import path, { join } from "path";
|
||||||
|
import appIcon from "../../resources/diamond.png?asset";
|
||||||
import icon from "../../resources/icon.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 ipcTypes from "../util/ipcTypes.json";
|
||||||
import client from "./graphql/graphql-client";
|
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 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();
|
log.initialize();
|
||||||
const isMac = process.platform === "darwin";
|
const isMac = process.platform === "darwin";
|
||||||
@@ -171,20 +174,9 @@ function createWindow(): void {
|
|||||||
type: "separator",
|
type: "separator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Temp Test Action - Get Token from Renderer",
|
label: "Temp Test Action",
|
||||||
click: (): void => {
|
click: (): void => {
|
||||||
client
|
TestQB();
|
||||||
.request(
|
|
||||||
`
|
|
||||||
query jobs{
|
|
||||||
jobs
|
|
||||||
{
|
|
||||||
id}}
|
|
||||||
`,
|
|
||||||
)
|
|
||||||
.then((data) => {
|
|
||||||
log.info("Data from graffle", data);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
30
src/main/quickbooks-desktop/QuickbooksConnector.cs
Normal file
30
src/main/quickbooks-desktop/QuickbooksConnector.cs
Normal 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}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
114
src/main/quickbooks-desktop/quickbooks-desktop.ts
Normal file
114
src/main/quickbooks-desktop/quickbooks-desktop.ts
Normal 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;
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ const store = new Store({
|
|||||||
defaults: {
|
defaults: {
|
||||||
settings: {
|
settings: {
|
||||||
filepaths: [],
|
filepaths: [],
|
||||||
|
qbFilePath: "",
|
||||||
runWatcherOnStartup: true,
|
runWatcherOnStartup: true,
|
||||||
polling: {
|
polling: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user