H E I S E N B E R G
H E I S E N B E R G•10mo ago

Clarification on https://github.com/windmill-labs/windmill-community-integrations/issues/2

I am thinking about attempting this issue, but I don't feel that I'm getting the full picture. Can anyone address my queries?
75 Replies
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
@Hugo tagging you since I saw you created the issue
Hugo
Hugo•10mo ago
yes sure
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
mind helping me with my queries?
Hugo
Hugo•10mo ago
sure
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
great! okay so i went through the integrations.yml file and also the readme file my question is, does the issue require to create http calls to the endpoints listed in integrations.yaml?
Hugo
Hugo•10mo ago
yes either using fetch or using the node sdk you also need to have/create an account on the service so that you can write tests and run them
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
yes got it. i see the endpoints are of intuit. so i'm guessing that i need to have an account on that to test my stuff out also, i'll need to specify them in the resource.ts file according to the docs
Hugo
Hugo•10mo ago
exactly but load the credentials from the .env file so that they're ignored and when we test it we can just put our own in the .env file there is also a complete example for a GitHub script in the repo that you can use as inspiration
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
yeah i went through the github integration before hand! okay i think that satisfies the queries
Hugo
Hugo•10mo ago
cool, i'm here if you have any other questions
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
as for intuit, platforms like these take a ton of data in endpoints. I'm guessing i'll need to create a detailed types file for this
No description
Hugo
Hugo•10mo ago
not for what is returned but only for the request body so as described in the "Create a customer" section in the docs btw preferably each request body input key should be a separate function argument instead of taking a single object (i should add that to the readme)
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
gotcha one last thing, this would be in the format of an sdk if im not wrong. what i mean is, the functions wont be "callable" via any script, rather you have to import the library in some js/ts code to actually make it work. correct? just the tests can call the functions
Hugo
Hugo•10mo ago
i'm not sure i follow
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
uh lemme refine that. in the integrations folder, the file that will be containing the typescript code to make the http requests to intuit, they will be a bunch of functions without an "entrypoint". meaning, there wont be any "start" or "run" script of any sort from anywhere (other files/package.json scripts) to call those functions.
Hugo
Hugo•10mo ago
exactly
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
gotcha! starting now what do i name the integration? typescript?
Hugo
Hugo•10mo ago
if you run bun run setup quickbooks it will generate all the folder and files you need with the correct name
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
sure
Hugo
Hugo•10mo ago
in this case the integration name is Quickbooks
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
all set!
No description
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
hey uh, there's a thing i needed to discuss. intuit doesn't allow the SDKs to use their API using some API key or so. it's exactly how google oauth works. like, there needs to be a proper server running that will host the redirect url, which will in turn give us the auth token which we can use to make requests. what should be the flow that we implement in here?
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
npm
intuit-oauth
Intuit Node.js client for OAuth2.0 and OpenIDConnect. Latest version: 4.0.0, last published: 3 years ago. Start using intuit-oauth in your project by running npm i intuit-oauth. There are 38 other projects in the npm registry using intuit-oauth.
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
one thing that might be done is (although im not that sure), we can externalize the auth to the users, and ask them to pass the auth token to the integration when they are using it. that way we might be able to use it.
No description
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
lemme know your thoughts on this 🙂 hey btw, can you assign me the issue? helps clear the confusion among other developers
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
think i got the idea of what i should be doing. referred this https://hub.windmill.dev/scripts/postgresql/1294/execute-query-and-return-results-postgresql
Script 'Execute Query and return results' for postgresql | Windmill...
How to Execute Query and return results for postgresql : Executes an arbitrary query and return the row results
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
ill try raising a pr by tonight (IST)
Hugo
Hugo•10mo ago
you don't have to handle the oauth flow, you can assume the resource contains the token
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
cool
Hugo
Hugo•10mo ago
regarding the octokit import, you can remove the line from your setup.ts file inside the quickbooks folder otherwise you won't be able to run your tests
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
yeap fixed that so do i make the requests using fetch or intuit sdk? using their sdk will mean i'll need to somehow parse the auth tokens n stuff. but if i do a raw request using fetch, the users can simply parse the token, companyid and realmid dynamically using their own version of intuit authkit
Hugo
Hugo•10mo ago
preferably with the sdk i'm guessing that if the resource contains the key, secret, realmid and tokens, it should work right?
No description
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
i never came across this one... lemme check do you have a link or something?
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
npm
node-quickbooks
node.js client for Intuit's IPP QuickBooks V3 API.. Latest version: 2.0.44, last published: 2 days ago. Start using node-quickbooks in your project by running npm i node-quickbooks. There are 36 other projects in the npm registry using node-quickbooks.
Hugo
Hugo•10mo ago
yes exactly
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
cool lemme see @Hugo hey there, i created the code for Create_Bill. care to give it a look? took me some time :/
Hugo
Hugo•10mo ago
sure
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
import QuickBooks from 'node-quickbooks';

