QBWC: "Index Out Of Range" in do_authenticate() - soap

I'm using QuickBooks WebConnector 2.2.0.71 and my WCF web service (on .NET 4.6.1). After pressing "Update selected" in WebConnector serverVersion and clientVersion requests successfully processed, but authenticate failed:
20170705.06:31:00 UTC : QBWebConnector.SOAPWebService.do_authenticate() : *** Calling authenticate() with following parameters:<userName="username"><password=<MaskedForSecurity>
20170705.06:31:00 UTC : QBWebConnector.SOAPWebService.do_authenticate() : QBWC1012: Authentication failed due to following error message.
Index Out Of Range.
More info:
StackTrace = в QBWebConnector.WebService.do_authenticate(String& ticket, String& companyFileName)
Source = QBWebConnector
Response of my WCF service (from WCF Test Client):
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body>
<authenticateResponse xmlns="http://developer.intuit.com/">
<authenticateResult xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:string>a3f10876-e027-419d-8dd8-3752a852ddae</a:string>
<a:string>nvu</a:string>
<a:string>3</a:string>
<a:string>60</a:string>
<a:string>60</a:string>
</authenticateResult>
</authenticateResponse>
</s:Body>
</s:Envelope>
Docs says "Your callback must return A string array with 4 possible elements. The first element contains either NONE or NVU (invalid user) or BUSY., or empty
string, or a string that is the QB company file name." but in samples first element is guid token, so I send array of 5 elements.
Same error occured when I send not an array, but int value, so I guess - maybe something wrong with my xml?

Page 21 of the QBWC Programmers Guide.
Your return to the authenticate call will be a string array with a maximum of four strings.
The first member of the array is a session token, which could be a GUID or anything else that you want to use to identify the session. This token will be returned by QBWC in subsequent callbacks in the session.
The second member of the string array can contain a variety of things.
a. If the username and password in the authenticate call is invalid, you would supply the value “nvu”.
b. If on the other hand the user data is valid but you have no work to do for that user, you would supply the value “none”.
c. If you do have work to do for the that user, you can supply the full pathname of the company to be used in the current update.
d. If you want to use whatever QuickBooks company is currently open at the client end, simply supply an empty string.
The optional third member of the string array contains the number of seconds to wait before the next update. You would use this to in effect tell that QBWC client not to bother you for a specified time.
The optional fourth member of the string array contains the number of seconds to be used as the MinimumRunEveryNSeconds time for your web service, which tells QBWC how frequently your web service needs to be contacted.
I am not sure why the Authenticate at the end of the doc is different than this.

Solved by adding [XmlSerializerFormat] to IService, so responce become
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<authenticateResponse xmlns="http://developer.intuit.com/">
<authenticateResult>
<string>d0297d33-859d-4259-a598-5fbf328bac3b</string>
<string>nvu</string>
<string>3</string>
<string>60</string>
</authenticateResult>
</authenticateResponse>
</s:Body>
</s:Envelope>

Related

Microsoft Ads 'AccountPerformanceReportRequest' data contract. The deserializer has no knowledge of any type that maps to this contract

