Merge branch 'dev_4'

[#4] Provide JSON parameter "custom_fields" with a configurable mapping to custom fields
This commit is contained in:
Jens Schuppe 2019-08-07 11:37:40 +02:00
commit aea1db611d
6 changed files with 191 additions and 1 deletions

View file

@ -231,6 +231,13 @@ class CRM_Twingle_Form_Profile extends CRM_Core_Form {
array()
);
$this->add(
'textarea', // field type
'custom_field_mapping', // field name
E::ts('Custom field mapping'), // field label
array()
);
$this->addButtons(array(
array(
'type' => 'submit',
@ -268,6 +275,67 @@ class CRM_Twingle_Form_Profile extends CRM_Core_Form {
$errors['name'] = E::ts('Only alphanumeric characters and the underscore (_) are allowed for profile names.');
}
// Validate custom field mapping.
try {
$custom_field_mapping = preg_split('/\r\n|\r|\n/', $values['custom_field_mapping'], -1, PREG_SPLIT_NO_EMPTY);
if (!is_array($custom_field_mapping)) {
throw new Exception(
E::ts('Could not parse custom field mapping.')
);
}
foreach ($custom_field_mapping as $custom_field_map) {
$custom_field_map = explode("=", $custom_field_map);
if (count($custom_field_map) !== 2) {
throw new Exception(
E::ts('Could not parse custom field mapping.')
);
}
list($twingle_field_name, $custom_field_name) = $custom_field_map;
$custom_field_id = substr($custom_field_name, strlen('custom_'));
// Check for custom field existence
try {
$custom_field = civicrm_api3('CustomField', 'getsingle', array(
'id' => $custom_field_id,
));
}
catch (CiviCRM_API3_Exception $exception) {
throw new Exception(
E::ts(
'Custom field custom_%1 does not exist.',
array(1 => $custom_field_id)
)
);
}
// Only allow custom fields on relevant entities.
try {
$custom_group = civicrm_api3('CustomGroup', 'getsingle', array(
'id' => $custom_field['custom_group_id'],
'extends' => array(
'IN' => array(
'Contact',
'Individual',
'Organization',
'Contribution',
'ContributionRecur',
),
),
));
} catch (CiviCRM_API3_Exception $exception) {
throw new Exception(
E::ts(
'Custom field custom_%1 is not in a CustomGroup that extends one of the supported CiviCRM entities.',
array(1 => $custom_field['id'])
)
);
}
}
}
catch (Exception $exception) {
$errors['custom_field_mapping'] = $exception->getMessage();
}
return empty($errors) ? TRUE : $errors;
}

View file

@ -69,6 +69,21 @@ class CRM_Twingle_Profile {
return in_array($project_id, $project_ids);
}
/**
* @return array
* The profile's configured custom field mapping
*/
public function getCustomFieldMapping() {
$custom_field_mapping = array();
if (!empty($custom_field_definition = $this->getAttribute('custom_field_mapping'))) {
foreach (preg_split('/\r\n|\r|\n/', $custom_field_definition, -1, PREG_SPLIT_NO_EMPTY) as $custom_field_map) {
list($twingle_field_name, $custom_field_name) = explode("=", $custom_field_map);
$custom_field_mapping[$twingle_field_name] = $custom_field_name;
}
}
return $custom_field_mapping;
}
/**
* Retrieves all data attributes of the profile.
*
@ -191,6 +206,7 @@ class CRM_Twingle_Profile {
'donation_receipt_groups',
'campaign',
'contribution_source',
'custom_field_mapping',
);
}
@ -250,6 +266,7 @@ class CRM_Twingle_Profile {
'donation_receipt_groups' => NULL,
'campaign' => NULL,
'contribution_source' => NULL,
'custom_field_mapping' => NULL,
));
}

View file

@ -99,6 +99,16 @@ class CRM_Twingle_Submission {
}
$params['gender_id'] = $gender_id;
}
// Validate custom fields parameter, if given.
if (!empty($params['custom_fields'])) {
if (!is_array($custom_fields = json_decode($params['custom_fields'], TRUE))) {
throw new CiviCRM_API3_Exception(
E::ts('Invalid format for custom fields.'),
'invalid_format'
);
}
}
}
/**

View file

@ -238,6 +238,13 @@ function _civicrm_api3_twingle_donation_Submit_spec(&$params) {
'api.required' => 0,
'description' => E::ts('The CiviCRM ID of a campaign to assign the contribution.'),
);
$params['custom_fields'] = array(
'name' => 'custom_fields',
'title' => E::ts('Custom fields'),
'type' => CRM_Utils_Type::T_STRING,
'api.required' => 0,
'description' => E::ts('Additional information for either the contact or the (recurring) contribution.'),
);
}
/**
@ -280,6 +287,27 @@ function civicrm_api3_twingle_donation_Submit($params) {
);
}
// Extract custom field values using the profile's mapping of Twingle fields
// to CiviCRM custom fields.
$custom_fields = array();
if (!empty($params['custom_fields'])) {
$custom_field_mapping = $profile->getCustomFieldMapping();
foreach (json_decode($params['custom_fields']) as $twingle_field => $value) {
if (isset($custom_field_mapping[$twingle_field])) {
// Get custom field definition to store values by entity the field
// extends.
$custom_field_id = substr($custom_field_mapping[$twingle_field], strlen('custom_'));
$custom_field = civicrm_api3('CustomField', 'getsingle', array(
'id' => $custom_field_id,
// Chain a CustomGroup.getsingle API call.
'api.CustomGroup.getsingle' => array(),
));
$custom_fields[$custom_field['api.CustomGroup.getsingle']['extends']][$custom_field_mapping[$twingle_field]] = $value;
}
}
}
// Create contact(s).
if ($params['is_anonymous']) {
// Retrieve the ID of the contact to use for anonymous donations defined
@ -351,6 +379,15 @@ function civicrm_api3_twingle_donation_Submit($params) {
$contact_data[$contact_component] = $params[$contact_param];
}
}
// Add custom field values.
if (!empty($custom_fields['Contact'])) {
$contact_data += $custom_fields['Contact'];
}
if (!empty($custom_fields['Individual'])) {
$contact_data += $custom_fields['Individual'];
}
if (!$contact_id = CRM_Twingle_Submission::getContact(
'Individual',
$contact_data
@ -375,6 +412,12 @@ function civicrm_api3_twingle_donation_Submit($params) {
$organisation_data = array(
'organization_name' => $params['organization_name'],
);
// Add custom field values.
if (!empty($custom_fields['Organization'])) {
$organisation_data += $custom_fields['Organization'];
}
if (!empty($submitted_address)) {
$organisation_data += $submitted_address;
// Use configured location type for organisation address.
@ -459,6 +502,11 @@ function civicrm_api3_twingle_donation_Submit($params) {
'total_amount' => $params['amount'] / 100,
);
// Add custom field values.
if (!empty($custom_fields['Contribution'])) {
$contribution_data += $custom_fields['Contribution'];
}
if (!empty($params['purpose'])) {
$contribution_data['note'] = $params['purpose'];
}
@ -512,6 +560,10 @@ function civicrm_api3_twingle_donation_Submit($params) {
)
// ... and frequency unit and interval from a static mapping.
+ CRM_Twingle_Submission::getFrequencyMapping($params['donation_rhythm']);
// Add custom field values.
if (!empty($custom_fields['ContributionRecur'])) {
$mandate_data += $custom_fields['ContributionRecur'];
}
// Add cycle day for recurring contributions.
if ($params['donation_rhythm'] != 'one_time') {
@ -543,6 +595,13 @@ function civicrm_api3_twingle_donation_Submit($params) {
'financial_type_id' => $profile->getAttribute('financial_type_id_recur'),
)
+ CRM_Twingle_Submission::getFrequencyMapping($params['donation_rhythm']);
// Add custom field values.
if (!empty($custom_fields['ContributionRecur'])) {
$contribution_recur_data += $custom_fields['ContributionRecur'];
$contribution_data += $custom_fields['ContributionRecur'];
}
$contribution_recur = civicrm_api3('contributionRecur', 'create', $contribution_recur_data);
if ($contribution_recur['is_error']) {
throw new CiviCRM_API3_Exception(

View file

@ -27,3 +27,17 @@
{htxt id='id-financial_type_id_recur'}
{ts domain="de.systopia.twingle"}Select which financial type to use for recurring contributions.{/ts}
{/htxt}
{htxt id='id-custom_field_mapping'}
{ts domain="de.systopia.twingle"}<p>Map Twingle custom fields to CiviCRM custom fields using the following format (each assignment in a separate line):</p>
<pre>twingle_field_1=custom_123<br />twingle_field_2=custom_789</pre>
<p>Always use the <code>custom_[id]</code> notation for CiviCRM custom fields.</p>
<p>Only custom fields extending one of the following CiviCRM entities are allowed:</p>
<ul>
<li><strong>Contact</strong> &ndash; Will be set on the Individual contact</li>
<li><strong>Individual</strong> &ndash; Will be set on the Individual contact</li>
<li><strong>Organization</strong> &ndash; Will be set on the Organization contact, if an organisation name was submitted</li>
<li><strong>Contribution</strong> &ndash; Will be set on the contribution</li>
<li><strong>ContributionRecur</strong> &ndash; Will be set on the recurring contribution and deriving single contributions</li>
</ul>{/ts}
{/htxt}

View file

@ -161,7 +161,7 @@
<fieldset>
<legend>{ts domain="de.systopia.twingle"}Groups{/ts}</legend>
<legend>{ts domain="de.systopia.twingle"}Groups and Correlations{/ts}</legend>
<table class="form-layout-compressed">
@ -190,6 +190,28 @@
<td class="content">{$form.contribution_source.html}</td>
</tr>
<tr class="crm-section">
<td class="label">
{$form.custom_field_mapping.label}
<a
onclick='
CRM.help(
"{ts domain="de.systopia.twingle"}Custom field mapping{/ts}",
{literal}{
"id": "id-custom_field_mapping",
"file": "CRM\/Twingle\/Form\/Profile"
}{/literal}
);
return false;
'
href="#"
title="{ts domain="de.systopia.twingle"}Help{/ts}"
class="helpicon"
></a>
</td>
<td class="content">{$form.custom_field_mapping.html}</td>
</tr>
</table>
</fieldset>