diff --git a/includes/contact_component.inc b/includes/contact_component.inc index 1c0496dad..0c0d95b6b 100644 --- a/includes/contact_component.inc +++ b/includes/contact_component.inc @@ -253,7 +253,7 @@ function _webform_edit_civicrm_contact($component) { '#parents' => array('extra', 'default_custom_ref'), ); } - + $case_count = isset($data['case']['number_of_case']) ? $data['case']['number_of_case'] : 0; if ($case_count > 0) { $form['defaults']['default']['#options']['case_roles'] = t('Case roles'); @@ -347,7 +347,7 @@ function _webform_edit_civicrm_contact($component) { '#type' => 'select', '#multiple' => TRUE, '#title' => t('Tags'), - '#options' => array('' => '- ' . t('None') . ' -') + CRM_Core_BAO_Tag::getTags("civicrm_contact", $tags, NULL, '- '), + '#options' => array('' => '- ' . t('None') . ' -') + wf_crm_get_tags('contact'), '#default_value' => $component['extra']['filters']['tag'], '#description' => t('Listed contacts must be have at least one of the selected tags (leave blank to not filter by tag).'), ); @@ -887,55 +887,56 @@ function wf_crm_update_existing_component(&$component, $enabled, $data) { * @return array */ function wf_crm_find_relations($cid, $types = array(), $current = TRUE) { - $found = $allowed = array(); + $found = $allowed = $type_ids = []; $cid = (int) $cid; static $employer_type = 0; if ($cid) { if (!$employer_type && $current) { $employer_type = wf_crm_aval(wf_civicrm_api('relationshipType', 'get', array('name_a_b' => 'Employee of', 'return' => 'id')), 'id'); } - $type_ids = ''; foreach ($types as $t) { - list($type, $a_b) = explode('_', $t); + list($type, $a) = explode('_', $t); // Put current employer first in the list if ($type == $employer_type && $current) { - $sql = "SELECT id, employer_id - FROM civicrm_contact - WHERE id = $cid OR employer_id = $cid"; - $dao = CRM_Core_DAO::executeQuery($sql); - $employer = $dao->id == $cid ? $dao->employer_id : $dao->id; - while ($dao->fetch()) { - $found[$employer] = $employer; + $search_key = $a == 'b' ? 'id' : 'employer_id'; + // Note: inconsistency in api3 - search key is "employer_id" but return key is "current_employer_id" + $employer = wf_crm_apivalues('contact', 'get', [ + $search_key => $cid, + 'sequential' => 1, + ], $a == 'b' ? 'current_employer_id' : 'id'); + if ($employer) { + $found[$employer[0]] = $employer[0]; } - $dao->free(); } - $type_ids .= ($type_ids ? ',' : '') . $type; - if ($a_b == 'a' || $a_b == 'r') { + $type_ids[] = $type; + if ($a == 'a' || $a == 'r') { $allowed[] = $type . '_a'; } - if ($a_b == 'b' || $a_b == 'r') { + if ($a == 'b' || $a == 'r') { $allowed[] = $type . '_b'; } } - $typeClause = ''; + $params = [ + 'return' => ['contact_id_a', 'contact_id_b', 'relationship_type_id', 'end_date'], + 'contact_id_a' => $cid, + 'contact_id_b' => $cid, + 'options' => ['or' => [['contact_id_a', 'contact_id_b']]], + ]; if ($type_ids) { - $typeClause = "AND relationship_type_id IN ($type_ids)"; + $params['relationship_type_id'] = ['IN' => $type_ids]; } - $sql = "SELECT relationship_type_id, contact_id_a, contact_id_b - FROM civicrm_relationship - WHERE (contact_id_a = $cid OR contact_id_b = $cid) $typeClause"; if ($current) { - $sql .= " AND is_active = 1 AND (end_date > CURDATE() OR end_date IS NULL)"; + $params['is_active'] = 1; } - $dao = CRM_Core_DAO::executeQuery($sql); - while ($dao->fetch()) { - $a_b = $dao->contact_id_a == $cid ? 'b' : 'a'; - if (!$allowed || in_array($dao->relationship_type_id . '_' . $a_b, $allowed)) { - $c = $dao->{"contact_id_$a_b"}; - $found[$c] = $c; + foreach (wf_crm_apivalues('relationship', 'get', $params) as $relationship) { + $a = $relationship['contact_id_a'] == $cid ? 'b' : 'a'; + if (!$current || empty($relationship['end_date']) || strtotime($relationship['end_date']) > time()) { + if (!$allowed || in_array($relationship['relationship_type_id'] . '_' . $a, $allowed)) { + $c = $relationship["contact_id_$a"]; + $found[$c] = $c; + } } } - $dao->free(); } return $found; } diff --git a/includes/utils.inc b/includes/utils.inc index 4a4b8ebc9..371c506e9 100644 --- a/includes/utils.inc +++ b/includes/utils.inc @@ -54,14 +54,12 @@ function wf_crm_field_options($field, $context, $data) { elseif ($name == 'privacy') { $ret = wf_crm_get_privacy_options(); } - elseif ($table === 'other') { - if ($field['table'] === 'tag') { - $split = explode('_', $name); - $ret = CRM_Core_BAO_Tag::getTags("civicrm_{$ent}", $ret, wf_crm_aval($split, 1), '- '); - } - elseif ($field['table'] === 'group') { - $ret = wf_crm_apivalues('group', 'get', array('is_hidden' => 0), 'title'); - } + elseif (isset($field['table']) && $field['table'] === 'tag') { + $split = explode('_', $name); + $ret = wf_crm_get_tags($ent, wf_crm_aval($split, 1)); + } + elseif (isset($field['table']) && $field['table'] === 'group') { + $ret = wf_crm_apivalues('group', 'get', array('is_hidden' => 0), 'title'); } elseif ($name === 'survey_id') { $ret = wf_crm_get_surveys(wf_crm_aval($data, "activity:$c:activity:1", array())); @@ -120,29 +118,78 @@ function wf_crm_field_options($field, $context, $data) { return $ret; } +/** + * Fetch tags within a given tagset + * + * If no tagset specified, all tags NOT within a tagset are returned. + * Return format is a flat array with some tic marks to indicate nesting. + * + * @param string $used_for + * @param int $parent_id + * @return array + */ +function wf_crm_get_tags($used_for, $parent_id = NULL) { + $params = [ + 'used_for' => ['LIKE' => "%civicrm_{$used_for}%"], + 'is_tagset' => 0, + 'is_selectable' => 1, + 'parent_id' => $parent_id ?: ['IS NULL' => 1], + 'options' => ['sort' => 'name'], + ]; + $tags = wf_crm_apivalues('Tag', 'get', $params, 'name'); + // Tagsets cannot be nested so no need to fetch children + if ($parent_id || !$tags) { + return $tags; + } + // Fetch child tags + unset($params['parent_id']); + $params += ['return' => ['name', 'parent_id'], 'parent_id.is_tagset' => 0, 'parent_id.is_selectable' => 1]; + $unsorted = wf_crm_apivalues('Tag', 'get', $params); + $parents = array_fill_keys(array_keys($tags), ['depth' => 1]); + // Loop until all children are placed under their parents + while ($unsorted) { + foreach ($unsorted as $id => $tag) { + $parent = $tag['parent_id']; + if (isset($parents[$parent])) { + $name = str_repeat('- ', $parents[$parent]['depth']) . $tag['name']; + $pos = array_search($parents[$parent]['child'] ?? $parent, array_keys($tags)) + 1; + $tags = array_slice($tags, 0, $pos, TRUE) + [$id => $name] + array_slice($tags, $pos, NULL, TRUE); + $parents[$id] = ['depth' => $parents[$parent]['depth'] + 1]; + $parents[$parent]['child'] = $id; + unset($unsorted[$id]); + } + } + } + return $tags; +} + /** * Get list of states, keyed by abbreviation rather than ID. - * FIXME use the api for this. + * * @param null|int|string $param + * @return array */ function wf_crm_get_states($param = NULL) { $ret = array(); if (!$param || $param == 'default') { - $config = CRM_Core_Config::singleton(); - if (!$param && !empty($config->provinceLimit)) { - $param = implode(',', $config->provinceLimit); + $provinceLimit = wf_crm_get_civi_setting('provinceLimit'); + if (!$param && $provinceLimit) { + $param = (array) $provinceLimit; } else { - $param = (int) $config->defaultContactCountry; + $param = [(int) wf_crm_get_civi_setting('defaultContactCountry', 1228)]; } } else { - $param = (int) $param; + $param = array((int) $param); } - $sql = "SELECT name AS label, UPPER(abbreviation) AS value FROM civicrm_state_province WHERE country_id IN ($param) ORDER BY name"; - $dao = CRM_Core_DAO::executeQuery($sql); - while ($dao->fetch()) { - $ret[$dao->value] = $dao->label; + $states = wf_crm_apivalues('state_province', 'get', array( + 'return' => 'abbreviation,name', + 'sort' => 'name', + 'country_id' => array('IN' => $param) + )); + foreach ($states as $state) { + $ret[strtoupper($state['abbreviation'])] = $state['name']; } // Localize the state/province names if in an non-en_US locale $tsLocale = CRM_Utils_System::getUFLocale(); @@ -167,62 +214,73 @@ function wf_crm_get_states($param = NULL) { * @return string or integer */ function wf_crm_state_abbr($input, $ret = 'abbreviation', $country_id = NULL) { - $input_type = $ret == 'id' ? 'abbreviation' : 'id'; - $sql = "SELECT $ret FROM civicrm_state_province WHERE $input_type = %1"; - $vars = array(1 => array($input, $ret == 'id' ? 'String' : 'Integer')); - if ($ret === 'id') { + $params = ['sequential' => 1]; + if ($ret == 'id') { + $params['abbreviation'] = $input; if (!$country_id || $country_id === 'default') { - $config = CRM_Core_Config::singleton(); - $country_id = (int) $config->defaultContactCountry; + $country_id = (int) wf_crm_get_civi_setting('defaultContactCountry', 1228); } - $sql .= ' AND country_id = %2'; - $vars[2] = array($country_id, 'Integer'); } - $sql .= ' LIMIT 0, 1'; - return CRM_Core_DAO::singleValueQuery($sql, $vars); + else { + $params['id'] = $input; + } + $params['country_id'] = $country_id; + $result = wf_crm_apivalues('StateProvince', 'get', $params, $ret); + return wf_crm_aval($result, 0); } /** * Get list of events. - * FIXME use the api for this. * * @param array $reg_options * @param string $context + * * @return array */ function wf_crm_get_events($reg_options, $context) { - $ret = array(); + $ret = []; $format = wf_crm_aval($reg_options, 'title_display', 'title'); - $sql = "SELECT id, title, start_date, end_date, event_type_id FROM civicrm_event WHERE is_template = 0 AND is_active = 1"; + $params = [ + 'is_template' => 0, + 'is_active' => 1, + ]; + $event_types = array_filter((array) $reg_options['event_type'], "is_numeric"); + if ($event_types) { + $params['event_type_id'] = ['IN' => $event_types]; + } + if (is_numeric(wf_crm_aval($reg_options, 'show_public_events'))) { + $params['is_public'] = $reg_options['show_public_events']; + } + $params['options'] = ['sort' => 'start_date' . ($context == 'config_form' ? ' DESC' : '')]; + $values = wf_crm_apivalues('Event', 'get', $params); // 'now' means only current events, 1 means show all past events, other values are relative date strings $date_past = wf_crm_aval($reg_options, 'show_past_events', 'now'); if ($date_past != '1') { $date_past = date('Y-m-d H:i:s', strtotime($date_past)); - $sql .= " AND (end_date >= '$date_past' OR end_date IS NULL)"; + foreach ($values as $key => $value) { + if (isset($value['end_date']) && $value['end_date'] <= $date_past) { + unset($values[$key]); + } + } } // 'now' means only past events, 1 means show all future events, other values are relative date strings $date_future = wf_crm_aval($reg_options, 'show_future_events', '1'); if ($date_future != '1') { $date_future = date('Y-m-d H:i:s', strtotime($date_future)); - $sql .= " AND (end_date <= '$date_future' OR end_date IS NULL)"; - } - $event_types = array_filter((array) $reg_options['event_type'], "is_numeric"); - if ($event_types) { - $sql .= ' AND event_type_id IN ( ' . implode(", ", $event_types) . ' ) '; - } - if (is_numeric(wf_crm_aval($reg_options, 'show_public_events'))) { - $sql .= ' AND is_public = ' . $reg_options['show_public_events']; + foreach ($values as $key => $value) { + if (isset($value['end_date']) && $value['end_date'] >= $date_future) { + unset($values[$key]); + } + } } - $sql .= ' ORDER BY start_date ' . ($context == 'config_form' ? 'DESC' : ''); - $dao = CRM_Core_DAO::executeQuery($sql); - while ($dao->fetch()) { - $ret[$dao->id . '-' . $dao->event_type_id] = wf_crm_format_event($dao, $format); + foreach ($values as $value) { + $ret[$value['id'] . '-' . $value['event_type_id']] = wf_crm_format_event($value, $format); } return $ret; } /** - * @param array|object $event + * @param array $event * @param string $format * @return string */ @@ -231,28 +289,29 @@ function wf_crm_format_event($event, $format) { // Date format foreach ($format as $value) { if (strpos($value, 'dateformat') === 0) { - $config = CRM_Core_Config::singleton(); - $date_format = $config->$value; + $date_format = wf_crm_get_civi_setting($value); } } - $event = (object) $event; - $title = array(); + $title = []; if (in_array('title', $format)) { - $title[] = $event->title; + $title[] = $event['title']; } if (in_array('type', $format)) { - $types = wf_crm_apivalues('event', 'getoptions', array('field' => 'event_type_id', 'context' => 'get')); - $title[] = $types[$event->event_type_id]; + $types = wf_crm_apivalues('event', 'getoptions', [ + 'field' => 'event_type_id', + 'context' => 'get', + ]); + $title[] = $types[$event['event_type_id']]; } - if (in_array('start', $format) && $event->start_date) { - $title[] = CRM_Utils_Date::customFormat($event->start_date, $date_format); + if (in_array('start', $format) && !empty($event['start_date'])) { + $title[] = CRM_Utils_Date::customFormat($event['start_date'], $date_format); } - if (in_array('end', $format) && $event->end_date) { + if (in_array('end', $format) && isset($event['end_date'])) { // Avoid showing redundant end-date if it is the same as the start date - $same_day = substr($event->start_date, 0, 10) == substr($event->end_date, 0, 10); + $same_day = substr($event['start_date'], 0, 10) == substr($event['end_date'], 0, 10); if (!$same_day || in_array('dateformatDatetime', $format) || in_array('dateformatTime', $format)) { - $end_format = (in_array('dateformatDatetime', $format) && $same_day) ? $config->dateformatTime : $date_format; - $title[] = CRM_Utils_Date::customFormat($event->end_date, $end_format); + $end_format = (in_array('dateformatDatetime', $format) && $same_day) ? wf_crm_get_civi_setting('dateformatTime') : $date_format; + $title[] = CRM_Utils_Date::customFormat($event['end_date'], $end_format); } } return implode(' - ', $title); @@ -393,10 +452,10 @@ function wf_crm_get_matching_rules($contact_type) { static $rules; $contact_type = ucfirst($contact_type); if (!$rules) { - $rules = array_fill_keys(array('Individual', 'Organization', 'Household'), array()); - $dao = CRM_Core_DAO::executeQuery('SELECT * FROM civicrm_dedupe_rule_group'); - while ($dao->fetch()) { - $rules[$dao->contact_type][$dao->id] = $dao->title; + $rules = array_fill_keys(['Individual', 'Organization', 'Household'], []); + $values = wf_crm_apivalues('RuleGroup', 'get'); + foreach ($values as $value) { + $rules[$value['contact_type']][$value['id']] = $value['title']; } } return $rules[$contact_type]; @@ -469,8 +528,7 @@ function wf_crm_get_fields($var = 'fields') { static $sets; if (!$fields) { - $config = CRM_Core_Config::singleton(); - $components = $config->enableComponents; + $components = wf_crm_get_civi_setting('enable_components'); $sets = array( 'contact' => array('entity_type' => 'contact', 'label' => t('Contact Fields')), @@ -480,7 +538,7 @@ function wf_crm_get_fields($var = 'fields') { 'email' => array('entity_type' => 'contact', 'label' => t('Email'), 'max_instances' => 9, 'custom_fields' => 'combined'), 'website' => array('entity_type' => 'contact', 'label' => t('Website'), 'max_instances' => 9, 'custom_fields' => 'combined'), 'im' => array('entity_type' => 'contact', 'label' => t('Instant Message'), 'max_instances' => 9, 'custom_fields' => 'combined'), - 'activity' => array('entity_type' => 'activity', 'label' => t('Activity'), 'max_instances' => 40, 'attachments' => TRUE), + 'activity' => array('entity_type' => 'activity', 'label' => t('Activity'), 'max_instances' => 60, 'attachments' => TRUE), 'relationship' => array('entity_type' => 'contact', 'label' => t('Relationship'), 'help_text' => TRUE, 'custom_fields' => 'combined'), ); $conditional_sets = array( @@ -504,9 +562,9 @@ function wf_crm_get_fields($var = 'fields') { 'type' => 'number', 'data_type' => 'Money', 'extra' => array( - 'field_prefix' => wf_crm_aval($config, 'defaultCurrencySymbol', '$'), - 'point' => wf_crm_aval($config, 'monetaryDecimalPoint', '.'), - 'separator' => wf_crm_aval($config, 'monetaryThousandSeparator', ','), + 'field_prefix' => wf_crm_get_civi_setting('defaultCurrencySymbol', '$'), + 'point' => wf_crm_get_civi_setting('monetaryDecimalPoint', '.'), + 'separator' => wf_crm_get_civi_setting('monetaryThousandSeparator', ','), 'decimals' => 2, 'min' => 0, ), @@ -543,15 +601,9 @@ function wf_crm_get_fields($var = 'fields') { 'contact_type' => 'organization', ); // Individual names - if (version_compare(CRM_Utils_System::version(), '4.5', '<')) { - // This setting doesn't exist prior to 4.5 so hard-code it. - $enabled_names = array('Prefix', 'Suffix', 'First Name', 'Middle Name', 'Last Name'); - } - else { - $enabled_names = wf_crm_explode_multivalue_str(CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'contact_edit_options')); - $name_options = CRM_Core_OptionGroup::values('contact_edit_options', FALSE, FALSE, FALSE, NULL, 'name'); - $enabled_names = array_intersect_key($name_options, array_flip($enabled_names)); - } + $enabled_names = wf_crm_get_civi_setting('contact_edit_options'); + $name_options = array_column(wf_crm_apivalues('OptionValue', 'get', ['option_group_id' => 'contact_edit_options', 'return' => ['name', 'value']]), 'name', 'value'); + $enabled_names = array_intersect_key($name_options, array_flip($enabled_names)); foreach (array('prefix_id' => t('Name Prefix'), 'formal_title' => t('Formal Title'), 'first_name' => t('First Name'), 'middle_name' => t('Middle Name'), 'last_name' => t('Last Name'), 'suffix_id' => t('Name Suffix')) as $key => $label) { if (in_array(ucwords(str_replace(array('_id', '_'), array('', ' '), $key)), $enabled_names)) { $fields['contact_' . $key] = array( @@ -598,7 +650,7 @@ function wf_crm_get_fields($var = 'fields') { $fields['contact_preferred_language'] = array( 'name' => t('Preferred Language'), 'type' => 'select', - 'value' => $config->lcMessages, + 'value' => wf_crm_get_civi_setting('lcMessages', 'en_US'), ); if (array_key_exists('file', webform_components())) { $fields['contact_image_URL'] = array( @@ -692,7 +744,7 @@ function wf_crm_get_fields($var = 'fields') { 'name' => t('Country'), 'type' => 'select', 'extra' => array('civicrm_live_options' => 1), - 'value' => $config->defaultContactCountry, + 'value' => wf_crm_get_civi_setting('defaultContactCountry', 1228), ); $fields['address_state_province_id'] = array( 'name' => t('State/Province'), @@ -740,14 +792,17 @@ function wf_crm_get_fields($var = 'fields') { 'type' => 'select', 'expose_list' => TRUE, ); - $defaultLocType = CRM_Core_BAO_LocationType::getDefault(); + $defaultLocType = wf_crm_aval(wf_civicrm_api('LocationType', 'get', [ + 'return' => ["id"], + 'is_default' => 1, + ]), 'id'); foreach (array('address' => t('Address # Location'), 'phone' => t('Phone # Location'), 'email' => t('Email # Location'), 'im' => t('IM # Location')) as $key => $label) { if (isset($sets[$key])) { $fields[$key . '_location_type_id'] = array( 'name' => $label, 'type' => 'select', 'expose_list' => TRUE, - 'value' => $defaultLocType->id, + 'value' => $defaultLocType, ); } } @@ -768,16 +823,6 @@ function wf_crm_get_fields($var = 'fields') { 'table' => 'group', 'expose_list' => TRUE, ); - $tagsets = array('' => t('Tag(s)')) + CRM_Core_BAO_Tag::getTagSet('civicrm_contact'); - foreach ($tagsets as $pid => $name) { - $fields['other_tag' . ($pid ? "_$pid" : '')] = array( - 'name' => $name, - 'type' => 'select', - 'extra' => array('multiple' => 1, 'civicrm_live_options' => 1), - 'table' => 'tag', - 'expose_list' => TRUE, - ); - } $fields['activity_activity_type_id'] = array( 'name' => t('Activity # Type'), 'type' => 'select', @@ -849,8 +894,9 @@ function wf_crm_get_fields($var = 'fields') { 'integer' => 1, ), ); + $tag_entities = array('other', 'activity'); if (isset($sets['case'])) { - $case_info = new CRM_Case_XMLProcessor_Process(); + $tag_entities[] = 'case'; $fields['case_case_type_id'] = array( 'name' => t('Case # Type'), 'type' => 'select', @@ -860,7 +906,7 @@ function wf_crm_get_fields($var = 'fields') { 'name' => t('Case # Client'), 'type' => 'select', 'expose_list' => TRUE, - 'extra' => array('required' => 1, 'multiple' => $case_info->getAllowMultipleCaseClients()), + 'extra' => array('required' => 1, 'multiple' => wf_crm_get_civi_setting('civicaseAllowMultipleClients', 0)), 'data_type' => 'ContactReference', 'set' => 'caseRoles', 'value' => 1, @@ -904,12 +950,10 @@ function wf_crm_get_fields($var = 'fields') { ); // Fetch case roles $sets['caseRoles'] = array('entity_type' => 'case', 'label' => t('Case Roles')); - // Use the vanilla civicrm_api for this because it will throw an error in CiviCRM 4.4 (api doesn't exist) - $case_types = civicrm_api('case_type', 'get', array('version' => 3, 'options' => array('limit' => 0))); - foreach (wf_crm_aval($case_types, 'values', array()) as $case_type) { + foreach (wf_crm_apivalues('case_type', 'get') as $case_type) { foreach ($case_type['definition']['caseRoles'] as $role) { foreach (wf_crm_get_relationship_types() as $rel_type) { - if ($rel_type['name_b_a'] == $role['name']) { + if (in_array($role['name'], [$rel_type['name_b_a'], $rel_type['label_b_a']])) { if (!isset($fields['case_role_' . $rel_type['id']])) { $fields['case_role_' . $rel_type['id']] = array( 'name' => $rel_type['label_b_a'], @@ -930,6 +974,29 @@ function wf_crm_get_fields($var = 'fields') { } } } + $all_tagsets = wf_crm_apivalues('tag', 'get', [ + 'return' => ['id', 'name', 'used_for'], + 'is_tagset' => 1, + 'parent_id' => ['IS NULL' => 1], + ]); + foreach ($tag_entities as $entity) { + $table_name = $entity == 'other' ? 'civicrm_contact' : "civicrm_$entity"; + $tagsets = ['' => t('Tag(s)')]; + foreach ($all_tagsets as $set) { + if (strpos($set['used_for'], $table_name) !== FALSE) { + $tagsets[$set['id']] = $set['name']; + } + } + foreach ($tagsets as $pid => $name) { + $fields[$entity . '_tag' . ($pid ? "_$pid" : '')] = [ + 'name' => $name, + 'type' => 'select', + 'extra' => ['multiple' => 1, 'civicrm_live_options' => 1], + 'table' => 'tag', + 'expose_list' => TRUE, + ]; + } + } $fields['relationship_relationship_type_id'] = array( 'name' => t('Relationship Type(s)'), 'type' => 'select', @@ -1074,7 +1141,7 @@ function wf_crm_get_fields($var = 'fields') { ), 'set' => 'contributionRecur', ); - } + } if (isset($sets['participant'])) { $fields['participant_event_id'] = array( 'name' => t('Event(s)'), @@ -1271,7 +1338,7 @@ function wf_crm_get_fields($var = 'fields') { } // File attachment fields - $numAttachments = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'max_attachments'); + $numAttachments = wf_crm_get_civi_setting('max_attachments', 3); foreach ($sets as $ent => $set) { if (!empty($set['attachments']) && $numAttachments) { $sets["{$ent}upload"] = array( @@ -1312,109 +1379,117 @@ function wf_crm_get_fields($var = 'fields') { 'email' => t('email'), ); - // Pull custom fields and match to Webform element types - $custom_types = wf_crm_custom_types_map_array(); + // Fetch custom groups list($contact_types) = wf_crm_get_contact_types(); - $custom_extends = "'" . implode("','", array_keys($contact_types + $sets)) . "'"; - $sql = " - SELECT cf.*, cg.title AS custom_group_name, LOWER(cg.extends) AS entity_type, cg.extends_entity_column_id, cg.extends_entity_column_value AS sub_types, cg.is_multiple, cg.max_multiple, cg.id AS custom_group_id, cg.help_pre as cg_help - FROM civicrm_custom_field cf - INNER JOIN civicrm_custom_group cg ON cg.id = cf.custom_group_id - WHERE cf.is_active <> 0 AND cg.extends IN ($custom_extends) AND cg.is_active <> 0 - ORDER BY cf.custom_group_id, cf.weight"; - $dao = CRM_Core_DAO::executeQuery($sql); - while ($dao->fetch()) { - if (isset($custom_types[$dao->html_type])) { - $set = 'cg' . $dao->custom_group_id; - // Place these custom fields directly into their entity - if (wf_crm_aval($sets, "$dao->entity_type:custom_fields") == 'combined') { - //if ($dao->entity_type == 'address' || $dao->entity_type == 'relationship' || $dao->entity_type == 'membership' || $dao->entity_type == 'phone') { - $set = $dao->entity_type; - } - elseif (!isset($sets[$set])) { - $sets[$set]['label'] = $dao->custom_group_name; - if (isset($contact_types[$dao->entity_type]) || $dao->entity_type == 'contact') { - $sets[$set]['entity_type'] = 'contact'; - if ($dao->entity_type != 'contact') { - $sets[$set]['contact_type'] = $dao->entity_type; - } - if ($dao->is_multiple) { - $sets[$set]['max_instances'] = ($dao->max_multiple ? $dao->max_multiple : 9); - } - else { - $sets[$set]['max_instances'] = 1; - } - } - else { - $sets[$set]['entity_type'] = $dao->entity_type; - } - if ($dao->sub_types) { - $sets[$set]['sub_types'] = wf_crm_explode_multivalue_str($dao->sub_types); + $custom_sets = []; + $custom_groups = wf_crm_apivalues('CustomGroup', 'get', [ + 'return' => ['title', 'extends', 'extends_entity_column_value', 'extends_entity_column_id', 'is_multiple', 'max_multiple', 'help_pre'], + 'is_active' => 1, + 'extends' => ['IN' => array_keys($contact_types + $sets)], + 'options' => ['sort' => 'weight'], + ]); + foreach ($custom_groups as $custom_group) { + $set = 'cg' . $custom_group['id']; + $entity_type = strtolower($custom_group['extends']); + // Place these custom fields directly into their entity + if (wf_crm_aval($sets, "$entity_type:custom_fields") == 'combined') { + $set = $entity_type; + } + else { + $sets[$set] = [ + 'label' => $custom_group['title'], + 'entity_type' => $entity_type, + 'max_instances' => 1, + ]; + if (isset($contact_types[$entity_type]) || $entity_type == 'contact') { + $sets[$set]['entity_type'] = 'contact'; + if ($entity_type != 'contact') { + $sets[$set]['contact_type'] = $entity_type; } - if ($dao->extends_entity_column_id) { - $sets[$set]['extension_of'] = $dao->extends_entity_column_id; + if (!empty($custom_group['is_multiple'])) { + $sets[$set]['max_instances'] = $custom_group['max_multiple'] ?? 9; } - $sets[$set]['help_text'] = $dao->cg_help; } - $id = $set . '_custom_' . $dao->id; - $fields[$id] = $custom_types[$dao->html_type]; - if ($dao->html_type == 'Text' && $dao->data_type == 'Money') { - $fields[$id] = $moneyDefaults; + if (!empty($custom_group['extends_entity_column_value'])) { + $sets[$set]['sub_types'] = $custom_group['extends_entity_column_value']; } - $fields[$id]['name'] = $dao->label; - $fields[$id]['required'] = $dao->is_required; - $fields[$id]['value'] = implode(',', wf_crm_explode_multivalue_str($dao->default_value)); - $fields[$id]['data_type'] = $dao->data_type; - if (!empty($dao->help_pre) || !empty($dao->help_post)) { - $fields[$id]['extra']['description'] = $dao->help_pre ? $dao->help_pre : $dao->help_post; - $fields[$id]['extra']['description_above'] = (int) !$dao->help_pre; - $fields[$id]['has_help'] = TRUE; - } - // Conditional rule - todo: support additional entities - if ($sets[$set]['entity_type'] == 'contact' && !empty($sets[$set]['sub_types'])) { - $fields[$id]['civicrm_condition'] = array( - 'andor' => 'or', - 'action' => 'show', - 'rules' => array( - 'contact_contact_sub_type' => array( - 'values' => $sets[$set]['sub_types'], - ), - ), - ); + if (!empty($custom_group['extends_entity_column_id'])) { + $sets[$set]['extension_of'] = $custom_group['extends_entity_column_id']; } + $sets[$set]['help_text'] = $custom_group['help_pre'] ?? NULL; + } + $custom_sets[$custom_group['id']] = $set; + } - if ($dao->entity_type == 'relationship' && $dao->sub_types) { - $fields[$id]['attributes']['data-relationship-type'] = implode(',', wf_crm_explode_multivalue_str($dao->sub_types)); - } + // Fetch custom fields + $custom_types = wf_crm_custom_types_map_array(); + $custom_fields = wf_crm_apivalues('CustomField', 'get', [ + 'is_active' => 1, + 'custom_group_id' => ['IN' => array_keys($custom_sets)], + 'html_type' => ['IN' => array_keys($custom_types)], + 'options' => ['sort' => 'weight'], + ]); + foreach ($custom_fields as $custom_field) { + $set = $custom_sets[$custom_field['custom_group_id']]; + $custom_group = $custom_groups[$custom_field['custom_group_id']]; + $id = $set . '_custom_' . $custom_field['id']; + $fields[$id] = $custom_types[$custom_field['html_type']]; + if ($custom_field['html_type'] == 'Text' && $custom_field['data_type'] == 'Money') { + $fields[$id] = $moneyDefaults; + } + $fields[$id]['name'] = $custom_field['label']; + $fields[$id]['required'] = (int) !empty($custom_field['is_required']); + if (!empty($custom_field['default_value'])) { + $fields[$id]['value'] = implode(',', wf_crm_explode_multivalue_str($custom_field['default_value'])); + } + $fields[$id]['data_type'] = $custom_field['data_type']; + if (!empty($custom_field['help_pre']) || !empty($custom_field['help_post'])) { + $fields[$id]['extra']['description'] = !empty($custom_field['help_pre']) ? $custom_field['help_pre'] : $custom_field['help_post']; + $fields[$id]['extra']['description_above'] = (int) empty($custom_field['help_pre']); + $fields[$id]['has_help'] = TRUE; + } + // Conditional rule - todo: support additional entities + if ($sets[$set]['entity_type'] == 'contact' && !empty($sets[$set]['sub_types'])) { + $fields[$id]['civicrm_condition'] = [ + 'andor' => 'or', + 'action' => 'show', + 'rules' => [ + 'contact_contact_sub_type' => [ + 'values' => $sets[$set]['sub_types'], + ], + ], + ]; + } - if ($fields[$id]['type'] == 'date') { - $fields[$id]['extra']['start_date'] = ($dao->start_date_years ? '-' . $dao->start_date_years : '-50') . ' years'; - $fields[$id]['extra']['end_date'] = ($dao->end_date_years ? '+' . $dao->end_date_years : '+50') . ' years'; - // Add "time" component for datetime fields - if (!empty($dao->time_format)) { - $fields[$id]['name'] .= ' - ' . t('date'); - $fields[$id . '_timepart'] = array( - 'name' => $dao->label . ' - ' . t('time'), - 'type' => 'time', - 'extra' => array('hourformat' => $dao->time_format == 1 ? '12-hour' : '24-hour'), - ); - } - } - elseif ($fields[$id]['data_type'] == 'ContactReference') { - $fields[$id]['expose_list'] = TRUE; - $fields[$id]['empty_option'] = t('None'); - } - elseif ($fields[$id]['data_type'] !== 'Boolean' && $fields[$id]['type'] == 'select') { - $fields[$id]['extra']['civicrm_live_options'] = 1; - } - elseif ($fields[$id]['type'] == 'textarea') { - $fields[$id]['extra']['cols'] = $dao->note_columns; - $fields[$id]['extra']['rows'] = $dao->note_rows; + if ($set == 'relationship' && !empty($custom_group['extends_entity_column_value'])) { + $fields[$id]['attributes']['data-relationship-type'] = implode(',', $custom_group['extends_entity_column_value']); + } + + if ($fields[$id]['type'] == 'date') { + $fields[$id]['extra']['start_date'] = (!empty($custom_field['start_date_years']) ? '-' . $custom_field['start_date_years'] : '-50') . ' years'; + $fields[$id]['extra']['end_date'] = (!empty($custom_field['end_date_years']) ? '+' . $custom_field['end_date_years'] : '+50') . ' years'; + // Add "time" component for datetime fields + if (!empty($custom_field['time_format'])) { + $fields[$id]['name'] .= ' - ' . t('date'); + $fields[$id . '_timepart'] = [ + 'name' => $custom_field['label'] . ' - ' . t('time'), + 'type' => 'time', + 'extra' => ['hourformat' => $custom_field['time_format'] == 1 ? '12-hour' : '24-hour'], + ]; } } + elseif ($fields[$id]['data_type'] == 'ContactReference') { + $fields[$id]['expose_list'] = TRUE; + $fields[$id]['empty_option'] = t('None'); + } + elseif ($fields[$id]['data_type'] !== 'Boolean' && $fields[$id]['type'] == 'select') { + $fields[$id]['extra']['civicrm_live_options'] = 1; + } + elseif ($fields[$id]['type'] == 'textarea') { + $fields[$id]['extra']['cols'] = $custom_field['note_columns'] ?? 60; + $fields[$id]['extra']['rows'] = $custom_field['note_rows'] ?? 4; + } } - $sets += wf_crm_get_empty_sets(); - $dao->free(); } return $$var; } @@ -1758,31 +1833,11 @@ function wf_crm_is_positive($val) { * @return array $sets */ function wf_crm_get_empty_sets() { - $sets = array(); - - $sql = "SELECT cg.id, cg.title, cg.help_pre, cg.extends, SUM(cf.is_active) as custom_field_sum - FROM civicrm_custom_group cg - LEFT OUTER JOIN civicrm_custom_field cf - ON (cg.id = cf.custom_group_id) - GROUP By cg.id"; - - $dao = CRM_Core_DAO::executeQuery($sql); - - while($dao->fetch()) { - // Because a set with all fields disabled = empty set - if (empty($dao->custom_field_sum)) { - $set = 'cg' . $dao->id; - if ($dao->extends == 'address' || $dao->extends == 'relationship' || $dao->extends == 'membership') { - $set = $dao->extends; - } - $sets[$set] = array( - 'label' => $dao->title, - 'entity_type' => strtolower($dao->extends), - 'help_text' => $dao->help_pre, - ); - } + $sets = wf_crm_get_fields('sets'); + foreach (array_keys(wf_crm_get_fields()) as $key) { + list($set) = explode('_', $key); + unset($sets[$set]); } - return $sets; } @@ -1795,7 +1850,6 @@ function wf_crm_custom_types_map_array() { $custom_types = array( 'Select' => array('type' => 'select'), 'Multi-Select' => array('type' => 'select', 'extra' => array('multiple' => 1)), - 'AdvMulti-Select' => array('type' => 'select', 'extra' => array('multiple' => 1)), 'Radio' => array('type' => 'select', 'extra' => array('aslist' => 0)), 'CheckBox' => array('type' => 'select', 'extra' => array('multiple' => 1)), 'Text' => array('type' => 'textfield'), @@ -1813,3 +1867,31 @@ function wf_crm_custom_types_map_array() { return $custom_types; } + +/** + * @param string $setting_name + * @param mixed $default_value + * @return mixed + */ +function wf_crm_get_civi_setting($setting_name, $default_value = NULL) { + $aliases = [ + 'defaultCurrencySymbol' => 'defaultCurrency', + ]; + $settings = wf_civicrm_api('Setting', 'get', [ + 'sequential' => 1, + 'return' => str_replace(array_keys($aliases), array_values($aliases), $setting_name), + ]); + // Not a real setting, requires cross-lookup + if ($setting_name == 'defaultCurrencySymbol') { + $currencies = wf_crm_apivalues('Contribution', 'getoptions', [ + 'field' => "currency", + 'context' => "abbreviate", + ]); + return wf_crm_aval($currencies, $settings['values'][0]['defaultCurrency'], $default_value); + } + $result = wf_crm_aval($settings, "values:0:$setting_name", $default_value); + if ($result === 'default') { + return $default_value; + } + return $result; +} diff --git a/includes/wf_crm_admin_component.inc b/includes/wf_crm_admin_component.inc index 88f134644..a79d80ec2 100644 --- a/includes/wf_crm_admin_component.inc +++ b/includes/wf_crm_admin_component.inc @@ -373,7 +373,7 @@ class wf_crm_admin_component { } } // CSS trick to add currency symbol to options element keys - $symbol = wf_crm_aval(CRM_Core_Config::singleton(), 'defaultCurrencySymbol', '$'); + $symbol = wf_crm_get_civi_setting('defaultCurrencySymbol', '$'); backdrop_add_css(' .option-key-cell:before { content:"' . $symbol . '"; diff --git a/includes/wf_crm_admin_form.inc b/includes/wf_crm_admin_form.inc index e0cf387e9..770fa223c 100644 --- a/includes/wf_crm_admin_form.inc +++ b/includes/wf_crm_admin_form.inc @@ -652,6 +652,12 @@ class wf_crm_admin_form { '#multiple' => TRUE, ); $this->help($this->form['caseTab']['case'][$fs]["case_{$n}_settings_existing_case_status"], 'existing_case_status'); + $this->form['caseTab']['case'][$fs]["case_{$n}_settings_duplicate_case"] = array( + '#type' => 'checkbox', + '#title' => t('Create new case based on existing case'), + '#default_value' => wf_crm_aval($this->data, "case:{$n}:duplicate_case", 0), + ); + $this->help($this->form['caseTab']['case'][$fs]["case_{$n}_settings_duplicate_case"], 'duplicate_case_status'); $case_type = wf_crm_aval($this->data, "case:{$n}:case:1:case_type_id"); foreach ($this->filterCaseSets($case_type) as $sid => $set) { $fs1 = "case_case_{$n}_fieldset_$sid"; @@ -694,9 +700,8 @@ class wf_crm_admin_form { if ($sid == 'caseRoles') { // Lookup case-role names $creator = $manager = NULL; - // Use the vanilla civicrm_api for this because it will throw an error in CiviCRM 4.4 (api doesn't exist) - $case_types = civicrm_api('case_type', 'get', array('version' => 3, 'id' => $case_type, 'options' => array('limit' => 0))); - foreach (wf_crm_aval($case_types, 'values', array()) as $type) { + $case_types = wf_crm_apivalues('case_type', 'get', array('id' => $case_type)); + foreach ($case_types as $type) { foreach ($type['definition']['caseRoles'] as $role) { if (!empty($role['creator'])) { $creator = ($creator == $role['name'] || $creator === NULL) ? $role['name'] : FALSE; @@ -1667,6 +1672,11 @@ class wf_crm_admin_form { if (substr($key, 0, 7) == 'civicrm') { ++$i; $field = wf_crm_get_field($key); + if (substr($key, -11) === '_createmode') { + // Update webform's settings with 'Create mode' value for custom group. + $this->settings['data']['config']['create_mode'][$key] = $val; + } + if (!isset($enabled[$key])) { $val = (array) $val; if (in_array('create_civicrm_webform_element', $val, TRUE) || (!empty($val[0]) && $field['type'] == 'hidden')) { @@ -1697,10 +1707,6 @@ class wf_crm_admin_form { webform_component_update($component); } - if (substr($key, -11) === '_createmode') { - // Update webform's settings with 'Create mode' value for custom group. - $this->settings['data']['config']['create_mode'][$key] = $val; - } } // add empty fieldsets for custom civicrm sets with no fields, if "add dynamically" is checked elseif (strpos($key, 'settings_dynamic_custom') && $val == 1) { @@ -2014,7 +2020,7 @@ class wf_crm_admin_form { * Default value callback */ public static function get_default_contact_cs($fid, $options) { - return CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'checksum_timeout', NULL, 7); + return wf_crm_get_civi_setting('checksum_timeout', 7); } /** diff --git a/includes/wf_crm_admin_help.inc b/includes/wf_crm_admin_help.inc index dac666895..aba5b31b1 100644 --- a/includes/wf_crm_admin_help.inc +++ b/includes/wf_crm_admin_help.inc @@ -138,8 +138,6 @@ class wf_crm_admin_help { public static function contribution_payment_processor_id() { print '
' . t('Supported payment processors enabled on the contribution page are available here. "Pay Later" option allows the user to purchase events/memberships without entering a credit card.') . - '
' . - t("Note that only on-site credit card processors are currently supported on Webforms. Services that redirect to an external website, such as Paypal Standard, are not supported. Recurring payments are not supported.") . '
'; } @@ -350,7 +348,7 @@ class wf_crm_admin_help { public static function activity_assignee_contact_id() { civicrm_initialize(); print ''; - if (CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'activity_assignee_notification')) { + if (wf_crm_get_civi_setting('activity_assignee_notification')) { print t('A copy of this activity will be emailed to the assignee.'); } else { @@ -382,6 +380,16 @@ class wf_crm_admin_help { '
'; } + public static function duplicate_case_status() { + print '' . + t('Choosing this option means a new case will always be created even when an existing case has been selected. If an existing case has been selected the data for this case will NOT be updated.') . + '
' . + t('Useful if you want to pre-fill a form with existing case data, allow the user to make updates and then create a new case with their updates.') . + '
' . + t('Note: Populate the existing case by selecting an option from the Update Existing Case drop-down or by passing "case1=[caseid]" in the url etc.') . + '
'; + } + public static function existing_grant_status() { print '' . t('If a matching grant of the chosen type already exists for the applicant, it will be autofilled and updated.') . diff --git a/includes/wf_crm_webform_ajax.inc b/includes/wf_crm_webform_ajax.inc index 415f0dec8..67afb7cb7 100644 --- a/includes/wf_crm_webform_ajax.inc +++ b/includes/wf_crm_webform_ajax.inc @@ -134,7 +134,7 @@ class wf_crm_webform_ajax extends wf_crm_webform_base { } } // Populate related contacts - elseif ($c == 1 && $i > $c && $field == 'existing') { + elseif ($i > $c && $field == 'existing') { $related_component = $this->getComponent($fid); if (wf_crm_aval($related_component['extra'], 'default') == 'relationship') { $old_related_cid = wf_crm_aval($this->ent, "contact:$i:id"); diff --git a/includes/wf_crm_webform_base.inc b/includes/wf_crm_webform_base.inc index 5eeaa3e4c..6498522ab 100755 --- a/includes/wf_crm_webform_base.inc +++ b/includes/wf_crm_webform_base.inc @@ -59,7 +59,7 @@ abstract class wf_crm_webform_base { return $this->_contribution_page; case 'tax_rate': - $taxSettings = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME, 'contribution_invoice_settings'); + $taxSettings = wf_crm_get_civi_setting('contribution_invoice_settings'); if (is_array($taxSettings) && !empty($taxSettings['invoicing'])) { if ($this->contribution_page) { // tax integration @@ -208,19 +208,6 @@ abstract class wf_crm_webform_base { $rel = $this->getRelationship($types, $cid, wf_crm_aval($this->ent['contact'], "$r:id")); if ($rel) { $info['relationship'][$r] = $rel; - // Fetch custom data - $len = strlen($prefix . 'custom_'); - foreach ($this->enabled as $k => $v) { - if (substr($k, 0, $len) == $prefix . 'custom_') { - $custom = wf_civicrm_api('custom_value', 'get', array('entity_id' => $rel['id'], 'entity_table' => 'Relationship')); - foreach ($custom['values'] as $k => $v) { - if (isset($v[0])) { - $info['relationship'][$r]["custom_$k"] = $v[0]; - } - } - break; - } - } } } } @@ -494,39 +481,40 @@ abstract class wf_crm_webform_base { * @return array */ protected function getRelationship($r_types, $cid1, $cid2) { - $found = array(); - $active_clause = ''; - if (!empty($this->settings['create_new_relationship'])) { - $active_clause = 'AND is_active = 1 AND (end_date IS NULL OR end_date >= now())'; - } + $found = []; + $active_only = !empty($this->settings['create_new_relationship']); if ($r_types && $cid1 && $cid2) { - $types = array(); + $types = []; foreach ($r_types as $r_type) { list($type, $side) = explode('_', $r_type); $types[$type] = $type; } - $sql = "SELECT * FROM civicrm_relationship - WHERE relationship_type_id IN (" . implode(',', $types) . ") - AND ((contact_id_a = $cid1 AND contact_id_b = $cid2) OR (contact_id_a = $cid2 AND contact_id_b = $cid1)) $active_clause - ORDER BY is_active DESC, IF(end_date, 1, 0), end_date DESC"; - $dao = CRM_Core_DAO::executeQuery($sql); - while ($dao->fetch()) { - $type = $dao->relationship_type_id; - $side = $dao->contact_id_a == $cid1 ? 'a' : 'b'; - // Verify this is the correct orientation for the relationship - if (in_array("{$type}_$side", $r_types) || in_array("{$type}_r", $r_types)) { - // Discard metadata from the query - foreach ((array) $dao as $k => $v) { - if ($k[0] != '_' && $k != 'N' && $k != 'relationship_type_id') { - $found[$k] = $v; - } - } + $params = [ + 'contact_id_a' => ['IN' => [$cid1, $cid2]], + 'contact_id_b' => ['IN' => [$cid1, $cid2]], + 'relationship_type_id' => ['IN' => $types], + ]; + if ($active_only) { + $params['is_active'] = 1; + $params['options']['sort'] = 'is_active DESC, end_date ASC'; + } + foreach (wf_crm_apivalues('relationship', 'get', $params) as $rel) { + $type = $rel['relationship_type_id']; + $side = $rel['contact_id_a'] == $cid1 ? 'a' : 'b'; + if ( + // Verify relationship orientation + (in_array("{$type}_$side", $r_types) || in_array("{$type}_r", $r_types)) + // Verify 2 contacts are different unless we're specifically looking for a self-relationship + && ($rel['contact_id_a'] != $rel['contact_id_b'] || $cid1 == $cid2) + // Verify end date is not past when searching for active only + && (empty($rel['end_date']) || !$active_only || strtotime($rel['end_date']) > time()) + ) { // Support multi-valued relationship type fields, fudge the rest $found['relationship_type_id'][] = in_array("{$type}_r", $r_types) ? "{$type}_r" : "{$type}_$side"; - $found['relationship_permission'] = ($found['is_permission_a_b'] ? 1 : 0) + ($found['is_permission_b_a'] ? 2 : 0); + $found['relationship_permission'] = (!empty($rel['is_permission_a_b']) ? 1 : 0) + (!empty($rel['is_permission_b_a']) ? 2 : 0); + $found += $rel; } } - $dao->free(); } return $found; } @@ -617,37 +605,18 @@ abstract class wf_crm_webform_base { /** * Fetch info and remaining spaces for events - * - * @param $events - * Array of event info to fill (reference) */ protected function loadEvents() { if (!empty($this->events)) { $now = time(); - // Fetch event info - $dao = CRM_Core_DAO::executeQuery('SELECT id, title, start_date, end_date, event_type_id, max_participants, financial_type_id - FROM civicrm_event WHERE id IN (' . implode(',', array_keys($this->events)) . ')'); - while ($dao->fetch()) { - $this->events[$dao->id]['title'] = $dao->title; - $this->events[$dao->id]['start_date'] = $dao->start_date; - $this->events[$dao->id]['end_date'] = $dao->end_date; - $this->events[$dao->id]['event_type_id'] = $dao->event_type_id; - $this->events[$dao->id]['financial_type_id'] = $dao->financial_type_id; - $this->events[$dao->id]['full'] = FALSE; - $this->events[$dao->id]['ended'] = $dao->end_date && strtotime($dao->end_date) < $now; - if ($this->events[$dao->id]['max_participants'] = $dao->max_participants) { - $remaining = CRM_Event_BAO_Participant::eventFull($dao->id, TRUE, FALSE); - if (is_string($remaining)) { - $this->events[$dao->id]['full'] = TRUE; - $this->events[$dao->id]['remaining'] = 0; - $this->events[$dao->id]['full_message'] = $remaining; - } - else { - $this->events[$dao->id]['remaining'] = $remaining ? $remaining : $dao->max_participants; - } - } + $events = wf_crm_apivalues('Event', 'get', [ + 'return' => ['title', 'start_date', 'end_date', 'event_type_id', 'max_participants', 'financial_type_id', 'event_full_text', 'is_full'], + 'id' => ['IN' => array_keys($this->events)], + ]); + foreach ($events as $id => $event) { + $this->events[$id] = $event + $this->events[$id] + ['available_places' => 0]; + $this->events[$id]['ended'] = !empty($event['end_date']) && strtotime($event['end_date']) < $now; } - $dao->free(); } } @@ -664,7 +633,7 @@ abstract class wf_crm_webform_base { * @return array */ protected function getCustomData($entity_id, $entity_type = NULL, $normalize = TRUE) { - static $parents = array(); + static $parents = []; if (empty($parents)) { // Create matching table to sort fields by group foreach (wf_crm_get_fields() as $key => $value) { @@ -674,36 +643,25 @@ abstract class wf_crm_webform_base { } } } - $params = array('entityID' => $entity_id); + $params = ['entity_id' => $entity_id]; if ($entity_type) { - $params['entityType'] = ucfirst($entity_type); - } - $result = CRM_Core_BAO_CustomValueTable::getValues($params); - if (!empty($result['is_error'])) { - return array(); + $params['entity_table'] = ucfirst($entity_type); } - unset($result['is_error'], $result['entityID']); - $values = array(); - // Convert multi-value strings to arrays and sort by group + $result = wf_crm_apivalues('CustomValue', 'get', $params); + $values = []; foreach ($result as $key => $value) { - $pieces = explode('_', $key); - if ($pieces[0] == 'custom') { - $name = 'custom_' . $pieces[1]; - if (empty($pieces[2])) { - $pieces[2] = ($normalize ? 1 : 0); - } - if (isset($parents[$name])) { - $values[$parents[$name]][$pieces[2]][$name] = $value; + $name = 'custom_' . $key; + // Sort into groups + if (isset($parents[$name])) { + $n = 1; + foreach ($value as $id => $item) { + // Non-numeric keys are api extras like "id" and "latest" + if (is_numeric($id)) { + $values[$parents[$name]][$normalize ? $n++ : $id][$name] = $item; + } } } } - if ($normalize) { - // Normalize array keys - foreach ($values as &$value) { - array_unshift($value, 0); - unset($value[0]); - } - } return $values; } @@ -942,19 +900,14 @@ abstract class wf_crm_webform_base { 'icon' => $val, ); } - $file = wf_crm_apivalues('file', 'get', $val); - $entity_id = ''; - if ($entity && $n && (strpos($fieldName, 'custom_') === 0 || strpos($fieldName, 'file_') === 0)) { - $entity_id = $this->ent[$entity][$n]['id']; - } + $file = wf_crm_apivalues('Attachment', 'get', $val); if (!empty($file[$val])) { - $fileHash = is_callable(array('CRM_Core_BAO_File', 'generateFileHash')) ? '&fcs=' . CRM_Core_BAO_File::generateFileHash($entity_id, $val) : ''; - return array( + return [ 'data_type' => 'File', - 'name' => CRM_Utils_File::cleanFileName($file[$val]['uri']), - 'file_url'=> CRM_Utils_System::url('civicrm/file', "reset=1&id={$val}&eid={$entity_id}{$fileHash}", TRUE), - 'icon' => file_icon_url((object) array('filemime' => $file[$val]['mime_type'])), - ); + 'name' => $file[$val]['name'], + 'file_url'=> $file[$val]['url'], + 'icon' => file_icon_url((object) ['filemime' => $file[$val]['mime_type']]), + ]; } return NULL; } @@ -995,4 +948,22 @@ abstract class wf_crm_webform_base { return CRM_Core_Key::get('CRM_Contribute_Controller_Contribution', TRUE); } + /** + * Historically webform_civicrm was configured with the live payment processor ID and the is_test flag. + * But this is not how CiviCRM expects it to work and this can cause problems where payments use the live processor + * instead of test. So we "fix" the processor ID here to be the correct one for live/test. + * An "improved" fix would involve changing the configuration saved by the user but this avoids that. + * + * @throws \CiviCRM_API3_Exception + */ + protected function fixPaymentProcessorID() { + // Check for is_test and payment_processor_id (pay later = 0 is set to '' here. is_test has no meaning for pay later). + if (!empty($this->data['contribution'][1]['contribution'][1]['is_test']) + && !empty($this->data['contribution'][1]['contribution'][1]['payment_processor_id'])) { + $paymentProcessor = \Civi\Payment\System::singleton()->getById($this->data['contribution'][1]['contribution'][1]['payment_processor_id']); + $paymentProcessor = \Civi\Payment\System::singleton()->getByName($paymentProcessor->getPaymentProcessor()['name'], TRUE); + $this->data['contribution'][1]['contribution'][1]['payment_processor_id'] = $paymentProcessor->getPaymentProcessor()['id']; + } + } + } diff --git a/includes/wf_crm_webform_postprocess.inc b/includes/wf_crm_webform_postprocess.inc index a0e5af080..4e65ff97b 100644 --- a/includes/wf_crm_webform_postprocess.inc +++ b/includes/wf_crm_webform_postprocess.inc @@ -43,6 +43,7 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $this->node = $node; $this->settings = $node->webform_civicrm; $this->data = $this->settings['data']; + $this->fixPaymentProcessorID(); $this->enabled = wf_crm_enabled_fields($node); $this->all_fields = wf_crm_get_fields(); $this->all_sets = wf_crm_get_fields('sets'); @@ -331,8 +332,7 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $country_id = $this->crmValues[$ckey]; } else { - $config = CRM_Core_Config::singleton(); - $country_id = $config->defaultContactCountry; + $country_id = wf_crm_get_civi_setting('defaultContactCountry', 1228); } $states = wf_crm_get_states($country_id); if ($states && !array_key_exists(strtoupper($element['#value']), $states)) { @@ -386,14 +386,12 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { continue; } $participants = current(wf_crm_aval($this->data['contact'], "$c:contact", array())); - $firstName = CRM_Utils_Array::value('first_name', $participants); - $lastName = CRM_Utils_Array::value('last_name', $participants); - $participantName = "{$firstName} {$lastName}"; + $participantName = ($participants['first_name'] ?? '') . ' ' . ($participants['last_name'] ?? ''); if (!trim($participantName)) { - $participantName = CRM_Utils_Array::value('webform_label', $participants); + $participantName = $participants['webform_label'] ?? NULL; if (!empty($this->existing_contacts[$c])) { - $participantName = CRM_Contact_BAO_Contact::displayName($this->existing_contacts[$c]); + $participantName = wf_crm_apivalues('contact', 'get', $this->existing_contacts[$c], 'display_name')[0]; } } foreach (wf_crm_aval($par, 'participant', array()) as $n => $p) { @@ -408,7 +406,7 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { 'entity_table' => 'civicrm_participant', 'event_id' => $eid, 'contact_ids' => $contacts, - 'unit_price' => $p['fee_amount'], + 'unit_price' => $p['fee_amount'] ?? 0, 'element' => "civicrm_{$c}_participant_{$n}_participant_{$id_and_type}", 'contact_label' => $participantName, ); @@ -419,28 +417,29 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { // Subtract events already registered for - this only works with known contacts $cids = array_filter($this->existing_contacts); if ($this->events && $cids) { - $dao = CRM_Core_DAO::executeQuery("SELECT event_id, contact_id - FROM civicrm_participant p, civicrm_participant_status_type s - WHERE s.id = p.status_id AND s.is_counted = 1 - AND event_id IN (" . implode(',', array_keys($this->events)) . ") - AND contact_id IN (" . implode(',', $cids) . ") - AND is_test = 0"); - while ($dao->fetch()) { - if (isset($this->events[$dao->event_id])) { - if (!(--$this->events[$dao->event_id]['count'])) { - unset($this->events[$dao->event_id]); + $status_types = wf_crm_apivalues('participant_status_type', 'get', ['is_counted' => 1, 'return' => 'id']); + $existing = wf_crm_apivalues('Participant', 'get', [ + 'return' => ['event_id', 'contact_id'], + 'event_id' => ['IN' => array_keys($this->events)], + 'status_id' => ['IN' => array_keys($status_types)], + 'contact_id' => ['IN' => $cids], + 'is_test' => 0, + ]); + foreach ($existing as $participant) { + if (isset($this->events[$participant['event_id']])) { + if (!(--$this->events[$participant['event_id']]['count'])) { + unset($this->events[$participant['event_id']]); } } foreach ($this->line_items as $k => &$item) { - if ($dao->event_id == $item['event_id'] && in_array($dao->contact_id, $item['contact_ids'])) { - unset($this->line_items[$k]['contact_ids'][array_search($dao->contact_id, $item['contact_ids'])]); + if ($participant['event_id'] == $item['event_id'] && in_array($participant['contact_id'], $item['contact_ids'])) { + unset($this->line_items[$k]['contact_ids'][array_search($participant['contact_id'], $item['contact_ids'])]); if (!(--$item['qty'])) { unset($this->line_items[$k]); } } } } - $dao->free(); } $this->loadEvents(); // Add event info to line items @@ -456,12 +455,12 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { if ($event['ended']) { form_set_error($eid, t('Sorry, you can no longer register for %event.', array('%event' => $event['title']))); } - elseif ($event['max_participants'] && $event['count'] > $event['remaining']) { - if (!empty($event['full'])) { - form_set_error($eid, '' . $event['title'] . ': ' . $event['full_message']); + elseif (!empty($event['max_participants']) && $event['count'] > $event['available_places']) { + if (!empty($event['is_full'])) { + form_set_error($eid, '' . $event['title'] . ': ' . $event['event_full_text']); } else { - form_set_error($eid, format_plural($event['remaining'], + form_set_error($eid, format_plural($event['available_places'], 'Sorry, you tried to register !count people for %event but there is only 1 space remaining.', 'Sorry, you tried to register !count people for %event but there are only @count spaces remaining.', array('%event' => $event['title'], '!count' => $event['count']))); @@ -757,8 +756,8 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { foreach ($contact['address'] as &$address) { // Translate state/prov abbr to id if (!empty($address['state_province_id'])) { - $config = CRM_Core_Config::singleton(); - if (!($address['state_province_id'] = wf_crm_state_abbr($address['state_province_id'], 'id', wf_crm_aval($address, 'country_id', $config->defaultContactCountry)))) { + $default_country = wf_crm_get_civi_setting('defaultContactCountry', 1228); + if (!($address['state_province_id'] = wf_crm_state_abbr($address['state_province_id'], 'id', wf_crm_aval($address, 'country_id', $default_country)))) { $address['state_province_id'] = ''; } } @@ -911,14 +910,18 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $params['method'] = 'Webform'; break; case 'tag': - $api = 'entity_tag'; + $api = 'EntityTag'; break; default: $api = $data_type; } if (!empty($add) || !empty($remove)) { // Retrieve current records for this entity - if ($entity_type == 'contact') { + if ($api == 'EntityTag') { + $params['entity_id'] = $id; + $params['entity_table'] = 'civicrm_' . $entity_type; + } + elseif ($api == 'group_contact' && $entity_type == 'contact') { $params['contact_id'] = $id; } else { @@ -1038,11 +1041,12 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $n = $this->data['participant_reg_type'] == 'separate' ? $c : 1; if ($p = wf_crm_aval($this->data, "participant:$n:participant")) { // Fetch existing participant records - $existing = array(); - $dao = CRM_Core_DAO::executeQuery("SELECT id, event_id FROM civicrm_participant WHERE contact_id = $cid AND is_test = 0"); - while ($dao->fetch()) { - $existing[$dao->event_id] = $dao->id; - } + $existing = wf_crm_apivalues('Participant', 'get', [ + 'return' => ["event_id"], + 'contact_id' => $cid, + 'is_test' => 0, + ]); + $existing = array_column($existing, 'id', 'event_id'); foreach ($p as $e => $params) { $remove = array(); $fid = "civicrm_{$c}_participant_{$e}_participant_event_id"; @@ -1104,6 +1108,8 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { unset($params['status_id']); } $result = wf_civicrm_api('participant', 'create', $params); + $this->ent['participant'][$n]['id'] = $result['id']; + // Update line-item foreach ($this->line_items as &$item) { if ($item['element'] == "civicrm_{$n}_participant_{$e}_participant_{$id_and_type}") { @@ -1272,7 +1278,8 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { if (is_array($data) && !empty($data['case'][1]['client_id'])) { $params = $data['case'][1]; // Set some defaults in create mode - if (empty($this->ent['case'][$n]['id'])) { + // Create duplicate case based on existing case if 'duplicate_case' checkbox is checked + if (empty($this->ent['case'][$n]['id']) || !empty($this->data['case'][$n]['duplicate_case'])) { if (empty($params['case_type_id'])) { // Abort if no case type. continue; @@ -1312,6 +1319,8 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $result = wf_civicrm_api('case', 'create', $params); // Final processing if save was successful if (!empty($result['id'])) { + // handle case tags + $this->handleEntityTags('case', $result['id'], $n, $params); // Store id $this->ent['case'][$n]['id'] = $result['id']; // Save custom field data @@ -1420,6 +1429,8 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $activity = wf_civicrm_api('activity', 'create', $params); // Final processing if save was successful if (!empty($activity['id'])) { + // handle activity tags + $this->handleEntityTags('activity', $activity['id'], $n, $params); // Store id $this->ent['activity'][$n]['id'] = $activity['id']; // Save custom data & attachments @@ -1428,7 +1439,7 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $this->processAttachments('activity', $n, $activity['id'], empty($params['id'])); } if (!empty($params['assignee_contact_id'])) { - if (CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'activity_assignee_notification')) { + if (wf_crm_get_civi_setting('activity_assignee_notification')) { // Send email to assignees. TODO: Move to CiviCRM API? $assignees = wf_crm_apivalues('contact', 'get', array( 'id' => array('IN' => (array) $params['assignee_contact_id']), @@ -1453,6 +1464,28 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { } } + /** + * Handle adding/updating tags for entities (cases, activity) + * + * @param $entityType + * @param $entityId + * @param $n + * @param $params + */ + function handleEntityTags($entityType, $entityId, $n, $params) { + foreach ($this->all_fields as $fid => $field) { + list($set, $type) = explode('_', $fid, 2); + if ($set == $entityType && isset($field['table']) && $field['table'] == 'tag') { + $field_name = 'civicrm_' . $n . '_' . $entityType. '_1_' . $fid; + if (isset($this->enabled[$field_name]) && isset($this->data[$entityType][$n])) { + $add = wf_crm_aval($this->data[$entityType][$n], $entityType . ":1:$type", array()); + $remove = $this->getExposedOptions($field_name, $add); + $this->addOrRemoveMultivaluedData('tag', $entityType, $entityId, $add, $remove); + } + } + } + } + /** * Process the submission into the details of the activity. */ @@ -1685,7 +1718,12 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { // Email for ($i = 1; $i <= $this->data['contact'][1]['number_of_email']; ++$i) { if (!empty($this->crmValues["civicrm_1_contact_{$i}_email_email"])) { - $params['email'] = $this->crmValues["civicrm_1_contact_{$i}_email_email"]; + // Force email value to contain a string. + // For saved draft $this->form_state['storage']['submitted'] contains + // a form values wrapped with array and this causes a payment error + // (because email appears as array($email_value) instead of $email_value). + $emailArray = (array) $this->crmValues["civicrm_1_contact_{$i}_email_email"]; + $params['email'] = array_shift($emailArray); break; } } @@ -1885,13 +1923,6 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $params = $this->contributionParams(); $params['contribution_status_id'] = 'Pending'; $params['is_pay_later'] = $this->contributionIsPayLater; - //Fix IPN payments marked as paid by cheque - if (empty($params['payment_instrument_id'])) { - if (!empty($params['payment_processor_id']) && $this->contribution_page['is_monetary']) { - $defaultPaymentInstrument = CRM_Core_OptionGroup::values('payment_instrument', FALSE, FALSE, FALSE, 'AND is_default = 1'); - $params['payment_instrument_id'] = key($defaultPaymentInstrument); - } - } $numInstallments = wf_crm_aval($params, 'installments', NULL, TRUE); $frequencyInterval = wf_crm_aval($params, 'frequency_unit'); @@ -1911,18 +1942,8 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { private function submitIPNPayment() { $params = $this->data['contribution'][1]['contribution'][1]; $processor_type = wf_civicrm_api('payment_processor', 'getsingle', array('id' => $params['payment_processor_id'])); - if (version_compare($this->civicrm_version, 4.7, '<')) { - $mode = empty($params['is_test']) ? 'live' : 'test'; - $paymentProcessor = CRM_Core_Payment::singleton($mode, $processor_type); - } - else { - $paymentProcessor = \Civi\Payment\System::singleton()->getById($params['payment_processor_id']); - // Ideally we would pass the correct id for the test processor through but that seems not to be the - // case so load it here. - if (!empty($params['is_test'])) { - $paymentProcessor = \Civi\Payment\System::singleton()->getByName($processor_type['name'], TRUE); - } - } + $paymentProcessor = \Civi\Payment\System::singleton()->getById($params['payment_processor_id']); + // Add contact details to params (most processors want a first_name and last_name) $contact = wf_civicrm_api('contact', 'getsingle', array('id' => $this->ent['contact'][1]['id'])); $params += $contact; @@ -1953,10 +1974,6 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $paymentProcessor->setSuccessUrl($this->getIpnRedirectUrl('success')); $paymentProcessor->setCancelUrl($this->getIpnRedirectUrl('cancel')); } - // Legacy paypal settings. Remove when dropping support for CiviCRM 4.6 and below. - // @see webform_civicrm_civicrm_alterPaymentProcessorParams - $params['webform_redirect_cancel'] = $this->getIpnRedirectUrl('cancel'); - $params['webform_redirect_success'] = $this->getIpnRedirectUrl('success'); if (method_exists($paymentProcessor, 'doTransferCheckout')) { //Paypal Express checkout @@ -2071,46 +2088,25 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { } } - // Fix bug for testing. - if ($params['is_test'] == 1) { - $liveProcessorName = wf_civicrm_api('payment_processor', 'getvalue', array( - 'id' => $params['payment_processor_id'], - 'return' => 'name', - )); - // Lookup current domain for multisite support - static $domain = 0; - if (!$domain) { - $domain = wf_civicrm_api('domain', 'get', array('current_domain' => 1, 'return' => 'id')); - $domain = wf_crm_aval($domain, 'id', 1); - } - $params['payment_processor_id'] = wf_civicrm_api('payment_processor', 'getvalue', array( - 'return' => 'id', - 'name' => $liveProcessorName, - 'is_test' => 1, - 'domain_id' => $domain, - )); + if (empty($params['payment_instrument_id'])) { + $params['payment_instrument_id'] = $this->getPaymentInstrument($params['payment_processor_id']); } // doPayment requries payment_processor and payment_processor_mode fields. - if (version_compare($this->civicrm_version, '4.7', '>=')) { - $params['payment_processor'] = wf_crm_aval($params, 'payment_processor_id'); - } - - // Record additional parameters if we're processing a credit card after version 4.7.17 (CRM-20158) - if (version_compare($this->civicrm_version, '4.7.17', '>=')) { - if (!empty($params['credit_card_number'])) { - if (!empty($params['credit_card_type'])) { - $result = wf_civicrm_api('OptionValue', 'get', array( - 'return' => ['value'], - 'option_group_id.name' => 'accept_creditcard', - 'name' => ucfirst($params['credit_card_type']), - )); - if (!empty($result['id'])) { - $params['card_type_id'] = $result['values'][$result['id']]['value']; - } + $params['payment_processor'] = wf_crm_aval($params, 'payment_processor_id'); + + if (!empty($params['credit_card_number'])) { + if (!empty($params['credit_card_type'])) { + $result = wf_civicrm_api('OptionValue', 'get', array( + 'return' => ['value'], + 'option_group_id.name' => 'accept_creditcard', + 'name' => ucfirst($params['credit_card_type']), + )); + if (!empty($result['id'])) { + $params['card_type_id'] = $result['values'][$result['id']]['value']; } - $params['pan_truncation'] = substr($params['credit_card_number'],-4); } + $params['pan_truncation'] = substr($params['credit_card_number'],-4); } // Save this stuff for later @@ -2330,7 +2326,7 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $val = array_unique(array_merge($val, $this->data[$ent][$c][$table][$n][$name])); } // Implode data that will be stored as a string - if ($table !== 'other' && $name !== 'event_id' && $name !== 'relationship_type_id' && $table !== 'contact' && $dataType != 'ContactReference') { + if ($table !== 'other' && $name !== 'event_id' && $name !== 'relationship_type_id' && $table !== 'contact' && $dataType != 'ContactReference' && strpos($name, 'tag') !== 0) { $val = CRM_Utils_Array::implodePadded($val); } } @@ -2372,7 +2368,7 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $val = $sum; } else { - $val = isset($val[0]) ? $val[0] : ''; + $val = is_array($val) ? reset($val) : $val; } if ($component['type'] == 'autocomplete' && is_string($val) && strlen($val)) { $options = wf_crm_field_options($component, '', $this->data); @@ -2381,8 +2377,7 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { // Fudge together date and time fields if ($field['type'] === 'time' && substr($name, -8) === 'timepart') { $name = str_replace('_timepart', '', $name); - // Add date (default to today) - $date = wf_crm_aval($this->data, "$ent:$c:$table:$n:$name", date('Ymd')); + $date = wf_crm_aval($this->data, "$ent:$c:$table:$n:$name", ''); $val = $date . str_replace(':', '', $val); } // Only known contacts are allowed to empty a field @@ -2616,4 +2611,9 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { return $values; } + + private function getPaymentInstrument($paymentProcessorId) { + $processor = \Civi\Payment\System::singleton()->getById($paymentProcessorId); + return $processor->getPaymentInstrumentID(); + } } diff --git a/includes/wf_crm_webform_preprocess.inc b/includes/wf_crm_webform_preprocess.inc index 629f4c8e4..df2f0c892 100644 --- a/includes/wf_crm_webform_preprocess.inc +++ b/includes/wf_crm_webform_preprocess.inc @@ -21,6 +21,7 @@ class wf_crm_webform_preprocess extends wf_crm_webform_base { $this->node = $form['#node']; $this->settings = $this->node->webform_civicrm; $this->data = $this->settings['data']; + $this->fixPaymentProcessorID(); $this->ent['contact'] = array(); $this->all_fields = wf_crm_get_fields(); $this->all_sets = wf_crm_get_fields('sets'); @@ -175,15 +176,15 @@ class wf_crm_webform_preprocess extends wf_crm_webform_base { 'scope' => 'footer', ); $this->form['#attached']['css'][] = backdrop_get_path('module', 'webform_civicrm') . '/css/webform_civicrm_forms.css'; - $config = CRM_Core_Config::singleton(); + $default_country = wf_crm_get_civi_setting('defaultContactCountry', 1228); // Variables to push to the client-side $js_vars = array(); // JS Cache eliminates the need for most ajax state/province callbacks foreach ($this->data['contact'] as $c) { if (!empty($c['number_of_address'])) { $js_vars += array( - 'defaultCountry' => $config->defaultContactCountry, - 'defaultStates' => wf_crm_get_states($config->defaultContactCountry), + 'defaultCountry' => $default_country, + 'defaultStates' => wf_crm_get_states($default_country), 'noCountry' => t('- First Choose a Country -'), 'callbackPath' => url('webform-civicrm/js', array('alias' => TRUE)), ); @@ -197,18 +198,10 @@ class wf_crm_webform_preprocess extends wf_crm_webform_base { 'data' => backdrop_get_path('module', 'webform_civicrm') . '/js/webform_civicrm_payment.js', 'scope' => 'footer', ); - $page_id = $this->data['contribution'][1]['contribution'][1]['contribution_page_id']; - if (version_compare($this->civicrm_version, '4.7', '>=')) { - $currency = $this->contribution_page['currency']; - $contributionCallbackQuery = array('currency' => $currency, 'snippet' => 4); - $contributionCallbackUrl = 'civicrm/payment/form'; - $js_vars['processor_id_key'] = 'processor_id'; - } - else { - $contributionCallbackQuery = array('reset' => 1, 'id' => $page_id, 'qfKey' => $this->getQfKey(), 'snippet' => 4); - $contributionCallbackUrl = 'civicrm/contribute/transact'; - $js_vars['processor_id_key'] = 'type'; - } + $currency = $this->contribution_page['currency']; + $contributionCallbackQuery = array('currency' => $currency, 'snippet' => 4); + $contributionCallbackUrl = 'civicrm/payment/form'; + $js_vars['processor_id_key'] = 'processor_id'; if (!empty($this->data['contribution'][1]['contribution'][1]['is_test'])) { // RM: This is needed in order for CiviCRM to know that this is a 'test' (i.e. 'preview' action in CiviCRM) transaction - otherwise, CiviCRM defaults to 'live' and returns the payment form with public key for the live payment processor! $contributionCallbackQuery['action'] = CRM_Core_Action::description(CRM_Core_Action::PREVIEW); @@ -287,15 +280,15 @@ class wf_crm_webform_preprocess extends wf_crm_webform_base { $this->setMessage(t('Sorry, %event has ended.', array('%event' => $event['title'])), 'warning'); } } - elseif ($event['full']) { + elseif (!empty($event['is_full'])) { if (!empty($reg['show_remaining'])) { - $this->setMessage('' . check_plain($event['title']) . ': ' . check_plain($event['full_message']), 'warning'); + $this->setMessage('' . check_plain($event['title']) . ': ' . check_plain($event['event_full_text']), 'warning'); } } else { $reg['block_form'] = FALSE; - if ($event['max_participants'] && ($reg['show_remaining'] == 'always' || intval($reg['show_remaining']) >= $event['remaining'])) { - $this->setMessage(format_plural($event['remaining'], + if (!empty($event['max_participants']) && ($reg['show_remaining'] == 'always' || intval($reg['show_remaining']) >= $event['available_places'])) { + $this->setMessage(format_plural($event['available_places'], '%event has 1 remaining space.', '%event has @count remaining spaces.', array('%event' => $event['title']))); @@ -314,23 +307,20 @@ class wf_crm_webform_preprocess extends wf_crm_webform_base { * @param int $c */ private function loadParticipants($c) { - $select = array('id', 'event_id', 'role_id', 'status_id'); - if (array_key_exists('participant_campaign_id', $this->all_fields)) { - $select[] = 'campaign_id'; - } $status_types = wf_crm_apivalues('participant_status_type', 'get'); - $dao = CRM_Core_DAO::executeQuery('SELECT ' . implode(',', $select) . ' - FROM civicrm_participant - WHERE contact_id = ' . $this->ent['contact'][$c]['id'] . ' AND event_id IN (' . implode(',', array_keys($this->events)) . ")" - ); - while ($dao->fetch()) { - $par = array(); - foreach ($select as $sel) { - $par['participant'][1][$sel] = $dao->$sel; - } - $par += $this->getCustomData($dao->id, 'Participant'); - $status = $status_types[$dao->status_id]; - foreach ($this->events[$dao->event_id]['form'] as $event) { + $participants = wf_crm_apivalues('participant', 'get', [ + 'contact_id' => $this->ent['contact'][$c]['id'], + 'event_id' => ['IN' => array_keys($this->events)], + ]); + foreach ($participants as $row) { + $par = []; + // v3 participant api returns some non-standard keys with participant_ prepended + foreach (['id', 'event_id', 'role_id', 'status_id', 'campaign_id'] as $sel) { + $par['participant'][1][$sel] = $row[$sel] = $row[$sel] ?? $row['participant_' . $sel] ?? NULL; + } + $par += $this->getCustomData($row['id'], 'Participant'); + $status = $status_types[$row['status_id']]; + foreach ($this->events[$row['event_id']]['form'] as $event) { if ($event['contact'] == $c) { // If status has been set by admin or exposed to the form, use it as a filter if (in_array($status['id'], $event['status_id']) || @@ -352,7 +342,6 @@ class wf_crm_webform_preprocess extends wf_crm_webform_base { } } } - $dao->free(); } /** @@ -582,7 +571,7 @@ class wf_crm_webform_preprocess extends wf_crm_webform_base { if (!is_null($itemTaxRate)) { // Change the line item label to display the tax rate it contains - $taxSettings = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME, 'contribution_invoice_settings'); + $taxSettings = wf_crm_get_civi_setting('contribution_invoice_settings'); if (($taxSettings['tax_display_settings'] != 'Do_not_show') && ($itemTaxRate !== 0)) { $item['label'] .= ' (' . t('includes !rate @tax', array('!rate' => (float)$itemTaxRate . '%', '@tax' => $taxSettings['tax_term'])) . ')'; @@ -786,17 +775,7 @@ class wf_crm_webform_preprocess extends wf_crm_webform_base { } } if ($items) { - // Todo: Remove when we drop support for 4.4 - https://www.drupal.org/node/2832331 - if (version_compare($this->civicrm_version, '4.6.0', '<')) { - $values = array(); - foreach ($items as $id) { - $value = wf_crm_apivalues($type, 'get', array('id' => $id)); - $values[$id] = $value[$id]; - } - } - else { - $values = wf_crm_apivalues($type, 'get', array('id' => array('IN' => array_values($items)))); - } + $values = wf_crm_apivalues($type, 'get', array('id' => array('IN' => array_values($items)))); foreach ($items as $n => $id) { if (isset($values[$id])) { // Load core + custom data @@ -807,6 +786,14 @@ class wf_crm_webform_preprocess extends wf_crm_webform_base { $this->info[$type][$n]["{$type}upload"][1]["file_$f"] = $file['file_id']; } } + // Load tags + $tags = NULL; + foreach (array_keys($this->enabled) as $fid) { + if (strpos($fid, "civicrm_{$n}_{$type}_1_{$type}_tag") === 0) { + $tags = $tags ?? wf_crm_apivalues('EntityTag', 'get', ['entity_id' => $id, 'entity_table' => "civicrm_" . $type, 'sequential' => 1], 'tag_id'); + $this->info[$type][$n][$type][1][str_replace("civicrm_{$n}_{$type}_1_{$type}_", '', $fid)] = $tags; + } + } } } } diff --git a/js/webform_civicrm_admin.js b/js/webform_civicrm_admin.js index 7a056a746..7fe2bbfb5 100644 --- a/js/webform_civicrm_admin.js +++ b/js/webform_civicrm_admin.js @@ -568,7 +568,7 @@ var wfCiviAdmin = (function ($, D) { * TODO: Move more code here! Backdrop's version of jQuery is ancient. * TODO: change 'cj' to 'CRM.$' when we drop support for Civi v4.4 */ - cj(function($) { + CRM.$(function($) { // Inline help $('#wf-crm-configure-form, #webform-component-edit-form').on('click', 'a.helpicon', function () { var topic = $(this).attr('href').substr(1); diff --git a/webform_civicrm.info b/webform_civicrm.info index 38a3426e9..66e387d86 100644 --- a/webform_civicrm.info +++ b/webform_civicrm.info @@ -3,6 +3,6 @@ description = A powerful, flexible, user-friendly form builder for CiviCRM. backdrop = 1.x type = module package = CiviCRM -dependencies[] = civicrm -dependencies[] = webform (>=4.12) - +php = 7.0 +dependencies[] = civicrm (>=5.12) +dependencies[] = webform (>=4.19) diff --git a/webform_civicrm.module b/webform_civicrm.module index 3fc0e688b..e4bd7b9e5 100644 --- a/webform_civicrm.module +++ b/webform_civicrm.module @@ -10,10 +10,10 @@ /** * The versions of CiviCRM and WebForm. Min is >=. Max is <. FALSE = no MAX */ -define('WEBFORM_CIVICRM_CIVICRM_VERSION_MIN', '1.x-4.7.0'); +define('WEBFORM_CIVICRM_CIVICRM_VERSION_MIN', '1.x-5.12.0'); define('WEBFORM_CIVICRM_CIVICRM_VERSION_MAX', FALSE); -define('WEBFORM_CIVICRM_WEBFORM_VERSION', '1.x-1.1.0'); +define('WEBFORM_CIVICRM_WEBFORM_VERSION', '1.x-4.19.0'); /** * Implements hook_config_info(). @@ -390,6 +390,13 @@ function webform_civicrm_webform_submission_actions($node, $submission) { 'query' => array('action' => 'view', 'reset' => 1, 'cid' => $data['contact'][1]['id'], 'id' => $data['contribution'][1]['id']), ); } + if (!empty($data['participant'][1]['id'])) { + $actions['civicrm_action participant_view'] = array( + 'title' => t('View Participant'), + 'href' => 'civicrm/contact/view/participant', + 'query' => array('action' => 'view', 'reset' => 1, 'cid' => $data['contact'][1]['id'], 'id' => $data['participant'][1]['id']), + ); + } } } return $actions; @@ -601,23 +608,6 @@ function webform_civicrm_preprocess_webform_components_form(&$vars) { wf_crm_admin_component::preprocessComponentsForm($vars['form'], $vars['rows'], $vars['form']['#node']); } -/** - * Implements hook_civicrm_alterPaymentProcessorParams(). - * - * Legacy handling for paypal. - * We use it to override the return url so that the user gets redirected to the right place from paypal. - * - * Remove when dropping support for CiviCRM 4.6 and below. - */ -function webform_civicrm_civicrm_alterPaymentProcessorParams($paymentObj, $rawParams, &$cookedParams) { - if (!empty($rawParams['webform_redirect_cancel']) && !empty($rawParams['webform_redirect_success']) - && !empty($cookedParams['return']) && !empty($cookedParams['cancel_return']) - ) { - $cookedParams['return'] = $rawParams['webform_redirect_success']; - $cookedParams['cancel_return'] = $rawParams['webform_redirect_cancel']; - } -} - /** * Return a value from nested arrays or objects. *