* - caseId int case ID
* - context string page on which selector is build
* - activity_type_id int|string the activitiy types we want to restrict by
- * @param bool $getCount
- * Get count of the activities
*
- * @return array|int
+ * @return array
* Relevant data object values of open activities
* @throws \CiviCRM_API3_Exception
*/
- public static function getActivities($params, $getCount = FALSE) {
+ public static function getActivities($params) {
$activities = array();
// Activity.Get API params
- $activityParams = array(
- 'is_deleted' => 0,
- 'is_current_revision' => 1,
- 'is_test' => 0,
- 'contact_id' => CRM_Utils_Array::value('contact_id', $params),
- 'return' => array(
- 'activity_date_time',
- 'source_record_id',
- 'source_contact_id',
- 'source_contact_name',
- 'assignee_contact_id',
- 'target_contact_id',
- 'target_contact_name',
- 'assignee_contact_name',
- 'status_id',
- 'subject',
- 'activity_type_id',
- 'activity_type',
- 'case_id',
- 'campaign_id',
- ),
- 'check_permissions' => 1,
- 'options' => array(
- 'offset' => CRM_Utils_Array::value('offset', $params, 0),
- ),
- );
-
- if (!empty($params['activity_status_id'])) {
- $activityParams['activity_status_id'] = array('IN' => explode(',', $params['activity_status_id']));
- }
-
- $activityParams['activity_type_id'] = self::filterActivityTypes($params);
+ $activityParams = self::getActivityParamsForDashboardFunctions($params);
if (!empty($params['rowCount']) &&
$params['rowCount'] > 0
) {
$activityParams['options']['limit'] = $params['rowCount'];
}
- // set limit = 0 if we need to fetch the activity count
- elseif ($getCount) {
- $activityParams['options']['limit'] = 0;
- }
if (!empty($params['sort'])) {
if (is_a($params['sort'], 'CRM_Utils_Sort')) {
$activityParams['options']['sort'] = empty($order) ? "activity_date_time DESC" : str_replace('activity_type ', 'activity_type_id.label ', $order);
- //TODO :
- // 1. we should use Activity.Getcount for fetching count only, but in order to check that
- // current logged in user has permission to view Case activities we are performing filtering out those activities from list (see below).
- // This logic need to be incorporated in Activity.get definition
+ $activityParams['return'] = [
+ 'activity_date_time',
+ 'source_record_id',
+ 'source_contact_id',
+ 'source_contact_name',
+ 'assignee_contact_id',
+ 'target_contact_id',
+ 'target_contact_name',
+ 'assignee_contact_name',
+ 'status_id',
+ 'subject',
+ 'activity_type_id',
+ 'activity_type',
+ 'case_id',
+ 'campaign_id',
+ ];
+ foreach (['case_id' => 'CiviCase', 'campaign_id' => 'CiviCampaign'] as $attr => $component) {
+ if (in_array($component, self::activityComponents())) {
+ $activityParams['return'][] = $attr;
+ }
+ }
$result = civicrm_api3('Activity', 'Get', $activityParams);
- $enabledComponents = self::activityComponents();
$bulkActivityTypeID = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Bulk Email');
$allCampaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE);
);
foreach ($result['values'] as $id => $activity) {
- // skip case activities if CiviCase is not enabled OR those actvities which are
- if (!empty($activity['case_id']) && !in_array('CiviCase', $enabledComponents)) {
- continue;
- }
$activities[$id] = array();
- // if count is needed, no need to populate the array list with attributes
- if ($getCount) {
- continue;
- }
-
$isBulkActivity = (!$bulkActivityTypeID || ($bulkActivityTypeID === $activity['activity_type_id']));
+
foreach ($mappingParams as $apiKey => $expectedName) {
if (in_array($apiKey, array('assignee_contact_name', 'target_contact_name'))) {
$activities[$id][$expectedName] = CRM_Utils_Array::value($apiKey, $activity, array());
$activities[$id]['is_recurring_activity'] = CRM_Core_BAO_RecurringEntity::getParentFor($id, 'civicrm_activity');
}
- return $getCount ? count($activities) : $activities;
+ return $activities;
}
/**
* count of activities
*/
public static function getActivitiesCount($input) {
- return self::getActivities($input, TRUE);
+ $activityParams = self::getActivityParamsForDashboardFunctions($input);
+ return civicrm_api3('Activity', 'getcount', $activityParams);
}
/**
return FALSE;
}
+ /**
+ * @param $params
+ * @return array
+ */
+ protected static function getActivityParamsForDashboardFunctions($params) {
+ $activityParams = [
+ 'is_deleted' => 0,
+ 'is_current_revision' => 1,
+ 'is_test' => 0,
+ 'contact_id' => CRM_Utils_Array::value('contact_id', $params),
+ 'check_permissions' => 1,
+ 'options' => [
+ 'offset' => CRM_Utils_Array::value('offset', $params, 0),
+ ],
+ ];
+
+ if (!empty($params['activity_status_id'])) {
+ $activityParams['activity_status_id'] = ['IN' => explode(',', $params['activity_status_id'])];
+ }
+
+ $activityParams['activity_type_id'] = self::filterActivityTypes($params);
+ $enabledComponents = self::activityComponents();
+ // @todo - should we move this to activity get api.
+ foreach ([
+ 'case_id' => 'CiviCase',
+ 'campaign_id' => 'CiviCampaign'
+ ] as $attr => $component) {
+ if (!in_array($component, $enabledComponents)) {
+ $activityParams[$attr] = ['IS NULL' => 1];
+ }
+ }
+ return $activityParams;
+ }
+
/**
* Checks if user has permissions to edit inbound e-mails, either bsic info
* or both basic information and content.
if ($this->_action & CRM_Core_Action::UPDATE) {
// We filter out alternatives, in case this is a stored e-mail, before sending to front-end
- $this->_values['details'] = CRM_Utils_String::stripAlternatives($this->_values['details']) ?: '';
+ if (isset($this->_values['details'])) {
+ $this->_values['details'] = CRM_Utils_String::stripAlternatives($this->_values['details']) ?: '';
+ }
if ($this->_activityTypeName === 'Inbound Email' &&
!CRM_Core_Permission::check('edit inbound email basic information and content')
}
if ($this->_action & CRM_Core_Action::DELETE) {
+ $this->assign('msg_title', $this->_values['msg_title']);
return;
}
'dedupe_default_limit' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
'remote_profile_submissions' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
'allow_alert_autodismissal' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
+ 'prevNextBackend' => CRM_Core_BAO_Setting::SEARCH_PREFERENCES_NAME,
);
public $_uploadMaxSize;
'recentItemsMaxCount',
'recentItemsProviders',
'dedupe_default_limit',
+ 'prevNextBackend',
));
}
$values['contribution_date_low'] = $date['from'];
$values['contribution_date_high'] = $date['to'];
}
- $searchParams = CRM_Contact_BAO_Query::convertFormValues($values);
- // @todo the use of defaultReturnProperties means the search will be inefficient
- // as slow-unneeded properties are included.
- $query = new CRM_Contact_BAO_Query($searchParams,
- CRM_Contribute_BAO_Query::defaultReturnProperties(CRM_Contact_BAO_Query::MODE_CONTRIBUTE,
- FALSE
- ), NULL, FALSE, FALSE, CRM_Contact_BAO_Query::MODE_CONTRIBUTE
- );
- if ($field == 'contribution_date_high' || $field == 'contribution_date_low') {
- $query->dateQueryBuilder($params[$field], 'civicrm_contribution', 'contribution_date', 'receive_date', 'Contribution Date');
- }
}
}
+
+ $searchParams = CRM_Contact_BAO_Query::convertFormValues(
+ $values,
+ 0,
+ FALSE,
+ NULL,
+ [
+ 'financial_type_id',
+ 'contribution_soft_credit_type_id',
+ 'contribution_status_id',
+ 'contribution_page_id',
+ 'financial_trxn_card_type_id',
+ 'contribution_payment_instrument_id',
+ ]
+ );
+ // @todo the use of defaultReturnProperties means the search will be inefficient
+ // as slow-unneeded properties are included.
+ $query = new CRM_Contact_BAO_Query($searchParams,
+ CRM_Contribute_BAO_Query::defaultReturnProperties(CRM_Contact_BAO_Query::MODE_CONTRIBUTE,
+ FALSE
+ ), NULL, FALSE, FALSE, CRM_Contact_BAO_Query::MODE_CONTRIBUTE
+ );
+
if (!empty($query->_where[0])) {
$where = implode(' AND ', $query->_where[0]) .
" AND civicrm_entity_batch.batch_id IS NULL ";
*
* Generated from xml/schema/CRM/Case/Case.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:2a046fd795b19790f45c5d9dde06a538)
+ * (GenCodeChecksum:6b30b1ce81c7eb8088cac1a630c41c37)
*/
/**
'localizable' => 0,
'html' => [
'type' => 'Select Date',
+ 'formatType' => 'activityDateTime',
],
],
'case_end_date' => [
'localizable' => 0,
'html' => [
'type' => 'Select Date',
+ 'formatType' => 'activityDateTime',
],
],
'details' => [
}
// copy files attached to old activity if any, to new one,
// as long as users have not selected the 'delete attachment' option.
- if (empty($newActParams['is_delete_attachment'])) {
+ if (empty($newActParams['is_delete_attachment']) && ($this->_activityId != $activity->id)) {
CRM_Core_BAO_File::copyEntityFile('civicrm_activity', $this->_activityId,
'civicrm_activity', $activity->id
);
}
}
elseif ($id == 'email_on_hold') {
- if ($formValues['email_on_hold']['on_hold']) {
- $params[] = array('on_hold', '=', $formValues['email_on_hold']['on_hold'], 0, 0);
+ if ($onHoldValue = CRM_Utils_Array::value('email_on_hold', $formValues)) {
+ $onHoldValue = (array) $onHoldValue;
+ $params[] = array('on_hold', 'IN', $onHoldValue, 0, 0);
}
}
elseif (substr($id, 0, 7) == 'custom_'
continue;
}
- $limitToPrimaryClause = $primaryLocation ? "AND {$name}.is_primary = 1" : '';
+ $from .= self::getEntitySpecificJoins($name, $mode, $side, $primaryLocation);
+ }
+ return $from;
+ }
- switch ($name) {
- case 'civicrm_address':
- //CRM-14263 further handling of address joins further down...
- $from .= " $side JOIN civicrm_address ON ( contact_a.id = civicrm_address.contact_id {$limitToPrimaryClause} )";
- continue;
+ /**
+ * Get join statements for the from clause depending on entity type
+ *
+ * @param string $name
+ * @param int $mode
+ * @param string $side
+ * @param string $primaryLocation
+ * @return string
+ */
+ protected static function getEntitySpecificJoins($name, $mode, $side, $primaryLocation) {
+ $limitToPrimaryClause = $primaryLocation ? "AND {$name}.is_primary = 1" : '';
+ switch ($name) {
+ case 'civicrm_address':
+ //CRM-14263 further handling of address joins further down...
+ return " $side JOIN civicrm_address ON ( contact_a.id = civicrm_address.contact_id {$limitToPrimaryClause} )";
- case 'civicrm_phone':
- $from .= " $side JOIN civicrm_phone ON (contact_a.id = civicrm_phone.contact_id {$limitToPrimaryClause}) ";
- continue;
+ case 'civicrm_phone':
+ return " $side JOIN civicrm_phone ON (contact_a.id = civicrm_phone.contact_id {$limitToPrimaryClause}) ";
- case 'civicrm_email':
- $from .= " $side JOIN civicrm_email ON (contact_a.id = civicrm_email.contact_id {$limitToPrimaryClause})";
- continue;
+ case 'civicrm_email':
+ return " $side JOIN civicrm_email ON (contact_a.id = civicrm_email.contact_id {$limitToPrimaryClause})";
- case 'civicrm_im':
- $from .= " $side JOIN civicrm_im ON (contact_a.id = civicrm_im.contact_id {$limitToPrimaryClause}) ";
- continue;
+ case 'civicrm_im':
+ return " $side JOIN civicrm_im ON (contact_a.id = civicrm_im.contact_id {$limitToPrimaryClause}) ";
- case 'im_provider':
- $from .= " $side JOIN civicrm_im ON (contact_a.id = civicrm_im.contact_id) ";
- $from .= " $side JOIN civicrm_option_group option_group_imProvider ON option_group_imProvider.name = 'instant_messenger_service'";
- $from .= " $side JOIN civicrm_option_value im_provider ON (civicrm_im.provider_id = im_provider.value AND option_group_imProvider.id = im_provider.option_group_id)";
- continue;
+ case 'im_provider':
+ $from = " $side JOIN civicrm_im ON (contact_a.id = civicrm_im.contact_id) ";
+ $from .= " $side JOIN civicrm_option_group option_group_imProvider ON option_group_imProvider.name = 'instant_messenger_service'";
+ $from .= " $side JOIN civicrm_option_value im_provider ON (civicrm_im.provider_id = im_provider.value AND option_group_imProvider.id = im_provider.option_group_id)";
+ return $from;
- case 'civicrm_openid':
- $from .= " $side JOIN civicrm_openid ON ( civicrm_openid.contact_id = contact_a.id {$limitToPrimaryClause} )";
- continue;
+ case 'civicrm_openid':
+ return " $side JOIN civicrm_openid ON ( civicrm_openid.contact_id = contact_a.id {$limitToPrimaryClause} )";
- case 'civicrm_worldregion':
- $from .= " $side JOIN civicrm_country ON civicrm_address.country_id = civicrm_country.id ";
- $from .= " $side JOIN civicrm_worldregion ON civicrm_country.region_id = civicrm_worldregion.id ";
- continue;
+ case 'civicrm_worldregion':
+ $from = " $side JOIN civicrm_country ON civicrm_address.country_id = civicrm_country.id ";
+ return "$from $side JOIN civicrm_worldregion ON civicrm_country.region_id = civicrm_worldregion.id ";
- case 'civicrm_location_type':
- $from .= " $side JOIN civicrm_location_type ON civicrm_address.location_type_id = civicrm_location_type.id ";
- continue;
+ case 'civicrm_location_type':
+ return " $side JOIN civicrm_location_type ON civicrm_address.location_type_id = civicrm_location_type.id ";
- case 'civicrm_group':
- $from .= " $side JOIN civicrm_group ON civicrm_group.id = civicrm_group_contact.group_id ";
- continue;
+ case 'civicrm_group':
+ return " $side JOIN civicrm_group ON civicrm_group.id = civicrm_group_contact.group_id ";
- case 'civicrm_group_contact':
- $from .= " $side JOIN civicrm_group_contact ON contact_a.id = civicrm_group_contact.contact_id ";
- continue;
+ case 'civicrm_group_contact':
+ return " $side JOIN civicrm_group_contact ON contact_a.id = civicrm_group_contact.contact_id ";
- case 'civicrm_group_contact_cache':
- $from .= " $side JOIN civicrm_group_contact_cache ON contact_a.id = civicrm_group_contact_cache.contact_id ";
- continue;
+ case 'civicrm_group_contact_cache':
+ return " $side JOIN civicrm_group_contact_cache ON contact_a.id = civicrm_group_contact_cache.contact_id ";
- case 'civicrm_activity':
- case 'civicrm_activity_tag':
- case 'activity_type':
- case 'activity_status':
- case 'parent_id':
- case 'civicrm_activity_contact':
- case 'source_contact':
- case 'activity_priority':
- $from .= CRM_Activity_BAO_Query::from($name, $mode, $side);
- continue;
-
- case 'civicrm_entity_tag':
- $from .= " $side JOIN civicrm_entity_tag ON ( civicrm_entity_tag.entity_table = 'civicrm_contact' AND
- civicrm_entity_tag.entity_id = contact_a.id ) ";
- continue;
-
- case 'civicrm_note':
- $from .= " $side JOIN civicrm_note ON ( civicrm_note.entity_table = 'civicrm_contact' AND
- contact_a.id = civicrm_note.entity_id ) ";
- continue;
-
- case 'civicrm_subscription_history':
- $from .= " $side JOIN civicrm_subscription_history
- ON civicrm_group_contact.contact_id = civicrm_subscription_history.contact_id
- AND civicrm_group_contact.group_id = civicrm_subscription_history.group_id";
- continue;
-
- case 'civicrm_relationship':
- if (self::$_relType == 'reciprocal') {
- if (self::$_relationshipTempTable) {
- // we have a temptable to join on
- $tbl = self::$_relationshipTempTable;
- $from .= " INNER JOIN {$tbl} civicrm_relationship ON civicrm_relationship.contact_id = contact_a.id";
- }
- else {
- $from .= " $side JOIN civicrm_relationship ON (civicrm_relationship.contact_id_b = contact_a.id OR civicrm_relationship.contact_id_a = contact_a.id)";
- $from .= " $side JOIN civicrm_contact contact_b ON (civicrm_relationship.contact_id_a = contact_b.id OR civicrm_relationship.contact_id_b = contact_b.id)";
- }
- }
- elseif (self::$_relType == 'b') {
- $from .= " $side JOIN civicrm_relationship ON (civicrm_relationship.contact_id_b = contact_a.id )";
- $from .= " $side JOIN civicrm_contact contact_b ON (civicrm_relationship.contact_id_a = contact_b.id )";
+ case 'civicrm_activity':
+ case 'civicrm_activity_tag':
+ case 'activity_type':
+ case 'activity_status':
+ case 'parent_id':
+ case 'civicrm_activity_contact':
+ case 'source_contact':
+ case 'activity_priority':
+ return CRM_Activity_BAO_Query::from($name, $mode, $side);
+
+ case 'civicrm_entity_tag':
+ $from = " $side JOIN civicrm_entity_tag ON ( civicrm_entity_tag.entity_table = 'civicrm_contact'";
+ return "$from AND civicrm_entity_tag.entity_id = contact_a.id ) ";
+
+ case 'civicrm_note':
+ $from = " $side JOIN civicrm_note ON ( civicrm_note.entity_table = 'civicrm_contact'";
+ return "$from AND contact_a.id = civicrm_note.entity_id ) ";
+
+ case 'civicrm_subscription_history':
+ $from = " $side JOIN civicrm_subscription_history";
+ $from .= " ON civicrm_group_contact.contact_id = civicrm_subscription_history.contact_id";
+ return "$from AND civicrm_group_contact.group_id = civicrm_subscription_history.group_id";
+
+ case 'civicrm_relationship':
+ if (self::$_relType == 'reciprocal') {
+ if (self::$_relationshipTempTable) {
+ // we have a temptable to join on
+ $tbl = self::$_relationshipTempTable;
+ return " INNER JOIN {$tbl} civicrm_relationship ON civicrm_relationship.contact_id = contact_a.id";
}
else {
- $from .= " $side JOIN civicrm_relationship ON (civicrm_relationship.contact_id_a = contact_a.id )";
- $from .= " $side JOIN civicrm_contact contact_b ON (civicrm_relationship.contact_id_b = contact_b.id )";
+ $from = " $side JOIN civicrm_relationship ON (civicrm_relationship.contact_id_b = contact_a.id OR civicrm_relationship.contact_id_a = contact_a.id)";
+ $from .= " $side JOIN civicrm_contact contact_b ON (civicrm_relationship.contact_id_a = contact_b.id OR civicrm_relationship.contact_id_b = contact_b.id)";
+ return $from;
}
- continue;
+ }
+ elseif (self::$_relType == 'b') {
+ $from = " $side JOIN civicrm_relationship ON (civicrm_relationship.contact_id_b = contact_a.id )";
+ return "$from $side JOIN civicrm_contact contact_b ON (civicrm_relationship.contact_id_a = contact_b.id )";
+ }
+ else {
+ $from = " $side JOIN civicrm_relationship ON (civicrm_relationship.contact_id_a = contact_a.id )";
+ return "$from $side JOIN civicrm_contact contact_b ON (civicrm_relationship.contact_id_b = contact_b.id )";
+ }
- case 'civicrm_log':
- $from .= " INNER JOIN civicrm_log ON (civicrm_log.entity_id = contact_a.id AND civicrm_log.entity_table = 'civicrm_contact')";
- $from .= " INNER JOIN civicrm_contact contact_b_log ON (civicrm_log.modified_id = contact_b_log.id)";
- continue;
+ case 'civicrm_log':
+ $from = " INNER JOIN civicrm_log ON (civicrm_log.entity_id = contact_a.id AND civicrm_log.entity_table = 'civicrm_contact')";
+ return "$from INNER JOIN civicrm_contact contact_b_log ON (civicrm_log.modified_id = contact_b_log.id)";
- case 'civicrm_tag':
- $from .= " $side JOIN civicrm_tag ON civicrm_entity_tag.tag_id = civicrm_tag.id ";
- continue;
+ case 'civicrm_tag':
+ return " $side JOIN civicrm_tag ON civicrm_entity_tag.tag_id = civicrm_tag.id ";
- case 'civicrm_grant':
- $from .= CRM_Grant_BAO_Query::from($name, $mode, $side);
- continue;
+ case 'civicrm_grant':
+ return CRM_Grant_BAO_Query::from($name, $mode, $side);
- case 'civicrm_campaign':
- //Move to default case if not in either mode.
- if ($mode & CRM_Contact_BAO_Query::MODE_CONTRIBUTE) {
- $from .= CRM_Contribute_BAO_Query::from($name, $mode, $side);
- continue;
- }
- elseif ($mode & CRM_Contact_BAO_Query::MODE_MAILING) {
- $from .= CRM_Mailing_BAO_Query::from($name, $mode, $side);
- continue;
- }
- elseif ($mode & CRM_Contact_BAO_Query::MODE_CAMPAIGN) {
- $from .= CRM_Campaign_BAO_Query::from($name, $mode, $side);
- continue;
- }
+ case 'civicrm_website':
+ return " $side JOIN civicrm_website ON contact_a.id = civicrm_website.contact_id ";
- case 'civicrm_website':
- $from .= " $side JOIN civicrm_website ON contact_a.id = civicrm_website.contact_id ";
- continue;
+ case 'civicrm_campaign':
+ //Move to default case if not in either mode.
+ if ($mode & CRM_Contact_BAO_Query::MODE_CONTRIBUTE) {
+ return CRM_Contribute_BAO_Query::from($name, $mode, $side);
+ }
+ elseif ($mode & CRM_Contact_BAO_Query::MODE_MAILING) {
+ return CRM_Mailing_BAO_Query::from($name, $mode, $side);
+ }
+ elseif ($mode & CRM_Contact_BAO_Query::MODE_CAMPAIGN) {
+ return CRM_Campaign_BAO_Query::from($name, $mode, $side);
+ }
- default:
- $locationTypeName = '';
- if (strpos($name, '-address') != 0) {
- $locationTypeName = 'address';
- }
- elseif (strpos($name, '-phone') != 0) {
- $locationTypeName = 'phone';
- }
- elseif (strpos($name, '-email') != 0) {
- $locationTypeName = 'email';
- }
- elseif (strpos($name, '-im') != 0) {
- $locationTypeName = 'im';
- }
- elseif (strpos($name, '-openid') != 0) {
- $locationTypeName = 'openid';
- }
+ default:
+ $locationTypeName = '';
+ if (strpos($name, '-address') != 0) {
+ $locationTypeName = 'address';
+ }
+ elseif (strpos($name, '-phone') != 0) {
+ $locationTypeName = 'phone';
+ }
+ elseif (strpos($name, '-email') != 0) {
+ $locationTypeName = 'email';
+ }
+ elseif (strpos($name, '-im') != 0) {
+ $locationTypeName = 'im';
+ }
+ elseif (strpos($name, '-openid') != 0) {
+ $locationTypeName = 'openid';
+ }
- if ($locationTypeName) {
- //we have a join on an location table - possibly in conjunction with search builder - CRM-14263
- $parts = explode('-', $name);
- $locationTypes = CRM_Core_DAO_Address::buildOptions('location_type_id', 'validate');
- foreach ($locationTypes as $locationTypeID => $locationType) {
- if ($parts[0] == str_replace(' ', '_', $locationType)) {
- $locationID = $locationTypeID;
- }
+ if ($locationTypeName) {
+ //we have a join on an location table - possibly in conjunction with search builder - CRM-14263
+ $parts = explode('-', $name);
+ $locationTypes = CRM_Core_DAO_Address::buildOptions('location_type_id', 'validate');
+ foreach ($locationTypes as $locationTypeID => $locationType) {
+ if ($parts[0] == str_replace(' ', '_', $locationType)) {
+ $locationID = $locationTypeID;
}
- $from .= " $side JOIN civicrm_{$locationTypeName} `{$name}` ON ( contact_a.id = `{$name}`.contact_id ) and `{$name}`.location_type_id = $locationID ";
- }
- else {
- $from .= CRM_Core_Component::from($name, $mode, $side);
}
- $from .= CRM_Contact_BAO_Query_Hook::singleton()->buildSearchfrom($name, $mode, $side);
+ $from = " $side JOIN civicrm_{$locationTypeName} `{$name}` ON ( contact_a.id = `{$name}`.contact_id ) and `{$name}`.location_type_id = $locationID ";
+ }
+ else {
+ $from = CRM_Core_Component::from($name, $mode, $side);
+ }
+ $from .= CRM_Contact_BAO_Query_Hook::singleton()->buildSearchfrom($name, $mode, $side);
- continue;
- }
+ return $from;
}
- return $from;
}
/**
}
}
+ /**
+ * Add relationship permission criteria to where clause.
+ *
+ * @param string $grouping
+ * @param array $where Array to add "where" criteria to, in case you are generating a temp table.
+ * Not the main query.
+ */
public function addRelationshipPermissionClauses($grouping, &$where) {
$relPermission = $this->getWhereValues('relation_permission', $grouping);
if ($relPermission) {
$where[$grouping][] = "(civicrm_relationship.is_permission_a_b IN (" . implode(",", $relPermission[2]) . "))";
$allRelationshipPermissions = CRM_Contact_BAO_Relationship::buildOptions('is_permission_a_b');
- $relQill = '';
- foreach ($relPermission[2] as $rel) {
- if (!empty($relQill)) {
- $relQill .= ' OR ';
- }
- $relQill .= ts($allRelationshipPermissions[$rel]);
- }
- $this->_qill[$grouping][] = ts('Permissioned Relationships') . ' - ' . $relQill;
+
+ $relPermNames = array_intersect_key($allRelationshipPermissions, array_flip($relPermission[2]));
+ $this->_qill[$grouping][] = ts('Permissioned Relationships') . ' - ' . implode(' OR ', $relPermNames);
}
}
}
/**
- * Fetch a list of contacts from the prev/next cache for displaying a search results page
+ * Fetch a list of contacts for displaying a search results page
*
- * @param string $cacheKey
- * @param int $offset
- * @param int $rowCount
+ * @param array $cids
+ * List of contact IDs
* @param bool $includeContactIds
* @return CRM_Core_DAO
*/
- public function getCachedContacts($cacheKey, $offset, $rowCount, $includeContactIds) {
+ public function getCachedContacts($cids, $includeContactIds) {
+ CRM_Utils_Type::validateAll($cids, 'Positive');
$this->_includeContactIds = $includeContactIds;
$onlyDeleted = in_array(array('deleted_contacts', '=', '1', '0', '0'), $this->_params);
list($select, $from, $where) = $this->query(FALSE, FALSE, FALSE, $onlyDeleted);
- $from = " FROM civicrm_prevnext_cache pnc INNER JOIN civicrm_contact contact_a ON contact_a.id = pnc.entity_id1 AND pnc.cacheKey = '$cacheKey' " . substr($from, 31);
- $order = " ORDER BY pnc.id";
- $groupByCol = array('contact_a.id', 'pnc.id');
- $select = self::appendAnyValueToSelect($this->_select, $groupByCol, 'GROUP_CONCAT');
- $groupBy = " GROUP BY " . implode(', ', $groupByCol);
- $limit = " LIMIT $offset, $rowCount";
+ $select .= sprintf(", (%s) AS _wgt", $this->createSqlCase('contact_a.id', $cids));
+ $where .= sprintf(' AND contact_a.id IN (%s)', implode(',', $cids));
+ $order = 'ORDER BY _wgt';
+ $groupBy = '';
+ $limit = '';
$query = "$select $from $where $groupBy $order $limit";
return CRM_Core_DAO::executeQuery($query);
}
+ /**
+ * Construct a SQL CASE expression.
+ *
+ * @param string $idCol
+ * The name of a column with ID's (eg 'contact_a.id').
+ * @param array $cids
+ * Array(int $weight => int $id).
+ * @return string
+ * CASE WHEN id=123 THEN 1 WHEN id=456 THEN 2 END
+ */
+ private function createSqlCase($idCol, $cids) {
+ $buf = "CASE\n";
+ foreach ($cids as $weight => $cid) {
+ $buf .= " WHEN $idCol = $cid THEN $weight \n";
+ }
+ $buf .= "END\n";
+ return $buf;
+ }
+
/**
* Populate $this->_permissionWhereClause with permission related clause and update other
* query related properties.
$blocks['Address'] = $otherEditOptions['Address'];
}
+ $website_types = array();
$openIds = array();
$primaryID = FALSE;
foreach ($blocks as $name => $label) {
}
if ($dataExists) {
- // skip remaining checks for website
if ($name == 'website') {
+ if (!empty($blockValues['website_type_id'])) {
+ if (empty($website_types[$blockValues['website_type_id']])) {
+ $website_types[$blockValues['website_type_id']] = $blockValues['website_type_id'];
+ }
+ else {
+ $errors["{$name}[1][website_type_id]"] = ts('Contacts may only have one website of each type at most.');
+ }
+ }
+
+ // skip remaining checks for website
continue;
}
CRM_Contact_Form_Edit_Website::buildQuickForm($this, $blockId, TRUE);
}
+ $this->addFormRule(array('CRM_Contact_Form_Inline_Website', 'formRule'), $this);
+
}
/**
$this->response();
}
+ /**
+ * Global validation rules for the form.
+ *
+ * @param array $fields
+ * Posted values of the form.
+ * @param array $errors
+ * List of errors to be posted back to the form.
+ * @param CRM_Contact_Form_Inline_Website $form
+ *
+ * @return array
+ */
+ public static function formRule($fields, $errors, $form) {
+ $hasData = $errors = array();
+ if (!empty($fields['website']) && is_array($fields['website'])) {
+ $types = array();
+ foreach ($fields['website'] as $instance => $blockValues) {
+ $dataExists = CRM_Contact_Form_Contact::blockDataExists($blockValues);
+
+ if ($dataExists) {
+ $hasData[] = $instance;
+ if (!empty($blockValues['website_type_id'])) {
+ if (empty($types[$blockValues['website_type_id']])) {
+ $types[$blockValues['website_type_id']] = $blockValues['website_type_id'];
+ }
+ else {
+ $errors["website[" . $instance . "][website_type_id]"] = ts('Contacts may only have one website of each type at most.');
+ }
+ }
+ }
+ }
+ }
+ return $errors;
+ }
+
}
$form->addRadio('privacy_toggle', ts('Privacy Options'), $options, array('allowClear' => FALSE));
// preferred communication method
-
- $onHold[] = $form->createElement('advcheckbox', 'on_hold', NULL, '');
- $form->addGroup($onHold, 'email_on_hold', ts('Email On Hold'));
+ if (Civi::settings()->get('civimail_multiple_bulk_emails')) {
+ $form->addSelect('email_on_hold',
+ array('entity' => 'email', 'multiple' => 'multiple', 'label' => ts('Email On Hold'), 'options' => CRM_Core_PseudoConstant::emailOnHoldOptions()));
+ }
+ else {
+ $form->add('advcheckbox', 'email_on_hold', ts('Email On Hold'));
+ }
$form->addSelect('preferred_communication_method',
array('entity' => 'contact', 'multiple' => 'multiple', 'label' => ts('Preferred Communication Method'), 'option_url' => NULL, 'placeholder' => ts('- any -')));
* class to parse contact csv files
*/
class CRM_Contact_Import_Parser_Contact extends CRM_Contact_Import_Parser {
- protected $_mapperKeys;
- protected $_mapperLocType;
+ protected $_mapperKeys = [];
+ protected $_mapperLocType = [];
protected $_mapperPhoneType;
protected $_mapperImProvider;
protected $_mapperWebsiteType;
* Class constructor.
*
* @param array $mapperKeys
- * @param int $mapperLocType
- * @param int $mapperPhoneType
- * @param int $mapperImProvider
- * @param int $mapperRelated
- * @param int $mapperRelatedContactType
+ * @param array $mapperLocType
+ * @param array $mapperPhoneType
+ * @param array $mapperImProvider
+ * @param array $mapperRelated
+ * @param array $mapperRelatedContactType
* @param array $mapperRelatedContactDetails
- * @param int $mapperRelatedContactLocType
- * @param int $mapperRelatedContactPhoneType
- * @param int $mapperRelatedContactImProvider
- * @param int $mapperWebsiteType
- * @param int $mapperRelatedContactWebsiteType
+ * @param array $mapperRelatedContactLocType
+ * @param array $mapperRelatedContactPhoneType
+ * @param array $mapperRelatedContactImProvider
+ * @param array $mapperWebsiteType
+ * @param array $mapperRelatedContactWebsiteType
*/
public function __construct(
- &$mapperKeys, $mapperLocType = NULL, $mapperPhoneType = NULL, $mapperImProvider = NULL, $mapperRelated = NULL, $mapperRelatedContactType = NULL, $mapperRelatedContactDetails = NULL, $mapperRelatedContactLocType = NULL, $mapperRelatedContactPhoneType = NULL, $mapperRelatedContactImProvider = NULL,
- $mapperWebsiteType = NULL, $mapperRelatedContactWebsiteType = NULL
+ &$mapperKeys, $mapperLocType = [], $mapperPhoneType = [], $mapperImProvider = [], $mapperRelated = [], $mapperRelatedContactType = [], $mapperRelatedContactDetails = [], $mapperRelatedContactLocType = [], $mapperRelatedContactPhoneType = [], $mapperRelatedContactImProvider = [],
+ $mapperWebsiteType = [], $mapperRelatedContactWebsiteType = []
) {
parent::__construct();
$this->_mapperKeys = &$mapperKeys;
$session = CRM_Core_Session::singleton();
$userID = $session->get('userID');
- $userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this);
+ $userChecksum = $this->getUserChecksum();
$validUser = FALSE;
- if (empty($userID) && $this->_contactId && $userChecksum) {
+ if ($userChecksum) {
$this->assign('userChecksum', $userChecksum);
$validUser = CRM_Contact_BAO_Contact_Utils::validChecksum($this->_contactId, $userChecksum);
$this->_isChecksumUser = $validUser;
return self::$_links;
}
+ /**
+ * Get the user checksum from the url to use in links.
+ *
+ * @return string
+ */
+ protected function getUserChecksum() {
+ $userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this);
+ if (empty($userID) && $this->_contactId) {
+ return $userChecksum;
+ }
+ return FALSE;
+ }
+
}
// and contain the search criteria (parameters)
// note that the default action is basic
if ($rowCount) {
+ /** @var CRM_Core_PrevNextCache_Interface $prevNext */
+ $prevNext = Civi::service('prevnext');
$cacheKey = $this->buildPrevNextCache($sort);
- $resultSet = $this->_query->getCachedContacts($cacheKey, $offset, $rowCount, $includeContactIds)->fetchGenerator();
+ $cids = $prevNext->fetch($cacheKey, $offset, $rowCount);
+ $resultSet = empty($cids) ? [] : $this->_query->getCachedContacts($cids, $includeContactIds)->fetchGenerator();
}
else {
$resultSet = $this->_query->searchQuery($offset, $rowCount, $sort, FALSE, $includeContactIds)->fetchGenerator();
$params = array_merge($defaults, $params);
$params['skipLineItem'] = TRUE;
$trxnsData['trxn_date'] = !empty($trxnsData['trxn_date']) ? $trxnsData['trxn_date'] : date('YmdHis');
+ $params['payment_instrument_id'] = CRM_Utils_Array::value('payment_instrument_id', $trxnsData, CRM_Utils_Array::value('payment_instrument_id', $params));
$arAccountId = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($contributionDAO->financial_type_id, 'Accounts Receivable Account is');
$completedStatusId = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
$trxnsData['net_amount'] = !empty($trxnsData['net_amount']) ? $trxnsData['net_amount'] : $trxnsData['total_amount'];
$params['pan_truncation'] = CRM_Utils_Array::value('pan_truncation', $trxnsData);
$params['card_type_id'] = CRM_Utils_Array::value('card_type_id', $trxnsData);
+ $params['check_number'] = CRM_Utils_Array::value('check_number', $trxnsData);
// record the entry
$financialTrxn = CRM_Contribute_BAO_Contribution::recordFinancialAccounts($params, $trxnsData);
}
/**
- * Function to check line items.
+ * Checks if line items total amounts
+ * match the contribution total amount.
*
* @param array $params
* array of order params.
if (empty($item['financial_type_id'])) {
$item['financial_type_id'] = $params['financial_type_id'];
}
- $lineItemAmount += $item['line_total'];
+ $lineItemAmount += $item['line_total'] + CRM_Utils_Array::value('tax_amount', $item, 0.00);
}
}
return;
}
$whereTable = $fields[$fldName];
- $value = trim($value);
+ if (!is_array($value)) {
+ $value = trim($value);
+ }
$dataType = "String";
if (!empty($whereTable['type'])) {
$form->add('text', 'contribution_amount_high', ts('To'), array('size' => 8, 'maxlength' => 8));
$form->addRule('contribution_amount_high', ts('Please enter a valid money value (e.g. %1).', array(1 => CRM_Utils_Money::format('99.99', ' '))), 'money');
- // Adding Cancelled Contribution fields -- CRM-21343
- $form->add('text', 'contribution_cancel_reason', ts('Cancellation / Refund Reason'), array('size' => 40));
+ $form->addField('cancel_reason', array('entity' => 'Contribution'));
CRM_Core_Form_Date::buildDateRange($form, 'contribution_cancel_date', 1, '_low', '_high', ts('From:'), FALSE);
$form->addElement('hidden', 'contribution_cancel_date_range_error');
*
* Generated from xml/schema/CRM/Contribute/Contribution.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:45a20d00d01766a61687cbac5cef1482)
+ * (GenCodeChecksum:eec525df6c3c6151861750217f3ebe5d)
*/
/**
'cancel_reason' => [
'name' => 'cancel_reason',
'type' => CRM_Utils_Type::T_TEXT,
- 'title' => ts('Cancel Reason'),
+ 'title' => ts('Cancellation / Refund Reason'),
'import' => TRUE,
'where' => 'civicrm_contribution.cancel_reason',
'headerPattern' => '/(cancel.?)?reason/i',
protected function assignContactEmailDetails() {
if ($this->_contactID) {
list($this->userDisplayName, $this->userEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($this->_contactID);
+ if (empty($this->userDisplayName)) {
+ $this->userDisplayName = civicrm_api3('contact', 'getvalue', ['id' => $this->_contactID, 'return' => 'display_name']);
+ }
$this->assign('displayName', $this->userDisplayName);
}
}
$this->_defaults = array();
$this->_amount = $this->get('amount');
+ // Assigning this to the template means it will be passed through to the payment form.
+ // This can, for example, by used by payment processors using client side encryption
+ $this->assign('currency', $this->getCurrency());
//CRM-6907
+ // these lines exist to support a non-default currenty on the form but are probably
+ // obsolete & meddling wth the defaultCurrency is not the right approach....
$config = CRM_Core_Config::singleton();
$config->defaultCurrency = CRM_Utils_Array::value('currency',
$this->_values,
*/
protected $_prefix = "contribute_";
+
+ /**
+ * Explicitly declare the entity api name.
+ */
+ public function getDefaultEntity() {
+ return 'Contribution';
+ }
+
/**
* Processing needed for buildForm and later.
*/
* Build the form object.
*/
public function buildQuickForm() {
- parent::buildQuickForm();
- $this->addContactSearchFields();
+ if ($this->isFormInViewOrEditMode()) {
+ parent::buildQuickForm();
+ $this->addContactSearchFields();
- CRM_Contribute_BAO_Query::buildSearchForm($this);
+ CRM_Contribute_BAO_Query::buildSearchForm($this);
+ }
$rows = $this->get('rows');
if (is_array($rows)) {
if ($this->_context == 'user') {
$query->setSkipPermission(TRUE);
}
- $summary = &$query->summaryContribution($this->_context);
- $this->set('summary', $summary);
- $this->assign('contributionSummary', $summary);
+
$controller->run();
}
case 'Multi-Select State/Province':
case 'Multi-Select Country':
if ($field['data_type'] == 'ContactReference' && $value) {
- $display = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $value, 'display_name');
+ if (is_numeric($value)) {
+ $display = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $value, 'display_name');
+ }
+ else {
+ $display = $value;
+ }
}
elseif (is_array($value)) {
$v = array();
case 'File':
if ($skipFile) {
- continue;
+ break;
}
//store the file in d/b
if (CRM_Core_Permission::access('CiviEvent')) {
$fields['Participant'] = CRM_Event_BAO_Participant::exportableFields();
//get the component payment fields
+ // @todo - review this - inconsistent with other entities & hacky.
if ($exportMode == CRM_Export_Form_Select::EVENT_EXPORT) {
$componentPaymentFields = array();
foreach (CRM_Export_BAO_Export::componentPaymentFields() as $payField => $payTitle) {
}
}
+ /**
+ * Get a list of available backend services.
+ *
+ * @return array
+ * Array(string $id => string $label).
+ */
+ public static function getPrevNextBackends() {
+ return [
+ 'default' => ts('Default (Auto-detect)'),
+ 'sql' => ts('SQL'),
+ 'redis' => ts('Redis'),
+ ];
+ }
+
}
break;
default:
- $field['sqlType'] = $field['phpType'] = $type;
+ $field['phpType'] = $this->value('phpType', $fieldXML, $type);
+ $field['sqlType'] = $type;
if ($type == 'int unsigned') {
$field['crmType'] = 'CRM_Utils_Type::T_INT';
}
else {
- $field['crmType'] = 'CRM_Utils_Type::T_' . strtoupper($type);
+ $field['crmType'] = $this->value('crmType', $fieldXML, 'CRM_Utils_Type::T_' . strtoupper($type));
}
break;
}
}
}
$newObject->save();
+ CRM_Utils_Hook::post('create', CRM_Core_DAO_AllCoreTables::getBriefName($daoName), $newObject->id, $newObject);
}
+
return $newObject;
}
*
* Generated from xml/schema/CRM/Core/EntityFile.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:354c22131251fde259f5b796e102fccf)
+ * (GenCodeChecksum:d2d6205c8973c5ad7a989ecb674b9f94)
*/
/**
'localizable' => FALSE,
'sig' => 'civicrm_entity_file::0::entity_table::entity_id',
],
- 'index_entity_file_id' => [
- 'name' => 'index_entity_file_id',
+ 'UI_entity_table_entity_id_file_id' => [
+ 'name' => 'UI_entity_table_entity_id_file_id',
'field' => [
0 => 'entity_table',
1 => 'entity_id',
2 => 'file_id',
],
'localizable' => FALSE,
- 'sig' => 'civicrm_entity_file::0::entity_table::entity_id::file_id',
+ 'unique' => TRUE,
+ 'sig' => 'civicrm_entity_file::1::entity_table::entity_id::file_id',
],
];
return ($localize && !empty($indices)) ? CRM_Core_DAO_AllCoreTables::multilingualize(__CLASS__, $indices) : $indices;
*
* Generated from xml/schema/CRM/Core/UFGroup.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:a48f9522d0bd2e1d485064ebfc66f9a2)
+ * (GenCodeChecksum:d0a806459507dc6b32ba955e4e899358)
*/
/**
'title' => [
'name' => 'title',
'type' => CRM_Utils_Type::T_STRING,
- 'title' => ts('Title'),
+ 'title' => ts('Profile Name'),
'description' => ts('Form title.'),
'required' => TRUE,
'maxlength' => 64,
'entity' => 'UFGroup',
'bao' => 'CRM_Core_BAO_UFGroup',
'localizable' => 1,
+ 'html' => [
+ 'type' => 'Text',
+ ],
],
'frontend_title' => [
'name' => 'frontend_title',
'type' => CRM_Utils_Type::T_STRING,
- 'title' => ts('Frontend Title'),
+ 'title' => ts('Public Title'),
'description' => ts('Profile Form Public title'),
'maxlength' => 64,
'size' => CRM_Utils_Type::BIG,
'entity' => 'UFGroup',
'bao' => 'CRM_Core_BAO_UFGroup',
'localizable' => 1,
+ 'html' => [
+ 'type' => 'Text',
+ ],
],
'description' => [
'name' => 'description',
global $dbLocale;
$dbLocale = "_{$locale}";
+ // For self::getLocale()
+ global $tsLocale;
+ $tsLocale = $locale;
}
/**
$dao = new CRM_Core_DAO_JobLog();
$dao->domain_id = $domainID;
- $dao->description = substr($message, 0, 235);
- if (strlen($message) > 235) {
- $dao->description .= " (...)";
+
+ /*
+ * The description is a summary of the message.
+ * HTML tags are stripped from the message.
+ * The description is limited to 240 characters
+ * and has an ellipsis added if it is truncated.
+ */
+ $maxDescription = 240;
+ $ellipsis = " (...)";
+ $description = strip_tags($message);
+ if (strlen($description) > $maxDescription) {
+ $description = substr($description, 0, $maxDescription - strlen($ellipsis)) . $ellipsis;
}
+ $dao->description = $description;
+
if ($this->currentJob) {
$dao->job_id = $this->currentJob->id;
$dao->name = $this->currentJob->name;
$form->assign('suppressSubmitButton', $form->_paymentObject->isSuppressSubmitButtons());
- $currency = $form->getCurrency();
- $form->assign('currency', $currency);
+ $form->assign('currency', $form->getCurrency());
// also set cancel subscription url
if (!empty($form->_paymentProcessor['is_recur']) && !empty($form->_values['is_recur'])) {
*/
public function getCount($cacheKey);
+ /**
+ * Fetch a list of contacts from the prev/next cache for displaying a search results page
+ *
+ * @param string $cacheKey
+ * @param int $offset
+ * @param int $rowCount
+ * @return array
+ * List of contact IDs (entity_id1).
+ */
+ public function fetch($cacheKey, $offset, $rowCount);
+
}
--- /dev/null
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 5 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2018 |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM. |
+ | |
+ | CiviCRM is free software; you can copy, modify, and distribute it |
+ | under the terms of the GNU Affero General Public License |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
+ | |
+ | CiviCRM is distributed in the hope that it will be useful, but |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
+ | See the GNU Affero General Public License for more details. |
+ | |
+ | You should have received a copy of the GNU Affero General Public |
+ | License and the CiviCRM Licensing Exception along |
+ | with this program; if not, contact CiviCRM LLC |
+ | at info[AT]civicrm[DOT]org. If you have questions about the |
+ | GNU Affero General Public License or the licensing of CiviCRM, |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * Class CRM_Core_PrevNextCache_Memory
+ *
+ * Store the previous/next cache in a Redis set.
+ *
+ * Each logical prev-next cache corresponds to three distinct items in Redis:
+ * - "{prefix}/{qfKey}/list" - Sorted set of `entity_id`, with all entities
+ * - "{prefix}/{qfkey}/sel" - Sorted set of `entity_id`, with only entities marked by user
+ * - "{prefix}/{qfkey}/data" - Hash mapping from `entity_id` to `data`
+ *
+ * @link https://github.com/phpredis/phpredis
+ */
+class CRM_Core_PrevNextCache_Redis implements CRM_Core_PrevNextCache_Interface {
+
+ const TTL = 21600;
+
+ /**
+ * @var Redis
+ */
+ protected $redis;
+
+ /**
+ * @var string
+ */
+ protected $prefix;
+
+ /**
+ * CRM_Core_PrevNextCache_Redis constructor.
+ * @param array $settings
+ */
+ public function __construct($settings) {
+ $this->redis = CRM_Utils_Cache_Redis::connect($settings);
+ $this->prefix = isset($settings['prefix']) ? $settings['prefix'] : '';
+ $this->prefix .= \CRM_Utils_Cache::DELIMITER . 'prevnext' . \CRM_Utils_Cache::DELIMITER;
+ }
+
+ public function fillWithSql($cacheKey, $sql) {
+ $dao = CRM_Core_DAO::executeQuery($sql, [], FALSE, NULL, FALSE, TRUE, TRUE);
+ if (is_a($dao, 'DB_Error')) {
+ throw new CRM_Core_Exception($dao->message);
+ }
+
+ list($allKey, $dataKey, , $maxScore) = $this->initCacheKey($cacheKey);
+
+ while ($dao->fetch()) {
+ list (, $entity_id, $data) = array_values($dao->toArray());
+ $maxScore++;
+ $this->redis->zAdd($allKey, $maxScore, $entity_id);
+ $this->redis->hSet($dataKey, $entity_id, $data);
+ }
+
+ $dao->free();
+ return TRUE;
+ }
+
+ public function fillWithArray($cacheKey, $rows) {
+ list($allKey, $dataKey, , $maxScore) = $this->initCacheKey($cacheKey);
+
+ foreach ($rows as $row) {
+ $maxScore++;
+ $this->redis->zAdd($allKey, $maxScore, $row['entity_id1']);
+ $this->redis->hSet($dataKey, $row['entity_id1'], $row['data']);
+ }
+
+ return TRUE;
+ }
+
+ public function fetch($cacheKey, $offset, $rowCount) {
+ $allKey = $this->key($cacheKey, 'all');
+ return $this->redis->zRange($allKey, $offset, $offset + $rowCount - 1);
+ }
+
+ public function markSelection($cacheKey, $action, $ids = NULL) {
+ $allKey = $this->key($cacheKey, 'all');
+ $selKey = $this->key($cacheKey, 'sel');
+
+ if ($action === 'select') {
+ foreach ((array) $ids as $id) {
+ $score = $this->redis->zScore($allKey, $id);
+ $this->redis->zAdd($selKey, $score, $id);
+ }
+ }
+ elseif ($action === 'unselect' && $ids === NULL) {
+ $this->redis->delete($selKey);
+ $this->redis->setTimeout($selKey, self::TTL);
+ }
+ elseif ($action === 'unselect' && $ids !== NULL) {
+ foreach ((array) $ids as $id) {
+ $this->redis->zDelete($selKey, $id);
+ }
+ }
+ }
+
+ public function getSelection($cacheKey, $action = 'get') {
+ $allKey = $this->key($cacheKey, 'all');
+ $selKey = $this->key($cacheKey, 'sel');
+
+ if ($action === 'get') {
+ $result = [];
+ foreach ($this->redis->zRange($selKey, 0, -1) as $entity_id) {
+ $result[$entity_id] = 1;
+ }
+ return [$cacheKey => $result];
+ }
+ elseif ($action === 'getall') {
+ $result = [];
+ foreach ($this->redis->zRange($allKey, 0, -1) as $entity_id) {
+ $result[$entity_id] = 1;
+ }
+ return [$cacheKey => $result];
+ }
+ else {
+ throw new \CRM_Core_Exception("Unrecognized action: $action");
+ }
+ }
+
+ public function getPositions($cacheKey, $id1) {
+ $allKey = $this->key($cacheKey, 'all');
+ $dataKey = $this->key($cacheKey, 'data');
+
+ $rank = $this->redis->zRank($allKey, $id1);
+ if (!is_int($rank) || $rank < 0) {
+ return ['foundEntry' => 0];
+ }
+
+ $pos = ['foundEntry' => 1];
+
+ if ($rank > 0) {
+ $pos['prev'] = [];
+ foreach ($this->redis->zRange($allKey, $rank - 1, $rank - 1) as $value) {
+ $pos['prev']['id1'] = $value;
+ }
+ $pos['prev']['data'] = $this->redis->hGet($dataKey, $pos['prev']['id1']);
+ }
+
+ $count = $this->getCount($cacheKey);
+ if ($count > $rank + 1) {
+ $pos['next'] = [];
+ foreach ($this->redis->zRange($allKey, $rank + 1, $rank + 1) as $value) {
+ $pos['next']['id1'] = $value;
+ }
+ $pos['next']['data'] = $this->redis->hGet($dataKey, $pos['next']['id1']);
+ }
+
+ return $pos;
+ }
+
+ public function deleteItem($id = NULL, $cacheKey = NULL) {
+ if ($id === NULL && $cacheKey !== NULL) {
+ // Delete by cacheKey.
+ $allKey = $this->key($cacheKey, 'all');
+ $selKey = $this->key($cacheKey, 'sel');
+ $dataKey = $this->key($cacheKey, 'data');
+ $this->redis->delete($allKey, $selKey, $dataKey);
+ }
+ elseif ($id === NULL && $cacheKey === NULL) {
+ // Delete everything.
+ $keys = $this->redis->keys($this->prefix . '*');
+ $this->redis->del($keys);
+ }
+ elseif ($id !== NULL && $cacheKey !== NULL) {
+ // Delete a specific contact, within a specific cache.
+ $this->redis->zDelete($this->key($cacheKey, 'all'), $id);
+ $this->redis->zDelete($this->key($cacheKey, 'sel'), $id);
+ $this->redis->hDel($this->key($cacheKey, 'data'), $id);
+ }
+ elseif ($id !== NULL && $cacheKey === NULL) {
+ // Delete a specific contact, across all prevnext caches.
+ $allKeys = $this->redis->keys($this->key('*', 'all'));
+ foreach ($allKeys as $allKey) {
+ $parts = explode(\CRM_Utils_Cache::DELIMITER, $allKey);
+ array_pop($parts);
+ $tmpCacheKey = array_pop($parts);
+ $this->deleteItem($id, $tmpCacheKey);
+ }
+ }
+ else {
+ throw new CRM_Core_Exception("Not implemented: Redis::deleteItem");
+ }
+ }
+
+ public function getCount($cacheKey) {
+ $allKey = $this->key($cacheKey, 'all');
+ return $this->redis->zSize($allKey);
+ }
+
+ /**
+ * Construct the full path to a cache item.
+ *
+ * @param string $cacheKey
+ * Identifier for this saved search.
+ * Ex: 'abcd1234abcd1234'.
+ * @param string $item
+ * Ex: 'list', 'rel', 'data'.
+ * @return string
+ * Ex: 'dmaster/prevnext/abcd1234abcd1234/list'
+ */
+ private function key($cacheKey, $item) {
+ return $this->prefix . $cacheKey . \CRM_Utils_Cache::DELIMITER . $item;
+ }
+
+ /**
+ * Initialize any data-structures or timeouts for the cache-key.
+ *
+ * This is non-destructive -- if data already exists, it's preserved.
+ *
+ * @return array
+ * 0 => string $allItemsCacheKey,
+ * 1 => string $dataItemsCacheKey,
+ * 2 => string $selectedItemsCacheKey,
+ * 3 => int $maxExistingScore
+ */
+ private function initCacheKey($cacheKey) {
+ $allKey = $this->key($cacheKey, 'all');
+ $selKey = $this->key($cacheKey, 'sel');
+ $dataKey = $this->key($cacheKey, 'data');
+
+ $this->redis->setTimeout($allKey, self::TTL);
+ $this->redis->setTimeout($dataKey, self::TTL);
+ $this->redis->setTimeout($selKey, self::TTL);
+
+ $maxScore = 0;
+ foreach ($this->redis->zRange($allKey, -1, -1, TRUE) as $lastElem => $lastScore) {
+ $maxScore = $lastScore;
+ }
+ return array($allKey, $dataKey, $selKey, $maxScore);
+ }
+
+}
* @param string $cacheKey
* @param string $action
* Ex: 'select', 'unselect'.
- * @param array|int|NULL $cIds
+ * @param array|int|NULL $ids
* A list of contact IDs to (un)select.
* To unselect all contact IDs, use NULL.
*/
- public function markSelection($cacheKey, $action, $cIds = NULL) {
+ public function markSelection($cacheKey, $action, $ids = NULL) {
if (!$cacheKey) {
return;
}
$params = array();
- if ($cIds && $cacheKey && $action) {
- if (is_array($cIds)) {
- $cIdFilter = "(" . implode(',', $cIds) . ")";
+ if ($ids && $cacheKey && $action) {
+ if (is_array($ids)) {
+ $cIdFilter = "(" . implode(',', $ids) . ")";
$whereClause = "
WHERE cacheKey = %1
AND (entity_id1 IN {$cIdFilter} OR entity_id2 IN {$cIdFilter})
WHERE cacheKey = %1
AND (entity_id1 = %2 OR entity_id2 = %2)
";
- $params[2] = array("{$cIds}", 'Integer');
+ $params[2] = array("{$ids}", 'Integer');
}
if ($action == 'select') {
$whereClause .= "AND is_selected = 0";
}
// default action is reseting
}
- elseif (!$cIds && $cacheKey && $action == 'unselect') {
+ elseif (!$ids && $cacheKey && $action == 'unselect') {
$sql = "
UPDATE civicrm_prevnext_cache
SET is_selected = 0
return (int) CRM_Core_DAO::singleValueQuery($query, $params, TRUE, FALSE);
}
+ /**
+ * Fetch a list of contacts from the prev/next cache for displaying a search results page
+ *
+ * @param string $cacheKey
+ * @param int $offset
+ * @param int $rowCount
+ * @return array
+ * List of contact IDs.
+ */
+ public function fetch($cacheKey, $offset, $rowCount) {
+ $cids = array();
+ $dao = CRM_Utils_SQL_Select::from('civicrm_prevnext_cache pnc')
+ ->where('pnc.cacheKey = @cacheKey', ['cacheKey' => $cacheKey])
+ ->select('pnc.entity_id1 as cid')
+ ->orderBy('pnc.id')
+ ->limit($rowCount, $offset)
+ ->execute();
+ while ($dao->fetch()) {
+ $cids[] = $dao->cid;
+ }
+ return $cids;
+ }
+
}
if ($isRead) {
return;
}
- $config =& CRM_Core_Config::singleton();
// FIXME: This belongs in CRM_Utils_System_*
- if ($config->userSystem->is_drupal && function_exists('drupal_session_start')) {
+ if (CRM_Core_Config::singleton()->userSystem->is_drupal && function_exists('drupal_session_start')) {
// https://issues.civicrm.org/jira/browse/CRM-14356
if (!(isset($GLOBALS['lazy_session']) && $GLOBALS['lazy_session'] == TRUE)) {
drupal_session_start();
* @param int $id
* The event id to copy.
* boolean $afterCreate call to copy after the create function
- * @param null $newEvent
- * @param bool $afterCreate
*
* @return CRM_Event_DAO_Event
+ * @throws \CRM_Core_Exception
*/
- public static function copy($id, $newEvent = NULL, $afterCreate = FALSE) {
-
+ public static function copy($id) {
$eventValues = array();
//get the require event values.
CRM_Core_DAO::commonRetrieve('CRM_Event_DAO_Event', $eventParams, $eventValues, $returnProperties);
- // since the location is sharable, lets use the same loc_block_id.
- $locBlockId = CRM_Utils_Array::value('loc_block_id', $eventValues);
-
- $fieldsFix = ($afterCreate) ? array() : array('prefix' => array('title' => ts('Copy of') . ' '));
+ $fieldsFix = array('prefix' => array('title' => ts('Copy of') . ' '));
if (empty($eventValues['is_show_location'])) {
$fieldsFix['prefix']['is_show_location'] = 0;
}
- if ($newEvent && is_a($newEvent, 'CRM_Event_DAO_Event')) {
- $copyEvent = $newEvent;
- }
-
- if (!isset($copyEvent)) {
- $copyEvent = &CRM_Core_DAO::copyGeneric('CRM_Event_DAO_Event',
- array('id' => $id),
- array(
- 'loc_block_id' =>
- ($locBlockId) ? $locBlockId : NULL,
- ),
- $fieldsFix
- );
- }
+ $copyEvent = CRM_Core_DAO::copyGeneric('CRM_Event_DAO_Event',
+ array('id' => $id),
+ // since the location is sharable, lets use the same loc_block_id.
+ array('loc_block_id' => CRM_Utils_Array::value('loc_block_id', $eventValues)),
+ $fieldsFix
+ );
CRM_Price_BAO_PriceSet::copyPriceSet('civicrm_event', $id, $copyEvent->id);
- $copyUF = &CRM_Core_DAO::copyGeneric('CRM_Core_DAO_UFJoin',
+ CRM_Core_DAO::copyGeneric('CRM_Core_DAO_UFJoin',
array(
'entity_id' => $id,
'entity_table' => 'civicrm_event',
array('entity_id' => $copyEvent->id)
);
- $copyTellFriend = &CRM_Core_DAO::copyGeneric('CRM_Friend_DAO_Friend',
+ CRM_Core_DAO::copyGeneric('CRM_Friend_DAO_Friend',
array(
'entity_id' => $id,
'entity_table' => 'civicrm_event',
array('entity_id' => $copyEvent->id)
);
- $copyPCP = &CRM_Core_DAO::copyGeneric('CRM_PCP_DAO_PCPBlock',
+ CRM_Core_DAO::copyGeneric('CRM_PCP_DAO_PCPBlock',
array(
'entity_id' => $id,
'entity_table' => 'civicrm_event',
$copyMapping = CRM_Utils_Array::first(CRM_Core_BAO_ActionSchedule::getMappings(array(
'id' => ($copyEvent->is_template == 1 ? CRM_Event_ActionMapping::EVENT_TPL_MAPPING_ID : CRM_Event_ActionMapping::EVENT_NAME_MAPPING_ID),
)));
- $copyReminder = &CRM_Core_DAO::copyGeneric('CRM_Core_DAO_ActionSchedule',
+ CRM_Core_DAO::copyGeneric('CRM_Core_DAO_ActionSchedule',
array('entity_value' => $id, 'mapping_id' => $oldMapping->getId()),
array('entity_value' => $copyEvent->id, 'mapping_id' => $copyMapping->getId())
);
-
- if (!$afterCreate) {
- // CRM-19302
- self::copyCustomFields($id, $copyEvent->id);
- }
+ self::copyCustomFields($id, $copyEvent->id);
$copyEvent->save();
CRM_Utils_System::flushCache();
- if (!$afterCreate) {
- CRM_Utils_Hook::copy('Event', $copyEvent);
- }
+ CRM_Utils_Hook::copy('Event', $copyEvent);
+
return $copyEvent;
}
$params = array_merge(CRM_Event_BAO_Event::getTemplateDefaultValues($params['template_id']), $params);
}
- $event = CRM_Event_BAO_Event::create($params);
-
// now that we have the event’s id, do some more template-based stuff
if (!empty($params['template_id'])) {
- CRM_Event_BAO_Event::copy($params['template_id'], $event, TRUE);
+ $event = CRM_Event_BAO_Event::copy($params['template_id']);
+ }
+ else {
+ $event = CRM_Event_BAO_Event::create($params);
}
$this->set('id', $event->id);
* all the fields in the event wizard
*
* @return void
+ * @throws \CRM_Core_Exception
*/
public function copy() {
$id = CRM_Utils_Request::retrieve('id', 'Positive', $this, TRUE, 0, 'GET');
return $controller->run();
}
+ public function delete() {
+ $controller = new CRM_Core_Controller_Simple(
+ 'CRM_Event_Form_Participant',
+ ts('Delete Participant'),
+ $this->_action
+ );
+
+ $controller->setEmbedded(TRUE);
+ $controller->set('id', $this->_id);
+ $controller->set('cid', $this->_contactId);
+ $controller->run();
+ }
+
public function preProcess() {
$context = CRM_Utils_Request::retrieve('context', 'Alphanumeric', $this);
$this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse');
if ($this->_action & CRM_Core_Action::VIEW) {
$this->view();
}
- elseif ($this->_action & (CRM_Core_Action::UPDATE |
- CRM_Core_Action::ADD |
- CRM_Core_Action::DELETE
- )
- ) {
+ elseif ($this->_action & (CRM_Core_Action::UPDATE | CRM_Core_Action::ADD)) {
$this->edit();
}
+ elseif ($this->_action & (CRM_Core_Action::DELETE | CRM_Core_Action::DETACH)) {
+ $this->delete();
+ }
else {
$this->browse();
}
$groupBy = "civicrm_activity.id ";
}
- if (!empty($groupBy)) {
- if (!Civi::settings()->get('searchPrimaryDetailsOnly')) {
- CRM_Core_DAO::disableFullGroupByMode();
- }
- $groupBy = CRM_Contact_BAO_Query::getGroupByFromSelectColumns($query->_select, $groupBy);
- }
-
- return $groupBy;
+ return $groupBy ? ' GROUP BY ' . $groupBy : '';
}
/**
$processor = new CRM_Export_BAO_ExportProcessor($exportMode, $fields, $queryOperator, $mergeSameHousehold);
$returnProperties = array();
-
- $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
- // Warning - this imProviders var is used in a somewhat fragile way - don't rename it
- // without manually testing the export of IM provider still works.
- $imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
self::$relationshipTypes = $processor->getRelationshipTypes();
- $queryMode = $processor->getQueryMode();
-
if ($fields) {
foreach ($fields as $key => $value) {
$fieldName = CRM_Utils_Array::value(1, $value);
if (!array_key_exists($column, $returnProperties)) {
$returnProperties[$column] = 1;
$column = $column == 'id' ? 'civicrm_primary_id' : $column;
+ $processor->setColumnAsCalculationOnly($column);
$exportParams['merge_same_address']['temp_columns'][$column] = 1;
}
}
if (!array_key_exists($column, $returnProperties)) {
$returnProperties[$column] = 1;
$exportParams['postal_mailing_export']['temp_columns'][$column] = 1;
+ $processor->setColumnAsCalculationOnly($column);
}
}
}
$paymentDetails = array();
if ($processor->isExportPaymentFields()) {
-
// get payment related in for event and members
$paymentDetails = CRM_Contribute_BAO_Contribution::getContributionDetails($exportMode, $ids);
//get all payment headers.
// If we haven't selected specific payment fields, load in all the
// payment headers.
if (!$processor->isExportSpecifiedPaymentFields()) {
- $paymentHeaders = self::componentPaymentFields();
if (!empty($paymentDetails)) {
$addPaymentHeader = TRUE;
}
}
- // If we have selected specific payment fields, leave the payment headers
- // as an empty array; the headers for each selected field will be added
- // elsewhere.
- else {
- $paymentHeaders = array();
- }
- $nullContributionDetails = array_fill_keys(array_keys($paymentHeaders), NULL);
}
$componentDetails = array();
- $setHeader = TRUE;
$rowCount = self::EXPORT_ROW_COUNT;
$offset = 0;
$count = -1;
- // for CRM-3157 purposes
- $i18n = CRM_Core_I18n::singleton();
+ list($outputColumns, $sqlColumns, $metadata) = self::getExportStructureArrays($returnProperties, $processor);
+ $headerRows = $processor->getHeaderRows();
- list($outputColumns, $headerRows, $sqlColumns, $metadata) = self::getExportStructureArrays($returnProperties, $processor);
+ // add payment headers if required
+ if ($addPaymentHeader && $processor->isExportPaymentFields()) {
+ // @todo rather than do this for every single row do it before the loop starts.
+ // where other header definitions take place.
+ $headerRows = array_merge($headerRows, $processor->getPaymentHeaders());
+ foreach (array_keys($processor->getPaymentHeaders()) as $paymentHdr) {
+ self::sqlColumnDefn($processor, $sqlColumns, $paymentHdr);
+ }
+ }
+ $exportTempTable = self::createTempTable($sqlColumns);
$limitReached = FALSE;
+
while (!$limitReached) {
$limitQuery = "{$queryString} LIMIT {$offset}, {$rowCount}";
+ CRM_Core_DAO::disableFullGroupByMode();
$iterationDAO = CRM_Core_DAO::executeQuery($limitQuery);
+ CRM_Core_DAO::reenableFullGroupByMode();
// If this is less than our limit by the end of the iteration we do not need to run the query again to
// check if some remain.
$rowsThisIteration = 0;
while ($iterationDAO->fetch()) {
$count++;
$rowsThisIteration++;
- $row = array();
- $query->convertToPseudoNames($iterationDAO);
-
- //first loop through output columns so that we return what is required, and in same order.
- foreach ($outputColumns as $field => $value) {
-
- // add im_provider to $dao object
- if ($field == 'im_provider' && property_exists($iterationDAO, 'provider_id')) {
- $iterationDAO->im_provider = $iterationDAO->provider_id;
- }
-
- //build row values (data)
- $fieldValue = NULL;
- if (property_exists($iterationDAO, $field)) {
- $fieldValue = $iterationDAO->$field;
- // to get phone type from phone type id
- if ($field == 'phone_type_id' && isset($phoneTypes[$fieldValue])) {
- $fieldValue = $phoneTypes[$fieldValue];
- }
- elseif ($field == 'provider_id' || $field == 'im_provider') {
- $fieldValue = CRM_Utils_Array::value($fieldValue, $imProviders);
- }
- elseif (strstr($field, 'master_id')) {
- $masterAddressId = NULL;
- if (isset($iterationDAO->$field)) {
- $masterAddressId = $iterationDAO->$field;
- }
- // get display name of contact that address is shared.
- $fieldValue = CRM_Contact_BAO_Contact::getMasterDisplayName($masterAddressId);
- }
- }
-
- if ($processor->isRelationshipTypeKey($field)) {
- foreach (array_keys($value) as $property) {
- if ($property === 'location') {
- // @todo just undo all this nasty location wrangling!
- foreach ($value['location'] as $locationKey => $locationFields) {
- foreach (array_keys($locationFields) as $locationField) {
- $fieldKey = str_replace(' ', '_', $locationKey . '-' . $locationField);
- $row[$field . '_' . $fieldKey] = $processor->getRelationshipValue($field, $iterationDAO->contact_id, $fieldKey);
- }
- }
- }
- else {
- $row[$field . '_' . $property] = $processor->getRelationshipValue($field, $iterationDAO->contact_id, $property);
- }
- }
- }
- else {
- $row[$field] = self::getTransformedFieldValue($field, $iterationDAO, $fieldValue, $i18n, $metadata, $paymentDetails, $processor);
- }
- }
-
- // add payment headers if required
- if ($addPaymentHeader && $processor->isExportPaymentFields()) {
- // @todo rather than do this for every single row do it before the loop starts.
- // where other header definitions take place.
- $headerRows = array_merge($headerRows, $paymentHeaders);
- foreach (array_keys($paymentHeaders) as $paymentHdr) {
- self::sqlColumnDefn($processor, $sqlColumns, $paymentHdr);
- }
- }
-
- if ($setHeader) {
- $exportTempTable = self::createTempTable($sqlColumns);
- }
-
- //build header only once
- $setHeader = FALSE;
-
- // If specific payment fields have been selected for export, payment
- // data will already be in $row. Otherwise, add payment related
- // information, if appropriate.
- if ($addPaymentHeader) {
- if (!$processor->isExportSpecifiedPaymentFields()) {
- if ($processor->isExportPaymentFields()) {
- $paymentData = CRM_Utils_Array::value($row[$paymentTableId], $paymentDetails);
- if (!is_array($paymentData) || empty($paymentData)) {
- $paymentData = $nullContributionDetails;
- }
- $row = array_merge($row, $paymentData);
- }
- elseif (!empty($paymentDetails)) {
- $row = array_merge($row, $nullContributionDetails);
- }
- }
- }
- //remove organization name for individuals if it is set for current employer
- if (!empty($row['contact_type']) &&
- $row['contact_type'] == 'Individual' && array_key_exists('organization_name', $row)
- ) {
- $row['organization_name'] = '';
- }
+ $row = $processor->buildRow($query, $iterationDAO, $outputColumns, $metadata, $paymentDetails, $addPaymentHeader, $paymentTableId);
// add component info
// write the row to a file
if (isset($exportParams['postal_mailing_export']['postal_mailing_export']) &&
$exportParams['postal_mailing_export']['postal_mailing_export'] == 1
) {
- self::postalMailingFormat($exportTempTable, $headerRows, $sqlColumns, $exportMode);
+ self::postalMailingFormat($exportTempTable, $sqlColumns, $exportMode);
}
// do merge same address and merge same household processing
if ($mergeSameAddress) {
- self::mergeSameAddress($exportTempTable, $headerRows, $sqlColumns, $exportParams);
+ self::mergeSameAddress($exportTempTable, $sqlColumns, $exportParams);
}
// merge the records if they have corresponding households
/**
* @param string $tableName
- * @param $headerRows
* @param $sqlColumns
* @param array $exportParams
*/
- public static function mergeSameAddress($tableName, &$headerRows, &$sqlColumns, $exportParams) {
+ public static function mergeSameAddress($tableName, &$sqlColumns, $exportParams) {
// check if any records are present based on if they have used shared address feature,
// and not based on if city / state .. matches.
$sql = "
$unsetKeys = array_keys($sqlColumns);
foreach ($unsetKeys as $headerKey => $sqlColKey) {
if (array_key_exists($sqlColKey, $exportParams['merge_same_address']['temp_columns'])) {
- unset($sqlColumns[$sqlColKey], $headerRows[$headerKey]);
+ unset($sqlColumns[$sqlColKey]);
}
}
}
FROM {$exportTempTable}
GROUP BY civicrm_primary_id ";
+ CRM_Core_DAO::disableFullGroupByMode();
CRM_Core_DAO::executeQuery($query);
+ CRM_Core_DAO::reenableFullGroupByMode();
$query = "DROP TABLE $exportTempTable";
CRM_Core_DAO::executeQuery($query);
}
}
- /**
- * Manipulate header rows for relationship fields.
- *
- * @param $headerRows
- */
- public static function manipulateHeaderRows(&$headerRows) {
- foreach ($headerRows as & $header) {
- $split = explode('-', $header);
- if ($relationTypeName = CRM_Utils_Array::value($split[0], self::$relationshipTypes)) {
- $split[0] = $relationTypeName;
- $header = implode('-', $split);
- }
- }
- }
-
/**
* Exclude contacts who are deceased, have "Do not mail" privacy setting,
* or have no street address
* @param $exportTempTable
- * @param $headerRows
* @param $sqlColumns
* @param $exportParams
*/
- public static function postalMailingFormat($exportTempTable, &$headerRows, &$sqlColumns, $exportParams) {
+ public static function postalMailingFormat($exportTempTable, &$sqlColumns, $exportParams) {
$whereClause = array();
if (array_key_exists('is_deceased', $sqlColumns)) {
$unsetKeys = array_keys($sqlColumns);
foreach ($unsetKeys as $headerKey => $sqlColKey) {
if (array_key_exists($sqlColKey, $exportParams['postal_mailing_export']['temp_columns'])) {
- unset($sqlColumns[$sqlColKey], $headerRows[$headerKey]);
+ unset($sqlColumns[$sqlColKey]);
}
}
}
/**
* Build componentPayment fields.
+ *
+ * This is no longer used by export but BAO_Mapping still calls it & we
+ * should find a generic way to handle this or move this to that class.
+ *
+ * @deprecated
*/
public static function componentPaymentFields() {
static $componentPaymentFields;
return $componentPaymentFields;
}
- /**
- * Set the definition for the header rows and sql columns based on the field to output.
- *
- * @param string $field
- * @param array $headerRows
- * @param \CRM_Export_BAO_ExportProcessor $processor
- *
- * @return array
- */
- public static function setHeaderRows($field, $headerRows, $processor) {
-
- $queryFields = $processor->getQueryFields();
- if (substr($field, -11) == 'campaign_id') {
- // @todo - set this correctly in the xml rather than here.
- $headerRows[] = ts('Campaign ID');
- }
- elseif ($processor->isMergeSameHousehold() && $field === 'id') {
- $headerRows[] = ts('Household ID');
- }
- elseif (isset($queryFields[$field]['title'])) {
- $headerRows[] = $queryFields[$field]['title'];
- }
- elseif ($field == 'provider_id') {
- // @todo - set this correctly in the xml rather than here.
- $headerRows[] = ts('IM Service Provider');
- }
- elseif ($processor->isExportPaymentFields() && array_key_exists($field, self::componentPaymentFields())) {
- $headerRows[] = CRM_Utils_Array::value($field, self::componentPaymentFields());
- }
- else {
- $headerRows[] = $field;
- }
-
- return $headerRows;
- }
-
/**
* Get the various arrays that we use to structure our output.
*
* yet find a way to comment them for posterity.
*/
public static function getExportStructureArrays($returnProperties, $processor) {
- $metadata = $headerRows = $outputColumns = $sqlColumns = array();
+ $metadata = $outputColumns = $sqlColumns = array();
$phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
$imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
$queryFields = $processor->getQueryFields();
foreach ($returnProperties as $key => $value) {
if (($key != 'location' || !is_array($value)) && !$processor->isRelationshipTypeKey($key)) {
$outputColumns[$key] = $value;
- $headerRows = self::setHeaderRows($key, $headerRows, $processor);
+ $processor->addOutputSpecification($key);
self::sqlColumnDefn($processor, $sqlColumns, $key);
}
elseif ($processor->isRelationshipTypeKey($key)) {
foreach ($value as $relationField => $relationValue) {
// below block is same as primary block (duplicate)
if (isset($queryFields[$relationField]['title'])) {
- if ($queryFields[$relationField]['name'] == 'name') {
- $headerName = $field . '-' . $relationField;
- }
- else {
- if ($relationField == 'current_employer') {
- $headerName = $field . '-' . 'current_employer';
- }
- else {
- $headerName = $field . '-' . $relationField;
- }
- }
-
if (!$processor->isHouseholdMergeRelationshipTypeKey($field)) {
// Do not add to header row if we are only generating for merge reasons.
- $headerRows[] = $headerName;
+ $processor->addOutputSpecification($relationField, $key);
}
-
- self::sqlColumnDefn($processor, $sqlColumns, $headerName);
- }
- elseif ($relationField == 'phone_type_id') {
- $headerName = $field . '-' . 'Phone Type';
- $headerRows[] = $headerName;
- self::sqlColumnDefn($processor, $sqlColumns, $headerName);
- }
- elseif ($relationField == 'provider_id') {
- $headerName = $field . '-' . 'Im Service Provider';
- $headerRows[] = $headerName;
- self::sqlColumnDefn($processor, $sqlColumns, $headerName);
- }
- elseif ($relationField == 'state_province_id') {
- $headerName = $field . '-' . 'state_province_id';
- $headerRows[] = $headerName;
- self::sqlColumnDefn($processor, $sqlColumns, $headerName);
+ self::sqlColumnDefn($processor, $sqlColumns, $field . '-' . $relationField);
}
elseif (is_array($relationValue) && $relationField == 'location') {
// fix header for location type case
$hdr .= "-" . CRM_Core_PseudoConstant::getLabel('CRM_Core_BAO_IM', 'provider_id', $type[1]);
}
}
- $headerName = $field . '-' . $hdr;
- $headerRows[] = $headerName;
- self::sqlColumnDefn($processor, $sqlColumns, $headerName);
+ $processor->addOutputSpecification($field, $key, $ltype, CRM_Utils_Array::value(1, $type));
+ self::sqlColumnDefn($processor, $sqlColumns, $field . '-' . $hdr);
}
}
}
}
- self::manipulateHeaderRows($headerRows);
}
else {
foreach ($value as $locationType => $locationFields) {
$metadata[$daoFieldName]['pseudoconstant']['var'] = 'imProviders';
}
self::sqlColumnDefn($processor, $sqlColumns, $outputFieldName);
- $headerRows = self::setHeaderRows($outputFieldName, $headerRows, $processor);
+ $processor->addOutputSpecification($outputFieldName, NULL, $locationType, CRM_Utils_Array::value(1, $type));
self::sqlColumnDefn($processor, $sqlColumns, $outputFieldName);
if ($actualDBFieldName == 'country' || $actualDBFieldName == 'world_region') {
$metadata[$daoFieldName] = array('context' => 'country');
}
}
}
- return array($outputColumns, $headerRows, $sqlColumns, $metadata);
+ return array($outputColumns, $sqlColumns, $metadata);
}
/**
$today = date('Ymd');
$relationActive = " AND (crel.is_active = 1 AND ( crel.end_date is NULL OR crel.end_date >= {$today} ) )";
$relationWhere = " WHERE contact_a.is_deleted = 0 {$relationshipClause} {$relationActive}";
- $relationGroupBy = CRM_Contact_BAO_Query::getGroupByFromSelectColumns($relationQuery->_select, "crel.{$contactA}");
+ CRM_Core_DAO::disableFullGroupByMode();
$relationSelect = "{$relationSelect}, {$contactA} as refContact ";
- $relationQueryString = "$relationSelect $relationFrom $relationWhere $relationHaving $relationGroupBy";
+ $relationQueryString = "$relationSelect $relationFrom $relationWhere $relationHaving GROUP BY crel.{$contactA}";
$allRelContactDAO = CRM_Core_DAO::executeQuery($relationQueryString);
+ CRM_Core_DAO::reenableFullGroupByMode();
+
while ($allRelContactDAO->fetch()) {
$relationQuery->convertToPseudoNames($allRelContactDAO);
$row = [];
}
}
- /**
- * @param $field
- * @param $iterationDAO
- * @param $fieldValue
- * @param $i18n
- * @param $metadata
- * @param $paymentDetails
- *
- * @param \CRM_Export_BAO_ExportProcessor $processor
- *
- * @return string
- */
- protected static function getTransformedFieldValue($field, $iterationDAO, $fieldValue, $i18n, $metadata, $paymentDetails, $processor) {
-
- if ($field == 'id') {
- return $iterationDAO->contact_id;
- // special case for calculated field
- }
- elseif ($field == 'source_contact_id') {
- return $iterationDAO->contact_id;
- }
- elseif ($field == 'pledge_balance_amount') {
- return $iterationDAO->pledge_amount - $iterationDAO->pledge_total_paid;
- // special case for calculated field
- }
- elseif ($field == 'pledge_next_pay_amount') {
- return $iterationDAO->pledge_next_pay_amount + $iterationDAO->pledge_outstanding_amount;
- }
- elseif (isset($fieldValue) &&
- $fieldValue != ''
- ) {
- //check for custom data
- if ($cfID = CRM_Core_BAO_CustomField::getKeyID($field)) {
- return CRM_Core_BAO_CustomField::displayValue($fieldValue, $cfID);
- }
-
- elseif (in_array($field, array(
- 'email_greeting',
- 'postal_greeting',
- 'addressee',
- ))) {
- //special case for greeting replacement
- $fldValue = "{$field}_display";
- return $iterationDAO->$fldValue;
- }
- else {
- //normal fields with a touch of CRM-3157
- switch ($field) {
- case 'country':
- case 'world_region':
- return $i18n->crm_translate($fieldValue, array('context' => 'country'));
-
- case 'state_province':
- return $i18n->crm_translate($fieldValue, array('context' => 'province'));
-
- case 'gender':
- case 'preferred_communication_method':
- case 'preferred_mail_format':
- case 'communication_style':
- return $i18n->crm_translate($fieldValue);
-
- default:
- if (isset($metadata[$field])) {
- // No I don't know why we do it this way & whether we could
- // make better use of pseudoConstants.
- if (!empty($metadata[$field]['context'])) {
- return $i18n->crm_translate($fieldValue, $metadata[$field]);
- }
- if (!empty($metadata[$field]['pseudoconstant'])) {
- // This is not our normal syntax for pseudoconstants but I am a bit loath to
- // call an external function until sure it is not increasing php processing given this
- // may be iterated 100,000 times & we already have the $imProvider var loaded.
- // That can be next refactor...
- // Yes - definitely feeling hatred for this bit of code - I know you will beat me up over it's awfulness
- // but I have to reach a stable point....
- $varName = $metadata[$field]['pseudoconstant']['var'];
- if ($varName === 'imProviders') {
- return CRM_Core_PseudoConstant::getLabel('CRM_Core_DAO_IM', 'provider_id', $fieldValue);
- }
- if ($varName === 'phoneTypes') {
- return CRM_Core_PseudoConstant::getLabel('CRM_Core_DAO_Phone', 'phone_type_id', $fieldValue);
- }
- }
-
- }
- return $fieldValue;
- }
- }
- }
- elseif ($processor->isExportSpecifiedPaymentFields() && array_key_exists($field, self::componentPaymentFields())) {
- $paymentTableId = $processor->getPaymentTableID();
- $paymentData = CRM_Utils_Array::value($iterationDAO->$paymentTableId, $paymentDetails);
- $payFieldMapper = array(
- 'componentPaymentField_total_amount' => 'total_amount',
- 'componentPaymentField_contribution_status' => 'contribution_status',
- 'componentPaymentField_payment_instrument' => 'pay_instru',
- 'componentPaymentField_transaction_id' => 'trxn_id',
- 'componentPaymentField_received_date' => 'receive_date',
- );
- return CRM_Utils_Array::value($payFieldMapper[$field], $paymentData, '');
- }
- else {
- // if field is empty or null
- return '';
- }
- }
-
}
*/
protected $returnProperties = [];
+ /**
+ * @var array
+ */
+ protected $outputSpecification = [];
+
/**
* CRM_Export_BAO_ExportProcessor constructor.
*
}
}
+ /**
+ * Get the label for the header row based on the field to output.
+ *
+ * @param string $field
+ *
+ * @return string
+ */
+ public function getHeaderForRow($field) {
+ if (substr($field, -11) == 'campaign_id') {
+ // @todo - set this correctly in the xml rather than here.
+ // This will require a generalised handling cleanup
+ return ts('Campaign ID');
+ }
+ if ($this->isMergeSameHousehold() && $field === 'id') {
+ return ts('Household ID');
+ }
+ elseif (isset($this->getQueryFields()[$field]['title'])) {
+ return $this->getQueryFields()[$field]['title'];
+ }
+ elseif ($this->isExportPaymentFields() && array_key_exists($field, $this->getcomponentPaymentFields())) {
+ return CRM_Utils_Array::value($field, $this->getcomponentPaymentFields());
+ }
+ else {
+ return $field;
+ }
+ }
+
/**
* @param $params
* @param $order
return array($query, $select, $from, $where, $having);
}
+ /**
+ * Add a row to the specification for how to output data.
+ *
+ * @param string $key
+ * @param string $relationshipType
+ * @param string $locationType
+ * @param int $entityTypeID phone_type_id or provider_id for phone or im fields.
+ */
+ public function addOutputSpecification($key, $relationshipType = NULL, $locationType = NULL, $entityTypeID = NULL) {
+ $label = $this->getHeaderForRow($key);
+ $labelPrefix = $fieldPrefix = [];
+ if ($relationshipType) {
+ $labelPrefix[] = $this->getRelationshipTypes()[$relationshipType];
+ $fieldPrefix[] = $relationshipType;
+ }
+ if ($locationType) {
+ $labelPrefix[] = $fieldPrefix[] = $locationType;
+ }
+ if ($entityTypeID) {
+ if ($key === 'phone') {
+ $labelPrefix[] = $fieldPrefix[] = CRM_Core_PseudoConstant::getLabel('CRM_Core_BAO_Phone', 'phone_type_id', $entityTypeID);
+ }
+ if ($key === 'im') {
+ $labelPrefix[] = $fieldPrefix[] = CRM_Core_PseudoConstant::getLabel('CRM_Core_BAO_IM', 'provider_id', $entityTypeID);
+ }
+ }
+ $index = ($fieldPrefix ? (implode('-', $fieldPrefix) . '-') : '') . $key;
+ $this->outputSpecification[$index]['header'] = ($labelPrefix ? (implode('-', $labelPrefix) . '-') : '') . $label;
+
+ }
+
+ /**
+ * Mark a column as only required for calculations.
+ *
+ * Do not include the row with headers.
+ *
+ * @param string $column
+ */
+ public function setColumnAsCalculationOnly($column) {
+ $this->outputSpecification[$column]['do_not_output_to_csv'] = TRUE;
+ }
+
+ /**
+ * @return array
+ */
+ public function getHeaderRows() {
+ $headerRows = [];
+ foreach ($this->outputSpecification as $key => $spec) {
+ if (empty($spec['do_not_output_to_csv'])) {
+ $headerRows[] = $spec['header'];
+ }
+ }
+ return $headerRows;
+ }
+
+ /**
+ * Build the row for output.
+ *
+ * @param \CRM_Contact_BAO_Query $query
+ * @param CRM_Core_DAO $iterationDAO
+ * @param array $outputColumns
+ * @param $metadata
+ * @param $paymentDetails
+ * @param $addPaymentHeader
+ * @param $paymentTableId
+ *
+ * @return array
+ */
+ public function buildRow($query, $iterationDAO, $outputColumns, $metadata, $paymentDetails, $addPaymentHeader, $paymentTableId) {
+ $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
+ $imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
+
+ $row = [];
+ $query->convertToPseudoNames($iterationDAO);
+
+ //first loop through output columns so that we return what is required, and in same order.
+ foreach ($outputColumns as $field => $value) {
+
+ // add im_provider to $dao object
+ if ($field == 'im_provider' && property_exists($iterationDAO, 'provider_id')) {
+ $iterationDAO->im_provider = $iterationDAO->provider_id;
+ }
+
+ //build row values (data)
+ $fieldValue = NULL;
+ if (property_exists($iterationDAO, $field)) {
+ $fieldValue = $iterationDAO->$field;
+ // to get phone type from phone type id
+ if ($field == 'phone_type_id' && isset($phoneTypes[$fieldValue])) {
+ $fieldValue = $phoneTypes[$fieldValue];
+ }
+ elseif ($field == 'provider_id' || $field == 'im_provider') {
+ $fieldValue = CRM_Utils_Array::value($fieldValue, $imProviders);
+ }
+ elseif (strstr($field, 'master_id')) {
+ $masterAddressId = NULL;
+ if (isset($iterationDAO->$field)) {
+ $masterAddressId = $iterationDAO->$field;
+ }
+ // get display name of contact that address is shared.
+ $fieldValue = CRM_Contact_BAO_Contact::getMasterDisplayName($masterAddressId);
+ }
+ }
+
+ if ($this->isRelationshipTypeKey($field)) {
+ foreach (array_keys($value) as $property) {
+ if ($property === 'location') {
+ // @todo just undo all this nasty location wrangling!
+ foreach ($value['location'] as $locationKey => $locationFields) {
+ foreach (array_keys($locationFields) as $locationField) {
+ $fieldKey = str_replace(' ', '_', $locationKey . '-' . $locationField);
+ $row[$field . '_' . $fieldKey] = $this->getRelationshipValue($field, $iterationDAO->contact_id, $fieldKey);
+ }
+ }
+ }
+ else {
+ $row[$field . '_' . $property] = $this->getRelationshipValue($field, $iterationDAO->contact_id, $property);
+ }
+ }
+ }
+ else {
+ $row[$field] = $this->getTransformedFieldValue($field, $iterationDAO, $fieldValue, $metadata, $paymentDetails);
+ }
+ }
+
+ // If specific payment fields have been selected for export, payment
+ // data will already be in $row. Otherwise, add payment related
+ // information, if appropriate.
+ if ($addPaymentHeader) {
+ if (!$this->isExportSpecifiedPaymentFields()) {
+ $nullContributionDetails = array_fill_keys(array_keys($this->getPaymentHeaders()), NULL);
+ if ($this->isExportPaymentFields()) {
+ $paymentData = CRM_Utils_Array::value($row[$paymentTableId], $paymentDetails);
+ if (!is_array($paymentData) || empty($paymentData)) {
+ $paymentData = $nullContributionDetails;
+ }
+ $row = array_merge($row, $paymentData);
+ }
+ elseif (!empty($paymentDetails)) {
+ $row = array_merge($row, $nullContributionDetails);
+ }
+ }
+ }
+ //remove organization name for individuals if it is set for current employer
+ if (!empty($row['contact_type']) &&
+ $row['contact_type'] == 'Individual' && array_key_exists('organization_name', $row)
+ ) {
+ $row['organization_name'] = '';
+ }
+ return $row;
+ }
+
+ /**
+ * @param $field
+ * @param $iterationDAO
+ * @param $fieldValue
+ * @param $metadata
+ * @param $paymentDetails
+ *
+ * @return string
+ */
+ public function getTransformedFieldValue($field, $iterationDAO, $fieldValue, $metadata, $paymentDetails) {
+
+ $i18n = CRM_Core_I18n::singleton();
+ if ($field == 'id') {
+ return $iterationDAO->contact_id;
+ // special case for calculated field
+ }
+ elseif ($field == 'source_contact_id') {
+ return $iterationDAO->contact_id;
+ }
+ elseif ($field == 'pledge_balance_amount') {
+ return $iterationDAO->pledge_amount - $iterationDAO->pledge_total_paid;
+ // special case for calculated field
+ }
+ elseif ($field == 'pledge_next_pay_amount') {
+ return $iterationDAO->pledge_next_pay_amount + $iterationDAO->pledge_outstanding_amount;
+ }
+ elseif (isset($fieldValue) &&
+ $fieldValue != ''
+ ) {
+ //check for custom data
+ if ($cfID = CRM_Core_BAO_CustomField::getKeyID($field)) {
+ return CRM_Core_BAO_CustomField::displayValue($fieldValue, $cfID);
+ }
+
+ elseif (in_array($field, array(
+ 'email_greeting',
+ 'postal_greeting',
+ 'addressee',
+ ))) {
+ //special case for greeting replacement
+ $fldValue = "{$field}_display";
+ return $iterationDAO->$fldValue;
+ }
+ else {
+ //normal fields with a touch of CRM-3157
+ switch ($field) {
+ case 'country':
+ case 'world_region':
+ return $i18n->crm_translate($fieldValue, array('context' => 'country'));
+
+ case 'state_province':
+ return $i18n->crm_translate($fieldValue, array('context' => 'province'));
+
+ case 'gender':
+ case 'preferred_communication_method':
+ case 'preferred_mail_format':
+ case 'communication_style':
+ return $i18n->crm_translate($fieldValue);
+
+ default:
+ if (isset($metadata[$field])) {
+ // No I don't know why we do it this way & whether we could
+ // make better use of pseudoConstants.
+ if (!empty($metadata[$field]['context'])) {
+ return $i18n->crm_translate($fieldValue, $metadata[$field]);
+ }
+ if (!empty($metadata[$field]['pseudoconstant'])) {
+ // This is not our normal syntax for pseudoconstants but I am a bit loath to
+ // call an external function until sure it is not increasing php processing given this
+ // may be iterated 100,000 times & we already have the $imProvider var loaded.
+ // That can be next refactor...
+ // Yes - definitely feeling hatred for this bit of code - I know you will beat me up over it's awfulness
+ // but I have to reach a stable point....
+ $varName = $metadata[$field]['pseudoconstant']['var'];
+ if ($varName === 'imProviders') {
+ return CRM_Core_PseudoConstant::getLabel('CRM_Core_DAO_IM', 'provider_id', $fieldValue);
+ }
+ if ($varName === 'phoneTypes') {
+ return CRM_Core_PseudoConstant::getLabel('CRM_Core_DAO_Phone', 'phone_type_id', $fieldValue);
+ }
+ }
+
+ }
+ return $fieldValue;
+ }
+ }
+ }
+ elseif ($this->isExportSpecifiedPaymentFields() && array_key_exists($field, $this->getcomponentPaymentFields())) {
+ $paymentTableId = $this->getPaymentTableID();
+ $paymentData = CRM_Utils_Array::value($iterationDAO->$paymentTableId, $paymentDetails);
+ $payFieldMapper = array(
+ 'componentPaymentField_total_amount' => 'total_amount',
+ 'componentPaymentField_contribution_status' => 'contribution_status',
+ 'componentPaymentField_payment_instrument' => 'pay_instru',
+ 'componentPaymentField_transaction_id' => 'trxn_id',
+ 'componentPaymentField_received_date' => 'receive_date',
+ );
+ return CRM_Utils_Array::value($payFieldMapper[$field], $paymentData, '');
+ }
+ else {
+ // if field is empty or null
+ return '';
+ }
+ }
+
/**
* Get array of fields to return, over & above those defined in the main contact exportable fields.
*
* Array of fields to return in the format ['field_name' => 1,...]
*/
public function getAdditionalReturnProperties() {
-
- $missing = [
- 'location_type',
- 'im_provider',
- 'phone_type_id',
- 'provider_id',
- 'current_employer',
- ];
if ($this->getQueryMode() === CRM_Contact_BAO_Query::MODE_CONTACTS) {
$componentSpecificFields = [];
}
$componentSpecificFields = array_merge($componentSpecificFields, CRM_Contribute_BAO_Query::softCreditReturnProperties(TRUE));
unset($componentSpecificFields['contribution_status_id']);
}
- return array_merge(array_fill_keys($missing, 1), $componentSpecificFields);
+ return $componentSpecificFields;
}
/**
/**
* Get fields that indicate payment fields have been requested for a component.
*
+ * Ideally this should be protected but making it temporarily public helps refactoring..
+ *
* @return array
*/
- protected function getComponentPaymentFields() {
+ public function getComponentPaymentFields() {
return [
'componentPaymentField_total_amount' => ts('Total Amount'),
'componentPaymentField_contribution_status' => ts('Contribution Status'),
];
}
+ /**
+ * Get headers for payment fields.
+ *
+ * Returns an array of contribution fields when the entity supports payment fields and specific fields
+ * are not specified. This is a transitional function for refactoring legacy code.
+ */
+ public function getPaymentHeaders() {
+ if ($this->isExportPaymentFields() && !$this->isExportSpecifiedPaymentFields()) {
+ return $this->getcomponentPaymentFields();
+ }
+ return [];
+ }
+
/**
* Get the default properties when not specified.
*
$components = array('Contact', 'Contribute', 'Member', 'Event', 'Pledge', 'Case', 'Grant', 'Activity');
// FIXME: This should use a modified version of CRM_Contact_Form_Search::getModeValue but it doesn't have all the contexts
+ // FIXME: Or better still, use CRM_Core_DAO_AllCoreTables::getBriefName($daoName) to get the $entityShortName
switch ($this->getQueryMode()) {
case CRM_Contact_BAO_Query::MODE_CONTRIBUTE:
$entityShortname = 'Contribute';
$this->assign('membershipSummary', $membershipSummary);
$this->assign('totalCount', $totalCount);
- $this->assign('month', CRM_Utils_Date::customFormat($monthStartTs, '%B'));
+ $this->assign('month', CRM_Utils_Date::customFormatTs($monthStartTs, '%B'));
$this->assign('year', date('Y', $monthStartTs));
$this->assign('premonth', CRM_Utils_Date::customFormat($preMonth, '%B'));
$this->assign('currentMonth', date('F'));
case 'Radio':
//special case if user select -none-
if ($params["price_{$id}"] <= 0) {
- continue;
+ break;
}
$params["price_{$id}"] = array($params["price_{$id}"] => 1);
$optionValueId = CRM_Utils_Array::key(1, $params["price_{$id}"]);
*
* This function creates a table AND adds the details to the developer tab & $this->>temporary tables.
*
- * @todo improve presentation on the developer tab since CREATE TEMPORARY is removed.
- *
* @param string $identifier
* @param $sql
- * @param bool $isTrueTemporary
- * Is this a mysql temporary table or temporary in a less technical sense.
*
* @return string
*/
- public function createTemporaryTable($identifier, $sql, $isTrueTemporary = TRUE) {
+ public function createTemporaryTable($identifier, $sql) {
+ $tempTable = CRM_Utils_SQL_TempTable::build()->setUtf8(TRUE)->createWithQuery($sql);
+ $name = $tempTable->getName();
+ // Developers may force tables to be durable to assist in debugging so lets check.
+ $isNotTrueTemporary = $tempTable->isDurable();
+ // The TempTable build routine adds the next line - we output it to help developers see what has happened.
+ $sql = 'CREATE ' . ($isNotTrueTemporary ? '' : 'TEMPORARY ') . "TABLE $name DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci " . $sql;
$this->addToDeveloperTab($sql);
- $name = CRM_Utils_SQL_TempTable::build()->setUtf8(TRUE)->setDurable($isTrueTemporary)->createWithQuery($sql)->getName();
- $this->temporaryTables[$identifier] = ['temporary' => $isTrueTemporary, 'name' => $name];
+ $this->temporaryTables[$identifier] = ['temporary' => !$isNotTrueTemporary, 'name' => $name];
return $name;
}
WHERE smartgroup_contact.group_id IN ({$smartGroups}) ";
}
- $this->groupTempTable = CRM_Utils_SQL_TempTable::build()->setCategory('rptgrp')->setId(date('Ymd_') . uniqid())->getName();
- $this->executeReportQuery("
- CREATE TEMPORARY TABLE $this->groupTempTable $this->_databaseAttributes
- $query
- ");
+ $this->groupTempTable = $this->createTemporaryTable('rptgrp', $query);
CRM_Core_DAO::executeQuery("ALTER TABLE $this->groupTempTable ADD INDEX i_id(id)");
}
'title' => ts('Financial Account Owner - Debit'),
'operatorType' => CRM_Report_Form::OP_SELECT,
'type' => CRM_Utils_Type::T_INT,
- 'options' => array('' => '- Select Organization -') + CRM_Financial_BAO_FinancialAccount::getOrganizationNames(),
+ 'options' => array('' => '- Select Organization -') + CRM_Financial_BAO_FinancialAccount::getOrganizationNames(FALSE),
'name' => 'contact_id',
'alias' => 'financial_account_civireport_debit',
),
'title' => ts('Financial Account Owner - Credit'),
'operatorType' => CRM_Report_Form::OP_SELECT,
'type' => CRM_Utils_Type::T_INT,
- 'options' => array('' => '- Select Organization -') + CRM_Financial_BAO_FinancialAccount::getOrganizationNames(),
+ 'options' => array('' => '- Select Organization -') + CRM_Financial_BAO_FinancialAccount::getOrganizationNames(FALSE),
'name' => 'contact_id',
'alias' => 'financial_account_civireport_credit',
),
// @todo this acl has no test coverage and is very hard to test manually so could be fragile.
$this->resetFormSqlAndWhereHavingClauses();
- $this->contactTempTable = CRM_Utils_SQL_TempTable::build()->setCategory('rptlybunt')->setId(date('Ymd_') . uniqid())->getName();
+ $this->contactTempTable = $this->createTemporaryTable('rptlybunt', "
+ SELECT SQL_CALC_FOUND_ROWS {$this->_aliases['civicrm_contact']}.id as cid {$this->_from}
+ {$this->_where}
+ GROUP BY {$this->_aliases['civicrm_contact']}.id"
+ );
$this->limit();
- $getContacts = "
- CREATE TEMPORARY TABLE $this->contactTempTable {$this->_databaseAttributes}
- SELECT SQL_CALC_FOUND_ROWS {$this->_aliases['civicrm_contact']}.id as cid {$this->_from} {$this->_where}
- GROUP BY {$this->_aliases['civicrm_contact']}.id";
- $this->executeReportQuery($getContacts);
if (empty($this->_params['charts'])) {
$this->setPager();
}
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2018
- * $Id$
- *
*/
/**
- * This class is for UF Group
+ * This class is for UF Group (Profile) configuration.
*/
class CRM_UF_Form_Group extends CRM_Core_Form {
+ use CRM_Core_Form_EntityFormTrait;
+
+ /**
+ * Fields for the entity to be assigned to the template.
+ *
+ * Fields may have keys
+ * - name (required to show in tpl from the array)
+ * - description (optional, will appear below the field)
+ * - not-auto-addable - this class will not attempt to add the field using addField.
+ * (this will be automatically set if the field does not have html in it's metadata
+ * or is not a core field on the form's entity).
+ * - help (option) add help to the field - e.g ['id' => 'id-source', 'file' => 'CRM/Contact/Form/Contact']]
+ * - template - use a field specific template to render this field
+ * - required
+ * - is_freeze (field should be frozen).
+ *
+ * @var array
+ */
+ protected $entityFields = [];
+
+ /**
+ * Set entity fields to be assigned to the form.
+ */
+ protected function setEntityFields() {
+ $this->entityFields = [
+ 'title' => ['name' => 'title'],
+ 'frontend_title' => ['name' => 'frontend_title'],
+ 'description' => ['name' => 'description', 'help' => ['id' => 'id-description', 'file' => 'CRM/UF/Form/Group.hlp']],
+ 'uf_group_type' => ['name' => 'uf_group_type', 'not-auto-addable' => TRUE, 'help' => ['id' => 'id-used_for', 'file' => 'CRM/UF/Form/Group.hlp'], 'post_html_text' => ' ' . $this->getOtherModuleString()]
+ ];
+ }
+
+ /**
+ * Explicitly declare the entity api name.
+ */
+ public function getDefaultEntity() {
+ return 'UFGroup';
+ }
+
/**
* The form id saved to the session for an update.
*
/**
* Set variables up before form is built.
- *
- * @return void
*/
public function preProcess() {
// current form id
* @return void
*/
public function buildQuickForm() {
+ self::buildQuickEntityForm();
if ($this->_action & (CRM_Core_Action::DISABLE | CRM_Core_Action::DELETE)) {
if ($this->_action & (CRM_Core_Action::DISABLE)) {
$display = 'Disable Profile';
));
return;
}
- $this->applyFilter('__ALL__', 'trim');
-
- // title
- $this->add('text', 'title', ts('Profile Name'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_UFGroup', 'title'), TRUE);
- $this->add('text', 'frontend_title', ts('Public Title'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_UFGroup', 'frontend_title'));
- $this->add('textarea', 'description', ts('Description'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_UFGroup', 'description'));
//add checkboxes
$uf_group_type = array();
}
$defaults['uf_group_type'] = isset($checked) ? $checked : "";
- //get the uf join records for current uf group other than default modules
- $otherModules = array();
- $otherModules = CRM_Core_BAO_UFGroup::getUFJoinRecord($this->_id, TRUE, TRUE);
- if (!empty($otherModules)) {
- $otherModuleString = NULL;
- foreach ($otherModules as $key) {
- $otherModuleString .= " [ x ] <label>" . $key . "</label>";
- }
- $this->assign('otherModuleString', $otherModuleString);
- }
-
$showAdvanced = 0;
$advFields = array(
'group',
}
else {
// get the submitted form values.
- $params = $ids = array();
+ $ids = array();
$params = $this->controller->exportValues($this->_name);
if (!array_key_exists('is_active', $params)) {
CRM_Utils_System::updateCategories();
}
+ /**
+ * Set the delete message.
+ *
+ * We do this from the constructor in order to do a translation.
+ */
+ public function setDeleteMessage() {}
+
+ /**
+ * Get the string to display next to the used for field indicating unchangeable uses.
+ *
+ * @return string
+ */
+ protected function getOtherModuleString() {
+ $otherModules = CRM_Core_BAO_UFGroup::getUFJoinRecord($this->_id, TRUE, TRUE);
+ if (!empty($otherModules)) {
+ $otherModuleString = NULL;
+ foreach ($otherModules as $key) {
+ $otherModuleString .= " [ x ] <label>" . $key . "</label>";
+ }
+ }
+ return $otherModuleString;
+ }
+
}
--- /dev/null
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 5 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2017 |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM. |
+ | |
+ | CiviCRM is free software; you can copy, modify, and distribute it |
+ | under the terms of the GNU Affero General Public License |
+ | Version 3, 19 November 2007. |
+ | |
+ | CiviCRM is distributed in the hope that it will be useful, but |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
+ | See the GNU Affero General Public License for more details. |
+ | |
+ | You should have received a copy of the GNU Affero General Public |
+ | License along with this program; if not, contact CiviCRM LLC |
+ | at info[AT]civicrm[DOT]org. If you have questions about the |
+ | GNU Affero General Public License or the licensing of CiviCRM, |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * Upgrade logic for FiveNine */
+class CRM_Upgrade_Incremental_php_FiveNine extends CRM_Upgrade_Incremental_Base {
+
+ /**
+ * Compute any messages which should be displayed beforeupgrade.
+ *
+ * Note: This function is called iteratively for each upcoming
+ * revision to the database.
+ *
+ * @param string $preUpgradeMessage
+ * @param string $rev
+ * a version number, e.g. '4.4.alpha1', '4.4.beta3', '4.4.0'.
+ * @param null $currentVer
+ */
+ public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) {
+ // Example: Generate a pre-upgrade message.
+ // if ($rev == '5.12.34') {
+ // $preUpgradeMessage .= '<p>' . ts('A new permission, "%1", has been added. This permission is now used to control access to the Manage Tags screen.', array(1 => ts('manage tags'))) . '</p>';
+ // }
+ }
+
+ /**
+ * Compute any messages which should be displayed after upgrade.
+ *
+ * @param string $postUpgradeMessage
+ * alterable.
+ * @param string $rev
+ * an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs.
+ */
+ public function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
+ if ($rev == '5.9.0') {
+ $args = array(
+ 1 => ts('Enable multiple bulk email address for a contact'),
+ 2 => ts('Email on Hold'),
+ );
+ $postUpgradeMessage .= '<p>' . ts('If the setting "%1" is enabled, you should update any smart groups based on the "%2" field.', $args) . '</p>';
+ }
+
+ // Example: Generate a post-upgrade message.
+ // if ($rev == '5.12.34') {
+ // $postUpgradeMessage .= '<br /><br />' . ts("By default, CiviCRM now disables the ability to import directly from SQL. To use this feature, you must explicitly grant permission 'import SQL datasource'.");
+ // }
+ }
+
+ /*
+ * Important! All upgrade functions MUST add a 'runSql' task.
+ * Uncomment and use the following template for a new upgrade version
+ * (change the x in the function name):
+ */
+
+ // /**
+ // * Upgrade function.
+ // *
+ // * @param string $rev
+ // */
+ // public function upgrade_5_0_x($rev) {
+ // $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
+ // $this->addTask('Do the foo change', 'taskFoo', ...);
+ // // Additional tasks here...
+ // // Note: do not use ts() in the addTask description because it adds unnecessary strings to transifex.
+ // // The above is an exception because 'Upgrade DB to %1: SQL' is generic & reusable.
+ // }
+
+ // public static function taskFoo(CRM_Queue_TaskContext $ctx, ...) {
+ // return TRUE;
+ // }
+
+}
--- /dev/null
+{* file to handle db changes in 5.7.0 during upgrade *}
--- /dev/null
+{* file to handle db changes in 5.9.0 during upgrade *}
--- /dev/null
+{* file to handle db changes in 5.9.alpha1 during upgrade *}
if ($skipFields === NULL) {
return FALSE;
}
+ // Strip extra numbers from custom fields e.g. custom_32_1 should be custom_32
+ if (strpos($fldName, 'custom_') === 0) {
+ list($fldName, $customId) = explode('_', $fldName);
+ $fldName .= '_' . $customId;
+ }
// Field should be skipped
if (in_array($fldName, $skipFields)) {
ts('Your extensions directory (%1) is read-only. If you would like to perform downloads or upgrades, then change the file permissions.',
array(1 => $basedir)),
ts('Read-Only Extensions'),
- \Psr\Log\LogLevel::WARNING,
+ \Psr\Log\LogLevel::NOTICE,
'fa-plug'
);
}
}
}
+ /**
+ * Wrapper for customFormat that takes a timestamp
+ *
+ * @param int $timestamp
+ * Date and time in timestamp format.
+ * @param string $format
+ * The output format.
+ * @param array $dateParts
+ * An array with the desired date parts.
+ *
+ * @return string
+ * the $format-formatted $date
+ */
+ public static function customFormatTs($timestamp, $format = NULL, $dateParts = NULL) {
+ return CRM_Utils_Date::customFormat(date("Y-m-d H:i:s", $timestamp), $format, $dateParts);
+ }
+
/**
* Converts the date/datetime from MySQL format to ISO format
*
/**
* @param string|NULL $category
+ *
* @return CRM_Utils_SQL_TempTable
*/
public function setCategory($category) {
}
/**
- * @parma bool $value
+ * Set whether the table should be durable.
+ *
+ * Durable tables are not TEMPORARY in the mysql sense.
+ *
+ * @param bool $durable
+ *
* @return CRM_Utils_SQL_TempTable
*/
public function setDurable($durable = TRUE) {
}
/**
+ * Setter for id
+ *
* @param mixed $id
+ *
* @return CRM_Utils_SQL_TempTable
*/
public function setId($id) {
return $this;
}
+ /**
+ * Set table collation to UTF8.
+ *
+ * This would make sense as a default but cautiousness during phasing in has made it opt-in.
+ *
+ * @param bool $value
+ *
+ * @return $this
+ */
public function setUtf8($value = TRUE) {
$this->utf8 = $value;
return $this;
[]
));
+ $container->setDefinition('prevnext.driver.redis', new Definition(
+ 'CRM_Core_PrevNextCache_Redis',
+ [new Reference('cache_config')]
+ ));
+
+ $container->setDefinition('cache_config', new Definition('ArrayObject'))
+ ->setFactory(array(new Reference(self::SELF), 'createCacheConfig'));
+
$container->setDefinition('civi.mailing.triggers', new Definition(
'Civi\Core\SqlTrigger\TimestampTriggers',
array('civicrm_mailing', 'Mailing')
* @return \CRM_Core_PrevNextCache_Interface
*/
public static function createPrevNextCache($container) {
- $cacheDriver = \CRM_Utils_Cache::getCacheDriver();
- $service = 'prevnext.driver.' . strtolower($cacheDriver);
- return $container->has($service)
- ? $container->get($service)
- : $container->get('prevnext.driver.sql');
+ $setting = \Civi::settings()->get('prevNextBackend');
+ if ($setting === 'default') {
+ // For initial release (5.8.x), continue defaulting to SQL.
+ $isTransitional = version_compare(\CRM_Utils_System::version(), '5.9.alpha1', '<');
+ $cacheDriver = \CRM_Utils_Cache::getCacheDriver();
+ $service = 'prevnext.driver.' . strtolower($cacheDriver);
+ return $container->has($service) && !$isTransitional
+ ? $container->get($service)
+ : $container->get('prevnext.driver.sql');
+ }
+ else {
+ return $container->get('prevnext.driver.' . $setting);
+ }
+ }
+
+ public static function createCacheConfig() {
+ $driver = \CRM_Utils_Cache::getCacheDriver();
+ $settings = \CRM_Utils_Cache::getCacheSettings($driver);
+ $settings['driver'] = $driver;
+ return new \ArrayObject($settings);
}
/**
'ext' => 'civicrm',
'js' => array('ang/crmUi.js'),
'partials' => array('ang/crmUi'),
- 'requires' => array('crmResource'),
+ 'requires' => array(
+ 'crmResource',
+ 'ui.utils',
+ ),
);
link: function (scope, element, attrs) {
scope.ts = CRM.ts(null);
- element.find('.crm-wizard-buttons button').click(function () {
+ element.find('.crm-wizard-buttons button[ng-click^=crmUiWizardCtrl]').click(function () {
// These values are captured inside the click handler to ensure the
// positions/sizes of the elements are captured at the time of the
// click vs. at the time this directive is initialized.
}
$activities = _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params, FALSE, 'Activity', $sql);
+ if ($options['is_count']) {
+ return civicrm_api3_create_success($activities, $params, 'Activity', 'get');
+ }
+
if (!empty($params['check_permissions']) && !CRM_Core_Permission::check('view all activities')) {
// @todo get this to work at the query level - see contact_id join above.
foreach ($activities as $activity) {
}
}
}
- if ($options['is_count']) {
- return civicrm_api3_create_success($activities, $params, 'Activity', 'get');
- }
$activities = _civicrm_api3_activity_get_formatResult($params, $activities, $options);
//legacy custom data get - so previous formatted response is still returned too
$paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getPayment($params['payment_processor'], $params['payment_processor_mode']);
$paymentProcessor['object']->doPayment($params);
- $params['payment_instrument_id'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_PaymentProcessorType', $paymentProcessor['payment_processor_type_id'], 'payment_type') == 1 ? 'Credit Card' : 'Debit Card';
+ $params['payment_instrument_id'] = $paymentProcessor['object']->getPaymentInstrumentID();
+
return civicrm_api('Contribution', 'create', $params);
}
}
}
+ // Add custom greeting fields
+ $greetingFields = ['email_greeting', 'postal_greeting', 'addressee'];
+ foreach ($greetingFields as $greetingField) {
+ if (isset($profileFields[$greetingField]) && !isset($profileFields["{$greetingField}_custom"])) {
+ $profileFields["{$greetingField}_custom"] = ['name' => "{$greetingField}_custom"];
+ }
+ }
+
foreach ($profileFields as $fieldName => $field) {
if (!isset($params[$fieldName])) {
continue;
'title' => ts('Enable multiple bulk email address for a contact.'),
'is_domain' => 1,
'is_contact' => 0,
- 'description' => ts('CiviMail will deliver a copy of the email to each bulk email listed for the contact.'),
+ 'description' => ts('CiviMail will deliver a copy of the email to each bulk email listed for the contact. Enabling this setting will also change the options for the "Email on Hold" field in Advanced Search.'),
'help_text' => NULL,
),
'include_message_id' => array(
'description' => 'If set, this will be the default profile used for contact search.',
'help_text' => NULL,
),
+ 'prevNextBackend' => array(
+ 'group_name' => 'Search Preferences',
+ 'group' => 'Search Preferences',
+ 'name' => 'prevNextBackend',
+ 'type' => 'String',
+ 'quick_form_type' => 'Select',
+ 'html_type' => 'Select',
+ 'html_attributes' => array(
+ //'class' => 'crm-select2',
+ ),
+ 'default' => 'default',
+ 'add' => '5.9',
+ 'title' => 'PrevNext Cache',
+ 'is_domain' => 1,
+ 'is_contact' => 0,
+ 'pseudoconstant' => array(
+ 'callback' => 'CRM_Core_BAO_PrevNextCache::getPrevNextBackends',
+ ),
+ 'description' => 'When performing a search, how should the search-results be cached?',
+ 'help_text' => '',
+ ),
'searchPrimaryDetailsOnly' => array(
'group_name' => 'Search Preferences',
'group' => 'Search Preferences',
LOCK TABLES `civicrm_domain` WRITE;
/*!40000 ALTER TABLE `civicrm_domain` DISABLE KEYS */;
-INSERT INTO `civicrm_domain` (`id`, `name`, `description`, `config_backend`, `version`, `contact_id`, `locales`, `locale_custom_strings`) VALUES (1,'Default Domain Name',NULL,NULL,'5.8.beta1',1,NULL,'a:1:{s:5:\"en_US\";a:0:{}}');
+INSERT INTO `civicrm_domain` (`id`, `name`, `description`, `config_backend`, `version`, `contact_id`, `locales`, `locale_custom_strings`) VALUES (1,'Default Domain Name',NULL,NULL,'5.9.alpha1',1,NULL,'a:1:{s:5:\"en_US\";a:0:{}}');
/*!40000 ALTER TABLE `civicrm_domain` ENABLE KEYS */;
UNLOCK TABLES;
{if $action eq 8}
<div class="messages status no-popup">
<div class="icon inform-icon"></div>
- {ts}Do you want to delete this message template?{/ts}
+ {ts 1=$msg_title|escape}Do you want to delete the message template '%1'?{/ts}
</div>
{else}
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
var params = {
title: data.count == 1 ? {/literal}"{ts escape='js'}Similar Contact Found{/ts}" : "{ts escape='js'}Similar Contacts Found{/ts}"{literal},
info: "{/literal}{ts escape='js'}If the contact you were trying to add is listed below, click their name to view or edit their record{/ts}{literal}:",
- contacts: data.values
+ contacts: data.values,
+ cid: cid
};
if (data.count) {
openDupeAlert(params);
info: data.count ?
"{/literal}{ts escape='js'}If the contact you were trying to add is listed below, click their name to view or edit their record{/ts}{literal}:" :
"{/literal}{ts escape='js'}No matches found using the default Supervised deduping rule.{/ts}{literal}",
- contacts: data.values
+ contacts: data.values,
+ cid: cid
};
updateDupeAlert(params, data.count ? 'alert' : 'success');
});
<%- contact.display_name %>
</a>
<%- contact.email %>
+ <% if (cid) { %>
+ <% var params = {reset: 1, action: 'update', oid: contact.id > cid ? contact.id : cid, cid: contact.id > cid ? cid : contact.id }; %>
+ (<a href="<%= CRM.url('civicrm/contact/merge', params) %>">{/literal}{ts}Merge{/ts}{literal}</a>)
+ <% } %>
</li>
<% }); %>
</ul>
{$form.preferred_communication_method.html}
<br/>
-{if $form.email_on_hold}
+{if $form.email_on_hold.type == 'select'}
+ <br/>
+ {$form.email_on_hold.label}
+ <br/>
+ {$form.email_on_hold.html}
+ <br/>
+{elseif $form.email_on_hold.type == 'checkbox'}
<div class="spacer"></div>
{$form.email_on_hold.html}
{$form.email_on_hold.label}
<div class="crm-content crm-custom-data crm-contact-reference">
<a href="{crmURL p='civicrm/contact/view' q="reset=1&cid=`$element.contact_ref_id`"}" title="view contact">{$element.field_value}</a>
</div>
- {elseif $element.field_data_type EQ 'Memo'}
- <div class="crm-content crm-custom-data">{$element.field_value|nl2br}</div>
{elseif $element.field_data_type EQ 'Money'}
<div class="crm-content crm-custom-data">{$element.field_value|crmMoney}</div>
{else}
</div>
{/if}
- {if $onbehalfProfile|@count}
+ {if $onbehalfProfile && $onbehalfProfile|@count}
<div class="crm-group onBehalf_display-group label-left crm-profile-view">
{include file="CRM/UF/Form/Block.tpl" fields=$onbehalfProfile prefix='onbehalf'}
</div>
{/if}
- {if $honoreeProfileFields|@count}
+ {if $honoreeProfileFields && $honoreeProfileFields|@count}
<div class="crm-group honor_block-group">
<div class="header-dark">
{$soft_credit_type}
{include file="CRM/Contribute/Form/Contribution/PremiumBlock.tpl" context="makeContribution"}
</div>
- {if $honoreeProfileFields|@count}
+ {if $honoreeProfileFields && $honoreeProfileFields|@count}
<fieldset class="crm-public-form-item crm-group honor_block-group">
{crmRegion name="contribution-soft-credit-block"}
<legend>{$honor_block_title}</legend>
<div class="crm-public-form-item" id="on-behalf-block">
{crmRegion name="onbehalf-block"}
- {if $onBehalfOfFields|@count}
+ {if $onBehalfOfFields && $onBehalfOfFields|@count}
<fieldset>
<legend>{$fieldSetTitle}</legend>
{if $form.org_option}
</div>
{/if}
{elseif $isPendingOutcome}
- <div>{ts 1=$paymentProcessor.name}Your contribution has been submitted to %1 for processing. Please print this page for your records.{/ts}</div>
+ <div>{ts 1=$paymentProcessor.name}Your contribution has been submitted to %1 for processing.{/ts}</div>
{if $is_email_receipt}
<div>
{if $onBehalfEmail AND ($onBehalfEmail neq $email)}
</div>
{/if}
{else}
- <div>{ts}Your transaction has been processed successfully. Please print this page for your records.{/ts}</div>
+ <div>{ts}Your transaction has been processed successfully.{/ts}</div>
{if $is_email_receipt}
<div>
{if $onBehalfEmail AND ($onBehalfEmail neq $email)}
</div>
{/if}
- {if $onbehalfProfile|@count}
+ {if $onbehalfProfile && $onbehalfProfile|@count}
<div class="crm-group onBehalf_display-group label-left crm-profile-view">
{include file="CRM/UF/Form/Block.tpl" fields=$onbehalfProfile prefix='onbehalf'}
</div>
{/if}
- {if $honoreeProfileFields|@count}
+ {if $honoreeProfileFields && $honoreeProfileFields|@count}
<div class="crm-group honor_block-group">
<div class="header-dark">
{$soft_credit_type}
{/if}
</table>
-{if count($softContributions)} {* We show soft credit name with PCP section if contribution is linked to a PCP. *}
+{if $softContributions && count($softContributions)} {* We show soft credit name with PCP section if contribution is linked to a PCP. *}
<div class="crm-accordion-wrapper crm-soft-credit-pane">
<div class="crm-accordion-header">
{ts}Soft Credit{/ts}
{include file="CRM/Contribute/Form/PCP.js.tpl"}
</td>
<td>
- {$form.contribution_cancel_reason.label}<br />
- {$form.contribution_cancel_reason.html}
+ {$form.cancel_reason.label}<br />
+ {$form.cancel_reason.html}
</td>
</tr>
<tr>
{/capture}{help id=$help.id file=$help.file}{/if}
{if $action == 2 && $fieldSpec.is_add_translate_dialog}{include file='CRM/Core/I18n/Dialog.tpl' table=$entityTable field=$fieldName id=$entityID}{/if}
</td>
- <td>{if $form.$fieldName.html}{if $fieldSpec.formatter === 'crmMoney'}{$form.$fieldName.html|crmMoney}{else}{$form.$fieldName.html}{/if}{else}{$fieldSpec.place_holder}{/if}<br />
+ <td>{$fieldSpec.pre_html_text}{if $form.$fieldName.html}{if $fieldSpec.formatter === 'crmMoney'}{$form.$fieldName.html|crmMoney}{else}{$form.$fieldName.html}{/if}{else}{$fieldSpec.place_holder}{/if}{$fieldSpec.post_html_text}<br />
{if $fieldSpec.description}<span class="description">{$fieldSpec.description}</span>{/if}
{if $fieldSpec.documentation_link}{docURL page=$fieldSpec.documentation_link.page resource=$fieldSpec.documentation_link.resource}{/if}
</td>
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*}
-{if $config->languageLimit|@count >= 2 and $translatePermission }
+{if $config->languageLimit && $config->languageLimit|@count >= 2 and $translatePermission }
<a href="{crmURL p='civicrm/i18n' q="reset=1&table=$table&field=$field&id=$id"}" data-field="{$field}" class="crm-hover-button crm-multilingual-edit-button" title="{ts}Languages{/ts}">
<i class="crm-i fa-language fa-lg"></i>
</a>
<p>{if $params.waitlist}
{ts}You may allow users to join a waitlist when the event is full (by checking the box below).{/ts}
{else}
- {ts}You may allow users to join a waitlist when the event is full. To enable this feature you must first enable the Participant Statuses used by the waitlist work-flow (click the pencil icon, or navigate to Administer » CiviEvent » Participant Statuses). Then reload this form and check 'Offer a Waitlist?'.{/ts}
+ {ts}You may allow users to join a waitlist when the event is full. To enable this feature you must first enable the Participant Statuses used by the waitlist work-flow (click the wrench icon, or navigate to Administer » CiviEvent » Participant Statuses). Then reload this form and check 'Offer a Waitlist?'.{/ts}
{/if}</p>
<p>{ts}Otherwise, the registration link is hidden and the "Event Full Message"' is displayed when the maximum number of registrations is reached. Only participants with status types marked as 'counted' are included when checking if the event is full.{/ts}</p>
{/htxt}
{ts}Multiple Participants{/ts}
{/htxt}
{htxt id="id-allow_multiple"}
-<p>{ts}Check this box to allow users to register themselves AND additional participants for an event. When this feature is enabled, users have the option to specify the number of additional participants they are registering for. If this is a paid event, they can select a different event fees for each participant - and will be charged the total of those fees. If a profile is included - they will complete the profile information for each participant.{/ts}</p>
+<p>{ts}Check this box to allow users to register themselves AND additional participants for an event. When this feature is enabled, users have the option to specify the number of additional participants they are registering for. If this is a paid event, they can select a different event fee for each participant and will be charged the total of those fees. If a profile is included, they will complete the profile information for each participant.{/ts}</p>
<p>{ts}You can use different profile for the person who is registering than for "Additional Participants". For example, you may want to require an email address from the person entering the registration while not requiring (or even requesting) emails for additional participants (i.e. their "guests").{/ts}</p>
{/htxt}
{htxt id="id-max_additional-title"}
{/if}
{* PayPal_Standard sets contribution_mode to 'notify'. We don't know if transaction is successful until we receive the IPN (payment notification) *}
{elseif $contributeMode EQ 'notify' and $paidEvent}
- <p>{ts 1=$paymentProcessor.name}Your registration payment has been submitted to %1 for processing. Please print this page for your records.{/ts}</p>
+ <p>{ts 1=$paymentProcessor.name}Your registration payment has been submitted to %1 for processing.{/ts}</p>
{if $is_email_confirm}
<p>{ts 1=$email}A registration confirmation email will be sent to %1 once the transaction is processed successfully.{/ts}</p>
{/if}
{else}
- <p>{ts}Your registration has been processed successfully. Please print this page for your records.{/ts}</p>
+ <p>{ts}Your registration has been processed successfully.{/ts}</p>
{if $is_email_confirm}
<p>{ts 1=$email}A registration confirmation email has also been sent to %1{/ts}</p>
{/if}
</tr>
{counter start=0 skip=1 print=false}
{foreach from=$event_rows item=row}
- <tr id='rowid{$row.participant_id}' class=" crm-event-participant-id_{$row.participant_id} {cycle values="odd-row,even-row"}{if $row.status eq Cancelled} disabled{/if}">
+ <tr id='rowid{$row.participant_id}' class=" crm-event-participant-id_{$row.participant_id} {cycle values="odd-row,even-row"}{if $row.status eq 'Cancelled'} disabled{/if}">
<td class="crm-participant-event-id_{$row.event_id}"><a href="{crmURL p='civicrm/event/info' q="reset=1&id=`$row.event_id`&context=dashboard"}">{$row.event_title}</a></td>
<td class="crm-participant-event_start_date">
{$row.event_start_date|crmDate}
{/if}
</div>
{crmRegion name="crm-event-userdashboard-post"}
-{/crmRegion}
\ No newline at end of file
+{/crmRegion}
<tr class="columnheader-dark">
<th scope="col" rowspan="2">{ts}Members by Type{/ts}</th>
{if $preMonth}
- <th scope="col" colspan="3">{$premonth} – {ts}(Last Month){/ts}</th>
+ <th scope="col" colspan="3">{$premonth} {ts}(Last Month){/ts}</th>
{/if}
<th scope="col" colspan="3">{$month}{if $isCurrent}{ts} (MTD){/ts}{/if}</th>
<th scope="col" colspan="3">
</div>
{else}
<table class="form-layout">
- <tr class="crm-uf_group-form-block-title">
- <td class="label">{$form.title.label} {if $action == 2}{include file='CRM/Core/I18n/Dialog.tpl' table='civicrm_uf_group' field='title' id=$gid}{/if}</td>
- <td class="html-adjust">{$form.title.html}</td>
- </tr>
- <tr class="crm-uf_group-form-block-frontend_title">
- <td class="label">{$form.frontend_title.label}</td>
- <td class="html-adjust">{$form.frontend_title.html}</td>
- </tr>
- <tr class="crm-uf_group-form-block-description">
- <td class="label">{$form.description.label} {help id='id-description' file="CRM/UF/Form/Group.hlp"}</td>
- <td class="html-adjust">{$form.description.html}</td>
- </tr>
- <tr class="crm-uf_group-form-block-uf_group_type">
- <td class="label">{$form.uf_group_type.label} {help id='id-used_for' file="CRM/UF/Form/Group.hlp"}</td>
- <td class="html-adjust">{$form.uf_group_type.html} {$otherModuleString}</td>
+ {foreach from=$entityFields item=fieldSpec}
+ {assign var=fieldName value=$fieldSpec.name}
+ <tr class="crm-{$entityInClassFormat}-form-block-{$fieldName}">
+ {include file="CRM/Core/Form/Field.tpl"}
</tr>
+ {/foreach}
<tr class="crm-uf_group-form-block-weight" >
<td class="label">{$form.weight.label}{if $config->userSystem->is_drupal EQ '1'} {help id='id-profile_weight' file="CRM/UF/Form/Group.hlp"}{/if}</td>
<td class="html-adjust">{$form.weight.html}</td>
$this->contributionCreate([
'contact_id' => $contactId,
'total_amount' => 1,
- 'payment_instrument_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Check'),
- 'financial_type_id' => 1,
- 'contribution_status_id' => 1,
+ 'payment_instrument_id' => 'Check',
+ 'financial_type_id' => 'Donation',
+ 'contribution_status_id' => 'Completed',
'receive_date' => '20080522000000',
'receipt_date' => '20080522000000',
'trxn_id' => '22ereerwww322323',
$this->contributionCreate([
'contact_id' => $contactId,
'total_amount' => 1,
- 'payment_instrument_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Credit Card'),
- 'financial_type_id' => 1,
- 'contribution_status_id' => 1,
+ 'payment_instrument_id' => 'Credit Card',
+ 'financial_type_id' => 'Member Dues',
+ 'contribution_status_id' => 'Completed',
'receive_date' => '20080523000000',
'receipt_date' => '20080523000000',
'trxn_id' => '22ereerwww323323',
$result = CRM_Batch_BAO_Batch::getBatchFinancialItems($entityId, $returnvalues, $notPresent, $params, TRUE)->fetchAll();
$this->assertEquals(count($result), 1, 'In line' . __LINE__);
$this->assertEquals($result[0]['payment_method'], CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Check'), 'In line' . __LINE__);
-
+ $params['financial_type_id'] = implode(',', [
+ CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'financial_type_id', 'Donation'),
+ CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'financial_type_id', 'Member Dues'),
+ ]);
+ $result = CRM_Batch_BAO_Batch::getBatchFinancialItems($entityId, $returnvalues, $notPresent, $params, TRUE)->fetchAll();
+ $this->assertEquals(count($result), 1, 'In line' . __LINE__);
}
}
$this->assertContains('INNER JOIN civicrm_rel_temp_', $sql, "Query appears to use temporary table of compiled relationships?", TRUE);
}
+ public function testRelationshipPermissionClause() {
+ $params = [['relation_type_id', 'IN', ['1_b_a'], 0, 0], ['relation_permission', 'IN', [2], 0, 0]];
+ $sql = CRM_Contact_BAO_Query::getQuery($params);
+ $this->assertContains('(civicrm_relationship.is_permission_a_b IN (2))', $sql);
+ }
+
/**
* Test Relationship Clause
*/
--- /dev/null
+<?php
+
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 5 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2018 |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM. |
+ | |
+ | CiviCRM is free software; you can copy, modify, and distribute it |
+ | under the terms of the GNU Affero General Public License |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
+ | |
+ | CiviCRM is distributed in the hope that it will be useful, but |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
+ | See the GNU Affero General Public License for more details. |
+ | |
+ | You should have received a copy of the GNU Affero General Public |
+ | License and the CiviCRM Licensing Exception along |
+ | with this program; if not, contact CiviCRM LLC |
+ | at info[AT]civicrm[DOT]org. If you have questions about the |
+ | GNU Affero General Public License or the licensing of CiviCRM, |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * Test class for CRM_Contact_Form_Search_Criteria
+ *
+ * @package CiviCRM
+ * @group headless
+ */
+class CRM_Contact_Form_Search_CriteriaTest extends CiviUnitTestCase {
+
+ /**
+ * Test that the 'multiple bulk email' setting correctly affects the type of
+ * field used for the 'email on hold' criteria in Advanced Search.
+ */
+ public function testAdvancedHSearchObservesMultipleBulkEmailSetting() {
+
+ // If setting is enabled, criteria should be a select element.
+ Civi::settings()->set('civimail_multiple_bulk_emails', 1);
+ $form = new CRM_Contact_Form_Search_Advanced();
+ $form->controller = new CRM_Contact_Controller_Search();
+ $form->preProcess();
+ $form->buildQuickForm();
+ $onHoldElemenClass = (get_class($form->_elements[$form->_elementIndex['email_on_hold']]));
+ $this->assertEquals('HTML_QuickForm_select', $onHoldElemenClass, 'civimail_multiple_bulk_emails setting = 1, so email_on_hold should be a select element.');
+
+ // If setting is disabled, criteria should be a checkbox.
+ Civi::settings()->set('civimail_multiple_bulk_emails', 0);
+ $form = new CRM_Contact_Form_Search_Advanced();
+ $form->controller = new CRM_Contact_Controller_Search();
+ $form->preProcess();
+ $form->buildQuickForm();
+ $onHoldElemenClass = (get_class($form->_elements[$form->_elementIndex['email_on_hold']]));
+ $this->assertEquals('HTML_QuickForm_advcheckbox', $onHoldElemenClass, 'civimail_multiple_bulk_emails setting = 0, so email_on_hold should be a checkbox.');
+ }
+
+}
* @package CiviCRM
* @group headless
*/
-class CRM_Contact_Imports_Parser_ContactTest extends CiviUnitTestCase {
- protected $_tablesToTruncate = array();
+class CRM_Contact_Import_Parser_ContactTest extends CiviUnitTestCase {
+ protected $_tablesToTruncate = ['civicrm_address', 'civicrm_phone'];
/**
* Setup function.
$this->assertEquals(1, $address['location_type_id']);
$this->assertEquals(1, $address['is_primary']);
+ $this->markTestIncomplete('phone actually doesn\'t work');
$phone = $this->callAPISuccessGetSingle('Phone', array('phone' => '12334'));
$this->assertEquals(1, $phone['location_type_id']);
$this->assertEquals(1, $address['values'][1]['is_primary']);
$this->assertEquals('Big Mansion', $address['values'][1]['street_address']);
+ $this->markTestIncomplete('phone import primary actually IS broken');
$phone = $this->callAPISuccess('Phone', 'get', array('contact_id' => $contact['id'], 'sequential' => 1));
$this->assertEquals(1, $phone['values'][0]['location_type_id']);
$this->assertEquals(1, $phone['values'][0]['is_primary']);
$fields[] = 'phone';
$this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, array(0 => NULL, 1 => NULL, 2 => NULL, 3 => NULL, 4 => NULL, 5 => 3, 6 => 3, 7 => 'Primary', 8 => 'Primary'), $fields);
$contact = $this->callAPISuccessGetSingle('Contact', array('external_identifier' => 'android'));
- $address = $this->callAPISuccess('Address', 'get', array('contact_id' => $contact['id'], 'sequential' => 1));
+ $address = $this->callAPISuccess('Address', 'get', array('contact_id' => $contact['id'], 'sequential' => 1))['values'];
- $this->assertEquals(1, $address['values'][0]['location_type_id']);
- $this->assertEquals(1, $address['values'][0]['is_primary']);
- $this->assertEquals('Teeny Mansion', $address['values'][0]['street_address']);
+ $this->assertEquals(1, $address[1]['location_type_id']);
+ $this->assertEquals(1, $address[1]['is_primary']);
+ $this->assertEquals('Teeny Mansion', $address[1]['street_address']);
- $this->assertEquals(3, $address['values'][1]['location_type_id']);
- $this->assertEquals(0, $address['values'][1]['is_primary']);
- $this->assertEquals('Big Mansion', $address['values'][1]['street_address']);
+ $this->assertEquals(3, $address[0]['location_type_id']);
+ $this->assertEquals(0, $address[0]['is_primary']);
+ $this->assertEquals('Big Mansion', $address[0]['street_address']);
- $phone = $this->callAPISuccess('Phone', 'get', array('contact_id' => $contact['id'], 'sequential' => 1));
- $this->assertEquals(3, $phone['values'][0]['location_type_id']);
- $this->assertEquals(0, $phone['values'][0]['is_primary']);
- $this->assertEquals(12334, $phone['values'][0]['phone']);
- $this->assertEquals(1, $phone['values'][1]['location_type_id']);
- $this->assertEquals(1, $phone['values'][1]['is_primary']);
- $this->assertEquals(4444, $phone['values'][1]['phone']);
+ $this->markTestIncomplete('phone import primary actually IS broken');
+ $phone = $this->callAPISuccess('Phone', 'get', array('contact_id' => $contact['id'], 'sequential' => 1))['values'];
+ $this->assertEquals(3, $phone[1]['location_type_id']);
+ $this->assertEquals(0, $phone[1]['is_primary']);
+ $this->assertEquals(12334, $phone[1]['phone']);
+ $this->assertEquals(1, $phone[0]['location_type_id']);
+ $this->assertEquals(1, $phone[0]['is_primary']);
+ $this->assertEquals(4444, $phone[0]['phone']);
$this->callAPISuccess('Contact', 'delete', array('id' => $contact['id']));
}
* @param int $onDuplicateAction
* @param int $expectedResult
* @param array|null $mapperLocType
+ * Array of location types that map to the input arrays.
* @param array|null $fields
* Array of field names. Will be calculated from $originalValues if not passed in, but
* that method does not cope with duplicates.
*/
- protected function runImport($originalValues, $onDuplicateAction, $expectedResult, $mapperLocType = NULL, $fields = NULL) {
+ protected function runImport($originalValues, $onDuplicateAction, $expectedResult, $mapperLocType = [], $fields = NULL) {
if (!$fields) {
$fields = array_keys($originalValues);
}
*/
protected $contactID;
+ /**
+ * Contributions created for the test.
+ *
+ * @var array
+ */
+ protected $contributions = [];
+
/**
* Prepare for test
*/
$this->quickCleanUpFinancialEntities();
$this->quickCleanup(['civicrm_uf_match']);
CRM_Utils_Hook::singleton()->reset();
+ CRM_Core_Session::singleton()->reset();
+ CRM_Core_Smarty::singleton()->clearTemplateVars();
+ $this->callAPISuccess('Contact', 'delete', ['id' => $this->contactID]);
}
/**
/**
* Test the content of the dashboard.
*/
- public function testDashboardContentContributions() {
- $this->contributionCreate(['contact_id' => $this->contactID]);
+ public function testDashboardContentContributionsWithInvoicingEnabled() {
+ $this->contributions[] = $this->contributionCreate([
+ 'contact_id' => $this->contactID,
+ 'receive_date' => '2018-11-21',
+ 'receipt_date' => '2018-11-22',
+ ]);
+ $this->contributions[] = $this->contributionCreate([
+ 'contact_id' => $this->contactID,
+ 'receive_date' => '2018-11-21',
+ 'receipt_date' => '2018-11-22',
+ 'trxn_id' => '',
+ 'invoice_id' => '',
+ ]);
+ $recur = $this->callAPISuccess('ContributionRecur', 'create', [
+ 'contact_id' => $this->contactID,
+ 'frequency_interval' => 1,
+ 'amount' => 5,
+ ]);
+ $this->contributions[] = $this->contributionCreate([
+ 'contact_id' => $this->contactID,
+ 'receive_date' => '2018-11-21',
+ 'amount_level' => 'high',
+ 'contribution_status_id' => 'Cancelled',
+ 'invoice_id' => NULL,
+ 'trxn_id' => NULL,
+ 'contribution_recur_id' => $recur['id'],
+ ]);
+ $this->callAPISuccess('Setting', 'create', ['invoicing' => 1]);
$this->runUserDashboard();
$expectedStrings = [
'Your Contribution(s)',
- '<table class="selector"><tr class="columnheader"><th>Total Amount</th><th>Financial Type</th><th>Received date</th><th>Receipt Sent</th><th>Status</th>',
- '</tr><tr id=\'rowid1\'class="odd-row"><td>$ 100.00 </td><td>Donation</td>',
- '</td><td></td><td>Completed</td></tr></table>',
+ '<table class="selector"><tr class="columnheader"><th>Total Amount</th><th>Financial Type</th><th>Received date</th><th>Receipt Sent</th><th>Status</th><th></th>',
+ '<td>Completed</td><td><a class="button no-popup nowrap"href="/index.php?q=civicrm/contribute/invoice&reset=1&id=1&cid=' . $this->contactID . '"><i class="crm-i fa-print"></i><span>Print Invoice</span></a></td></tr><tr id=\'rowid2\'',
];
+
$this->assertPageContains($expectedStrings);
- $this->assertSmartyVariables(['invoicing' => NULL]);
+ $this->assertSmartyVariableArrayIncludes('contribute_rows', 0, [
+ 'contact_id' => $this->contactID,
+ 'contribution_id' => '1',
+ 'total_amount' => '100.00',
+ 'financial_type' => 'Donation',
+ 'contribution_source' => 'SSF',
+ 'receive_date' => '2018-11-21 00:00:00',
+ 'contribution_status' => 'Completed',
+ 'currency' => 'USD',
+ //'receipt_date' => '2018-11-22 00:00:00',
+ ]);
+
}
/**
* Test the content of the dashboard.
*/
- public function testDashboardContentContributionsWithInvoicingEnabled() {
- $this->markTestIncomplete('some issue on jenkins but not locally - disabling to investigage on master as this is an rc patch');
+ public function testDashboardContentContributions() {
$this->contributionCreate(['contact_id' => $this->contactID]);
- $this->callAPISuccess('Setting', 'create', ['invoicing' => 1]);
+ $this->contributions[] = civicrm_api3('Contribution', 'get', [
+ 'contact_id' => $this->contactID,
+ 'options' => ['limit' => 12, 'sort' => 'receive_date DESC'],
+ 'sequential' => 1,
+ ])['values'];
$this->runUserDashboard();
$expectedStrings = [
'Your Contribution(s)',
- '<table class="selector"><tr class="columnheader"><th>Total Amount</th><th>Financial Type</th><th>Received date</th><th>Receipt Sent</th><th>Status</th><th></th>',
- '<td>Completed</td><td><a class="button no-popup nowrap"href="/index.php?q=civicrm/contribute/invoice&reset=1&id=1&cid=' . $this->contactID . '"><i class="crm-i fa-print"></i><span>Print Invoice</span></a></td></tr></table>',
+ '<table class="selector"><tr class="columnheader"><th>Total Amount</th><th>Financial Type</th><th>Received date</th><th>Receipt Sent</th><th>Status</th>',
+ '<td>$ 100.00 </td><td>Donation</td>',
+ '<td>Completed</td>',
];
$this->assertPageContains($expectedStrings);
- $this->assertSmartyVariables(['invoicing' => TRUE]);
}
/**
* Run the user dashboard.
*/
protected function runUserDashboard() {
+ $_REQUEST = ['reset' => 1, 'id' => $this->contactID];
$dashboard = new CRM_Contact_Page_View_UserDashBoard();
+ $dashboard->_contactId = $this->contactID;
$dashboard->run();
+ $_REQUEST = [];
}
}
'form_value' => array('cancel_reason' => 'Invalid Credit Card Number'),
'expected_count' => 1,
'expected_contribution' => array($Contribution3['id']),
- 'expected_qill' => "Cancel Reason Like '%Invalid Credit Card Number%'",
+ 'expected_qill' => "Cancellation / Refund Reason Like '%Invalid Credit Card Number%'",
),
// Case 3: Search for Cancelled Date and Cancelled Reason
array(
'form_value' => array('cancel_date' => date('Y-m-d'), 'cancel_reason' => 'Insufficient funds'),
'expected_count' => 1,
'expected_contribution' => array($Contribution1['id']),
- 'expected_qill' => "Cancel Date Like '%" . date('Y-m-d') . "%'ANDCancel Reason Like '%Insufficient funds%'",
+ 'expected_qill' => "Cancel Date Like '%" . date('Y-m-d') . "%'ANDCancellation / Refund Reason Like '%Insufficient funds%'",
),
);
$this->customGroupDelete($customGroup['id']);
}
+ public function testGetDisplayedValuesContactRef() {
+ $customGroup = $this->customGroupCreate(['extends' => 'Individual']);
+ $params = [
+ 'data_type' => 'ContactReference',
+ 'html_type' => 'Autocomplete-Select',
+ 'label' => 'test ref',
+ 'custom_group_id' => $customGroup['id'],
+ ];
+ $createdField = $this->callAPISuccess('customField', 'create', $params);
+ $contact1 = $this->individualCreate();
+ $contact2 = $this->individualCreate(['custom_' . $createdField['id'] => $contact1['id']]);
+
+ $this->assertEquals($contact1['display_name'], CRM_Core_BAO_CustomField::displayValue($contact2['id'], $createdField['id']));
+ $this->assertEquals("Bob", CRM_Core_BAO_CustomField::displayValue("Bob", $createdField['id']));
+
+ $this->contactDelete($contact2['id']);
+ $this->contactDelete($contact1['id']);
+ $this->customGroupDelete($customGroup['id']);
+ }
+
public function testDeleteCustomField() {
$customGroup = $this->customGroupCreate(array('extends' => 'Individual'));
$fields = array(
--- /dev/null
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 5 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2018 |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM. |
+ | |
+ | CiviCRM is free software; you can copy, modify, and distribute it |
+ | under the terms of the GNU Affero General Public License |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
+ | |
+ | CiviCRM is distributed in the hope that it will be useful, but |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
+ | See the GNU Affero General Public License for more details. |
+ | |
+ | You should have received a copy of the GNU Affero General Public |
+ | License and the CiviCRM Licensing Exception along |
+ | with this program; if not, contact CiviCRM LLC |
+ | at info[AT]civicrm[DOT]org. If you have questions about the |
+ | GNU Affero General Public License or the licensing of CiviCRM, |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+ */
+/**
+ * Class CRM_Core_I18n_LocaleTest
+ * @group headless
+ */
+class CRM_Core_I18n_LocaleTest extends CiviUnitTestCase {
+
+ public function setUp() {
+ parent::setUp();
+ }
+
+ public function tearDown() {
+ CRM_Core_I18n_Schema::makeSinglelingual('en_US');
+ parent::tearDown();
+ }
+
+ /**
+ *
+ */
+ public function testI18nLocaleChange() {
+ $this->enableMultilingual();
+ CRM_Core_I18n_Schema::addLocale('fr_CA', 'en_US');
+
+ CRM_Core_I18n::singleton()->setLocale('fr_CA');
+ $locale = CRM_Core_I18n::getLocale();
+
+ $this->assertEquals($locale, 'fr_CA');
+ }
+
+}
*
* @param int $feeTotal
* @param int $actualPaidAmt
+ * @param array $participantParams
+ * @param array $contributionParams
*
* @return array
* @throws Exception
*/
- protected function addParticipantWithPayment($feeTotal, $actualPaidAmt) {
+ protected function addParticipantWithPayment($feeTotal, $actualPaidAmt, $participantParams = [], $contributionParams = []) {
$priceSetId = $this->eventPriceSetCreate($feeTotal);
CRM_Price_BAO_PriceSet::addTo('civicrm_event', $this->_eventId, $priceSetId);
// create participant record
$eventId = $this->_eventId;
- $participantParams = array(
- 'send_receipt' => 1,
- 'is_test' => 0,
- 'is_pay_later' => 0,
- 'event_id' => $eventId,
- 'register_date' => date('Y-m-d') . " 00:00:00",
- 'role_id' => 1,
- 'status_id' => 14,
- 'source' => 'Event_' . $eventId,
- 'contact_id' => $this->_contactId,
- 'note' => 'Note added for Event_' . $eventId,
- 'fee_level' => '\ 1Price_Field - 55\ 1',
+ $participantParams = array_merge(
+ [
+ 'send_receipt' => 1,
+ 'is_test' => 0,
+ 'is_pay_later' => 0,
+ 'event_id' => $eventId,
+ 'register_date' => date('Y-m-d') . " 00:00:00",
+ 'role_id' => 1,
+ 'status_id' => 14,
+ 'source' => 'Event_' . $eventId,
+ 'contact_id' => $this->_contactId,
+ 'note' => 'Note added for Event_' . $eventId,
+ 'fee_level' => '\ 1Price_Field - 55\ 1',
+ ],
+ $participantParams
);
$participant = $this->callAPISuccess('participant', 'create', $participantParams);
$this->callAPISuccessGetSingle('participant', array('id' => $participant['id']));
// create participant contribution with partial payment
- $contributionParams = array(
- 'total_amount' => $actualPaidAmt,
- 'source' => 'Fall Fundraiser Dinner: Offline registration',
- 'currency' => 'USD',
- 'receipt_date' => date('Y-m-d') . " 00:00:00",
- 'contact_id' => $this->_contactId,
- 'financial_type_id' => 4,
- 'payment_instrument_id' => 4,
- 'contribution_status_id' => 1,
- 'receive_date' => date('Y-m-d') . " 00:00:00",
- 'skipLineItem' => 1,
- 'partial_payment_total' => $feeTotal,
- 'partial_amount_to_pay' => $actualPaidAmt,
+ $contributionParams = array_merge(
+ [
+ 'total_amount' => $actualPaidAmt,
+ 'source' => 'Fall Fundraiser Dinner: Offline registration',
+ 'currency' => 'USD',
+ 'receipt_date' => date('Y-m-d') . " 00:00:00",
+ 'contact_id' => $this->_contactId,
+ 'financial_type_id' => 4,
+ 'payment_instrument_id' => 4,
+ 'contribution_status_id' => 1,
+ 'receive_date' => date('Y-m-d') . " 00:00:00",
+ 'skipLineItem' => 1,
+ 'partial_payment_total' => $feeTotal,
+ 'partial_amount_to_pay' => $actualPaidAmt,
+ ],
+ $contributionParams
);
$contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams);
);
}
+ /**
+ * See https://lab.civicrm.org/dev/core/issues/153
+ */
+ public function testPaymentWithCustomPaymentInstrument() {
+ $feeAmt = 100;
+ $amtPaid = 0;
+
+ // Create undetermined Payment Instrument
+ $paymentInstrumentID = $this->createPaymentInstrument(['label' => 'Undetermined'], 'Accounts Receivable');
+
+ // record pending payment for an event
+ $result = $this->addParticipantWithPayment(
+ $feeAmt, $amtPaid,
+ ['is_pay_later' => 1],
+ [
+ 'total_amount' => 100,
+ 'payment_instrument_id' => $paymentInstrumentID,
+ 'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending'),
+ ]
+ );
+ $contributionID = $result['contribution']['id'];
+ extract($result);
+
+ // check payment info
+ $paymentInfo = CRM_Contribute_BAO_Contribution::getPaymentInfo($participant['id'], 'event');
+ $this->assertEquals(round($paymentInfo['total']), $feeAmt, 'Total amount recorded is not proper');
+ $this->assertEquals(round($paymentInfo['paid']), $amtPaid, 'Amount paid is not proper');
+ $this->assertEquals(round($paymentInfo['balance']), $feeAmt, 'Balance amount is not proper');
+ $this->assertEquals($paymentInfo['contribution_status'], 'Pending', 'Contribution status is not proper');
+
+ // make additional payment via 'Record Payment' form
+ $form = new CRM_Contribute_Form_AdditionalPayment();
+ $submitParams = array(
+ 'contact_id' => $result['contribution']['contact_id'],
+ 'contribution_id' => $contributionID,
+ 'total_amount' => 100,
+ 'currency' => 'USD',
+ 'trxn_date' => '2017-04-11 13:05:11',
+ 'payment_processor_id' => 0,
+ 'payment_instrument_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Check'),
+ 'check_number' => '#123',
+ );
+ $form->cid = $result['contribution']['contact_id'];
+ $form->testSubmit($submitParams);
+
+ // check payment info again and see if the payment is completed
+ $paymentInfo = CRM_Contribute_BAO_Contribution::getPaymentInfo($participant['id'], 'event');
+ $this->assertEquals(round($paymentInfo['total']), $feeAmt, 'Total amount recorded is not proper');
+ $this->assertEquals(round($paymentInfo['paid']), $feeAmt, 'Amount paid is not proper');
+ $this->assertEquals(round($paymentInfo['balance']), 0, 'Balance amount is not proper');
+ $this->assertEquals($paymentInfo['contribution_status'], 'Completed', 'Contribution status is not proper');
+
+ $this->callAPISuccess('OptionValue', 'delete', ['id' => $paymentInstrumentID]);
+ }
+
/**
* CRM-13964
*/
$dao->fetch();
$this->assertEquals('Org 2', $dao->{$employerRelationshipTypeID . '_a_b_organization_name'});
$this->assertEquals('well dodgey', $dao->{$employerRelationshipTypeID . '_a_b_legal_name'});
+
+ $this->assertEquals([
+ 0 => 'First Name',
+ 1 => 'Employee of-Organization Name',
+ 2 => 'Employee of-Legal Name',
+ 3 => 'Employee of-Contact Source',
+ ], $headerRows);
}
/**
* Get return properties manually added in.
*/
public function getExtraReturnProperties() {
- return [
- 'location_type' => 1,
- 'im_provider' => 1,
- 'phone_type_id' => 1,
- 'provider_id' => 1,
- 'current_employer' => 1,
- ];
+ return [];
}
/**
'tags' => 1,
'notes' => 1,
'phone_type_id' => 1,
- 'provider_id' => 1,
];
if (!$isContactMode) {
unset($returnProperties['groups']);
*/
public function getMembershipReturnProperties() {
return [
- 'location_type' => 1,
- 'im_provider' => 1,
- 'phone_type_id' => 1,
- 'provider_id' => 1,
- 'current_employer' => 1,
'contact_type' => 1,
'contact_sub_type' => 1,
'sort_name' => 1,
80 => 'Group(s)',
81 => 'Tag(s)',
82 => 'Note(s)',
- 83 => 'IM Service Provider',
];
if (!$isContactExport) {
unset($headers[80]);
95 => 'Invoice Reference',
96 => 'Invoice Number',
97 => 'Currency',
- 98 => 'Cancel Reason',
+ 98 => 'Cancellation / Refund Reason',
99 => 'Receipt Date',
100 => 'Product Name',
101 => 'SKU',
'groups' => 'groups text',
'tags' => 'tags text',
'notes' => 'notes text',
- 'provider_id' => 'provider_id varchar(255)',
];
if (!$isContactExport) {
unset($columns['groups']);
'world_region' => 'world_region varchar(128)',
'url' => 'url varchar(128)',
'phone_type_id' => 'phone_type_id varchar(16)',
- 'provider_id' => 'provider_id varchar(255)',
'financial_type' => 'financial_type varchar(64)',
'contribution_source' => 'contribution_source varchar(255)',
'receive_date' => 'receive_date varchar(32)',
*/
public function testGetFinancialTransactionsList() {
$individualID = $this->individualCreate();
- $this->contributionCreate(array('contact_id' => $individualID));
+ $this->contributionCreate(array('contact_id' => $individualID, 'trxn_id' => 12345));
$batch = $this->callAPISuccess('Batch', 'create', array('title' => 'test', 'status_id' => 'Open'));
CRM_Core_DAO::executeQuery("
INSERT INTO civicrm_entity_batch (entity_table, entity_id, batch_id)
'civicrm_membership_type',
'civicrm_membership',
'civicrm_uf_match',
+ 'civicrm_email',
)
);
foreach (array(17, 18, 23, 32) as $contactID) {
}
}
+ /**
+ * Test customFormat() function
+ */
+ public function testCustomFormat() {
+ $dateTime = "2018-11-08 21:46:44";
+ $this->assertEquals(CRM_Utils_Date::customFormat($dateTime, "%b"), "Nov");
+ $this->assertEquals(CRM_Utils_Date::customFormat($dateTime, "%B"), "November");
+ $this->assertEquals(CRM_Utils_Date::customFormat($dateTime, "%d"), "08");
+ $this->assertEquals(CRM_Utils_Date::customFormat($dateTime, "%e"), " 8");
+ $this->assertEquals(CRM_Utils_Date::customFormat($dateTime, "%E"), "8");
+ $this->assertEquals(CRM_Utils_Date::customFormat($dateTime, "%f"), "th");
+ $this->assertEquals(CRM_Utils_Date::customFormat($dateTime, "%H"), "21");
+ $this->assertEquals(CRM_Utils_Date::customFormat($dateTime, "%I"), "09");
+ $this->assertEquals(CRM_Utils_Date::customFormat($dateTime, "%k"), "21");
+ $this->assertEquals(CRM_Utils_Date::customFormat($dateTime, "%l"), " 9");
+ $this->assertEquals(CRM_Utils_Date::customFormat($dateTime, "%m"), "11");
+ $this->assertEquals(CRM_Utils_Date::customFormat($dateTime, "%M"), "46");
+ $this->assertEquals(CRM_Utils_Date::customFormat($dateTime, "%p"), "pm");
+ $this->assertEquals(CRM_Utils_Date::customFormat($dateTime, "%P"), "PM");
+ $this->assertEquals(CRM_Utils_Date::customFormat($dateTime, "%Y"), "2018");
+ }
+
+ /**
+ * Test customFormat() function
+ */
+ public function testCustomFormatTs() {
+ $ts = mktime(21, 46, 44, 11, 8, 2018);
+ $this->assertEquals(CRM_Utils_Date::customFormatTs($ts, "%b"), "Nov");
+ $this->assertEquals(CRM_Utils_Date::customFormatTs($ts, "%B"), "November");
+ $this->assertEquals(CRM_Utils_Date::customFormatTs($ts, "%d"), "08");
+ $this->assertEquals(CRM_Utils_Date::customFormatTs($ts, "%e"), " 8");
+ $this->assertEquals(CRM_Utils_Date::customFormatTs($ts, "%E"), "8");
+ $this->assertEquals(CRM_Utils_Date::customFormatTs($ts, "%f"), "th");
+ $this->assertEquals(CRM_Utils_Date::customFormatTs($ts, "%H"), "21");
+ $this->assertEquals(CRM_Utils_Date::customFormatTs($ts, "%I"), "09");
+ $this->assertEquals(CRM_Utils_Date::customFormatTs($ts, "%k"), "21");
+ $this->assertEquals(CRM_Utils_Date::customFormatTs($ts, "%l"), " 9");
+ $this->assertEquals(CRM_Utils_Date::customFormatTs($ts, "%m"), "11");
+ $this->assertEquals(CRM_Utils_Date::customFormatTs($ts, "%M"), "46");
+ $this->assertEquals(CRM_Utils_Date::customFormatTs($ts, "%p"), "pm");
+ $this->assertEquals(CRM_Utils_Date::customFormatTs($ts, "%P"), "PM");
+ $this->assertEquals(CRM_Utils_Date::customFormatTs($ts, "%Y"), "2018");
+ }
+
}
array('field(table.civicrm_column_name,4,5,6)', 'MysqlOrderBy', 'field(table.civicrm_column_name,4,5,6)'),
array('table.civicrm_column_name desc,other_column, another_column desc', 'MysqlOrderBy', 'table.civicrm_column_name desc,other_column, another_column desc'),
array('table.`Home-street_address` asc, `table-alias`.`Home-street_address` desc,`table-alias`.column', 'MysqlOrderBy', 'table.`Home-street_address` asc, `table-alias`.`Home-street_address` desc,`table-alias`.column'),
+ // Lab issue dev/core#93 allow for 3 column orderby
+ array('contact_id.gender_id.label', 'MysqlOrderBy', 'contact_id.gender_id.label'),
array('a string', 'String', 'a string'),
array('{"contact":{"contact_id":205}}', 'Json', '{"contact":{"contact_id":205}}'),
array('{"contact":{"contact_id":!n†rude®}}', 'Json', NULL),
*/
protected $pageContent;
+ /**
+ * @var \CRM_Core_Page
+ */
+ protected $page;
+
+ /**
+ * @var string
+ */
+ protected $tplName;
+
/**
* Variables assigned to smarty.
*
*/
protected $smartyVariables = [];
+ protected $context;
+
/**
* @param string $content
* @param string $context
*/
public function checkPageContent(&$content, $context, $tplName, &$object) {
$this->pageContent = $content;
+ $this->tplName = $tplName;
+ $this->page = $object;
+ $this->context = $context;
// Ideally we would validate $content as valid html here.
// Suppress console output.
$content = '';
* @param $expectedStrings
*/
protected function assertPageContains($expectedStrings) {
+ unset($this->smartyVariables['config']);
+ unset($this->smartyVariables['session']);
foreach ($expectedStrings as $expectedString) {
- $this->assertContains($expectedString, $this->pageContent);
+ $this->assertContains($expectedString, $this->pageContent, print_r($this->contributions, TRUE) . print_r($this->smartyVariables, TRUE));
}
}
}
}
+ /**
+ * Check an array assigned to smarty for the inclusion of the expected variables.
+ *
+ * @param string $variableName
+ * @param $index
+ * @param $expected
+ */
+ protected function assertSmartyVariableArrayIncludes($variableName, $index, $expected) {
+ $smartyVariable = $this->smartyVariables[$variableName];
+ if ($index !== NULL) {
+ $smartyVariable = $smartyVariable[$index];
+ }
+ foreach ($expected as $key => $value) {
+ $this->assertEquals($value, $smartyVariable[$key], 'Checking ' . $key);
+ }
+ }
+
/**
* Set up environment to listen for page content.
*/
'financial_type_id' => 1,
'payment_instrument_id' => 1,
'non_deductible_amount' => 10.00,
- 'trxn_id' => 12345,
- 'invoice_id' => 67890,
'source' => 'SSF',
'contribution_status_id' => 1,
), $params);
return $this->callAPISuccess('FinancialType', 'create', $params);
}
+ /**
+ * Create Payment Instrument.
+ *
+ * @param array $params
+ * @param string $financialAccountName
+ *
+ * @return int
+ */
+ protected function createPaymentInstrument($params = array(), $financialAccountName = 'Donation') {
+ $params = array_merge(array(
+ 'label' => 'Payment Instrument -' . substr(sha1(rand()), 0, 7),
+ 'option_group_id' => 'payment_instrument',
+ 'is_active' => 1,
+ ),
+ $params
+ );
+ $newPaymentInstrument = $this->callAPISuccess('OptionValue', 'create', $params);
+
+ $relationTypeID = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Asset Account is' "));
+
+ $financialAccountParams = [
+ 'entity_table' => 'civicrm_option_value',
+ 'entity_id' => key($newPaymentInstrument),
+ 'account_relationship' => $relationTypeID,
+ 'financial_account_id' => $this->callAPISuccess('FinancialAccount', 'getValue', ['name' => $financialAccountName, 'return' => 'id']),
+ ];
+ CRM_Financial_BAO_FinancialTypeAccount::add($financialAccountParams);
+
+ return CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', $params['label']);
+ }
+
/**
* Enable Tax and Invoicing
*/
$this->assertSelections([]);
}
+ public function testFetch() {
+ $this->testFillArray();
+
+ $cids = $this->prevNext->fetch($this->cacheKey, 0, 2);
+ $this->assertEquals([100, 400], $cids);
+
+ $cids = $this->prevNext->fetch($this->cacheKey, 0, 4);
+ $this->assertEquals([100, 400, 200, 300], $cids);
+
+ $cids = $this->prevNext->fetch($this->cacheKey, 2, 2);
+ $this->assertEquals([200, 300], $cids);
+ }
+
public function getFillFunctions() {
return [
['testFillSql'],
$this->callAPISuccess('contribution_page', 'submit', $submitParams);
$contribution = $this->callAPISuccessGetSingle('contribution', array(
'contribution_page_id' => $this->_ids['contribution_page'],
- 'contribution_status_id' => 2,
+ 'contribution_status_id' => 'Pending',
));
$this->assertEquals(80, $contribution['total_amount']);
$lineItems = $this->callAPISuccess('LineItem', 'get', array(
$params = array_merge($params, array(
'id' => $contributionID,
'invoice_number' => CRM_Utils_Array::value('invoice_prefix', Civi::settings()->get('contribution_invoice_settings')) . "" . $contributionID,
+ 'trxn_id' => 12345,
+ 'invoice_id' => 6789,
));
$contributionID = $this->contributionCreate($params);
}
}
+ /**
+ * Test cancel reason works as a filter.
+ */
+ public function testFilterCancelReason() {
+ $params = $this->_params;
+ $params['cancel_date'] = 'yesterday';
+ $params['cancel_reason'] = 'You lose sucker';
+ $this->callAPISuccess('Contribution', 'create', $params);
+ $params = $this->_params;
+ $params['cancel_date'] = 'yesterday';
+ $params['cancel_reason'] = 'You are a winner';
+ $this->callAPISuccess('Contribution', 'create', $params);
+ $this->callAPISuccessGetCount('Contribution', ['cancel_reason' => 'You are a winner'], 1);
+ }
+
/**
* We need to ensure previous tested behaviour still works as part of the api contract.
*/
));
}
+ /**
+ * @expectedException CiviCRM_API3_Exception
+ * @expectedExceptionMessage Line item total doesn't match with total amount.
+ */
+ public function testCreateOrderIfTotalAmountDoesNotMatchLineItemsAmountsIfNoTaxSupplied() {
+ $params = [
+ 'contact_id' => $this->_individualId,
+ 'receive_date' => '2018-01-01',
+ 'total_amount' => 50,
+ 'financial_type_id' => $this->_financialTypeId,
+ 'contribution_status_id' => 1,
+ 'line_items' => [
+ 0 => [
+ 'line_item' => [
+ '0' => [
+ 'price_field_id' => 1,
+ 'price_field_value_id' => 1,
+ 'label' => 'Test 1',
+ 'field_title' => 'Test 1',
+ 'qty' => 1,
+ 'unit_price' => 40,
+ 'line_total' => 40,
+ 'financial_type_id' => 1,
+ 'entity_table' => 'civicrm_contribution',
+ ],
+ ]
+ ],
+ ],
+ ];
+
+ civicrm_api3('Order', 'create', $params);
+ }
+
+ /**
+ * @expectedException CiviCRM_API3_Exception
+ * @expectedExceptionMessage Line item total doesn't match with total amount.
+ */
+ public function testCreateOrderIfTotalAmountDoesNotMatchLineItemsAmountsIfTaxSupplied() {
+ $params = [
+ 'contact_id' => $this->_individualId,
+ 'receive_date' => '2018-01-01',
+ 'total_amount' => 50,
+ 'financial_type_id' => $this->_financialTypeId,
+ 'contribution_status_id' => 1,
+ 'tax_amount' => 15,
+ 'line_items' => [
+ 0 => [
+ 'line_item' => [
+ '0' => [
+ 'price_field_id' => 1,
+ 'price_field_value_id' => 1,
+ 'label' => 'Test 1',
+ 'field_title' => 'Test 1',
+ 'qty' => 1,
+ 'unit_price' => 30,
+ 'line_total' => 30,
+ 'financial_type_id' => 1,
+ 'entity_table' => 'civicrm_contribution',
+ 'tax_amount' => 15,
+ ],
+ ]
+ ],
+ ],
+ ];
+
+ civicrm_api3('Order', 'create', $params);
+ }
+
+ public function testCreateOrderIfTotalAmountDoesMatchLineItemsAmountsAndTaxSupplied() {
+ $params = [
+ 'contact_id' => $this->_individualId,
+ 'receive_date' => '2018-01-01',
+ 'total_amount' => 50,
+ 'financial_type_id' => $this->_financialTypeId,
+ 'contribution_status_id' => 1,
+ 'tax_amount' => 15,
+ 'line_items' => [
+ 0 => [
+ 'line_item' => [
+ '0' => [
+ 'price_field_id' => 1,
+ 'price_field_value_id' => 1,
+ 'label' => 'Test 1',
+ 'field_title' => 'Test 1',
+ 'qty' => 1,
+ 'unit_price' => 35,
+ 'line_total' => 35,
+ 'financial_type_id' => 1,
+ 'entity_table' => 'civicrm_contribution',
+ 'tax_amount' => 15,
+ ],
+ ]
+ ],
+ ],
+ ];
+
+ $order = civicrm_api3('Order', 'create', $params);
+ $this->assertEquals(1, $order['count']);
+ }
+
}
$this->assertEquals("Hello 123", $note['note']);
}
+ /**
+ * Check handling a custom greeting.
+ */
+ public function testSubmitGreetingFields() {
+ $profileFieldValues = $this->_createIndividualContact();
+ $params = reset($profileFieldValues);
+ $contactId = key($profileFieldValues);
+ $params['profile_id'] = $this->_profileID;
+ $params['contact_id'] = $contactId;
+
+ $this->callAPISuccess('ufField', 'create', array(
+ 'uf_group_id' => $this->_profileID,
+ 'field_name' => 'email_greeting',
+ 'visibility' => 'Public Pages and Listings',
+ 'field_type' => 'Contact',
+ 'label' => 'Email Greeting',
+ ));
+
+ $emailGreetings = array_column(civicrm_api3('OptionValue', 'get', ['option_group_id' => "email_greeting"])['values'], NULL, 'name');
+
+ $params['email_greeting'] = $emailGreetings['Customized']['value'];
+ // Custom greeting should be required
+ $this->callAPIFailure('profile', 'submit', $params);
+
+ $params['email_greeting_custom'] = 'Hello fool!';
+ $this->callAPISuccess('profile', 'submit', $params);
+
+ // Api3 will not return custom greeting field so resorting to this
+ $greeting = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contactId, 'email_greeting_custom');
+
+ $this->assertEquals("Hello fool!", $greeting);
+ }
+
/**
* Helper function to create an Individual with address/email/phone info. Import UF Group and UF Fields
* @param array $params
<comment>Date on which given case starts.</comment>
<html>
<type>Select Date</type>
+ <formatType>activityDateTime</formatType>
</html>
<add>1.8</add>
</field>
<comment>Date on which given case ends.</comment>
<html>
<type>Select Date</type>
+ <formatType>activityDateTime</formatType>
</html>
<add>1.8</add>
</field>
<field>
<name>cancel_reason</name>
<type>text</type>
+ <title>Cancellation / Refund Reason</title>
<import>true</import>
+ <export>true</export>
<headerPattern>/(cancel.?)?reason/i</headerPattern>
<html>
<type>Text</type>
+ <size>40</size>
</html>
<add>1.3</add>
</field>
<add>1.5</add>
</foreignKey>
<index>
- <name>index_entity_file_id</name>
+ <name>UI_entity_table_entity_id_file_id</name>
<fieldName>entity_table</fieldName>
<fieldName>entity_id</fieldName>
<fieldName>file_id</fieldName>
+ <unique>true</unique>
<add>1.1</add>
</index>
</table>
</field>
<field>
<name>title</name>
+ <title>Profile Name</title>
<type>varchar</type>
<length>64</length>
<localizable>true</localizable>
<required>true</required>
+ <html>
+ <type>Text</type>
+ </html>
<comment>Form title.</comment>
<add>1.1</add>
</field>
<field>
<name>frontend_title</name>
+ <title>Public Title</title>
<type>varchar</type>
<length>64</length>
<localizable>true</localizable>
<comment>Profile Form Public title</comment>
+ <html>
+ <type>Text</type>
+ </html>
<add>4.7</add>
</field>
<field>
<type>int</type>
<required>true</required>
<default>1</default>
+ <html>
+ <type>Text</type>
+ </html>
<comment>Controls display order when multiple user framework groups are setup for concurrent display.</comment>
<add>1.2</add>
<drop>1.3</drop>
<?xml version="1.0" encoding="iso-8859-1" ?>
<version>
- <version_no>5.8.beta1</version_no>
+ <version_no>5.9.alpha1</version_no>
</version>