I'm trying to use the Microsoft Bing Ads' Reporting API to gather ad performance data such as clicks, spend, etc. programmatically. Below, I describe the steps taken.
There are two issues -
1 - I have to request for user consent again and again as access token
is short lived and refreshed token also giving unauthenticated token
error.
2 - After following the steps I don't get the expected SOAP
Response. Instead I get below response.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:DeserializationFailed</faultcode>
<faultstring>The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter https://bingads.microsoft.com/Reporting/v13:ReportRequest. The InnerException message was 'Error in line 13 position 71. Element 'https://bingads.microsoft.com/Reporting/v13:ReportRequest' contains data of the ':AccountPerformanceReportRequest' data contract. The deserializer has no knowledge of any type that maps to this contract. Add the type corresponding to 'AccountPerformanceReportRequest' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.</faultstring>
</s:Fault>
</s:Body>
</s:Envelope>
I'm using Postman to test the service and my end goal is to use http to do the same in Mulesoft later. This is the URL I am using
https://reporting.api.bingads.microsoft.com/Api/Advertiser/Reporting/V13/ReportingService.svc
Authentication
I have followed their OAuth 2.0 Authentication Flow in that, I have:
Registered my Application (using the Developer Account)
Requested user consent (through the Ad account)
Generated the Access Token and Refresh Token Every time I hit the API.
**
I generate a new Access Token by requesting user consent again and again as refreshing
token is also not working.
**
Making the Request
The documentation describes a Reporting Service Operation which follows an asynchronous approach. First we need to use SubmitGenerateReport to make a request to the Reporting Service. This returns a ResponseRequestId which we can then use to repeatedly poll the service using PollGenerateReport till we get the requested report in response.
SubmitGenerateReport
SubmitGenerateReport has to be in SOAP XML Format as stated here. Following is the document I generated for my use case looking at the provided example in the documentation. Action I am passing as header attribute - SOAPAction:SubmitGenerateReport
<x:Envelope
xmlns:x="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:v="https://bingads.microsoft.com/Reporting/v13"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<x:Header>
<v:AuthenticationToken>****</v:AuthenticationToken>
<v:CustomerAccountId>****</v:CustomerAccountId>
<v:CustomerId>****</v:CustomerId>
<v:DeveloperToken>****</v:DeveloperToken>
</x:Header>
<x:Body>
<v:SubmitGenerateReportRequest>
<v:ReportRequest i:type="AccountPerformanceReportRequest">
<v:Format>Csv</v:Format>
<v:ReportName>AccountPerformanceReportRequest</v:ReportName>
<v:Aggregation>Summary</v:Aggregation>
</v:ReportRequest>
</v:SubmitGenerateReportRequest>
</x:Body>
</x:Envelope>
I even tried passing all the input variables, scope, time etc but getting some error again. I understand error clearly tells me where the error is but the report types I am using are given in Microsoft documentations.
Any help and suggestion would be really helpful.
1. I have to request for user consent again and again as access token is short lived and refreshed token also giving unauthenticated token error.
I would like to point you to these tutorial, as reference for my code below.
https://learn.microsoft.com/en-us/advertising/guides/get-started?view=bingads-13
https://learn.microsoft.com/en-us/advertising/guides/authentication-oauth-quick-start?view=bingads-13
In the first step, you fetch code, for this you need browser verification.
$clientId = '...'
Start-Process "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=$clientId&scope=openid%20profile%20https://ads.microsoft.com/msads.manage%20offline_access&response_type=code&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient&state=ClientStateGoesHere&prompt=login"
$code = 'https://login.microsoftonline.com/common/oauth2/nativeclient?code=<code>&state=ClientStateGoesHere'
$code = $code -match 'code=(.*)\&'
$code = $Matches[1]
Now, using this code, you get accessToken/refreshToken.
$response = Invoke-WebRequest https://login.microsoftonline.com/common/oauth2/v2.0/token -ContentType application/x-www-form-urlencoded -Method POST -Body "client_id=$clientId&scope=https://ads.microsoft.com/msads.manage%20offline_access&code=$code&grant_type=authorization_code&redirect_uri=https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fnativeclient"
$oauthTokens = ($response.Content | ConvertFrom-Json)
Since, this access token $oauthTokens.access_token will expire after one hour, use the refresh token to get new access and refresh tokens. This process you need to do periodically, say on 1/2 hourly basis.
Process to refresh is the following. This does not require you to login.
$response = Invoke-WebRequest https://login.microsoftonline.com/common/oauth2/v2.0/token -ContentType application/x-www-form-urlencoded -Method POST -Body "client_id=$clientId&scope=https://ads.microsoft.com/msads.manage%20offline_access&code=$code&grant_type=refresh_token&refresh_token=$($oauthTokens.refresh_token)"
$oauthTokens = ($response.Content | ConvertFrom-Json)
PS, I'm unclear if we could refresh infinitely or whether it is bound to a day. I verified that an expired accessToken could be renewed via refreshToken via this method after 1.5 hours - no need of generating code again via relogin.
2. After following the steps I don't get the expected SOAP Response. Instead I get below response
Thank you for providing the detailed soap xmls. I tried the same on my test account and able to repro exact same error message.
Here's the udpated SOAP xml request I used to get it to work.
<s:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header xmlns="https://bingads.microsoft.com/Reporting/v13">
<AuthenticationToken i:nil="false">here goes token</AuthenticationToken>
<CustomerAccountId i:nil="false">176045209</CustomerAccountId>
<CustomerId i:nil="false">169549046</CustomerId>
<DeveloperToken i:nil="false">here goes dev Token</DeveloperToken>
</s:Header>
<s:Body>
<SubmitGenerateReportRequest xmlns="https://bingads.microsoft.com/Reporting/v13">
<ReportRequest i:nil="false" i:type="AccountPerformanceReportRequest">
<Format i:nil="false">Csv</Format>
<ReportName i:nil="false">reportName1</ReportName>
<!--These fields are applicable if the derived type attribute is set to AccountPerformanceReportRequest-->
<Aggregation>Summary</Aggregation>
<Columns i:nil="false">
<AccountPerformanceReportColumn>Impressions</AccountPerformanceReportColumn>
<AccountPerformanceReportColumn>Revenue</AccountPerformanceReportColumn>
<AccountPerformanceReportColumn>AccountName</AccountPerformanceReportColumn>
</Columns>
<Scope i:nil="false">
<AccountIds i:nil="false" xmlns:a1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a1:long>176045209</a1:long>
</AccountIds>
</Scope>
<Time i:nil="false">
<CustomDateRangeEnd i:nil="false">
<Day>22</Day>
<Month>07</Month>
<Year>2022</Year>
</CustomDateRangeEnd>
<CustomDateRangeStart i:nil="false">
<Day>01</Day>
<Month>07</Month>
<Year>2022</Year>
</CustomDateRangeStart>
</Time>
</ReportRequest>
</SubmitGenerateReportRequest>
</s:Body>
</s:Envelope>
Here's the postman result.
PS, I received error, when some fields were missing. I did not use xml namespaces.
Hope this helps.

