In the `salesforce_pull` module the call to upsert an object expects an array of data to be returned. That is an incorrect assumption according to the latest documentation:

http://www.salesforce.com/us/developer/docs/api_rest/Content/dome_upsert...

In fact, a successful upsert operation actually returns no content and a status code of 204. This breaks the remainder of the `salesforce_push_sync_rest` method because we're never actually told the Salesforce Id. This causes the module to insert an empty salesforce_id into the salesforce_mapping_object table.

Comments

markhuot’s picture

StatusFileSize
new795 bytes

Attaching a patch of how I fixed the issue.

kostajh’s picture

Version: 7.x-3.0-beta4 » 7.x-3.x-dev
Status: Active » Needs review
kostajh’s picture

Status: Needs review » Needs work

Thanks for the patch. I think it would be better to check $contact before assigning the SFID, though.

mariacha1’s picture

Status: Needs work » Needs review
StatusFileSize
new1.09 KB

Here's a new version of the patch with a couple notes:

       // An external key has been specified, attempt an upsert().
       if (!empty($key_field)) {
         $data = $sfapi->objectUpsert($mapping->salesforce_object_type, $key_field, $key_value, $params);
+        // Error handling if no data id is returned, check to see if it was created.
+        if(!isset($data['id'])) {
+          $contact = $sfapi->apiCall("sobjects/{$mapping->salesforce_object_type}/{$key_field}/{$key_value}", 'GET');

We're not making the second call out unless the $data['id'] comes back empty the first time around.

+          if(isset($contact['id'])) {
+            $data['id'] = $contact['id'];
+          }

Also not setting $data['id'] unless $contact['id'] is set.

+          else {
+            $data['errorCode'] = '204';
+            $data['message'] = t('Salesforce sync failed.');
+          }
+        }
       }
       // No key or mapping, create a new object in Salesforce.
       else {

Finally, if all that happens and there's still no $data['id'] throw a message to keep the record from being inserted into the database with an empty id. (If that happens more than once it throws a nasty PDO error.)

moss.dev’s picture

Hi, I have just been testing this patch,

I found that $conatact['id'] needs to be changed to $conatact['Id'] - uppercase I in Id, then all works well.

Thanks, for the patch.

kostajh’s picture

Issue summary: View changes
Status: Needs review » Needs work
aaronbauman’s picture

Couple more minor necessary for this patch:

  • $contact doesn't make sense to me as a variable name. maybe $exists or $fetch instead
  • For the mock errorCode, don't use an HTTP Response code. It should be an appropriate value like "NOT_FOUND"

Finally, minor point of clarification: the initial assertion is not quite accurate.
A SFID will be returned from an upsert() call if an object was created.
This is an important feature that will limit unnecessary API calls.

moss.dev’s picture

I now have content in sync after this patch.

But... one issue I am still getting here is, the Salesforce ID (even on node creation) is not populated to the node. I am having to use a Node ID (External ID) field on salesforce records to check for duplication.

When the node is created and salesforce_push does its stuff the Salesforce ID is sent back but the module is not picking it up. It is shown in the status message but does not make it back to the content.

I'm sure before this patch the Salesforce ID was populated on creation (I may be totally mistaken here) but it definitely happened at one point as I have populated fields.

I will try and get this side of it working today and report back if I manage to.

aaronbauman’s picture

When Drupal has a record of the Salesforce ID, it is in db table salesforce_mapping_object, and is assigned to $entity->salesforce_id during salesforce_mapping_entity_load()

If salesforce_id property is empty or not set, it's because there is no db record of a salesforce object (and your sync probably failed, or was never triggered).

The only explanation I can see for what you're experiencing -- the SF ID reported in the status message but not saved to the db -- is that for some reason the call $mapped_objects->save(); at the end of salesforce_push_sync_rest is failing. If that's the case, there will be PHP or watchdog error log messages about it.

moss.dev’s picture

Oh no, sorry maybe I am not explaining myself to well.

The object sync'd correctly, I have the salesforce ID in salesforce_mapping_object, everything is working as it should.

I also have a field mapped in drupal to the Salesforce ID, which in the old salesforce suite I would use as a key to check the items matched and the record already existed.

I have added this mapping with the new salesforce suite so when I save a node in drupal it pushes all of the fields to Salesforce and what I am then expecting is Salesforce to return the Salesforce ID and that to get updated on the field on the node.

At some point with the new module this has happened as I have some content with the correct SFID stored in my field on the node. At some point this has stopped happening and that was what originally brought me to this thread. It may be that the two are totaly unrelated and I am also starting to think that due to the API update this isn't really supposed to happen any more (although it seems very strange to me that the SFID is not being used as a key now).

aaronbauman’s picture

OK, here is the key difference:

I also have a field mapped in drupal to the Salesforce ID

This issue thread is not about field mappings.
You should create a new issue with your concern (if there isn't one already).

aaronbauman’s picture

Another point on the original issue:
This is actually a more fundamental problem with our Drupal schema in that we rely on Salesforce Id so pervasively.

If we're using upsert(), we already have a unique foreign identifier for the record.
Technically we don't need to store the salesforce id on the Drupal side at all.
(Arguably it's nice to have, but as demonstrated in this issue it can actually cause more confusion.)

I'm not saying it's strictly necessary to fix this issue, but a systemic fix would allow the value of "salesforce_id" to accommodate whatever identifier is used to synch the record -- Salesforce Id, Foreign Key, or LookupId.

bleedev’s picture

Status: Needs work » Fixed

This is now being handled as of commit 2575031.

aaronbauman’s picture

Version: 7.x-3.x-dev » 8.x-3.x-dev
Status: Fixed » Active
Issue tags: +needs-forward-port-to-8.x

  • Commit 2575031 on 7.x-3.x, process-deleted-refactor by bleedev:
    Handle upsert responses
    
    - Issue #1992260 by markhuot, kostajh,...

  • Commit 2575031 on 7.x-3.x, mapped-object-ui by bleedev:
    Handle upsert responses
    
    - Issue #1992260 by markhuot, kostajh,...
aaronbauman’s picture

Cross-promotion: please go upvote this idea
https://success.salesforce.com/ideaView?id=08730000000aBr9AAE

  • aaronbauman committed a4fb119 on 8.x-3.x
    Further update and refactor D8 in prep for alpha release by evanjenkins...
aaronbauman’s picture

Status: Active » Fixed

This is committed.
Please still go and up-vote this idea though:
https://success.salesforce.com/ideaView?id=08730000000aBr9AAE

It would be nice to not have to do this.

  • aaronbauman committed 5631556 on 8.x-3.x
    Issue #1992260 by aaronbauman - Preserve original upsert response when...

  • ironsizide committed 811ef90 on 8.x-3.x
    Merge branch '8.x-3.x' into pull-cron-delete
    
    * 8.x-3.x:
    by aaronbauman...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.