Add a new Salesforce Push Upsert Allowed Event

Created on 9 June 2025, 18 days ago

Problem/Motivation

When no Salesforce ID is set, Upsert is required on push, but in some cases this is undesired.

We have a case where a Lead is converted to a Contact and then the Contact subsequently had their email address changed, in which case we can prevent the push with SalesforcePushAllowedEvent but actually we may want the push to still occur to create a new Lead in this case rather than Upsert into a converted lead (which would result in error code "CANNOT_UPDATE_CONVERTED_LEAD" from Salesforce). Yet the below code does not allow us to skip the upsert and instead go the 'create' route.

MappedObject::push contains:

    if ($this->sfid() && !$mapping->alwaysUpsert()) {
      $action = 'update';
      $result = $this->client()->objectUpdate(
        $mapping->getSalesforceObjectType(),
        $this->sfid(),
        $params->getParams()
      );
    }
    elseif ($mapping->hasKey()) {
      $action = 'upsert';
      $result = $this->client()->objectUpsert(
        $mapping->getSalesforceObjectType(),
        $mapping->getKeyField(),
        $mapping->getKeyValue($drupal_entity),
        $params->getParams()
      );
    }
    else {
      $action = 'create';
      $result = $this->client()->objectCreate(
        $mapping->getSalesforceObjectType(),
        $params->getParams()
      );
    }

Steps to reproduce

  1. Have a mapping for Lead <> Drupal User with upsert key as 'Email'
  2. Have a mapping for Contact <> Drupal User
  3. Register a new user with e.g. me@example.com
  4. Convert a Lead in SF, change its email address to me2@example.com
  5. Sync down Contact <> Drupal User (assuming Lead to Contact conversion is handled in your code)
  6. Register a new user with me@example.com, ie, the same email address of the previously converted Lead
  7. New Mapping is created for (6) yet the Upsert behaviour will kick in on upsert key. But the Lead with that email is already converted. We instead want a new Lead.

Proposed resolution

Add a new event

Remaining tasks

MR

User interface changes

N/A

API changes

New SalesforcePushUpsertAllowedEvent

Data model changes

N/A

✨ Feature request
Status

Active

Version

5.1

Component

salesforce_mapping.module

Created by

πŸ‡¬πŸ‡§United Kingdom scott_euser

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @scott_euser
  • Pipeline finished with Failed
    18 days ago
    Total: 178s
    #518005
  • Pipeline finished with Success
    18 days ago
    Total: 401s
    #518014
  • Pipeline finished with Success
    18 days ago
    Total: 291s
    #518033
  • Pipeline finished with Canceled
    18 days ago
    Total: 117s
    #518049
  • Pipeline finished with Success
    18 days ago
    Total: 323s
    #518052
  • πŸ‡¬πŸ‡§United Kingdom scott_euser

    Added test coverage for the event as well now, ready for review.

  • πŸ‡¬πŸ‡§United Kingdom scott_euser
  • πŸ‡ΊπŸ‡ΈUnited States AaronBauman Philadelphia

    Thank you for the detailed description and the MR.
    This is an interesting idea, I think we can make something work here.

    I don't like having these 2 different events one after another - one event should suffice. And I'd like to see it be a little less single-purpose.

    Proposed changes:
    1. Build this logic into existing PushParams event, rather than adding a new event
    2. Allow subscriber to override push operation and choose any of update, upsert, or create

    So maybe that looks like a new method on PushParams, which can be set by a subscriber to override whatever operation would have been selected in MappedObject::push

    Does this make sense? I think it would solve your issue, as well as making this more useful in more scenarios.

  • πŸ‡¬πŸ‡§United Kingdom scott_euser

    Sure sounds good, thanks for the quick review!

  • Pipeline finished with Canceled
    17 days ago
    Total: 141s
    #519086
  • Pipeline finished with Success
    17 days ago
    Total: 209s
    #519089
  • Pipeline finished with Canceled
    17 days ago
    Total: 145s
    #519125
  • Pipeline finished with Canceled
    17 days ago
    Total: 325s
    #519132
  • πŸ‡¬πŸ‡§United Kingdom scott_euser

    Okay I believe this is now what you described, I moved the choice of action to before the push params event, then pass it as a new argument with set/get methods. Only odd thing is that push params event is also called in PullBase hence the default value being needed here as changing the action is only appropriate to the MappedObject context.

  • Pipeline finished with Success
    17 days ago
    Total: 237s
    #519138
  • πŸ‡ΊπŸ‡ΈUnited States AaronBauman Philadelphia

    Looks good to me.
    Thanks for jumping on that feedback so quickly.
    I'll set to RTBC and get it into the next release.

    push params event is also called in PullBase

    Probably the SalesforcePushParamsEvent in PullBase should be made into its own class.
    Seems like it was shoehorned in there, and is not exactly appropriate for the use case.
    That's outside the scope of this issue though.

  • πŸ‡¬πŸ‡§United Kingdom scott_euser

    Yep makes sense to keep that separate
    Thanks!

Production build 0.71.5 2024