Coder Social home page Coder Social logo

intuit / quickbooks-v3-dotnet-sdk Goto Github PK

View Code? Open in Web Editor NEW
105.0 32.0 137.0 32.74 MB

.Net SDK for QuickBooks REST API v3 services

License: Apache License 2.0

C# 99.06% CSS 0.19% HTML 0.32% ASP.NET 0.43%
quickbooks quickbooks-online-dotnet-sdk hacktoberfest hacktoberfest2020

quickbooks-v3-dotnet-sdk's Introduction

SDK BannerSDK BannerSDK Banner

V3-DotNet-SDK

Logo

IDG .NET SDK for QuickBooks V3 (Class lib Project written in .NET Standard 2.0- Supports .Net Full Framework 4.6.1, 4.7.2 and .Net Core 2.1,.Net Core 2.2)

Support: Help
Documentation: User Guide Refer SDK class lib docs
License: Apache 2
Binaries: Nuget
Binaries for OAuth2 only: Nuget

The QuickBooks Online .NET SDK provides a set of .NET class libraries that make it easier to call QuickBooks Online APIs, and access to QuickBooks Online data. It supports .Net Core 2.1, .Net Core 2.2, .Net Full Framework 4.6.1 and 4.7.2. Some of the features included in this SDK are:

  • Ability to perform single and batch processing of CRUD operations on all QuickBooks Online entities.
  • A common interface to the Request and Response Handler with two implemented classes to handle both synchronous and asynchronous requests.
  • Support for both XML and JSON Request and Response formats.
  • Ability to configure app settings in the configuration file requiring no additional code change.
  • Support for Gzip and Deflate compression formats to improve performance of Service calls to QuickBooks Online.
  • Retry policy constructors to help apps handle transient errors.
  • Logging mechanisms for trace and request/response logging.
  • Query Filters that enable you to write Intuit queries to retrieve QuickBooks Online entities whose properties meet a specified criteria.
  • Queries for accessing QuickBooks Reports.
  • Sparse Update to update writable properties specified in a request and leave the others unchanged.
  • Change data that enables you to retrieve a list of entities modified during specified time points.
  • Supports OAuth2

Note: ->Oauth1 support has been removed from this SDK. Intuit.Ipp.Retry logic now have been moved to Intuit.Ipp.Core. So, if you see Retry not found issues while updating your code, just remove that Using Intuit.Ipp.Retry statement and add Using Intuit.Ipp.Core if not already present.

Understanding the .Net SDK code structure:

Schema

  • Schema - Schema files for QBO V3 APIs are available under this folder.

The code has been divided into following main categories-

Data projects

  • Intuit.Ipp.XsdExtension - This is an external tool whose executable is used to generate the different classes based on the input QBO V3 service schema.

  • Intuit.Ipp.Data - This project has the updated classes in CDMEntities folder generated by the XsdExtension tool based on new releases of schema.

Core and Common functionality projects

  • Intuit.Ipp.Core - This project does the job of handling the core functionalities like handling configuration, handling sync, async requests, callbacks and retry logic.

  • Intuit.Ipp.QueryFilter - Handles all query operations related logic.

  • Intuit.Ipp.Utility - Handles serialization, deserialization logic, compression, and other config based logic for the API calls.

  • Intuit.Ipp.Diagnostics - Handles the old Trace Logger code.

  • Intuit.Ipp.Exception - Handles the exception logic for the different services calls.

Service projects

Security/Auth related projects

Test Projects

  • Unit Tests - All unit test projects are available under the Code folder. You can identify them if they have a .Test suffix in their name.
  • Integration Tests - All integration tests are available under Intuit.Ipp.Test

Nuget Package Creation Project

  • Intuit.Ipp.Nupkg- This project has the configuration for version of package and all dependencies.After you do a build in Release mode, this project will generate the Nuget packages under the folder Code->artifacts->nupkg for the different .Net supported versions listed above. You can then upload the package to a Nuget org.

Understanding some important exceptions thrown by the SDK

  • IdsException - This is the base execption thrown when other sub exceptions cannot catch it. Make sure to enable logs to get details for the internal error when you see this exception. These may be related to service downtime.
  • ValidationException - These are valid business validation rules based error and should be corrected in the code. These are all API related exceptions,
  • InvalidTokenException - This exception is thrown when your OAuth2 token has expired or is invalid. You will need to regenerate a new token by doing OAuth2 again or renew you tokens if they are still valid.

Enabling logs for the SDK

