Update payment in open-source QuickBooks PHP DevKit on GitHub - quickbooks

I am using the open-source QuickBooks PHP DevKit on GitHub. I am trying to update a payment. But I am getting an error "ERROR!2030: [Invalid ID, Id should be a valid number. Supplied value:{-17}]"
Code I had given is shown below
First added code for update function in Quickbooks/IPP/Service/Payment.php like below:
public function update($Context, $realm, $IDType, $Object)
{
return parent::_update($Context, $realm, QuickBooks_IPP_IDS::RESOURCE_PAYMENT, $Object, $IDType);
}
After that in the payment_update.php page, I added the code as given below:
$IPP->version(QuickBooks_IPP_IDS::VERSION_3);
$PaymentService = new QuickBooks_IPP_Service_Payment();
$payments = $PaymentService->query($Context, $realm, "SELECT * FROM Payment where Id='27'");
$Payment = $payments[0];
$Payment->setPaymentRefNum("5Update");
if ($resp = $PaymentService->update($Context, $realm, $Payment->getId(), $Payment))
{
print('Updated the item name to ' . $Payment->getTotalAmt());
}
else
{
print('ERROR!');
print($PaymentService->lastError($Context));
}
Do I need to add any other changes in the class file for updating a payment. Please advise how can I update payment & line.
Request:
POST https://quickbooks.api.intuit.com/v3/company/1214054285/payment HTTP/1.1
Content-Type: application/xml
Authorization: OAuth realm="", oauth_signature_method="HMAC-SHA1", oauth_signature="XXXX", oauth_nonce="zVYx5", oauth_timestamp="1402573818", oauth_token="XXXX", oauth_consumer_key="XXXXX", oauth_version="1.0"
Content-Length: 1023
<Payment xmlns="http://schema.intuit.com/finance/v3">
<Id>27</Id>
<SyncToken>1</SyncToken>
<MetaData xmlns="http://schema.intuit.com/finance/v3">
<CreateTime>2014-06-12T00:36:12-07:00</CreateTime>
<LastUpdatedTime>2014-06-12T00:37:44-07:00</LastUpdatedTime>
</MetaData>
<Line xmlns="http://schema.intuit.com/finance/v3">
<Amount>12.00</Amount>
<LinkedTxn xmlns="http://schema.intuit.com/finance/v3">
<TxnId>{-17}</TxnId>
<TxnType>Invoice</TxnType>
</LinkedTxn>
</Line>
<Line xmlns="http://schema.intuit.com/finance/v3">
<Amount>5.00</Amount>
<LinkedTxn xmlns="http://schema.intuit.com/finance/v3">
<TxnId>{-13}</TxnId>
<TxnType>Invoice</TxnType>
</LinkedTxn>
</Line>
<TxnDate>2014-05-11</TxnDate>
<CurrencyRef>USD</CurrencyRef>
<CustomerRef>12</CustomerRef>
<DepositToAccountRef>18</DepositToAccountRef>
<PaymentRefNum>5Update</PaymentRefNum>
<TotalAmt>17.00</TotalAmt>
<UnappliedAmt>0</UnappliedAmt>
<ProcessPayment>false</ProcessPayment>
</Payment>
Response:
HTTP/1.1 400 Bad Request
Date: Thu, 12 Jun 2014 11:49:09 GMT
Content-Type: application/xml
Content-Length: 285
intuit_tid: ae570ca6-4f46-4132-978d-f12f394c50d2
Content-Encoding: gzip
Via: 1.1 ipp-gateway-.net
Vary: Accept-Encoding
Connection: close

This was fixed in an update several months ago.
Please use the latest code from GitHub and you should be all set:
https://github.com/consolibyte/quickbooks-php

Related

Put method in asp.net mvc REST service

I put data to my api using the code below:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(Baseurl);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.PutAsJsonAsync($"/api/Home/UpdateEmpDetails/{id}", newEmployee).Result;
if (response.IsSuccessStatusCode)
{
//...
}
}
but I get the following error:
{StatusCode: 405, ReasonPhrase: 'Method Not Allowed', Version: 1.1, Content: System.Net.Http.StreamContent, Headers: { X-Powered-By-Plesk: PleskWin Connection: close Date: Thu, 05 Oct 2017 05:26:07 GMT Server: Microsoft-IIS/10.0 X-Powered-By: ASP.NET Content-Length: 1293 Allow: GET Allow: HEAD Allow: OPTIONS Allow: TRACE Content-Type: text/html }}
can anyone help me?
WebDAV module may cause 405 error, so make sure you have WebDAV module not installed. Check if it is installed from Control Panel > "Turn Windows Features On or Off". If you don’t need to use WebDAV then remove "WebDAV Publishing" to fix "405 method not allowed" issue.
Or you may it fix it for only this project by adding the following to web.config of your WebApi project:
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule"/> <!-- add to remove webdav -->
</modules>

