QBO API Add Payment error - php

I'm connecting to Quicbooks using IPP_V3 from my webserver.
I'm trying to implement the example_payment_add.php
I'm getting a Business validation error when adding payment by assigning it to an invoice.
I even changed the order in which the values are assigned as instructed in the below page:
https://developer.intuit.com/docs/0025_quickbooksapi/0050_data_services/030_entity_services_reference/payment
(Last point: The sequence in which the Lines are received is the sequence in which lines are preserved.)
Note: Just adding a payment to a customer, without assigning it to a customer, is working.
Error:
6000: [A business validation error has occurred while processing your request, Business Validation Error: Unexpected Internal Error. (-30035)]
Code:
require_once dirname(__FILE__) . '/config.php';
require_once dirname(__FILE__) . '/views/header.tpl.php';
?>
<pre>
<?php
// Set up the IPP instance
$IPP = new QuickBooks_IPP($dsn);
// Get our OAuth credentials from the database
$creds = $IntuitAnywhere->load($the_username, $the_tenant);
// Tell the framework to load some data from the OAuth store
$IPP->authMode(
QuickBooks_IPP::AUTHMODE_OAUTH,
$the_username,
$creds);
// Print the credentials we're using
//print_r($creds);
// This is our current realm
$realm = $creds['qb_realm'];
// Load the OAuth information from the database
if ($Context = $IPP->context())
{
// Set the IPP version to v3
$IPP->version(QuickBooks_IPP_IDS::VERSION_3);
$PaymentService = new QuickBooks_IPP_Service_Payment();
// Create payment object
$Payment = new QuickBooks_IPP_Object_Payment();
$Payment->setTxnDate('2014-04-04');
// Create line for payment (this details what it's applied to)
$Line = new QuickBooks_IPP_Object_Line();
$Line->setAmount(1);
// The line has a LinkedTxn node which links to the actual invoice
$LinkedTxn = new QuickBooks_IPP_Object_LinkedTxn();
$LinkedTxn->setTxnId('10001'); //real invoice number in quickbooks
$LinkedTxn->setTxnType('Invoice');
$Line->setLinkedTxn($LinkedTxn);
$Payment->addLine($Line);
$Payment->setCustomerRef('876');
$Payment->setPaymentRefNum('8762393');
$Payment->setTotalAmt(1);
// Send payment to QBO
if ($resp = $PaymentService->add($Context, $realm, $Payment))
{
print('Our new Payment ID is: [' . $resp . ']');
}
else
{
print($PaymentService->lastError());
}
/*
print('<br><br><br><br>');
print("\n\n\n\n\n\n\n\n");
print('Request [' . $IPP->lastRequest() . ']');
print("\n\n\n\n");
print('Response [' . $IPP->lastResponse() . ']');
print("\n\n\n\n\n\n\n\n\n");
*/
}
else
{
die('Unable to load a context...?');
}
?>
</pre>
<?php
require_once dirname(__FILE__) . '/views/footer.tpl.php';

SOLVED: Need to use Transaction Id of the Invoice instead of the Invoice Number.

This is almost certainly incorrect:
$LinkedTxn->setTxnId('10001'); //real invoice number in quickbooks
You should be using the Id value from the invoice in QuickBooks. The Id value is different from the user-visible Invoice reference # (the DocNumber field).
You need to use the Id value.
This also doesn't make a whole lot of sense:
$Line->setAmount(1);
...
$Payment->setTotalAmt(0.01);
How can the total payment amount be only 1 penny, and then you try to apply a full dollar to the invoice?

Using a httpSnooper tool(like fiddler) or by enabling the devkit logger, you should try to capture the raw request and response XML/JSON.
You can use the XML/JSON in ApiExplorer tool to debug this issue.
Otherwise, you can try to create a payment from QBO ui and retrieve the same using GetById endpoint. That way you can find out the correct structure of the payment object.
Hope it will useful.
Thanks

Related

How to Return List of Project Tasks in ActiveCollab