Logs help you in easliy identifying detailed issues with your payload, get more info in the exception details for fixing them.

  • New logging support was added to the SDK which includes support for reporting headers and multiple logging sinks available from Serilog. You can chooise to have either one or more of these logging sinks enabled. - Serilogger logs can be enabled for OAuth2PlatformClient using the following lines -

          static OAuth2Client oauthClient = new OAuth2Client(clientID, clientSecret, redirectURI, appEnvironment);
          //Use this line to enable only intuit-tid based logs, no tokens/response will be logged. 
          //If set to false, all detailed logs will be available for response
          //If set to true, only intuit-tid response headers will be available
          
          // This will work with both custom logger or already supported serilog logger sinks in the SDK
          oauthClient.EnableAdvancedLoggerInfoMode = true;
          
          // Option for devs to use this for setting their own custom logger
          //Adding support for custom logger where value can be an instance of Serilog.Core.ILogger
          oauthClient.CustomLogger =  <ILogger custom logger>;
    
          //Already supported logger in the SDK. Either use custom logger or the below statements for serilog logs to work.     
          oauthClient.EnableSerilogRequestResponseLoggingForConsole = true;
          oauthClient.EnableSerilogRequestResponseLoggingForDebug = true;
          oauthClient.EnableSerilogRequestResponseLoggingForFile = true;
          oauthClient.EnableSerilogRequestResponseLoggingForTrace = true;
          oauthClient.ServiceRequestLoggingLocationForFile = @"C:\Documents\Serilog_log";//Any drive logging location
    

Serilogger logs can be enabled for QBO API calls using the following lines -

        ServiceContext context = new ServiceContext(dictionary["realmId"], IntuitServicesType.QBO, oauthValidator);

        //Adding support for custom logger where value can be an instance of Serilog.Core.ILogger
        context.IppConfiguration.AdvancedLogger.RequestAdvancedLog.CustomLogger = <ILogger custom logger>;
        
        //Already supported logger in the SDK. Either use custom logger or the below statements for serilog logs to work.     
        context.IppConfiguration.AdvancedLogger.RequestAdvancedLog.EnableSerilogRequestResponseLoggingForFile = true;
        context.IppConfiguration.AdvancedLogger.RequestAdvancedLog.EnableSerilogRequestResponseLoggingForConsole = true;
        context.IppConfiguration.AdvancedLogger.RequestAdvancedLog.EnableSerilogRequestResponseLoggingForTrace = true;
        context.IppConfiguration.AdvancedLogger.RequestAdvancedLog.EnableSerilogRequestResponseLoggingForDebug = true;
        context.IppConfiguration.AdvancedLogger.RequestAdvancedLog.ServiceRequestLoggingLocationForFile = @"C:\Documents\Serilog_log"; //Any drive logging location

Old file based logs can be enabled by using the following lines-

        context.IppConfiguration.Logger.RequestLog.EnableRequestResponseLogging = true;
        context.IppConfiguration.Logger.RequestLog.ServiceRequestLoggingLocation = @"C:\Documents\Serilog_log"; //Any drive logging location
  • Fiddler logs are really useful too. You can enable them by following the steps below

Download Fiddler from Google and run it alongside your code to log raw requests and responses along with URL and headers. When you download Fiddler, open it, go to Tools > Fiddler Option > Enable (Tick Mark) Capture HTTPS connects > Enable Decrypt Https traffic. That’s it. No other setting is required. The .NET localhost is by default captured in Fiddler, so after you have enabled https traffic in Fiddler just run your code. (Fiddler should be open.) You will see requests and responses logged in Fiddler. You should set 'decode the raw request body' by clicking on the yellow bar in Fiddler. Then go to the File menu on top, select Save all session > Save the fiddler session. A .saz file is created, which can be viewed later.

Running Tests

Refer to the following steps to generate all the keys required to run tests using OAuth Playground-

  • Go to Developer Docs.

  • Create an app on our IDG platform for the QuickBooks Online v3 APIs.

  • For OAuth2 apps, you will get a set of Development keys, including client key and client secret. This can be used to get OAuth access token and refresh token for sandbox companies.

  • To get Prod app keys to get OAuth tokens for live companies: Go to your app->Settings tab-> enter all URLs and save. Then get the prod keys from Keys tab under Prod section.

  • To get OAuth access tokens, go to your app's dashboard, Click Oauth Playground

    • For OAuth2 apps, select the desired app and make sure the OAuth playground redirect_uri is present under Keys tab and go through the OAuth authorization flow to get access and refresh tokens along with the realmid to make API calls for QuickBooks company.
      • Access tokens are valid for 1 hour which can be refreshed using refesh token. When you request a fresh access token, always use the refresh token returned in the most recent refreshing access token API response. A refresh token expires 24 hours after you receive it. More info can be found at: Refreshing the access token
  • NOTE: For sandbox testing, you need to use dev app keys and sandbox base URL. For live/prod QuickBooks company testing, use prod app keys and prod base URL after doing a private publish as mentioned below. Go to your app->Prod tab-> enter all URLs and save. Then get the prod keys from Keys tab under Prod tab of the app.

Contribute:

We greatly encourage contributions! You can add new features, report and fix existing bugs, write docs and tutorials, or any of the above. Feel free to open issues and/or send pull requests.

The master branch of this repository contains the latest release of the SDK, while snapshots are published to the develop branch. In general, pull requests should be submitted against develop by forking this repo into your account, developing and testing your changes, and creating pull requests to request merges. See the Contributing to a Project article for more details about how to contribute.