How can I pass a parameter from XML Response tag in a new GET XML Request in Soap UI?

I have tried to find a solution in this community in different threads but yet to find one that I am looking for.
I am using SoapUI version 5.3.0 My Application have a couple of RESTful APIs. Initially I am sending json request to a WebService and getting back the following XML Response:
<StartDataExtractResult xmlns="http://schemas.datacontract.org/2004/07/AriaTechCore" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<StatusCode>1</StatusCode>
<StatusText>success</StatusText>
<RequestNumber>397</RequestNumber>
</StartDataExtractResult>
As soon as RequestNumber tag is generated. I have to access to 2 more XML EndPoints (where the value of RequestNumber is appended) to know the Status as below:
A. http://quickextract.quickaudit.in/webs/quickextract.svc/GetExtractionDetails/396
B.
http://quickextract.quickaudit.in/webs/quickextract.svc/GetRequestStatus/396
As of now, I have created the 2 seperateTestSteps for the above mentioned XML Endpoints:
A. http://quickextract.quickaudit.in/webs/quickextract.svc/GetExtractionDetails/
B. http://quickextract.quickaudit.in/webs/quickextract.svc/GetRequestStatus/
Now I need to append the value within tag in the GET Request to get back a response from the WebServices.
Update:
I have created a 'Property Transfer' at Testsuite level as "TSreqNum". This 'Property Transfer' is getting updated as per the initial Response. But I am not sure how would I append "TSreqNum" to construct the complete GET Request as:
http://quickextract.quickaudit.in/webs/quickextract.svc/GetExtractionDetails/TSreqNum
Can anyone help me out please?
You can use the property within the URL of the GET request:
http://host:port/path/${#TestSuite#TSreqNum}
The URL gets updated with the property value.

How to get the ItemId of save-to-sent copy when sending mail via EWS