Sorry this may be a trivial question but I am new to PHP. In the documentation to retrieve project tasks, the following code is provided to connect to an Active Collab cloud account:
<?php
require_once '/path/to/vendor/autoload.php';
// Provide name of your company, name of the app that you are developing, your email address and password.
$authenticator = new \ActiveCollab\SDK\Authenticator\Cloud('ACME Inc', 'My Awesome Application', 'you#acmeinc.com', 'hard to guess, easy to remember');
// Show all Active Collab 5 and up account that this user has access to.
print_r($authenticator->getAccounts());
// Show user details (first name, last name and avatar URL).
print_r($authenticator->getUser());
// Issue a token for account #123456789.
$token = $authenticator->issueToken(123456789);
// Did we get it?
if ($token instanceof \ActiveCollab\SDK\TokenInterface) {
print $token->getUrl() . "\n";
print $token->getToken() . "\n";
} else {
print "Invalid response\n";
die();
}
This works fine. I can then create a client to make API calls:
$client = new \ActiveCollab\SDK\Client($token);
and get the list of tasks for a given project as shown in the documentation.
$client->get('projects/65/tasks'); // PHP object
My question is, what methods/attributes are available to get the list of tasks? I can print the object using print_r() (print will obviously not work), and what I really want is in the raw_response header. This is private however and I cannot access it. How do I actually get the list of tasks (ex: the raw_response either has a string or json object)?
Thanks in advance.
There are several methods to work with body:
$response = $client->get('projects/65/tasks');
// Will output raw JSON, as string.
$response->getBody();
// Will output parsed JSON, as associative array.
print_r($response->getJson());
For full list of available response methods, please check ResponseInterface.
If you wish to loop through tasks, use something like this:
$response = $client->get('projects/65/tasks');
$parsed_json = $response->getJson();
if (!empty($parsed_json['tasks'])) {
foreach ($parsed_json['tasks'] as $task) {
print $task['name'] . "\n"
}
}

What is a pagination cursor & how can I use it

I am trying to retrieve a list of customers using the square PHP SDK. If I leave the $cursor blank, I can see a list of all of my customer information. How do I use the pagination cursor to receive a customer by their name? Sample code below:
<?php
require_once(__DIR__ . '/vendor/autoload.php');
// Configure OAuth2 access token for authorization: oauth2
SquareConnect\Configuration::getDefaultConfiguration()->setAccessToken('YOUR_ACCESS_TOKEN');
$api_instance = new SquareConnect\Api\CustomersApi();
// string | A pagination cursor returned by a previous call to this endpoint.
//Provide this to retrieve the next set of results for your original query.
//See [Paginating results](#paginatingresults) for more information.
$cursor = "cursor_example";
try {
$result = $api_instance->listCustomers($cursor);
print_r($result);
} catch (Exception $e) {
echo 'Exception when calling CustomersApi->listCustomers: '
, $e->getMessage(), PHP_EOL;
}
?>
The pagination cursor does not allow you to query for customers by name. If you have more than one "page" of customer, then it allows for you to get more customers by providing a token representing the next page.
If you have enough customers to fill multiple pages, a cursor would be returned in the response.

Using Service Account to access Google Analytics API doesn't work

I'm trying to access my Google Analytics data using a service account. I've created one in the Developers Console and I've enabled the Google Analytics API in that same console, but somehow, I can't manage to pull data from the API.
I've used the script on this page.
My code is as follows:
<?php
$keyfile = 'google/key.p12';
// Initialise the Google Client object
$client = new Google_Client();
$client->setApplicationName('MyNAME');
$client->setAssertionCredentials(
new Google_AssertionCredentials(
'XXXX#developer.gserviceaccount.com', array('https://www.googleapis.com/auth/analytics.readonly'), file_get_contents($keyfile)
)
);
$client->setClientId('XXXX.apps.googleusercontent.com');
$client->setAccessType('offline_access');
$analytics = new Google_AnalyticsService($client);
$analytics_id = 'ga:UA-XXXXXX-1'; // http://productforums.google.com/forum/#!topic/analytics/dRuAr1K4waI
// get data for the last 2 weeks
$lastWeek = date('Y-m-d', strtotime('-2 week'));
$today = date('Y-m-d');
// Test connection
try {
$results = $analytics->data_ga->get($analytics_id, $lastWeek, $today, 'ga:visits');
echo '<b>Number of visits this week:</b> ';
echo $results['totalsForAllResults']['ga:visits'];
} catch (Exception $e) {
echo 'There was an error : - ' . $e->getMessage();
}
?>
Note: if it says "XXXX", that means I've removed part of the string for security purposes; the proper strings are in my actual script.
It should either display the number of users or a error, but I just get a blank screen. I'm sure the URL to the keyfile is correct.
Does anybody have suggestions on how to fix this? That would be much appreciated.
It looks like you are using your property Id (UA-XXXXX-1) in place of your view (profile) id. If you go to Google Analytics Query Explorer it makes it easy to see what your actual ga:XXXX view (profile) id is. Any given property can have multiple view's (profiles). This reference guide gives a good description of the parameters that this request requires.

