Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delay trigger of salesforce integration until after user has activated their account #1555

Closed
johndwells opened this issue Sep 1, 2023 · 7 comments
Labels

Comments

@johndwells
Copy link

Question

We are using Formie for our front-end user registration forms, and we need this registration information sent to Salesforce. However, user accounts are not activated immediately; rather we send an activation email for them to verify their account.

So it would be ideal if we could delay sending the registration info to Salesforce until after the activation has occurred.

Is that possible?

Could we write custom module code that waits for a user to be activated, and then triggers the Salesforce integration on the related submission?

Additional context

No response

@engram-design
Copy link
Member

That’s an interesting one. Provided there’s a webhook from Salesforce when an account is activated, it should be possible with some effort. The tricky part will be delaying the queue job until this webhook is received.

you could use a module and the payload events to firstly return false on the before send payload. You’d then have to write a webhook listener to wait for Salesforce to report back. Then in that listener, you fetch the submission and manually trigger the Salesforce integrations sendPayload() function to send it to Salesforce.

@johndwells
Copy link
Author

@engram-design Yep this makes sense. Point of clarification, we are waiting for the user to verify their email through Craft, so we don't need to listen to a Salesforce webhook, we simply need to listen to Craft's craft\services\Users::EVENT_AFTER_ACTIVATE_USER event.

Anyway, knowing that I can call sendPayload() on demand is the key, thanks.

When it comes time to running the integration once the user has activated their account, we have the submissionId (which we get from the User record because we have stored the submissionId on a custom field). We also have a few integrations configured for the particular form.

How do we go about getting the correct integration for the submission in question, to call sendPayload() on?

@johndwells
Copy link
Author

@engram-design I think I figured it out, pretty straightforward in the end:

$submission = \verbb\formie\Formie::getInstance()->getSubmissions()->getSubmissionById($submissionId);
if(!$submission) {
	return;
}

$integration = \verbb\formie\Formie::$plugin->getIntegrations()->getIntegrationByHandle('salesforce');
if(!$integration) {
	return;
}

$integration->sendPayload($submission);

But LMK if there's a better way, but that seems right?!

@engram-design
Copy link
Member

Oh, my mistake! There's a slightly similar option with how element integrations need to be handled when we're talking about users. I think I'll bundle this with that issue.

But that's exactly the way to go about it for the moment!

@johndwells
Copy link
Author

johndwells commented Sep 8, 2023

@engram-design So I've been able to test this further, and while the result of $integration->sendPayload($submission); is true, my lead does not appear in Salesforce.

Let me know if you want me to raise a separate ticket, but here's what's happening, from the top:

To recap, we have a configured a "Register" form that asks for the users email & password, and then have configured 2 integrations: 1 to create a Craft user, and 1 to send the submission to Salesforce as a Lead. Without any custom module code, both integrations run fine.

However, we don't want the Salesforce integration to be run until the user has activated their Craft account, by following the verification link that is sent to their inbox.

To accomplish this, in our module we first hook into the Salesforce::EVENT_BEFORE_TRIGGER_INTEGRATION event, and set $event->isValid = false; if the user's account is not active:

/**
 * Do not send Salesforce Lead if user is not yet verified
 */
\yii\base\Event::on(
    \verbb\formie\services\Submissions::class,
    \verbb\formie\services\Submissions::EVENT_BEFORE_TRIGGER_INTEGRATION,
    static function(\verbb\formie\events\TriggerIntegrationEvent $event) {
	    $submission = $event->submission;
	    $type = $event->type;

	    $form = $submission->getForm();
	    if($type != 'verbb\formie\integrations\crm\Salesforce' || $form->handle != 'register') {
		    return;
	    }

	    $user = \craft\elements\User::find()
		    ->email($submission->email)
		    ->status(null)
		    ->one();

	    if(!$user || $user->status != \craft\elements\User::STATUS_ACTIVE) {
		    $event->isValid = false;
	    }
    }
);

Then, we listen to Users::EVENT_AFTER_ACTIVATE_USER, and trigger the payload manually:

/**
 * When a user is activated (e.g. they have verified email), trigger Salesforce integration
 */
Event::on(
    Users::class,
    Users::EVENT_AFTER_ACTIVATE_USER,
    static function(UserEvent $event) {
	    $user = $event->user;
	    $submissionId = $user->submissionId;

	    if(!$submissionId) {
		    return;
	    }

	    $submission = Formie::getInstance()->getSubmissions()->getSubmissionById($submissionId);
	    if(!$submission) {
		    return;
	    }

	    $integration = Formie::$plugin->getIntegrations()->getIntegrationByHandle('salesforce');
	    if(!$integration) {
		    return;
	    }

	    $result = $integration->sendPayload($submission);
    }
);

Using xdebug, I've set a breakpoint inside \verbb\formie\integrations\crm\Salesforce::sendPayload() on this line:

$leadValues = $this->getFieldMappingValues($submission, $this->leadFieldMapping, 'lead');

And found that the content of $leadValues is an empty array. This is because $this->leadFieldMapping is also empty! And because $leadValues is empty, no payload is ever sent.

But in a normal run of the Salesforce integration, $this->leadFieldMapping is an array containing all of the mapping rules, and as a result $leadValues fills up, and the payload is successfully sent.

So the question becomes, how does verbb\formie\integrations\crm\Salesforce::$leadFieldMapping get filled with the necessary data?

Is there something else I need to call after $integration = Formie::$plugin->getIntegrations()->getIntegrationByHandle('salesforce');, or another way to get & fully init the integration model?

@engram-design
Copy link
Member

Ah, yes this is actually a slight limitation of things at the moment that I forgot to mention. You'll need to populate an integration with settings from the form, which is usually done automatically when you trigger running all integrations when a submission is placed. Specifically the Submissions::triggerIntegrations() function.

But if you want to pick one integration to run specifically, you'll need to prep the integration. For the moment, you can do the following before sendPayload()

Formie::$plugin->getIntegrations()->getAllEnabledIntegrationsForForm($submission->form);

I'll look at improving this.

@johndwells
Copy link
Author

@engram-design That did it! Thanks as always for all of your help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants