Skip to content

Commit

Permalink
Add “Attach File Uploads” for all data objects for Salesforce integra…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
engram-design committed Feb 13, 2025
1 parent 2083ccf commit c717bd0
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 35 deletions.
110 changes: 75 additions & 35 deletions src/integrations/crm/Salesforce.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

use Craft;
use craft\base\LocalFsInterface;
use craft\elements\db\AssetQuery;
use craft\helpers\App;
use craft\helpers\DateTimeHelper;
use craft\helpers\FileHelper;
Expand Down Expand Up @@ -76,6 +77,11 @@ public static function displayName(): string
public ?array $caseFieldMapping = null;
public bool $duplicateLeadTask = false;
public string $duplicateLeadTaskSubject = 'Task';
public bool $mapToContactAttachments = false;
public bool $mapToLeadAttachments = false;
public bool $mapToOpportunityAttachments = false;
public bool $mapToAccountAttachments = false;
public bool $mapToCaseAttachments = false;

private array $users = [];

Expand Down Expand Up @@ -292,6 +298,12 @@ public function sendPayload(Submission $submission): bool

return false;
}

if ($this->mapToAccountAttachments) {
$this->processAttachments($submission, [
'FirstPublishLocationId' => $accountId,
]);
}
}

$contactId = null;
Expand Down Expand Up @@ -348,6 +360,12 @@ public function sendPayload(Submission $submission): bool
$contactId = $response['records'][0]['Id'] ?? '';
$contactOwnerId = $response['records'][0]['OwnerId'] ?? '';
}

if ($this->mapToContactAttachments) {
$this->processAttachments($submission, [
'FirstPublishLocationId' => $contactId,
]);
}
}

if ($this->mapToLead) {
Expand Down Expand Up @@ -381,6 +399,12 @@ public function sendPayload(Submission $submission): bool

return false;
}

if ($this->mapToLeadAttachments) {
$this->processAttachments($submission, [
'FirstPublishLocationId' => $leadId,
]);
}
} catch (Throwable $e) {
Integration::apiError($this, $e, false);

Expand Down Expand Up @@ -477,6 +501,12 @@ public function sendPayload(Submission $submission): bool

return false;
}

if ($this->mapToOpportunityAttachments) {
$this->processAttachments($submission, [
'FirstPublishLocationId' => $opportunityId,
]);
}
}

if ($this->mapToCase) {
Expand Down Expand Up @@ -507,11 +537,11 @@ public function sendPayload(Submission $submission): bool
return false;
}

$attachmentPayload = [
'FirstPublishLocationId' => $caseId,
];

$this->processAttachments($submission, $this->caseFieldMapping, $this->getFormSettingValue('case'), $attachmentPayload);
if ($this->mapToCaseAttachments) {
$this->processAttachments($submission, [
'FirstPublishLocationId' => $caseId,
]);
}
}
} catch (Throwable $e) {
Integration::apiError($this, $e);
Expand Down Expand Up @@ -570,6 +600,40 @@ protected function defineRules(): array
return $rules;
}

protected function processAttachments(Submission $submission, array $payload): void
{
$localAttachments = [];

// For any File Upload field, add as an attachment.
if ($assets = $this->_getAssetsForSubmission($submission)) {
foreach ($assets as $asset) {
$path = Assets::getFullAssetFilePath($asset);

// If a non-local asset, store so we can delete later
if (!($asset->getVolume()->getFs() instanceof LocalFsInterface)) {
$localAttachments[] = $path;
}

$fileContent = base64_encode(file_get_contents($path));
$fileName = basename($path);

$attachmentPayload = array_merge($payload, [
'Title' => $fileName,
'PathOnClient' => $fileName,
'VersionData' => $fileContent,
]);

$response = $this->deliverPayload($submission, 'sobjects/ContentVersion', $attachmentPayload);
}
}

foreach ($localAttachments as $path) {
if (file_exists($path)) {
unlink($path);
}
}
}


// Private Methods
// =========================================================================
Expand Down Expand Up @@ -706,40 +770,16 @@ private function _prepPayload(array $fields): array
return $payload;
}