HTTP/1.1 401 Unauthorized Asana API

PROBLEM: I cannot authorize my connection to ASANA.
Breaking my code to the simplist bits. I used: http://onlinecurl.com/ to mimic what I see at
https://asana.com/developers/documentation/getting-started/authentication#sts=API%20Keys
This is my command.
curl --user 'NWE2MDJqUloubnpCUjh0d3gxVmYydW5BeFlJUER0Smw6' https://app.asana.com/api/1.0/users/me
Original : 5a602jRZ.nzBR8twx1Vf2unAxYIPDtJl
I even used https://www.base64encode.org/ to make sure my base64 was correct, which it is.
Response Header
1 HTTP/1.1 401 Unauthorized
2 Server: nginx
3 Date: Sat, 25 Oct 2014 17:58:23 GMT
4 Content-Type: application/json; charset=UTF-8
5 Transfer-Encoding: chunked
6 Connection: keep-alive
7 X-Asana-Content-String-Length: 41
8 Pragma: no-cache
9 Set-Cookie: TooBusyRedirectCount=0
10 Cache-Control: no-store
11 X-Asana-Preferred-Release-Revision: 20141024_201328_7ebcb21240775f3d5e6038b42ade419530485b76
12 X-Robots-Tag: none
Response Body
1{"errors":[{"message":"Not Authorized"}]}
How can I connect to the service with my Authorization???
Since writing this I have reset my aPIKEY
You do not need to base64-encode the username yourself, curl will do that for you. Also, please be careful of sharing your API key on public forums; these are sensitive credentials that should be treated like usernames and passwords! If that is a real API key I advise you reset it immediately (which you can do through the UI where you discovered it).
There needs to be a content Header
Here is what I did in Google Scripts.
In the site : http://onlinecurl.com/
we would need an extra option in headers for content-type
function getTasksFromAsana() {
api_key = "XXXX";
workspace_id = "WORKSPACE-ID";
// set up HTTPS connection
uri = "https://app.asana.com/api/1.0/users/me";
// set up the request
req={};
req = {
"headers":{ 'content-type': 'application/json','authorization': 'Basic ' + api_key }
}
Logger.log('Get Tasks Asana');
var response = UrlFetchApp.fetch(uri,req);
Logger.log(response.getContentText());
}

Issue during migration from Google OAuth 1.0 to OAuth 2.0 - The oAuth client was disabled

I'm trying to follow the documentation "https://developers.google.com/accounts/docs/OAuth_ref" to migrate oAuth to oAuth2 but keep getting an error
In the "APIs & auth" - "Credentials" Section in our API developers console we have 1 Client ID for web application set up along with a number of service account client Ids.
The client Ids appear to be in a format xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com for each client ID that is set up.
If I use the exact Id for the 'client ID for web application' in the format [xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com] then I get an error
{
"error" : "invalid_client"
}
If I use the more generic client ID [ xxxxxxxxxxxx.apps.googleusercontent.com
] then I get the following error
{
"error" : "disabled_client",
"error_description" : "The OAuth client was disabled."
}
Here is my post request from Fiddler
POST https://accounts.google.com/o/oauth2/token HTTP/1.1
Authorization: OAuth realm="",oauth_consumer_key="<consumerKey>",oauth_token="<token>",oauth_timestamp="1400680750",oauth_nonce="6637551",oauth_signature_method="HMAC-SHA1",oauth_signature="I%2FCOsR1BrGQHnqTeyhX4GUrKrv8%3D"
Content-Type: application/x-www-form-urlencoded
Host: accounts.google.com
Content-Length: 151
Expect: 100-continue
Connection: Keep-Alive
grant_type=urn:ietf:params:oauth:grant-type:migration:oauth1&client_id=<clientID>.apps.googleusercontent.com&client_secret={<client_secret>}
Here is the base string I use for oauth_signature
POST&https://accounts.google.com/o/oauth2/token&client_id=<clientID>.apps.googleusercontent.com&client_secret=<clientSecret>&grant_type=urn:ietf:params:oauth:grant-type:migration:oauth1&oauth_consumer_key=<consumerKey>&oauth_nonce=2648138&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1400681371&oauth_token=<token>
Here is the response I get from Google
HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=utf-8
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Date: Wed, 21 May 2014 13:59:16 GMT
Content-Disposition: attachment; filename="json.txt"; filename*=UTF-8''json.txt
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Server: GSE
Alternate-Protocol: 443:quic
Transfer-Encoding: chunked
5b
{
"error" : "disabled_client",
"error_description" : "The OAuth client was disabled."
}
0
Any suggestions?
Here a related post: https://groups.google.com/forum/#!topic/google-analytics-data-export-api/yveoPwSVzCQ
As for Owen's suggestion, I am pretty sure the error is not related to oauth1 vs oauth2 client type validation but rather to the provided oauth2 credentials (client id and client secret).
It turns out that the POST body that I was sending to google was incorrect.
Originally I had sent
grant_type=urn:ietf:params:oauth:grant-type:migration:oauth1&client_id=<clientID>.apps.googleusercontent.com&client_secret={<client_secret>}
Note the { } around the client_secret. When I removed these then I no longer got the errors.
Now I can pass in the client_id in the format xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com and the client_secret without { } and I get a sucessful response.
The reason for the other error that I had been receiving was that the client id in the format xxxxxxxxxxxx.apps.googleusercontent.com was an old client_id that had been deleted and was no longer visible on the Google Developer console.

