Question

I am following step 6 of this guide to update a customer's information using the php sdk. The idea is to retrieve the customer by its id and issue an update request for that customer. My code:

$ipp_customer = $data_service->FindById(
  new IPPCustomer( array('Id' => '120'), true)
);
$ipp_customer->sparse = 'true';
$ipp_customer->DisplayName = 'Carrier Name';
$data_service->Update($ipp_customer);

I get a validation error (error code 2090) on the response for the update. It seems the SDK is not populating SyncToken with 0 when generating the update request. This resulted in the validation error.

Then I looked at the sample code provided in the php SDK (/v3-php-sdk-2.0.1/_Samples/CustomerUpdate.php). The sample code uses $dataService->Add for performing the update. The resulting request of calling Add doesn't have SyncToken, so the sample code does not seem applicable.

How to use the SDK correctly to update a customer?

The Request/Response messages are as follow:

REQUEST BODY
=============
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Customer xmlns:ns0="http://schema.intuit.com/finance/v3" sparse="true">
  <ns0:Id>120</ns0:Id>
  <ns0:SyncToken/>
  <ns0:MetaData>
    <ns0:CreateTime/>
    <ns0:LastUpdatedTime/>
  </ns0:MetaData>
  <ns0:FullyQualifiedName/>
  <ns0:DisplayName>Carrier Name</ns0:DisplayName>
  <ns0:PrintOnCheckName/>
  <ns0:Active>true</ns0:Active>
  <ns0:PrimaryPhone>
    <ns0:FreeFormNumber/>
  </ns0:PrimaryPhone>
  <ns0:Fax>
    <ns0:FreeFormNumber/>
  </ns0:Fax>
  <ns0:Taxable>false</ns0:Taxable>
  <ns0:BillAddr>
    <ns0:Id>87</ns0:Id>
    <ns0:Line1/>
    <ns0:Line2/>
    <ns0:City/>
    <ns0:CountrySubDivisionCode/>
    <ns0:PostalCode/>
    <ns0:Lat/>
    <ns0:Long/>
  </ns0:BillAddr>
  <ns0:Job>false</ns0:Job>
  <ns0:BillWithParent>false</ns0:BillWithParent>
  <ns0:Balance>0</ns0:Balance>
  <ns0:BalanceWithJobs>0</ns0:BalanceWithJobs>
  <ns0:PreferredDeliveryMethod/>
</ns0:Customer>

 RESPONSE BODY
 =============
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <IntuitResponse xmlns="http://schema.intuit.com/finance/v3" time="2014-01-21T12:53:53.838-08:00">
  <Fault type="ValidationFault">
   <Error code="2090" element="SyncToken">
    <Message>Invalid Number</Message>
    <Detail>Invalid Number : </Detail>
   </Error>
  </Fault>
 </IntuitResponse>

Thanks.

Edit 1 Here is the Response body as a result of FindById call:

RESPONSE BODY
=============
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<IntuitResponse xmlns="http://schema.intuit.com/finance/v3" time="2014-01-24T10:21:58.493-08:00">
 <Customer domain="QBO" sparse="false">
  <Id>120</Id>
  <SyncToken>13</SyncToken>
  <MetaData>
   <CreateTime>2014-01-17T14:08:42-08:00</CreateTime>
   <LastUpdatedTime>2014-01-24T09:27:00-08:00</LastUpdatedTime>
  </MetaData>
  <FullyQualifiedName>Carrier Name Modif</FullyQualifiedName>
  <DisplayName>Carrier Name Modif</DisplayName>
  <PrintOnCheckName>Carrier Name</PrintOnCheckName>
  <Active>true</Active>
  <Taxable>false</Taxable>
  <BillAddr>
   <Id>87</Id>
  </BillAddr>
  <Job>false</Job>
  <BillWithParent>false</BillWithParent>
  <Balance>0</Balance>
  <BalanceWithJobs>0</BalanceWithJobs>
  <PreferredDeliveryMethod>Print</PreferredDeliveryMethod>
 </Customer>
</IntuitResponse>

Edit 2 I debugged through the SDK using the sample script (CustomerUpdate.php) and using my application code (which is a cakephp webapp). Using print_r, the sample script's call to FindById produced an IPPCustomer with SyncToken outputs:

[SyncToken] => 46

My application code's call to FindById produced:

[SyncToken] => String Object
  (
    [value] => 46
  )

This result led me to believe the xml-to-object parsing is handled differently due to some contextual differences. cakephp has a String class defined and is available for use by the application code. In v3-php-sdk-2.0.1/Dependencies/XDS2PHP/src/com/mikebevz/xsd2php/Bind.php, the function bindXml makes a call to class_exists (around line 138). The following is an excerpt:

if (!class_exists($class_name)) {
  // assign $model->{$name} to child node's value
} else {
  // assign $model->{$name) to newly created object $class_name, which wraps child nodes' value
}

The class_exists('string') evaluates to true when using cakephp (my application code). The class_exists('string') evaluates to false when not using cakephp (the sample script). I believe this is why the xml-to-object parsing behaves differently when using this library. Consequently, I get

<ns0:SyncToken/>   

instead of the expected

<ns0:SyncToken>46</ns0:SyncToken>

It seems cakephp, having defined String class, runs into a conflict situation with IPP PHP SDK. This conflicting situation can be re-created by adding the following line to the sample CustomerUpdate.php script:

require_once('cake/libs/string.php'); // assuming cakephp 1.3's string class

I think the problem is more clear now, any suggestions for a solution?

Was it helpful?

Solution 2

Sorry if my response comes late. I ran into the exact same issue as you Eric, thank you for pointing me in the direction of the /Dependencies/XDS2PHP/src/com/mikebevz/xsd2php/Bind.php file.

The workaround I've implemented for this was to test for the presence of a Controller object(exists in a cakephp environment)

I ended up replacing this :

if (!class_exists($class_name)) {

With:

if (!class_exists($className) || (($className == 'string') && class_exists('Controller'))) {

Now the dataService->Update call is working as expected.

OTHER TIPS

You can use Add to make your code work.

$ipp_customer = $dataService->FindById(
  new IPPCustomer( array('Id' => '6'), true)
);

$ipp_customer->DisplayName = 'Name Name Something';
$dataService->Add($ipp_customer);

This successfully updated the display name of the user with ID 6 in my QuickBooks setup. It should work for you as well.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top