From 73481fb7ed7a54e368e45fa9244b872bbfed941b Mon Sep 17 00:00:00 2001 From: Jens Schuppe Date: Mon, 5 Aug 2019 16:34:35 +0200 Subject: [PATCH 1/2] [#4] (wip) Process custom fields parameter --- CRM/Twingle/Profile.php | 16 ++++++++++ CRM/Twingle/Submission.php | 10 ++++++ api/v3/TwingleDonation/Submit.php | 52 +++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/CRM/Twingle/Profile.php b/CRM/Twingle/Profile.php index 85e6fd0..486e973 100644 --- a/CRM/Twingle/Profile.php +++ b/CRM/Twingle/Profile.php @@ -69,6 +69,20 @@ 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 $twingle_field_name => $custom_field_name) { + $custom_field_mapping[$twingle_field_name] = $custom_field_name; + } + } + return $custom_field_mapping; + } + /** * Retrieves all data attributes of the profile. * @@ -191,6 +205,7 @@ class CRM_Twingle_Profile { 'donation_receipt_groups', 'campaign', 'contribution_source', + 'custom_field_mapping', ); } @@ -250,6 +265,7 @@ class CRM_Twingle_Profile { 'donation_receipt_groups' => NULL, 'campaign' => NULL, 'contribution_source' => NULL, + 'custom_field_mapping' => NULL, )); } diff --git a/CRM/Twingle/Submission.php b/CRM/Twingle/Submission.php index a13d624..2ebf15e 100644 --- a/CRM/Twingle/Submission.php +++ b/CRM/Twingle/Submission.php @@ -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' + ); + } + } } /** diff --git a/api/v3/TwingleDonation/Submit.php b/api/v3/TwingleDonation/Submit.php index 2bdc898..e773f4f 100644 --- a/api/v3/TwingleDonation/Submit.php +++ b/api/v3/TwingleDonation/Submit.php @@ -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,15 @@ 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']; + } + // Add custom field values. + if (!empty($custom_fields['ContributionRecur'])) { + $contribution_data += $custom_fields['ContributionRecur']; + } + if (!empty($params['purpose'])) { $contribution_data['note'] = $params['purpose']; } From b85291527d2176ca21b9b733f953b32dbd6daaca Mon Sep 17 00:00:00 2001 From: Jens Schuppe Date: Tue, 6 Aug 2019 13:58:32 +0200 Subject: [PATCH 2/2] [#4] (wip) Custom field mapping configuration --- CRM/Twingle/Form/Profile.php | 68 ++++++++++++++++++++++++++ CRM/Twingle/Profile.php | 3 +- api/v3/TwingleDonation/Submit.php | 15 ++++-- templates/CRM/Twingle/Form/Profile.hlp | 14 ++++++ templates/CRM/Twingle/Form/Profile.tpl | 24 ++++++++- 5 files changed, 118 insertions(+), 6 deletions(-) diff --git a/CRM/Twingle/Form/Profile.php b/CRM/Twingle/Form/Profile.php index 29ed717..be31ffb 100644 --- a/CRM/Twingle/Form/Profile.php +++ b/CRM/Twingle/Form/Profile.php @@ -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; } diff --git a/CRM/Twingle/Profile.php b/CRM/Twingle/Profile.php index 486e973..7286a23 100644 --- a/CRM/Twingle/Profile.php +++ b/CRM/Twingle/Profile.php @@ -76,7 +76,8 @@ class CRM_Twingle_Profile { 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 $twingle_field_name => $custom_field_name) { + 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; } } diff --git a/api/v3/TwingleDonation/Submit.php b/api/v3/TwingleDonation/Submit.php index e773f4f..e6209da 100644 --- a/api/v3/TwingleDonation/Submit.php +++ b/api/v3/TwingleDonation/Submit.php @@ -506,10 +506,6 @@ function civicrm_api3_twingle_donation_Submit($params) { if (!empty($custom_fields['Contribution'])) { $contribution_data += $custom_fields['Contribution']; } - // Add custom field values. - if (!empty($custom_fields['ContributionRecur'])) { - $contribution_data += $custom_fields['ContributionRecur']; - } if (!empty($params['purpose'])) { $contribution_data['note'] = $params['purpose']; @@ -564,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') { @@ -595,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( diff --git a/templates/CRM/Twingle/Form/Profile.hlp b/templates/CRM/Twingle/Form/Profile.hlp index f2c80e7..2f564be 100644 --- a/templates/CRM/Twingle/Form/Profile.hlp +++ b/templates/CRM/Twingle/Form/Profile.hlp @@ -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"}

Map Twingle custom fields to CiviCRM custom fields using the following format (each assignment in a separate line):

+
twingle_field_1=custom_123
twingle_field_2=custom_789
+

Always use the custom_[id] notation for CiviCRM custom fields.

+

Only custom fields extending one of the following CiviCRM entities are allowed:

+ {/ts} +{/htxt} diff --git a/templates/CRM/Twingle/Form/Profile.tpl b/templates/CRM/Twingle/Form/Profile.tpl index 773dfb7..0835359 100644 --- a/templates/CRM/Twingle/Form/Profile.tpl +++ b/templates/CRM/Twingle/Form/Profile.tpl @@ -161,7 +161,7 @@
- {ts domain="de.systopia.twingle"}Groups{/ts} + {ts domain="de.systopia.twingle"}Groups and Correlations{/ts} @@ -190,6 +190,28 @@ + + + + +
{$form.contribution_source.html}
+ {$form.custom_field_mapping.label} + + {$form.custom_field_mapping.html}