Post batch request with Breezejs

I've been trying to POST an entity using Breezejs and WebAPI OData Controllers.
Here are the configurations:
config.Routes.MapODataRoute(
routeName: "odata",
routePrefix: "odata",
model: model,
batchHandler: new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));
Where the model is very straight forward:
public class ServiceMetadata
{
public int ServiceMetadataId { get; set; }
public string ServiceName { get; set; }
public string Description { get; set; }
public ObjectState? State { get; set; }
public DateTime? LastUpdated { get; set; }
}
And it is mapped through the default:
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
The Client is also very simple taken using AngularJs and partially from the Todo example: http://www.breezejs.com/samples/todo-angular
breeze.config.initializeAdapterInstance("modelLibrary", "backingStore", true);
var serviceName = 'http://localhost:8081/odata/';
breeze.config.initializeAdapterInstances({ dataService: "OData" });
var manager = new breeze.EntityManager(serviceName);
manager.enableSaveQueuing(true);
The actual Posting is done using the default createEntity() method:
function createServiceMetadata(initialValues) {
return manager.createEntity('ServiceMetadata', initialValues);
}
And the whole thing looks like:
serviceMetadatas.createServiceMetadata({
ServiceName: $scope.newServiceName,
Description: $scope.newServiceDescription
});
serviceMetadatas.saveChanges();
However, the request is not being transferred to the correct controller (ServiceMetadatasController which inherits from EntitySetController), or any other controller for that matter.
The HTTP request looks like this:
POST http://localhost:8081/odata/$batch HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0
Accept: multipart/mixed
Accept-Language: he-IL,he;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DataServiceVersion: 2.0
Content-Type: multipart/mixed; charset=UTF-8;boundary=batch_4f09-d7cf-dd99
MaxDataServiceVersion: 2.0
Referer: http://localhost:9000/
Content-Length: 580
Origin: http://localhost:9000
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
--batch_4f09-d7cf-dd99
Content-Type: multipart/mixed; boundary=changeset_ca0c-06b7-ddbe
--changeset_ca0c-06b7-ddbe
Content-Type: application/http
Content-Transfer-Encoding: binary
POST ServiceMetadatas HTTP/1.1
Content-ID: 1
DataServiceVersion: 2.0
Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1
Content-Type: application/json;odata=verbose
MaxDataServiceVersion: 2.0
{"ServiceMetadataId":-1,"ServiceName":"sdf sdf","Description":"sd fgs df","LastUpdated":null}
--changeset_ca0c-06b7-ddbe--
--batch_4f09-d7cf-dd99--
And the response:
HTTP/1.1 202 Accepted
Cache-Control: no-cache
Pragma: no-cache
Content-Type: multipart/mixed; boundary=batchresponse_966d4460-e00e-4900-b1c9-85b17081cfac
Expires: -1
Server: Microsoft-IIS/8.0
Access-Control-Allow-Origin: http://localhost:9000
Access-Control-Allow-Credentials: true
DataServiceVersion: 2.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcVG9tZXJcRG9jdW1lbnRzXFZpc3VhbCBTdHVkaW8gMjAxMlxQcm9qZWN0c1xFYXN5Qml6eVxFYXN5Qml6eS5XZWJBUElcb2RhdGFcJGJhdGNo?=
X-Powered-By: ASP.NET
Date: Sun, 15 Sep 2013 14:32:39 GMT
Content-Length: 443
--batchresponse_966d4460-e00e-4900-b1c9-85b17081cfac
Content-Type: multipart/mixed; boundary=changesetresponse_44da5dcf-877d-4041-a82b-c51d06a4e9a4
--changesetresponse_44da5dcf-877d-4041-a82b-c51d06a4e9a4
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 406 Not Acceptable
Content-ID: 1
--changesetresponse_44da5dcf-877d-4041-a82b-c51d06a4e9a4--
--batchresponse_966d4460-e00e-4900-b1c9-85b17081cfac--
Any idea what the hack is going on?
B.T.W GET requests works great.
P.S.
After looking at couple of demos, I though the using BreezeJS will be straight forward considering WebApi and OData.
I must say it is Far from being easy to configure this JS library. I hope it will turn out to be hard-to-setup but easy-to-use.
Thanks.
#UPDATE See Javier's great answer!!
In after digging allllot on the breeze code, I came to realize that the problem is laying deep in the createChangeRequests() of breezejs, right here:
request.requestUri = entity.entityType.defaultResourceName;
Where for some reason the defaultResouceName, completely ignores the path to this entity.
Long story short, the following is a hack to resolve:
manager.metadataStore.getEntityType(ENTITY_TYPE).setProperties({defaultResourceName: THE_MISSING_PART_FROM_THE_URL + ENTITY_TYPE});
manager.createEntity(ENTITY_TYPE, values);
Not very nice, but still works!
New answer is .. use webApiOData data service instead of "OData":
breeze.config.initializeAdapterInstances({
dataService : 'webApiOData'
});
The problem is in the url of the inner request. The url needs to be relative to the host. Let's say your service is hosted in host/service (in our case, service will be the equivalent as the odata prefix), so normally you send requests like host/service/Customers or /service/Customers.
When you issue a batch request, the urls in the inner requests might be absolute or relative to the host. The problem is that in your request, the url is ServiceMetadatas which is relative to the service root, not the host.
Web API is interpreting the relative url as host/ServiceMetadatas instead of as host/service/ServiceMetadatas and that's what causes the error.
Based on your repro project, the following request works fine:
POST http://localhost:6974/odata/$batch HTTP/1.1
Host: localhost:6974
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0
Accept: multipart/mixed
Accept-Language: he-IL,he;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DataServiceVersion: 2.0
Content-Type: multipart/mixed; charset=UTF-8;boundary=batch_4f09-d7cf-dd99
MaxDataServiceVersion: 2.0
Referer: http://localhost:9000/
Content-Length: 565
Origin: http://localhost:9000
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
--batch_4f09-d7cf-dd99
Content-Type: multipart/mixed; boundary=changeset_ca0c-06b7-ddbe
--changeset_ca0c-06b7-ddbe
Content-Type: application/http
Content-Transfer-Encoding: binary
POST odata/ServiceMetadatas HTTP/1.1
Content-ID: 1
DataServiceVersion: 2.0
Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1
Content-Type: application/json;odata=verbose
MaxDataServiceVersion: 2.0
{"ServiceMetadataId":-1,"ServiceName":"sdf sdf","Description":"sd fgs df"}
--changeset_ca0c-06b7-ddbe--
--batch_4f09-d7cf-dd99--
The associated response is the following one:
HTTP/1.1 202 Accepted
Cache-Control: no-cache
Pragma: no-cache
Content-Type: multipart/mixed; boundary=batchresponse_6779b5e5-6e40-4363-9a98-5a33d062da28
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 2.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcamFjYWx2YXJcRG93bmxvYWRzXE9EYXRhQmF0Y2gtbWFzdGVyXENsZWFuV2ViQXBpUHJvamVjdFxvZGF0YVwkYmF0Y2g=?=
X-Powered-By: ASP.NET
Date: Tue, 17 Sep 2013 16:48:50 GMT
Content-Length: 872
--batchresponse_6779b5e5-6e40-4363-9a98-5a33d062da28
Content-Type: multipart/mixed; boundary=changesetresponse_b63ca946-ce66-43e6-a78f-d44a5b8f2d5c
--changesetresponse_b63ca946-ce66-43e6-a78f-d44a5b8f2d5c
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 201 Created
Location: http://localhost:6974/odata/ServiceMetadatas(-1)
Content-ID: 1
Content-Type: application/json; odata=verbose; charset=utf-8
DataServiceVersion: 2.0
{
"d":{
"__metadata":{
"id":"http://localhost:6974/odata/ServiceMetadatas(-1)","uri":"http://localhost:6974/odata/ServiceMetadatas(-1)","type":"CleanWebApiProject.Models.ServiceMetadata"
},"ServiceMetadataId":-1,"ServiceName":"sdf sdf","Description":"sd fgs df"
}
}
--changesetresponse_b63ca946-ce66-43e6-a78f-d44a5b8f2d5c--
--batchresponse_6779b5e5-6e40-4363-9a98-5a33d062da28--
The only change that I made in the controller is the following (and not related to batch):
public class ServiceMetadatasController : EntitySetController<ServiceMetadata, int>
{
protected override ServiceMetadata CreateEntity(ServiceMetadata entity)
{
return entity;
}
protected override int GetKey(ServiceMetadata entity)
{
return entity.ServiceMetadataId;
}
public override IQueryable<ServiceMetadata> Get()
{
return new List<ServiceMetadata>
{
new ServiceMetadata() {ServiceName = "Service1", Description = "Desc1"},
new ServiceMetadata() {ServiceName = "Service2", Description = "Desc1"}
}.AsQueryable();
}
}
I hope this solves your problem, also let me know if you are generating the url for the inner request manually or if it's breezejs doing it for you, so that I can follow up and make sure it gets fixed.
Not sure if this is your issue but Microsoft's ODataModelBuilder does not implement a complete OData model. In particular, it doesn't generate foreign key constraints. MS is aware of this and is planning to update it in a later release. Until then you are better off using WCF data services to create your OData endpoints.

