using .NET IPP QBOV3 SDK
I have been working (struggling) on a small integration project all week.
The purpose of the project is to be able to have some accounts integration between a windows desktop client application, to quickbooks online.
I want to be able to -
Create new customers/suppliers (can do this)
Add sales invoices (cannot do this)
Return credit balances (not even tried this yet)
After reading a few forums, and articles to come to the understanding the QBOV3 .NET SDK was the one to use, for two reasons.
I'm going to use C# .net, as a winforms application to code the
functionality I need (this allows me to have the functionality integrated in the
current system, a this is also written in c# .net winforms)
It seems intuit say this is the way to go, as all over APIs are
going to be depreciated.
So, my first hurdle was the OAuth - which eventually I managed to figure out. I can now authorise and connect to my QBO sandbox account - great!
I can also create customers from the winforms application, and they appear in QBO - also great!
The next step, which has stumped me for the last 2 or so, is to be able to create an invoice for a customer - I just cant seem to figure out what to do. I am constantly getting a 'Bad request' error.
I have found next to no examples online on how to do this from a c# winforms application. It cant be that hard - so I'm really kicking myself at the moment.
Any help, or sample to set me in the right direction would be appreciated.
I cant believe no simple examples exist of this already - I guess not many are doing this via a desktop winforms application, or I am just looking in the wrong places - or have missed something obvious!
Reading through the API documentation is confusing, and doesn't really offer any sample code. I would of thought adding a sales invoice would be a pretty big thing to cover.
Here is the code I am currently using to gain some simple functionality - creating the customer works fine (if the customer doesn't exist in qbo - this is something I need to check before adding - so any steer on that would be great also)
Here is the code I cobbled together so far..
private void button2_Click(object sender, EventArgs e)
{
string consumerKey = "consumerKey";
string consumerSecret = "consumerSecret";
string accessToken = "accessToken";
string accessTokenSecret = "accessTokenSecret";
string appToken = "appToken";
string companyID = "companyID"; //realmID
OAuthRequestValidator oauthValidator = new OAuthRequestValidator(accessToken, accessTokenSecret, consumerKey, consumerSecret);
ServiceContext context = new ServiceContext(appToken, companyID, IntuitServicesType.QBO, oauthValidator);
//uses production as default, which is https://quickbooks.api.intuit.com
context.IppConfiguration.BaseUrl.Qbo = "https://sandbox-quickbooks.api.intuit.com/";
//If not set, the default base URL, https://quickbooks.api.intuit.com, is used
DataService service = new DataService(context);
//add customer
Customer customer = new Customer();
customer.CompanyName = "Jims Junk";
customer.GivenName = "Jim";
customer.FamilyName = "Little";
customer.PrimaryEmailAddr = new EmailAddress() { Address = "test#test.com", Default = true };
customer.DisplayName = "Jims Junk Ltd"
Customer resultCustomer = service.Add(customer) as Customer;
//invoice
//-An invoice must have at least one Line that describes an item.
//- An invoice must have CustomerRef populated.
//- The DocNumber attribute is populated automatically by the data service if not supplied.
//- If ShipAddr, BillAddr, or both are not provided, the appropriate customer address from Customer is used to fill those values.
//-DocNumber, if supplied, must be unique.
Invoice invoice = new Invoice();
invoice.DocNumber = "uniqueNumber";
invoice.TxnDate = DateTime.Today.Date;
invoice.TxnDateSpecified = true;
invoice.CustomerRef = new ReferenceType()
{
name = customer.DisplayName,
Value = resultCustomer.Id
};
Line invLine = new Line();
invLine.Amount = 10000;
invLine.DetailType = LineDetailTypeEnum.SalesItemLineDetail;
invLine.Description = "Test Product";
invoice.Line = new Line[] { invLine };
Invoice resultInvoice = service.Add(invoice) as Invoice;
}
Sods Law, after a few days of not finding anything - Just now I find a code sample that has helped.
I have now managed to get an invoice posted into QBO.
Here is the linked that helped - http://developer.qbapi.com/Create-Invoice-Error---Bad-Request.aspx
ill just leave it here, so that others may benefit if struggling.
Thanks for reading.
Related
Hey all the last time I used IGDB was when it was in version 3 and it was easy to search for a game depending on the platform chosen:
string url = "https://api-v3.igdb.com/games/?search=" + gameNameHere +
"&fields=name,genres,involved_companies,first_release_date,cover";
HttpWebRequest gameRequest = (HttpWebRequest)WebRequest.Create(url);
However, this version 4 is quite compilated since they tie in Twitch Oauth for some reason in order to call the API.
Besides the Oauth issue I am unable to find a simple search for a game using the IGDB-DOTNET wrapper for V4...
Now for this wrapper I start out (like it says on the website) with the following:
var igdb = new IGDBClient(
// Found in Twitch Developer portal for your app
Environment.GetEnvironmentVariable("IGDB_CLIENT_ID"),
Environment.GetEnvironmentVariable("IGDB_CLIENT_SECRET")
);
I place both my Client ID and Secret into the proper spots above. Ok, easy enough.
But now it continues to this - calling it "simple":
// Simple fields
var games = await igdb.QueryAsync<Game>(IGDBClient.Endpoints.Games,
query: "fields id,name; where id = 4;");
var game = games.First();
game.Id; // 4
game.Name; // Thief
So where did this Thief game ID of 4 come from? How do I search for the game "Thief" and get that ID in order to call the above to get the needed name, cover, artwork, etc...?
The other 3 examples below that also do not show how to search for a game.
So is this below what its looking for me to do in order to search?
var games = await igdb.QueryAsync<Game>(IGDBClient.Endpoints.Games,
query: "search \"Thief\"; fields id,name,cover;");
If not then how does one do that for V4?
Yes, you are right,
var r = await IGDBClient.QueryAsync<Game>(IGDBClient.Endpoints.Games,
$"search \"{query}\"; fields id, name,first_release_date,total_rating,summary,cover.*;");
where query = "Thief";
The last line of the following code results in an "Operation returned an invalid status code 'BadRequest'" exception and I don't understand why:
Given the following code :
var tenantDomain = ConfigurationManager.AppSettings["TenantDomain"];
var clientId = ConfigurationManager.AppSettings["ClientID"];
var secret = ConfigurationManager.AppSettings["ClientSecret"];
var subscriptionId = ConfigurationManager.AppSettings["SubscriptionID"];
var serviceCreds = await ApplicationTokenProvider.LoginSilentAsync(tenantDomain, clientId, secret);
var bmc = new BillingManagementClient(serviceCreds);
bmc.SubscriptionId = subscriptionId;
List<Invoice> allInvoices = bmc.Invoices.List().ToList();
Suggestions anyone ? Should I specify a date period explicitly ? How?
Suggestions anyone ? Should I specify a date period explicitly ? How?
If we want to access Billing we need to assign the Billing Reader role to someone that needs access to the subscription billing. We could get the detail steps for the azure official tutorials. I also test the code you mentioned, there is no issue with code, if it is supported. The following is the snippet from the official tutorials.
The Billing Reader feature is in preview, and does not yet support enterprise (EA) subscriptions or non-global clouds.
Please have a try to login Azure Portal to check whether have access to Access to invoice. If you see the Access to invoice is disabled, it seems that the subscription type is not supported.
If you still have further questions, could contact support to get your issue resolved quickly.
I'm upgrading a C# application used at work to gather client satisfaction stats using Survey Monkey. The upgrade is to make it use the Survey Monkey API V3 instead of V2 (since V2 gets turned off soon). Both versions of our code make use of Ben Emmett's excellent .NET wrapper(https://github.com/bcemmett/SurveyMonkeyApi) extended with appropriate methods to support creating new surveys and sending invitations.
In version 2 we used the Create_Flow API method to generate new surveys based on an existing one (we have a couple of existing base surveys and choose the appropriate one based on the type of project we're surveying about). It's important that the title of the new survey reflect the name of the relevant project. The relevant part of our V2 code looks like this:
var data = new CreateFlowSettings();
data.survey.survey_title = legislationTitle;
data.survey.from_survey_id = fromSurveyId;
data.collector.recipients = recipients;
data.email_message.subject = subject;
data.email_message.body_text = bodyText;
data.email_message.reply_email = replyEmail;
var serializedData = JsonConvert.SerializeObject(data);
const string endPoint = "/batch/create_flow";
var response = MakeApiRequest(endPoint, serializedData);
var createFlowResponse =
JsonConvert.DeserializeObject<CreateFlowResponseObjects.CreateFlowResponse>(response.ToString());
return createFlowResponse;
In V3 we create our surveys using the /surveys endpoint like so (the term 'template' used in the code below is not a reference to the Survey Monkey concept of template surveys):
public Survey CreateSurvey(string templateSurveyid, string newSurveyTitle)
{
const string endpoint = "/surveys";
var requestData = new RequestData {{"from_survey_id", templateSurveyid}, {"title", newSurveyTitle}};
var result = MakeApiRequest(endpoint, Verb.POST, requestData);
return result.ToObject<Survey>();
}
In V2 the title of the survey displayed at the top of each page in our new surveys would reflect the 'survey_title' data we sent with the API request. In V3 however the 'title' value is NOT replacing the text appearing at the top of each page. It IS correctly determining the name of the survey on the site but at the top of each page we see the title of the survey on which the new one was based (the survey with the id passed to the API as 'from_survey_id').
I think I've googled this pretty extensively and can't find anybody else describing this problem. Any ideas what I am doing wrong? Do I need to code modifying the survey after creation to achieve this in V3?
So it turns out this is a bug in API v3. Only part of the survey title is being updated on copy survey.
This has been resolved - expect a fix out (likely sometime this week) and it will start working without any changes on your side.
Note: PATCH on the survey should be working properly (but I wouldn't recommend coding around the issue unless necessary)
Right now I have an app that allows a user to schedule/post a Facebook post and then monitor the likes/comments. One of the problems I foresee is that currently I am pulling every single comment/like whether it's been processed or not. What I would like to do instead is be able to say 'Give me all the NEW comments since XYZdate/XYZcomment.' Is this currently possible?
var accessToken = existingUserNode.Attributes["accessToken"].Value;
var facebookAPIMgr = new FacebookWrapper.FacebookAPIManager();
var msg = new FacebookWrapper.FacebookMessage()
{
AccessToken = accessToken,
FacebookMessageId = facebookPost.FacebookMessageId
};
//Get Facebook Message Comments
// Need to find a way to limit this to only new comments/likes
var comments = facebookAPIMgr.RetrieveComments(msg);
You can do time-based pagination as part of your graph API query. If you keep a unix timestamp of when you polled things last, you can simply do https://graph.facebook.com/{whatever}?since={last run}.
This worked when I was working heavily with the Graph API earlier this year, and is still around on the documentation, but considering how much Facebook loves to change stuff without telling anyone you may still encounter problems. So just a warning, YMMV.
I'm wanting to copy an already existing Google Docs Spreadsheet to a new Google Docs spreadsheet. I dont think the v2.0 .NET API can handle it natively (or if so I can't find the class/method), however It looks like the v3.0 protocol can but I'm not sure how to implement this in the current framework or even if it is possible with the current .net api. eg. ~DocumentsFeed.copy() (pseudo code).
Exporting to a temp excel file then uploading with a new name is not possible either as some of the complex formulas get messed up in the conversion process.
I am a bit of a .NET noob so any info would be greatly appreciated eg. How would I go about doing this in .NET if I could only use the v3 protocol (ajax etc) and not the .NET API.
Thanks
EDIT: (final class thanks to #langsamu for his help!)
using System;
using Google.GData.Documents;
using Google.GData.Client;
using Google.GData.Extensions;
public class GoogleDocument
{
private DocumentsService ds;
private String username;
private String password;
public GoogleDocument(String username, String password)
{
this.ds = new DocumentsService("doc service name");
this.username = username;
this.password = password;
this.ds.setUserCredentials(username, password);
this.ds.QueryClientLoginToken();
}
public void copyDocument(String oldFileName, String newFileName)
{
SpreadsheetQuery query = new Google.GData.Documents.SpreadsheetQuery();
query.Title = oldFileName;
query.TitleExact = true;
DocumentsFeed feed = this.ds.Query(query);
AtomEntry entry = feed.Entries[0];
entry.Title.Text = newFileName;
var feedUri = new Uri(DocumentsListQuery.documentsBaseUri);
this.ds.Insert(feedUri, entry);
}
}
Google.GData.Documents.DocumentsService service = new Google.GData.Documents.DocumentsService("YOUR_APPLICATIONS_NAME");
service.setUserCredentials("YOUR_USERNAME", "YOUR_PASSWORD");
Google.GData.Documents.SpreadsheetQuery query = new Google.GData.Documents.SpreadsheetQuery();
query.Title = "YOUR_SPREADSHEETS_TITLE";
query.TitleExact = true;
Google.GData.Documents.DocumentsFeed feed = service.Query(query);
Google.GData.Client.AtomEntry entry = feed.Entries[0];
var feedUri = new Uri(Google.GData.Documents.DocumentsListQuery.documentsBaseUri);
service.Insert(feedUri, entry);
This solution is basically about retrieving an existing spreadsheet (service.Query) using the Document List API and re-inserting it (service.Insert).
Make sure you replace the ALL CAPS application name, username, password and spreadsheet title.
Add a reference to Google.GData.Documents.
This is using .NET 4 (should work with lower versions as well) and Google Documents List Data API v2.0 (DLL says version is 1.6.0.0: google-gdata), which seems to use version 3.0 of the protocol.
It is a bit unclear if you are developing a web application or a desktop application, so I'll try and cover both (essentially they are very much alike - because...).
If you are developing a web application you won't be able to make a 100% AJAX solution. You will only be able to request URL's on the same domain. To do this you will need to either do the communication server side only, or do it server side and proxy it to your web app through AJAX.
If you are developing a desktop application you'll have to do this stuff aswell. Except the AJAX part.
An example app would be fairly easy - 2-3 hours work to whip up considering the documentation given. With just a little knowledge of HTTP and POST request forming you should be able to make it work.