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.