I have been trying to integrate a PHP based solution with QuickBooks Enterprise edition. I use QuickBooks PHP Dev Kit (http://consolibyte.com/quickbooks-open-source/) to connect the application to sync multiple modules bidirectionally.
The first module (QuickBooks to VtigerCRM) with multiple records are getting synced perfectly. When I try with my next module, only few records are getting synced and throws a error IteratorID is not valid. Then, I tried sending the params with new IteratorID in XML with no success.
20180821.05:13:03 UTC : QBWebConnector.SOAPWebService.do_receiveResponseXML() : hresult=""
20180821.05:13:03 UTC : QBWebConnector.SOAPWebService.do_receiveResponseXML() : message=""
20180821.05:13:03 UTC : QBWebConnector.SOAPWebService.do_receiveResponseXML() : Received from receiveResponseXML() following parameters:
20180821.05:13:03 UTC : QBWebConnector.SOAPWebService.do_receiveResponseXML() : more="-1">
20180821.05:13:03 UTC : QBWebConnector.SOAPWebService.do_getLastError() : * Calling getLastError() with following parameter:
20180821.05:13:03 UTC : QBWebConnector.SOAPWebService.do_getLastError() : wcTicket="403c7856-d600-c664-5187-3d9e2036c0cc"
20180821.05:13:04 UTC : QBWebConnector.SOAPWebService.do_getLastError() : Received from getLastError() following parameter:
20180821.05:13:04 UTC : QBWebConnector.SOAPWebService.do_getLastError() : errorMsg="3391: The iteratorID "{80c35df0-ae92-43a3-af49-946da1c306fb}" is not valid."
20180821.05:13:04 UTC : QBWebConnector.SOAPWebService.do_getLastError() : Received error from application: 3391: The iteratorID "{80c35df0-ae92-43a3-af49-946da1c306fb}" is not valid.
20180821.05:13:04 UTC : QBWebConnector.CompanyFileLock.Send_CompanyQueryRqXML() : XML dump follows: -
<?xml version="1.0"?><?qbxml version="13.0"?><QBXML><QBXMLMsgsRq onError="stopOnError"><CompanyQueryRq requestID="1"><OwnerID>{90A44FB7-33D9-4815-AC85-AC86A7E7D1EB}</OwnerID></CompanyQueryRq></QBXMLMsgsRq></QBXML>
I have added the code of the Helper.php
<?php
// Support URL
if (!empty($_GET['support']))
{
header('Location: http://www.consolibyte.com/');
exit;
}
// We need to make sure the correct timezone is set, or some PHP installations will complain
if (function_exists('date_default_timezone_set'))
{
// * MAKE SURE YOU SET THIS TO THE CORRECT TIMEZONE! *
// List of valid timezones is here: http://us3.php.net/manual/en/timezones.php
date_default_timezone_set('America/New_York');
}
// Require the framework
require_once 'QuickBooks.php';
require_once('config.inc.php');
global $dbconfig;
$user = 'quickbooks';
$pass = 'password';
define('QB_QUICKBOOKS_CONFIG_LAST', 'last');
define('QB_QUICKBOOKS_CONFIG_CURR', 'curr');
define('QB_QUICKBOOKS_MAX_RETURNED', 1);
define('QB_PRIORITY_PURCHASEORDER', 1);
define('QB_PRIORITY_ITEM', 6);
define('QB_PRIORITY_CUSTOMER', 5);
define('QB_PRIORITY_SALESORDER', 2);
/**
* Request priorities, invoices last...
*/
define('QB_PRIORITY_INVOICE', 3);
define('QB_PRIORITY_ESTIMATE',4);
define('QB_QUICKBOOKS_MAILTO', 'keith#consolibyte.com');
// Map QuickBooks actions to handler functions
$map = array(
QUICKBOOKS_IMPORT_CUSTOMER => array( '_quickbooks_customer_import_request', '_quickbooks_customer_import_response' ),
QUICKBOOKS_IMPORT_ITEM => array( '_quickbooks_item_import_request', '_quickbooks_item_import_response' ),
QUICKBOOKS_IMPORT_ESTIMATE =>array( '_quickbooks_quote_import_request', '_quickbooks_quote_import_response' ),
QUICKBOOKS_IMPORT_SALESORDER => array( '_quickbooks_salesorder_import_request', '_quickbooks_salesorder_import_response' ),
QUICKBOOKS_IMPORT_INVOICE => array( '_quickbooks_invoice_import_request', '_quickbooks_invoice_import_response' ),
QUICKBOOKS_IMPORT_PURCHASEORDER => array( '_quickbooks_purchaseorder_import_request', '_quickbooks_purchaseorder_import_response' ),
);
// Error handlers
$errmap = array(
500 => '_quickbooks_error_e500_notfound', // Catch errors caused by searching for things not present in QuickBooks
1 => '_quickbooks_error_e500_notfound',
'*' => '_quickbooks_error_catchall', // Catch any other errors that might occur
);
// An array of callback hooks
$hooks = array(
QuickBooks_WebConnector_Handlers::HOOK_LOGINSUCCESS => '_quickbooks_hook_loginsuccess', // call this whenever a successful login occurs
);
// Logging level
//$log_level = QUICKBOOKS_LOG_NORMAL;
//$log_level = QUICKBOOKS_LOG_VERBOSE;
//$log_level = QUICKBOOKS_LOG_DEBUG; // Use this level until you're sure everything works!!!
$log_level = QUICKBOOKS_LOG_DEVELOP;
// 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( // See the comments in the QuickBooks/Server/Handlers.php file
'deny_concurrent_logins' => false,
'deny_reallyfast_logins' => false,
);
$driver_options = array( // See the comments in the QuickBooks/Driver/<YOUR DRIVER HERE>.php file ( i.e. 'Mysql.php', etc. )
);
$callback_options = array(
);
$dsn = $dbconfig['db_type']."://".$dbconfig['db_username'].":".$dbconfig['db_password']."#".$dbconfig['db_server']."/".$dbconfig['db_name'];
//$dsn = 'mysql://root:smackcoders#localhost/vtiger2';
//$dsn = 'mysql://testuser:testpassword#localhost/testdatabase';
define('QB_QUICKBOOKS_DSN', $dsn);
// If we haven't done our one-time initialization yet, do it now!
if (!QuickBooks_Utilities::initialized($dsn))
{
// Create the example tables
$file = dirname(__FILE__) . '/example.sql';
if (file_exists($file))
{
$contents = file_get_contents($file);
foreach (explode(';', $contents) as $sql)
{
if (!trim($sql))
{
continue;
}
mysql_query($sql) or die(trigger_error(mysql_error()));
}
}
else
{
die('Could not locate "./example.sql" to create the demo SQL schema!');
}
// Create the database tables
QuickBooks_Utilities::initialize($dsn);
// Add the default authentication username/password
QuickBooks_Utilities::createUser($dsn, $user, $pass);
}
// Initialize the queue
QuickBooks_WebConnector_Queue_Singleton::initialize($dsn);
// Create a new server and tell it to handle the requests
$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);
/**
* Login success hook - perform an action when a user logs in via the Web Connector
*
*
*/
function _quickbooks_hook_loginsuccess($requestID, $user, $hook, &$err, $hook_data, $callback_config)
{
// For new users, we need to set up a few things
// Fetch the queue instance
$Queue = QuickBooks_WebConnector_Queue_Singleton::getInstance();
$date = date('Y-m-d H:i:s');
// Set up the invoice imports
if (!_quickbooks_get_last_run($user, QUICKBOOKS_IMPORT_INVOICE))
{
// And write the initial sync time
_quickbooks_set_last_run($user, QUICKBOOKS_IMPORT_INVOICE, $date);
}
// Do the same for customers
if (!_quickbooks_get_last_run($user, QUICKBOOKS_IMPORT_CUSTOMER))
{
_quickbooks_set_last_run($user, QUICKBOOKS_IMPORT_CUSTOMER, $date);
}
// ... and for sales orders
if (!_quickbooks_get_last_run($user, QUICKBOOKS_IMPORT_SALESORDER))
{
_quickbooks_set_last_run($user, QUICKBOOKS_IMPORT_SALESORDER, $date);
}
// ... and for items
if (!_quickbooks_get_last_run($user, QUICKBOOKS_IMPORT_ITEM))
{
_quickbooks_set_last_run($user, QUICKBOOKS_IMPORT_ITEM, $date);
}
// Make sure the requests get queued up
$Queue->enqueue(QUICKBOOKS_IMPORT_CUSTOMER, 1, QB_PRIORITY_CUSTOMER, null, $user);
$Queue->enqueue(QUICKBOOKS_IMPORT_ITEM, 1, QB_PRIORITY_ITEM, null, $user);
$Queue->enqueue(QUICKBOOKS_IMPORT_ESTIMATE, 1, QB_PRIORITY_ESTIMATE, null, $user);
$Queue->enqueue(QUICKBOOKS_IMPORT_SALESORDER, 1, QB_PRIORITY_SALESORDER, null, $user);
$Queue->enqueue(QUICKBOOKS_IMPORT_INVOICE, 1, QB_PRIORITY_INVOICE, null, $user);
$Queue->enqueue(QUICKBOOKS_IMPORT_PURCHASEORDER, 1, QB_PRIORITY_PURCHASEORDER, null, $user);
}
/**
* Get the last date/time the QuickBooks sync ran
*
* #param string $user The web connector username
* #return string A date/time in this format: "yyyy-mm-dd hh:ii:ss"
*/
function _quickbooks_get_last_run($user, $action)
{
$type = null;
$opts = null;
return QuickBooks_Utilities::configRead(QB_QUICKBOOKS_DSN, $user, md5(__FILE__), QB_QUICKBOOKS_CONFIG_LAST . '-' . $action, $type, $opts);
}
function _quickbooks_set_last_run($user, $action, $force = null)
{
$value = date('Y-m-d') . 'T' . date('H:i:s');
if ($force)
{
$value = date('Y-m-d', strtotime($force)) . 'T' . date('H:i:s', strtotime($force));
}
return QuickBooks_Utilities::configWrite(QB_QUICKBOOKS_DSN, $user, md5(__FILE__), QB_QUICKBOOKS_CONFIG_LAST . '-' . $action, $value);
}
/**
*
*
*/
function _quickbooks_get_current_run($user, $action)
{
$type = null;
$opts = null;
return QuickBooks_Utilities::configRead(QB_QUICKBOOKS_DSN, $user, md5(__FILE__), QB_QUICKBOOKS_CONFIG_CURR . '-' . $action, $type, $opts);
}
/**
*
*
*/
function _quickbooks_set_current_run($user, $action, $force = null)
{
$value = date('Y-m-d') . 'T' . date('H:i:s');
if ($force)
{
$value = date('Y-m-d', strtotime($force)) . 'T' . date('H:i:s', strtotime($force));
}
return QuickBooks_Utilities::configWrite(QB_QUICKBOOKS_DSN, $user, md5(__FILE__), QB_QUICKBOOKS_CONFIG_CURR . '-' . $action, $value);
}
/**
* Build a request to import invoices already in QuickBooks into our application
*/
function _quickbooks_invoice_import_request($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $version, $locale)
{
// Iterator support (break the result set into small chunks)
$attr_iteratorID = '';
$attr_iterator = ' iterator="Start" ';
if (empty($extra['iteratorID']))
{
$last = _quickbooks_get_last_run($user, $action);
_quickbooks_set_last_run($user, $action); // Update the last run time to NOW()
// Set the current run to $last
_quickbooks_set_current_run($user, $action, $last);
}
else
{
$extra['iteratorID'] = $saved_iterator_id; // From Table
// This is a continuation of a batch
$attr_iteratorID = ' iteratorID="' . $extra['iteratorID'] . '" ';
$attr_iterator = ' iterator="Continue" ';
$last = _quickbooks_get_current_run($user, $action);
}
// Build the request
$xml = '<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="' . $version . '"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<InvoiceQueryRq ' . $attr_iterator . ' ' . $attr_iteratorID . ' requestID="' . $requestID . '">
<MaxReturned>' . QB_QUICKBOOKS_MAX_RETURNED . '</MaxReturned>
<ModifiedDateRangeFilter>
<FromModifiedDate>' . $last . '</FromModifiedDate>
</ModifiedDateRangeFilter>
<IncludeLineItems>true</IncludeLineItems>
<OwnerID>0</OwnerID>
</InvoiceQueryRq>
</QBXMLMsgsRq>
</QBXML>';
return $xml;
}
/**
* Handle a response from QuickBooks
*/
function _quickbooks_invoice_import_response($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents)
{
if (!empty($idents['iteratorRemainingCount']))
{
// Queue up another request
$Queue = QuickBooks_WebConnector_Queue_Singleton::getInstance();
$Queue->enqueue(QUICKBOOKS_IMPORT_INVOICE, null, QB_PRIORITY_INVOICE, array( 'iteratorID' => $idents['iteratorID'] ), $user);
}else{
return true;
}
// This piece of the response from QuickBooks is now stored in $xml. You
// can process the qbXML response in $xml in any way you like. Save it to
// a file, stuff it in a database, parse it and stuff the records in a
// database, etc. etc. etc.
//
// The following example shows how to use the built-in XML parser to parse
// the response and stuff it into a database.
// Import all of the records
$errnum = 0;
$errmsg = '';
$Parser = new QuickBooks_XML_Parser($xml);
if ($Doc = $Parser->parse($errnum, $errmsg))
{
$Root = $Doc->getRoot();
$List = $Root->getChildAt('QBXML/QBXMLMsgsRs/InvoiceQueryRs');
$smackHelper = new Quickbooks_vtigerHelper();
$smackHelper->addInvoice($List->children());
}
return true;
}
/**
* Build a request to import customers already in QuickBooks into our application
*/
function _quickbooks_customer_import_request($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $version, $locale)
{
// Iterator support (break the result set into small chunks)
$attr_iteratorID = '';
$attr_iterator = ' iterator="Start" ';
if (empty($extra['iteratorID']))
{
// This is the first request in a new batch
$last = _quickbooks_get_last_run($user, $action);
_quickbooks_set_last_run($user, $action); // Update the last run time to NOW()
// Set the current run to $last
_quickbooks_set_current_run($user, $action, $last);
}
else
{
$extra['iteratorID'] = $saved_iterator_id; // From Table
// This is a continuation of a batch
$attr_iteratorID = ' iteratorID="' . $extra['iteratorID'] . '" ';
$attr_iterator = ' iterator="Continue" ';
$last = _quickbooks_get_current_run($user, $action);
}
// Build the request
$xml = '<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="' . $version . '"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<CustomerQueryRq ' . $attr_iterator . ' ' . $attr_iteratorID . ' requestID="' . $requestID . '">
<MaxReturned>' . QB_QUICKBOOKS_MAX_RETURNED . '</MaxReturned>
<FromModifiedDate>' . $last . '</FromModifiedDate>
<OwnerID>0</OwnerID>
</CustomerQueryRq>
</QBXMLMsgsRq>
</QBXML>';
return $xml;
}
/**
* Handle a response from QuickBooks
*/
function _quickbooks_customer_import_response($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents)
{
if (!empty($idents['iteratorRemainingCount']))
{
// Queue up another request
$Queue = QuickBooks_WebConnector_Queue_Singleton::getInstance();
$Queue->enqueue(QUICKBOOKS_IMPORT_CUSTOMER, null, QB_PRIORITY_CUSTOMER, array( 'iteratorID' => $idents['iteratorID'] ), $user);
}else{
return true;
}
// Import all of the records
$errnum = 0;
$errmsg = '';
$Parser = new QuickBooks_XML_Parser($xml);
if ($Doc = $Parser->parse($errnum, $errmsg))
{
$Root = $Doc->getRoot();
$List = $Root->getChildAt('QBXML/QBXMLMsgsRs/CustomerQueryRs');
$smackHelper = new Quickbooks_vtigerHelper();
$smackHelper->addContacts($List->children());
}
return true;
}
function _quickbooks_quote_import_response($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents)
{
if (!empty($idents['iteratorRemainingCount']))
{
// Queue up another request
$Queue = QuickBooks_WebConnector_Queue_Singleton::getInstance();
$Queue->enqueue(QUICKBOOKS_IMPORT_ESTIMATE, null, QB_PRIORITY_ESTIMATE, array( 'iteratorID' => $idents['iteratorID'] ), $user);
}else{
return true;
}
// Import all of the records
$errnum = 0;
$errmsg = '';
$Parser = new QuickBooks_XML_Parser($xml);
if ($Doc = $Parser->parse($errnum, $errmsg))
{
$Root = $Doc->getRoot();
$List = $Root->getChildAt('QBXML/QBXMLMsgsRs/EstimateQueryRs');
$smackHelper = new Quickbooks_vtigerHelper();
$smackHelper->addQuotes($List->children());
}
return true;
}
function _quickbooks_quote_import_request($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $version, $locale)
{
if (empty($extra['iteratorID']))
{
$last = _quickbooks_get_last_run($user, $action);
_quickbooks_set_last_run($user, $action); // Update the last run time to NOW()
$attr_iterator = ' iterator="Start" ';
// Set the current run to $last
_quickbooks_set_current_run($user, $action, $last);
}
else
{
$extra['iteratorID'] = $saved_iterator_id; // From Table
// This is a continuation of a batch
$attr_iteratorID = ' iteratorID="' . $extra['iteratorID'] . '" ';
$attr_iterator = ' iterator="Continue" ';
$last = _quickbooks_get_current_run($user, $action);
//$last = '2015-08-18T01:03:41';
//$last = _quickbooks_get_current_run($user, $action);
}
// Build the request
$xml = '<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="' . $version . '"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<EstimateQueryRq ' . $attr_iterator . ' ' . $attr_iteratorID . ' requestID="' . $requestID . '">
<MaxReturned>' . QB_QUICKBOOKS_MAX_RETURNED . '</MaxReturned>
<ModifiedDateRangeFilter>
<FromModifiedDate>' . $last . '</FromModifiedDate>
</ModifiedDateRangeFilter>
<IncludeLineItems>true</IncludeLineItems>
<OwnerID>0</OwnerID>
</EstimateQueryRq>
</QBXMLMsgsRq>
</QBXML>';
return $xml;
}
function _quickbooks_salesorder_import_request($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $version, $locale)
{
// Iterator support (break the result set into small chunks)
$attr_iteratorID = '';
$attr_iterator = ' iterator="Start" ';
if (empty($extra['iteratorID']))
{
// This is the first request in a new batch
$last = _quickbooks_get_last_run($user, $action);
_quickbooks_set_last_run($user, $action); // Update the last run time to NOW()
// Set the current run to $last
_quickbooks_set_current_run($user, $action, $last);
}
else
{
$extra['iteratorID'] = $saved_iterator_id; // From Table
// This is a continuation of a batch
$attr_iteratorID = ' iteratorID="' . $extra['iteratorID'] . '" ';
$attr_iterator = ' iterator="Continue" ';
$last = _quickbooks_get_current_run($user, $action);
}
// Build the request
$xml = '<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="' . $version . '"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<SalesOrderQueryRq ' . $attr_iterator . ' ' . $attr_iteratorID . ' requestID="' . $requestID . '">
<MaxReturned>' . QB_QUICKBOOKS_MAX_RETURNED . '</MaxReturned>
<ModifiedDateRangeFilter>
<FromModifiedDate>' . $last . '</FromModifiedDate>
</ModifiedDateRangeFilter>
<IncludeLineItems>true</IncludeLineItems>
<OwnerID>0</OwnerID>
</SalesOrderQueryRq>
</QBXMLMsgsRq>
</QBXML>';
return $xml;
}
/**
* Handle a response from QuickBooks
*/
function _quickbooks_salesorder_import_response($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents)
{
if (!empty($idents['iteratorRemainingCount']))
{
// Queue up another request
$Queue = QuickBooks_WebConnector_Queue_Singleton::getInstance();
$Queue->enqueue(QUICKBOOKS_IMPORT_SALESORDER, null, QB_PRIORITY_SALESORDER, array( 'iteratorID' => $idents['iteratorID'] ), $user);
}else{
return true;
}
// Import all of the records
$errnum = 0;
$errmsg = '';
$Parser = new QuickBooks_XML_Parser($xml);
if ($Doc = $Parser->parse($errnum, $errmsg))
{
$Root = $Doc->getRoot();
$List = $Root->getChildAt('QBXML/QBXMLMsgsRs/SalesOrderQueryRs');
$smackHelper = new Quickbooks_vtigerHelper();
$smackHelper->addSalesOrder($List->children());
}
return true;
}
/**
* Build a request to import customers already in QuickBooks into our application
*/
function _quickbooks_item_import_request($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $version, $locale)
{
// Iterator support (break the result set into small chunks)
$attr_iteratorID = '';
$attr_iterator = ' iterator="Start" ';
if (empty($extra['iteratorID']))
{
// This is the first request in a new batch
$last = _quickbooks_get_last_run($user, $action);
_quickbooks_set_last_run($user, $action); // Update the last run time to NOW()
// Set the current run to $last
_quickbooks_set_current_run($user, $action, $last);
}
else
{
$extra['iteratorID'] = $saved_iterator_id; // From Table
// This is a continuation of a batch
$attr_iteratorID = ' iteratorID="' . $extra['iteratorID'] . '" ';
$attr_iterator = ' iterator="Continue" ';
$last = _quickbooks_get_current_run($user, $action);
}
// Build the request
$xml = '<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="' . $version . '"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<ItemQueryRq ' . $attr_iterator . ' ' . $attr_iteratorID . ' requestID="' . $requestID . '">
<MaxReturned>' . QB_QUICKBOOKS_MAX_RETURNED . '</MaxReturned>
<FromModifiedDate>' . $last . '</FromModifiedDate>
<OwnerID>0</OwnerID>
</ItemQueryRq>
</QBXMLMsgsRq>
</QBXML>';
return $xml;
}
/**
* Handle a response from QuickBooks
*/
function _quickbooks_item_import_response($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents)
{
if (!empty($idents['iteratorRemainingCount']))
{
// Queue up another request
$Queue = QuickBooks_WebConnector_Queue_Singleton::getInstance();
$Queue->enqueue(QUICKBOOKS_IMPORT_ITEM, null, QB_PRIORITY_ITEM, array( 'iteratorID' => $idents['iteratorID'] ), $user);
}else{
return true;
}
// Import all of the records
$errnum = 0;
$errmsg = '';
$Parser = new QuickBooks_XML_Parser($xml);
if ($Doc = $Parser->parse($errnum, $errmsg))
{
$Root = $Doc->getRoot();
$List = $Root->getChildAt('QBXML/QBXMLMsgsRs/ItemQueryRs');
$smackHelper = new Quickbooks_vtigerHelper();
$smackHelper->addProducts($List->children(),'Products');
}
return true;
}
/**
* Build a request to import invoices already in QuickBooks into our application
*/
function _quickbooks_purchaseorder_import_request($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $version, $locale)
{
// Iterator support (break the result set into small chunks)
$attr_iteratorID = '';
$attr_iterator = ' iterator="Start" ';
if (empty($extra['iteratorID']))
{
// This is the first request in a new batch
$last = _quickbooks_get_last_run($user, $action);
_quickbooks_set_last_run($user, $action); // Update the last run time to NOW()
// Set the current run to $last
_quickbooks_set_current_run($user, $action, $last);
}
else
{
$extra['iteratorID'] = $saved_iterator_id; // From Table
// This is a continuation of a batch
$attr_iteratorID = ' iteratorID="' . $extra['iteratorID'] . '" ';
$attr_iterator = ' iterator="Continue" ';
$last = _quickbooks_get_current_run($user, $action);
}
// Build the request
$xml = '<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="' . $version . '"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<PurchaseOrderQueryRq ' . $attr_iterator . ' ' . $attr_iteratorID . ' requestID="' . $requestID . '">
<MaxReturned>' . QB_QUICKBOOKS_MAX_RETURNED . '</MaxReturned>
<!--<ModifiedDateRangeFilter>
<FromModifiedDate>' . $last . '</FromModifiedDate>
</ModifiedDateRangeFilter>-->
<IncludeLineItems>true</IncludeLineItems>
<OwnerID>0</OwnerID>
</PurchaseOrderQueryRq>
</QBXMLMsgsRq>
</QBXML>';
return $xml;
}
/**
* Handle a response from QuickBooks
*/
function _quickbooks_purchaseorder_import_response($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents)
{
if (!empty($idents['iteratorRemainingCount']))
{
// Queue up another request
$Queue = QuickBooks_WebConnector_Queue_Singleton::getInstance();
$Queue->enqueue(QUICKBOOKS_IMPORT_PURCHASEORDER, null, QB_PRIORITY_PURCHASEORDER, array( 'iteratorID' => $idents['iteratorID'] ), $user);
}else{
return true;
}
// This piece of the response from QuickBooks is now stored in $xml. You
// can process the qbXML response in $xml in any way you like. Save it to
// a file, stuff it in a database, parse it and stuff the records in a
// database, etc. etc. etc.
//
// The following example shows how to use the built-in XML parser to parse
// the response and stuff it into a database.
// Import all of the records
$errnum = 0;
$errmsg = '';
$Parser = new QuickBooks_XML_Parser($xml);
if ($Doc = $Parser->parse($errnum, $errmsg))
{
$Root = $Doc->getRoot();
$List = $Root->getChildAt('QBXML/QBXMLMsgsRs/PurchaseOrderQueryRs');
// TODO
}
return true;
}
/**
* Handle a 500 not found error from QuickBooks
*
* Instead of returning empty result sets for queries that don't find any
* records, QuickBooks returns an error message. This handles those error
* messages, and acts on them by adding the missing item to QuickBooks.
*/
function _quickbooks_error_e500_notfound($requestID, $user, $action, $ID, $extra, &$err, $xml, $errnum, $errmsg)
{
$Queue = QuickBooks_WebConnector_Queue_Singleton::getInstance();
if ($action == QUICKBOOKS_IMPORT_INVOICE)
{
return true;
}
else if ($action == QUICKBOOKS_IMPORT_CUSTOMER)
{
return true;
}
else if ($action == QUICKBOOKS_IMPORT_SALESORDER)
{
return true;
}
else if ($action == QUICKBOOKS_IMPORT_ITEM)
{
return true;
}
else if ($action == QUICKBOOKS_IMPORT_PURCHASEORDER)
{
return true;
}
return false;
}
function _quickbooks_error_catchall($requestID, $user, $action, $ID, $extra, &$err, $xml, $errnum, $errmsg)
{
$message = '';
$message .= 'Request ID: ' . $requestID . "\r\n";
$message .= 'User: ' . $user . "\r\n";
$message .= 'Action: ' . $action . "\r\n";
$message .= 'ID: ' . $ID . "\r\n";
$message .= 'Extra: ' . print_r($extra, true) . "\r\n";
//$message .= 'Error: ' . $err . "\r\n";
$message .= 'Error number: ' . $errnum . "\r\n";
$message .= 'Error message: ' . $errmsg . "\r\n";
mail(QB_QUICKBOOKS_MAILTO,
'QuickBooks error occured!',
$message);
}
So I see at least a few potential issues, and have some questions. First, some background --
Iterators in QuickBooks work just like a database cursor. Part of that means that you can't have two iterators open at once - you have to finish with one iterator before you start and/or continue another iterator. So if you do this, you'll get the error you're seeing:
Start iterator #1
Fetch some data from iterator #1
Start iterator #2
Try to fetch some data from iterator #1 again
That will fail because starting the second iterator has closed/killed the first iterator. This is probably what's happening to you.
What is this?
$extra['iteratorID'] = $saved_iterator_id; // From Table
That looks like an undefined variable to me. Did you check your PHP error logs?
Why are you saving this to a table, and what table are you saving it to? Where in the code are you pulling it back out of the table? I don't see any code that gets it from the table.
I need to develop an iOS app that fetches data from an OpenCart installation online. This includes ordering online, adding things to wish list, creating a user account. Logging in to an already existing user account and everything else that open cart offers. Basically, it is an iOS version of the OpenCart website that connects to the OpenCart's MySQL database.
I googled a little bit but couldn't find a proper API that I can use to hookup my app with OpenCart. What other options do I have? Does OpenCart offer any web service? (Like WordPress offers XML-RPC). Or is there a good API that I can use?
Unfortunately, OpenCart does not offer any API straight away. (that's for an answer).
There is an opensource OpenCart API project on GitHub that you can download (google it, I do not remember it's name) but this offers only the very limited and basic methods for just reading of data (if I remember correctly there were methods for getting the list of categories, list of products and product details and few more).
This could be your starting point: fork, add methods, share. Or create your own API from a scratch if you wish (again, sharing will be highly welcomed :-) - I believe you could even find users willing to pay for it - I would have created one if I had time - but sadly I have not...).
<?php
include_once 'functions.php';
class ControllerJsonJson extends Controller {
public function index() {
// Menu
$this->load->model('catalog/category');
$this->load->model('catalog/product');
$this->load->model('tool/image');
$data['categories'] = array();
$categories = $this->model_catalog_category->getCategories(0);
foreach ($categories as $category) {
if ($category['top']) {
// Level 2
$children_data = array();
$children = $this->model_catalog_category->getCategories($category['category_id']);
foreach ($children as $child) {
if ($child['image']) {
$childpopup = $this->model_tool_image->resize($child['image'], $this->config->get('config_image_popup_width'), $this->config->get('config_image_popup_height'));
$childthumb = $this->model_tool_image->resize($child['image'], 74,74);
} else {
$childthumb='';
$childpopup = '';
}
$filter_data = array(
'filter_category_id' => $child['category_id'],
'filter_sub_category' => true
);
$children_data[] = array(
'popup'=>$childpopup,
'thumb'=>$childthumb,
'id' => $child['category_id'],
'name' => $child['name'] . ($this->config->get('config_product_count') ? ' (' . $this->model_catalog_product->getTotalProducts($filter_data) . ')' : ''),
'href' => $this->url->link('product/category', 'path=' . $category['category_id'] . '_' . $child['category_id'])
);
}
if ($category['image']) {
$categorypopup = $this->model_tool_image->resize($category['image'], $this->config->get('config_image_popup_width'), $this->config->get('config_image_popup_height'));
$categorythumb = $this->model_tool_image->resize($category['image'], 74,74);
} else {
$categorypopup = '';
$categorythumb='';
}
// Level 1
$data['categories'][] = array(
'popup' => $categorypopup,
'thumb' => $categorythumb,
'id' => $category['category_id'],
'name' => $category['name'],
'children' => $children_data,
'column' => $category['column'] ? $category['column'] : 1,
'href' => $this->url->link('product/category', 'path=' . $category['category_id'])
);
}
}
$obj=new functions();
echo $obj->json_pretty_encode($data);
}
}
<?php
class functions {
//put your code here
public function json_pretty_encode($obj){
header("Content-type: application/json");
$json = json_encode($obj);
if (!$json) return $json;
$f = '';
$len = strlen($json);
$depth = 0;
$newline = false;
for ($i = 0; $i < $len; ++$i)
{
if ($newline)
{
$f .= "\n";
$f .= str_repeat(' ', $depth);
$newline = false;
}
$c = $json[$i];
if ($c == '{' || $c == '[')
{
$f .= $c;
$depth++;
$newline = true;
}
else if ($c == '}' || $c == ']')
{
$depth--;
$f .= "\n";
$f .= str_repeat(' ', $depth);
$f .= $c;
}
else if ($c == '"')
{
$s = $i;
do {
$c = $json[++$i];
if ($c == '\\')
{
$i += 2;
$c = $json[$i];
}
} while ($c != '"');
$f .= substr($json, $s, $i-$s+1);
}
else if ($c == ':')
{
$f .= ': ';
}
else if ($c == ',')
{
$f .= ',';
$newline = true;
}
else
{
$f .= $c;
}
}
return $f;
}
}