How do I set the SalesTerm for a Customer with QuickBooks_IPP?

I'm successfully adding a Customer to QuickBooks using QuickBooks_IPP, but I'm having difficulty setting the sales term for the customer. I've looked through the documentation and cannot find examples of setting the SalesTerm.
I've added these lines to the example code, but does not throw an error and does not add the sales term.
$Term = new QuickBooks_IPP_Object_SalesTerm();
$Term->setSalesTermRef(2); //15 days
$Customer->setSalesTermRef($Term);
This is the full Customer add code:
// Set the IPP version to v3
$IPP->version(QuickBooks_IPP_IDS::VERSION_3);
$CustomerService = new QuickBooks_IPP_Service_Customer();
$Customer = new QuickBooks_IPP_Object_Customer();
$Customer->setTitle('Ms');
$Customer->setGivenName('Shannon');
$Customer->setMiddleName('B');
$Customer->setFamilyName('Palmer');
$Customer->setDisplayName('Shannon B Palmer ' . mt_rand(0, 1000));
//set days due
$Term = new QuickBooks_IPP_Object_SalesTerm();
$Term->setSalesTermRef(2);
$Customer->setSalesTermRef($Term);
// Phone #
$PrimaryPhone = new QuickBooks_IPP_Object_PrimaryPhone();
$PrimaryPhone->setFreeFormNumber('860-532-0089');
$Customer->setPrimaryPhone($PrimaryPhone);
// Mobile #
$Mobile = new QuickBooks_IPP_Object_Mobile();
$Mobile->setFreeFormNumber('860-532-0089');
$Customer->setMobile($Mobile);
// Fax #
$Fax = new QuickBooks_IPP_Object_Fax();
$Fax->setFreeFormNumber('860-532-0089');
$Customer->setFax($Fax);
// Bill address
$BillAddr = new QuickBooks_IPP_Object_BillAddr();
$BillAddr->setLine1('72 E Blue Grass Road');
$BillAddr->setLine2('Suite D');
$BillAddr->setCity('Mt Pleasant');
$BillAddr->setCountrySubDivisionCode('MI');
$BillAddr->setPostalCode('48858');
$Customer->setBillAddr($BillAddr);
// Email
$PrimaryEmailAddr = new QuickBooks_IPP_Object_PrimaryEmailAddr();
$PrimaryEmailAddr->setAddress('support#consolibyte.com');
$Customer->setPrimaryEmailAddr($PrimaryEmailAddr);
if ($resp = $CustomerService->add($Context, $realm, $Customer))
{
print('Our new customer ID is: [' . $resp . ']');
}
else
{
print($CustomerService->lastError($Context));
}
I can query for the Customer after the add but it does not return the SalesTerm as I would expect. Do I need the SalesTerm Service instead of the Object?
The only time you'd wrap something in an object like you're doing with QuickBooks_IPP_Object_SalesTerm is if it's actually a full nested node in the XML request.
i.e. if you saw this in Intuit's documentation:
<Customer>
...
<SalesTermRef>
<Id>...</Id>
... other nested tags inside here ...
</SalesTermRef>
...
</Customer>
Then you would have been on the right track.
But per Intuit's docs, this is only a normal non-nested node:
<SalesTermRef>4</SalesTermRef>
So just use the ->setSalesTermRef($val) method:
// Terms (e.g. Net 30, etc.)
$Customer->setSalesTermRef(4);
Sometimes the easiest way to see this stuff is to examine the XML output. Look at what you're sending with:
print($CustomerService->lastRequest());

