<?php require_once '../../QuickBooks.php'; $arr = array('Name' => 'Sales', 'Descrip' => 'Test'); $path_or_tablefield = 'account.Descrip'; $mode = QUICKBOOKS_SQL_SCHEMA_MAP_TO_XML; $map = array(); $others = array(); QuickBooks_SQL_Schema::mapToSchema($path_or_tablefield, $mode, $map, $others); print "\n\n"; print_r($map); $path_or_tablefield = 'account.SomethingElse'; $mode = QUICKBOOKS_SQL_SCHEMA_MAP_TO_XML; $map = array(); $others = array(); QuickBooks_SQL_Schema::mapToSchema($path_or_tablefield, $mode, $map, $others); print "\n\n"; print_r($map); $path_or_tablefield = 'account.Parent_ListID'; $mode = QUICKBOOKS_SQL_SCHEMA_MAP_TO_XML; $map = array(); $others = array(); QuickBooks_SQL_Schema::mapToSchema($path_or_tablefield, $mode, $map, $others); print "\n\n"; print_r($map); print "\n\n";
/** * @TODO Change this to return false by default, and only catch the specific errors we're concerned with. * */ public static function catchall($requestID, $user, $action, $ident, $extra, &$err, $xml, $errnum, $errmsg, $config) { $Driver = QuickBooks_Driver_Singleton::getInstance(); /* $Parser = new QuickBooks_XML($xml); $errnumTemp = 0; $errmsgTemp = ''; $Doc = $Parser->parse($errnumTemp, $errmsgTemp); $Root = $Doc->getRoot(); $emailStr = var_export($Root->children(), true); $List = $Root->getChildAt('QBXML QBXMLMsgsRs '.QuickBooks_Utilities::actionToResponse($action)); $Node = current($List->children()); */ $map = array(); $others = array(); QuickBooks_SQL_Schema::mapToSchema(trim(QuickBooks_Utilities::actionToXMLElement($action)), QUICKBOOKS_SQL_SCHEMA_MAP_TO_SQL, $map, $others); $sqlObject = new QuickBooks_SQL_Object($map[0], trim(QuickBooks_Utilities::actionToXMLElement($action))); $table = $sqlObject->table(); switch ($errnum) { case 1: // These errors occur when we search for something and it doesn't exist // These errors occur when we search for something and it doesn't exist case 500: // i.e. we query for invoices modified since xyz, but there are none that have been modified since then // This isn't really an error, just ignore it return true; case 1000: // An internal error occured // @todo Hopefully at some point we'll have a better idea of how to handle this error... return true; case 3200: // Ignore EditSequence errors (the record will be picked up and a conflict reported next time it runs... maybe?) // @todo Think about this one more return true; case 3250: // This feature is not enabled or not available in this version of QuickBooks. // Do nothing (this can be safely ignored) return true; case 3100: // Name of List Element is already in use. $multipart = array(QUICKBOOKS_DRIVER_SQL_FIELD_ID => $ident); $sqlObject->set(QUICKBOOKS_DRIVER_SQL_FIELD_ERROR_NUMBER, $errnum); $sqlObject->set(QUICKBOOKS_DRIVER_SQL_FIELD_ERROR_MESSAGE, $errmsg); $Driver->update(QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, $sqlObject, array($multipart)); break; case 3260: // Insufficient permission level to perform this action. // There's nothing we can do about this, if they don't grant the user permission, just skip it return true; case 3200: // The provided edit sequence is out-of-date. if (!($tmp = $Driver->get(QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, array(QUICKBOOKS_DRIVER_SQL_FIELD_ID => $ident)))) { return true; } switch ($config['conflicts']) { case QUICKBOOKS_SERVER_SQL_CONFLICT_LOG: $multipart = array(QUICKBOOKS_DRIVER_SQL_FIELD_ID => $ident); $sqlObject->set(QUICKBOOKS_DRIVER_SQL_FIELD_ERROR_NUMBER, $errnum); $sqlObject->set(QUICKBOOKS_DRIVER_SQL_FIELD_ERROR_MESSAGE, $errmsg); $Driver->update(QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, $sqlObject, array($multipart)); break; case QUICKBOOKS_SERVER_SQL_CONFLICT_NEWER: $Parser = new QuickBooks_XML_Parser($xml); $errnumTemp = 0; $errmsgTemp = ''; $Doc = $Parser->parse($errnumTemp, $errmsgTemp); $Root = $Doc->getRoot(); $List = $Root->getChildAt('QBXML QBXMLMsgsRs ' . QuickBooks_Utilities::actionToResponse($action)); $TimeModified = $Root->getChildDataAt('QBXML QBXMLMsgsRs ' . QuickBooks_Utilities::actionToResponse($action) . ' ' . QuickBooks_Utilities::actionToXMLElement($action) . ' TimeModified'); $EditSequence = $Root->getChildDataAt('QBXML QBXMLMsgsRs ' . QuickBooks_Utilities::actionToResponse($action) . ' ' . QuickBooks_Utilities::actionToXMLElement($action) . ' EditSequence'); $multipart = array(QUICKBOOKS_DRIVER_SQL_FIELD_ID => $ident); if (QuickBooks_Utilities::compareQBTimeToSQLTime($TimeModified, $tmp->get(QUICKBOOKS_DRIVER_SQL_FIELD_MODIFY)) >= 0 && $config['mode'] != QUICKBOOKS_SERVER_SQL_MODE_WRITEONLY) { //@TODO: Make this get only a single item, not the whole table $Driver->queueEnqueue($user, QuickBooks_Utilities::convertActionToQuery($action), __FILE__, true, QUICKBOOKS_SERVER_SQL_CONFLICT_QUEUE_PRIORITY, $extra); } else { if (QuickBooks_Utilities::compareQBTimeToSQLTime($TimeModified, $tmp->get(QUICKBOOKS_DRIVER_SQL_FIELD_MODIFY)) < 0) { //Updates the EditSequence without marking the row as resynced. $tmpSQLObject = new QuickBooks_SQL_Object($table, null); $tmpSQLObject->set("EditSequence", $EditSequence); $Driver->update(QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, $tmpSQLObject, array($multipart)); $Driver->queueEnqueue($user, QuickBooks_Utilities::convertActionToMod($action), $tmp->get(QUICKBOOKS_DRIVER_SQL_FIELD_ID), true, QUICKBOOKS_SERVER_SQL_CONFLICT_QUEUE_PRIORITY, $extra); } else { //Trash it, set synced. $tmpSQLObject = new QuickBooks_SQL_Object($table, null); $tmpSQLObject->set(QUICKBOOKS_DRIVER_SQL_FIELD_ERROR_MESSAGE, "Read/Write Mode is WRITEONLY, and Conflict Mode is NEWER, and Quickbooks has Newer data, so no Update Occured."); $Driver->update(QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, $tmpSQLObject, array($multipart)); } } break; case QUICKBOOKS_SERVER_SQL_CONFLICT_QUICKBOOKS: if ($config['mode'] == QUICKBOOKS_SERVER_SQL_MODE_READWRITE) { //@TODO: Make this get only a single item, not the whole table $Driver->queueEnqueue($user, QuickBooks_Utilities::convertActionToQuery($action), null, true, QUICKBOOKS_SERVER_SQL_CONFLICT_QUEUE_PRIORITY, $extra); $multipart = array(QUICKBOOKS_DRIVER_SQL_FIELD_ID => $ident); $sqlObject->set(QUICKBOOKS_DRIVER_SQL_FIELD_ERROR_NUMBER, $errnum); $sqlObject->set(QUICKBOOKS_DRIVER_SQL_FIELD_ERROR_MESSAGE, $errmsg); $Driver->update(QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, $sqlObject, array($multipart)); //Use what's on quickbooks, and trash whatever is here. } else { $multipart = array(QUICKBOOKS_DRIVER_SQL_FIELD_ID => $ident); $sqlObject->set(QUICKBOOKS_DRIVER_SQL_FIELD_ERROR_NUMBER, $errnum); $sqlObject->set(QUICKBOOKS_DRIVER_SQL_FIELD_ERROR_MESSAGE, $errmsg); $Driver->update(QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, $sqlObject, array($multipart)); // @TODO: Raise Notification that the conflicts level requires writing to SQL table, but Mode disallows this } break; case QUICKBOOKS_SERVER_SQL_CONFLICT_SQL: // Updates the EditSequence without marking the row as resynced. $tmpSQLObject = new QuickBooks_SQL_Object($table, null); $tmpSQLObject->set("EditSequence", $EditSequence); $Driver->update(QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, $tmpSQLObject, array($multipart)); $Driver->queueEnqueue($user, QuickBooks_Utilities::convertActionToMod($action), $tmp->get(QUICKBOOKS_DRIVER_SQL_FIELD_ID), true, QUICKBOOKS_SERVER_SQL_CONFLICT_QUEUE_PRIORITY, $extra); break; case QUICKBOOKS_SERVER_SQL_CONFLICT_CALLBACK: break; default: break; } break; default: if (strstr($xml, 'statusSeverity="Info"') === false) { // } break; } // Please don't change this, it stops us from knowing what's actually // going wrong. If an error occurs, we should either catch it if it's // recoverable, or treated as a fatal error so we know about it and // can address it later. //return false; return true; }
/** * * * @TODO Clean this up! */ protected static function _transformToSQLObjects($curpath, $Node, &$objects, $current = null, $extra = array()) { if ($Node->childCount()) { //print('LOOKING AT [' . strtolower(trim(trim($curpath) . ', ' . $Node->name())) . ']' . "\n"); // switch (strtolower(trim(trim($curpath) . ' ' . $Node->name()))) { case 'accountret': if (!isset($extra['ListID'])) { $extra['ListID'] = $Node->getChildDataAt('AccountRet ListID'); } if (empty($extra['FullName'])) { $extra['FullName'] = $Node->getChildDataAt('AccountRet FullName'); } $extra['EntityListID'] = $extra['ListID']; $extra['EntityType'] = 'Account'; break; case 'billingrateret': if (!isset($extra['ListID'])) { $extra['ListID'] = $Node->getChildDataAt('BillingRateRet ListID'); } break; case 'billpaymentcheckret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('BillPaymentCheckRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'BillPaymentCheck'; //$extra['ExchangeRate'] = $Node->getChildDataAt('BillPaymentCheckRet ExchangeRate'); //$extra['AmountInHomeCurrency'] = $Node->getChildDataAt('BillPaymentCheckRet AmountInHomeCurrency'); break; case 'billpaymentcreditcardret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('BillPaymentCreditCardRet TxnID'); } break; case 'billret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('BillRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'Bill'; break; case 'billret itemgrouplineret': if (!isset($extra['ListID'])) { $extra['TxnLineID'] = $Node->getChildDataAt('ItemGroupLineRet TxnLineID'); } break; case 'chargeret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('ChargeRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'Charge'; break; case 'checkret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('CheckRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'Check'; break; case 'checkret itemgrouplineret': if (!isset($extra['TxnLineID'])) { $extra['TxnLineID'] = $Node->getChildDataAt('ItemGroupLineRet TxnLineID'); } break; case 'companyret': if (!isset($extra['CompanyName'])) { $extra['CompanyName'] = $Node->getChildDataAt('CompanyRet CompanyName'); } $extra['EntityListID'] = $extra['CompanyName']; $extra['EntityType'] = 'Company'; break; case 'creditcardchargeret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('CreditCardChargeRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'CreditCardCharge'; break; case 'creditcardchargeret itemgrouplineret': if (!isset($extra['TxnLineID'])) { $extra['TxnLineID'] = $Node->getChildDataAt('ItemGroupLineRet TxnLineID'); } break; case 'creditcardcreditret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('CreditCardCreditRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'CreditCardCredit'; break; case 'creditcardcreditret itemgrouplineret': if (!isset($extra['TxnLineID'])) { $extra['TxnLineID'] = $Node->getChildDataAt('ItemGroupLineRet TxnLineID'); } break; case 'creditmemoret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('CreditMemoRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'CreditMemo'; break; case 'creditmemoret creditmemolinegroupret': if (!isset($extra['TxnLineID'])) { $extra['TxnLineID'] = $Node->getChildDataAt('CreditMemoLineGroupRet TxnLineID'); } break; case 'customerret': if (!isset($extra['EntityListID'])) { $extra['EntityListID'] = $Node->getChildDataAt('CustomerRet ListID'); } $extra['EntityType'] = 'Customer'; break; case 'dataextdefret': if (!isset($extra['DataExtName'])) { $extra['DataExtName'] = $Node->getChildDataAt('DataExtDefRet DataExtName'); } if (!isset($extra['OwnerID'])) { $extra['OwnerID'] = $Node->getChildDataAt('DataExtDefRet OwnerID'); } break; case 'depositret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('DepositRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'Deposit'; break; case 'employeeret': if (!isset($extra['ListID'])) { $extra['ListID'] = $Node->getChildDataAt('EmployeeRet ListID'); } $extra['EntityListID'] = $extra['ListID']; $extra['EntityType'] = 'Employee'; break; case 'estimateret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('EstimateRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'Estimate'; break; case 'estimateret estimatelineret': if (!isset($extra['Txn_TxnID'])) { $extra['Txn_TxnID'] = $Node->getChildDataAt('EstimateLineRet TxnLineID'); } $extra['TxnType'] = 'EstimateLine'; break; case 'estimateret estimatelinegroupret': if (!isset($extra['TxnLineID'])) { $extra['TxnLineID'] = $Node->getChildDataAt('EstimateLineGroupRet TxnLineID'); } $extra['Txn_TxnID'] = $extra['TxnLineID']; $extra['TxnType'] = 'EstimateLineGroup'; break; case 'estimateret estimatelinegroupret estimatelineret': $extra['Txn_TxnID'] = $Node->getChildDataAt('EstimateLineRet TxnLineID'); $extra['TxnType'] = 'EstimateLineGroup_EstimateLine'; break; case 'inventoryadjustmentret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('InventoryAdjustmentRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'InventoryAdjustment'; break; case 'invoiceret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('InvoiceRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'Inventory'; break; case 'invoiceret invoicelineret': $extra['Txn_TxnID'] = $Node->getChildDataAt('InvoiceLineRet TxnLineID'); $extra['TxnType'] = 'InvoiceLine'; break; case 'invoiceret invoicelinegroupret': if (!isset($extra['TxnLineID'])) { $extra['TxnLineID'] = $Node->getChildDataAt('InvoiceLineGroupRet TxnLineID'); } $extra['Txn_TxnID'] = $extra['TxnLineID']; $extra['TxnType'] = 'InvoiceLineGroup'; break; case 'invoiceret invoicelinegroupret invoicelineret': $extra['Txn_TxnID'] = $Node->getChildDataAt('InvoiceLineRet TxnLineID'); $extra['TxnType'] = 'InvoiceLineGroup_InvoiceLine'; break; case 'itemgroupret': if (!isset($extra['ListID'])) { $extra['ListID'] = $Node->getChildDataAt('ItemGroupRet ListID'); } $extra['EntityListID'] = $extra['ListID']; $extra['EntityType'] = 'ItemGroup'; break; case 'iteminventoryret': $extra['EntityListID'] = $Node->getChildDataAt('ItemInventoryRet ListID'); $extra['EntityType'] = 'ItemInventory'; break; case 'iteminventoryassemblyret': if (!isset($extra['ListID'])) { $extra['ListID'] = $Node->getChildDataAt('ItemInventoryAssemblyRet ListID'); } $extra['EntityListID'] = $extra['ListID']; $extra['EntityType'] = 'ItemInventoryAssembly'; break; case 'itemnoninventoryret': if (!isset($extra['EntityListID'])) { $extra['EntityListID'] = $Node->getChildDataAt('ItemNonInventoryRet ListID'); } $extra['EntityType'] = 'ItemNonInventory'; break; case 'itemdiscountret': if (!isset($extra['EntityListID'])) { $extra['EntityListID'] = $Node->getChildDataAt('ItemDiscountRet ListID'); } $extra['EntityType'] = 'ItemDiscount'; break; case 'itemfixedassetret': if (!isset($extra['EntityListID'])) { $extra['EntityListID'] = $Node->getChildDataAt('ItemFixedAssetRet ListID'); } $extra['EntityType'] = 'ItemFixedAsset'; break; case 'itemotherchargeret': if (!isset($extra['EntityListID'])) { $extra['EntityListID'] = $Node->getChildDataAt('ItemOtherChargeRet ListID'); } $extra['EntityType'] = 'ItemOtherCharge'; break; case 'itempaymentret': if (!isset($extra['EntityListID'])) { $extra['EntityListID'] = $Node->getChildDataAt('ItemPaymentRet ListID'); } $extra['EntityType'] = 'ItemPayment'; break; case 'itemreceiptret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('ItemReceiptRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'ItemReceipt'; break; case 'itemreceiptret itemreceiptlinegroupret': if (!isset($extra['TxnLineID'])) { $extra['TxnLineID'] = $Node->getChildDataAt('ItemReceiptLineGroupRet TxnLineID'); } break; case 'itemsalestaxret': if (!isset($extra['EntityListID'])) { $extra['EntityListID'] = $Node->getChildDataAt('ItemSalesTaxRet ListID'); } $extra['EntityType'] = 'ItemSalesTax'; break; case 'itemsalestaxgroupret': if (!isset($extra['ListID'])) { $extra['ListID'] = $Node->getChildDataAt('ItemSalesTaxGroupRet ListID'); } $extra['EntityListID'] = $extra['ListID']; $extra['EntityType'] = 'ItemSalesTaxGroup'; break; case 'itemserviceret': if (!isset($extra['EntityListID'])) { $extra['EntityListID'] = $Node->getChildDataAt('ItemServiceRet ListID'); } $extra['EntityType'] = 'ItemService'; break; case 'itemsubtotalret': if (!isset($extra['EntityListID'])) { $extra['EntityListID'] = $Node->getChildDataAt('ItemSubtotalRet ListID'); } $extra['EntityType'] = 'ItemSubtotal'; break; case 'journalentryret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('JournalEntryRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'JournalEntry'; break; case 'pricelevelret': if (!isset($extra['ListID'])) { $extra['ListID'] = $Node->getChildDataAt('PriceLevelRet ListID'); } break; case 'purchaseorderret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('PurchaseOrderRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'PurchaseOrder'; break; case 'purchaseorderret purchaseorderlineret': $extra['Txn_TxnID'] = $Node->getChildDataAt('PurchaseOrderLineRet TxnLineID'); $extra['TxnType'] = 'PurchaseOrderLine'; break; case 'purchaseorderret purchaseorderlinegroupret': if (!isset($extra['TxnLineID'])) { $extra['TxnLineID'] = $Node->getChildDataAt('PurchaseOrderLineGroupRet TxnLineID'); } $extra['Txn_TxnID'] = $extra['TxnLineID']; $extra['TxnType'] = 'PurchaseOrderLineGroup'; break; case 'purchaseorderret purchaseorderlinegroupret purchaseorderlineret': $extra['Txn_TxnID'] = $Node->getChildDataAt('PurchaseOrderLineRet TxnLineID'); $extra['TxnType'] = 'PurchaseOrderLineGroup_PurchaseOrderLine'; break; case 'receivepaymentret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('ReceivePaymentRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'ReceivePayment'; break; case 'salesorderret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('SalesOrderRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'SalesOrder'; break; case 'salesorderret salesorderlineret': $extra['Txn_TxnID'] = $Node->getChildDataAt('SalesOrderLineRet TxnLineID'); $extra['TxnType'] = 'SalesOrderLine'; break; case 'salesorderret salesorderlinegroupret': $extra['TxnLineID'] = $Node->getChildDataAt('SalesOrderLineGroupRet TxnLineID'); $extra['Txn_TxnID'] = $extra['TxnLineID']; $extra['TxnType'] = 'SalesOrderLineGroup'; break; case 'salesorderret salesorderlinegroupret salesorderlineret': $extra['Txn_TxnID'] = $Node->getChildDataAt('SalesOrderLineRet TxnLineID'); $extra['TxnType'] = 'SalesOrderLineGroup_SalesOrderLine'; break; case 'salesreceiptret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('SalesReceiptRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'SalesReceipt'; break; case 'salesreceiptret salesreceiptlineret': $extra['Txn_TxnID'] = $Node->getChildDataAt('SalesReceiptLineRet TxnLineID'); $extra['TxnType'] = 'SalesReceiptLine'; break; case 'salesreceiptret salesreceiptlinegroupret': $extra['TxnLineID'] = $Node->getChildDataAt('SalesReceiptLineGroupRet TxnLineID'); $extra['Txn_TxnID'] = $extra['TxnLineID']; $extra['TxnType'] = 'SalesReceiptLineGroup'; break; case 'salesreceiptret salesreceiptlinegroupret salesreceiptlineret': $extra['Txn_TxnID'] = $Node->getChildDataAt('SalesReceiptLineRet TxnLineID'); $extra['TxnType'] = 'SalesReceiptLineGroup_SalesReceiptLine'; break; case 'unitofmeasuresetret': if (!isset($extra['ListID'])) { $extra['ListID'] = $Node->getChildDataAt('UnitOfMeasureSetRet ListID'); } break; case 'vendorret': if (!isset($extra['EntityListID'])) { $extra['EntityListID'] = $Node->getChildDataAt('VendorRet ListID'); } $extra['EntityType'] = 'Vendor'; break; case 'vendorcreditret': if (!isset($extra['TxnID'])) { $extra['TxnID'] = $Node->getChildDataAt('VendorCreditRet TxnID'); } $extra['Txn_TxnID'] = $extra['TxnID']; $extra['TxnType'] = 'VendorCredit'; break; case 'vendorcreditret itemgrouplineret': if (!isset($extra['TxnLineID'])) { $extra['TxnLineID'] = $Node->getChildDataAt('ItemGroupLineRet TxnLineID'); } break; case 'workerscompcoderet': if (!isset($extra['ListID'])) { $extra['ListID'] = $Node->getChildDataAt('WorkersCompCodeRet ListID'); } break; } foreach ($Node->children() as $Child) { $merge = false; $others = array(); switch ($Child->name()) { case 'AppliedToTxnRet': case 'BillingRatePerItemRet': case 'CreditMemoLineRet': case 'CreditMemoLineGroupRet': case 'DataExtRet': case 'AssignToObject': case 'DefaultUnit': case 'DepositLineRet': case 'EstimateLineRet': case 'EstimateLineGroupRet': case 'ExpenseLineRet': case 'InvoiceAdjustmentLineRet': case 'InvoiceLineRet': case 'InvoiceLineGroupRet': case 'InventoryAdjustmentLineRet': case 'ItemGroupRet': case 'ItemGroupLine': case 'ItemGroupLineRet': case 'ItemInventoryAssemblyLineRet': case 'ItemInventoryAssemblyLine': case 'ItemLineRet': case 'ItemSalesTaxGroupRet': //case 'ItemSalesTaxRef': //case 'ItemSalesTaxRef': case 'LinkedTxn': case 'PriceLevelPerItemRet': case 'PurchaseOrderLineRet': case 'PurchaseOrderLineGroupRet': case 'RelatedUnit': case 'SalesOrderLineRet': case 'SalesOrderLineGroupRet': case 'SalesReceiptLineRet': case 'SalesReceiptLineGroupRet': case 'Service': case 'SubscribedServices': case 'TaxLineInfoRet': // * * * WARNING WARNING WARNING * * * // The next line of code causes problems with some responses // because it converts our associative array to turn into a // numeric array. This causes objects to get cut into multiple // pieces: // // array( // 'account' => array( 'Name' => 'test', 'ListID' => 1234' ), // 0 => array( account_taxlineinforet data here ), // 1 => array( 'CashFlowClassification' => 'abc' ), // this is the other half of the Account data from the 'account' associative array key // ) // // Do not make a change to this code without double checking syncs // and talking this over with Keith first please! Thanks! // // Previously we were using this line, but it was causing problems: //$others = array_values($objects); // This line of code seems to work OK $others = $objects; $objects = array(); $merge = true; break; } QuickBooks_Callbacks_SQL_Callbacks::_transformToSQLObjects($curpath . ' ' . $Node->name(), $Child, $objects, null, $extra); // * * * WARNING * * * // Please see notes above about object chunking problems which might be related to the code below if ($merge) { $objects = array_values($objects); $objects = array_merge($others, $objects); } // //echo '<br /> '; //print_r($objects); //echo '<br /><br />'; } } else { $map = array(); $others = array(); QuickBooks_SQL_Schema::mapToSchema(trim($curpath . ' ' . $Node->name()), QUICKBOOKS_SQL_SCHEMA_MAP_TO_SQL, $map, $others); //Okay so if the first element is a child element that is custom mapped, it'll end up creating the object with an incorrect path. //print('map for: {' . $curpath . ' ' . $Node->name() . "} [" . $map[0] . "]\n"); //print_r($map); if ($map[0] and !isset($objects[$map[0]])) { //print('creating new object: ' . $map[0] . "\n"); //print_r($objects); $tempMap = array(); $tempOthers = array(); QuickBooks_SQL_Schema::mapToSchema(trim($curpath), QUICKBOOKS_SQL_SCHEMA_MAP_TO_SQL, $tempMap, $tempOthers); if ($map[0] == 'dataextdef_assigntoobject') { $objects[$map[0]] = new QuickBooks_SQL_Object($map[0], trim($curpath . ' ' . $Node->name())); } else { $objects[$map[0]] = new QuickBooks_SQL_Object($map[0], trim($curpath)); } // Some tables, such 'Invoice_InvoiceLine', won't have data in the SQL schema that // directly links them back to the 'Invoice' record they're part of. Thus, we need // to add a few schema fields, and then here we set those fields to values from the // parent of these objects so that they get tied to the correct 'Invoice' in the // database table 'Invoice_InvoiceLine' $table = $objects[$map[0]]->table(); switch (strtolower($table)) { case 'account_taxlineinfo': $objects[$map[0]]->set('Account_ListID', $extra['ListID']); $objects[$map[0]]->set('Account_FullName', $extra['FullName']); break; case 'billingrate_billingrateperitem': $objects[$map[0]]->set('BillingRate_ListID', $extra['ListID']); break; case 'billpaymentcheck_appliedtotxn': $objects[$map[0]]->set('FromTxnID', $extra['TxnID']); $objects[$map[0]]->set('BillPaymentCheck_TxnID', $extra['TxnID']); break; case 'billpaymentcreditcard_appliedtotxn': $objects[$map[0]]->set('FromTxnID', $extra['TxnID']); $objects[$map[0]]->set('BillPaymentCreditCard_TxnID', $extra['TxnID']); break; case 'bill_linkedtxn': $objects[$map[0]]->set('FromTxnID', $extra['TxnID']); $objects[$map[0]]->set('Bill_TxnID', $extra['TxnID']); break; case 'bill_expenseline': $objects[$map[0]]->set('Bill_TxnID', $extra['TxnID']); break; case 'bill_itemline': $objects[$map[0]]->set('Bill_TxnID', $extra['TxnID']); break; case 'bill_itemgroupline': $objects[$map[0]]->set('Bill_TxnID', $extra['TxnID']); break; case 'bill_itemgroupline_itemline': $objects[$map[0]]->set('Bill_TxnID', $extra['TxnID']); $objects[$map[0]]->set('Bill_ItemGroupLine_TxnLineID', $extra['TxnLineID']); break; case 'check_linkedtxn': $objects[$map[0]]->set('FromTxnID', $extra['TxnID']); $objects[$map[0]]->set('Check_TxnID', $extra['TxnID']); break; case 'check_expenseline': $objects[$map[0]]->set('Check_TxnID', $extra['TxnID']); break; case 'check_itemline': $objects[$map[0]]->set('Check_TxnID', $extra['TxnID']); break; case 'check_itemgroupline': $objects[$map[0]]->set('Check_TxnID', $extra['TxnID']); break; case 'check_itemgroupline_itemline': $objects[$map[0]]->set('Check_TxnID', $extra['TxnID']); $objects[$map[0]]->set('Check_ItemGroupLine_TxnLineID', $extra['TxnLineID']); break; case 'company_subscribedservices_service': $objects[$map[0]]->set('Company_CompanyName', $extra['CompanyName']); break; case 'creditcardcharge_expenseline': $objects[$map[0]]->set('CreditCardCharge_TxnID', $extra['TxnID']); break; case 'creditcardcharge_itemline': $objects[$map[0]]->set('CreditCardCharge_TxnID', $extra['TxnID']); break; case 'creditcardcharge_itemgroupline': $objects[$map[0]]->set('CreditCardCharge_TxnID', $extra['TxnID']); break; case 'creditcardcharge_itemgroupline_itemline': $objects[$map[0]]->set('CreditCardCharge_TxnID', $extra['TxnID']); $objects[$map[0]]->set('CreditCardCharge_ItemGroupLine_TxnLineID', $extra['TxnLineID']); break; case 'creditcardcredit_expenseline': $objects[$map[0]]->set('CreditCardCredit_TxnID', $extra['TxnID']); break; case 'creditcardcredit_itemline': $objects[$map[0]]->set('CreditCardCredit_TxnID', $extra['TxnID']); break; case 'creditcardcredit_itemgroupline': $objects[$map[0]]->set('CreditCardCredit_TxnID', $extra['TxnID']); break; case 'creditcardcredit_itemgroupline_itemline': $objects[$map[0]]->set('CreditCardCredit_TxnID', $extra['TxnID']); $objects[$map[0]]->set('CreditCardCredit_ItemGroupLine_TxnLineID', $extra['TxnLineID']); break; case 'creditmemo_linkedtxn': $objects[$map[0]]->set('FromTxnID', $extra['TxnID']); $objects[$map[0]]->set('CreditMemo_TxnID', $extra['TxnID']); break; case 'creditmemo_creditmemoline': $objects[$map[0]]->set('CreditMemo_TxnID', $extra['TxnID']); break; case 'creditmemo_creditmemolinegroup': $objects[$map[0]]->set('CreditMemo_TxnID', $extra['TxnID']); break; case 'creditmemo_creditmemolinegroup_creditmemoline': $objects[$map[0]]->set('CreditMemo_TxnID', $extra['TxnID']); $objects[$map[0]]->set('CreditMemo_CreditMemoLineGroup_TxnLineID', $extra['TxnLineID']); break; case 'dataext': if (!empty($extra['EntityType'])) { $objects[$map[0]]->set('EntityType', $extra['EntityType']); $objects[$map[0]]->set('Entity_ListID', $extra['EntityListID']); } else { $objects[$map[0]]->set('TxnType', $extra['TxnType']); $objects[$map[0]]->set('Txn_TxnID', $extra['Txn_TxnID']); } break; case 'dataextdef_assigntoobject': if (!empty($extra['DataExtName'])) { $objects[$map[0]]->set('DataExtDef_DataExtName', $extra['DataExtName']); } if (!empty($extra['OwnerID']) or isset($extra['OwnerID']) and $extra['OwnerID'] == 0) { $objects[$map[0]]->set('DataExtDef_OwnerID', $extra['OwnerID']); } break; case 'deposit_depositline': $objects[$map[0]]->set('Deposit_TxnID', $extra['TxnID']); break; case 'employee_earnings': $objects[$map[0]]->set('Employee_ListID', $extra['ListID']); break; case 'estimate_linkedtxn': $objects[$map[0]]->set('FromTxnID', $extra['TxnID']); $objects[$map[0]]->set('Estimate_TxnID', $extra['TxnID']); break; case 'estimate_estimateline': $objects[$map[0]]->set('Estimate_TxnID', $extra['TxnID']); break; case 'estimate_estimatelinegroup': $objects[$map[0]]->set('Estimate_TxnID', $extra['TxnID']); break; case 'estimate_estimatelinegroup_estimateline': $objects[$map[0]]->set('Estimate_TxnID', $extra['TxnID']); $objects[$map[0]]->set('Estimate_EstimateLineGroup_TxnLineID', $extra['TxnLineID']); break; case 'inventoryadjustment_inventoryadjustmentline': $objects[$map[0]]->set('InventoryAdjustment_TxnID', $extra['TxnID']); break; case 'invoice_linkedtxn': $objects[$map[0]]->set('FromTxnID', $extra['TxnID']); $objects[$map[0]]->set('Invoice_TxnID', $extra['TxnID']); break; case 'invoice_invoiceline': $objects[$map[0]]->set('Invoice_TxnID', $extra['TxnID']); break; case 'invoice_invoicelinegroup': $objects[$map[0]]->set('Invoice_TxnID', $extra['TxnID']); break; case 'invoice_invoicelinegroup_invoiceline': $objects[$map[0]]->set('Invoice_TxnID', $extra['TxnID']); $objects[$map[0]]->set('Invoice_InvoiceLineGroup_TxnLineID', $extra['TxnLineID']); break; case 'itemgroup_itemgroupline': $objects[$map[0]]->set('ItemGroup_ListID', $extra['ListID']); break; case 'iteminventoryassembly_iteminventoryassemblyline': $objects[$map[0]]->set('ItemInventoryAssembly_ListID', $extra['ListID']); break; case 'itemreceipt_linkedtxn': $objects[$map[0]]->set('FromTxnID', $extra['TxnID']); $objects[$map[0]]->set('ItemReceipt_TxnID', $extra['TxnID']); break; case 'itemreceipt_expenseline': $objects[$map[0]]->set('ItemReceipt_TxnID', $extra['TxnID']); break; case 'itemreceipt_itemline': $objects[$map[0]]->set('ItemReceipt_TxnID', $extra['TxnID']); break; case 'itemreceipt_itemgroupline': $objects[$map[0]]->set('ItemReceipt_TxnID', $extra['TxnID']); break; case 'itemreceipt_itemgroupline_itemline': $objects[$map[0]]->set('ItemReceipt_TxnID', $extra['TxnID']); $objects[$map[0]]->set('ItemReceipt_ItemGroupLine_TxnLineID', $extra['TxnLineID']); break; case 'itemsalestaxgroup_itemsalestax': $objects[$map[0]]->set('ItemSalesTaxGroup_ListID', $extra['ListID']); break; case 'journalentry_journalcreditline': $objects[$map[0]]->set('JournalEntry_TxnID', $extra['TxnID']); break; case 'journalentry_journaldebitline': $objects[$map[0]]->set('JournalEntry_TxnID', $extra['TxnID']); break; case 'pricelevel_pricelevelperitem': $objects[$map[0]]->set('PriceLevel_ListID', $extra['ListID']); break; case 'purchaseorder_linkedtxn': $objects[$map[0]]->set('FromTxnID', $extra['TxnID']); $objects[$map[0]]->set('PurchaseOrder_TxnID', $extra['TxnID']); break; case 'purchaseorder_purchaseorderline': $objects[$map[0]]->set('PurchaseOrder_TxnID', $extra['TxnID']); break; case 'purchaseorder_purchaseorderlinegroup': $objects[$map[0]]->set('PurchaseOrder_TxnID', $extra['TxnID']); break; case 'purchaseorder_purchaseorderlinegroup_purchaseorderline': $objects[$map[0]]->set('PurchaseOrder_TxnID', $extra['TxnID']); $objects[$map[0]]->set('PurchaseOrder_PurchaseOrderLineGroup_TxnLineID', $extra['TxnLineID']); break; case 'receivepayment_linkedtxn': case 'receivepayment_appliedtotxn': $objects[$map[0]]->set('FromTxnID', $extra['TxnID']); $objects[$map[0]]->set('ReceivePayment_TxnID', $extra['TxnID']); break; case 'salesorder_linkedtxn': $objects[$map[0]]->set('FromTxnID', $extra['TxnID']); $objects[$map[0]]->set('SalesOrder_TxnID', $extra['TxnID']); break; case 'salesorder_salesorderline': $objects[$map[0]]->set('SalesOrder_TxnID', $extra['TxnID']); break; case 'salesorder_salesorderlinegroup': $objects[$map[0]]->set('SalesOrder_TxnID', $extra['TxnID']); break; case 'salesorder_salesorderlinegroup_salesorderline': $objects[$map[0]]->set('SalesOrder_TxnID', $extra['TxnID']); $objects[$map[0]]->set('SalesOrder_SalesOrderLineGroup_TxnLineID', $extra['TxnLineID']); break; case 'salesreceipt_salesreceiptline': $objects[$map[0]]->set('SalesReceipt_TxnID', $extra['TxnID']); break; case 'salesreceipt_salesreceiptlinegroup': $objects[$map[0]]->set('SalesReceipt_TxnID', $extra['TxnID']); break; case 'salesreceipt_salesreceiptlinegroup_salesreceiptline': $objects[$map[0]]->set('SalesReceipt_TxnID', $extra['TxnID']); $objects[$map[0]]->set('SalesReceipt_SalesReceiptLineGroup_TxnLineID', $extra['TxnLineID']); break; case 'unitofmeasureset_relatedunit': $objects[$map[0]]->set('UnitOfMeasureSet_ListID', $extra['ListID']); break; case 'unitofmeasureset_defaultunit': $objects[$map[0]]->set('UnitOfMeasureSet_ListID', $extra['ListID']); break; case 'vendorcredit_linkedtxn': $objects[$map[0]]->set('FromTxnID', $extra['TxnID']); $objects[$map[0]]->set('VendorCredit_TxnID', $extra['TxnID']); break; case 'vendorcredit_expenseline': $objects[$map[0]]->set('VendorCredit_TxnID', $extra['TxnID']); break; case 'vendorcredit_itemline': $objects[$map[0]]->set('VendorCredit_TxnID', $extra['TxnID']); break; case 'vendorcredit_itemgroupline': $objects[$map[0]]->set('VendorCredit_TxnID', $extra['TxnID']); break; case 'vendorcredit_itemgroupline_itemline': $objects[$map[0]]->set('VendorCredit_TxnID', $extra['TxnID']); $objects[$map[0]]->set('VendorCredit_ItemGroupLine_TxnLineID', $extra['TxnLineID']); break; case 'workerscompcode_ratehistory': $objects[$map[0]]->set('WorkersCompCode_ListID', $extra['ListID']); break; } } if (isset($objects[$map[0]])) { $tempMap = array(); $tempOthers = array(); QuickBooks_SQL_Schema::mapToSchema(trim($curpath), QUICKBOOKS_SQL_SCHEMA_MAP_TO_SQL, $tempMap, $tempOthers); if ($map[0] == 'dataextdef_assigntoobject') { if ($objects[$map[0]]->path() != trim($curpath . ' ' . $Node->name()) and strlen(trim($curpath)) < strlen($objects[$map[0]]->path())) { $objects[$map[0]]->change(trim($curpath . ' ' . $Node->name())); } } else { if ($objects[$map[0]]->path() != trim($curpath) and strlen(trim($curpath)) < strlen($objects[$map[0]]->path())) { $objects[$map[0]]->change(trim($curpath)); } } $objects[$map[0]]->set($map[1], $Node->data()); } } }
/** * Transform an XML document into an SQL schema * * @param string $curpath * @param QuickBooks_XML_Node $node * @param array $tables * @return */ protected static function _transform($curpath, $node, &$tables) { //print("\n"); print '' . $curpath . ' node: ' . $node->name() . "\n"; //print(' node: ' . $node->name() . "\n"); //$tables = array(); $table = ''; $field = ''; //QuickBooks_SQL_Schema::mapPathToSQL($node->name(), $table, $field); // table name //print(' table for node: ' . $table . "\n"); //print(' field for node: ' . $field . "\n"); $this_sql = array(); $other_sql = array(); QuickBooks_SQL_Schema::mapToSchema($curpath . ' ' . $node->name(), QUICKBOOKS_SQL_SCHEMA_MAP_TO_SQL, $this_sql, $other_sql); //print('mapping: '); //print_r($this_sql); //print_r($other_sql); //print("\n\n\n"); //print_r($this_sql); foreach (array_merge(array($this_sql), $other_sql) as $sql) { $table = $sql[0]; $field = $sql[1]; if (!$sql[0] or !$sql[1]) { print ' table for node: ' . $sql[0] . "\n"; print ' field for node: ' . $sql[1] . "\n"; } else { print "\n"; } if ($table) { if (!isset($tables[$table])) { //print('trying to map key for: ' . $curpath . ' ' . $name); //$map = null; //QuickBooks_SQL_Schema::mapPrimaryKey($curpath . ' ' . $name, QUICKBOOKS_SQL_SCHEMA_MAP_TO_SQL, $map); //print_r($map); //exit; $tables[$table] = array(0 => $table, 1 => array(), 2 => null, 3 => array(), 4 => array()); } } if ($table and $field) { if (!isset($tables[$table][1][$field])) { $tables[$table][1][$field] = QuickBooks_SQL_Schema::mapFieldToSQLDefinition($table, $field, $node->data()); } } } if ($node->childCount()) { /* $sql = array(); $other_sql = array(); QuickBooks_SQL_Schema::mapToSchema($curpath . ' ' . $node->name(), QUICKBOOKS_SQL_SCHEMA_MAP_TO_SQL, $sql, $other_sql); foreach (array_merge($sql, $other_sql) as $sql) { $table = $sql[0]; $field = $sql[1]; } */ foreach ($node->children() as $child) { QuickBooks_SQL_Schema::_transform($curpath . ' ' . $node->name(), $child, $tables); } } /* print('tables: '); print_r($tables); exit; foreach ($tables as $table) { //print_r($table); exit; } */ }
/** * Transform an XML document into an SQL schema * * @param string $curpath * @param QuickBooks_XML_Node $node * @param array $tables * @return */ protected static function _transform($curpath, $node, &$tables) { print '' . $curpath . ' node: ' . $node->name() . "\n"; $table = ''; $field = ''; $this_sql = array(); $other_sql = array(); QuickBooks_SQL_Schema::mapToSchema($curpath . ' ' . $node->name(), QUICKBOOKS_SQL_SCHEMA_MAP_TO_SQL, $this_sql, $other_sql); foreach (array_merge(array($this_sql), $other_sql) as $sql) { $table = $sql[0]; $field = $sql[1]; /* if (!$sql[0] or !$sql[1]) { print(' table for node: ' . $sql[0] . "\n"); print(' field for node: ' . $sql[1] . "\n"); } else { print("\n"); } */ if ($table) { if (!isset($tables[$table])) { $tables[$table] = array(0 => $table, 1 => array(), 2 => null, 3 => array(), 4 => array()); } } if ($table and $field) { if (!isset($tables[$table][1][$field])) { $tables[$table][1][$field] = QuickBooks_SQL_Schema::mapFieldToSQLDefinition($table, $field, $node->data()); } } } if ($node->childCount()) { foreach ($node->children() as $child) { QuickBooks_SQL_Schema::_transform($curpath . ' ' . $node->name(), $child, $tables); } } return true; }
/** * @TODO Change this to return false by default, and only catch the specific errors we're concerned with. * */ public static function catchall($requestID, $user, $action, $ident, $extra, &$err, $xml, $errnum, $errmsg, $config) { $Driver = QuickBooks_Driver_Singleton::getInstance(); $ignore = array(QUICKBOOKS_IMPORT_DELETEDTXNS => true, QUICKBOOKS_QUERY_DELETEDTXNS => true, QUICKBOOKS_IMPORT_DELETEDLISTS => true, QUICKBOOKS_QUERY_DELETEDLISTS => true, QUICKBOOKS_VOID_TRANSACTION => true, QUICKBOOKS_DELETE_TRANSACTION => true, QUICKBOOKS_DELETE_LIST => true); if (isset($ignore[$action])) { // Ignore errors for these requests return true; } /* $Parser = new QuickBooks_XML($xml); $errnumTemp = 0; $errmsgTemp = ''; $Doc = $Parser->parse($errnumTemp, $errmsgTemp); $Root = $Doc->getRoot(); $emailStr = var_export($Root->children(), true); $List = $Root->getChildAt('QBXML QBXMLMsgsRs '.QuickBooks_Utilities::actionToResponse($action)); $Node = current($List->children()); */ $map = array(); $others = array(); QuickBooks_SQL_Schema::mapToSchema(trim(QuickBooks_Utilities::actionToXMLElement($action)), QUICKBOOKS_SQL_SCHEMA_MAP_TO_SQL, $map, $others); $object = new QuickBooks_SQL_Object($map[0], trim(QuickBooks_Utilities::actionToXMLElement($action))); $table = $object->table(); $existing = null; if ($table and is_numeric($ident)) { $multipart = array(QUICKBOOKS_DRIVER_SQL_FIELD_ID => $ident); $existing = $Driver->get(QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, $multipart); } switch ($errnum) { case 1: // These errors occur when we search for something and it doesn't exist // These errors occur when we search for something and it doesn't exist case 500: // i.e. we query for invoices modified since xyz, but there are none that have been modified since then // This isn't really an error, just ignore it if ($action == QUICKBOOKS_DERIVE_CUSTOMER) { // Tried to derive, doesn't exist, add it $Driver->queueEnqueue($user, QUICKBOOKS_ADD_CUSTOMER, $ident, true, QuickBooks_Utilities::priorityForAction(QUICKBOOKS_ADD_CUSTOMER)); } else { if ($action == QUICKBOOKS_DERIVE_INVOICE) { // Tried to derive, doesn't exist, add it $Driver->queueEnqueue($user, QUICKBOOKS_ADD_INVOICE, $ident, true, QuickBooks_Utilities::priorityForAction(QUICKBOOKS_ADD_INVOICE)); } else { if ($action == QUICKBOOKS_DERIVE_RECEIVEPAYMENT) { // Tried to derive, doesn't exist, add it $Driver->queueEnqueue($user, QUICKBOOKS_ADD_RECEIVEPAYMENT, $ident, true, QuickBooks_Utilities::priorityForAction(QUICKBOOKS_ADD_RECEIVEPAYMENT)); } } } return true; case 1000: // An internal error occured // @todo Hopefully at some point we'll have a better idea of how to handle this error... return true; //case 3120: // 3120 errors are handled in the 3210 error handler section // break; //case 3120: // 3120 errors are handled in the 3210 error handler section // break; case 3170: // This list has been modified by another user. // This list has been modified by another user. case 3175: case 3176: case 3180: // This error can occur in several different situations, so we test per situation if (false !== strpos($errmsg, 'list has been modified by another user') or false !== strpos($errmsg, 'internals could not be locked') or false !== strpos($errmsg, 'failed to acquire the lock') or false !== strpos($errmsg, 'list element is in use')) { // This is *not* an error, we can just send the request again, and it'll go through just fine return true; } break; case 3200: // Ignore EditSequence errors (the record will be picked up and a conflict reported next time it runs... maybe?) if ($action == QUICKBOOKS_MOD_CUSTOMER and $existing) { // Queue up a derive customer request // Tried to derive, doesn't exist, add it $Driver->queueEnqueue($user, QUICKBOOKS_DERIVE_CUSTOMER, $ident, true, 9999, array('ListID' => $existing['ListID'])); } else { if ($action == QUICKBOOKS_MOD_INVOICE and $existing) { // Queue up a derive customer request // Tried to derive, doesn't exist, add it $Driver->queueEnqueue($user, QUICKBOOKS_DERIVE_INVOICE, $ident, true, 9999, array('TxnID' => $existing['TxnID'])); } } return true; case 3120: case 3210: //print_r($existing); //print('TXNID: [' . $existing['TxnID'] . ']'); // 3210: The "AppliedToTxnAdd payment amount" field has an invalid value "129.43". QuickBooks error message: You cannot pay more than the amount due. if ($action == QUICKBOOKS_ADD_RECEIVEPAYMENT and (false !== strpos($errmsg, 'pay more than the amount due') or false !== strpos($errmsg, 'cannot be found')) and $existing) { // If this happens, we're going to try to re-submit the payment, *without* the AppliedToTxn element $db_errnum = null; $db_errmsg = null; $Driver->query("\n\t\t\t\t\t\tUPDATE \n\t\t\t\t\t\t\t" . QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . "receivepayment_appliedtotxn \n\t\t\t\t\t\tSET \n\t\t\t\t\t\t\tqbsql_to_skip = 1 \n\t\t\t\t\t\tWHERE \n\t\t\t\t\t\t\tReceivePayment_TxnID = '%s' ", $db_errnum, $db_errmsg, null, null, array($existing['TxnID'])); return true; } break; case 3250: // This feature is not enabled or not available in this version of QuickBooks. // Do nothing (this can be safely ignored) return true; case 3260: // Insufficient permission level to perform this action. // Insufficient permission level to perform this action. case 3261: // The integrated application has no permission to ac... // There's nothing we can do about this, if they don't grant the user permission, just skip it return true; case 3100: // Name of List Element is already in use. break; case '0x8004040D': // The ticket parameter is invalid (how does this happen!?!) return true; } // This is our catch-all which marks the item as errored out if (strstr($xml, 'statusSeverity="Info"') === false) { $multipart = array(QUICKBOOKS_DRIVER_SQL_FIELD_ID => $ident); $object->set(QUICKBOOKS_DRIVER_SQL_FIELD_ERROR_NUMBER, $errnum); $object->set(QUICKBOOKS_DRIVER_SQL_FIELD_ERROR_MESSAGE, $errmsg); // Do not set the resync field, we want resync and modified timestamps to be different $update_resync_field = false; $update_discov_field = false; $update_derive_field = false; if ($table and is_numeric($ident)) { // Set the error message $Driver->update(QUICKBOOKS_DRIVER_SQL_PREFIX_SQL . $table, $object, array($multipart), $update_resync_field, $update_discov_field, $update_derive_field); } } // Please don't change this, it stops us from knowing what's actually // going wrong. If an error occurs, we should either catch it if it's // recoverable, or treated as a fatal error so we know about it and // can address it later. //return false; // I'm changing it because otherwise the sync never completes if a // single error occurs... we need a way to skip errored-out records return true; }