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?
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.