type Quickbooks = {
clientId: string;
clientSecret: string;
realmId: string;
authToken: string;
refreshToken: string;
};

type Bill = {
VendorRef: {
value: string;
name?: string;
};
Line: {
Id?: string;
DetailType: 'AccountBasedExpenseLineDetail';
Amount: number;
AccountBasedExpenseLineDetail: {
AccountRef: {
value: string;
name?: string;
};
TaxAmount?: number;
TaxInclusiveAmt?: number;
ClassRef?: {
value: string;
name?: string;
};
TaxCodeRef?: {
value: string;
name?: string;
};
BillableStatus?: string;
CustomerRef?: {
value: string;
name?: string;
};
};
Description?: string;
LineNum?: number;
}[];
CurrencyRef?: {
value: string;
name?: string;
};
};

export async function main(resource: Quickbooks, bill: Bill) {
var qbo = new QuickBooks(
resource.clientId,
resource.clientSecret,
resource.authToken,
false,
resource.realmId,
false,
true,
null,
'2.0',
resource.refreshToken
);

return new Promise((resolve, reject) => {
qbo.createBill(bill, function (err: any, result: any) {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
}
import QuickBooks from 'node-quickbooks';

type Quickbooks = {
clientId: string;
clientSecret: string;
realmId: string;
authToken: string;
refreshToken: string;
};

type Bill = {
VendorRef: {
value: string;
name?: string;
};
Line: {
Id?: string;
DetailType: 'AccountBasedExpenseLineDetail';
Amount: number;
AccountBasedExpenseLineDetail: {
AccountRef: {
value: string;
name?: string;
};
TaxAmount?: number;
TaxInclusiveAmt?: number;
ClassRef?: {
value: string;
name?: string;
};
TaxCodeRef?: {
value: string;
name?: string;
};
BillableStatus?: string;
CustomerRef?: {
value: string;
name?: string;
};
};
Description?: string;
LineNum?: number;
}[];
CurrencyRef?: {
value: string;
name?: string;
};
};

export async function main(resource: Quickbooks, bill: Bill) {
var qbo = new QuickBooks(
resource.clientId,
resource.clientSecret,
resource.authToken,
false,
resource.realmId,
false,
true,
null,
'2.0',
resource.refreshToken
);

return new Promise((resolve, reject) => {
qbo.createBill(bill, function (err: any, result: any) {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
}
Hugo
Hugo•10mo ago
looks good, the only thing is our platform can better parse the main function parameters if you describe the type directly like this:
import QuickBooks from "node-quickbooks";

type Quickbooks = {
clientId: string;
clientSecret: string;
realmId: string;
authToken: string;
refreshToken: string;
};

export async function main(
resource: Quickbooks,
VendorRef: {
value: string;
name?: string;
},
Line: {
Id?: string;
DetailType: "AccountBasedExpenseLineDetail";
Amount: number;
AccountBasedExpenseLineDetail: {
AccountRef: {
value: string;
name?: string;
};
TaxAmount?: number;
TaxInclusiveAmt?: number;
ClassRef?: {
value: string;
name?: string;
};
TaxCodeRef?: {
value: string;
name?: string;
};
BillableStatus?: string;
CustomerRef?: {
value: string;
name?: string;
};
};
Description?: string;
LineNum?: number;
}[],
CurrencyRef?: {
value: string;
name?: string;
}
) {
var qbo = new QuickBooks(
resource.clientId,
resource.clientSecret,
resource.authToken,
false,
resource.realmId,
false,
true,
null,
"2.0",
resource.refreshToken
);

return new Promise((resolve, reject) => {
qbo.createBill(
{
VendorRef,
Line,
CurrencyRef,
},
function (err: any, result: any) {
if (err) {
reject(err);
} else {
resolve(result);
}
}
);
});
}
import QuickBooks from "node-quickbooks";

type Quickbooks = {
clientId: string;
clientSecret: string;
realmId: string;
authToken: string;
refreshToken: string;
};

export async function main(
resource: Quickbooks,
VendorRef: {
value: string;
name?: string;
},
Line: {
Id?: string;
DetailType: "AccountBasedExpenseLineDetail";
Amount: number;
AccountBasedExpenseLineDetail: {
AccountRef: {
value: string;
name?: string;
};
TaxAmount?: number;
TaxInclusiveAmt?: number;
ClassRef?: {
value: string;
name?: string;
};
TaxCodeRef?: {
value: string;
name?: string;
};
BillableStatus?: string;
CustomerRef?: {
value: string;
name?: string;
};
};
Description?: string;
LineNum?: number;
}[],
CurrencyRef?: {
value: string;
name?: string;
}
) {
var qbo = new QuickBooks(
resource.clientId,
resource.clientSecret,
resource.authToken,
false,
resource.realmId,
false,
true,
null,
"2.0",
resource.refreshToken
);

return new Promise((resolve, reject) => {
qbo.createBill(
{
VendorRef,
Line,
CurrencyRef,
},
function (err: any, result: any) {
if (err) {
reject(err);
} else {
resolve(result);
}
}
);
});
}
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
oh okay. ill keep that in mind
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
hey @Hugo , i have put up a draft for now. it doesnt have the tests, just the functions. can you give it a look to see if its as per your requirements or not? https://github.com/windmill-labs/windmill-community-integrations/pull/4
Hugo
Hugo•10mo ago
looks pretty good!
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
nice! im burnt out for the day 🙂 ill resume tomorrow with the tests hey, i started with the tests, and something seems off. i keep getting a 403. I cross checked the request made by the node sdk with the one in intuit playground. they both look identical, yet im getting errors. now im also certain that my environments are configured properly since i console logged them i was wondering if you could help me a bit in debugging it? never mind, i fixed it 🙂 hey uh, this endpoint is failing in my case: https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/purchase#create-a-purchase
{
"PaymentType": "CreditCard",
"AccountRef": {
"value": "42"
},
"Line": [
{
"DetailType": "AccountBasedExpenseLineDetail",
"Amount": 10.0,
"AccountBasedExpenseLineDetail": {
"AccountRef": {
"value": "13"
},
"ProjectRef": {
"value": "42991284"
}
}
}
]
}
{
"PaymentType": "CreditCard",
"AccountRef": {
"value": "42"
},
"Line": [
{
"DetailType": "AccountBasedExpenseLineDetail",
"Amount": 10.0,
"AccountBasedExpenseLineDetail": {
"AccountRef": {
"value": "13"
},
"ProjectRef": {
"value": "42991284"
}
}
}
]
}
i slightly modified the JSON whet it was complaining, still its failing.
{
"responseHeader": {
"status": 400,
"message": "",
"intuitTid": "1-65e1ca07-55423da61db1b8b7197ac190",
"realmID": "9341451914020643"
},
"response": {
"Fault": {
"Error": [
{
"Message": "Request has invalid or unsupported property",
"Detail": "Property Name:failed to parse json object; a property specified is unsupported or invalid",
"code": "2010"
}
],
"type": "ValidationFault"
},
"time": "2024-03-01T04:28:56.029-08:00"
}
}
{
"responseHeader": {
"status": 400,
"message": "",
"intuitTid": "1-65e1ca07-55423da61db1b8b7197ac190",
"realmID": "9341451914020643"
},
"response": {
"Fault": {
"Error": [
{
"Message": "Request has invalid or unsupported property",
"Detail": "Property Name:failed to parse json object; a property specified is unsupported or invalid",
"code": "2010"
}
],
"type": "ValidationFault"
},
"time": "2024-03-01T04:28:56.029-08:00"
}
}
This is the error
Hugo
Hugo•10mo ago
does it work if you use the docs "try it" button?
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
nope tried it from there aswell im getting the same error from all the places
Hugo
Hugo•10mo ago
is it possible that the name attribute corresponds to an object that must be created beforehand?
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
uh... can be a case. lemme check that up what im not sure is, which Name attribute it is referring to. there are 2 in the original body
{
"PaymentType": "CreditCard",
"AccountRef": {
"name": "Visa",
"value": "42"
},
"Line": [
{
"DetailType": "AccountBasedExpenseLineDetail",
"Amount": 10.0,
"AccountBasedExpenseLineDetail": {
"AccountRef": {
"name": "Meals and Entertainment",
"value": "13"
},
"ProjectRef": {
"value": "42991284"
}
}
}
]
}
{
"PaymentType": "CreditCard",
"AccountRef": {
"name": "Visa",
"value": "42"
},
"Line": [
{
"DetailType": "AccountBasedExpenseLineDetail",
"Amount": 10.0,
"AccountBasedExpenseLineDetail": {
"AccountRef": {
"name": "Meals and Entertainment",
"value": "13"
},
"ProjectRef": {
"value": "42991284"
}
}
}
]
}
Hugo
Hugo•10mo ago
i mean probably both require the object to be created beforehand i'm guessing the first one the name of a valid credit card account and the second of an expense account
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
okay lemme check that once uhh... hey, stupid question but, i dont think i seem to find any section that allows me to create a card 🙂 (both from the app dashboard and api docs) P.S. i dont think that the error has got anything to do with missing dependencies. it feels more like an error on parsing/accessing nested items from their end i'll skip this one for now. the function is implemented and types are correct, just not writing the test. ill make a list of things not working once i update my pr
Hugo
Hugo•10mo ago
Set up, use, and pay credit card accounts
Learn how to set up, use, and pay credit card accounts in QuickBooks Desktop.A Credit Card gives you an option to borrow funds for purchases or for paying bills
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
i think this is what you are referring to. i do have a Visa card. Since the balance is 0 i updated the card to be Mastercard in the request. still no luck
No description
Hugo
Hugo•10mo ago
do you set the "value" property to the account id as well?
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
i just copied what their docs gave me 😦 its really confusing to understand i must admit but all of the queries work except this one so im confused https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/customer#full-update-a-customer this too is giving me a hard time :/ pushed a couple of tests. here are my blockers: - how do i test the code for "Get by id" - issue with update customer, creating a purchase Hey @Hugo can you give me some tips on how do i get about this?
Hugo
Hugo•10mo ago
Hey, i'll have a look today
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
awesome! ill be available for the next 7-8 hours so drop in a text whenever you can
Hugo
Hugo•10mo ago
for creating a purchase, you need to remove the projectref attribute
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
Gotcha
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
I think I was making a sparse update.... Not sure why it still crashed
Hugo
Hugo•10mo ago
for Get by id, just check that it returns an object with a least one of the expected attribute i've just tried the example in their api tester and it works
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
Nah, I mean, how do I get the id in the first place?
Hugo
Hugo•10mo ago
list and then take first
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
Strange, nvm I'll give it a try again tomorrow
Hugo
Hugo•10mo ago
or create then try to get it
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
Cool so need to initialize the client in the tests ig
Hugo
Hugo•10mo ago
yes like in the github example, but should be as simple as copy pasting from the script file
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
Gotcha Overall, do you feel the tests and the scrupts are as per your standards? I've updated the code 2 days back
Hugo
Hugo•10mo ago
yes, just one thing for the tests is that ideally you should use the client to check that the action did work e.g. after calling the script to create a purchase, you use the id returned to query the purchase with a separate call and just check that it return the right object also the readme should be a bit more detailed
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
Understood Oh, yeah I didn't touch the readme file at all. So it's kinda blank rn hey man, your suggestions worked nicely! expect the final PR to be live by today @Hugo i have made my final commit. do give it a review when you can!
Hugo
Hugo•10mo ago
Hey, looks good! three tests failed because you don't pass resource.isSandBox (sparse update invoice, update customer, delete purchase), please check these ones as well as the rest One other thing, we need to make sure we can run the tests as many times as we want so for: - delete: you need to create the object beforehand otherwise it won't work at some point - update: you have to make sure the object exists or create one - create with constraint: the create customer test failed because a customer with the same name already existed. would be great if you can check that and delete it if it does after that, the PR will be ready to merged!
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
ohhh ah so lets do this: - delete: i create an object before issuing the delete - update: i create an object before updating it. update it, and delete it then - create: i create an object, and delete it next sounds good @Hugo ?
Hugo
Hugo•10mo ago
perfect
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
great on it now hey uh, landed into a problem. all the reviews that you gave are fixed. except one: the customer entity. https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/customer looks like we cant "delete" any customer. the company dashboard gives an option to invalidate customers but the API doesnt @Hugo in this case, the next best thing that we can do is, generate random names for customers using uuid or something, hoping they dont collide
Hugo
Hugo•10mo ago
sounds good
H E I S E N B E R G
H E I S E N B E R GOP•10mo ago
okay done @Hugo pushed my changes