Paypal Adaptive Payments works in sandbox mode but not production

I'm trying to use Paypal's adaptive payments API and having a tough time switching it to production. Everything works as expected on sandbox mode and I get a proper response, but when I switch to my live APP ID it doesn't work.
These are the configuration values I'm using for sandbox
PayPal URL : https://www.sandbox.paypal.com/webapps/adaptivepayment/flow/pay?paykey=[TOKEN_HERE]
Application ID : APP-80W284485P519543T
These values work for me in sandbox mode. But when I switch to the below production values, it stops working
PayPal URL : https://www.paypal.com/webapps/adaptivepayment/flow/pay?paykey=[TOKEN_HERE]
Application ID : [ACTUAL APP ID]
This is what I mean by stops working.
In production mode, the application gets the paykey
Appends it to the Paypal URL and then redirects it to their site
On site load, I get the following message
This transaction has already been approved. Please visit your PayPal Account Overview to see the details
The final URL it ends up on - https://ic.paypal.com/webapps/adaptivepayment/flow/payinit?execution=e6s1
Screenshot - http://screencast.com/t/28qJZ9CIk
There is also a 'Return' button there, and when I click on it I get taken to a different site each time (Looks like I get sent to random failUrls)
I've included the code I use below
$payRequest = new PayRequest();
$payRequest->actionType = "PAY";
$payRequest->cancelUrl = $cancelURL; //my success and fail urls
$payRequest->returnUrl = $returnURL;
$payRequest->clientDetails = new ClientDetailsType();
$payRequest->clientDetails->applicationId = $this->config['application_id'];
$payRequest->clientDetails->deviceId = $this->config['device_id'];
$payRequest->clientDetails->ipAddress = $this->CI->input->ip_address();
$payRequest->currencyCode = $currencyCode;
$payRequest->requestEnvelope = new RequestEnvelope();
$payRequest->requestEnvelope->errorLanguage = "en_US";
//I set the receiver and the amounts. I also define that these are digital goods payments
$receiver1 = new receiver();
$receiver1->email = $opts['receiver_email'];
$receiver1->amount = $opts['amount'];
$receiver1->paymentType = 'DIGITALGOODS';
$payRequest->receiverList = new ReceiverList();
$payRequest->receiverList = array($receiver1);
//Then I make the call
$ap = new AdaptivePayments();
$response = $ap->Pay($payRequest);
if(strtoupper($ap->isSuccess) == 'FAILURE') {
log_message('error', "PAYMENT_FAIL : " . print_r($ap->getLastError(), true));
return false;
} else {
if($response->paymentExecStatus == "COMPLETED") {
header("Location: " . $this->config['success_url']);
exit;
} else {
$token = $response->payKey;
$payPalURL = $this->config['paypal_redirect_url'] . 'paykey='.$token;
header("Location: ".$payPalURL);
exit;
}
}
This is code taken from their sample implementation, so not really sure what's going wrong here. Other information that might be relevant
I'm using adaptive payments to make sure that the sender and receiver
actually did the transaction
I have set the payment type as 'DIGITAL GOODS'
EDIT
I've included a sample URL with the pay key attached
https://www.paypal.com/webapps/adaptivepayment/flow/pay?paykey=AP-0H388650F08226841
I found the issue that was giving me all of this grief.
The Paypal SDK uses a couple of constants which are defined in /sdk/lib/Config/paypal_sdk_clientproperties
The constants contain the username, password, application_id the API url and a few others. These are used directly in the file /sdk/lib/CallerServices,php. So contrary to what you would expect in an API, these values are not injected in the setup phase so if you don't notice that file and change the values, the above code will not work.
To fix the issue, simply update the values defined in the file and you should be good to go.

Categories