Service Exception

I am trying to upload a video to youtube from an iPhone "installed application" with GData for ObjectiveC.
Currently I receive an error on my upload ticket: ServiceException - error code 500.
From the documentation I cannot figure out what this error means and what I am doing wrong:
500 (Internal error) - A 500 response code indicates that YouTube
experienced an error handling a request. You could retry the request
at a later time.
I received only this error for more then a week (so this is not a temporary outage) and I've tryied with different product registrations for the Youtube API.
Can anyone spot what I am doing wrong in my request ?
Below you can find the log from GData's GTMHttpDebugLogs:
uploadTicket:finishedWithEntry:error:
2012-10-18 17:13:26 +0000
Request: POST https://uploads.gdata.youtube.com/resumable/feeds/api/users/default/uploads
Request headers:
Accept: application/atom+xml, text/xml
Authorization: AuthSub token=<authorization subtoken refreshed every time>
Cache-Control: no-cache
Content-Length: 793
Content-Type: application/atom+xml; charset=utf-8
GData-Version: 2.0
Slug: video-filename.mp4
User-Agent: <bundle>/2.0.0 GData-ObjectiveC/1.12 iPhone/5.1 (gzip)
X-GData-Key: key=<my developer key
X-Upload-Content-Length: 4005670
X-Upload-Content-Type: video/mp4
Request body: (793 bytes)
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gml="http://www.opengis.net/gml" xmlns:app="http://www.w3.org/2007/app" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:media="http://search.yahoo.com/mrss/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:yt="http://gdata.youtube.com/schemas/2007"><yt:accessControl action="list"/><media:group><media:description>Video description here</media:description><media:keywords/><media:category scheme="http://gdata.youtube.com/schemas/2007/categories.cat">Music</media:category><media:title>Video title here</media:title></media:group></entry>
Response: status 500
Response headers:
Cache-Control: no-cache, no-store, must-revalidate
Content-Length: 171
Content-Type: application/vnd.google.gdata.error+xml
Date: Thu, 18 Oct 2012 17:13:19 GMT
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Pragma: no-cache
Server: HTTP Upload Server Built on Oct 3 2012 16:52:30 (1349308350)
X-GData-User-Country: US
X-GUploader-UploadID: <### I made this upload id anonymous ###>
Response body: (171 bytes)
<errors xmlns='http://schemas.google.com/g/2005'><error><domain>GData</domain><code>ServiceException</code><internalReason>Internal Error</internalReason></error></errors>
-----------------------------------------------------------
This is being caused by <yt:accessControl action="list"/> in your request, which isn't a valid value. It should be something like <yt:accessControl action='list' permission='denied'/>
That being said, the API should handle that gracefully and not return an internal server error. I'll file a bug with the relevant folks internally to fix that.

Resources