public function saveAll($dir) { $Parser = new QuickBooks_XML($this->_xml); $arr_actions_adds = QuickBooks_Utilities::listActions('*Add', false); $arr_actions_mods = QuickBooks_Utilities::listActions('*Mod', false); //print_r($arr_actions_mods); //exit; $i = 0; $errnum = 0; $errmsg = ''; if ($Doc = $Parser->parse($errnum, $errmsg)) { $children = $Doc->children(); $children = $children[0]->children(); foreach ($children as $Action) { print 'Action name is: ' . $Action->name() . "\n"; //if ($Action->name() != 'VendorAddRq') //{ // continue; //} //print_r($Action); $section = $this->_extractSectionForTag($this->_xml, $Action->name()); //print($section); $wrapper = ''; if ($Action->hasChildren()) { $first = $Action->getChild(0); //print_r($first); if (in_array($first->name(), $arr_actions_mods) or in_array($first->name(), $arr_actions_adds)) { $wrapper = $first->name(); print ' WRAPPER NODE IS: ' . $wrapper . "\n"; } } //exit; $paths_datatype = array(); $paths_maxlength = array(); $paths_isoptional = array(); $paths_sinceversion = array(); $paths_isrepeatable = array(); $paths_reorder = array(); //$curdepth = 0; $lastdepth = 0; $paths = $Action->asArray(QUICKBOOKS_XML_ARRAY_PATHS); foreach ($paths as $path => $datatype) { $tmp = explode(' ', $path); $tag = end($tmp); $comment = $this->_extractCommentForTag($section, $tag); //print("\t{" . $path . '} => ' . $datatype . ' (' . $comment . ')' . "\n"); $parse = $this->_parseComment($comment); //print_r($parse); //print("\n"); $path = trim(substr($path, strlen($Action->name()))); if (strlen($wrapper) and substr($path, 0, strlen($wrapper)) == $wrapper) { $path = substr($path, strlen($wrapper) + 1); } $paths_datatype[$path] = $datatype; $paths_maxlength[$path] = $parse['maxlength']; $paths_isoptional[$path] = $parse['isoptional']; $paths_sinceversion[$path] = $parse['version']; $paths_isrepeatable[$path] = $parse['mayrepeat']; $curdepth = substr_count($path, ' '); if ($curdepth - $lastdepth > 1) { $tmp2 = explode(' ', $path); for ($i = 1; $i < count($tmp2); $i++) { $paths_reorder[] = implode(' ', array_slice($tmp2, 0, $i)); } } $lastdepth = substr_count($path, ' '); $paths_reorder[] = $path; } //print(var_export($paths_datatype)); //print(var_export($paths_maxlength)); //print(var_export($paths_isoptional)); //print(var_export($paths_sinceversion)); //print(var_export($paths_isrepeatable)); //print(var_export($paths_reorder)); $contents = file_get_contents('/home/asdg/QuickBooks/QBXML/Schema/Object/Template.php'); $contents = str_replace('Template', $Action->name(), $contents); $contents = str_replace('\'_qbxmlWrapper\'', var_export($wrapper, true), $contents); $contents = str_replace('\'_dataTypePaths\'', var_export($paths_datatype, true), $contents); $contents = str_replace('\'_maxLengthPaths\'', var_export($paths_maxlength, true), $contents); $contents = str_replace('\'_isOptionalPaths\'', var_export($paths_isoptional, true), $contents); $contents = str_replace('\'_sinceVersionPaths\'', var_export($paths_sinceversion, true), $contents); $contents = str_replace('\'_isRepeatablePaths\'', var_export($paths_isrepeatable, true), $contents); $contents = str_replace('\'_reorderPaths\'', var_export($paths_reorder, true), $contents); $fp = fopen('/home/adg/QuickBooks/tmp/' . $Action->name() . '.php', 'w+'); fwrite($fp, $contents); fclose($fp); print "\n\n"; if ($i > 150) { exit; } $i++; } } }
/** * @deprecated Use QuickBooks_XML::extractTagContents() instead */ protected static function _extractTagContents($tag, $data) { $tmp = QuickBooks_XML::extractTagContents($tag, $data); return $tmp; }
public function asIDSXML($indent = 0, $parent = null, $optype = null, $flavor = null) { // We're not going to actually change the data, just change a copy of it $data = $this->_data; if (!$parent) { $parent = $this->resource(); } if ($optype == QuickBooks_IPP_IDS::OPTYPE_ADD or $optype == QuickBooks_IPP_IDS::OPTYPE_MOD) { if ($flavor == QuickBooks_IPP_IDS::FLAVOR_ONLINE) { $xml = str_repeat("\t", $indent) . '<' . $this->resource() . ' xmlns="http://www.intuit.com/sb/cdm/v2" xmlns:ns2="http://www.intuit.com/sb/cdm/qbopayroll/v1" xmlns:ns3="http://www.intuit.com/sb/cdm/qbo">' . QUICKBOOKS_CRLF; } else { $xml = str_repeat("\t", $indent) . '<Object xsi:type="' . $this->resource() . '">' . QUICKBOOKS_CRLF; } // Merge in the defaults for this object type $data = array_merge($this->_defaults(), $data); } else { if ($parent == 'CustomField') { $xml = str_repeat("\t", $indent) . '<' . $parent . ' xsi:type="StringTypeCustomField">' . QUICKBOOKS_CRLF; } else { $xml = str_repeat("\t", $indent) . '<' . $parent . '>' . QUICKBOOKS_CRLF; } } // Re-order is correctly $data = $this->_reorder($data); // Go through the data, creating XML out of it foreach ($data as $key => $value) { if (is_object($value)) { // If this causes problems, it can be commented out. It handles only situations where you are ->set(...)ing full objects, which can also be done by ->add(...)ing full objects instead $xml .= $value->asIDSXML($indent + 1, null, null, $flavor); } else { if (is_array($value)) { foreach ($value as $skey => $svalue) { //print('converting array: [' . $key . ' >> ' . $skey . ']'); if (is_object($svalue)) { $xml .= $svalue->asIDSXML($indent + 1, $key, null, $flavor); } else { if (substr($key, -2, 2) == 'Id') { $for_qbxml = false; $tmp = QuickBooks_IPP_IDS::parseIdType($svalue); if ($tmp[0]) { $xml .= str_repeat("\t", $indent + 1) . '<' . $key . ' idDomain="' . $tmp[0] . '">'; } else { $xml .= str_repeat("\t", $indent + 1) . '<' . $key . '>'; } $xml .= QuickBooks_XML::encode($tmp[1], $for_qbxml); $xml .= '</' . $key . '>' . QUICKBOOKS_CRLF; } else { //$for_qbxml = false; // //$xml .= str_repeat("\t", $indent + 1) . '<' . $key . '>'; //$xml .= QuickBooks_XML::encode($value, $for_qbxml); //$xml .= '</' . $key . '>' . QUICKBOOKS_CRLF; $xml .= str_repeat("\t", $indent + 1) . '<' . $key . '>' . QuickBooks_XML::encode($svalue, false) . '</' . $key . '>' . QUICKBOOKS_CRLF; } } } } else { if (substr($key, -2, 2) == 'Id') { $for_qbxml = false; $tmp = QuickBooks_IPP_IDS::parseIdType($value); if ($tmp[0]) { $xml .= str_repeat("\t", $indent + 1) . '<' . $key . ' idDomain="' . $tmp[0] . '">'; } else { $xml .= str_repeat("\t", $indent + 1) . '<' . $key . '>'; } $xml .= QuickBooks_XML::encode($tmp[1], $for_qbxml); $xml .= '</' . $key . '>' . QUICKBOOKS_CRLF; } else { $for_qbxml = false; $xml .= str_repeat("\t", $indent + 1) . '<' . $key . '>'; $xml .= QuickBooks_XML::encode($value, $for_qbxml); $xml .= '</' . $key . '>' . QUICKBOOKS_CRLF; } } } } if ($optype == QuickBooks_IPP_IDS::OPTYPE_ADD or $optype == QuickBooks_IPP_IDS::OPTYPE_MOD) { if ($flavor == QuickBooks_IPP_IDS::FLAVOR_ONLINE) { $xml .= str_repeat("\t", $indent) . '</' . $this->resource() . '>' . QUICKBOOKS_CRLF; } else { $xml .= str_repeat("\t", $indent) . '</Object>' . QUICKBOOKS_CRLF; } } else { $xml .= str_repeat("\t", $indent) . '</' . $parent . '>' . QUICKBOOKS_CRLF; } return $xml; }
<?php ini_set('include_path', ini_get('include_path') . ':' . realpath(dirname(__FILE__) . '/..')); require_once 'QuickBooks.php'; require_once 'QuickBooks/XML.php'; $xml = file_get_contents('/home/library_php/QuickBooks/data/InvoiceQuery.xml'); $Parser = new QuickBooks_XML($xml); $errnum = 0; $errmsg = ''; $Parser->parse($errnum, $errmsg); //print_R($Parser); $tmp = $Parser->children(); $base = current($tmp); $tmp = $base->children(); $rs = next($tmp); $tmp = $rs->children(); $qbxml = current($tmp); Transform($qbxml); function Transform($node) { $name = $node->name(); // table name $fields = array(); $subtables = array(); foreach ($node->children() as $child) { if (substr($child->name(), -3) == 'Ref') { // We need to look through the reference, and see if we can find it's unique identifier (is it a ListID? a FullName? a TxnID?) $fields[substr($child->name(), 0, -3) . '_ListID'] = array('link!'); } else { if ($child->childCount()) { $child->setName($node->name() . '_' . $child->name());
/** * Get an IDS object by Name (i.e. get a customer by the QuickBooks Name field) * * @param QuickBooks_IPP_Context $Context * @param integer $realmID * @param string $resource * @param string $xml * @return QuickBooks_IPP_Object */ protected function _findByName($Context, $realmID, $resource, $name, $xml = '') { $IPP = $Context->IPP(); if ($IPP->flavor() == QuickBooks_IPP_IDS::FLAVOR_DESKTOP) { if (!$xml) { $xml = ''; $xml .= '<?xml version="1.0" encoding="UTF-8"?>' . QUICKBOOKS_CRLF; $xml .= '<' . $resource . 'Query xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.intuit.com/sb/cdm/' . $IPP->version() . '">' . QUICKBOOKS_CRLF; $xml .= ' <FirstLastInside>' . QuickBooks_XML::encode($name) . '</FirstLastInside>' . QUICKBOOKS_CRLF; $xml .= '</' . $resource . 'Query>'; } } else { $xml = http_build_query(array('Filter' => 'Name :EQUALS: ' . $name)); } $return = $IPP->IDS($Context, $realmID, $resource, QuickBooks_IPP_IDS::OPTYPE_QUERY, $xml); $this->_setLastRequestResponse($Context->lastRequest(), $Context->lastResponse()); $this->_setLastDebug($Context->lastDebug()); if (count($return)) { return $return[0]; } return null; }
/** * * @param string $requestID * @param string $user * @param string $action * @param mixed $ID * @param mixed $extra * @param string $err * @param integer $last_action_time * @param integer $last_actionident_time * @param string $xml * @param array $idents * @return boolean */ protected static function _doQueryResponse($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents, $callback_options = array()) { // This is stuff we'll be passing to the callback handler functions/methods // $action // $ID $err = ''; $qbxml =& $xml; $qbiterator = null; $qbres = null; $method = null; if (isset($extra['method'])) { $method = $extra['method']; } $xml_errnum = 0; $xml_errmsg = ''; $Parser = new QuickBooks_XML($xml); if ($Parser->validate($xml_errnum, $xml_errmsg) and $Doc = $Parser->parse($xml_errnum, $xml_errmsg)) { $list = array(); $Root = $Doc->getRoot(); // Get rid of some gunk... $Response = $Root->getChildAt('QBXML QBXMLMsgsRs ' . $action . 'Rs'); if ($Response) { foreach ($Response->children() as $Child) { if ($Object = QuickBooks_Callbacks_API_Callbacks::_objectFromXML($action, $Child)) { $list[] = $Object; } } } $Iterator = new QuickBooks_Iterator($list); } else { $err = 'XML parser error: ' . $xml_errnum . ': ' . $xml_errmsg; } if ($err) { return false; } //print_r($extra); //print_r($Iterator); if (isset($extra['callbacks']) and is_array($extra['callbacks'])) { QuickBooks_Callbacks_API_Callbacks::_callCallbacks($extra['callbacks'], $method, $action, $ID, $err, $qbxml, $Iterator, $qbres, $callback_options); } return true; }
protected function _parseIDS_v3($xml, $optype, $flavor, $version, &$xml_errnum, &$xml_errmsg, &$err_code, &$err_desc, &$err_db) { /* if ($optype == QuickBooks_IPP_IDS::OPTYPE_ENTITLEMENTS) { $xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><EntitlementsResponse><QboCompany>true</QboCompany><PlanName>QBWEBVAR1MO</PlanName><MaxUsers>3</MaxUsers><CurrentUsers>1</CurrentUsers><DaysRemainingTrial>0</DaysRemainingTrial><Entitlement id="7"><name>PayPal</name><term>Off</term></Entitlement><Entitlement id="8"><name>Merchant Service</name><term>Off</term></Entitlement><Entitlement id="50"><name>Adjusted Trial Balance Report</name><term>Off</term></Entitlement><Entitlement id="51"><name>Adjusting Journal Entries</name><term>Off</term></Entitlement><Entitlement id="52"><name>Accountant Menu</name><term>Off</term></Entitlement><Entitlement id="53"><name>Reconciliation Troubleshooting</name><term>Off</term></Entitlement><Entitlement id="54"><name>Reclassify Transactions</name><term>Off</term></Entitlement><Entitlement id="55"><name>Write Off Invoices</name><term>Off</term></Entitlement><Entitlement id="1"><name>Class Tracking</name><term>Off</term></Entitlement><Entitlement id="3"><name>Expense Tracking by Customer</name><term>Off</term></Entitlement><Entitlement id="4"><name>Time Tracking</name><term>Off</term></Entitlement><Entitlement id="5"><name>Budgets</name><term>Off</term></Entitlement><Entitlement id="6"><name>Custom Invoice Styles</name><term>On</term></Entitlement><Entitlement id="9"><name>1099 Forms for Vendors</name><term>Off</term></Entitlement><Entitlement id="10"><name>Managing Bills to Pay Later</name><term>On</term></Entitlement><Entitlement id="11"><name>Complete Set of Reports</name><term>On</term></Entitlement><Entitlement id="12"><name>Enhanced Reporting</name><term>On</term></Entitlement><Entitlement id="13"><name>Exporting to Excel</name><term>On</term></Entitlement><Entitlement id="15"><name>Delayed Charges</name><term>On</term></Entitlement><Entitlement id="16"><name>Custom Sales Fields</name><term>On</term></Entitlement><Entitlement id="17"><name>More Users -- up to 20</name><term>On</term></Entitlement><Entitlement id="19"><name>Recurring Transactions</name><term>On</term></Entitlement><Entitlement id="20"><name>Closing the Books</name><term>On</term></Entitlement><Entitlement id="21"><name>Location Tracking</name><term>Off</term></Entitlement><Entitlement id="22"><name>More Names</name><term>On</term></Entitlement><Entitlement id="25"><name>Custom Home Page</name><term>On</term></Entitlement><Entitlement id="26"><name>Do-it-yourself Payroll</name><term>Off</term></Entitlement><Entitlement id="28"><name>Online Banking</name><term>On</term></Entitlement><Entitlement id="29"><name>Basic Sales</name><term>On</term></Entitlement><Entitlement id="30"><name>Basic Banking</name><term>On</term></Entitlement><Entitlement id="31"><name>Accounting</name><term>On</term></Entitlement><Entitlement id="33"><name>Reports Only User</name><term>Off</term></Entitlement><Entitlement id="35"><name>Estimates</name><term>On</term></Entitlement><Entitlement id="41"><name>Company Snapshot</name><term>On</term></Entitlement><Entitlement id="42"><name>Purchase Order</name><term>Off</term></Entitlement><Entitlement id="43"><name>Inventory</name><term>Off</term></Entitlement><Entitlement id="44"><name>Do-it-yourself Payroll (Paycycle)</name><term>Off</term></Entitlement><Entitlement id="45"><name>Multi-Currency</name><term>On</term></Entitlement><Entitlement id="46"><name>Trends</name><term>On</term></Entitlement><Entitlement id="47"><name>Hide Employee List</name><term>Off</term></Entitlement><Entitlement id="48"><name>Simple Report List</name><term>Off</term></Entitlement><Entitlement id="49"><name>Global Tax Model</name><term>On</term></Entitlement><Entitlement id="56"><name>Text Messaging</name><term>On</term></Entitlement><Entitlement id="58"><name>Vendor Collaboration</name><term>On</term></Entitlement></EntitlementsResponse>'; } */ // Parse it $Parser = new QuickBooks_XML_Parser($xml); // Initial to success $xml_errnum = QuickBooks_XML::ERROR_OK; $err_code = QuickBooks_IPP::ERROR_OK; // Try to parse the XML IDS response $errnum = QuickBooks_XML::ERROR_OK; $errmsg = null; if ($Doc = $Parser->parse($errnum, $errmsg)) { $Root = $Doc->getRoot(); switch ($optype) { case QuickBooks_IPP_IDS::OPTYPE_ENTITLEMENTS: $e = array('_i' => array(), '_e' => array()); $List = $Root->getChildAt('EntitlementsResponse'); foreach ($List->children() as $ObjList) { if ($ObjList->name() == 'Entitlement') { $Entitlement = new QuickBooks_IPP_Entitlement($ObjList->getAttribute('id'), $ObjList->getChildDataAt('Entitlement/name'), $ObjList->getChildDataAt('Entitlement/term')); $e['_e'][] = $Entitlement; } else { $e['_i'][$ObjList->name()] = $ObjList->data(); } } return $e; break; case QuickBooks_IPP_IDS::OPTYPE_CDC: $types = array(); $List = $Root->getChildAt('IntuitResponse CDCResponse'); foreach ($List->children() as $ObjList) { foreach ($ObjList->children() as $Child) { $type = $Child->name(); if (empty($types[$type])) { $types[$type] = array(); } $class = 'QuickBooks_IPP_Object_' . $Child->name(); $Object = new $class(); foreach ($Child->children() as $Data) { $this->_push($Data, $Object); } $types[$type][] = $Object; } } return $types; break; case QuickBooks_IPP_IDS::OPTYPE_ADD: // Parse an ADD type response return QuickBooks_IPP_IDS::buildIDType('', QuickBooks_XML::extractTagContents('Id', $xml)); case QuickBooks_IPP_IDS::OPTYPE_MOD: return true; // If we got this far, it was a success // If we got this far, it was a success case QuickBooks_IPP_IDS::OPTYPE_QUERY: $list = array(); $List = $Root->getChildAt('IntuitResponse QueryResponse'); $attrs = $List->attributes(); if (!array_key_exists('startPosition', $attrs) and array_key_exists('totalCount', $attrs)) { return $attrs['totalCount']; } else { foreach ($List->children() as $Child) { $class = 'QuickBooks_IPP_Object_' . $Child->name(); $Object = new $class(); foreach ($Child->children() as $Data) { $this->_push($Data, $Object); } $list[] = $Object; } return $list; } } } else { $xml_errnum = $errnum; $xml_errmsg = $errmsg; return false; } }
/** * Resursive helper function for converting to XML * * @param QuickBooks_XML_Node $node * @param integer $tabs * @param boolean $empty A constant, one of: QUICKBOOKS_XML_XML_PRESERVE, QUICKBOOKS_XML_XML_DROP, QUICKBOOKS_XML_XML_COMPRESS * @param string $indent * @return string */ public function _asXMLHelper($node, $tabs, $empty, $indent) { $xml = ''; if ($node->childCount()) { $xml .= str_repeat($indent, $tabs) . '<' . $node->name(); foreach ($node->attributes() as $key => $value) { // Make sure double-encode is *off* //$xml .= ' ' . $key . '="' . QuickBooks_XML::encode($value, true, false) . '"'; $xml .= ' ' . $key . '="' . QuickBooks_XML::encode($value) . '"'; } $xml .= '>' . "\n"; foreach ($node->children() as $child) { $xml .= $this->_asXMLHelper($child, $tabs + 1, $empty, $indent); } $xml .= str_repeat($indent, $tabs) . '</' . $node->name() . '>' . "\n"; } else { if ($node->hasAttributes()) { $xml .= str_repeat($indent, $tabs) . '<' . $node->name(); foreach ($node->attributes() as $key => $value) { // Double-encode is *off* //$xml .= ' ' . $key . '="' . QuickBooks_XML::encode($value, true, false) . '"'; $xml .= ' ' . $key . '="' . QuickBooks_XML::encode($value) . '"'; } // Double-encode is *off* //$xml .= '>' . QuickBooks_XML::encode($node->data(), true, false) . '</' . $node->name() . '>' . "\n"; $xml .= '>' . QuickBooks_XML::encode($node->data()) . '</' . $node->name() . '>' . "\n"; } else { if ($node->hasData() or $empty == QUICKBOOKS_XML_XML_PRESERVE) { // Double-encode is *off* //$xml .= str_repeat($indent, $tabs) . '<' . $node->name() . '>' . QuickBooks_XML::encode($node->data(), true, false) . '</' . $node->name() . '>' . "\n"; $xml .= str_repeat($indent, $tabs) . '<' . $node->name() . '>' . QuickBooks_XML::encode($node->data()) . '</' . $node->name() . '>' . "\n"; } else { if ($empty == QUICKBOOKS_XML_XML_COMPRESS) { $xml .= str_repeat($indent, $tabs) . '<' . $node->name() . ' />' . "\n"; } else { if ($empty == QUICKBOOKS_XML_XML_DROP) { // do nothing, drop the empty element } } } } /* $xml .= str_repeat($indent, $tabs) . '<' . $node->name(); foreach ($node->attributes() as $key => $value) { $xml .= ' ' . $key . '="' . htmlentities($value, ENT_QUOTES) . '"'; } if ($node->data()) { $xml .= '>' . htmlentities($node->data()) . '</' . $node->name() . '>' . "\n"; } else if ($compress) { $xml .= ' />' . "\n"; } else { $xml .= '></' . $node->name() . '>' . "\n"; } */ } return $xml; }
/** * @deprecated See QuickBooksXML::encode() instead */ public static function htmlspecialchars($string, $quote_style = ENT_COMPAT, $charset = 'ISO-8859-1', $double_encode = true) { /* if (!$charset) { $charset = 'ISO-8859-1'; } if (version_compare(PHP_VERSION, '5.2.3', '>=')) { return htmlspecialchars($string, $quote_style, $charset, $double_encode); } else { $string = htmlspecialchars($string, $quote_style, $charset); $fix = array( '&amp;' => '&', '&quot;' => '"', ); return str_replace(array_keys($fix), array_values($fix), $string); } */ return QuickBooks_XML::encode($str, true, $double_encode); }
/** * XML parsing recursive helper function * * @param string $xml * @param QuickBooks_XML_Node $root * @return void */ protected function _parseHelper($xml, &$Root, &$errnum, &$errmsg, $indent = 0) { $errnum = QUICKBOOKS_XML_ERROR_OK; $errmsg = ''; $arr = array(); $xml = trim($xml); if (!strlen($xml)) { return false; } $data = ''; $vstack = array(); $dstack = array(); // Remove comments while (false !== strpos($xml, '<!--')) { $start = strpos($xml, '<!--'); $end = strpos($xml, '-->', $start); if (false !== $start and false !== $end) { $xml = substr($xml, 0, $start) . substr($xml, $end + 3); } else { break; } } $raw = $xml; $current = 0; $last = ''; $i = 0; // Parse while (false !== strpos($xml, '<')) { $opentag_start = strpos($xml, '<'); $opentag_end = strpos($xml, '>'); $tag_w_attrs = trim(substr($xml, $opentag_start + 1, $opentag_end - $opentag_start - 1)); $tag = ''; $attributes = array(); $this->_extractAttributes($tag_w_attrs, $tag, $attributes); if (substr($tag_w_attrs, 0, 1) == '?') { // ignore } else { if (substr($tag_w_attrs, 0, 1) == '!') { // ignore } else { if (substr($tag_w_attrs, -1, 1) == '/') { // ***DO NOT*** completely ignore, auto-closed because it has no children // Completely ignoring causes some SOAP errors for requests like <serverVersion xmlns="http://developer.intuit.com/" /> // Shove the item on to the stack array_unshift($vstack, array($tag, $tag_w_attrs, $current + $opentag_end)); array_unshift($dstack, array($tag, $tag_w_attrs, $current + $opentag_end)); $key = key($vstack); $tmp = array_shift($vstack); $pop = $tag; $gnk = $tag_w_attrs; $pos = $current + $opentag_end; // there is no data, so empty data and the length is 0 $length = 0; $data = null; if (count($vstack)) { array_shift($dstack); } else { $dstack[$key] = array($pop, $gnk, $pos, $length, $data); } } else { if (substr($tag_w_attrs, 0, 1) == '/') { // NOTE: If you change the code here, you'll likely have to // change it in the above else () section as well, as that // section handles data-less tags like <serverVersion /> $tag = substr($tag, 1); $key = key($vstack); $tmp = array_shift($vstack); $pop = $tmp[0]; $gnk = $tmp[1]; $pos = $tmp[2]; if ($pop != $tag) { $errnum = QUICKBOOKS_XML_ERROR_MISMATCH; $errmsg = 'Mismatched tags, found: ' . $tag . ', expected: ' . $pop; return false; } $data = substr($raw, $pos, $current + $opentag_start - $pos); if (count($vstack)) { array_shift($dstack); } else { $dstack[$key] = array($pop, $gnk, $pos, $current + $opentag_start - $pos, $data); } } else { array_unshift($vstack, array($tag, $tag_w_attrs, $current + $opentag_end + 1)); array_unshift($dstack, array($tag, $tag_w_attrs, $current + $opentag_end + 1)); } } } } $xml = substr($xml, $opentag_end + 1); $current = $current + $opentag_end + 1; } if (strlen($xml)) { $errnum = QUICKBOOKS_XML_ERROR_GARBAGE; $errmsg = 'Found this garbage data at end of stream: ' . $xml; return false; } if (count($vstack)) { $errnum = QUICKBOOKS_XML_ERROR_DANGLING; $errmsg = 'XML stack still contains this after parsing: ' . var_export($vstack, true); return false; } //print_r($dstack); //exit; $dstack = array_reverse($dstack); $last = ''; foreach ($dstack as $node) { $tag = $node[0]; $tag_w_attrs = $node[1]; $start = $node[2]; if (count($node) < 5) { continue; } $length = $node[3]; $payload = $node[4]; $tmp = ''; $attributes = array(); $this->_extractAttributes($tag_w_attrs, $tmp, $attributes); $Node = new QuickBooks_XML_Node($tag); foreach ($attributes as $key => $value) { $value = QuickBooks_XML::decode($value, true); $Node->addAttribute($key, $value); } if (false !== strpos($payload, '<')) { // The tag contains child tags $tmp = $this->_parseHelper($payload, $Node, $errnum, $errmsg, $indent + 1); if (!$tmp) { return false; } } else { // This tag has no child tags contained inside it // Make sure we decode any entities $payload = QuickBooks_XML::decode($payload, true); $Node->setData($payload); } $Root->addChild($Node); $last = $tag; } return $Root; }
public function disconnect($app_username, $app_tenant, $force = false) { if ($arr = $this->_driver->oauthLoad($this->_key, $app_username, $app_tenant) and strlen($arr['oauth_access_token']) > 0 and strlen($arr['oauth_access_token_secret']) > 0) { $arr['oauth_consumer_key'] = $this->_consumer_key; $arr['oauth_consumer_secret'] = $this->_consumer_secret; $retr = $this->_request(QuickBooks_IPP_OAuth::METHOD_GET, QuickBooks_IPP_IntuitAnywhere::URL_CONNECT_DISCONNECT, array(), $arr['oauth_access_token'], $arr['oauth_access_token_secret']); // Extract the error code $code = (int) QuickBooks_XML::extractTagContents('ErrorCode', $retr); if ($code == 0 or $code == 270 or $force) { return $this->_driver->oauthAccessDelete($arr['app_username'], $arr['app_tenant']); } } return false; }
/** * * * */ public function voidOrRefund($Transaction, $amount = null, $salestax = null, $comment = null, $force_new_transaction = true) { $this->_setError(QuickBooks_MerchantService::ERROR_OK); $this->_log('voidOrRefund()', QUICKBOOKS_LOG_VERBOSE); if (!$this->isSignedOn()) { $this->signOn(); if ($this->errorNumber()) { return false; } } // Error checking if (!$Transaction instanceof QuickBooks_MerchantService_Transaction) { $this->_setError(QuickBooks_MerchantService::ERROR_PARAM, 'voidOrRefund() expects first parameter to be a Transaction object, got: ' . print_r($Transaction, true)); return false; } if (!is_numeric($amount)) { $this->_setError(QuickBooks_MerchantService::ERROR_PARAM, 'voidOrRefund() expects second parameter to be a float, got: ' . print_r($amount, true)); return false; } $transRequestID = $this->_transRequestID(QuickBooks_MerchantService::TYPE_VOIDORREFUND, $Transaction, $amount, $force_new_transaction); $xml = ''; $xml .= '<?xml version="1.0" encoding="utf-8"?>' . QUICKBOOKS_CRLF; $xml .= '<?qbmsxml version="4.1"?>' . QUICKBOOKS_CRLF; $xml .= '<QBMSXML>' . QUICKBOOKS_CRLF; $xml .= $this->_createSessionXML(); $xml .= ' <QBMSXMLMsgsRq>' . QUICKBOOKS_CRLF; $xml .= ' <CustomerCreditCardTxnVoidOrRefundRq>' . QUICKBOOKS_CRLF; $xml .= ' <TransRequestID>' . $transRequestID . '</TransRequestID>' . QUICKBOOKS_CRLF; $xml .= ' <CreditCardTransID>' . $Transaction->getTransactionID() . '</CreditCardTransID>' . QUICKBOOKS_CRLF; if ((double) $amount) { $xml .= ' <Amount>' . sprintf('%01.2f', (double) $amount) . '</Amount>' . QUICKBOOKS_CRLF; } if (!is_null($salestax) and (double) $salestax) { $xml .= ' <SalesTaxAmount>' . sprintf('%01.2f', (double) $salestax) . '</SalesTaxAmount>' . QUICKBOOKS_CRLF; } //<BatchID >STRTYPE</BatchID> <!-- optional --> if ($comment) { $xml .= ' <Comment>' . substr(QuickBooks_XML::encode($comment), 0, 500) . '</Comment>' . QUICKBOOKS_CRLF; } $xml .= ' </CustomerCreditCardTxnVoidOrRefundRq>' . QUICKBOOKS_CRLF; $xml .= ' </QBMSXMLMsgsRq>' . QUICKBOOKS_CRLF; $xml .= '</QBMSXML>' . QUICKBOOKS_CRLF; return $this->_doQBMS(QuickBooks_MerchantService::TYPE_VOIDORREFUND, 'QBMSXML/QBMSXMLMsgsRs/CustomerCreditCardTxnVoidOrRefundRs', $xml); }
protected function _parseIDS_v3($xml, $optype, $flavor, $version, &$xml_errnum, &$xml_errmsg, &$err_code, &$err_desc, &$err_db) { // Parse it $Parser = new QuickBooks_XML_Parser($xml); // Initial to success $xml_errnum = QuickBooks_XML::ERROR_OK; $err_code = QuickBooks_IPP::ERROR_OK; // Try to parse the XML IDS response $errnum = QuickBooks_XML::ERROR_OK; $errmsg = null; if ($Doc = $Parser->parse($errnum, $errmsg)) { $Root = $Doc->getRoot(); switch ($optype) { case QuickBooks_IPP_IDS::OPTYPE_CDC: $types = array(); $List = $Root->getChildAt('IntuitResponse CDCResponse'); foreach ($List->children() as $ObjList) { foreach ($ObjList->children() as $Child) { $type = $Child->name(); if (empty($types[$type])) { $types[$type] = array(); } $class = 'QuickBooks_IPP_Object_' . $Child->name(); $Object = new $class(); foreach ($Child->children() as $Data) { $this->_push($Data, $Object); } $types[$type][] = $Object; } } return $types; break; case QuickBooks_IPP_IDS::OPTYPE_ADD: // Parse an ADD type response return QuickBooks_IPP_IDS::buildIDType('', QuickBooks_XML::extractTagContents('Id', $xml)); case QuickBooks_IPP_IDS::OPTYPE_MOD: return true; // If we got this far, it was a success // If we got this far, it was a success case QuickBooks_IPP_IDS::OPTYPE_QUERY: $list = array(); $List = $Root->getChildAt('IntuitResponse QueryResponse'); $attrs = $List->attributes(); if (!array_key_exists('startPosition', $attrs) and array_key_exists('totalCount', $attrs)) { return $attrs['totalCount']; } else { foreach ($List->children() as $Child) { $class = 'QuickBooks_IPP_Object_' . $Child->name(); $Object = new $class(); foreach ($Child->children() as $Data) { $this->_push($Data, $Object); } $list[] = $Object; } return $list; } } } else { $xml_errnum = $errnum; $xml_errmsg = $errmsg; return false; } }
protected function _extractAttributes($tag_w_attrs, &$tag, &$attributes) { $tag = ''; $attributes = array(); $tmp = QuickBooks_XML::extractTagAttributes($tag_w_attrs, true); $tag = array_shift($tmp); $attributes = $tmp; /* print('extracting attributes from: {{' . $tag_w_attrs . '}}' . "\n"); print(' tag: [[' . $tag . ']]' . "\n"); print(' attrs: ' . print_r($attributes, true) . "\n"); print("\n"); */ return true; }
<DataExtName>Alternate Email</DataExtName> <DataExtType>STR255TYPE</DataExtType> <DataExtValue>helpdesk@stmatthews.edu</DataExtValue> </DataExtRet> </DataExtModRs> <DataExtModRs statusCode="0" statusSeverity="Info" statusMessage="Status OK"> <DataExtRet> <OwnerID>0</OwnerID> <DataExtName>Location</DataExtName> <DataExtType>STR255TYPE</DataExtType> <DataExtValue>Cayman</DataExtValue> </DataExtRet> </DataExtModRs> </QBXMLMsgsRs> </QBXML>'; $Parser = new QuickBooks_XML($xml); $err = ''; $err2 = ''; $Doc = $Parser->parse($err, $err2); $Root = $Doc->getRoot(); print_r($Root); exit; $children1 = $Doc->children(); foreach ($children1 as $child) { print_r($child->asXML()); } print "\n\n\n"; $children2 = $Doc->children('InvoiceLineAdd'); foreach ($children2 as $child) { print_r($child->asXML()); }
/** * * * */ protected static function _queryResponse($type, $List, $requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents, $callback_config = array()) { $type = strtolower($type); $Driver = QuickBooks_Driver_Singleton::getInstance(); $objects = array(); // For each one of the objects we got back in the qbXML response... foreach ($List->children() as $Node) { // If this object is a base-level object, we're going to keep track of it's TxnID or // ListID so that we can use it to tie child elements back to this base-level // element (about 20 or 30 lines below this is that code) // Child records get deleted, and then re-created with the same // qbsql_id values so that we don't muck up people's associated // records. This keeps track of deleted records so we can re-create // the records with the same qbsql_id values. $deleted = array(); // Convert the XML nodes to objects, based on the XML to SQL schema definitions in Schema.php $objects = array(); QuickBooks_Callbacks_SQL_Callbacks::_transformToSQLObjects('', $Node, $objects); //print_r($objects); //exit; // For each object we created from the XML nodes... // (might have created more than one, e.g. an Invoice, plus 10 InvoiceLines, plus a Invoice_DataExt, etc.) /* if (count($objects) > 1) { print_r($objects); exit; } */ // This keeps track of whether or not we're ignoring this entire batch of UPDATES/INSERTS $ignore_this_and_its_children = false; foreach ($objects as $key => $object) { $Object =& $object; if ($ignore_this_and_its_children) { // If we're supposed to ignore this object and it's children, then just continue continue; } $table = $Object->table(); $path = $Object->path(); $map = array(); QuickBooks_SQL_Schema::mapPrimaryKey($path, QUICKBOOKS_SQL_SCHEMA_MAP_TO_SQL, $map); // Special hack for preferences if ($Object->table() == 'preferences') { $map = array('qb_preferences', 'qbsql_external_id'); } //print_r($Object); //print_r($path); //print_r($map); //exit; // if ($table and count($map) and $map[0] and $map[1]) { $addMapTest = array(); $addMapTestOthers = array(); QuickBooks_SQL_Schema::mapToSchema(trim(QuickBooks_Utilities::actionToXMLElement($action)), QUICKBOOKS_SQL_SCHEMA_MAP_TO_SQL, $addMapTest, $addMapTestOthers); if (!isset($extra['IsAddResponse']) and !isset($extra['is_add_response']) or !(count($addMapTest) and $addMapTest[0]) or $map[0] != $addMapTest[0]) { // GARRETT'S bug Fix -- Arrays with primary keys consisting of multiple fields weren't updating properly // due to failure to check for arrays. $multipart = array(); if (is_array($map[1])) { foreach ($map[1] as $table_name) { $multipart[$table_name] = $object->get($table_name); } } else { $multipart[$map[1]] = $object->get($map[1]); } } else { $multipart[QUICKBOOKS_DRIVER_SQL_FIELD_ID] = $ID; } $hooks = array(); if (isset($callback_config['hooks'])) { $hooks = $callback_config['hooks']; } if ($tmp = $Driver->get(QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, $multipart)) { $actually_do_update = false; $actually_do_updaterelatives = false; $actually_do_deletechildren = false; if (isset($tmp[Quickbooks_Utilities::keyForAction($action)])) { // I have no idea what this does or what this is for.... // > EDIT: This keeps track of what the old TxnID or ListID is, so that we can use it to update relative tables $extra['AddResponse_OldKey'] = $tmp[Quickbooks_Utilities::keyForAction($action)]; $extra['temporary_TxnID_or_ListID_or_LineID'] = $tmp[Quickbooks_Utilities::keyForAction($action)]; } if (empty($extra['AddResponse_OldKey']) and Quickbooks_Utilities::keyForAction($action) == 'TxnID' and isset($tmp['TxnLineID'])) { //$extra['AddResponse_OldKey'] = $tmp->get("TxnLineID"); $extra['AddResponse_OldKey'] = $tmp['TxnLineID']; $extra['temporary_TxnID_or_ListID_or_LineID'] = $tmp['TxnLineID']; } // Make sure a conflict mode has been selected if (empty($callback_config['conflicts'])) { $callback_config['conflicts'] = null; } if (empty($callback_config['mode'])) { $callback_config['mode'] = QuickBooks_WebConnector_Server_SQL::MODE_READONLY; } if (isset($extra['is_query_response']) or isset($extra['is_import_response']) or isset($extra['is_mod_response']) or isset($extra['is_add_response'])) { // @TODO There should probably be some conflict handling code below to handle conflicts $actually_do_update = true; $actually_do_deletechildren = true; $actually_do_updaterelatives = true; } //$Driver->log('Diagnostics for incoming: is_query[' . !empty($extra['is_query_response']) . '], is_import[' . !empty($extra['is_import_response']) . '], is_mod[' . !empty($extra['is_mod_response']) . '], is_add[' . !empty($extra['is_add_response']) . '], conflict mode: ' . $callback_config['conflicts'] . '', null, QUICKBOOKS_LOG_DEVELOP); // Conflict handling code // @todo I think this should only apply to query and improt, right? I mean, if it's a mod or add, then // *of course* it was modified after resynced, thats how we knew to send it back to QuickBooks... if ($tmp[QUICKBOOKS_DRIVER_SQL_FIELD_MODIFY] > $tmp[QUICKBOOKS_DRIVER_SQL_FIELD_RESYNC] and $callback_config['mode'] != QuickBooks_WebConnector_Server_SQL::MODE_READONLY) { // CONFLICT resolution code switch ($callback_config['conflicts']) { case QuickBooks_WebConnector_Server_SQL::CONFLICT_NEWER: $msg = 'Conflict mode: (newer) ' . $callback_config['conflicts'] . ' is not supported right now.'; trigger_error($msg); die($msg); case QuickBooks_WebConnector_Server_SQL::CONFLICT_QUICKBOOKS: // QuickBooks is master, so remove all existing child records of this record, then apply the QuickBooks version update $actually_do_deletechildren = true; $actually_do_update = true; //QuickBooks_Callbacks_SQL_Callbacks::_DeleteChildren($table, $user, $action, $ID, $object, $extra); //$Driver->update(QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, $object, array( $multipart )); break; case QuickBooks_WebConnector_Server_SQL::CONFLICT_CALLBACK: $msg = 'Conflict mode: (callback) ' . $callback_config['conflicts'] . ' is not supported right now.'; trigger_error($msg); die($msg); break; case QuickBooks_WebConnector_Server_SQL::CONFLICT_SQL: // The SQL table is the master table, but we have an out-of-date EditSequence value // In this case, what we want to do is update our record to the latest EditSequence value, // and then re-queue the object so that it gets updated the next time the sync runs to // the values from the SQL record $tmp_editsequence_update = new QuickBooks_SQL_Object($table, null); $tmp_editsequence_update->set('EditSequence', $object->get('EditSequence')); // *Just* update the EditSequence value $Driver->update(QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, $tmp_editsequence_update, array($multipart), false); // Re-queue it so the conflict gets resolved $Driver->queueEnqueue($user, QuickBooks_Utilities::convertActionToMod($action), $tmp[QUICKBOOKS_DRIVER_SQL_FIELD_ID], true, QUICKBOOKS_SERVER_SQL_CONFLICT_QUEUE_PRIORITY, $extra); break; case QuickBooks_WebConnector_Server_SQL::CONFLICT_LOG: default: if (isset($extra['IsModResponse']) or isset($extra['is_mod_response']) or isset($extra['is_add_response'])) { // If it's actually a mod response, then this isn't actually a conflict, it's just the mod response happening normally $actually_do_update = true; $actually_do_deletechildren = true; $actually_do_updaterelatives = true; } else { // Log it...? $Driver->log('Conflict occured at: ' . $table, null, QUICKBOOKS_LOG_NORMAL); } break; } } //print_r($object); //print_r($tmp); // If the EditSequence has not changed since the last time this record was updated, // then we can just skip this update because everything should already be up to // date. // // This works around a very important issue as a result of Mod requests. When a Mod // request is issued and succeeds, it updates the record. Then, on the next Query // request, the record will be re-imported because the DateModified timestamp was // updated as a result of the Mod request. However, if the record is modified // by the end-user in between that Mod request and Import, the changes the user // made will be overwritten/a conflict will occur *even though the Query response // was only due to a Mod request that we sent ourselves* and the record in // QuickBooks never actually changed between the Mod and the Query. if (empty($extra['is_query_response']) and isset($tmp['EditSequence']) and $tmp['EditSequence'] == $object->get('EditSequence')) { $actually_do_update = false; $actually_do_deletechildren = false; $actually_do_updaterelatives = false; //$Driver->log('Ignoring UPDATE: ' . $table . ': ' . print_r($object, true) . ' due to EditSequence equality.', null, QUICKBOOKS_LOG_DEVELOP); // Make sure we ignore the children too (invoice lines, data exts, etc.) $ignore_this_and_its_children = true; } if ($callback_config['mode'] == QuickBooks_WebConnector_Server_SQL::MODE_WRITEONLY) { // In WRITE-ONLY mode, we only write changes to QuickBooks, but never read them back // (but should we update the EditSequence still?) $actually_do_update = false; $actually_do_deletechildren = false; $actually_do_updaterelatives = false; } //$deleted = array(); if ($actually_do_deletechildren) { QuickBooks_Callbacks_SQL_Callbacks::_deleteChildren($table, $user, $action, $ID, $object, $extra, $deleted); //$Driver->log('Immediately after deleting: ' . print_r($deleted, true)); } if ($actually_do_updaterelatives) { QuickBooks_Callbacks_SQL_Callbacks::_updateRelatives($table, $user, $action, $ID, $object, $extra); } if ($actually_do_update) { // This handles setting certain special fields (SortOrder, booleans, etc.) QuickBooks_Callbacks_SQL_Callbacks::_massageUpdateRecord($table, $object); //print('applying updates, and with these deletes: '); //print_r($deleted); $object->set(QUICKBOOKS_DRIVER_SQL_FIELD_MODIFY, date('Y-m-d H:i:s')); //$Driver->log('Applying UPDATE: ' . $table . ': ' . print_r($object, true) . ', where: ' . print_r($multipart, true), null, QUICKBOOKS_LOG_DEVELOP); $Driver->update(QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, $object, array($multipart)); $qbsql_id = null; if (!empty($multipart[QUICKBOOKS_DRIVER_SQL_FIELD_ID])) { $qbsql_id = $multipart[QUICKBOOKS_DRIVER_SQL_FIELD_ID]; } // Call any hooks that occur when a record is updated $hook_data = array('hook' => QuickBooks_SQL::HOOK_SQL_UPDATE, 'user' => $user, 'table' => QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, 'object' => $object, 'data' => $object->asArray(), 'qbsql_id' => $qbsql_id, 'where' => array($multipart)); $err = null; QuickBooks_Callbacks_SQL_Callbacks::_callHooks($hooks, QuickBooks_SQL::HOOK_SQL_UPDATE, $requestID, $user, $err, $hook_data, $callback_config); } else { //$Driver->log('Skipping UPDATE: ' . $table . ': ' . print_r($object, true) . ', where: ' . print_r($multipart, true), null, QUICKBOOKS_LOG_DEVELOP); } if ($actually_do_update and isset($extra['is_add_response'])) { // It's an add response, call the hooks $qbsql_id = null; if (!empty($multipart[QUICKBOOKS_DRIVER_SQL_FIELD_ID])) { $qbsql_id = $multipart[QUICKBOOKS_DRIVER_SQL_FIELD_ID]; } // Call any hooks that occur when a record is updated $hook_data = array('hook' => QuickBooks_SQL::HOOK_QUICKBOOKS_INSERT, 'user' => $user, 'table' => QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, 'object' => $object, 'data' => $object->asArray(), 'qbsql_id' => $qbsql_id, 'where' => array($multipart)); $err = null; QuickBooks_Callbacks_SQL_Callbacks::_callHooks($hooks, QuickBooks_SQL::HOOK_QUICKBOOKS_INSERT, $requestID, $user, $err, $hook_data, $callback_config); } else { if ($actually_do_update and isset($extra['is_mod_response'])) { // It's an add response, call the hooks $qbsql_id = null; if (!empty($multipart[QUICKBOOKS_DRIVER_SQL_FIELD_ID])) { $qbsql_id = $multipart[QUICKBOOKS_DRIVER_SQL_FIELD_ID]; } // Call any hooks that occur when a record is updated $hook_data = array('hook' => QuickBooks_SQL::HOOK_QUICKBOOKS_UPDATE, 'user' => $user, 'table' => QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, 'object' => $object, 'data' => $object->asArray(), 'qbsql_id' => $qbsql_id, 'where' => array($multipart)); $err = null; QuickBooks_Callbacks_SQL_Callbacks::_callHooks($hooks, QuickBooks_SQL::HOOK_QUICKBOOKS_UPDATE, $requestID, $user, $err, $hook_data, $callback_config); } } } else { // The record *DOES NOT* exist in the current table, so just INSERT it if ($callback_config['mode'] != QuickBooks_WebConnector_Server_SQL::MODE_WRITEONLY) { // This handles setting certain special fields (booleans, SortOrder, etc.) QuickBooks_Callbacks_SQL_Callbacks::_massageInsertRecord($table, $object); //$Driver->log('DELETED: ' . print_r($deleted, true) . ', table: [' . $table . ']'); // This makes sure that re-inserted child records are re-inserted with the // same qbsql_id values if (isset($deleted[$table][QUICKBOOKS_TXNLINEID][$object->get(QUICKBOOKS_TXNLINEID)][0])) { $tmp = $deleted[$table][QUICKBOOKS_TXNLINEID][$object->get(QUICKBOOKS_TXNLINEID)]; unset($deleted[$table][QUICKBOOKS_TXNLINEID][$object->get(QUICKBOOKS_TXNLINEID)]); // Can't use this anymore after it's been used for an INSERT $object->set(QUICKBOOKS_DRIVER_SQL_FIELD_ID, $tmp[0]); $object->set(QUICKBOOKS_DRIVER_SQL_FIELD_USERNAME_ID, $tmp[1]); $object->set(QUICKBOOKS_DRIVER_SQL_FIELD_EXTERNAL_ID, $tmp[2]); } else { if (isset($deleted[$table][QUICKBOOKS_TXNLINEID]) and count($deleted[$table][QUICKBOOKS_TXNLINEID]) > 0) { // We deleted some child from this table, and what we deleted *should* // have been sent to QuickBooks and received from QuickBooks in the // same order... so we should be able to just fetch the next deleted // thing, and re-use that qbsql_id value reset($deleted[$table][QUICKBOOKS_TXNLINEID]); $tmp = array_shift($deleted[$table][QUICKBOOKS_TXNLINEID]); // Remove it from the list so it can't be used anymore $object->set(QUICKBOOKS_DRIVER_SQL_FIELD_ID, $tmp[0]); $object->set(QUICKBOOKS_DRIVER_SQL_FIELD_USERNAME_ID, $tmp[1]); $object->set(QUICKBOOKS_DRIVER_SQL_FIELD_EXTERNAL_ID, $tmp[2]); } } if ('' == $object->get(QUICKBOOKS_DRIVER_SQL_FIELD_USERNAME_ID)) { $object->set(QUICKBOOKS_DRIVER_SQL_FIELD_USERNAME_ID, null); } if ('' == $object->get(QUICKBOOKS_DRIVER_SQL_FIELD_EXTERNAL_ID)) { $object->set(QUICKBOOKS_DRIVER_SQL_FIELD_EXTERNAL_ID, null); } //print_r($object); //$Driver->log('Applying INSERT: ' . $table . ': ' . print_r($object, true), null, QUICKBOOKS_LOG_DEVELOP); $object->set(QUICKBOOKS_DRIVER_SQL_FIELD_MODIFY, date('Y-m-d H:i:s')); $Driver->insert(QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, $object); $last = $Driver->last(); // Call any hooks that occur when a record is inserted $hook_data = array('hook' => QuickBooks_SQL::HOOK_SQL_INSERT, 'user' => $user, 'table' => QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, 'object' => $object, 'data' => $object->asArray(), 'qbsql_id' => $last); $err = null; QuickBooks_Callbacks_SQL_Callbacks::_callHooks($hooks, QuickBooks_SQL::HOOK_SQL_INSERT, $requestID, $user, $err, $hook_data, $callback_config); } else { //$Driver->log('Skipping INSERT: ' . $table . ': ' . print_r($object, true), null, QUICKBOOKS_LOG_DEVELOP); } } // Triggered actions // Receive Payment => reload any linked invoices // Invoice => reload the customer // Purchase Order => reload the vendor QuickBooks_Callbacks_SQL_Callbacks::_triggerActions($user, $table, $Object, $action); } } } // Find out if we need to iterate further to get more results $matches = array(); //$iterator_count = ereg('iteratorRemainingCount="([0-9]*)" iteratorID="([^"]*)"', $xml, $matches); $matched_iteratorID = QuickBooks_XML::extractTagAttribute('iteratorID', $xml); $matched_iteratorRemainingCount = QuickBooks_XML::extractTagAttribute('iteratorRemainingCount', $xml); // If an iterator was used and there's results remaining if ($matched_iteratorID and $matched_iteratorRemainingCount > 0) { $extra = array('iteratorID' => $matched_iteratorID); // Set the iteratorID to be used /* // What is this code trying to do...? This doesn't look right... if ( (int) $matches[1] < QUICKBOOKS_SERVER_SQL_ITERATOR_MAXRETURNED) { $extra['maxReturned'] = (int) $matches[1]; } */ // queueEnqueue($user, $action, $ident, $replace = true, $priority = 0, $extra = null, $qbxml = null) $Driver->queueEnqueue($user, $action, null, true, QUICKBOOKS_SERVER_SQL_ITERATOR_PRIORITY, $extra); // Queue up another go! } else { // We're done with this iterator! // When the current iterator started... $module = __CLASS__; $type = null; $opts = null; // configRead($user, $module, $key, &$type, &$opts) $curr_sync_datetime = $Driver->configRead($user, $module, QuickBooks_Callbacks_SQL_Callbacks::_keySyncCurr($action), $type, $opts); // last sync started... //print('WRITING: [' . $curr_sync_datetime . '] from /' . $module . '/ {' . QuickBooks_Callbacks_SQL_Callbacks::_keySyncCurr($action) . '}'); // Start of the iteration, update the previous timestamp to NOW $Driver->configWrite($user, $module, QuickBooks_Callbacks_SQL_Callbacks::_keySyncPrev($action), $curr_sync_datetime, null); } }
public function clientResult($MOD, $DO) { $Client = new QuickBooks_Client($this->_soapURL()); switch ($this->_soapMethod()) { case 'authenticate': $params = $this->_authenticateParameters(); $result = $Client->authenticate($params['username'], $params['password']); break; case 'clientVersion': break; case 'serverVersion': break; case 'sendRequestXML': $params = $this->_sendRequestXMLParameters(); $result = $Client->sendRequestXML($params['ticket'], $params['hcpresponse'], $params['companyfile'], $params['country'], $params['majorversion'], $params['minorversion']); break; case 'receiveResponseXML': $params = $this->_receiveResponseXMLParameters(); $result = $Client->receiveResponseXML($params['ticket'], $params['response'], $params['hresult'], $params['message']); break; } $this->_skin->assign('soap_method', $this->_soapMethod()); $this->_skin->assign('soap_url', $this->_soapURL()); switch ($this->_soapMethod()) { case 'authenticate': $this->_skin->assign('new_soap_method', 'sendRequestXML'); break; case 'sendRequestXML': $this->_skin->assign('new_soap_method', 'receiveResponseXML'); break; case 'receiveResponseXML': $this->_skin->assign('new_soap_method', 'sendRequestXML'); break; } $raw_request = $Client->getLastRequest(); $errnum = 0; $errmsg = ''; $Parser = new QuickBooks_XML($raw_request); $formatted_request = $Parser->beautify($errnum, $errmsg, false); $raw_response = $Client->getLastResponse(); $errnum = 0; $errmsg = ''; $Parser = new QuickBooks_XML($raw_response); $formatted_response = $Parser->beautify($errnum, $errmsg, false); $this->_skin->assign('result', $result); $this->_skin->assign('soap_raw_request', $raw_request); $this->_skin->assign('soap_formatted_request', $formatted_request); $this->_skin->assign('soap_raw_response', $raw_response); $this->_skin->assign('soap_formatted_response', $formatted_response); $this->_skin->display('Tests/clientResult.tpl'); }
<Type>Hen</Type> </Animal> <Animal id="3"> <Name>Wasabi</Name> <Type>Hen</Type> <Note>Wasabi & Yamaguchi are in *loooovvvveee*</Note> </Animal> </Animals>'; print "\n"; print 'List of animal names: ' . "\n"; $Parser->load($xml2); $errnum = 0; $errmsg = ''; if ($Parser->validate($errnum, $errmsg)) { $Doc = $Parser->parse($errnum, $errmsg); $Root = $Doc->getRoot(); $List = $Root->getChildAt('Animals'); foreach ($List->children() as $Animal) { $name = $Animal->getChildDataAt('Animal Name'); $note = $Animal->getChildDataAt('Animal Note'); print "\t" . $name . ' (' . $note . ')' . "\n"; } } print "\n"; print 'Error number: ' . $errnum . "\n"; print 'Error message: ' . $errmsg . "\n"; $value = 'Keith & Shannon went to the store!'; print "\n"; print 'Double encoded: ' . QuickBooks_XML::encode(QuickBooks_XML::encode($value)) . "\n"; print 'NOT double encoded: ' . QuickBooks_XML::encode(QuickBooks_XML::encode($value, true, false), true, false) . "\n"; print "\n";
/** * Take a qbXML schema and transform that schema to an SQL schema definition * * @param string $xml The XML string to transform * @param array $tables An array of... erm... something? * @return boolean */ public static function mapSchemaToSQLDefinition($xml, &$tables) { $Parser = new QuickBooks_XML($xml); $errnum = 0; $errmsg = ''; $tmp = $Parser->parse($errnum, $errmsg); $tmp = $tmp->children(); $base = current($tmp); $tmp = $base->children(); $rs = next($tmp); foreach ($rs->children() as $qbxml) { QuickBooks_SQL_Schema::_transform('', $qbxml, $tables); } /* while (count($subtables) > 0) { $node = array_shift($subtables); $subsubtables = array(); $tables[] = QuickBooks_SQL_Schema::_transform('', $node, $subsubtables); $subtables = array_merge($subtables, $subsubtables); } */ // The code below tries to guess as a good set of indexes to use for // any database tables we've generated from the schema. The code looks // at all of the fields in the table and if any of them are *ListID or // *TxnID it makes them indexes. // This is a list of field names that will *always* be assigned // indexes, regardless of what table they are in $always_index_fields = array('Name', 'FullName', 'EntityType', 'TxnType', 'Email', 'IsActive', 'RefNumber', 'Address_State', 'Address_Country', 'BillAddress_State', 'BillAddress_Country', 'ShipAddress_State', 'ShipAddress_Country', 'CompanyName', 'LastName', 'TxnDate', 'IsPaid', 'IsPending', 'IsManuallyClosed', 'IsFullyReceived', 'IsToBePrinted', 'IsToBeEmailed', 'IsFullyInvoiced'); // This is a list of table.field names that will be assigned indexes $always_index_tablefields = array(); /* '*FullName', '*ListID', '*TxnID', '*EntityType', '*TxnType', '*LineID', */ foreach ($tables as $table => $tabledef) { $uniques = array(); $indexes = array(); foreach ($tabledef[1] as $field => $fielddef) { if ($field == 'ListID' or $field == 'TxnID' or $field == 'Name') { // We can't apply indexes to TEXT columns, so we need to // check and make sure the column isn't of type TEXT // before we decide to use this as an index if ($fielddef[0] != QUICKBOOKS_DRIVER_SQL_TEXT) { $uniques[] = $field; } } else { if (substr($field, -6, 6) == 'ListID' or substr($field, -5, 5) == 'TxnID' or substr($field, -6, 6) == 'LineID' or in_array($field, $always_index_fields) or in_array($table . '.' . $field, $always_index_tablefields)) { // We can't apply indexes to TEXT columns, so we need to // check and make sure the column isn't of type TEXT // before we decide to use this as an index if ($fielddef[0] != QUICKBOOKS_DRIVER_SQL_TEXT) { $indexes[] = $field; } } } } //print_r($indexes); //print_r($uniques); $tables[$table][3] = $indexes; $tables[$table][4] = $uniques; } return true; }
/** * */ protected function _hasErrors($response) { // @todo This should first check for HTTP errors // ... // v3 errors if (false !== strpos($response, '<Error')) { $errcode = QuickBooks_XML::extractTagAttribute('code', $response); $errtext = QuickBooks_XML::extractTagContents('Message', $response); $errdetail = QuickBooks_XML::extractTagContents('Detail', $response); $this->_setError($errcode, $errtext, $errdetail); return true; // Yes, there's an error! } else { // Check for generic IPP XML node errors $errcode = QuickBooks_XML::extractTagContents('errcode', $response); $errtext = QuickBooks_XML::extractTagContents('errtext', $response); $errdetail = QuickBooks_XML::extractTagContents('errdetail', $response); if ($errcode != QuickBooks_IPP::OK) { // Has errors! $this->_setError($errcode, $errtext, $errdetail); return true; } // Check for IDS XML error codes $errorcode = QuickBooks_XML::extractTagContents('ErrorCode', $response); $errordesc = QuickBooks_XML::extractTagContents('ErrorDesc', $response); if ($errorcode) { $this->_setError($errorcode, $errordesc); return true; } // Does not have any errors return false; } }
<?php require_once '../QuickBooks.php'; $data = '<QBXML><something>stuff</something><CustomerQueryRs iteratorRemainingCount="364q34" iteratorID="{1234-1234-1234}">...</CustomerQueryRs></QBXML>'; print 'contents: ' . QuickBooks_XML::extractTagContents('something', $data) . "\n"; print 'attribute: ' . QuickBooks_XML::extractTagAttribute('iteratorRemainingCount', $data) . "\n"; $data = '<CustomerQueryRs iteratorRemainingCount="123" iteratorID="{1234-1234-1234}">'; print 'attribuets: ' . print_r(QuickBooks_XML::extractTagAttributes($data, true), true) . "\n";