Steps to contribute:

  1. Fork this repository into your account on Github
  2. Clone your forked repository (not our original one) to your hard drive with git clone https://github.com/YOURUSERNAME/QuickBooks-V3-DotNET-SDK.git
  3. Design and develop your changes
  4. Add/update unit tests
  5. Create a pull request for review to request merge
  6. Obtain approval before your changes can be merged

Note: Before you submit the pull request, make sure to remove the keys and tokens from appsettings.json

Thank you for your contribution!

Samples: https://github.com/intuitdeveloper

quickbooks-v3-dotnet-sdk's People

Contributors

aaronhudon avatar amitemv avatar clement911 avatar dahlbyk avatar dependabot[bot] avatar diana-derose avatar grawlins avatar hershi9 avatar matthewsteeples avatar nbhambhani avatar nimisha84 avatar rkasaraneni20 avatar sm-g avatar sujitharamadass avatar timurka-xalien avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

quickbooks-v3-dotnet-sdk's Issues

Invalid URI: The format of the URI could not be determined.

            var oauthValidator = new OAuth2RequestValidator(oauthInfo.AccessToken);
            var serviceContext = new ServiceContext(oauthInfo.RealmId, IntuitServicesType.QBO, oauthValidator);
            var dataService = new DataService(serviceContext);
            serviceContext.RequestId = GuidGenerator.GenerateGuid();

            var customer = new Customer {
                GivenName = "QQQ",
                Title = "WWW",
                MiddleName = "EEE",
                FamilyName = "AAA"
            };

            var result = dataService.Add(customer) as Customer;

Exception throw in the last line: Invalid URI: The format of the URI could not be determined.

StackTrace:
at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
at System.Uri..ctor(String uriString)
at Intuit.Ipp.Core.Rest.RestHandler.PrepareRequest(RequestParameters requestParameters, Object requestBody, String oauthRequestUri, Boolean includeRequestId)
at Intuit.Ipp.Core.Rest.SyncRestHandler.PrepareRequest(RequestParameters requestParameters, Object requestBody, String oauthRequestUri, Boolean includeRequestId)
at Intuit.Ipp.DataService.DataService.Add[T](T entity)
at ClothResorting.Helpers.IntuitOAuthor.GetAllCustomer(String userId) in d:\users\downw\onedrive\documents\visual studio 2015\Projects\ClothResorting\ClothResorting\Helpers\IntuitOAuthor.cs:line 172
at ClothResorting.Controllers.Api.QuickBooksOnlineOAuthController.SyncInvoiceToQBO(Int32 id) in d:\users\downw\onedrive\documents\visual studio 2015\Projects\ClothResorting\ClothResorting\Controllers\Api\QuickBooksOnlineOAuthController.cs:line 80
at lambda_method(Closure , Object , Object[] )
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass6_1.b__3(Object instance, Object[] methodParameters)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)

============
I have valid access_Token and successfully built OAuth2RequestValidato and ServiceContext. Is there any possibility that was caused by string encode? If so how could I fix it because I cannot touch the Add() method?

Not able to authorize Endpoint using v5.7 and v5.8 of QuickBooks-V3-DotNET-SDK

App integration is running fine using v5.6, but after updating to either v5.7 or v5.8 using Nuget, AuthorizeEndpoint is failing.

Line 38 in the attached.
screen shot 2018-11-15 at 4 08 19 pm

"Value cannot be null. Parameter name: endpoint"
"System.ArgumentNullException: at Intuit.Ipp.OAuth2PlatformClient.TokenClient..ctor(String endpoint, HttpMessageHandler innerHttpMessageHandler)
at Intuit.Ipp.OAuth2PlatformClient.TokenClient..ctor(String endpoint, String clientId, String clientSecret, HttpMessageHandler innerHttpMessageHandler, AuthenticationStyle style)
at Intuit.Ipp.OAuth2PlatformClient.TokenClient..ctor(String endpoint, String clientId, String clientSecret, AuthenticationStyle style)
at ServicePal.WebApp.Synchronization.IntuitOAuth2Helper.d__1.MoveNext() in IntuitOAuth2Helper.cs:line 38

Just for kicks I did try:
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
That makes no difference.

Unparsable response from API not handled

Today QB was returning html page for API requests:




<!doctype html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<meta http-equiv="cache-control" content="max-age=0" />
		<meta http-equiv="cache-control" content="no-cache" />
		<meta http-equiv="expires" content="0" />
		<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
		<meta http-equiv="pragma" content="no-cache" />
		<title>
			We'll be back soon
		</title>
...