protected function processAttachments(Submission $submission, array $fieldMapping, array $fieldSettings, array $payload): void
private function _getAssetsForSubmission(Submission $submission): array
{
// For any mapped File Upload fields, also add as an attachment
$fileUploads = $this->getMappedFieldsByType($submission, $fieldMapping, $fieldSettings, FileUpload::class);
$localAttachments = [];

foreach ($fileUploads as $fileUpload) {
$assets = $fileUpload['value']->all();
$assets = [];

foreach ($assets as $asset) {
$path = Assets::getFullAssetFilePath($asset);

// If a non-local asset, store so we can delete later
if (!($asset->getVolume()->getFs() instanceof LocalFsInterface)) {
$localAttachments[] = $path;
}

$fileContent = base64_encode(file_get_contents($path));
$fileName = basename($path);

$attachmentPayload = array_merge($payload, [
'Title' => $fileName,
'PathOnClient' => $fileName,
'VersionData' => $fileContent,
]);

$response = $this->deliverPayload($submission, 'sobjects/ContentVersion', $attachmentPayload);
foreach ($submission->getFieldValuesForField(FileUpload::class) as $value) {
if ($value instanceof AssetQuery) {
$assets[] = $value->all();
}
}

foreach ($localAttachments as $path) {
if (file_exists($path)) {
unlink($path);
}
}
return array_merge(...$assets);
}
}
46 changes: 46 additions & 0 deletions src/templates/integrations/crm/salesforce/_form-settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
{% set duplicateLeadTask = form.settings.integrations[handle].duplicateLeadTask ?? '' %}
{% set duplicateLeadTaskSubject = form.settings.integrations[handle].duplicateLeadTaskSubject ?? '' %}

{% set mapToContactAttachments = form.settings.integrations[handle].mapToContactAttachments ?? '' %}
{% set mapToLeadAttachments = form.settings.integrations[handle].mapToLeadAttachments ?? '' %}
{% set mapToOpportunityAttachments = form.settings.integrations[handle].mapToOpportunityAttachments ?? '' %}
{% set mapToAccountAttachments = form.settings.integrations[handle].mapToAccountAttachments ?? '' %}
{% set mapToCaseAttachments = form.settings.integrations[handle].mapToCaseAttachments ?? '' %}

<field-select
label="{{ 'Opt-In Field' | t('formie') }}"
instructions="{{ 'Choose a field to opt-in to {name}. For example, you might only wish to record user data if they provide a value for a field of your choice - commonly, an Agree field.' | t('formie', { name: displayName }) }}"
Expand Down Expand Up @@ -46,6 +52,14 @@
}) }}

<div id="map-to-contact" class="{{ not mapToContact ? 'hidden' }}">
{{ forms.lightswitchField({
label: 'Attach File Uploads' | t('formie'),
instructions: 'Whether all File Upload fields should upload their files as attachments.' | t('formie', { name: displayName }),
id: 'mapToContactAttachments',
name: 'mapToContactAttachments',
on: mapToContactAttachments,
}) }}

<integration-field-mapping
label="{{ 'Contact Field Mapping' | t('formie') }}"
instructions="{{ 'Choose how your form fields should map to your {name} {label} fields.' | t('formie', { name: displayName, label: 'Contact' }) }}"
Expand Down Expand Up @@ -73,6 +87,14 @@
}) }}

<div id="map-to-lead" class="{{ not mapToLead ? 'hidden' }}">
{{ forms.lightswitchField({
label: 'Attach File Uploads' | t('formie'),
instructions: 'Whether all File Upload fields should upload their files as attachments.' | t('formie', { name: displayName }),
id: 'mapToLeadAttachments',
name: 'mapToLeadAttachments',
on: mapToLeadAttachments,
}) }}

{{ forms.lightswitchField({
label: 'Create Task for Duplicates' | t('formie'),
instructions: 'If a Lead is detected as duplicate, a new {name} Task object will be created.' | t('formie', { name: displayName }),
Expand Down Expand Up @@ -118,6 +140,14 @@
}) }}

<div id="map-to-opportunity" class="{{ not mapToOpportunity ? 'hidden' }}">
{{ forms.lightswitchField({
label: 'Attach File Uploads' | t('formie'),
instructions: 'Whether all File Upload fields should upload their files as attachments.' | t('formie', { name: displayName }),
id: 'mapToOpportunityAttachments',
name: 'mapToOpportunityAttachments',
on: mapToOpportunityAttachments,
}) }}

<integration-field-mapping
label="{{ 'Opportunity Field Mapping' | t('formie') }}"
instructions="{{ 'Choose how your form fields should map to your {name} {label} fields.' | t('formie', { name: displayName, label: 'Opportunity' }) }}"
Expand Down Expand Up @@ -145,6 +175,14 @@
}) }}

<div id="map-to-account" class="{{ not mapToAccount ? 'hidden' }}">
{{ forms.lightswitchField({
label: 'Attach File Uploads' | t('formie'),
instructions: 'Whether all File Upload fields should upload their files as attachments.' | t('formie', { name: displayName }),
id: 'mapToAccountAttachments',
name: 'mapToAccountAttachments',
on: mapToAccountAttachments,
}) }}

<integration-field-mapping
label="{{ 'Account Field Mapping' | t('formie') }}"
instructions="{{ 'Choose how your form fields should map to your {name} {label} fields.' | t('formie', { name: displayName, label: 'Account' }) }}"
Expand Down Expand Up @@ -172,6 +210,14 @@
}) }}

<div id="map-to-case" class="{{ not mapToCase ? 'hidden' }}">
{{ forms.lightswitchField({
label: 'Attach File Uploads' | t('formie'),
instructions: 'Whether all File Upload fields should upload their files as attachments.' | t('formie', { name: displayName }),
id: 'mapToCaseAttachments',
name: 'mapToCaseAttachments',
on: mapToCaseAttachments,
}) }}

<integration-field-mapping
label="{{ 'Case Field Mapping' | t('formie') }}"
instructions="{{ 'Choose how your form fields should map to your {name} {label} fields.' | t('formie', { name: displayName, label: 'Case' }) }}"
Expand Down

0 comments on commit c717bd0

Please sign in to comment.