The EWS documentation says that to send a message and save a copy to the Sent Items folder, you should use the CreateItem operation with a MessageDisposition value of SendAndSaveCopy.
<m:CreateItem MessageDisposition="SendAndSaveCopy">
<m:SavedItemFolderId>
<t:DistinguishedFolderId Id="sentitems" />
</m:SavedItemFolderId>
<m:Items>
<t:Message>
<t:Subject>Company Soccer Team</t:Subject>
<t:Body BodyType="HTML">Are you interested in joining?</t:Body>
<t:ToRecipients>
<t:Mailbox>
<t:EmailAddress>sadie#contoso.com </t:EmailAddress>
</t:Mailbox>
</t:ToRecipients>
</t:Message>
</m:Items>
</m:CreateItem>
On success, "the server responds to the CreateItem request with a CreateItemResponse message that includes a ResponseCode value of NoError, which indicates that the email was created successfully, and the ItemId of the newly created message."
Using EWS against Office 365, this works almost successfully. The message is sent, the copy is saved to Sent Items... but the ItemId of the saved copy is not returned in the response:
<m:CreateItemResponse>
<m:ResponseMessages>
<m:CreateItemResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:Items />
</m:CreateItemResponseMessage>
</m:ResponseMessages>
</m:CreateItemResponse>
Is there a way to direct the EWS server to actually return the ItemId of the saved copy? Alternatively, what's the preferred mechanism for locating the saved copy once the send completes?
Evidently the documentation is either wrong or inapplicable. This MSDN blog post matches my experience: no ItemId is returned from a SendAndSaveCopy CreateItem request. It suggests the following:
Simply stamp your e-mail message with a custom extended property when you create the message, and then use that extended property to find the message in the Sent Items folder after it has been sent.
A commenter suggests that rather than using an expensive FindItems-with-SearchFilter call to locate the custom-property-stamped saved copy, you should instead do the following:
1. Set your extended prop.
2. Do a FindItem with NO restriction against the sent items folder, SORTED by creation date descending with a indexed page view of about 5. Include your extended prop in the PropertySet.
3. Iterate across the results looking for your extended prop.

EWS FindItem CalendarView weird handling of MaxEntriesReturned

This is my SOAP FindItem call to retrieve calendar items:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:mes="http://schemas.microsoft.com/exchange/services/2006/messages">
<soapenv:Header>
<typ:RequestServerVersion Version="Exchange2007_SP1"/>
<typ:MailboxCulture>en-US</typ:MailboxCulture>
<typ:TimeZoneContext>
<typ:TimeZoneDefinition Id="W. Europe Standard Time"/>
</typ:TimeZoneContext>
</soapenv:Header>
<soapenv:Body>
<mes:FindItem Traversal="Shallow">
<mes:ItemShape>
<typ:BaseShape>AllProperties</typ:BaseShape>
<typ:AdditionalProperties>
<typ:FieldURI FieldURI="item:LastModifiedTime" />
</typ:AdditionalProperties>
</mes:ItemShape>
<mes:CalendarView MaxEntriesReturned="1000" StartDate="2015-02-18T00:00:00Z" EndDate="2015-12-05T23:59:59Z"/>
<mes:ParentFolderIds>
<typ:DistinguishedFolderId Id="calendar">
<typ:Mailbox>
<typ:EmailAddress>sddress#server.nl</typ:EmailAddress>
</typ:Mailbox>
</typ:DistinguishedFolderId>
</mes:ParentFolderIds>
</mes:FindItem>
</soapenv:Body>
</soapenv:Envelope>
The MaxEntriesReturned in the optional element
<mes:CalendarView MaxEntriesReturned="1000" StartDate="2015-02-18T00:00:00Z" EndDate="2015-12-05T23:59:59Z"/>
is supposed to mean the maximum number of results to return in the FindItem response
However:
1) The results easily returns more items:
<m:FindItemResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:FindItemResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:RootFolder TotalItemsInView="2516" IncludesLastItemInRange="false">
<t:Items>
<t:CalendarItem>
(and note the IncludesLastItemInRange="false", so there are more items. Then why return 2516?)
2) If I leave MaxEntriesReturned="1000" out of the query, I get a ErrorServerBusy response code with text The server cannot service this request right now. Try again later.
This may have to do with Exchange Server throttling policies, but that link says:
The EWSFindCountLimit parameter specifies the maximum result size of FindItem or FindFolder calls that can exist in memory on the Client Access server at the same time for this user in this current process
so I expect to get the ErrorExceededFindCountLimit response code with text You have exceeded the maximum number of objects that can be returned for the find operation. Use paging to reduce the result size and try your request again.
The issues I have with these observations:
1) I specify MaxEntriesReturned to prevent being overwhelmed with data, yet I get much more than I ask for. (Fine with ice cream, but not here).
2) If I do indeed bump into a throttling policy I'd like a decent ErrorExceededFindCountLimit response that tells me what is going on, so that my code can suggest corrective measures; ErrorServerBusy can mean many things.
What can be done about both?
This is all testing against Release to Manufacturing (RTM) version of Exchange Server 2013:
<ServerVersionInfo MajorVersion="15" MinorVersion="0" MajorBuildNumber="516" MinorBuildNumber="29" Version="Exchange2013" .../>
The TotalItemsInView attribute in the FindItem response corresponds to the total number of items in the entire CalendarView. The resulting dataset will still be bound by the set MaxEntriesReturned if you take a look at the actual amount of items returned.
So for instance, if I set MaxEntriesReturned to 1 for a date range I know has 4 events total, I'll get back: <m:RootFolder TotalItemsInView="4" IncludesLastItemInRange="false”>. But in the response, only one CalendarItem is returned.
[Note added by OP] That solves Item 1) of the question (item 2 is in this answer)
The CalenderView isn't page-able eg have a look at https://msdn.microsoft.com/en-us/library/microsoft.exchange.webservices.data.calendarview_properties(v=exchg.80).aspx and you will see that there is no property that allows you to specify an offset (or index) value.
What you need to do is reduce the time window so you get less then 1000 items returned. Then page the timewindow manually yourself to get the full Appointment list you want.
Cheers
Glen
Not content with waiting for an answer, I kept digging and came across Throttling Policies and the EWSFindCountLimit.
This explains issue 2) (item 1 is in this answer)
The article says If the call has a RequestServerVersion that is earlier than Exchange2010, you will receive a failure response with an error code of ErrorServerBusy.
That was exactly what I was doing: <typ:RequestServerVersion Version="Exchange2007_SP1"/>. Changing it to <typ:RequestServerVersion Version="Exchange2010"/> returns:
<m:FindItemResponseMessage ResponseClass="Error">
<m:MessageText>You have exceeded the maximum number of objects that can be returned for the find operation. Use paging to reduce the result size and try your request again.</m:MessageText>
<m:ResponseCode>ErrorExceededFindCountLimit</m:ResponseCode>
<m:DescriptiveLinkKey>0</m:DescriptiveLinkKey>
<m:MessageXml>
<t:Value Name="PolicyLimit">1000</t:Value>
</m:MessageXml>
</m:FindItemResponseMessage>
... nicely telling me that the limit I broke was 1000.
The article concludes: the moral of the story is: Always use a paging mechanism when calling FindItem or FindFolder