and SDK was unable to generate high-level exception like "Server not working":

Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
   в Newtonsoft.Json.JsonTextReader.ParseValue()
   в Newtonsoft.Json.JsonTextReader.Read()
   в Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)
   в Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   в Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   в Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   в Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   в Intuit.Ipp.Utility.JsonObjectSerializer.Deserialize[T](String message)
   в Intuit.Ipp.QueryFilter.QueryService`1.ExecuteIdsQuery(String idsQuery, QueryOperationType queryOperationType)

Master branch does not build

I am having trouble compiling IppDotNetDevKitCSV3.sln. I’m not sure but I’m guessing it is because of circular references. For example, Intuit.Ipp.Core references Intuit.Ipp.Retry which in turn references Intuit.Ipp.Core. Do you have any suggestions? Thanks.

UnitPrice property

QBO wants to see a property called "UnitPrice" on the json to create new Sales Receipts and the QBO .NET library puts a property called "PriceLevelRef" there instead. The same issue seems to plague Invoices as well, and probably more stuff.

ExecuteIdsQuery returns empty list - deserialization bug?

Seems similar to issue #23 but with a different call.

Using ExecuteIdsQuery()
https://quickbooks.api.intuit.com/v3/company/xxxxxx/query?minorversion=21&requestid=xxxxxx

Request Body:
Select * FROM Invoice WHERE MetaData.LastUpdatedTime > '2018-03-24T21:42:59.9658792Z' and MetaData.LastUpdatedTime < '2018-03-26T21:42:59.9147825Z'

Returns 3 Invoices:
image

image

However, after deserialization (line 178 in QueryService.cs) - there are no invoices to be found

image

image

I have pulled all the latest code from GitHub. Still not working.

Thoughts?

Current JsonReader item is not an object

I'm getting this error in y'alls code:

Newtonsoft.Json.JsonReaderException: Error reading JObject from JsonReader. Current JsonReader item is not an object: Null. Path 'Fault', line 1, position 29.
   at Newtonsoft.Json.Linq.JObject.Load(JsonReader reader, JsonLoadSettings settings)
   at Intuit.Ipp.Utility.IntuitConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)
   at Intuit.Ipp.Utility.IntuitConverter.AssignValueToProperty(Object target, JProperty prop, Type type, String propName, JsonSerializer serializer)
   at Intuit.Ipp.Utility.IntuitConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Intuit.Ipp.Utility.JsonObjectSerializer.Deserialize[T](String message)
   at Intuit.Ipp.DataService.Batch.Execute()

It started for certain company files of ours at 1AM PST this morning.

CDCAsyncCompleted returns ArgumentException when more than one entity is changed

Hi.

I am getting an ArgumentException when calling DataService.CDCAsync.

Intuit.Ipp.Exception.IdsException: An item with the same key has already been added.

This seems to happen due a difference between the synchronous CDC call and the asynchronous CDCAsync handler. When multiple entities of a common type are returned by the CDC, the repeated add into the returnValue Dictionary causes the error.

CDCAsync (causes error)

	object[] tempEntityArray = (object[])tempEntities;

	if (tempEntityArray.Length > 0)
	{
		foreach (object item in tempEntityArray)
		{
			entities.Add((IEntity)item);
			returnValue.Add(item.GetType().Name, entities);
			count++; // this line appears unused
		}
	}

CDC (works correctly)

	object[] tempEntityArray = (object[])tempEntities;

	if (tempEntityArray.Length > 0)
	{
		List<IEntity> arr = new List<IEntity>(); // this line appears unused
		string entityName = string.Empty;
		foreach (object item in tempEntityArray)
		{
			entities.Add((IEntity)item);
			entityName = item.GetType().Name;
		}
		returnValue.entities.Add(entityName, entities);
	}

Callback Error when trying to connect to a Sandbox Company

Callback
Code: none
State: e542d83e1b61425db569ea956c2df730 (valid)
RealmId: none
Error: invalid_scope

Note:SIWI flow does not returns relamId as it does not have the required scopes

Not sure what further configuration is to be done here.

Purpose of DiscoveryClient.Authority

There is some conversion from ctor argument to both Url and Authority:

Default Policy.ValidateIssuerName is true, so I expect that either new DiscoveryClient("https://developer.intuit.com/.well-known/openid_sandbox_configuration/") or new DiscoveryClient("https://oauth.platform.intuit.com/op/v1") should work.

But there is no https://oauth.platform.intuit.com/op/v1/.well-known/openid_sandbox_configuration/, and https://developer.intuit.com does not match Issuer (https://oauth.platform.intuit.com/op/v1).

There is also very interesting commented

So why DiscoveryClient.Authority ever exists?

SELECT Count(*) query not supported

Hi, first of all thanks for doing a great job with this SDK.

I can't however find a way to get the totalCount response from the query endpoint using the Batch.Execute() method, when passing in a query that has a SELECT Count(*) clause. Am I going about this the wrong way?

Here's the full code I use:
`Batch batch = ConnectionCache.GetQBODataService(qboCredentials).CreateNewBatch();
batch.Add(query, batchId);
batch.Execute();

			if (batch.IntuitBatchItemResponses != null && batch.IntuitBatchItemResponses.Count() > 0)
			{
				IntuitBatchResponse response = batch.IntuitBatchItemResponses.FirstOrDefault(item => item.Id == batchId);`

IntuitBatchResponse has a response but the response has Entity = null and Entities.Count = 0. No other property with the totalCount from the QuickBooks response. See image from Fiddler
count_query
attached.

uncaught exception on a thread causing APPCRASH

Application: MyService.exe Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.NullReferenceException at Intuit.Ipp.DataService.Batch.BatchAsyncompleted(System.Object, Intuit.Ipp.Core.AsyncCallCompletedEventArgs) at Intuit.Ipp.Core.Rest.AsyncRestHandler.AsyncExecutionCompleted(System.IAsyncResult) at System.Net.LazyAsyncResult.Complete(IntPtr) at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) at System.Net.ContextAwareResult.Complete(IntPtr) at System.Net.LazyAsyncResult.ProtectedInvokeCallback(System.Object, IntPtr) at System.Net.HttpWebRequest.SetResponse(System.Exception) at System.Net.ConnectionReturnResult.SetResponses(System.Net.ConnectionReturnResult) at System.Net.Connection.ReadComplete(Int32, System.Net.WebExceptionStatus) at System.Net.LazyAsyncResult.Complete(IntPtr) at System.Net.LazyAsyncResult.ProtectedInvokeCallback(System.Object, IntPtr) at System.Net.AsyncProtocolRequest.CompleteWithError(System.Exception) at System.Net.FixedSizeReader.ReadCallback(System.IAsyncResult) at System.Net.LazyAsyncResult.Complete(IntPtr) at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) at System.Net.ContextAwareResult.Complete(IntPtr) at System.Net.LazyAsyncResult.ProtectedInvokeCallback(System.Object, IntPtr) at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32, UInt32, System.Threading.NativeOverlapped*) at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32, UInt32, System.Threading.NativeOverlapped*)

Line item rate not getting mapped

We're using the .NET sdk but when we look at the order page in quickbooks online, we don't see the rate value for the product getting populated. Can someone point to the right field within Intuit.Ipp.Data namespace that needs to be mapped because I can't find that field?? Thanks
image

FindAllAsync returns empty list

I tried with customers and bills and it seems to happen no matter what.

Calling FindAll works:
image

But when FindAllAsync returns it does not have any data:
image

The logs show a huge response that somehow doesn't make it to the async callback:
image

Trace logs look pretty normal:
image

A couple other people seem to have had this issue as well:
https://help.developer.intuit.com/s/question/0D5G000004Dk723KAB/data-service-async-call-doesnt-respond-entities
https://help.developer.intuit.com/s/question/0D50f00004zqoZwCAI/findallasync-for-customer-doesnt-work-properly-c

On the second one @nimisha84 mentioned a question here on GitHub but I can't seem to locate that question.

AllowOnlineACHPayment is not enabling ACH Payment Method for Generated Invoice

When I create an Invoice via the Quickbooks UI, I have an option to allow Free ACH Payment.

When I create the same invoice via the Quickbooks SDK, I there are options for:
AllowOnlineACHPayment
and
allowCreditCard

Setting those to true does not result in the ACH option to be enabled.

I have also tried setting: AllowOnlineACHPaymentSpecified to true as well.

Here is a code snippit:
`if(invoice.FleetPilot.FleetPilotGroup.allowACH || invoice.FleetPilot.FleetPilotGroup.allowCreditCard)
{
newInvoice.AllowIPNPayment = true;
newInvoice.AllowIPNPaymentSpecified = true;
newInvoice.AllowOnlinePayment = true;
newInvoice.AllowOnlinePaymentSpecified = true;
}

				newInvoice.AllowOnlineACHPayment = invoice.FleetPilot.FleetPilotGroup.allowACH;
				newInvoice.AllowOnlineACHPaymentSpecified = invoice.FleetPilot.FleetPilotGroup.allowACH;

				newInvoice.allowCreditCard = invoice.FleetPilot.FleetPilotGroup.allowCreditCard;
				newInvoice.AllowOnlineCreditCardPaymentSpecified = invoice.FleetPilot.FleetPilotGroup.allowCreditCard;

				var addedInvoice = dataService.Add<Invoice>(newInvoice);
				invoice.ExternalID = addedInvoice.Id;
				listInvoices.Add(addedInvoice);

				if (invoice.FleetPilot.FleetPilotGroup.sendInvoices)
				{
					dataService.SendEmail<Invoice>(addedInvoice, invoice.FleetPilot.Pilot.EmailAddress);
				}`

Intuit.Ipp.Exception.SerializationException: Object reference not set to an instance of an object.

When I do

reportService.ExecuteReport("AgedReceivables");

I get

Intuit.Ipp.Exception.SerializationException: Object reference not set to an instance of an object. ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at Intuit.Ipp.Utility.ObjectToEnumConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.Serialization.JsonSerializerProxy.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)
   at Intuit.Ipp.Utility.IntuitConverter.AssignValueToProperty(Object target, JProperty prop, Type type, String propName, JsonSerializer serializer)
   at Intuit.Ipp.Utility.IntuitConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.Serialization.JsonSerializerProxy.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)
   at Intuit.Ipp.Utility.IntuitConverter.AssignValueToProperty(Object target, JProperty prop, Type type, String propName, JsonSerializer serializer)
   at Intuit.Ipp.Utility.IntuitConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.Serialization.JsonSerializerProxy.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)
   at Intuit.Ipp.Utility.IntuitConverter.AssignValueToProperty(Object target, JProperty prop, Type type, String propName, JsonSerializer serializer)
   at Intuit.Ipp.Utility.IntuitConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Intuit.Ipp.Utility.JsonObjectSerializer.Deserialize[T](String message)
   --- End of inner exception stack trace ---
   at Intuit.Ipp.Exception.IdsExceptionManager.HandleException(IdsException idsException)
   at Intuit.Ipp.Utility.JsonObjectSerializer.Deserialize[T](String message)
   at Intuit.Ipp.ReportService.ReportService.ExecuteReport(String reportName)

Happening on RealmId 193514831343224

Some bad .NET code in SampleApp-Dotnet_Payments app

remove lines 331-333 as they are not method parameters

    /// <param name="realmId"></param>
    /// <param name="access_token"></param>
    /// <param name="refresh_token"></param>

line 347 is testing for if (dictionary["access_token"] != null), but param is defined elsewhere (e.g. lines 216-219). Failure to do this results in error "The given key was not present in the dictionary." when sample app is unzipped and configured for the first time.

Business validation error when trying to create quickbooks item of type Inventory

When we try to create a quickbooks online item, we get a business validation error with below description -
Business Validation Error: When you create an item, if Track quantity on hand is turned off, the item cannot be of type Inventory.
We do have "track inventory quantity on hand" setting on so this shouldn't be occurring. Would be great if you could look into it?

Explicit usage of TLS 1.2 via ServicePointManager

Setting ServicePointManager.SecurityProtocol to TLS 1.2 affects on whole Application Domain and breaks all the other requests and network - based APIs from application that don't support TSL 1.2.
Sometimes theese APIs use default settings and your code breaks them.
In the files AsyncRestHandler.cs, SyncRestHandler.cs there is a following line

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

This sets security protocol to TLS 1.2 for the whole application, and breaks the requests to services that don't support TLS1.2. The appropriate security protocol is selected automatically while connecting to endpoint, so this code can be safely removed. In order to use TLS 1.2 explicity to enforce protocol selection please use the following code

var httpClientHandler = new HttpClientHandler { SslProtocols =SslProtocols.Tls12 }; httpClient = new HttpClient(httpClientHandler, disposeHandler: true);

Setting SecurityProtocol via Handler is inapplicable for HttpWebRequest so it should be replaced with HttpClient.

Question about unused exceptions

Support for .NET Core

Would be very helpful for the .NET SDK to support .NET core so the SDK can be used cross-platform.

Dependencies to consider:

  • Newtonsoft.Json (JSON.net) supports .NET core
  • DevDefined.OAuth does not support .NET core, an alternative will be needed. One possibility is OAuth.DotNetCore. Or updating DevDefined,OAuth, but I am unsure of what is required to make it work.

Assuming the dependency issue is addressed, are there other components within the SDK that would need to be updated/replaced to support .NET core?

Suspected License Violation

Hello, my name is Brock Allen and I am the co-author/co-owner of the IdentityModel project, whose main repository resides here https://github.com/IdentityModel/IdentityModel2.

It has come to my attention that a commit to this repository, controlled by Intuit, seems to contain files that were originally from the IdentityModel2 project. The manner in which the files were copied and modified violates the license of the IdentityModel2 project (as well as copyrights held by Microsoft included in the IdentityModel2 project). The commit to this repository is here:

c1ce13d

While the files do not match exactly those from the IdentityModel2 project, there are many striking similarities such as directory structure, file names, executable source code, unit tests, and code comments that are an exact match. The modifications performed to the original files are mostly cosmetic and include namespace changes, variable name changes, rewording comments, and replacing the copyright ownership notices themselves. Below are two file diffs that illustrate some of these similarities and modifications.

untitled0
untitled1

While IdentityModel2 uses the Apache 2 license, which is a permissive free software license, it does state in sections 4b and 4c (https://github.com/IdentityModel/IdentityModel2/blob/dev/LICENSE#L97-L104) that:

  • You must cause any modified files to carry prominent notices stating that You changed the files
  • You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works

On behalf of the owners of the IdentityModel project, I kindly request that Intuit remedy this copyright violation by either removing the files, or by adhering to the license agreement.

// @leastprivilege @jongalloway @shanselman

Change internal references from binary to project

What is the rationale of using binary references within the project definitions e.g.

<Reference Include="Intuit.Ipp.Core, Version=5.0.0.0, Culture=neutral, processorArchitecture=MSIL">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>..\..\SDK Assemblies\Intuit.Ipp.Core.dll</HintPath>
</Reference>

It makes compiling the SDK a nightmare with a lot of workarounds, you are shipping the entire library as one nuget package anyway so it can't be dependency versioning?

Inconsistent Awaiter usage within the OAuth2Client

I ran into an issue while trying to use the OAuth2Client.GetBearerTokenAsync method. We are in an ASP.NET synchronous code base, and when we attempt to use .GetAwaiter().GetResult() to fetch the token response, the call never returns, and the thread hangs forever.
I believe my specific issue can be fixed by adding ConfigureAwait(false) to the following line in https://github.com/intuit/QuickBooks-V3-DotNET-SDK/blob/master/IPPDotNetDevKitCSV3/Code/Intuit.Ipp.OAuth2PlatformClient/Client/OAuth2Client.cs#L138

This is based on the article I've listed below. I think it would be worthwhile to add ConfigureAwait(false) to all of the exposed async methods and make sure each awaited method in the call stack also uses ConfigureAwait(false)
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Append access can be requested only in write-only mode.

I get an error Append access can be requested only in write-only mode. with the following set to true:
<intuit> <ipp> <logger> <!-- To enable/disable Request and Response log--> <requestLog enableRequestResponseLogging="true" requestResponseLoggingDirectory="Z:\WWW\PM\Logs" xdt:Transform="Replace"/> </logger> </ipp> </intuit> <intuit> <ipp> <logger> <!-- To enable/disable Request and Response log--> <requestLog enableRequestResponseLogging="true" requestResponseLoggingDirectory="Z:\WWW\PM\Logs" xdt:Transform="Replace"/> </logger> </ipp> </intuit>

Configuration for ASP.NET Core on App Services

This is similar to issue #50 but more specific to hosting in azure via app services.

ASP.NET Core 2.x apps do not use the web.config file and when hosting in azure, the build autogenerates the web.config file with no good support for manipulating it to add stuff so you just get the default one that hosts the app.

Currently, the ServiceContext internally news up a configuration reader that only looks for configuration section of web config. Please add support to change how / where configuration information is provided. Because of the current implementation, we have no way to override the baseUrl to point to development sandbox; it's always pointing to production service.

In the meantime, I'm going to fork this project and include the ability to read the baseUrl from appSettings.json / Environment Variables (used by Azure app services).

Many Unicode characters don't work correctly

.NET internally stores strings encoded as UTF-16 but QBO expects UTF-8. The two encodings are the same for all single-byte code points so you tend not to notice when you aren't sending special characters to QBO. But, for queries with special characters you must put all strings through the following filter (I wrote it as an extension method for kicks):

        public static string ToUtf8(this string input) =>
            new string(Encoding.UTF8.GetBytes(input).Select(b => (char)b).ToArray());

Following the principle of least astonishment, this should be done by the SDK.

SDK access to more Preferences, such as TimeTrackingFeatureEnabled and ProjectsEnabled?

Is that in the upcoming plans?

"OtherPrefs": {
"NameValue": [
{
"Name": "SalesFormsPrefs.DefaultCustomerMessage",
"Value": "Thank you for your business and have a great day!"
},
{
"Name": "SalesFormsPrefs.DefaultItem",
"Value": "19"
},
{
"Name": "DTXCopyMemo",
"Value": "true"
},
{
"Name": "UncategorizedAssetAccountId",
"Value": "125"
},
{
"Name": "UncategorizedIncomeAccountId",
"Value": "123"
},
{
"Name": "UncategorizedExpenseAccountId",
"Value": "124"
},
{
"Name": "SFCEnabled",
"Value": "true"
},
{
"Name": "DataPartner",
"Value": "false"
},
{
"Name": "Vendor1099Enabled",
"Value": "true"
},
{
"Name": "TimeTrackingFeatureEnabled",
"Value": "true"
},
{
"Name": "FDPEnabled",
"Value": "false"
},
{
"Name": "ProjectsEnabled",
"Value": "true"
}
]
},

Problem when not using TLS1.2 because of in place update of 4.7.2

DiscoveryClient does not handle the TLS1.2 properly.
My project framework is on 4.7.1, and I have 4.7.2 installed on my computer. It works great.
Another developer does not have 4.7.2 so the TLS seems to be incorrect.

new OAuth2Client(clientId, clientSecret, redirectUrl, "sandbox").GetAuthorizationURL(scopes);

Actual

?client_id=ABC&response_type=code&scope=com.intuit.quickbooks.accounting&redirect_uri=http%3A%2F%2Flocalhost%3A27353%2Fcallback&state=DEF

Expected

https://appcenter.intuit.com/connect/oauth2?client_id=ABC&response_type=code&scope=com.intuit.quickbooks.accounting&redirect_uri=http%3A%2F%2Flocalhost%3A27353%2Fcallback&state=DEF

OR
throw an exception immediately instead of failing silently. Calling GetBearerTokenAsync will throw a null exception if the TLS is incorrect.

Workaround
Set the SecurityProtocol

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

Question: How to build?

I have question. How do you build this solution? Are there instructions somewhere on how to build it? I downloaded the source and can't build it in VS2017 because of multiple circular references. For example Ipp.Rety references Ipp.Core and Ipp.Core references Ipp.Retry and many others like that. What am I missing?

Error upgrading 6.0.0 to 7.2.1 - There was an error reflecting type 'Intuit.Ipp.Data.Invoice'.

  • We did an upgrade to v7.2.1 and suddenly an exception is thrown. Is this a known issue ?

Using Invoice invoice = new Invoice();
Error : There was an error reflecting type 'Intuit.Ipp.Data.Invoice'.

at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportElement(TypeModel model, XmlRootAttribute root, String defaultNamespace, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type type, XmlRootAttribute root, String defaultNamespace)
at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
at Intuit.Ipp.Utility.XmlObjectSerializer.Serialize(Object entity)

Cannot instantiate ServiceContext in .NET Core

OAuth2RequestValidator oauthValidator = new OAuth2RequestValidator(systemSettings.AccessToken);
ServiceContext serviceContext = new ServiceContext(systemSettings.RealmId, IntuitServicesType.QBO, oauthValidator);

thows:

Could not load file or assembly 'System.Configuration.ConfigurationManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.

StackTrace:

at Intuit.Ipp.Core.Configuration.LocalConfigReader.ReadConfiguration()
at Intuit.Ipp.Core.ServiceContext..ctor()
at Intuit.Ipp.Core.ServiceContext..ctor(String realmId, IntuitServicesType serviceType, IRequestValidator requestValidator)
at PiMarketing.Controllers.CampaignsController.d__17.MoveNext() in C:\Dev2\Pi_Marketing\PiMarketing\PiMarketing\Controllers\CampaignsController.cs:line 576

Its looking for the old ConfigurationManager that doesn't exist in .NET core

Method not found: 'System.Net.HttpWebRequest Intuit.Ipp.Core.Rest.IRestHandler.PrepareRequest(Intuit.Ipp.Core.Rest.RequestParameters, System.Object, System.String)'.

We've discovered this very unusual issue using version 5.5 of this project from nuget.

The following code works locally:

            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; //Add this just to be sure to use TLS1.2 
            realmId = Session["realm"].ToString();
            accessToken = Session["accessToken"].ToString();
            accessTokenSecret = Session["accessTokenSecret"].ToString();
            consumerKey = ConfigurationManager.AppSettings["consumerKey"].ToString();
            consumerSecret = ConfigurationManager.AppSettings["consumerSecret"].ToString();
            dataSourcetype = Session["dataSource"].ToString().ToLower();

            try
            {
                var intuitServicesType = new IntuitServicesType();
                        intuitServicesType = IntuitServicesType.QBO;

                var oauthValidator = new OAuthRequestValidator(accessToken, accessTokenSecret, consumerKey, consumerSecret);
                var context = new ServiceContext(realmId, intuitServicesType, oauthValidator);

                context.IppConfiguration.BaseUrl.Qbo = _qboBaseURL;
                
                var dataService = new DataService(context);

                var company = new Company();
                var cmps = dataService.FindAll(company);

When deploying the code to Windows 2012 R2 standard with Framework 4.7.1 installed, the last line var cmps = dataService.FindAll(company);

Throws the following error:
System.MissingMethodException: Method not found: 'System.Net.HttpWebRequest Intuit.Ipp.Core.Rest.IRestHandler.PrepareRequest(Intuit.Ipp.Core.Rest.RequestParameters, System.Object, System.String)'. at Intuit.Ipp.DataService.DataService.FindAll[T](T entity, Int32 startPosition, Int32 maxResults)

The web app is published to a file directory and has been deployed and tested in both debug and release mode.

The web app targets 4.7.1 (in [Project] > Properties > Application).

Verified that Intuit.Ipp.Core.dll is in the /bin directory and is version 5.5.0.0

LineDetailTypeEnum.SalesItemLineDetail behavior changed

I just updated from the 4.x SDK to the 5.6 SDK package and found some changed behavior that is causing us problems.

We pull down invoices using the QueryService. Once we have an invoice, we loop through the line items, looking for only those that have a DetailType equal to LineDetailTypeEnum.SalesItemLineDetail. The problem occurs when a line item has no Product/Service assigned to it. In the 4.x SDK, the line item's DetailType is set as DescriptionOnly. In the 5.6 SDK, the DetailType is SalesItemLineDetail. I believe the previous behavior is correct.

Not only does the new SDK assign the DetailType incorrectly, but the ItemRef property also seems to be incorrectly assigned to the first/default value that our QB instance uses. It should have no ItemRef as far as I know, and certainly not the one being reported.

Intuit.Ipp.Retry dll not copied to output bin in 5.2.0

Hi - since I upgraded the Nuget package to 5.2, I found that Intuit.Ipp.Retry.dll was not being copied along to the output exe folder of my project, and so I consistently get a runtime failure on running a report (ReportService.ExecuteReport, say).

System.IO.FileNotFoundException: Could not load file or assembly 'Intuit.Ipp.Retry, Version=5.1.2.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

It was OK up to now - have I missed something I'm supposed to be doing since the upgrade? Or is this some crazy Nuget thing?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.