I'm working on integrating QuickBooks Desktop with a CakePHP 3.3 app using consolibyte's php dev kit (http://www.consolibyte.com/docs/index.php/PHP_DevKit_for_QuickBooks_-_Quick-Start / https://github.com/consolibyte/quickbooks-php). I was able to work through the quick start guide and add a customer from within my QuickbooksController.php
(removed that test add and now receive 'No Data Exchange Required' when updating through web connector -which is good). but now i'm trying to move that queuing of adding a customer to where it should be, in ClientsController.php
. I'm encountering a couple different errors depending on what i require_once
First Scenario:
To start, I just tried to copy QuickbooksController.php
so I require_once
'd everything the same as in there. This is why there are so many commented out lines. This resulted in trying to load the file /.php
. require_once(/var/www/html/pivot/vendor/quickbooks-php-master/QuickBooks/Driver/.php): failed to open stream: No such file or directory [ROOT/vendor/quickbooks-php-master/QuickBooks/Loader.php, line 56]
Second Scenario
I then figured I should only really need the Queue class, so that was the only class I require_once
'd. This resulted in the error Class 'QuickBooks_Loader' not found
Third Scenario
Next I included QuickBooks_Loader
as well as Queue. This resulted in the error Notice (8): Use of undefined constant QUICKBOOKS_BASEDIR - assumed 'QUICKBOOKS_BASEDIR' [ROOT/vendor/quickbooks-php-master/QuickBooks/Loader.php, line 56]
require_once(QUICKBOOKS_BASEDIR/QuickBooks/Driver/Factory.php) [function.require-once]: failed to open stream: No such file or directory [ROOT/vendor/quickbooks-php-master/QuickBooks/Loader.php, line 56]
Fatal error: require_once() [function.require]: Failed opening required 'QUICKBOOKS_BASEDIR/QuickBooks/Driver/Factory.php' (include_path='.:/usr/share/php') in /var/www/html/pivot/vendor/quickbooks-php-master/QuickBooks/Loader.php on line 56
I can post my QuickbooksController.php if it would be useful, but for now omitting for space since I'm getting no errors when updating with Web Connector. Here is my [updated] Clients Controller
ClientsController.php
<?php
namespace App\Controller;
require_once(ROOT . DS . 'vendor' . DS . 'quickbooks-php-master' . DS . 'QuickBooks.php');
use App\Controller\AppController;
use Cake\I18n\Time;
use Cake\Utility\Text;
use Cake\Mailer\MailerAwareTrait;
use Cake\Log\Log;
use Cake\Core\Configure;
use QuickBooks;
/**
* Clients Controller
*
* @property \App\Model\Table\ClientsTable $Clients
*/
class ClientsController extends AppController
{
use MailerAwareTrait;
//...skipping to add function
/**
* Add method
*
* @return void Redirects on successful add, renders view otherwise.
*/
public function add()
{
$this->viewBuilder()->layout('dialog'); // we're gonna be opening in dialog
$dsn = Configure::read('qbDsn');
$client = $this->Clients->newEntity();
if ($this->request->is('post')) {
$newClientData = $this->request->data(); // transfer post data to $newClientData so we can manipulate further
//data manipulation omitted
$client = $this->Clients->patchEntity($client, $newClientData);
if ($this->Clients->save($client)) {
// incorrect - need to use global namespace not App\Controller
//$queue = new QuickBooks_WebConnector_Queue($dsn);
// Updated - confirmed correct
$queue = new \QuickBooks_WebConnector_Queue($dsn)
$queue->enqueue(QUICKBOOKS_ADD_CUSTOMER, $client->id);
$this->Flash->success(__('The client has been saved.'));
return $this->redirect(['action' => 'view', $client->id]);
} else {
Log::write('debug', $client->errors());
$this->Flash->error(__('The client could not be saved. Please, try again.'));
//return $this->redirect(($this->referer()));
}
}
}
Complete QuickBooksController.php
<?php
namespace App\Controller;
require_once(ROOT . DS . 'vendor' . DS . 'quickbooks-php-master' . DS . 'QuickBooks.php');
require_once(ROOT . DS . 'vendor' . DS . 'quickbooks-php-master' . DS . 'QuickBooks' . DS . 'Utilities.php');
require_once(ROOT . DS . 'vendor' . DS . 'quickbooks-php-master' . DS . 'QuickBooks' . DS . 'WebConnector' . DS . 'Server.php');
//require_once(ROOT . DS . 'vendor' . DS . 'quickbooks-php-master' . DS . 'QuickBooks' . DS . 'WebConnector' . DS . 'Queue.php');
require_once(ROOT . DS . 'vendor' . DS . 'quickbooks-php-master' . DS . 'QuickBooks' . DS . 'WebConnector' . DS . 'Handlers.php');
//require_once(ROOT . DS . 'vendor' . DS . 'quickbooks-php-master' . DS . 'QuickBooks' . DS . 'WebConnector' . DS . 'Functions.php');
use QuickBooks;
use App\Controller\AppController;
use Cake\Log\Log;
use QuickBooks_WebConnector_Server;
use QuickBooks_Utilities;
//use QuickBooks_WebConnector_Queue;
use QuickBooks_WebConnector_Handlers;
//use QuickBooks_WebConnector_Functions;
//use QuickBooks_WebConnector_QWC;
/**
* Quickbooks Controller
*
* @property \App\Model\Table\QuickbooksTable $Quickbooks
*/
class QuickbooksController extends AppController
{
public function initialize()
{
parent::initialize();
$this->Auth->allow();
$dsn = 'mysqli://qb@192.168.16.243/pivot';
$qbwc_user = 'quickbooks';
$qbwc_pass = 'password';
if(!QuickBooks_Utilities::initialized($dsn)) {
QuickBooks_Utilities::initialize($dsn);
QuickBooks_Utilities::createUser($dsn, $qbwc_user, $qbwc_pass);
}
}
public function endpoint()
{
$this->viewBuilder()->layout('qb');
$this->response->type(['xml' => 'text/xml']);
$this->response->type('xml');
$map = array(
//QuickBooks_WebConnector_Functions::QUICKBOOKS_ADD_CUSTOMER => array( '_quickbooks_customer_add_request', '_quickbooks_customer_add_response' ),
QUICKBOOKS_ADD_CUSTOMER => array(array($this, '_quickbooks_customer_add_request'), array($this, '_quickbooks_customer_add_response' )),
//QUICKBOOKS_ADD_SALESRECEIPT => array( '_quickbooks_salesreceipt_add_request', '_quickbooks_salesreceipt_add_response' ),
//'*' => array( '_quickbooks_customer_add_request', '_quickbooks_customer_add_response' ),
// ... more action handlers here ...
);
// This is entirely optional, use it to trigger actions when an error is returned by QuickBooks
$errmap = array(
3070 => '_quickbooks_error_stringtoolong', // Whenever a string is too long to fit in a field, call this function: _quickbooks_error_stringtolong()
// 'CustomerAdd' => '_quickbooks_error_customeradd', // Whenever an error occurs while trying to perform an 'AddCustomer' action, call this function: _quickbooks_error_customeradd()
// '*' => '_quickbooks_error_catchall', // Using a key value of '*' will catch any errors which were not caught by another error handler
// ... more error handlers here ...
);
// An array of callback hooks
$hooks = array(
// There are many hooks defined which allow you to run your own functions/methods when certain events happen within the framework
QuickBooks_WebConnector_Handlers::HOOK_LOGINSUCCESS => '_quickbooks_hook_loginsuccess', // Run this function whenever a successful login occurs
);
// Logging level
//$log_level = QUICKBOOKS_LOG_NORMAL;
//$log_level = QUICKBOOKS_LOG_VERBOSE;
//$log_level = QUICKBOOKS_LOG_DEBUG;
$log_level = QUICKBOOKS_LOG_DEVELOP; // Use this level until you're sure everything works!!!
// What SOAP server you're using
//$soapserver = QUICKBOOKS_SOAPSERVER_PHP; // The PHP SOAP extension, see: www.php.net/soap
$soapserver = QUICKBOOKS_SOAPSERVER_BUILTIN; // A pure-PHP SOAP server (no PHP ext/soap extension required, also makes debugging easier)
$soap_options = array( // See http://www.php.net/soap
);
$handler_options = array(
//'authenticate' => ' *** YOU DO NOT NEED TO PROVIDE THIS CONFIGURATION VARIABLE TO USE THE DEFAULT AUTHENTICATION METHOD FOR THE DRIVER YOU'RE USING (I.E.: MYSQL) *** '
//'authenticate' => 'your_function_name_here',
//'authenticate' => array( 'YourClassName', 'YourStaticMethod' ),
'deny_concurrent_logins' => false,
'deny_reallyfast_logins' => false,
); // See the comments in the QuickBooks/Server/Handlers.php file
$driver_options = array( // See the comments in the QuickBooks/Driver/<YOUR DRIVER HERE>.php file ( i.e. 'Mysql.php', etc. )
//'max_log_history' => 1024, // Limit the number of quickbooks_log entries to 1024
//'max_queue_history' => 64, // Limit the number of *successfully processed* quickbooks_queue entries to 64
);
$callback_options = array();
$dsn = 'mysqli://qb@192.168.16.243/pivot';
//$queue = new QuickBooks_WebConnector_Queue($dsn);
//$testKey = 25215;
//$queue->enqueue(QUICKBOOKS_ADD_CUSTOMER, $testKey);
$Server = new QuickBooks_WebConnector_Server($dsn, $map, $errmap, $hooks, $log_level, $soapserver, QUICKBOOKS_WSDL, $soap_options, $handler_options, $driver_options, $callback_options);
$response = $Server->handle(true, true);
}
function _quickbooks_customer_add_request($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $version, $locale)
{
$this->loadModel('Clients');
$client = $this->Clients->get($ID);
// Create and return a qbXML request
$qbxml = '<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="2.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<CustomerAddRq requestID="' . $requestID . '">
<CustomerAdd>
<Name>' . $client->company_name . '</Name>
<CompanyName>' . $client->company_name . '</CompanyName>
<BillAddress>
<Addr1>' . $client->address . '</Addr1>
<City>' . $client->city . '</City>
<State>' . $client->state . '</State>
<PostalCode>' . $client->zip . '</PostalCode>
<Country>' . $client->country . '</Country>
</BillAddress>';
if (isset($client->mailing_address) && isset($client->mailing_city) &&
isset($client->mailing_state) && isset($client->mailing_zip) &&
isset($client->mailing_country)){
$qbxml .= '<ShipAddress>
<Addr1>' . $client->mailing_address . '</Addr1>
<City>' . $client->mailing_city . '</City>
<State>' . $client->mailing_state . '</State>
<PostalCode>' . $client->mailing_zip . '</PostalCode>
<Country>' . $client->mailing_country . '</Country>
</ShipAddress>';
}
if (isset($client->primary_phone)){
$qbxml .= '<Phone>' . $client->primary_phone . '</Phone>';
}
if (isset($client->secondary_phone)){
$qbxml .= '<AltPhone>' . $client->secondary_phone . '</AltPhone>';
}
if (isset($client->fax)){
$qbxml .= '<Fax>' . $client->fax . '</Fax>';
}
if (isset($client->email)){
$qbxml .= '<Email>' . $client->email . '</Email>';
}
$qbxml .= '</CustomerAdd></CustomerAddRq></QBXMLMsgsRq></QBXML>';
return $qbxml;
}
function _quickbooks_customer_add_response($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents)
{
$this->loadModel('Clients');
$client = $this->Clients->get($ID);
$data = [
'qb_list_id' => $idents['ListID']
];
$client = $this->Clients->patchEntity($client, $data);
if (!$this->Clients->save($client)){
Log::write('debug', 'failed updating client qb_list_id in qb response');
Log::write('debug', $client->errors());
}
}
public function isAuthorized($user)
{
return true;
}
}
?>
Namespace error after only require_once
'ing QuickBooks.php as per Keith's suggestion (but not using global namespace)
2016-11-02 09:50:16 Error: [Error] Class 'App\Controller\QuickBooks_WebConnector_Queue' not found
Request URL: /clients/add.json
Referer URL: http://pivotstaging.efs.net/landings/admin
Client IP: 192.168.16.172
Stack Trace:
#0 [internal function]: App\Controller\ClientsController->add()
#1 /var/www/html/pivot/vendor/cakephp/cakephp/src/Controller/Controller.php(435): call_user_func_array(Array, Array)
#2 /var/www/html/pivot/vendor/cakephp/cakephp/src/Http/ActionDispatcher.php(122): Cake\Controller\Controller->invokeAction()
#3 /var/www/html/pivot/vendor/cakephp/cakephp/src/Http/ActionDispatcher.php(96): Cake\Http\ActionDispatcher->_invoke(Object(App\Controller\ClientsController))
#4 /var/www/html/pivot/vendor/cakephp/cakephp/src/Routing/Dispatcher.php(60): Cake\Http\ActionDispatcher->dispatch(Object(Cake\Network\Request), Object(Cake\Network\Response))
#5 /var/www/html/pivot/webroot/index.php(36): Cake\Routing\Dispatcher->dispatch(Object(Cake\Network\Request), Object(Cake\Network\Response))
#6 {main}
Most recent error
2016-11-03 07:47:39 Warning: Warning (2): require_once(/var/www/html/pivot/vendor/quickbooks-php-master/QuickBooks/Driver/.php): failed to open stream: No such file or directory in [/var/www/html/pivot/vendor/quickbooks-php-master/QuickBooks/Loader.php, line 56]
Request URL: /clients/add.json
Referer URL: http://pivotstaging.efs.net/landings/admin
Client IP: 192.168.16.172
Trace:
Cake\Error\BaseErrorHandler::handleError() - CORE/src/Error/BaseErrorHandler.php, line 146
require_once - ROOT/vendor/quickbooks-php-master/QuickBooks/Loader.php, line 56
QuickBooks_Loader::load() - ROOT/vendor/quickbooks-php-master/QuickBooks/Loader.php, line 56
QuickBooks_Loader::__autoload() - ROOT/vendor/quickbooks-php-master/QuickBooks/Loader.php, line 104
spl_autoload_call - [internal], line ??
class_exists - [internal], line ??
QuickBooks_Driver_Factory::create() - ROOT/vendor/quickbooks-php-master/QuickBooks/Driver/Factory.php, line 95
QuickBooks_WebConnector_Queue::__construct() - ROOT/vendor/quickbooks-php-master/QuickBooks/WebConnector/Queue.php, line 73
App\Controller\ClientsController::add() - APP/Controller/ClientsController.php, line 271
Cake\Controller\Controller::invokeAction() - CORE/src/Controller/Controller.php, line 435
Cake\Http\ActionDispatcher::_invoke() - CORE/src/Http/ActionDispatcher.php, line 122
Cake\Http\ActionDispatcher::dispatch() - CORE/src/Http/ActionDispatcher.php, line 96
Cake\Routing\Dispatcher::dispatch() - CORE/src/Routing/Dispatcher.php, line 60
[main] - ROOT/webroot/index.php, line 36
Any nudges in the right direction would be most appreciated :)