Customer Address Field is Mandatory?

A client of our IA app just reported a slew of IDS synch error messages like:
Error updating customer in Intuit Data Services. Error message was: empty addresses not allowed party_id = 679598
I looked at your new online docs and see that the Object Reference indicates that the customer address is "mandatory". Is this something new? If so, since when? Customers have been synching successfully with empty addresses up to now, this change took us completely unaware (if indeed it is a change). Is there some way you can apprise us of upcoming changes so we can act proactively? Also, what exactly qualifies as an "empty" address? What fields exactly, at a minimum, need to be non-empty? For example, if "State" is filled in is that enough?
BTW, what is party_id and how can I use it to identify the customer object?
Thanks in advance.
It's not a required field to add/update a customer but if you are including the XML address fields tag in your request, then you must enter a value for it. If you don't want to update the address then leave it out.
thanks,
Jarred
Example:
<?xml version="1.0" encoding="UTF-16"?>
<Mod xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" RequestId="7699faaff20f4e16987e26bddbbf9461" xmlns="http://www.intuit.com/sb/cdm/v2">
<ExternalRealmId>156234822</ExternalRealmId>
<Object xsi:type="Customer">
<Id>43497400</Id>
<SyncToken>1</SyncToken>
<MetaData>
<CreatedBy>app</CreatedBy>
<CreatedById>1</CreatedById>
<CreateTime>2010-06-18T03:48:36</CreateTime>
<LastModifiedBy>app</LastModifiedBy>
<LastModifiedById>1</LastModifiedById>
<LastUpdatedTime>2010-06-18T03:48:36</LastUpdatedTime>
<MetaData>
<Synchronized>false</Synchronized>
<PartyReferenceId>51077676</PartyReferenceId>
<TypeOf>Person</TypeOf>
<Name>Jane Doe</Name>
<ShowAs>Jane</ShowAs>
</Object>
</Mod>