/** * * * @param QuickBooks_XML_Node $root * @param string $path * @param QuickBooks_XML_Node $child * @param boolean $create * @return boolean */ protected function _addChildAtHelper(&$root, $path, $node, $create = false) { if (false !== strpos($path, ' ') and false === strpos($path, '/')) { $path = str_replace(' ', '/', $path); } $explode = explode('/', $path); /*$explode = explode(' ', $path);*/ $current = array_shift($explode); $next = current($explode); if ($path == $root->name()) { return $root->addChild($node); } else { $path = implode('/', $explode); foreach ($root->children() as $child) { if ($child->name() == $next) { return $this->_addChildAtHelper($child, $path, $node, $create); } } } if ($create) { $root->addChild(new QuickBooks_XML_Node($next)); foreach ($root->children() as $child) { if ($child->name() == $next) { return $this->_addChildAtHelper($child, $path, $node, $create); } } } return false; }
protected static function _ChildObjectsToXML($type, $action, $children, $parentPath = '') { $Driver = QuickBooks_Driver_Singleton::getInstance(); $nodes = array(); $file = '/QuickBooks/QBXML/Schema/Object/' . QuickBooks_Utilities::actionToRequest($action) . '.php'; $class = 'QuickBooks_QBXML_Schema_Object_' . QuickBooks_Utilities::actionToRequest($action); QuickBooks_Loader::load($file); $schema_object = new $class(); $usePath = ''; if ($parentPath != '') { $usePath .= $parentPath . ' '; } foreach ($children as $child) { // Figure out which LinkedTxn method should be used... if (strpos($child['table'], "linkedtxn") !== false) { if (stripos($action, "add") !== false) { $part = preg_replace("/add/i", "", $action); $part .= "LineAdd"; } else { if (stripos($action, 'mod') !== false) { $part = preg_replace("/mod/i", "", $action); $part .= "LineMod"; } } if ($schema_object->exists($usePath . 'LinkToTxnID')) { $Node = new QuickBooks_XML_Node("LinkToTxnID", $child['data']->get("ToTxnID")); $nodes[count($nodes)] = $Node; continue; } else { if ($schema_object->exists($action . ' ' . $part . ' ' . 'LinkToTxn')) { $Node = new QuickBooks_XML_Node("LinkToTxnID", $child['data']->get("ToTxnID")); $nodes[count($nodes)] = $Node; continue; } else { if ($schema_object->exists($usePath . 'LinkedTxn')) { $Node = new QuickBooks_XML_Node("LinkToTxnID", $child['data']->get("ToTxnID")); $nodes[count($nodes)] = $Node; continue; } else { if ($schema_object->exists($action . ' ' . $part . ' ' . 'LinkedTxn')) { $Node = new QuickBooks_XML_Node("LinkToTxnID", $child['data']->get("ToTxnID")); $nodes[count($nodes)] = $Node; continue; } else { if ($schema_object->exists($usePath . 'ApplyCheckToTxnAdd')) { $Node = new QuickBooks_XML_Node("ApplyCheckToTxnAdd"); $Node->setChildDataAt($Node->name() . ' ' . 'TxnID', $child['data']->get("ToTxnID")); $Node->setChildDataAt($Node->name() . ' ' . 'Amount', $child['data']->get("ToTxnID")); $nodes[count($nodes)] = $Node; continue; } else { if ($schema_object->exists($usePath . 'ApplyCheckToTxnMod')) { $Node = new QuickBooks_XML_Node("ApplyCheckToTxnMod"); $Node->setChildDataAt($Node->name() . ' ' . 'TxnID', $child['data']->get("ToTxnID")); $Node->setChildDataAt($Node->name() . ' ' . 'Amount', $child['data']->get("ToTxnID")); $nodes[count($nodes)] = $Node; continue; } else { continue; } } } } } } } else { if (strpos($child['table'], "dataext") !== false) { continue; } } $map = ''; $others = array(); QuickBooks_SQL_Schema::mapToSchema($child['table'] . '.*', QUICKBOOKS_SQL_SCHEMA_MAP_TO_XML, $map, $others); $map = str_replace(' *', '', $map); $explode = explode(' ', $map); $first = trim(current($explode)); $map = trim(implode(' ', array_slice($explode, 1))); if (stripos($action, 'add') !== false) { $map = str_replace('Ret', 'Add', $map); } else { $map = str_replace('Ret', 'Mod', $map); } // Journal entries have an unusual JournalEntryMod syntax. Instead of // the typical CreditLineMod and DebitLineMod entries, they instead // have just a single combined entry, JournalLineMod. if ($action == QUICKBOOKS_MOD_JOURNALENTRY) { if ($child['table'] == 'journalentry_journaldebitline' or $child['table'] == 'journalentry_journalcreditline') { $map = 'JournalLineMod'; } } $Node = new QuickBooks_XML_Node($map); /* $retArr[$index]["table"] = $table; $retArr[$index]["data"] = QuickBooks_SQL_Object($table, null, $arr); $retArr[$index]["children"] */ foreach ($child['data']->asArray() as $field => $value) { $map = ''; $others = array(); QuickBooks_SQL_Schema::mapToSchema($child['table'] . '.' . $field, QUICKBOOKS_SQL_SCHEMA_MAP_TO_XML, $map, $others); if ($Driver->foldsToLower()) { $retpos = strpos($map, 'Ret '); $retval = substr($map, 0, $retpos + 4); $map = substr($map, $retpos + 4); if (stripos($action, 'add') !== false) { $map = str_replace('Ret ', 'Add ', $map); } else { $map = str_replace('Ret ', 'Mod ', $map); } //print('unfolding: {' . $map . '}' . "\n"); $map = $schema_object->unfold($map); //print(' unfolded to: [' . $map . ']' . "\n"); } //print($field . ' => ' . $value . "\n"); //print_r($map); //print("\n\n"); if (!$map or !strlen($value)) { continue; } // OK, the paths look like this: // CustomerRet FirstName // // We don't need the 'CustomerRet' part of it, that's actually incorrect, so we'll strip it off $explode = explode(' ', $map); $first = trim(current($explode)); $map = trim(implode(' ', array_slice($explode, 1))); if (stripos($action, "add") !== false) { $map = str_replace("Ret", "Add", $map); } else { $map = str_replace("Ret", "Mod", $map); } $map = preg_replace("/.*" . $Node->name() . " /", "", $map); /* if (strtolower($Node->name()) == "estimatelinemod" and strpos($map, 'TxnLineID') !== false ) { $value = -1; } */ if (false === strpos($map, ' ')) { if ($schema_object->exists($usePath . $Node->name() . ' ' . $map)) { $use_in_request = true; switch ($schema_object->dataType($usePath . $Node->name() . ' ' . $map)) { case 'AMTTYPE': $value = str_replace(',', '', number_format($value, 2)); break; case 'BOOLTYPE': if ($value == 1) { $value = 'true'; } else { if ($value == 0) { $value = 'false'; } else { $use_in_request = false; } } break; default: break; } if ($use_in_request) { $Child = new QuickBooks_XML_Node($map); $Child->setData($value); $Node->addChild($Child); } } else { // ignore it } } else { // Please see comments about JournalEntries above! if ($action == QUICKBOOKS_MOD_JOURNALENTRY) { $map = str_replace(array('JournalCreditLine ', 'JournalDebitLine '), '', $map); } if ($schema_object->exists($usePath . $Node->name() . ' ' . $map)) { $use_in_request = true; switch ($schema_object->dataType($usePath . $Node->name() . ' ' . $map)) { case 'AMTTYPE': $value = str_replace(',', '', number_format($value, 2)); break; case 'BOOLTYPE': if ($value == 1) { $value = 'true'; } else { if ($value == 0) { $value = 'false'; } else { $use_in_request = false; } } break; default: break; } if ($use_in_request) { $Node->setChildDataAt($Node->name() . ' ' . $map, $value, true); } } } } $tNodes = QuickBooks_Callbacks_SQL_Callbacks::_ChildObjectsToXML(strtolower($child['table']), $action, $child['children'], $usePath . $Node->name()); foreach ($tNodes as $tn) { $Node->addChild($tn); } $nodes[count($nodes)] = $Node; } return $nodes; }
protected static function _ChildObjectsToXML($type, $action, $children, $parentPath = '') { $nodes = array(); $file = 'QuickBooks/QBXML/Schema/Object/' . QuickBooks_Utilities::actionToRequest($action) . '.php'; $class = 'QuickBooks_QBXML_Schema_Object_' . QuickBooks_Utilities::actionToRequest($action); require_once $file; $schema_object = new $class(); $usePath = ''; if ($parentPath != "") { $usePath .= $parentPath . ' '; } foreach ($children as $child) { // Figure out which LinkedTxn method should be used... if (strpos($child['table'], "linkedtxn") !== false) { if (stripos($action, "add") !== false) { $part = preg_replace("/add/i", "", $action); $part .= "LineAdd"; } else { if (stripos($action, "mod") !== false) { $part = preg_replace("/mod/i", "", $action); $part .= "LineMod"; } } if ($schema_object->exists($usePath . 'LinkToTxnID')) { $Node = new QuickBooks_XML_Node("LinkToTxnID", $child['data']->get("ToTxnID")); $nodes[count($nodes)] = $Node; continue; } else { if ($schema_object->exists($action . ' ' . $part . ' ' . 'LinkToTxn')) { $Node = new QuickBooks_XML_Node("LinkToTxnID", $child['data']->get("ToTxnID")); $nodes[count($nodes)] = $Node; continue; } else { if ($schema_object->exists($usePath . 'LinkedTxn')) { $Node = new QuickBooks_XML_Node("LinkToTxnID", $child['data']->get("ToTxnID")); $nodes[count($nodes)] = $Node; continue; } else { if ($schema_object->exists($action . ' ' . $part . ' ' . 'LinkedTxn')) { $Node = new QuickBooks_XML_Node("LinkToTxnID", $child['data']->get("ToTxnID")); $nodes[count($nodes)] = $Node; continue; } else { if ($schema_object->exists($usePath . 'ApplyCheckToTxnAdd')) { $Node = new QuickBooks_XML_Node("ApplyCheckToTxnAdd"); $Node->setChildDataAt($Node->name() . ' ' . 'TxnID', $child['data']->get("ToTxnID")); $Node->setChildDataAt($Node->name() . ' ' . 'Amount', $child['data']->get("ToTxnID")); $nodes[count($nodes)] = $Node; continue; } else { if ($schema_object->exists($usePath . 'ApplyCheckToTxnMod')) { $Node = new QuickBooks_XML_Node("ApplyCheckToTxnMod"); $Node->setChildDataAt($Node->name() . ' ' . 'TxnID', $child['data']->get("ToTxnID")); $Node->setChildDataAt($Node->name() . ' ' . 'Amount', $child['data']->get("ToTxnID")); $nodes[count($nodes)] = $Node; continue; } else { continue; } } } } } } } else { if (strpos($child['table'], "dataext") !== false) { continue; } } $map = ''; $others = array(); QuickBooks_SQL_Schema::mapToSchema($child['table'] . ".*", QUICKBOOKS_SQL_SCHEMA_MAP_TO_XML, $map, $others); $map = str_replace(" *", "", $map); $explode = explode(' ', $map); $first = trim(current($explode)); $map = trim(implode(' ', array_slice($explode, 1))); if (stripos($action, "add") !== false) { $map = str_replace("Ret", "Add", $map); } else { $map = str_replace("Ret", "Mod", $map); } $Node = new QuickBooks_XML_Node($map); /* $retArr[$index]["table"] = $table; $retArr[$index]["data"] = QuickBooks_SQL_Object($table, null, $arr); $retArr[$index]["children"] */ foreach ($child['data']->asArray() as $field => $value) { $map = ''; $others = array(); QuickBooks_SQL_Schema::mapToSchema($child['table'] . '.' . $field, QUICKBOOKS_SQL_SCHEMA_MAP_TO_XML, $map, $others); /* print($field . ' => ' . $value . "\n"); print_r($map); print("\n\n"); */ if (!$map or !strlen($value)) { continue; } // OK, the paths look like this: // CustomerRet FirstName // // We don't need the 'CustomerRet' part of it, that's actually incorrect, so we'll strip it off $explode = explode(' ', $map); $first = trim(current($explode)); $map = trim(implode(' ', array_slice($explode, 1))); if (stripos($action, "add") !== false) { $map = str_replace("Ret", "Add", $map); } else { $map = str_replace("Ret", "Mod", $map); } $map = preg_replace("/.*" . $Node->name() . " /", "", $map); if (strtolower($Node->name()) == "estimatelinemod" and strpos($map, 'TxnLineID') !== false) { $value = -1; } if (false === strpos($map, ' ')) { if ($schema_object->exists($usePath . $Node->name() . ' ' . $map)) { $use_in_request = true; switch ($schema_object->dataType($usePath . $Node->name() . ' ' . $map)) { case 'AMTTYPE': $value = str_replace(",", "", number_format($value, 2)); break; case 'BOOLTYPE': if ($value == 1) { $value = 'true'; } else { if ($value == 0) { $value = 'false'; } else { $use_in_request = false; } } break; default: break; } if ($use_in_request) { $Child = new QuickBooks_XML_Node($map); $Child->setData($value); $Node->addChild($Child); } } else { //ignore it } } else { if ($schema_object->exists($usePath . $Node->name() . ' ' . $map)) { $use_in_request = true; switch ($schema_object->dataType($usePath . $Node->name() . ' ' . $map)) { case 'AMTTYPE': $value = str_replace(",", "", number_format($value, 2)); break; case 'BOOLTYPE': if ($value == 1) { $value = 'true'; } else { if ($value == 0) { $value = 'false'; } else { $use_in_request = false; } } break; default: break; } if ($use_in_request) { $Node->setChildDataAt($Node->name() . ' ' . $map, $value, true); } } } } $tNodes = QuickBooks_Server_SQL_Callbacks::_ChildObjectsToXML(strtolower($child['table']), $action, $child['children'], $usePath . $Node->name()); foreach ($tNodes as $tn) { $Node->addChild($tn); } $nodes[count($nodes)] = $Node; } return $nodes; }
public function asQBXML($request, $version = null, $locale = null, $root = null) { $todo_for_empty_elements = QuickBooks_XML::XML_DROP; $indent = "\t"; // Call any cleanup routines $this->_cleanup(); // if (strtolower(substr($request, -2, 2)) != 'rq') { $request .= 'Rq'; } $Request = new QuickBooks_XML_Node($request); if ($schema = $this->_schema($request)) { $tmp = array(); // Restrict it to a specific qbXML version? if ($version) { } // Restrict it to a specific qbXML locale? if ($locale) { // List of fields which are not supported for some versions of qbXML if (strlen($locale) == 2) { // The OSR lists locales as 'QBOE', 'QBUK', 'QBCA', etc. vs. our QUICKBOOKS_LOCALE_* constants of just 'OE', 'UK', 'CA', etc. $locale = 'QB' . $locale; } $locales = $schema->localePaths(); } $thelist = $this->asList($request); $reordered = $schema->reorderPaths(array_keys($thelist)); foreach ($reordered as $key => $path) { $value = $this->_object[$path]; if (is_array($value)) { $tmp[$path] = array(); foreach ($value as $arr) { $tmp2 = array(); foreach ($arr->asList('') as $inkey => $invalue) { $arr->set($path . ' ' . $inkey, $invalue); } foreach ($schema->reorderPaths(array_keys($arr->asList(''))) as $subkey => $subpath) { // We need this later, so store it $fullpath = $subpath; if ($locale and isset($locales[$subpath])) { if (in_array($locale, $locales[$subpath])) { // //print('found: ' . $subpath . ' (' . $locale . ') so skipping!' . "\n"); } else { $subpath = substr($subpath, strlen($path) + 1); $tmp2[$subpath] = $arr->get($subpath); } } else { $subpath = substr($subpath, strlen($path) + 1); $tmp2[$subpath] = $arr->get($subpath); } if ($schema->dataType($fullpath) == QUICKBOOKS_QBXML_SCHEMA_TYPE_AMTTYPE and isset($tmp2[$subpath])) { $tmp2[$subpath] = sprintf('%01.2f', $tmp2[$subpath]); } } $tmp2 = new QuickBooks_QBXML_Object_Generic($tmp2, $arr->object()); $tmp[$path][] = $tmp2; } } else { // Do some simple data type casting... if ($schema->dataType($path) == QUICKBOOKS_QBXML_SCHEMA_TYPE_AMTTYPE) { $this->_object[$path] = sprintf('%01.2f', $this->_object[$path]); } if ($locale and isset($locales[$path])) { // Check to see if it's supported by the given locale if (in_array($locale, $locales[$path])) { // It's not supported by this locale, don't show add it } else { $tmp[$path] = $this->_object[$path]; } } else { // If we don't know whether or not it's supported, return it! $tmp[$path] = $this->_object[$path]; } } } // *DO NOT* change the source values of the original object! //$this->_object = $tmp; if ($wrapper = $schema->qbxmlWrapper()) { $Node = $this->asXML($wrapper, null, $tmp); $Request->addChild($Node); return $Request->asXML($todo_for_empty_elements, $indent); } else { if (count($this->_object) == 0) { // This catches the cases where we just want to get *all* objects // back (no filters) and thus the root level qbXML element is *empty* // and we need to *preserve* this empty element rather than just // drop it (which results in an empty string, and thus invalid query) $Node = $this->asXML($request, null, $tmp); return $Node->asXML(QuickBooks_XML::XML_PRESERVE, $indent); } else { $Node = $this->asXML($request, null, $tmp); return $Node->asXML($todo_for_empty_elements, $indent); } } } return ''; }
/** * Convert this object to a valid qbXML request/response * * @todo What should this function return if a schema can't be found...? * * @param boolean $compress_empty_elements * @param string $indent * @param string $root * @return string */ public function asQBXML($request, $todo_for_empty_elements = QUICKBOOKS_XML_XML_DROP, $indent = "\t", $root = null) { if (strtolower(substr($request, -2, 2)) != 'rq') { $request .= 'Rq'; } $Request = new QuickBooks_XML_Node($request); if ($schema = $this->_schema($request)) { $tmp = array(); //print_r(array_keys($this->asList($request))); foreach ($schema->reorderPaths(array_keys($this->asList($request))) as $key => $path) { $value = $this->_object[$path]; if (is_array($value)) { $tmp[$path] = array(); foreach ($value as $arr) { $tmp2 = array(); foreach ($arr->asList('') as $inkey => $invalue) { $arr->set($path . ' ' . $inkey, $invalue); } foreach ($schema->reorderPaths(array_keys($arr->asList(''))) as $subkey => $subpath) { $subpath = substr($subpath, strlen($path) + 1); $tmp2[$subpath] = $arr->get($subpath); } $tmp2 = new QuickBooks_Object_Generic($tmp2, $arr->object()); $tmp[$path][] = $tmp2; } } else { $tmp[$path] = $this->_object[$path]; } } $this->_object = $tmp; if ($wrapper = $schema->qbxmlWrapper()) { $Node = $this->asXML($wrapper); $Request->addChild($Node); return $Request->asXML($todo_for_empty_elements, $indent); } else { if (count($this->_object) == 0) { // This catches the cases where we just want to get *all* objects // back (no filters) and thus the root level qbXML element is *empty* // and we need to *preserve* this empty element rather than just // drop it (which results in an empty string, and thus invalid query) $Node = $this->asXML($request); return $Node->asXML(QUICKBOOKS_XML_XML_PRESERVE, $indent); } else { $Node = $this->asXML($request); return $Node->asXML($todo_for_empty_elements, $indent); } } } return ''; }
protected function _parseIDS_v2($xml, $optype, $flavor, $version, &$xml_errnum, &$xml_errmsg, &$err_code, &$err_desc, &$err_db) { // Massage it... *sigh* $xml = $this->_massageQBOXML($xml, $optype); // 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(); $List = current($Root->children()); switch ($optype) { case QuickBooks_IPP_IDS::OPTYPE_REPORT: // Parse a REPORT type response $Report = new QuickBooks_IPP_Object_Report('@todo Make sure we show the title of the report!'); foreach ($List->children() as $Child) { $class = 'QuickBooks_IPP_Object_' . $Child->name(); $Object = new $class(); foreach ($Child->children() as $Data) { $this->_push($Data, $Object); } $method = 'add' . $Child->name(); $Report->{$method}($Object); } return $Report; break; case QuickBooks_IPP_IDS::OPTYPE_QUERY: // Parse a QUERY type response // Parse a QUERY type response case QuickBooks_IPP_IDS::OPTYPE_FINDBYID: //print_r($List); //exit; //print_r($Root); //exit; // Stupid QuickBooks Online... *sigh* if ($optype == QuickBooks_IPP_IDS::OPTYPE_FINDBYID and $flavor == QuickBooks_IPP_IDS::FLAVOR_ONLINE) { $List = new QuickBooks_XML_Node(__CLASS__ . '__line_' . __LINE__); $List->addChild($Root); } //print_r($List); //exit; // Normal parsing of query results $list = array(); 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; break; case QuickBooks_IPP_IDS::OPTYPE_ADD: // Parse an ADD type response // Parse an ADD type response case QuickBooks_IPP_IDS::OPTYPE_MOD: //print("\n\n\n" . 'response was: ' . $List->name() . "\n\n\n"); //print_r('list name [' . $List->name() . ']'); switch ($List->name()) { case 'Id': // This is what QuickBooks Online, IDS v2 does return QuickBooks_IPP_IDS::buildIDType($List->getAttribute('idDomain'), $List->data()); case 'Error': $err_code = $List->getChildDataAt('Error ErrorCode'); $err_desc = $List->getChildDataAt('Error ErrorDesc'); $err_db = $List->getChildDataAt('Error DBErrorCode'); return false; case 'Success': $checks = array('Success PartyRoleRef Id', 'Success PartyRoleRef PartyReferenceId', 'Success ObjectRef Id'); foreach ($checks as $xpath) { $IDNode = $List->getChildAt($xpath); if ($IDNode) { return QuickBooks_IPP_IDS::buildIDType($IDNode->getAttribute('idDomain'), $IDNode->data()); } } $err_code = QuickBooks_IPP::ERROR_INTERNAL; $err_desc = 'Could not locate unique ID in response: ' . $xml; $err_db = ''; return false; default: // This should never happen unless Keith neglected // to implement some part of the IPP/IDS spec $err_code = QuickBooks_IPP::ERROR_INTERNAL; $err_desc = 'The parseIDS() method could not understand node [' . $List->name() . '] in response: ' . $xml; $err_db = null; return false; } break; default: $err_code = QuickBooks_IPP::ERROR_INTERNAL; $err_desc = 'The parseIDS() method could not understand the specified optype: [' . $optype . ']'; $err_db = null; return false; } } else { $xml_errnum = $errnum; $xml_errmsg = $errmsg; return false; } }