* particular component object.
*
* @return string
+ * @throws \CRM_Core_Exception
*/
public static function getActivitySubject($entityObj) {
+ // @todo determine the subject on the appropriate entity rather than from the activity.
switch ($entityObj->__table) {
case 'civicrm_membership':
- $membershipType = CRM_Member_PseudoConstant::membershipType($entityObj->membership_type_id);
- $subject = $membershipType ? $membershipType : ts('Membership');
-
- if (is_array($subject)) {
- $subject = implode(", ", $subject);
- }
+ $membershipType = CRM_Core_PseudoConstant::getLabel('CRM_Member_BAO_Membership', 'membership_type_id', $entityObj->membership_type_id);
+ $subject = $membershipType ?: ts('Membership');
if (!CRM_Utils_System::isNull($entityObj->source)) {
$subject .= " - {$entityObj->source}";
$subject .= sprintf(' (by %s)', $displayName);
}
- $subject .= " - Status: " . CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipStatus', $entityObj->status_id, 'label');
+ $subject .= ' - Status: ' . CRM_Core_PseudoConstant::getLabel('CRM_Member_BAO_Membership', 'status_id', $entityObj->status_id);
return $subject;
case 'civicrm_participant':
self::$_exportableFields[$name] = [];
// TODO: ideally we should retrieve all fields from xml, in this case since activity processing is done
- // my case hence we have defined fields as case_*
- if ($name === 'Activity') {
- $exportableFields = CRM_Activity_DAO_Activity::export();
- $exportableFields['source_contact_id'] = [
- 'title' => ts('Source Contact ID'),
- 'type' => CRM_Utils_Type::T_INT,
- ];
- $exportableFields['source_contact'] = [
- 'title' => ts('Source Contact'),
+ $exportableFields = CRM_Activity_DAO_Activity::export();
+ $exportableFields['source_contact_id'] = [
+ 'title' => ts('Source Contact ID'),
+ 'type' => CRM_Utils_Type::T_INT,
+ ];
+ $exportableFields['source_contact'] = [
+ 'title' => ts('Source Contact'),
+ 'type' => CRM_Utils_Type::T_STRING,
+ ];
+
+ // @todo - remove these - they are added by CRM_Core_DAO::appendPseudoConstantsToFields
+ // below. That search label stuff is referenced in search builder but is likely just
+ // a hack that duplicates, maybe differently, other functionality.
+ $activityFields = [
+ 'activity_type' => [
+ 'title' => ts('Activity Type'),
+ 'name' => 'activity_type',
'type' => CRM_Utils_Type::T_STRING,
- ];
+ 'searchByLabel' => TRUE,
+ ],
+ 'activity_status' => [
+ 'title' => ts('Activity Status'),
+ 'name' => 'activity_status',
+ 'type' => CRM_Utils_Type::T_STRING,
+ 'searchByLabel' => TRUE,
+ ],
+ 'activity_priority' => [
+ 'title' => ts('Activity Priority'),
+ 'name' => 'activity_priority',
+ 'type' => CRM_Utils_Type::T_STRING,
+ 'searchByLabel' => TRUE,
+ ],
+ ];
+ $fields = array_merge($activityFields, $exportableFields);
+ $fields['activity_type_id']['title'] = ts('Activity Type ID');
+ $fields['activity_priority_id'] = $fields['priority_id'];
- // @todo - remove these - they are added by CRM_Core_DAO::appendPseudoConstantsToFields
- // below. That search label stuff is referenced in search builder but is likely just
- // a hack that duplicates, maybe differently, other functionality.
- $Activityfields = [
- 'activity_type' => [
- 'title' => ts('Activity Type'),
- 'name' => 'activity_type',
- 'type' => CRM_Utils_Type::T_STRING,
- 'searchByLabel' => TRUE,
- ],
- 'activity_status' => [
- 'title' => ts('Activity Status'),
- 'name' => 'activity_status',
- 'type' => CRM_Utils_Type::T_STRING,
- 'searchByLabel' => TRUE,
- ],
- 'activity_priority' => [
- 'title' => ts('Activity Priority'),
- 'name' => 'activity_priority',
- 'type' => CRM_Utils_Type::T_STRING,
- 'searchByLabel' => TRUE,
- ],
- ];
- $fields = array_merge($Activityfields, $exportableFields);
- $fields['activity_type_id']['title'] = ts('Activity Type ID');
- }
- else {
+ if ($name === 'Case') {
+ // Now add "case_activity" fields
// Set title to activity fields.
- $fields = [
- 'case_activity_subject' => [
- 'title' => ts('Activity Subject'),
- 'type' => CRM_Utils_Type::T_STRING,
- ],
+ $caseActivityFields = [
'case_source_contact_id' => [
'title' => ts('Activity Reporter'),
'type' => CRM_Utils_Type::T_STRING,
],
- 'case_recent_activity_date' => [
- 'title' => ts('Activity Actual Date'),
+ 'case_activity_date_time' => [
+ 'title' => ts('Activity Date'),
'type' => CRM_Utils_Type::T_DATE,
],
- 'case_scheduled_activity_date' => [
- 'title' => ts('Activity Scheduled Date'),
- 'type' => CRM_Utils_Type::T_DATE,
- ],
- 'case_recent_activity_type' => [
+ 'case_activity_type' => [
'title' => ts('Activity Type'),
'type' => CRM_Utils_Type::T_STRING,
],
- 'case_activity_status' => [
- 'title' => ts('Activity Status'),
- 'type' => CRM_Utils_Type::T_STRING,
- ],
- 'case_activity_duration' => [
- 'title' => ts('Activity Duration'),
- 'type' => CRM_Utils_Type::T_INT,
- ],
'case_activity_medium_id' => [
'title' => ts('Activity Medium'),
'type' => CRM_Utils_Type::T_INT,
],
- 'case_activity_details' => [
- 'title' => ts('Activity Details'),
- 'type' => CRM_Utils_Type::T_TEXT,
- ],
'case_activity_is_auto' => [
'title' => ts('Activity Auto-generated?'),
'type' => CRM_Utils_Type::T_BOOLEAN,
],
];
+ $caseStandardFields = ['activity_subject', 'activity_status', 'activity_duration', 'activity_details'];
+ foreach ($caseStandardFields as $key) {
+ $caseActivityFields['case_' . $key] = $fields[$key];
+ }
+ $fields = $caseActivityFields;
}
-
- // add custom data for case activities
+ // Add custom data
$fields = array_merge($fields, CRM_Core_BAO_CustomField::getFieldsForImport('Activity'));
CRM_Core_DAO::appendPseudoConstantsToFields($fields);
self::$_exportableFields[$name] = $fields;
$ufm = new CRM_Core_DAO_UFMatch();
$ufm->contact_id = $session->get('userID');
if ($newLocale && $ufm->find(TRUE)) {
- $ufm->language = $newLocale;
- $ufm->save();
$session->set('lcMessages', $newLocale);
}
}
if (CRM_Core_Config::environment() != 'Production') {
CRM_Core_Session::setStatus(ts('Execution of scheduled jobs has been turned off by default since this is a non-production environment. You can override this for particular jobs by adding runInNonProductionEnvironment=TRUE as a parameter.'), ts("Non-production Environment"), "warning", array('expires' => 0));
}
+ else {
+ $cronError = Civi\Api4\System::check(FALSE)
+ ->addWhere('name', '=', 'checkLastCron')
+ ->addWhere('severity_id', '>', 1)
+ ->setIncludeDisabled(TRUE)
+ ->execute()
+ ->first();
+ if ($cronError) {
+ CRM_Core_Session::setStatus($cronError['message'], $cronError['title'], 'alert', ['expires' => 0]);
+ }
+ }
$sj = new CRM_Core_JobManager();
$rows = $temp = [];
$query->_tables['case_relation_type'] = $query->_whereTables['case_relation_type'] = 1;
}
- if (!empty($query->_returnProperties['case_recent_activity_date'])) {
- $query->_select['case_recent_activity_date'] = "case_activity.activity_date_time as case_recent_activity_date";
- $query->_element['case_recent_activity_date'] = 1;
+ if (!empty($query->_returnProperties['case_activity_date_time'])) {
+ $query->_select['case_activity_date_time'] = "case_activity.activity_date_time as case_activity_date_time";
+ $query->_element['case_activity_date_time'] = 1;
$query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1;
}
$query->_tables['civicrm_case'] = 1;
}
+ // @todo switch to a more standard case_source_contact as the key where we want the name not the id.
if (!empty($query->_returnProperties['case_source_contact_id'])) {
$query->_select['case_source_contact_id'] = "civicrm_case_reporter.sort_name as case_source_contact_id";
$query->_element['case_source_contact_id'] = 1;
$query->_select['case_activity_status_id'] = "rec_activity_status.id as case_activity_status_id";
$query->_element['case_activity_status_id'] = 1;
$query->_tables['case_activity'] = 1;
- $query->_tables['recent_activity_status'] = 1;
+ $query->_tables['case_activity_status'] = 1;
$query->_tables['civicrm_case_contact'] = 1;
$query->_tables['civicrm_case'] = 1;
}
$query->_select['case_activity_status'] = "rec_activity_status.label as case_activity_status";
$query->_element['case_activity_status'] = 1;
$query->_tables['case_activity'] = 1;
- $query->_tables['recent_activity_status'] = 1;
+ $query->_tables['case_activity_status'] = 1;
$query->_tables['civicrm_case_contact'] = 1;
$query->_tables['civicrm_case'] = 1;
}
}
if (!empty($query->_returnProperties['case_activity_medium_id'])) {
- $query->_select['case_activity_medium_id'] = "recent_activity_medium.label as case_activity_medium_id";
+ $query->_select['case_activity_medium_id'] = "case_activity_medium.label as case_activity_medium_id";
$query->_element['case_activity_medium_id'] = 1;
$query->_tables['case_activity'] = 1;
$query->_tables['case_activity_medium'] = 1;
$query->_tables['civicrm_case'] = 1;
}
- if (!empty($query->_returnProperties['case_scheduled_activity_date'])) {
- $query->_select['case_scheduled_activity_date'] = "case_activity.activity_date_time as case_scheduled_activity_date";
- $query->_element['case_scheduled_activity_date'] = 1;
+ if (!empty($query->_returnProperties['case_activity_date_time'])) {
+ $query->_select['case_activity_date_time'] = "case_activity.activity_date_time as case_activity_date_time";
+ $query->_element['case_activity_date_time'] = 1;
$query->_tables['case_activity'] = 1;
$query->_tables['civicrm_case_contact'] = 1;
$query->_tables['civicrm_case'] = 1;
}
- if (!empty($query->_returnProperties['case_recent_activity_type'])) {
- $query->_select['case_recent_activity_type'] = "rec_activity_type.label as case_recent_activity_type";
- $query->_element['case_recent_activity_type'] = 1;
+ if (!empty($query->_returnProperties['case_activity_type'])) {
+ $query->_select['case_activity_type'] = "rec_activity_type.label as case_activity_type";
+ $query->_element['case_activity_type'] = 1;
$query->_tables['case_activity'] = 1;
$query->_tables['case_activity_type'] = 1;
$query->_tables['civicrm_case_contact'] = 1;
$query->handleWhereFromMetadata($fieldSpec, $name, $value, $op);
return;
+ // @todo switch to a more standard case_source_contact as the key where we want the name not the id.
case 'case_source_contact_id':
$query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_case_reporter.sort_name", $op, $value, 'String');
$query->_qill[$grouping][] = ts("Activity Reporter %1 '%2'", [1 => $op, 2 => $value]);
$query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1;
return;
- case 'case_recent_activity_date':
+ case 'case_activity_date_time':
$date = CRM_Utils_Date::format($value);
$query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_activity.activity_date_time", $op, $date, 'Date');
if ($date) {
$date = CRM_Utils_Date::customFormat($date);
- $query->_qill[$grouping][] = ts("Activity Actual Date %1 %2", [1 => $op, 2 => $date]);
+ $query->_qill[$grouping][] = ts("Activity Date %1 %2", [1 => $op, 2 => $date]);
}
$query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1;
$query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1;
$query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1;
return;
- case 'case_scheduled_activity_date':
- $date = CRM_Utils_Date::format($value);
- $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_activity.activity_date_time", $op, $date, 'Date');
- if ($date) {
- $date = CRM_Utils_Date::customFormat($date);
- $query->_qill[$grouping][] = ts("Activity Schedule Date %1 %2", [1 => $op, 2 => $date]);
- }
- $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1;
- $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1;
- $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1;
- return;
-
- case 'case_recent_activity_type':
+ case 'case_activity_type':
$names = $value;
if (($activityType = CRM_Core_PseudoConstant::getLabel('CRM_Activity_BAO_Activity', 'activity_type_id', $value)) != FALSE) {
$names = $activityType;
}
$query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_activity.status_id", $op, $value, 'Int');
- $query->_qill[$grouping][] = ts("Activity Type %1 %2", [1 => $op, 2 => $names]);
+ $query->_qill[$grouping][] = ts("Activity Status %1 %2", [1 => $op, 2 => $names]);
$query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1;
$query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1;
$query->_tables['case_activity_status'] = 1;
$from .= " $side JOIN civicrm_option_value rec_activity_type ON (case_activity.activity_type_id = rec_activity_type.value AND option_group_activity_type.id = rec_activity_type.option_group_id ) ";
break;
- case 'recent_activity_status':
+ case 'case_activity_status':
$from .= " $side JOIN civicrm_option_group option_group_activity_status ON (option_group_activity_status.name = 'activity_status')";
$from .= " $side JOIN civicrm_option_value rec_activity_status ON (case_activity.status_id = rec_activity_status.value AND option_group_activity_status.id = rec_activity_status.option_group_id ) ";
break;
case 'case_activity_medium':
$from .= " $side JOIN civicrm_option_group option_group_activity_medium ON (option_group_activity_medium.name = 'encounter_medium')";
- $from .= " $side JOIN civicrm_option_value recent_activity_medium ON (case_activity.medium_id = recent_activity_medium.value AND option_group_activity_medium.id = recent_activity_medium.option_group_id ) ";
+ $from .= " $side JOIN civicrm_option_value case_activity_medium ON (case_activity.medium_id = case_activity_medium.value AND option_group_activity_medium.id = case_activity_medium.option_group_id ) ";
break;
case 'case_activity':
'case_type' => 1,
'case_role' => 1,
'case_deleted' => 1,
- 'case_recent_activity_date' => 1,
- 'case_recent_activity_type' => 1,
- 'case_scheduled_activity_date' => 1,
+ 'case_activity_date_time' => 1,
+ 'case_activity_type' => 1,
'phone' => 1,
- // 'case_scheduled_activity_type'=> 1
];
if ($includeCustomFields) {
'case_start_date' => 1,
'case_end_date' => 1,
'case_subject' => 1,
+ // @todo switch to a more standard case_source_contact as the key where we want the name not the id.
'case_source_contact_id' => 1,
'case_activity_status' => 1,
'case_activity_duration' => 1,
if (CRM_Core_Permission::check('view all contacts') ||
CRM_Core_Permission::check('edit all contacts')
) {
- if (is_array($contactAlias)) {
+ if (!CRM_Core_Permission::check('access deleted contacts')) {
$wheres = [];
- foreach ($contactAlias as $alias) {
+ foreach ((array) $contactAlias as $alias) {
// CRM-6181
$wheres[] = "$alias.is_deleted = 0";
}
return [NULL, '(' . implode(' AND ', $wheres) . ')'];
}
else {
- // CRM-6181
- return [NULL, "$contactAlias.is_deleted = 0"];
+ return [NULL, '( 1 )'];
}
}
}
$fromClause = implode(" ", $clauses);
- $whereClase = NULL;
+ $whereClause = NULL;
}
else {
$fromClause = " INNER JOIN civicrm_acl_contact_cache aclContactCache ON {$contactAlias}.id = aclContactCache.contact_id ";
- $whereClase = " aclContactCache.user_id = $contactID AND $contactAlias.is_deleted = 0";
+ $whereClause = " aclContactCache.user_id = $contactID";
+ if (!CRM_Core_Permission::check('access deleted contacts')) {
+ $whereClause .= " AND $contactAlias.is_deleted = 0";
+ }
}
- return [$fromClause, $whereClase];
+ return [$fromClause, $whereClause];
}
/**
// add activity fields
$this->_fields = array_merge($this->_fields, CRM_Activity_BAO_Activity::exportableFields());
+ $this->_fields = array_merge($this->_fields, CRM_Activity_BAO_Activity::exportableFields('Case'));
// Add hack as no unique name is defined for the field but the search form is in denial.
$this->_fields['activity_priority_id'] = $this->_fields['priority_id'];
}
if (!empty($this->_permissionWhereClause) && empty($this->_displayRelationshipType)) {
+ if (!empty($this->_permissionFromClause)) {
+ $from .= " $this->_permissionFromClause";
+ }
if (empty($where)) {
$where = "WHERE $this->_permissionWhereClause";
}
$options = $query->_options;
if (!empty($query->_permissionWhereClause)) {
+ if (!empty($query->_permissionFromClause) && !stripos($from, 'aclContactCache')) {
+ $from .= " $query->_permissionFromClause";
+ }
if (empty($where)) {
$where = "WHERE $query->_permissionWhereClause";
}
$sqlParts = $this->getSearchSQLParts(NULL, NULL, NULL, FALSE, FALSE, TRUE);
$query = "SELECT DISTINCT LEFT(contact_a.sort_name, 1) as sort_name
{$sqlParts['from']}
- {$sqlParts['where']}
- {$sqlParts['having']}
- GROUP BY sort_name
- ORDER BY sort_name asc";
+ {$sqlParts['where']}";
$dao = CRM_Core_DAO::executeQuery($query);
return $dao;
}
*/
public function generatePermissionClause($onlyDeleted = FALSE, $count = FALSE) {
if (!$this->_skipPermission) {
- $this->_permissionWhereClause = CRM_ACL_API::whereClause(
- CRM_Core_Permission::VIEW,
- $this->_tables,
- $this->_whereTables,
- NULL,
- $onlyDeleted,
- $this->_skipDeleteClause
- );
+ $permissionClauses = CRM_Contact_BAO_Contact_Permission::cacheClause();
+ $this->_permissionWhereClause = $permissionClauses[1];
+ $this->_permissionFromClause = $permissionClauses[0];
- if (!$onlyDeleted && CRM_Core_Permission::check('access deleted contacts')) {
- $this->_permissionWhereClause = str_replace(' ( 1 ) ', '(contact_a.is_deleted = 0)', $this->_permissionWhereClause);
+ if (CRM_Core_Permission::check('access deleted contacts')) {
+ if (!$onlyDeleted) {
+ $this->_permissionWhereClause = str_replace('( 1 )', '(contact_a.is_deleted = 0)', $this->_permissionWhereClause);
+ }
+ else {
+ if ($this->_permissionWhereClause === '( 1 )') {
+ $this->_permissionWhereClause = str_replace('( 1 )', '(contact_a.is_deleted)', $this->_permissionWhereClause);
+ }
+ else {
+ $this->_permissionWhereClause .= " AND (contact_a.is_deleted) ";
+ }
+ }
}
if (isset($this->_tables['civicrm_activity'])) {
$this->_permissionWhereClause .= '(' . implode(' AND ', $clauses) . ')';
}
}
-
- // regenerate fromClause since permission might have added tables
- if ($this->_permissionWhereClause) {
- //fix for row count in qill (in contribute/membership find)
- if (!$count) {
- $this->_useDistinct = TRUE;
- }
- //CRM-15231
- $this->_fromClause = self::fromClause($this->_tables, NULL, NULL, $this->_primaryLocation, $this->_mode);
- $this->_simpleFromClause = self::fromClause($this->_whereTables, NULL, NULL, $this->_primaryLocation, $this->_mode);
- // note : this modifies _fromClause and _simpleFromClause
- $this->includePseudoFieldsJoin($this->_sort);
- }
}
else {
// add delete clause if needed even if we are skipping permission
*/
public function summaryContribution($context = NULL) {
list($innerselect, $from, $where, $having) = $this->query(TRUE);
+ if (!empty($this->_permissionFromClause) && !stripos($from, 'aclContactCache')) {
+ $from .= " $this->_permissionFromClause";
+ }
if ($this->_permissionWhereClause) {
$where .= " AND " . $this->_permissionWhereClause;
}
$from = str_replace("INNER JOIN", "LEFT JOIN", $from);
$from .= $qcache['from'];
$where = $qcache['where'];
+ if (!empty($this->_permissionFromClause) && !stripos($from, 'aclContactCache')) {
+ $from .= " $this->_permissionFromClause";
+ }
if (!empty($this->_permissionWhereClause)) {
$where .= "AND $this->_permissionWhereClause";
}
'privacy_toggle' => 1,
'operator' => 'AND',
], $defaults);
- $this->normalizeDefaultValues($defaults);
+ $defaults = $this->normalizeDefaultValues($defaults);
//991/Subtypes not respected when editing smart group criteria
if (!empty($defaults['contact_type']) && !empty($this->_formValues['contact_sub_type'])) {
$this->addRule('cms_pass', 'Password is required', 'required');
$this->addRule(['cms_pass', 'cms_confirm_pass'], 'ERROR: Password mismatch', 'compare');
$this->add('text', 'email', ts('Email:'), ['class' => 'huge'])->freeze();
+ $this->addRule('email', 'Email is required', 'required');
$this->add('hidden', 'contactID');
//add a rule to check username uniqueness
// store the submitted values in an array
$params = $this->exportValues();
- CRM_Core_BAO_CMSUser::create($params, 'email');
- CRM_Core_Session::setStatus('', ts('User Added'), 'success');
+ if (CRM_Core_BAO_CMSUser::create($params, 'email') === FALSE) {
+ CRM_Core_Error::statusBounce(ts('Error creating CMS user account.'));
+ }
+ else {
+ CRM_Core_Session::setStatus(ts('User Added'), '', 'success');
+ }
}
/**
*/
use Civi\Api4\Activity;
+use Civi\Api4\ContributionPage;
+use Civi\Api4\ContributionRecur;
/**
*
return $rows;
}
+ /**
+ * Should an email receipt be sent for this contribution on completion.
+ *
+ * @param array $input
+ * @param int $contributionPageID
+ * @param int $recurringContributionID
+ *
+ * @return bool
+ * @throws \API_Exception
+ * @throws \Civi\API\Exception\UnauthorizedException
+ */
+ protected static function isEmailReceipt(array $input, $contributionPageID, $recurringContributionID): bool {
+ if (isset($input['is_email_receipt'])) {
+ return (bool) $input['is_email_receipt'];
+ }
+ if ($recurringContributionID) {
+ //CRM-13273 - is_email_receipt setting on recurring contribution should take precedence over contribution page setting
+ // but CRM-16124 if $input['is_email_receipt'] is set then that should not be overridden.
+ // dev/core#1245 this maybe not the desired effect because the default value for is_email_receipt is set to 0 rather than 1 in
+ // Instance that had the table added via an upgrade in 4.1
+ // see also https://github.com/civicrm/civicrm-svn/commit/7f39befd60bc735408d7866b02b3ac7fff1d4eea#diff-9ad8e290180451a2d6eacbd3d1ca7966R354
+ // https://lab.civicrm.org/dev/core/issues/1245
+ return (bool) ContributionRecur::get(FALSE)->addWhere('id', '=', $recurringContributionID)->addSelect('is_email_receipt')->execute()->first()['is_email_receipt'];
+ }
+ if ($contributionPageID) {
+ return (bool) ContributionPage::get(FALSE)->addWhere('id', '=', $contributionPageID)->addSelect('is_email_receipt')->execute()->first()['is_email_receipt'];
+ }
+ // This would be the case for backoffice (where is_email_receipt is not passed in) or events, where Event::sendMail will filter
+ // again anyway.
+ return TRUE;
+ }
+
/**
* @inheritDoc
*/
* @param CRM_Contribute_BAO_Contribution $contribution
* @param array $input
* @param array $contributionParams
- * @param int $paymentProcessorID
*
- * @return bool
+ * @return bool|array
* @throws CiviCRM_API3_Exception
*/
- protected static function repeatTransaction(&$contribution, &$input, $contributionParams, $paymentProcessorID) {
+ protected static function repeatTransaction(&$contribution, &$input, $contributionParams) {
if (!empty($contribution->id)) {
return FALSE;
}
])
);
$input['line_item'] = $contributionParams['line_item'] = $templateContribution['line_item'];
-
$contributionParams['status_id'] = 'Pending';
- if (isset($contributionParams['financial_type_id'])) {
- // Give precedence to passed in type.
+
+ if (isset($contributionParams['financial_type_id']) && count($input['line_item']) === 1) {
+ // We permit the financial type to be overridden for single line items.
+ // More comments on this are in getTemplateTransaction.
$contribution->financial_type_id = $contributionParams['financial_type_id'];
}
else {
$contributionParams['financial_type_id'] = $templateContribution['financial_type_id'];
}
- $contributionParams['contact_id'] = $templateContribution['contact_id'];
- $contributionParams['source'] = empty($templateContribution['source']) ? ts('Recurring contribution') : $templateContribution['source'];
+ foreach (['contact_id', 'currency', 'source'] as $fieldName) {
+ $contributionParams[$fieldName] = $templateContribution[$fieldName];
+ }
+
+ $contributionParams['source'] = $contributionParams['source'] ?: ts('Recurring contribution');
//CRM-18805 -- Contribution page not recorded on recurring transactions, Recurring contribution payments
//do not create CC or BCC emails or profile notifications.
$createContribution = civicrm_api3('Contribution', 'create', $contributionParams);
$contribution->id = $createContribution['id'];
- CRM_Contribute_BAO_ContributionRecur::copyCustomValues($contributionParams['contribution_recur_id'], $contribution->id);
+ $contribution->copyCustomFields($templateContribution['id'], $contribution->id);
self::handleMembershipIDOverride($contribution->id, $input);
- return TRUE;
+ return $createContribution;
}
}
//not really sure what params might be passed in but lets merge em into values
$values = array_merge($this->_gatherMessageValues($input, $values, $ids), $values);
- $values['is_email_receipt'] = $this->isEmailReceipt($input, $values);
+ $values['is_email_receipt'] = !$returnMessageText;
if (!empty($input['receipt_date'])) {
$values['receipt_date'] = $input['receipt_date'];
}
//get soft contributions
$softContributions = CRM_Contribute_BAO_ContributionSoft::getSoftContribution($this->id, TRUE);
if (!empty($softContributions)) {
- $values['softContributions'] = $softContributions['soft_credit'];
+ // For pcp soft credit, there is no 'soft_credit' member it comes
+ // back in different array members, but shortly after returning from
+ // this function it calls _assignMessageVariablesToTemplate which does
+ // its own lookup of any pcp soft credit, so we can skip it here.
+ $values['softContributions'] = $softContributions['soft_credit'] ?? NULL;
}
if (isset($this->contribution_page_id)) {
// This is a call we want to use less, in favour of loading related objects.
'Refunded' => ['Cancelled', 'Completed'],
'Partially paid' => ['Completed'],
'Pending refund' => ['Completed', 'Refunded'],
+ 'Failed' => ['Pending'],
];
if (!in_array($contributionStatuses[$fields['contribution_status_id']],
* @param array $input
* @param array $ids
* @param array $objects
- * @param CRM_Core_Transaction $transaction
- * It is not recommended to pass this in. The calling function handle it's own roll back if it wants it.
* @param bool $isPostPaymentCreate
* Is this being called from the payment.create api. If so the api has taken care of financial entities.
* Note that our goal is that this would only ever be called from payment.create and never handle financials (only
* @throws \CRM_Core_Exception
* @throws \CiviCRM_API3_Exception
*/
- public static function completeOrder($input, &$ids, $objects, $transaction = NULL, $isPostPaymentCreate = FALSE) {
- if (!$transaction) {
- $transaction = new CRM_Core_Transaction();
- }
+ public static function completeOrder($input, &$ids, $objects, $isPostPaymentCreate = FALSE) {
+ $transaction = new CRM_Core_Transaction();
$contribution = $objects['contribution'];
$primaryContributionID = $contribution->id ?? $objects['first_contribution']->id;
// The previous details are used when calculating line items so keep it before any code that 'does something'
'contribution_status_id',
'card_type_id',
'pan_truncation',
+ 'financial_type_id',
];
- if (self::isSingleLineItem($primaryContributionID)) {
- $inputContributionWhiteList[] = 'financial_type_id';
- }
$participant = $objects['participant'] ?? NULL;
$recurContrib = $objects['contributionRecur'] ?? NULL;
], array_intersect_key($input, array_fill_keys($inputContributionWhiteList, 1)
));
- // CRM-20678 Ensure that the currency is correct in subseqent transcations.
- if (empty($contributionParams['currency']) && isset($objects['first_contribution']->currency)) {
- $contributionParams['currency'] = $objects['first_contribution']->currency;
- }
-
$contributionParams['payment_processor'] = $input['payment_processor'] = $paymentProcessorId;
// If paymentProcessor is not set then the payment_instrument_id would not be correct.
}
$changeDate = CRM_Utils_Array::value('trxn_date', $input, date('YmdHis'));
- if (empty($contributionParams['receive_date']) && $changeDate) {
- $contributionParams['receive_date'] = $changeDate;
- }
-
- self::repeatTransaction($contribution, $input, $contributionParams, $paymentProcessorId);
- $contributionParams['financial_type_id'] = $contribution->financial_type_id;
-
- $values = [];
+ $contributionResult = self::repeatTransaction($contribution, $input, $contributionParams);
if ($input['component'] == 'contribute') {
- if ($contribution->contribution_page_id) {
- // Figure out what we gain from this.
- // Note that we may have overwritten the is_email_receipt input, fix that below.
- CRM_Contribute_BAO_ContributionPage::setValues($contribution->contribution_page_id, $values);
- }
- elseif ($recurContrib && $recurringContributionID) {
- $values['amount'] = $recurContrib->amount;
- $values['financial_type_id'] = $objects['contributionType']->id;
- $values['title'] = $source = ts('Offline Recurring Contribution');
- }
-
- if ($recurContrib && $recurringContributionID) {
- //CRM-13273 - is_email_receipt setting on recurring contribution should take precedence over contribution page setting
- // but CRM-16124 if $input['is_email_receipt'] is set then that should not be overridden.
- // dev/core#1245 this maybe not the desired effect because the default value for is_email_receipt is set to 0 rather than 1 in
- // Instance that had the table added via an upgrade in 4.1
- // see also https://github.com/civicrm/civicrm-svn/commit/7f39befd60bc735408d7866b02b3ac7fff1d4eea#diff-9ad8e290180451a2d6eacbd3d1ca7966R354
- // https://lab.civicrm.org/dev/core/issues/1245
- $values['is_email_receipt'] = $recurContrib->is_email_receipt;
- }
-
if ($contributionParams['contribution_status_id'] === $completedContributionStatusID) {
self::updateMembershipBasedOnCompletionOfContribution(
$contribution,
- $primaryContributionID,
$changeDate
);
}
$contributionParams['id'] = $contribution->id;
$contributionParams['is_post_payment_create'] = $isPostPaymentCreate;
- // CRM-19309 - if you update the contribution here with financial_type_id it can/will mess with $lineItem
- // unsetting it here does NOT cause any other contribution test to fail!
- unset($contributionParams['financial_type_id']);
- $contributionResult = civicrm_api3('Contribution', 'create', $contributionParams);
+ if (!$contributionResult) {
+ $contributionResult = civicrm_api3('Contribution', 'create', $contributionParams);
+ }
// Add new soft credit against current $contribution.
if (!empty($objects['contributionRecur']) && $objects['contributionRecur']->id) {
CRM_Core_Error::debug_log_message('Contribution record updated successfully');
$transaction->commit();
+ // @todo - check if Contribution::create does this, test, remove.
CRM_Contribute_BAO_ContributionRecur::updateRecurLinkedPledge($contribution->id, $recurringContributionID,
$contributionParams['contribution_status_id'], $input['amount']);
// create an activity record
+ // @todo - check if Contribution::create does this, test, remove.
if ($input['component'] == 'contribute') {
//CRM-4027
$targetContactID = NULL;
CRM_Activity_BAO_Activity::addActivity($contribution, NULL, $targetContactID);
}
- $isEmailReceipt = !array_key_exists('is_email_receipt', $values) || $values['is_email_receipt'] == 1;
- if (isset($input['is_email_receipt'])) {
- $isEmailReceipt = $input['is_email_receipt'];
- }
- // CRM-9132 legacy behaviour was that receipts were sent out in all instances. Still sending
- // when array_key 'is_email_receipt doesn't exist in case some instances where is needs setting haven't been set
- if ($isEmailReceipt) {
+ if (self::isEmailReceipt($input, $contribution->contribution_page_id, $recurringContributionID)) {
civicrm_api3('Contribution', 'sendconfirmation', [
'id' => $contribution->id,
'payment_processor_id' => $paymentProcessorId,
* @param array $ids
* Related object IDs.
* @param int $contributionID
- * @param array $values
- * Values related to objects that have already been loaded.
* @param bool $returnMessageText
* Should text be returned instead of sent. This.
* is because the function is also used to generate pdfs
* @throws \CiviCRM_API3_Exception
* @throws \Exception
*/
- public static function sendMail(&$input, &$ids, $contributionID, &$values,
- $returnMessageText = FALSE) {
-
+ public static function sendMail($input, $ids, $contributionID, $returnMessageText = FALSE) {
+ $values = [];
$contribution = new CRM_Contribute_BAO_Contribution();
$contribution->id = $contributionID;
if (!$contribution->find(TRUE)) {
* load them in this function. Code clean up would compensate for any minor performance implication.
*
* @param \CRM_Contribute_BAO_Contribution $contribution
- * @param int $primaryContributionID
* @param string $changeDate
*
* @throws \CRM_Core_Exception
* @throws \CiviCRM_API3_Exception
*/
- public static function updateMembershipBasedOnCompletionOfContribution($contribution, $primaryContributionID, $changeDate) {
+ public static function updateMembershipBasedOnCompletionOfContribution($contribution, $changeDate) {
$memberships = self::getRelatedMemberships($contribution->id);
foreach ($memberships as $membership) {
$membershipParams = [
// Passing num_terms to the api triggers date calculations, but for pending memberships these may be already calculated.
// sigh - they should be consistent but removing the end date check causes test failures & maybe UI too?
// The api assumes num_terms is a special sauce for 'is_renewal' so we need to not pass it when updating a pending to completed.
+ // ... except testCompleteTransactionMembershipPriceSetTwoTerms hits this line so the above is obviously not true....
// @todo once apiv4 ships with core switch to that & find sanity.
$membershipParams['num_terms'] = $contribution->getNumTermsByContributionAndMembershipType(
$membershipParams['membership_type_id'],
- $primaryContributionID
+ $contribution->id
);
}
// @todo remove all this stuff in favour of letting the api call further down handle in
* In BAO/Membership.php(renewMembership function), we skip the extend membership date and status
* when Contribution mode is notify and membership is for renewal )
*/
+ // Test cover for this is in testRepeattransactionRenewMembershipOldMembership
+ // Be afraid.
CRM_Member_BAO_Membership::fixMembershipStatusBeforeRenew($currentMembership, $changeDate);
// @todo - we should pass membership_type_id instead of null here but not
}
}
- /**
- * Should an email receipt be sent for this contribution when complete.
- *
- * @param array $input
- *
- * @return mixed
- */
- protected function isEmailReceipt($input) {
- if (isset($input['is_email_receipt'])) {
- return $input['is_email_receipt'];
- }
- if (!empty($this->_relatedObjects['contribution_page_id'])) {
- return $this->_relatedObjects['contribution_page_id']->is_email_receipt;
- }
- return TRUE;
- }
-
/**
* Function to replace contribution tokens.
*
}
if ($templateContributions->count()) {
$templateContribution = $templateContributions->first();
- $result = array_merge($templateContribution, $overrides);
$lineItems = CRM_Price_BAO_LineItem::getLineItemsByContributionID($templateContribution['id']);
+ // We only permit the financial type to be overridden for single line items.
+ // Otherwise we need to figure out a whole lot of extra complexity.
+ // It's not UI-possible to alter financial_type_id for recurring contributions
+ // with more than one line item.
+ if (count($lineItems) > 1 && isset($overrides['financial_type_id'])) {
+ unset($overrides['financial_type_id']);
+ }
+ $result = array_merge($templateContribution, $overrides);
$result['line_item'] = self::reformatLineItemsForRepeatContribution($result['total_amount'], $result['financial_type_id'], $lineItems, (array) $templateContribution);
return $result;
}
/**
* Copy custom data of the initial contribution into its recurring contributions.
*
+ * @deprecated
+ *
* @param int $recurId
* @param int $targetContributionId
*/
$title .= " - {$info['title']}";
}
$this->assign('transaction', TRUE);
- $this->assign('payments', $paymentInfo['transaction']);
+ $this->assign('payments', $paymentInfo['transaction'] ?? NULL);
$this->assign('paymentLinks', $paymentInfo['payment_links']);
return $title;
}
CRM_Core_Error::statusBounce($e->getMessage(), $urlParams, ts('Payment Processor Error'));
}
- $session = CRM_Core_Session::singleton();
- $buttonName = $this->controller->getButtonName();
- if ($this->_context == 'standalone') {
- if ($buttonName == $this->getButtonName('upload', 'new')) {
- $session->replaceUserContext(CRM_Utils_System::url('civicrm/contribute/add',
- 'reset=1&action=add&context=standalone'
- ));
- }
- else {
- $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view',
- "reset=1&cid={$this->_contactID}&selectedChild=contribute"
- ));
- }
- }
- elseif ($this->_context == 'contribution' && $this->_mode && $buttonName == $this->getButtonName('upload', 'new')) {
- $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/contribution',
- "reset=1&action=add&context={$this->_context}&cid={$this->_contactID}&mode={$this->_mode}"
- ));
- }
- elseif ($buttonName == $this->getButtonName('upload', 'new')) {
- $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/contribution',
- "reset=1&action=add&context={$this->_context}&cid={$this->_contactID}"
- ));
- }
+ $this->setUserContext();
//store contribution ID if not yet set (on create)
if (empty($this->_id) && !empty($contribution->id)) {
}
}
+ /**
+ * Set context in session
+ */
+ public function setUserContext(): void {
+ $session = CRM_Core_Session::singleton();
+ $buttonName = $this->controller->getButtonName();
+ if ($this->_context == 'standalone') {
+ if ($buttonName == $this->getButtonName('upload', 'new')) {
+ $session->replaceUserContext(CRM_Utils_System::url('civicrm/contribute/add',
+ 'reset=1&action=add&context=standalone'
+ ));
+ }
+ else {
+ $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view',
+ "reset=1&cid={$this->_contactID}&selectedChild=contribute"
+ ));
+ }
+ }
+ elseif ($this->_context == 'contribution' && $this->_mode && $buttonName == $this->getButtonName('upload', 'new')) {
+ $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/contribution',
+ "reset=1&action=add&context={$this->_context}&cid={$this->_contactID}&mode={$this->_mode}"
+ ));
+ }
+ elseif ($buttonName == $this->getButtonName('upload', 'new')) {
+ $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/contribution',
+ "reset=1&action=add&context={$this->_context}&cid={$this->_contactID}"
+ ));
+ }
+ }
+
}
}
$smarty = CRM_Core_Smarty::singleton();
$smarty->assign('dataArray', $dataArray);
- $smarty->assign('totalTaxAmount', $params['tax_amount']);
+ $smarty->assign('totalTaxAmount', $params['tax_amount'] ?? NULL);
}
// lets store it in the form variable so postProcess hook can get to this and use it
+--------------------------------------------------------------------+
*/
-use Dompdf\Dompdf;
-use Dompdf\Options;
-
/**
*
* @package CRM
'metric' => 'px',
]);
// functions call for adding activity with attachment
- $fileName = self::putFile($html, $pdfFileName);
+ $fileName = self::putFile($html, $pdfFileName, [
+ 'margin_top' => 10,
+ 'margin_left' => 65,
+ 'metric' => 'px',
+ ]);
self::addActivities($subject, $contactIds, $fileName, $params);
CRM_Utils_System::civiExit();
* Content for pdf in html format.
*
* @param string $name
+ * @param array $format
*
* @return string
* Name of file which is in pdf format
*/
- public static function putFile($html, $name = 'Invoice.pdf') {
- $options = new Options();
- $options->set('isRemoteEnabled', TRUE);
-
- $doc = new DOMPDF($options);
- $doc->load_html($html);
- $doc->render();
- $html = $doc->output();
- $config = CRM_Core_Config::singleton();
- $fileName = $config->uploadDir . $name;
- file_put_contents($fileName, $html);
- return $fileName;
+ public static function putFile($html, $name = 'Invoice.pdf', $format = NULL) {
+ return CRM_Utils_Mail::appendPDF($name, $html, $format)['fullPath'] ?? '';
}
/**
// CRM_Contribute_BAO_Contribution::composeMessageArray expects mysql formatted date
$objects['contribution']->receive_date = CRM_Utils_Date::isoToMysql($objects['contribution']->receive_date);
- $values = [];
if (isset($params['from_email_address']) && !$elements['createPdf']) {
// If a logged in user from email is used rather than a domain wide from email address
// the from_email_address params key will be numerical and we need to convert it to be
$input['receipt_from_name'] = str_replace('"', '', $fromDetails[0]);
}
- $mail = CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $objects['contribution']->id, $values,
- $elements['createPdf']);
+ $mail = CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $objects['contribution']->id, $elements['createPdf']);
if ($mail['html']) {
$message[] = $mail['html'];
$pdfElements['contribIDs'] = implode(',', $contribIds);
- $pdfElements['details'] = CRM_Contribute_Form_Task_Status::getDetails($pdfElements['contribIDs']);
+ $pdfElements['details'] = self::getDetails($pdfElements['contribIDs']);
$pdfElements['baseIPN'] = new CRM_Core_Payment_BaseIPN();
return $pdfElements;
}
+ /**
+ * @param string $contributionIDs
+ *
+ * @return array
+ */
+ private static function getDetails($contributionIDs) {
+ if (empty($contributionIDs)) {
+ return [];
+ }
+ $query = "
+SELECT c.id as contribution_id,
+ c.contact_id as contact_id ,
+ mp.membership_id as membership_id ,
+ pp.participant_id as participant_id ,
+ p.event_id as event_id
+FROM civicrm_contribution c
+LEFT JOIN civicrm_membership_payment mp ON mp.contribution_id = c.id
+LEFT JOIN civicrm_participant_payment pp ON pp.contribution_id = c.id
+LEFT JOIN civicrm_participant p ON pp.participant_id = p.id
+WHERE c.id IN ( $contributionIDs )";
+
+ $rows = [];
+ $dao = CRM_Core_DAO::executeQuery($query);
+
+ while ($dao->fetch()) {
+ $rows[$dao->contribution_id]['component'] = $dao->participant_id ? 'event' : 'contribute';
+ $rows[$dao->contribution_id]['contact'] = $dao->contact_id;
+ if ($dao->membership_id) {
+ if (!array_key_exists('membership', $rows[$dao->contribution_id])) {
+ $rows[$dao->contribution_id]['membership'] = [];
+ }
+ $rows[$dao->contribution_id]['membership'][] = $dao->membership_id;
+ }
+ if ($dao->participant_id) {
+ $rows[$dao->contribution_id]['participant'] = $dao->participant_id;
+ }
+ if ($dao->event_id) {
+ $rows[$dao->contribution_id]['event'] = $dao->event_id;
+ }
+ }
+ return $rows;
+ }
+
}
* Build the form object.
*/
public function buildQuickForm() {
- $status = CRM_Contribute_BAO_Contribution_Utils::getContributionStatuses(
- 'contribution', $this->_contributionIds[0]
- );
- $byName = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
- // FIXME: if it's invalid to transition from Pending to
- // In Progress or Overdue, we should move that logic to
- // CRM_Contribute_BAO_Contribution_Utils::getContributionStatuses.
- foreach (['Pending', 'In Progress', 'Overdue'] as $suppress) {
- unset($status[CRM_Utils_Array::key($suppress, $byName)]);
- }
- $this->add('select', 'contribution_status_id',
- ts('Contribution Status'),
- $status,
- TRUE
- );
$this->add('checkbox', 'is_email_receipt', ts('Send e-mail receipt'));
$this->setDefaults(['is_email_receipt' => 1]);
// submit the form with values.
self::processForm($this, $params);
- CRM_Core_Session::setStatus(ts('Contribution status has been updated for selected record(s).'), ts('Status Updated'), 'success');
+ CRM_Core_Session::setStatus(ts('Payments have been recorded for selected record(s).'), ts('Payments recorded'), 'success');
}
/**
* @throws \Exception
*/
public static function processForm($form, $params) {
- $statusID = $params['contribution_status_id'] ?? NULL;
- $baseIPN = new CRM_Core_Payment_BaseIPN();
-
- // get the missing pieces for each contribution
- $contribIDs = implode(',', $form->_contributionIds);
- $details = self::getDetails($contribIDs);
- $template = CRM_Core_Smarty::singleton();
-
- // for each contribution id, we just call the baseIPN stuff
foreach ($form->_rows as $row) {
- $input = $ids = $objects = [];
- $input['component'] = $details[$row['contribution_id']]['component'];
-
- $ids['contact'] = $row['contact_id'];
- $ids['contribution'] = $row['contribution_id'];
- $ids['contributionRecur'] = NULL;
- $ids['contributionPage'] = NULL;
- $ids['membership'] = $details[$row['contribution_id']]['membership'] ?? NULL;
- $ids['participant'] = $details[$row['contribution_id']]['participant'] ?? NULL;
- $ids['event'] = $details[$row['contribution_id']]['event'] ?? NULL;
-
- if (!$baseIPN->validateData($input, $ids, $objects, FALSE)) {
- CRM_Core_Error::statusBounce('Supplied data was not able to be validated');
- }
-
- $contribution = &$objects['contribution'];
-
- $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL,
- 'name'
- );
-
- if ($statusID == array_search('Cancelled', $contributionStatuses)) {
- $transaction = new CRM_Core_Transaction();
- $baseIPN->cancelled($objects, $transaction);
- $transaction->commit();
- continue;
- }
- elseif ($statusID == array_search('Failed', $contributionStatuses)) {
- $transaction = new CRM_Core_Transaction();
- $baseIPN->failed($objects, $transaction);
- $transaction->commit();
- continue;
- }
-
- // status is not pending
- if ($contribution->contribution_status_id != array_search('Pending',
- $contributionStatuses
- )
- ) {
- continue;
- }
-
- // set some fake input values so we can reuse IPN code
- $input['amount'] = $contribution->total_amount;
- $input['is_test'] = $contribution->is_test;
- $input['fee_amount'] = $params["fee_amount_{$row['contribution_id']}"];
- $input['check_number'] = $params["check_number_{$row['contribution_id']}"];
- $input['payment_instrument_id'] = $params["payment_instrument_id_{$row['contribution_id']}"];
- $input['net_amount'] = $contribution->total_amount - $input['fee_amount'];
-
- if (!empty($params["trxn_id_{$row['contribution_id']}"])) {
- $input['trxn_id'] = trim($params["trxn_id_{$row['contribution_id']}"]);
- }
- else {
- $input['trxn_id'] = $contribution->invoice_id;
- }
- $input['trxn_date'] = $params["trxn_date_{$row['contribution_id']}"] . ' ' . date('H:i:s');
- $input['is_email_receipt'] = !empty($params['is_email_receipt']);
-
- // @todo calling CRM_Contribute_BAO_Contribution::completeOrder like this is a pattern in it's last gasps. Call contribute.completetransaction api.
- CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $objects);
-
- // reset template values before processing next transactions
- $template->clearTemplateVars();
- }
- }
-
- /**
- * @param string $contributionIDs
- *
- * @return array
- */
- public static function &getDetails($contributionIDs) {
- if (empty($contributionIDs)) {
- return [];
- }
- $query = "
-SELECT c.id as contribution_id,
- c.contact_id as contact_id ,
- mp.membership_id as membership_id ,
- pp.participant_id as participant_id ,
- p.event_id as event_id
-FROM civicrm_contribution c
-LEFT JOIN civicrm_membership_payment mp ON mp.contribution_id = c.id
-LEFT JOIN civicrm_participant_payment pp ON pp.contribution_id = c.id
-LEFT JOIN civicrm_participant p ON pp.participant_id = p.id
-WHERE c.id IN ( $contributionIDs )";
-
- $rows = [];
- $dao = CRM_Core_DAO::executeQuery($query);
-
- while ($dao->fetch()) {
- $rows[$dao->contribution_id]['component'] = $dao->participant_id ? 'event' : 'contribute';
- $rows[$dao->contribution_id]['contact'] = $dao->contact_id;
- if ($dao->membership_id) {
- if (!array_key_exists('membership', $rows[$dao->contribution_id])) {
- $rows[$dao->contribution_id]['membership'] = [];
- }
- $rows[$dao->contribution_id]['membership'][] = $dao->membership_id;
- }
- if ($dao->participant_id) {
- $rows[$dao->contribution_id]['participant'] = $dao->participant_id;
- }
- if ($dao->event_id) {
- $rows[$dao->contribution_id]['event'] = $dao->event_id;
- }
+ $contribData = civicrm_api3('Contribution', 'getSingle', ['id' => $row['contribution_id']]);
+ $trxnParams = [
+ 'contribution_id' => $row['contribution_id'],
+ // We are safe assuming that payments will be for the total amount of
+ // the contribution because the contributions must be in "Pending"
+ // status.
+ 'total_amount' => $contribData['total_amount'],
+ 'fee_amount' => $params["fee_amount_{$row['contribution_id']}"],
+ 'check_number' => $params["check_number_{$row['contribution_id']}"],
+ 'payment_instrument_id' => $params["payment_instrument_id_{$row['contribution_id']}"],
+ 'net_amount' => $contribData['total_amount'] - $params["fee_amount_{$row['contribution_id']}"],
+ // Not sure why to default to invoice_id, but that's what the form has
+ // been doing historically
+ 'trxn_id' => $params["trxn_id_{$row['contribution_id']}"] ?? $contribData['invoice_id'],
+ 'trxn_date' => $params["trxn_date_{$row['contribution_id']}"] ?? 'now',
+ 'is_send_contribution_notification' => !empty($params['is_email_receipt']),
+ ];
+ $result = civicrm_api3('Payment', 'create', $trxnParams);
}
- return $rows;
}
}
'result' => TRUE,
],
self::UPDATE_STATUS => [
- 'title' => ts('Update pending contribution status'),
+ 'title' => ts('Record payments for contributions'),
'class' => 'CRM_Contribute_Form_Task_Status',
'result' => TRUE,
],
*/
const DEFAULT_SESSION_TTL = 172800;
- /**
- * Cache.
- *
- * Format is ($cacheKey => $cacheValue)
- *
- * @var array
- */
- public static $_cache = NULL;
-
- /**
- * Retrieve an item from the DB cache.
- *
- * @param string $group
- * (required) The group name of the item.
- * @param string $path
- * (required) The path under which this item is stored.
- * @param int $componentID
- * The optional component ID (so componenets can share the same name space).
- *
- * @return object
- * The data if present in cache, else null
- * @deprecated
- */
- public static function &getItem($group, $path, $componentID = NULL) {
- CRM_Core_Error::deprecatedFunctionWarning(
- 'CRM_Core_BAO_Cache::getItem is deprecated and will be removed from core soon, use Civi::cache() facade or define cache group using hook_civicrm_container'
- );
- if (($adapter = CRM_Utils_Constant::value('CIVICRM_BAO_CACHE_ADAPTER')) !== NULL) {
- $value = $adapter::getItem($group, $path, $componentID);
- return $value;
- }
-
- if (self::$_cache === NULL) {
- self::$_cache = [];
- }
-
- $argString = "CRM_CT_{$group}_{$path}_{$componentID}";
- if (!array_key_exists($argString, self::$_cache)) {
- $cache = CRM_Utils_Cache::singleton();
- $cleanKey = self::cleanKey($argString);
- self::$_cache[$argString] = $cache->get($cleanKey);
- if (self::$_cache[$argString] === NULL) {
- $table = self::getTableName();
- $where = self::whereCache($group, $path, $componentID);
- $rawData = CRM_Core_DAO::singleValueQuery("SELECT data FROM $table WHERE $where");
- $data = $rawData ? self::decode($rawData) : NULL;
-
- self::$_cache[$argString] = $data;
- if ($data !== NULL) {
- // Do not cache 'null' as that is most likely a cache miss & we shouldn't then cache it.
- $cache->set($cleanKey, self::$_cache[$argString]);
- }
- }
- }
- return self::$_cache[$argString];
- }
-
- /**
- * Retrieve all items in a group.
- *
- * @param string $group
- * (required) The group name of the item.
- * @param int $componentID
- * The optional component ID (so componenets can share the same name space).
- *
- * @return object
- * The data if present in cache, else null
- * @deprecated
- */
- public static function &getItems($group, $componentID = NULL) {
- CRM_Core_Error::deprecatedFunctionWarning(
- 'CRM_Core_BAO_Cache::getItems is deprecated and will be removed from core soon, use Civi::cache() facade or define cache group using hook_civicrm_container'
- );
- if (($adapter = CRM_Utils_Constant::value('CIVICRM_BAO_CACHE_ADAPTER')) !== NULL) {
- return $adapter::getItems($group, $componentID);
- }
-
- if (self::$_cache === NULL) {
- self::$_cache = [];
- }
-
- $argString = "CRM_CT_CI_{$group}_{$componentID}";
- if (!array_key_exists($argString, self::$_cache)) {
- $cache = CRM_Utils_Cache::singleton();
- $cleanKey = self::cleanKey($argString);
- self::$_cache[$argString] = $cache->get($cleanKey);
- if (!self::$_cache[$argString]) {
- $table = self::getTableName();
- $where = self::whereCache($group, NULL, $componentID);
- $dao = CRM_Core_DAO::executeQuery("SELECT path, data FROM $table WHERE $where");
-
- $result = [];
- while ($dao->fetch()) {
- $result[$dao->path] = self::decode($dao->data);
- }
-
- self::$_cache[$argString] = $result;
- $cache->set($cleanKey, self::$_cache[$argString]);
- }
- }
-
- return self::$_cache[$argString];
- }
-
- /**
- * Store an item in the DB cache.
- *
- * @param object $data
- * (required) A reference to the data that will be serialized and stored.
- * @param string $group
- * (required) The group name of the item.
- * @param string $path
- * (required) The path under which this item is stored.
- * @param int $componentID
- * The optional component ID (so componenets can share the same name space).
- * @deprecated
- * @throws CRM_Core_Exception
- */
- public static function setItem(&$data, $group, $path, $componentID = NULL) {
- CRM_Core_Error::deprecatedFunctionWarning(
- 'CRM_Core_BAO_Cache::setItem is deprecated and will be removed from core soon, use Civi::cache() facade or define cache group using hook_civicrm_container'
- );
- if (($adapter = CRM_Utils_Constant::value('CIVICRM_BAO_CACHE_ADAPTER')) !== NULL) {
- return $adapter::setItem($data, $group, $path, $componentID);
- }
-
- if (self::$_cache === NULL) {
- self::$_cache = [];
- }
-
- // get a lock so that multiple ajax requests on the same page
- // dont trample on each other
- // CRM-11234
- $lock = Civi::lockManager()->acquire("cache.{$group}_{$path}._{$componentID}");
- if (!$lock->isAcquired()) {
- throw new CRM_Core_Exception('Cannot acquire database lock');
- }
-
- $table = self::getTableName();
- $where = self::whereCache($group, $path, $componentID);
- $dataExists = CRM_Core_DAO::singleValueQuery("SELECT COUNT(*) FROM $table WHERE {$where}");
- // FIXME - Use SQL NOW() or CRM_Utils_Time?
- $now = date('Y-m-d H:i:s');
- $dataSerialized = self::encode($data);
-
- // This table has a wonky index, so we cannot use REPLACE or
- // "INSERT ... ON DUPE". Instead, use SELECT+(INSERT|UPDATE).
- if ($dataExists) {
- $sql = "UPDATE $table SET data = %1, created_date = %2 WHERE {$where}";
- $args = [
- 1 => [$dataSerialized, 'String'],
- 2 => [$now, 'String'],
- ];
- $dao = CRM_Core_DAO::executeQuery($sql, $args, TRUE, NULL, FALSE, FALSE);
- }
- else {
- $insert = CRM_Utils_SQL_Insert::into($table)
- ->row([
- 'group_name' => $group,
- 'path' => $path,
- 'component_id' => $componentID,
- 'data' => $dataSerialized,
- 'created_date' => $now,
- ]);
- $dao = CRM_Core_DAO::executeQuery($insert->toSQL(), [], TRUE, NULL, FALSE, FALSE);
- }
-
- $lock->release();
-
- // cache coherency - refresh or remove dependent caches
-
- $argString = "CRM_CT_{$group}_{$path}_{$componentID}";
- $cache = CRM_Utils_Cache::singleton();
- $data = self::decode($dataSerialized);
- self::$_cache[$argString] = $data;
- $cache->set(self::cleanKey($argString), $data);
-
- $argString = "CRM_CT_CI_{$group}_{$componentID}";
- unset(self::$_cache[$argString]);
- $cache->delete(self::cleanKey($argString));
- }
-
- /**
- * Delete all the cache elements that belong to a group OR delete the entire cache if group is not specified.
- *
- * @param string $group
- * The group name of the entries to be deleted.
- * @param string $path
- * Path of the item that needs to be deleted.
- * @param bool $clearAll clear all caches
- * @deprecated
- */
- public static function deleteGroup($group = NULL, $path = NULL, $clearAll = TRUE) {
- CRM_Core_Error::deprecatedFunctionWarning(
- 'CRM_Core_BAO_Cache::deleteGroup is deprecated and will be removed from core soon, use Civi::cache() facade or define cache group using hook_civicrm_container'
- );
- if (($adapter = CRM_Utils_Constant::value('CIVICRM_BAO_CACHE_ADAPTER')) !== NULL) {
- return $adapter::deleteGroup($group, $path);
- }
- else {
- $table = self::getTableName();
- $where = self::whereCache($group, $path, NULL);
- CRM_Core_DAO::executeQuery("DELETE FROM $table WHERE $where");
- }
-
- if ($clearAll) {
- self::resetCaches();
- }
- }
-
/**
* Cleanup ACL and System Level caches
*/
public static function resetCaches() {
- // also reset ACL Cache
- // @todo why is this called when CRM_Utils_System::flushCache() does it as well.
- CRM_ACL_BAO_Cache::resetCache();
-
- // also reset memory cache if any
CRM_Utils_System::flushCache();
}
* @see CRM_Utils_Cache::cleanKey()
*/
public static function cleanKey($key) {
+ CRM_Core_Error::deprecatedFunctionWarning('CRM_Utils_Cache::cleanKey');
return CRM_Utils_Cache::cleanKey($key);
}
+++ /dev/null
-<?php
-
-/*
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC. All rights reserved. |
- | |
- | This work is published under the GNU AGPLv3 license with some |
- | permitted exceptions and without any warranty. For full license |
- | and copyright information, see https://civicrm.org/licensing |
- +--------------------------------------------------------------------+
- */
-
-/**
- * Class CRM_Core_BAO_Cache_Psr16
- *
- * This optional adapter to help phase-out CRM_Core_BAO_Cache.
- *
- * In effect, it changes the default behavior of legacy cache-consumers
- * (CRM_Core_BAO_Cache) so that they store in the best-available tier
- * (Reds/Memcache or SQL or array) rather than being hard-coded to SQL.
- *
- * It basically just calls "CRM_Utils_Cache::create()" for each $group and
- * maps the getItem/setItem to get()/set().
- */
-class CRM_Core_BAO_Cache_Psr16 {
-
- /**
- * Original BAO behavior did not do expiration. PSR-16 providers have
- * diverse defaults. To provide some consistency, we'll pick a long(ish)
- * TTL for everything that goes through the adapter.
- */
- const TTL = 86400;
-
- /**
- * @param string $group
- * @return CRM_Utils_Cache_Interface
- */
- protected static function getGroup($group) {
- if (!isset(Civi::$statics[__CLASS__][$group])) {
- if (!in_array($group, self::getLegacyGroups())) {
- Civi::log()
- ->warning('Unrecognized BAO cache group ({group}). This should work generally, but data may not be flushed in some edge-cases. Consider migrating explicitly to PSR-16.', [
- 'group' => $group,
- ]);
- }
-
- $cache = CRM_Utils_Cache::create([
- 'name' => "bao_$group",
- 'type' => ['*memory*', 'SqlGroup', 'ArrayCache'],
- // We're replacing CRM_Core_BAO_Cache, which traditionally used a front-cache
- // that was not aware of TTLs. So it seems more consistent/performant to
- // use 'fast' here.
- 'withArray' => 'fast',
- ]);
- Civi::$statics[__CLASS__][$group] = $cache;
- }
- return Civi::$statics[__CLASS__][$group];
- }
-
- /**
- * Retrieve an item from the DB cache.
- *
- * @param string $group
- * (required) The group name of the item.
- * @param string $path
- * (required) The path under which this item is stored.
- * @param int $componentID
- * The optional component ID (so componenets can share the same name space).
- *
- * @return object
- * The data if present in cache, else null
- */
- public static function getItem($group, $path, $componentID = NULL) {
- // TODO: Generate a general deprecation notice.
- if ($componentID) {
- Civi::log()
- ->warning('getItem({group},{path},...) uses unsupported componentID. Consider migrating explicitly to PSR-16.', [
- 'group' => $group,
- 'path' => $path,
- ]);
- }
- return self::getGroup($group)->get(CRM_Utils_Cache::cleanKey($path));
- }
-
- /**
- * Retrieve all items in a group.
- *
- * @param string $group
- * (required) The group name of the item.
- * @param int $componentID
- * The optional component ID (so componenets can share the same name space).
- *
- * @throws CRM_Core_Exception
- */
- public static function &getItems($group, $componentID = NULL) {
- // Based on grepping universe, this function is not currently used.
- // Moreover, it's hard to implement in PSR-16. (We'd have to extend the
- // interface.) Let's wait and see if anyone actually needs this...
- throw new \CRM_Core_Exception('Not implemented: CRM_Core_BAO_Cache_Psr16::getItems');
- }
-
- /**
- * Store an item in the DB cache.
- *
- * @param object $data
- * (required) A reference to the data that will be serialized and stored.
- * @param string $group
- * (required) The group name of the item.
- * @param string $path
- * (required) The path under which this item is stored.
- * @param int $componentID
- * The optional component ID (so componenets can share the same name space).
- */
- public static function setItem(&$data, $group, $path, $componentID = NULL) {
- // TODO: Generate a general deprecation notice.
-
- if ($componentID) {
- Civi::log()
- ->warning('setItem({group},{path},...) uses unsupported componentID. Consider migrating explicitly to PSR-16.', [
- 'group' => $group,
- 'path' => $path,
- ]);
- }
- self::getGroup($group)
- ->set(CRM_Utils_Cache::cleanKey($path), $data, self::TTL);
- }
-
- /**
- * Delete all the cache elements that belong to a group OR delete the entire cache if group is not specified.
- *
- * @param string $group
- * The group name of the entries to be deleted.
- * @param string $path
- * Path of the item that needs to be deleted.
- */
- public static function deleteGroup($group = NULL, $path = NULL) {
- // FIXME: Generate a general deprecation notice.
-
- if ($path) {
- self::getGroup($group)->delete(CRM_Utils_Cache::cleanKey($path));
- }
- else {
- self::getGroup($group)->clear();
- }
- }
-
- /**
- * Cleanup any caches that we've mapped.
- *
- * Traditional SQL-backed caches are cleared as a matter of course during a
- * system flush (by way of "TRUNCATE TABLE civicrm_cache"). This provides
- * a spot where the adapter can
- */
- public static function clearDBCache() {
- foreach (self::getLegacyGroups() as $groupName) {
- $group = self::getGroup($groupName);
- $group->clear();
- }
- }
-
- /**
- * Get a list of known cache-groups
- *
- * @return array
- */
- public static function getLegacyGroups() {
- $groups = [
- // Universe
-
- // biz.jmaconsulting.lineitemedit
- 'lineitem-editor',
-
- // civihr/uk.co.compucorp.civicrm.hrcore
- 'HRCore_Info',
-
- ];
- // Handle Legacy Multisite caching group.
- $extensions = CRM_Extension_System::singleton()->getManager();
- $multisiteExtensionStatus = $extensions->getStatus('org.civicrm.multisite');
- if ($multisiteExtensionStatus == $extensions::STATUS_INSTALLED) {
- $extension_version = civicrm_api3('Extension', 'get', ['key' => 'org.civicrm.multisite'])['values'][0]['version'];
- if (version_compare($extension_version, '2.7', '<')) {
- Civi::log()->warning(
- 'CRM_Core_BAO_Cache_PSR is deprecated for multisite extension, you should upgrade to the latest version to avoid this warning, this code will be removed at the end of 2019',
- ['civi.tag' => 'deprecated']
- );
- $groups[] = 'descendant groups for an org';
- }
- }
- $entitySettingExtensionStatus = $extensions->getStatus('nz.co.fuzion.entitysetting');
- if ($multisiteExtensionStatus == $extensions::STATUS_INSTALLED) {
- $extension_version = civicrm_api3('Extension', 'get', ['key' => 'nz.co.fuzion.entitysetting'])['values'][0]['version'];
- if (version_compare($extension_version, '1.3', '<')) {
- Civi::log()->warning(
- 'CRM_Core_BAO_Cache_PSR is deprecated for entity setting extension, you should upgrade to the latest version to avoid this warning, this code will be removed at the end of 2019',
- ['civi.tag' => 'deprecated']
- );
- $groups[] = 'CiviCRM setting Spec';
- }
- }
- $atomFeedsSettingExtensionStatus = $extensions->getStatus('be.chiro.civi.atomfeeds');
- if ($atomFeedsSettingExtensionStatus == $extensions::STATUS_INSTALLED) {
- $extension_version = civicrm_api3('Extension', 'get', ['key' => 'be.chiro.civi.atomfeeds'])['values'][0]['version'];
- if (version_compare($extension_version, '0.1-alpha2', '<')) {
- Civi::log()->warning(
- 'CRM_Core_BAO_Cache_PSR is deprecated for Atomfeeds extension, you should upgrade to the latest version to avoid this warning, this code will be removed at the end of 2019',
- ['civi.tag' => 'deprecated']
- );
- $groups[] = 'dashboard';
- }
- }
- return $groups;
- }
-
-}
}
/**
- * Evaluate locale preferences and activate a chosen locale by
- * updating session+global variables.
+ * Activate a chosen locale.
+ *
+ * The locale is set by updating the session and global variables.
+ *
+ * When there is a choice of permitted languages (set on the "Administer" ->
+ * "Localisation" -> "Languages, Currency, Locations" screen) the locale to
+ * be applied can come from a variety of sources. The list below is the order
+ * of priority for deciding which of the sources "wins":
+ *
+ * - The request - when the "lcMessages" query variable is present in the URL.
+ * - The session - when the "lcMessages" session variable has been set.
+ * - Inherited from the CMS - when the "inheritLocale" setting is set.
+ * - CiviCRM settings - the fallback when none of the above set the locale.
+ *
+ * Single-language installs skip this and always set the default locale.
*
* @param \Civi\Core\SettingsBag $settings
* @param string $activatedLocales
* Imploded list of locales which are supported in the DB.
*/
public static function applyLocale($settings, $activatedLocales) {
- // are we in a multi-language setup?
- $multiLang = (bool) $activatedLocales;
- // set the current language
- $chosenLocale = NULL;
+ // Declare access to locale globals.
+ global $dbLocale, $tsLocale;
+ // Grab session reference.
$session = CRM_Core_Session::singleton();
- $permittedLanguages = CRM_Core_I18n::uiLanguages(TRUE);
+ // Set flag for multi-language setup.
+ $multiLang = (bool) $activatedLocales;
+
+ // Initialise the default and chosen locales.
+ $defaultLocale = $settings->get('lcMessages');
+ $chosenLocale = NULL;
- // The locale to be used can come from various places:
- // - the request (url)
- // - the session
- // - civicrm_uf_match
- // - inherited from the CMS
- // Only look at this if there is actually a choice of permitted languages
+ // When there is a choice of permitted languages.
+ $permittedLanguages = CRM_Core_I18n::uiLanguages(TRUE);
if (count($permittedLanguages) >= 2) {
+
+ // Is the "lcMessages" query variable present in the URL?
$requestLocale = CRM_Utils_Request::retrieve('lcMessages', 'String');
if (in_array($requestLocale, $permittedLanguages)) {
$chosenLocale = $requestLocale;
-
- //CRM-8559, cache navigation do not respect locale if it is changed, so reseting cache.
- // Ed: This doesn't sound good.
- // Civi::cache('navigation')->flush();
- }
- else {
- $requestLocale = NULL;
}
- if (!$requestLocale) {
+ // Check the session if the chosen locale hasn't been set yet.
+ if (empty($chosenLocale)) {
$sessionLocale = $session->get('lcMessages');
if (in_array($sessionLocale, $permittedLanguages)) {
$chosenLocale = $sessionLocale;
}
- else {
- $sessionLocale = NULL;
- }
}
- if ($requestLocale) {
- $ufm = new CRM_Core_DAO_UFMatch();
- $ufm->contact_id = $session->get('userID');
- if ($ufm->find(TRUE)) {
- $ufm->language = $chosenLocale;
- $ufm->save();
+ /*
+ * Maybe inherit the language from the CMS.
+ *
+ * If the language is specified via "lcMessages" we skip this, since the
+ * intention of the URL query var is to override all other sources.
+ */
+ if ($settings->get('inheritLocale') && empty($chosenLocale)) {
+
+ /*
+ * FIXME: On multi-language installs, CRM_Utils_System::getUFLocale() in
+ * many cases returns nothing if $dbLocale is not set, so set it to the
+ * default - even if it's overridden later.
+ */
+ $dbLocale = $multiLang && $defaultLocale ? "_{$defaultLocale}" : '';
+
+ // Retrieve locale as reported by CMS.
+ $cmsLocale = CRM_Utils_System::getUFLocale();
+ if (in_array($cmsLocale, $permittedLanguages)) {
+ $chosenLocale = $cmsLocale;
}
- $session->set('lcMessages', $chosenLocale);
- }
- if (!$chosenLocale and $session->get('userID')) {
- $ufm = new CRM_Core_DAO_UFMatch();
- $ufm->contact_id = $session->get('userID');
- if ($ufm->find(TRUE) &&
- in_array($ufm->language, $permittedLanguages)
- ) {
- $chosenLocale = $ufm->language;
+ // Clear chosen locale if not activated in multi-language CiviCRM.
+ if ($activatedLocales && !in_array($chosenLocale, explode(CRM_Core_DAO::VALUE_SEPARATOR, $activatedLocales))) {
+ $chosenLocale = NULL;
}
- $session->set('lcMessages', $chosenLocale);
+
}
- }
- global $dbLocale;
-
- // try to inherit the language from the hosting CMS
- // If the language is specified in the session (ie. via lcMessages) we still allow it to be overridden.
- if ($settings->get('inheritLocale') && empty($sessionLocale)) {
- // FIXME: On multilanguage installs, CRM_Utils_System::getUFLocale() in many cases returns nothing if $dbLocale is not set
- $lcMessages = $settings->get('lcMessages');
- $dbLocale = $multiLang && $lcMessages ? "_{$lcMessages}" : '';
- $chosenLocale = CRM_Utils_System::getUFLocale();
- if ($activatedLocales and !in_array($chosenLocale, explode(CRM_Core_DAO::VALUE_SEPARATOR, $activatedLocales))) {
- $chosenLocale = NULL;
+
+ // Assign the system default if the chosen locale hasn't been set.
+ if (empty($chosenLocale)) {
+ $chosenLocale = $defaultLocale;
}
+
+ // Always assign the chosen locale to the session.
+ $session->set('lcMessages', $chosenLocale);
+
}
+ else {
+
+ // CRM-11993 - Use default when it's a single-language install.
+ $chosenLocale = $defaultLocale;
- if (empty($chosenLocale)) {
- //CRM-11993 - if a single-lang site, use default
- $chosenLocale = $settings->get('lcMessages');
}
- // set suffix for table names - use views if more than one language
+ /*
+ * Set suffix for table names in multi-language installs.
+ * Use views if more than one language.
+ */
$dbLocale = $multiLang && $chosenLocale ? "_{$chosenLocale}" : '';
- // FIXME: an ugly hack to fix CRM-4041
- global $tsLocale;
+ // FIXME: an ugly hack to fix CRM-4041.
$tsLocale = $chosenLocale;
- // FIXME: as bad aplace as any to fix CRM-5428
- // (to be moved to a sane location along with the above)
+ /*
+ * FIXME: as bad a place as any to fix CRM-5428.
+ * (to be moved to a sane location along with the above)
+ */
if (function_exists('mb_internal_encoding')) {
mb_internal_encoding('UTF-8');
}
+
}
/**
CRM_Core_DAO::executeQuery($query);
}
- if ($adapter = CRM_Utils_Constant::value('CIVICRM_BAO_CACHE_ADAPTER')) {
- return $adapter::clearDBCache();
- }
-
// also delete all the import and export temp tables
self::clearTempTables();
}
public function addWizardStyle(&$wizard) {
$wizard['style'] = [
'barClass' => '',
- 'stepPrefixCurrent' => '<i class="crm-i fa-chevron-right" aria-hidden="true"></i> ',
- 'stepPrefixPast' => '<i class="crm-i fa-check" aria-hidden="true"></i> ',
+ 'stepPrefixCurrent' => '<i class="crm-i fa-chevron-right" aria-hidden="true"></i> ',
+ 'stepPrefixPast' => '<i class="crm-i fa-check" aria-hidden="true"></i> ',
'stepPrefixFuture' => ' ',
'subStepPrefixCurrent' => ' ',
'subStepPrefixPast' => ' ',
$options = &PEAR::getStaticProperty('DB_DataObject', 'options');
$options['database'] = $dsn;
$options['quote_identifiers'] = TRUE;
+ if (self::isSSLDSN($dsn)) {
+ // There are two different options arrays.
+ $other_options = &PEAR::getStaticProperty('DB', 'options');
+ $other_options['ssl'] = TRUE;
+ }
if (defined('CIVICRM_DAO_DEBUG')) {
self::DebugLevel(CIVICRM_DAO_DEBUG);
}
}
}
+ /**
+ * Does the DSN indicate the connection should use ssl.
+ *
+ * @param string $dsn
+ *
+ * @return bool
+ */
+ public static function isSSLDSN(string $dsn):bool {
+ // Note that ssl= below is not an official PEAR::DB option. It doesn't know
+ // what to do with it. We made it up because it's not required
+ // to have client-side certificates to use ssl, so here you can specify
+ // you want that by putting ssl=1 in the DSN string.
+ //
+ // Cast to bool in case of error which we interpret as no ssl.
+ return (bool) preg_match('/[\?&](key|cert|ca|capath|cipher|ssl)=/', $dsn);
+ }
+
}
if (CRM_Utils_Array::value('snippet', $_REQUEST) === CRM_Core_Smarty::PRINT_JSON) {
$out = [
'status' => 'fatal',
- 'content' => '<div class="messages status no-popup"><div class="icon inform-icon"></div>' . ts('Sorry but we are not able to provide this at the moment.') . '</div>',
+ 'content' => '<div class="messages status no-popup">' . CRM_Core_Page::crmIcon('fa-info-circle') . ' ' . ts('Sorry but we are not able to provide this at the moment.') . '</div>',
];
if ($config->backtrace && CRM_Core_Permission::check('view debug output')) {
$out['backtrace'] = self::parseBacktrace(debug_backtrace());
}
$file_log->close();
- // Use the custom fatalErrorHandler if defined
- if (in_array($priority, [PEAR_LOG_EMERG, PEAR_LOG_ALERT, PEAR_LOG_CRIT, PEAR_LOG_ERR])) {
- if ($config->fatalErrorHandler && function_exists($config->fatalErrorHandler)) {
- $name = $config->fatalErrorHandler;
- $vars = [
- 'debugLogMessage' => $message,
- 'priority' => $priority,
- ];
- $name($vars);
- }
- }
-
if (!isset(\Civi::$statics[__CLASS__]['userFrameworkLogging'])) {
// Set it to FALSE first & then try to set it. This is to prevent a loop as calling
// $config->userFrameworkLogging can trigger DB queries & under log mode this
$type, $name, $label = '',
$attributes = '', $required = FALSE, $extra = NULL
) {
+ if ($type === 'radio') {
+ CRM_Core_Error::deprecatedFunctionWarning('CRM_Core_Form::addRadio');
+ }
// Fudge some extra types that quickform doesn't support
$inputType = $type;
if ($type == 'wysiwyg' || in_array($type, self::$html5Types)) {
}
}
}
- $options[] = $this->createElement('radio', NULL, NULL, $var, $key, $optAttributes);
+ $element = $this->createElement('radio', NULL, NULL, $var, $key, $optAttributes);
+ if ($required) {
+ $element->setAttribute('required', TRUE);
+ }
+ $options[] = $element;
}
$group = $this->addGroup($options, $name, $title, $separator);
}
/**
- * @param $key
+ * The original version of this function, added circa 2010 and untouched
+ * since then, seemed intended to check for a 32-digit hex string followed
+ * optionally by an underscore and 4-digit number. But it had a bug where
+ * the optional part was never checked ever. So have decided to remove that
+ * second check to keep it simple since it seems like pseudo-security.
+ *
+ * @param string $key
*
* @return bool
*/
public static function valid($key) {
- // a valid key is a 32 digit hex number
- // followed by an optional _ and a number between 1 and 10000
- if (strpos('_', $key) !== FALSE) {
- list($hash, $seq) = explode('_', $key);
-
- // ensure seq is between 1 and 10000
- if (!is_numeric($seq) ||
- $seq < 1 ||
- $seq > 10000
- ) {
- return FALSE;
- }
- }
- else {
- $hash = $key;
- }
-
- // ensure that hash is a 32 digit hex number
- return (bool) preg_match('#[0-9a-f]{32}#i', $hash);
+ // ensure that key contains a 32 digit hex string
+ return (bool) preg_match('#[0-9a-f]{32}#i', $key);
}
}
catch (CRM_Core_Exception $e) {
Civi::log()->error('ipn_payment_callback_exception', [
'context' => [
- 'backtrace' => CRM_Core_Error::formatBacktrace(debug_backtrace()),
+ 'backtrace' => $e->getTraceAsString(),
+ 'message' => $e->getMessage(),
],
]);
}
*
* @return bool
*/
- public function recur(&$input, &$ids, &$objects, $first) {
+ public function recur($input, $ids, $objects, $first) {
$this->_isRecurring = TRUE;
$recur = &$objects['contributionRecur'];
$paymentProcessorObject = $objects['contribution']->_relatedObjects['paymentProcessor']['object'];
// do a subscription check
if ($recur->processor_id != $input['subscription_id']) {
- CRM_Core_Error::debug_log_message("Unrecognized subscription.");
- echo "Failure: Unrecognized subscription<p>";
+ CRM_Core_Error::debug_log_message('Unrecognized subscription.');
+ echo 'Failure: Unrecognized subscription<p>';
return FALSE;
}
$contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
- $transaction = new CRM_Core_Transaction();
-
$now = date('YmdHis');
//load new contribution object if required.
$recur->trxn_id = $recur->processor_id;
$isFirstOrLastRecurringPayment = CRM_Core_Payment::RECURRING_PAYMENT_START;
}
- $statusName = 'In Progress';
+
if (($recur->installments > 0) &&
($input['subscription_paynum'] >= $recur->installments)
) {
// this is the last payment
- $statusName = 'Completed';
$recur->end_date = $now;
$isFirstOrLastRecurringPayment = CRM_Core_Payment::RECURRING_PAYMENT_END;
+ // This end date update should occur in ContributionRecur::updateOnNewPayment
+ // testIPNPaymentRecurNoReceipt has test cover.
+ $recur->save();
}
- $recur->modified_date = $now;
- $recur->contribution_status_id = array_search($statusName, $contributionStatus);
- $recur->save();
}
else {
// Declined
$recur->cancel_date = $now;
$recur->save();
- $message = ts("Subscription payment failed - %1", [1 => htmlspecialchars($input['response_reason_text'])]);
+ $message = ts('Subscription payment failed - %1', [1 => htmlspecialchars($input['response_reason_text'])]);
CRM_Core_Error::debug_log_message($message);
// the recurring contribution has declined a payment or has failed
// check if contribution is already completed, if so we ignore this ipn
if ($objects['contribution']->contribution_status_id == 1) {
- $transaction->commit();
CRM_Core_Error::debug_log_message("Returning since contribution has already been handled.");
- echo "Success: Contribution has already been handled<p>";
+ echo 'Success: Contribution has already been handled<p>';
return TRUE;
}
- $this->completeTransaction($input, $ids, $objects, $transaction, $recur);
+ $this->completeTransaction($input, $ids, $objects);
// Only Authorize.net does this so it is on the a.net class. If there is a need for other processors
// to do this we should make it available via the api, e.g as a parameter, changing the nuance
* Get the input from passed in fields.
*
* @param array $input
- * @param array $ids
*
* @throws \CRM_Core_Exception
*/
- public function getInput(&$input, &$ids) {
+ public function getInput(&$input) {
$input['amount'] = $this->retrieve('x_amount', 'String');
$input['subscription_id'] = $this->retrieve('x_subscription_id', 'Integer');
$input['response_code'] = $this->retrieve('x_response_code', 'Integer');
$input['response_reason_text'] = $this->retrieve('x_response_reason_text', 'String', FALSE);
$input['subscription_paynum'] = $this->retrieve('x_subscription_paynum', 'Integer', FALSE, 0);
$input['trxn_id'] = $this->retrieve('x_trans_id', 'String', FALSE);
- $input['trxn_id'] = $this->retrieve('x_trans_id', 'String', FALSE);
$input['receive_date'] = $this->retrieve('receive_date', 'String', FALSE, date('YmdHis', strtotime('now')));
if ($input['trxn_id']) {
$input['trxn_id'] = md5(uniqid(rand(), TRUE));
}
- $billingID = $ids['billing'] = CRM_Core_BAO_LocationType::getBilling();
+ $billingID = CRM_Core_BAO_LocationType::getBilling();
$params = [
'first_name' => 'x_first_name',
'last_name' => 'x_last_name',
* @return bool
* @throws \CiviCRM_API3_Exception
*/
- public function failed(&$objects, &$transaction, $input = []) {
+ public function failed(&$objects, $transaction = NULL, $input = []) {
$contribution = &$objects['contribution'];
$memberships = [];
if (!empty($objects['membership'])) {
}
}
- $addLineItems = FALSE;
- if (empty($contribution->id)) {
- $addLineItems = TRUE;
- }
+ $addLineItems = empty($contribution->id);
$participant = &$objects['participant'];
-
- // CRM-15546
- $contributionStatuses = CRM_Core_PseudoConstant::get('CRM_Contribute_DAO_Contribution', 'contribution_status_id', [
- 'labelColumn' => 'name',
- 'flip' => 1,
- ]);
- $contribution->contribution_status_id = $contributionStatuses['Failed'];
- $contribution->receive_date = CRM_Utils_Date::isoToMysql($contribution->receive_date);
- $contribution->receipt_date = CRM_Utils_Date::isoToMysql($contribution->receipt_date);
- $contribution->thankyou_date = CRM_Utils_Date::isoToMysql($contribution->thankyou_date);
+ $contribution->contribution_status_id = CRM_Core_PseudoConstant::getKey('CRM_Contribute_DAO_Contribution', 'contribution_status_id', 'Failed');
$contribution->save();
// Add line items for recurring payments.
}
}
- $transaction->commit();
+ if ($transaction) {
+ $transaction->commit();
+ }
Civi::log()->debug("Setting contribution status to Failed");
return TRUE;
}
* @return bool
* @throws \CiviCRM_API3_Exception
*/
- public function cancelled(&$objects, &$transaction, $input = []) {
+ public function cancelled(&$objects, $transaction = NULL, $input = []) {
$contribution = &$objects['contribution'];
$memberships = [];
if (!empty($objects['membership'])) {
$this->cancelParticipant($participant->id);
}
}
- $transaction->commit();
+ if ($transaction) {
+ $transaction->commit();
+ }
Civi::log()->debug("Setting contribution status to Cancelled");
return TRUE;
}
* @param array $input
* @param array $ids
* @param array $objects
- * @param CRM_Core_Transaction $transaction
*
* @throws \CRM_Core_Exception
* @throws \CiviCRM_API3_Exception
*/
- public function completeTransaction(&$input, &$ids, &$objects, $transaction = NULL) {
- CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $objects, $transaction);
+ public function completeTransaction(&$input, &$ids, &$objects) {
+ CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $objects);
}
/**
* @param array $ids
* Related object IDs.
* @param array $objects
- * @param array $values
- * Values related to objects that have already been loaded.
- * @param bool $recur
- * Is it part of a recurring contribution.
- * @param bool $returnMessageText
- * Should text be returned instead of sent. This.
- * is because the function is also used to generate pdfs
- *
- * @return array
- * @throws \CRM_Core_Exception
+ *
* @throws \CiviCRM_API3_Exception
*/
- public function sendMail(&$input, &$ids, &$objects, &$values, $recur = FALSE, $returnMessageText = FALSE) {
- return CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $objects['contribution']->id, $values,
- $returnMessageText);
+ public function sendMail($input, $ids, $objects) {
+ CRM_Core_Error::deprecatedFunctionWarning('this should be done via completetransaction api');
+ civicrm_api3('Contribution', 'sendconfirmation', [
+ 'id' => $objects['contribution']->id,
+ ]);
}
}
return TRUE;
}
- /**
- * Submit a manual payment.
- *
- * @param array $params
- * Assoc array of input parameters for this transaction.
- *
- * @return array
- */
- public function doDirectPayment(&$params) {
- $statuses = CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id');
- if ($params['is_pay_later']) {
- $result['payment_status_id'] = array_search('Pending', $statuses);
- }
- else {
- $result['payment_status_id'] = array_search('Completed', $statuses);
- }
- return $result;
- }
-
/**
* Should a receipt be sent out for a pending payment.
*
* @param bool $first
*
* @return void
+ * @throws \CRM_Core_Exception
+ * @throws \CiviCRM_API3_Exception
*/
- public function single(&$input, &$ids, &$objects, $recur = FALSE, $first = FALSE) {
+ public function single($input, $ids, $objects, $recur = FALSE, $first = FALSE) {
$contribution = &$objects['contribution'];
// make sure the invoice is valid and matches what we have in the contribution record
$contribution->total_amount = $input['amount'];
}
- $transaction = new CRM_Core_Transaction();
-
$status = $input['paymentStatus'];
- if ($status == 'Denied' || $status == 'Failed' || $status == 'Voided') {
- return $this->failed($objects, $transaction);
+ if ($status === 'Denied' || $status === 'Failed' || $status === 'Voided') {
+ $this->failed($objects);
+ return;
}
if ($status === 'Pending') {
Civi::log()->debug('Returning since contribution status is Pending');
return;
}
- elseif ($status == 'Refunded' || $status == 'Reversed') {
- return $this->cancelled($objects, $transaction);
+ elseif ($status === 'Refunded' || $status === 'Reversed') {
+ $this->cancelled($objects);
+ return;
}
elseif ($status !== 'Completed') {
Civi::log()->debug('Returning since contribution status is not handled');
// check if contribution is already completed, if so we ignore this ipn
$completedStatusId = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
if ($contribution->contribution_status_id == $completedStatusId) {
- $transaction->commit();
Civi::log()->debug('PayPalIPN: Returning since contribution has already been handled. (ID: ' . $contribution->id . ').');
echo 'Success: Contribution has already been handled<p>';
return;
}
- $this->completeTransaction($input, $ids, $objects, $transaction, $recur);
+ $this->completeTransaction($input, $ids, $objects);
}
/**
$membershipID = $this->retrieve('membershipID', 'Integer', FALSE);
$contributionRecurID = $this->retrieve('contributionRecurID', 'Integer', FALSE);
- $this->getInput($input, $ids);
+ $this->getInput($input);
if ($component == 'event') {
$ids['event'] = $this->retrieve('eventID', 'Integer', TRUE);
return;
}
}
- $this->single($input, $ids, $objects, FALSE, FALSE);
+ $this->single($input, $ids, $objects);
}
/**
* @param array $input
- * @param array $ids
*
* @throws \CRM_Core_Exception
*/
- public function getInput(&$input, &$ids) {
- $billingID = $ids['billing'] = CRM_Core_BAO_LocationType::getBilling();
+ public function getInput(&$input) {
+ $billingID = CRM_Core_BAO_LocationType::getBilling();
$input['txnType'] = $this->retrieve('txn_type', 'String', FALSE);
$input['paymentStatus'] = $this->retrieve('payment_status', 'String', FALSE);
$input['invoice'] = $this->retrieve('invoice', 'String', TRUE);
/**
* Process recurring contributions.
+ *
* @param array $input
* @param array $ids
* @param array $objects
* @param bool $first
- * @return void
+ *
+ * @throws \CRM_Core_Exception
+ * @throws \CiviCRM_API3_Exception
*/
- public function recur(&$input, &$ids, &$objects, $first) {
+ public function recur($input, $ids, $objects, $first) {
if (!isset($input['txnType'])) {
Civi::log()->debug('PayPalProIPN: Could not find txn_type in input request.');
- echo "Failure: Invalid parameters<p>";
+ echo 'Failure: Invalid parameters<p>';
return;
}
// the contribution record
if ($recur->invoice_id != $input['invoice']) {
Civi::log()->debug('PayPalProIPN: Invoice values dont match between database and IPN request recur is ' . $recur->invoice_id . ' input is ' . $input['invoice']);
- echo "Failure: Invoice values dont match between database and IPN request recur is " . $recur->invoice_id . " input is " . $input['invoice'];
+ echo 'Failure: Invoice values dont match between database and IPN request recur is ' . $recur->invoice_id . " input is " . $input['invoice'];
return;
}
$contribution->total_amount = $input['amount'];
}
- $transaction = new CRM_Core_Transaction();
-
$status = $input['paymentStatus'];
- if ($status == 'Denied' || $status == 'Failed' || $status == 'Voided') {
- $this->failed($objects, $transaction);
+ if ($status === 'Denied' || $status === 'Failed' || $status === 'Voided') {
+ $this->failed($objects);
return;
}
if ($status === 'Pending') {
Civi::log()->debug('Returning since contribution status is Pending');
return;
}
- elseif ($status == 'Refunded' || $status == 'Reversed') {
- $this->cancelled($objects, $transaction);
+ elseif ($status === 'Refunded' || $status === 'Reversed') {
+ $this->cancelled($objects);
return;
}
elseif ($status !== 'Completed') {
// check if contribution is already completed, if so we ignore this ipn
$completedStatusId = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
if ($contribution->contribution_status_id == $completedStatusId) {
- $transaction->commit();
Civi::log()->debug('PayPalProIPN: Returning since contribution has already been handled.');
echo 'Success: Contribution has already been handled<p>';
return;
}
- $this->completeTransaction($input, $ids, $objects, $transaction, $recur);
+ $this->completeTransaction($input, $ids, $objects);
}
/**
$ids['contact'] = self::getValue('c', TRUE);
$ids['contribution'] = self::getValue('b', TRUE);
- $this->getInput($input, $ids);
+ $this->getInput($input);
if ($this->_component == 'event') {
$ids['event'] = self::getValue('e', TRUE);
/**
* @param array $input
- * @param array $ids
*
* @return void
* @throws CRM_Core_Exception
*/
- public function getInput(&$input, &$ids) {
- $billingID = $ids['billing'] = CRM_Core_BAO_LocationType::getBilling();
+ public function getInput(&$input) {
+ $billingID = CRM_Core_BAO_LocationType::getBilling();
$input['txnType'] = self::retrieve('txn_type', 'String', 'POST', FALSE);
$input['paymentStatus'] = self::retrieve('payment_status', 'String', 'POST', FALSE);
+++ /dev/null
-<?php
-/*
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC. All rights reserved. |
- | |
- | This work is published under the GNU AGPLv3 license with some |
- | permitted exceptions and without any warranty. For full license |
- | and copyright information, see https://civicrm.org/licensing |
- +--------------------------------------------------------------------+
- */
-
-
-/*
- * PxPay Functionality Copyright (C) 2008 Lucas Baker, Logistic Information Systems Limited (Logis)
- * PxAccess Functionality Copyright (C) 2008 Eileen McNaughton
- * Licensed to CiviCRM under the Academic Free License version 3.0.
- *
- * Grateful acknowledgements go to Donald Lobo for invaluable assistance
- * in creating this payment processor module
- */
-
-/**
- * Class CRM_Core_Payment_PaymentExpress
- */
-class CRM_Core_Payment_PaymentExpress extends CRM_Core_Payment {
- const CHARSET = 'iso-8859-1';
-
- protected $_mode = NULL;
-
- /**
- * Constructor.
- *
- * @param string $mode
- * The mode of operation: live or test.
- *
- * @param $paymentProcessor
- *
- * @return \CRM_Core_Payment_PaymentExpress
- */
- public function __construct($mode, &$paymentProcessor) {
-
- $this->_mode = $mode;
- $this->_paymentProcessor = $paymentProcessor;
- }
-
- /**
- * This function checks to see if we have the right config values.
- *
- * @internal param string $mode the mode we are operating in (live or test)
- *
- * @return string
- * the error message if any
- */
- public function checkConfig() {
- $config = CRM_Core_Config::singleton();
-
- $error = [];
-
- if (empty($this->_paymentProcessor['user_name'])) {
- $error[] = ts('UserID is not set in the Administer » System Settings » Payment Processors');
- }
-
- if (empty($this->_paymentProcessor['password'])) {
- $error[] = ts('pxAccess / pxPay Key is not set in the Administer » System Settings » Payment Processors');
- }
-
- if (!empty($error)) {
- return implode('<p>', $error);
- }
- else {
- return NULL;
- }
- }
-
- /**
- * This function collects all the information from a web/api form and invokes
- * the relevant payment processor specific functions to perform the transaction
- *
- * @param array $params
- * Assoc array of input parameters for this transaction.
- */
- public function doDirectPayment(&$params) {
- throw new CRM_Core_Exception(ts('This function is not implemented'));
- }
-
- /**
- * Main transaction function.
- *
- * @param array $params
- * Name value pair of contribution data.
- *
- * @param $component
- */
- public function doTransferCheckout(&$params, $component) {
- // This is broken - in 2015 this commit broke it... https://github.com/civicrm/civicrm-core/commit/204c86d59f0cfc4c4d917cc245fb41633d36916e#diff-b00e65c9829c27da8b34e35f2e64d9b6L114
- $component = strtolower($component);
- $config = CRM_Core_Config::singleton();
- if ($component != 'contribute' && $component != 'event') {
- throw new CRM_Core_Exception(ts('Component is invalid'));
- }
-
- $url = CRM_Utils_System::externUrl('extern/pxIPN');
-
- if ($component == 'event') {
- $cancelURL = CRM_Utils_System::url('civicrm/event/register',
- "_qf_Confirm_display=true&qfKey={$params['qfKey']}",
- FALSE, NULL, FALSE
- );
- }
- elseif ($component == 'contribute') {
- $cancelURL = CRM_Utils_System::url('civicrm/contribute/transact',
- "_qf_Confirm_display=true&qfKey={$params['qfKey']}",
- FALSE, NULL, FALSE
- );
- }
-
- /*
- * Build the private data string to pass to DPS, which they will give back to us with the
- *
- * transaction result. We are building this as a comma-separated list so as to avoid long URLs.
- *
- * Parameters passed: a=contactID, b=contributionID,c=contributionTypeID,d=invoiceID,e=membershipID,f=participantID,g=eventID
- */
-
- $privateData = "a={$params['contactID']},b={$params['contributionID']},c={$params['contributionTypeID']},d={$params['invoiceID']}";
-
- if ($component == 'event') {
- $merchantRef = substr($params['contactID'] . "-" . $params['contributionID'] . " " . substr($params['description'], 27, 20), 0, 24);
- $privateData .= ",f={$params['participantID']},g={$params['eventID']}";
- }
- elseif ($component == 'contribute') {
- $membershipID = $params['membershipID'] ?? NULL;
- if ($membershipID) {
- $privateData .= ",e=$membershipID";
- }
- $merchantRef = substr($params['contactID'] . "-" . $params['contributionID'] . " " . substr($params['description'], 20, 20), 0, 24);
-
- }
-
- $dpsParams = [
- 'AmountInput' => str_replace(",", "", number_format($params['amount'], 2)),
- 'CurrencyInput' => $params['currencyID'],
- 'MerchantReference' => $merchantRef,
- 'TxnData1' => $params['qfKey'],
- 'TxnData2' => $privateData,
- 'TxnData3' => $component . "," . $this->_paymentProcessor['id'],
- 'TxnType' => 'Purchase',
- // Leave this empty for now, causes an error with DPS if we populate it
- 'TxnId' => '',
- 'UrlFail' => $url,
- 'UrlSuccess' => $url,
- ];
- // Allow further manipulation of params via custom hooks
- CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $dpsParams);
-
- /*
- * determine whether method is pxaccess or pxpay by whether signature (mac key) is defined
- */
-
- if (empty($this->_paymentProcessor['signature'])) {
- /*
- * Processor is pxpay
- *
- * This contains the XML/Curl functions we'll need to generate the XML request
- */
-
- $dpsParams['PxPayUserId'] = $this->_paymentProcessor['user_name'];
- $dpsParams['PxPayKey'] = $this->_paymentProcessor['password'];
- // Build a valid XML string to pass to DPS
- $generateRequest = CRM_Core_Payment_PaymentExpressUtils::_valueXml($dpsParams);
-
- $generateRequest = CRM_Core_Payment_PaymentExpressUtils::_valueXml('GenerateRequest', $generateRequest);
- // Get the special validated URL back from DPS by sending them the XML we've generated
- $curl = CRM_Core_Payment_PaymentExpressUtils::_initCURL($generateRequest, $this->_paymentProcessor['url_site']);
- $success = FALSE;
-
- if ($response = curl_exec($curl)) {
- curl_close($curl);
- $valid = CRM_Core_Payment_PaymentExpressUtils::_xmlAttribute($response, 'valid');
- if (1 == $valid) {
- // the request was validated, so we'll get the URL and redirect to it
- $uri = CRM_Core_Payment_PaymentExpressUtils::_xmlElement($response, 'URI');
- CRM_Utils_System::redirect($uri);
- }
- else {
- // redisplay confirmation page
- CRM_Utils_System::redirect($cancelURL);
- }
- }
- else {
- // calling DPS failed
- throw new CRM_Core_Exception(ts('Unable to establish connection to the payment gateway.'));
- }
- }
- else {
- $processortype = "pxaccess";
- require_once 'PaymentExpress/pxaccess.inc.php';
- // URL
- $PxAccess_Url = $this->_paymentProcessor['url_site'];
- // User ID
- $PxAccess_Userid = $this->_paymentProcessor['user_name'];
- // Your DES Key from DPS
- $PxAccess_Key = $this->_paymentProcessor['password'];
- // Your MAC key from DPS
- $Mac_Key = $this->_paymentProcessor['signature'];
-
- $pxaccess = new PxAccess($PxAccess_Url, $PxAccess_Userid, $PxAccess_Key, $Mac_Key);
- $request = new PxPayRequest();
- $request->setAmountInput($dpsParams['AmountInput']);
- $request->setTxnData1($dpsParams['TxnData1']);
- $request->setTxnData2($dpsParams['TxnData2']);
- $request->setTxnData3($dpsParams['TxnData3']);
- $request->setTxnType($dpsParams['TxnType']);
- $request->setInputCurrency($dpsParams['InputCurrency']);
- $request->setMerchantReference($dpsParams['MerchantReference']);
- $request->setUrlFail($dpsParams['UrlFail']);
- $request->setUrlSuccess($dpsParams['UrlSuccess']);
- $request_string = $pxaccess->makeRequest($request);
- CRM_Utils_System::redirect($request_string);
- }
- }
-
-}
+++ /dev/null
-<?php
-/*
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC. All rights reserved. |
- | |
- | This work is published under the GNU AGPLv3 license with some |
- | permitted exceptions and without any warranty. For full license |
- | and copyright information, see https://civicrm.org/licensing |
- +--------------------------------------------------------------------+
- */
-
-
-/*
- * PxPay Functionality Copyright (C) 2008 Lucas Baker, Logistic Information Systems Limited (Logis)
- * PxAccess Functionality Copyright (C) 2008 Eileen McNaughton
- * Licensed to CiviCRM under the Academic Free License version 3.0.
- *
- * Grateful acknowledgements go to Donald Lobo for invaluable assistance
- * in creating this payment processor module
- */
-
-/**
- * Class CRM_Core_Payment_PaymentExpressUtils
- */
-class CRM_Core_Payment_PaymentExpressUtils {
-
- /**
- * @param $element
- * @param null $value
- *
- * @return string
- */
- public static function _valueXml($element, $value = NULL) {
- $nl = "\n";
-
- if (is_array($element)) {
- $xml = '';
- foreach ($element as $elem => $value) {
- $xml .= self::_valueXml($elem, $value);
- }
- return $xml;
- }
- return "<" . $element . ">" . $value . "</" . $element . ">" . $nl;
- }
-
- /**
- * @param $xml
- * @param string $name
- *
- * @return mixed
- */
- public static function _xmlElement($xml, $name) {
- $value = preg_replace('/.*<' . $name . '[^>]*>(.*)<\/' . $name . '>.*/', '\1', $xml);
- return $value;
- }
-
- /**
- * @param $xml
- * @param string $name
- *
- * @return mixed|null
- */
- public static function _xmlAttribute($xml, $name) {
- $value = preg_replace('/<.*' . $name . '="([^"]*)".*>/', '\1', $xml);
- return $value != $xml ? $value : NULL;
- }
-
- /**
- * @param $query
- * @param $url
- *
- * @return resource
- */
- public static function &_initCURL($query, $url) {
- $curl = curl_init();
-
- curl_setopt($curl, CURLOPT_URL, $url);
- curl_setopt($curl, CURLOPT_FRESH_CONNECT, TRUE);
- curl_setopt($curl, CURLOPT_POST, TRUE);
- curl_setopt($curl, CURLOPT_POSTFIELDS, $query);
- curl_setopt($curl, CURLOPT_TIMEOUT, 30);
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
- if (ini_get('open_basedir') == '' && ini_get('safe_mode') == 'Off') {
- curl_setopt($curl, CURLOPT_FOLLOWLOCATION, FALSE);
- }
- curl_setopt($curl, CURLOPT_HEADER, 0);
- curl_setopt($curl, CURLOPT_SSLVERSION, 0);
-
- if (strtoupper(substr(@php_uname('s'), 0, 3)) === 'WIN') {
- curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, Civi::settings()->get('verifySSL'));
- curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, Civi::settings()->get('verifySSL') ? 2 : 0);
- }
- return $curl;
- }
-
-}
if (strpos($icon, 'fa-') !== 0) {
$icon = "fa-$icon";
}
- $iconMarkup = "<i class='crm-i $icon' aria-hidden=\"true\"></i> ";
+ $iconMarkup = "<i class='crm-i $icon' aria-hidden=\"true\"></i> ";
}
// All other params are treated as html attributes
CRM_Utils_Array::remove($params, 'icon', 'p', 'q', 'a', 'f', 'h', 'fb', 'fe');
unset($dupePairs[$index]);
continue;
}
- if (($result = self::dedupePair($dupes, $mode, $checkPermissions, $cacheKeyString)) === FALSE) {
+ CRM_Utils_Hook::merge('flip', $dupes, $dupes['dstID'], $dupes['srcID']);
+ if (($result = self::dedupePair((int) $dupes['dstID'], (int) $dupes['srcID'], $mode, $checkPermissions, $cacheKeyString)) === FALSE) {
unset($dupePairs[$index]);
continue;
}
}
/**
- * Compare 2 addresses to see if they are the same.
+ * Compare 2 addresses to see if they are the effectively the same.
+ *
+ * Being the same would mean same location type and any populated fields that describe the locationn match.
+ *
+ * Metadata fields such as is_primary, on_hold, manual_geocode may differ.
*
* @param array $mainAddress
* @param array $comparisonAddress
return TRUE;
}
+ /**
+ * Does the location array have valid data.
+ *
+ * While not UI-creatable some sites wind up with email or address rows with no actual email or address
+ * through non core-UI processes.
+ *
+ * @param array $location
+ *
+ * @return bool
+ */
+ public static function locationHasData($location) {
+ return !empty(self::getLocationDataFields($location));
+ }
+
+ /**
+ * Get the location data from a location array, filtering out metadata.
+ *
+ * This returns data like street_address but not metadata like is_primary, on_hold etc.
+ *
+ * @param array $location
+ *
+ * @return mixed
+ */
+ public static function getLocationDataFields($location) {
+ $keysToIgnore = array_merge(self::ignoredFields(), ['display', 'location_type_id']);
+ foreach ($location as $field => $value) {
+ if (in_array($field, $keysToIgnore, TRUE)) {
+ unset($location[$field]);
+ }
+ }
+ return $location;
+ }
+
/**
* A function to build an array of information about location blocks that is
* required when merging location fields
/**
* Dedupe a pair of contacts.
*
- * @param array $dupes
+ * @param int $mainId Id of contact to keep.
+ * @param int $otherId Id of contact to delete.
* @param string $mode
* @param bool $checkPermissions
* @param string $cacheKeyString
*
* @return bool|array
+ * @throws \API_Exception
* @throws \CRM_Core_Exception
+ * @throws \CRM_Core_Exception_ResourceConflictException
* @throws \CiviCRM_API3_Exception
- * @throws \API_Exception
+ * @throws \Civi\API\Exception\UnauthorizedException
*/
- protected static function dedupePair($dupes, $mode = 'safe', $checkPermissions = TRUE, $cacheKeyString = NULL) {
- CRM_Utils_Hook::merge('flip', $dupes, $dupes['dstID'], $dupes['srcID']);
- $mainId = $dupes['dstID'];
- $otherId = $dupes['srcID'];
+ protected static function dedupePair(int $mainId, int $otherId, $mode = 'safe', $checkPermissions = TRUE, $cacheKeyString = NULL) {
$resultStats = [];
- if (!$mainId || !$otherId) {
- // return error
- return FALSE;
- }
$migrationInfo = [];
$conflicts = [];
// Try to lock the contacts before we load the data as we don't want it changing under us.
// If it exists on the 'main' contact already, skip it. Otherwise
// if the location type exists already, log a conflict.
foreach ($migrationInfo['main_details']['location_blocks'][$fieldName] as $mainAddressKey => $mainAddressRecord) {
+ if (!self::locationHasData($mainAddressRecord)) {
+ // Go ahead & overwrite the main address - it has no data in it.
+ // if it is the primary address then pass that honour to the address that actually has data.
+ $migrationInfo['location_blocks'][$fieldName][$mainAddressKey]['set_other_primary'] = $mainAddressRecord['is_primary'];
+ continue;
+ }
if (self::locationIsSame($addressRecord, $mainAddressRecord)) {
unset($migrationInfo[$key]);
- break;
+ continue;
}
- elseif ($addressRecordLocTypeId == $mainAddressRecord['location_type_id']) {
+ if ($addressRecordLocTypeId == $mainAddressRecord['location_type_id']) {
$conflicts[$key] = NULL;
- break;
+ continue;
}
}
}
* Evaluate whether a participant record is eligible for self-service transfer/cancellation. If so,
* return additional participant/event details.
*
- * TODO: BAO-level functions shouldn't set a redirect, and it should be possible to return "false" to the
- * calling function. The next refactor will add a fourth param $errors, which can be passed by reference
- * from the calling function. Instead of redirecting, we will return the error.
- * TODO: This function should always return FALSE when self-service has been disabled on an event.
- * TODO: This function fails when the "hours until self-service" is greater than 24 or less than zero.
+ * TODO: This function fails when the "hours until self-service" is less than zero.
* @param int $participantId
* @param string $url
* @param bool $isBackOffice
*/
- public static function getSelfServiceEligibility($participantId, $url, $isBackOffice) {
+ public static function getSelfServiceEligibility(int $participantId, string $url, bool $isBackOffice) : array {
$optionGroupId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'participant_role', 'id', 'name');
$query = "
- SELECT cpst.name as status, cov.name as role, cp.fee_level, cp.fee_amount, cp.register_date, cp.status_id, ce.start_date, ce.title, cp.event_id
+ SELECT cpst.name as status, cov.name as role, cp.fee_level, cp.fee_amount, cp.register_date, cp.status_id, ce.start_date, ce.title, cp.event_id, ce.allow_selfcancelxfer
FROM civicrm_participant cp
LEFT JOIN civicrm_participant_status_type cpst ON cpst.id = cp.status_id
LEFT JOIN civicrm_option_value cov ON cov.value = cp.role_id and cov.option_group_id = {$optionGroupId}
WHERE cp.id = {$participantId}";
$dao = CRM_Core_DAO::executeQuery($query);
while ($dao->fetch()) {
+ $details['eligible'] = TRUE;
$details['status'] = $dao->status;
$details['role'] = $dao->role;
$details['fee_level'] = trim($dao->fee_level, CRM_Core_DAO::VALUE_SEPARATOR);
$details['fee_amount'] = $dao->fee_amount;
$details['register_date'] = $dao->register_date;
$details['event_start_date'] = $dao->start_date;
+ $details['allow_selfcancelxfer'] = $dao->allow_selfcancelxfer;
$eventTitle = $dao->title;
$eventId = $dao->event_id;
}
+ if (!$details['allow_selfcancelxfer']) {
+ $details['eligible'] = FALSE;
+ $details['ineligible_message'] = ts('This event registration can not be transferred or cancelled. Contact the event organizer if you have questions.');
+ return $details;
+ }
//verify participant status is still Registered
if ($details['status'] != 'Registered') {
- $status = "You cannot transfer or cancel your registration for " . $eventTitle . ' as you are not currently registered for this event.';
- CRM_Core_Session::setStatus($status, ts('Sorry'), 'alert');
- CRM_Utils_System::redirect($url);
+ $details['eligible'] = FALSE;
+ $details['ineligible_message'] = "You cannot transfer or cancel your registration for " . $eventTitle . ' as you are not currently registered for this event.';
+ return $details;
}
+ // Determine if it's too late to self-service cancel/transfer.
$query = "select start_date as start, selfcancelxfer_time as time from civicrm_event where id = " . $eventId;
$dao = CRM_Core_DAO::executeQuery($query);
while ($dao->fetch()) {
$time_limit = $dao->time;
$start_date = $dao->start;
}
- $start_time = new Datetime($start_date);
$timenow = new Datetime();
- if (!$isBackOffice && !empty($start_time) && $start_time < $timenow) {
- $status = ts('Registration for this event cannot be cancelled or transferred once the event has begun. Contact the event organizer if you have questions.');
- CRM_Core_Error::statusBounce($status, $url, ts('Sorry'));
- }
- if (!$isBackOffice && !empty($time_limit) && $time_limit > 0) {
- $interval = $timenow->diff($start_time);
- $days = $interval->format('%d');
- $hours = $interval->format('%h');
- if ($hours <= $time_limit && $days < 1) {
- $status = ts("Registration for this event cannot be cancelled or transferred less than %1 hours prior to the event's start time. Contact the event organizer if you have questions.", [1 => $time_limit]);
- CRM_Core_Error::statusBounce($status, $url, ts('Sorry'));
+ if (!$isBackOffice && !empty($time_limit)) {
+ $cancelHours = abs($time_limit);
+ $cancelInterval = new DateInterval("PT${cancelHours}H");
+ $cancelInterval->invert = $time_limit < 0 ? 1 : 0;
+ $cancelDeadline = (new Datetime($start_date))->sub($cancelInterval);
+ if ($timenow > $cancelDeadline) {
+ $details['eligible'] = FALSE;
+ $details['ineligible_message'] = ts("Registration for this event cannot be cancelled or transferred less than %1 hours prior to the event's start time. Contact the event organizer if you have questions.", [1 => $time_limit]);
}
}
return $details;
}
}
}
+ $form->_priceSet['id'] = $form->_priceSet['id'] ?? $form->_priceSetId;
$form->assign('priceSet', $form->_priceSet);
}
else {
$this->_userContext = $session->readUserContext();
$this->_from_participant_id = CRM_Utils_Request::retrieve('pid', 'Positive', $this, FALSE, NULL, 'REQUEST');
$this->_userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this, FALSE, NULL, 'REQUEST');
- $this->isBackoffice = CRM_Utils_Request::retrieve('is_backoffice', 'String', $this, FALSE, NULL, 'REQUEST');
+ $this->isBackoffice = CRM_Utils_Request::retrieve('is_backoffice', 'String', $this, FALSE, NULL, 'REQUEST') ?? FALSE;
$params = ['id' => $this->_from_participant_id];
$participant = $values = [];
$this->_participant = CRM_Event_BAO_Participant::getValues($params, $values, $participant);
$details = CRM_Event_BAO_Participant::participantDetails($this->_from_participant_id);
$selfServiceDetails = CRM_Event_BAO_Participant::getSelfServiceEligibility($this->_from_participant_id, $url, $this->isBackoffice);
+ if (!$selfServiceDetails['eligible']) {
+ CRM_Core_Error::statusBounce($selfServiceDetails['ineligible_message'], $url, ts('Sorry'));
+ }
$details = array_merge($details, $selfServiceDetails);
$this->assign('details', $details);
//This participant row will be cancelled. Get line item(s) to cancel
$participant = $values = [];
$this->_participant_id = CRM_Utils_Request::retrieve('pid', 'Positive', $this, FALSE, NULL, 'REQUEST');
$this->_userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this, FALSE, NULL, 'REQUEST');
- $this->isBackoffice = CRM_Utils_Request::retrieve('is_backoffice', 'String', $this, FALSE, NULL, 'REQUEST');
+ $this->isBackoffice = CRM_Utils_Request::retrieve('is_backoffice', 'String', $this, FALSE, FALSE, 'REQUEST') ?? FALSE;
$params = ['id' => $this->_participant_id];
$this->_participant = CRM_Event_BAO_Participant::getValues($params, $values, $participant);
$this->_part_values = $values[$this->_participant_id];
$contributionId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_ParticipantPayment', $this->_participant_id, 'contribution_id', 'participant_id');
$this->assign('contributionId', $contributionId);
$selfServiceDetails = CRM_Event_BAO_Participant::getSelfServiceEligibility($this->_participant_id, $url, $this->isBackoffice);
+ if (!$selfServiceDetails['eligible']) {
+ CRM_Core_Error::statusBounce($selfServiceDetails['ineligible_message'], $url, ts('Sorry'));
+ }
$details = array_merge($details, $selfServiceDetails);
$this->assign('details', $details);
$this->selfsvcupdateUrl = CRM_Utils_System::url('civicrm/event/selfsvcupdate', "reset=1&id={$this->_participant_id}&id=0");
$addPaymentHeader = FALSE;
- list($outputColumns, $metadata) = $processor->getExportStructureArrays();
+ list($outputColumns) = $processor->getExportStructureArrays();
if ($processor->isMergeSameAddress()) {
foreach (array_keys($processor->getAdditionalFieldsForSameAddressMerge()) as $field) {
while ($iterationDAO->fetch()) {
$count++;
$rowsThisIteration++;
- $row = $processor->buildRow($query, $iterationDAO, $outputColumns, $metadata, $paymentDetails, $addPaymentHeader);
+ $row = $processor->buildRow($query, $iterationDAO, $outputColumns, $paymentDetails, $addPaymentHeader);
if ($row === FALSE) {
continue;
}
// These oddly constructed keys are for legacy reasons. Altering them will affect test success
// but in time it may be good to rationalise them.
$label = $this->getOutputSpecificationLabel($key, $relationshipType, $locationType, $entityLabel);
- $index = $this->getOutputSpecificationIndex($key, $relationshipType, $locationType, $entityLabel);
- $fieldKey = $this->getOutputSpecificationFieldKey($key, $relationshipType, $locationType, $entityLabel);
+ $index = $this->getOutputSpecificationIndex($key, $relationshipType, $locationType, $entityTypeID);
+ $fieldKey = $this->getOutputSpecificationFieldKey($key, $relationshipType, $locationType, $entityTypeID);
$this->outputSpecification[$index]['header'] = $label;
$this->outputSpecification[$index]['sql_columns'] = $this->getSqlColumnDefinition($fieldKey, $key);
* @param \CRM_Contact_BAO_Query $query
* @param CRM_Core_DAO $iterationDAO
* @param array $outputColumns
- * @param $metadata
* @param $paymentDetails
* @param $addPaymentHeader
*
* @return array|bool
*/
- public function buildRow($query, $iterationDAO, $outputColumns, $metadata, $paymentDetails, $addPaymentHeader) {
+ public function buildRow($query, $iterationDAO, $outputColumns, $paymentDetails, $addPaymentHeader) {
$paymentTableId = $this->getPaymentTableID();
if ($this->isHouseholdToSkip($iterationDAO->contact_id)) {
return FALSE;
$this->buildRelationshipFieldsForRow($row, $iterationDAO->contact_id, $value, $field);
}
else {
- $row[$field] = $this->getTransformedFieldValue($field, $iterationDAO, $fieldValue, $metadata, $paymentDetails);
+ $row[$field] = $this->getTransformedFieldValue($field, $iterationDAO, $fieldValue, $paymentDetails);
}
}
* @param $field
* @param $iterationDAO
* @param $fieldValue
- * @param $metadata
* @param $paymentDetails
*
* @return string
+ * @throws \CRM_Core_Exception
+ * @throws \CiviCRM_API3_Exception
*/
- public function getTransformedFieldValue($field, $iterationDAO, $fieldValue, $metadata, $paymentDetails) {
+ public function getTransformedFieldValue($field, $iterationDAO, $fieldValue, $paymentDetails) {
$i18n = CRM_Core_I18n::singleton();
if ($field == 'id') {
return $i18n->crm_translate($fieldValue);
default:
- $fieldSpec = $metadata[$field] ?? [];
+ $fieldSpec = $this->outputSpecification[$this->getMungedFieldName($field)]['metadata'];
// No I don't know why we do it this way & whether we could
// make better use of pseudoConstants.
if (!empty($fieldSpec['context'])) {
return $i18n->crm_translate($fieldValue, $fieldSpec);
}
- if (!empty($fieldSpec['pseudoconstant'])) {
+ if (!empty($fieldSpec['pseudoconstant']) && !empty($fieldSpec['hasLocationType'])) {
if (!empty($fieldSpec['bao'])) {
- return CRM_Core_PseudoConstant::getLabel($fieldSpec['bao'], $fieldSpec['name'], $fieldValue);
+ $transformedValue = CRM_Core_PseudoConstant::getLabel($fieldSpec['bao'], $fieldSpec['name'], $fieldValue);
+ if ($transformedValue) {
+ return $transformedValue;
+ }
+ return $fieldValue;
}
- // 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 = $fieldSpec['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;
}
}
* yet find a way to comment them for posterity.
*/
public function getExportStructureArrays() {
- $outputColumns = $metadata = [];
+ $outputColumns = [];
$queryFields = $this->getQueryFields();
foreach ($this->getReturnProperties() as $key => $value) {
if (($key != 'location' || !is_array($value)) && !$this->isRelationshipTypeKey($key)) {
$daoFieldName .= "-" . $type[1];
}
$this->addOutputSpecification($actualDBFieldName, NULL, $locationType, CRM_Utils_Array::value(1, $type));
- $metadata[$daoFieldName] = $this->getMetaDataForField($actualDBFieldName);
$outputColumns[$daoFieldName] = TRUE;
}
}
}
}
- return [$outputColumns, $metadata];
+ return [$outputColumns];
}
/**
*/
public function getPreview($limit) {
$rows = [];
- list($outputColumns, $metadata) = $this->getExportStructureArrays();
+ list($outputColumns) = $this->getExportStructureArrays();
$query = $this->runQuery([], '');
CRM_Core_DAO::disableFullGroupByMode();
$result = CRM_Core_DAO::executeQuery($query[1] . ' LIMIT ' . (int) $limit);
CRM_Core_DAO::reenableFullGroupByMode();
while ($result->fetch()) {
- $rows[] = $this->buildRow($query[0], $result, $outputColumns, $metadata, [], []);
+ $rows[] = $this->buildRow($query[0], $result, $outputColumns, [], []);
}
return $rows;
}
$paymentTrxnParams['status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Refunded');
}
+ //If Payment is recorded on Failed contribution, update it to Pending.
+ if ($contributionStatus === 'Failed' && $params['total_amount'] > 0) {
+ //Enter a financial trxn to record a payment in receivable account
+ //as failed transaction does not insert any trxn values. Hence, if Payment is
+ //recorded on a failed contribution, the transition happens from Failed -> Pending -> Completed.
+ $ftParams = array_merge($paymentTrxnParams, [
+ 'from_financial_account_id' => NULL,
+ 'to_financial_account_id' => $accountsReceivableAccount,
+ 'is_payment' => 0,
+ 'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending'),
+ ]);
+ CRM_Core_BAO_FinancialTrxn::create($ftParams);
+ $contributionStatus = 'Pending';
+ self::updateContributionStatus($contribution['id'], $contributionStatus);
+ }
$trxn = CRM_Core_BAO_FinancialTrxn::create($paymentTrxnParams);
if ($params['total_amount'] < 0 && !empty($params['cancelled_payment_id'])) {
\Civi::log('Parameter $ids is no longer used by Mailing::create. Use the api or just pass $params', ['civi.tag' => 'deprecated']);
}
+ // CRM-#1843
+ // If it is a mass sms, set url_tracking to false
+ if (!empty($params['sms_provider_id'])) {
+ $params['url_tracking'] = 0;
+ }
+
// CRM-12430
// Do the below only for an insert
// for an update, we should not set the defaults
$component->id = $mailing->reply_id;
$component->find(TRUE);
- $message = new Mail_Mime("\n");
-
$domain = CRM_Core_BAO_Domain::getDomain();
list($domainEmailName, $_) = CRM_Core_BAO_Domain::getNameAndEmail();
- $headers = [
- 'Subject' => $component->subject,
- 'To' => $to,
- 'From' => "\"$domainEmailName\" <" . CRM_Core_BAO_Domain::getNoReplyEmailAddress() . '>',
- 'Reply-To' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
- 'Return-Path' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+ $params = [
+ 'subject' => $component->subject,
+ 'toEmail' => $to,
+ 'from' => "\"$domainEmailName\" <" . CRM_Core_BAO_Domain::getNoReplyEmailAddress() . '>',
+ 'replyTo' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+ 'returnPath' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
];
// TODO: do we need reply tokens?
if ($eq->format == 'HTML' || $eq->format == 'Both') {
$html = CRM_Utils_Token::replaceDomainTokens($html, $domain, TRUE, $tokens['html']);
$html = CRM_Utils_Token::replaceMailingTokens($html, $mailing, NULL, $tokens['html']);
- $message->setHTMLBody($html);
}
if (!$html || $eq->format == 'Text' || $eq->format == 'Both') {
$text = CRM_Utils_Token::replaceDomainTokens($text, $domain, FALSE, $tokens['text']);
$text = CRM_Utils_Token::replaceMailingTokens($text, $mailing, NULL, $tokens['text']);
- $message->setTxtBody($text);
}
+ $params['html'] = $html;
+ $params['text'] = $text;
- $b = CRM_Utils_Mail::setMimeParams($message);
- $h = $message->headers($headers);
- CRM_Mailing_BAO_Mailing::addMessageIdHeader($h, 'a', $eq->job_id, queue_id, $eq->hash);
-
- $mailer = \Civi::service('pear_mail');
- if (is_object($mailer)) {
- $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
- $mailer->send($to, $h, $b);
- unset($errorScope);
+ CRM_Mailing_BAO_Mailing::addMessageIdHeader($params, 'a', $eq->job_id, queue_id, $eq->hash);
+ if (CRM_Core_BAO_MailSettings::includeMessageId()) {
+ $params['messageId'] = $params['Message-ID'];
}
+ CRM_Utils_Mail::send($params);
}
/**
}
}
- $message = new Mail_mime("\n");
-
list($addresses, $urls) = CRM_Mailing_BAO_Mailing::getVerpAndUrls($job, $queue_id, $eq->hash, $eq->email);
$bao = new CRM_Mailing_BAO_Mailing();
$bao->body_text = $text;
$html = CRM_Utils_Token::replaceResubscribeTokens($html, $domain, $groups, TRUE, $eq->contact_id, $eq->hash);
$html = CRM_Utils_Token::replaceActionTokens($html, $addresses, $urls, TRUE, $tokens['html']);
$html = CRM_Utils_Token::replaceMailingTokens($html, $dao, NULL, $tokens['html']);
- $message->setHTMLBody($html);
}
if (!$html || $eq->format == 'Text' || $eq->format == 'Both') {
$text = CRM_Utils_Token::replaceDomainTokens($text, $domain, TRUE, $tokens['text']);
$text = CRM_Utils_Token::replaceResubscribeTokens($text, $domain, $groups, FALSE, $eq->contact_id, $eq->hash);
$text = CRM_Utils_Token::replaceActionTokens($text, $addresses, $urls, FALSE, $tokens['text']);
$text = CRM_Utils_Token::replaceMailingTokens($text, $dao, NULL, $tokens['text']);
- $message->setTxtBody($text);
}
- $headers = [
- 'Subject' => $component->subject,
- 'From' => "\"$domainEmailName\" <" . CRM_Core_BAO_Domain::getNoReplyEmailAddress() . '>',
- 'To' => $eq->email,
- 'Reply-To' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
- 'Return-Path' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+ $params = [
+ 'subject' => $component->subject,
+ 'from' => "\"$domainEmailName\" <" . CRM_Core_BAO_Domain::getNoReplyEmailAddress() . '>',
+ 'toEmail' => $eq->email,
+ 'replyTo' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+ 'returnPath' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+ 'html' => $html,
+ 'text' => $text,
];
- CRM_Mailing_BAO_Mailing::addMessageIdHeader($headers, 'e', $job, $queue_id, $eq->hash);
- $b = CRM_Utils_Mail::setMimeParams($message);
- $h = $message->headers($headers);
-
- $mailer = \Civi::service('pear_mail');
-
- if (is_object($mailer)) {
- $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
- $mailer->send($eq->email, $h, $b);
- unset($errorScope);
+ CRM_Mailing_BAO_Mailing::addMessageIdHeader($params, 'e', $job, $queue_id, $eq->hash);
+ if (CRM_Core_BAO_MailSettings::includeMessageId()) {
+ $params['messageId'] = $params['Message-ID'];
}
+ CRM_Utils_Mail::send($params);
}
}
$component->find(TRUE);
- $headers = [
- 'Subject' => $component->subject,
- 'From' => "\"{$domainEmailName}\" <{$domainEmailAddress}>",
- 'To' => $email,
- 'Reply-To' => $confirm,
- 'Return-Path' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+ $params = [
+ 'subject' => $component->subject,
+ 'from' => "\"{$domainEmailName}\" <{$domainEmailAddress}>",
+ 'toEmail' => $email,
+ 'replyTo' => $confirm,
+ 'returnPath' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
];
$url = CRM_Utils_System::url('civicrm/mailing/confirm',
// render the & entities in text mode, so that the links work
$text = str_replace('&', '&', $text);
- $message = new Mail_mime("\n");
-
- $message->setHTMLBody($html);
- $message->setTxtBody($text);
- $b = CRM_Utils_Mail::setMimeParams($message);
- $h = $message->headers($headers);
- CRM_Mailing_BAO_Mailing::addMessageIdHeader($h, 's',
+ CRM_Mailing_BAO_Mailing::addMessageIdHeader($params, 's',
$this->contact_id,
$this->id,
$this->hash
);
- $mailer = \Civi::service('pear_mail');
-
- if (is_object($mailer)) {
- $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
- $mailer->send($email, $h, $b);
- unset($errorScope);
+ $params['html'] = $html;
+ $params['text'] = $text;
+ if (CRM_Core_BAO_MailSettings::includeMessageId()) {
+ $params['messageId'] = $params['Message-ID'];
}
+ CRM_Utils_Mail::send($params);
}
/**
}
}
- $message = new Mail_mime("\n");
-
list($addresses, $urls) = CRM_Mailing_BAO_Mailing::getVerpAndUrls($job, $queue_id, $eq->hash, $eq->email);
$bao = new CRM_Mailing_BAO_Mailing();
$bao->body_text = $text;
$html = CRM_Utils_Token::replaceUnsubscribeTokens($html, $domain, $groups, TRUE, $eq->contact_id, $eq->hash);
$html = CRM_Utils_Token::replaceActionTokens($html, $addresses, $urls, TRUE, $tokens['html']);
$html = CRM_Utils_Token::replaceMailingTokens($html, $dao, NULL, $tokens['html']);
- $message->setHTMLBody($html);
}
if (!$html || $eq->format == 'Text' || $eq->format == 'Both') {
$text = CRM_Utils_Token::replaceDomainTokens($text, $domain, FALSE, $tokens['text']);
$text = CRM_Utils_Token::replaceUnsubscribeTokens($text, $domain, $groups, FALSE, $eq->contact_id, $eq->hash);
$text = CRM_Utils_Token::replaceActionTokens($text, $addresses, $urls, FALSE, $tokens['text']);
$text = CRM_Utils_Token::replaceMailingTokens($text, $dao, NULL, $tokens['text']);
- $message->setTxtBody($text);
}
$emailDomain = CRM_Core_BAO_MailSettings::defaultDomain();
- $headers = [
- 'Subject' => $component->subject,
- 'From' => "\"$domainEmailName\" <" . CRM_Core_BAO_Domain::getNoReplyEmailAddress() . '>',
- 'To' => $eq->email,
- 'Reply-To' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
- 'Return-Path' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+ $params = [
+ 'subject' => $component->subject,
+ 'from' => "\"$domainEmailName\" <" . CRM_Core_BAO_Domain::getNoReplyEmailAddress() . '>',
+ 'toEmail' => $eq->email,
+ 'replyTo' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+ 'returnPath' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+ 'html' => $html,
+ 'text' => $text,
];
- CRM_Mailing_BAO_Mailing::addMessageIdHeader($headers, 'u', $job, $queue_id, $eq->hash);
-
- $b = CRM_Utils_Mail::setMimeParams($message);
- $h = $message->headers($headers);
-
- $mailer = \Civi::service('pear_mail');
-
- if (is_object($mailer)) {
- $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
- $mailer->send($eq->email, $h, $b);
- unset($errorScope);
+ CRM_Mailing_BAO_Mailing::addMessageIdHeader($params, 'u', $job, $queue_id, $eq->hash);
+ if (CRM_Core_BAO_MailSettings::includeMessageId()) {
+ $params['messageId'] = $params['Message-ID'];
}
+ CRM_Utils_Mail::send($params);
}
/**
$this->addFormRule(['CRM_Mailing_Form_Subscribe', 'formRule']);
}
- $addCaptcha = TRUE;
-
- // if recaptcha is not configured, then dont add it
- // CRM-11316 Only enable ReCAPTCHA for anonymous visitors
- $config = CRM_Core_Config::singleton();
+ // CRM-11316 Enable ReCAPTCHA for anonymous visitors
$session = CRM_Core_Session::singleton();
$contactID = $session->get('userID');
- if (empty($config->recaptchaPublicKey) ||
- empty($config->recaptchaPrivateKey) ||
- $contactID
- ) {
- $addCaptcha = FALSE;
- }
- else {
- // If this is POST request and came from a block,
- // lets add recaptcha only if already present.
- // Gross hack for now.
- if (!empty($_POST) &&
- !array_key_exists('recaptcha_challenge_field', $_POST)
- ) {
- $addCaptcha = FALSE;
- }
- }
-
- if ($addCaptcha) {
+ if (!$contactID) {
CRM_Utils_ReCAPTCHA::enableCaptchaOnForm($this);
}
// ie in an update situation.
$membership->find(TRUE);
}
- $membershipTypes = CRM_Member_PseudoConstant::membershipType();
- $title = CRM_Contact_BAO_Contact::displayName($membership->contact_id) . ' - ' . ts('Membership Type:') . ' ' . $membershipTypes[$membership->membership_type_id];
+ $title = CRM_Contact_BAO_Contact::displayName($membership->contact_id) . ' - ' . ts('Membership Type:')
+ . ' ' . CRM_Core_PseudoConstant::getLabel('CRM_Member_BAO_Membership', 'membership_type_id', $membership->membership_type_id);
$recentOther = [];
if (CRM_Core_Permission::checkActionPermission('CiviMember', CRM_Core_Action::UPDATE)) {
/**
* Find the membership status based on start date, end date, join date & status date.
*
+ * Loop through all the membership status definitions, ordered by their
+ * weight. For each, we loop through all possible variations of the given
+ * start, end, and join dates and adjust the starts and ends based on that
+ * membership status's rules, where the last computed set of adjusted start
+ * and end becomes a candidate. Then we compare that candidate to either
+ * "today" or some other given date, and if it falls between the adjusted
+ * start and end we have a match and we stop looping through status
+ * definitions. Then we call a hook in case that wasn't enough loops.
+ *
* @param string $startDate
* Start date of the member whose membership status is to be calculated.
* @param string $endDate
* End date of the member whose membership status is to be calculated.
* @param string $joinDate
* Join date of the member whose membership status is to be calculated.
- * @param \date|string $statusDate status date of the member whose membership status is to be calculated.
- * @param bool $excludeIsAdmin the statuses those having is_admin = 1.
- * Exclude the statuses those having is_admin = 1.
+ * @param string $statusDate
+ * Either the string "today" or a date against which we compare the adjusted start and end based on the status rules.
+ * @param bool $excludeIsAdmin
+ * Exclude the statuses having is_admin = 1.
* @param int $membershipTypeID
+ * Not used directly but gets passed to the hook.
* @param array $membership
- * Membership params as available to calling function - passed to the hook.
+ * Membership params as available to calling function - not used directly but passed to the hook.
*
* @return array
*/
public static function getMembershipStatusByDate(
$startDate, $endDate, $joinDate,
- $statusDate = 'today', $excludeIsAdmin = FALSE, $membershipTypeID, $membership = []
+ $statusDate = 'today', $excludeIsAdmin = FALSE, $membershipTypeID = NULL, $membership = []
) {
$membershipDetails = [];
if (!$statusDate || $statusDate == 'today') {
- $statusDate = getdate();
- $statusDate = date('Ymd',
- mktime($statusDate['hours'],
- $statusDate['minutes'],
- $statusDate['seconds'],
- $statusDate['mon'],
- $statusDate['mday'],
- $statusDate['year']
- )
- );
+ $statusDate = date('Ymd');
}
else {
$statusDate = CRM_Utils_Date::customFormat($statusDate, '%Y%m%d');
}
- $dates = ['start', 'end', 'join'];
- $events = ['start', 'end'];
-
- foreach ($dates as $dat) {
- if (${$dat . 'Date'} && ${$dat . 'Date'} != "null") {
- ${$dat . 'Date'} = CRM_Utils_Date::customFormat(${$dat . 'Date'}, '%Y%m%d');
-
- ${$dat . 'Year'} = substr(${$dat . 'Date'}, 0, 4);
-
- ${$dat . 'Month'} = substr(${$dat . 'Date'}, 4, 2);
-
- ${$dat . 'Day'} = substr(${$dat . 'Date'}, 6, 2);
- }
- else {
- ${$dat . 'Date'} = '';
- }
- }
-
//fix for CRM-3570, if we have statuses with is_admin=1,
//exclude these statuses from calculatation during import.
$where = "is_active = 1";
ORDER BY weight ASC";
$membershipStatus = CRM_Core_DAO::executeQuery($query);
- $hour = $minute = $second = 0;
+
+ $dates = [
+ 'start' => ($startDate && $startDate !== 'null') ? date('Ymd', strtotime($startDate)) : '',
+ 'end' => ($endDate && $endDate !== 'null') ? date('Ymd', strtotime($endDate)) : '',
+ 'join' => ($joinDate && $joinDate !== 'null') ? date('Ymd', strtotime($joinDate)) : '',
+ ];
while ($membershipStatus->fetch()) {
$startEvent = NULL;
$endEvent = NULL;
- foreach ($events as $eve) {
- foreach ($dates as $dat) {
+ foreach (['start', 'end'] as $eve) {
+ foreach ($dates as $dat => $date) {
// calculate start-event/date and end-event/date
- if (($membershipStatus->{$eve . '_event'} == $dat . '_date') &&
- ${$dat . 'Date'}
+ if (($membershipStatus->{$eve . '_event'} === $dat . '_date') &&
+ $date
) {
if ($membershipStatus->{$eve . '_event_adjust_unit'} &&
$membershipStatus->{$eve . '_event_adjust_interval'}
) {
+ $month = date('m', strtotime($date));
+ $day = date('d', strtotime($date));
+ $year = date('Y', strtotime($date));
// add in months
- if ($membershipStatus->{$eve . '_event_adjust_unit'} == 'month') {
- ${$eve . 'Event'} = date('Ymd', mktime($hour, $minute, $second,
- ${$dat . 'Month'} + $membershipStatus->{$eve . '_event_adjust_interval'},
- ${$dat . 'Day'},
- ${$dat . 'Year'}
+ if ($membershipStatus->{$eve . '_event_adjust_unit'} === 'month') {
+ ${$eve . 'Event'} = date('Ymd', mktime(0, 0, 0,
+ $month + $membershipStatus->{$eve . '_event_adjust_interval'},
+ $day,
+ $year
));
}
// add in days
- if ($membershipStatus->{$eve . '_event_adjust_unit'} == 'day') {
- ${$eve . 'Event'} = date('Ymd', mktime($hour, $minute, $second,
- ${$dat . 'Month'},
- ${$dat . 'Day'} + $membershipStatus->{$eve . '_event_adjust_interval'},
- ${$dat . 'Year'}
+ if ($membershipStatus->{$eve . '_event_adjust_unit'} === 'day') {
+ ${$eve . 'Event'} = date('Ymd', mktime(0, 0, 0,
+ $month,
+ $day + $membershipStatus->{$eve . '_event_adjust_interval'},
+ $year
));
}
// add in years
- if ($membershipStatus->{$eve . '_event_adjust_unit'} == 'year') {
- ${$eve . 'Event'} = date('Ymd', mktime($hour, $minute, $second,
- ${$dat . 'Month'},
- ${$dat . 'Day'},
- ${$dat . 'Year'} + $membershipStatus->{$eve . '_event_adjust_interval'}
+ if ($membershipStatus->{$eve . '_event_adjust_unit'} === 'year') {
+ ${$eve . 'Event'} = date('Ymd', mktime(0, 0, 0,
+ $month,
+ $day,
+ $year + $membershipStatus->{$eve . '_event_adjust_interval'}
));
}
// if no interval and unit, present
}
else {
- ${$eve . 'Event'} = ${$dat . 'Date'};
+ ${$eve . 'Event'} = $date;
}
}
}
$buttonName = $this->controller->getButtonName();
$session = CRM_Core_Session::singleton();
- if ($this->_context === 'standalone') {
- if ($buttonName == $this->getButtonName('upload', 'new')) {
- $session->replaceUserContext(CRM_Utils_System::url('civicrm/member/add',
+ if ($buttonName == $this->getButtonName('upload', 'new')) {
+ if ($this->_context === 'standalone') {
+ $url = CRM_Utils_System::url('civicrm/member/add',
'reset=1&action=add&context=standalone'
- ));
+ );
}
else {
- $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view',
- "reset=1&cid={$this->_contactID}&selectedChild=member"
- ));
+ $url = CRM_Utils_System::url('civicrm/contact/view/membership',
+ "reset=1&action=add&context=membership&cid={$this->_contactID}"
+ );
}
}
- elseif ($buttonName == $this->getButtonName('upload', 'new')) {
- $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/membership',
- "reset=1&action=add&context=membership&cid={$this->_contactID}"
- ));
+ else {
+ $url = CRM_Utils_System::url('civicrm/contact/view',
+ "reset=1&cid={$this->_contactID}&selectedChild=member"
+ );
}
+ $session->replaceUserContext($url);
}
/**
list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail();
if (!$domainEmailAddress || $domainEmailAddress == 'info@EXAMPLE.ORG') {
- $fixUrl = CRM_Utils_System::url("civicrm/admin/domain", 'action=update&reset=1');
+ $fixUrl = CRM_Utils_System::url('civicrm/admin/options/from_email_address', 'reset=1');
throw new CRM_Core_Exception(ts('The site administrator needs to enter a valid \'FROM Email Address\' in <a href="%1">Administer CiviCRM » Communications » FROM Email Addresses</a>. The email address used may need to be a valid mail account with your email service provider.', [1 => $fixUrl]));
}
}
}
}
+ $form->_priceSet['id'] = $form->_priceSet['id'] ?? $priceSetId;
$form->assign('priceSet', $form->_priceSet);
$component = 'contribution';
if ($name) {
$defaults['name'] = $name;
$provider = CRM_SMS_Provider::singleton(['provider' => $name]);
- $defaults['api_url'] = $provider->_apiURL;
+ $defaults['api_url'] = $provider->_apiURL ?? '';
}
if (!$this->_id) {
break;
default:
- throw new CRM_Core_Exception("Unrecognized entity type: $entityType");
+ if (strpos($entityType, 'Model') !== FALSE) {
+ $entity = str_replace('Model', '', $entityType);
+ $backboneModel = self::convertCiviModelToBackboneModel(
+ $entity,
+ ts('%1', [1 => $entity]),
+ $availableFields
+ );
+ if (!empty($backboneModel['schema'])) {
+ $civiSchema[$entityType] = $backboneModel;
+ }
+ }
+ if (!isset($civiSchema[$entityType])) {
+ throw new CRM_Core_Exception("Unrecognized entity type: $entityType");
+ }
}
}
*/
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>';
- // }
+ if ($rev == '5.28.alpha1') {
+ $preUpgradeMessage .= CRM_Upgrade_Incremental_php_FiveTwentyEight::createWpFilesMessage();
+ }
}
/**
* an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs.
*/
public function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
- // 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'.");
- // }
+ // Example: Generate a pre-upgrade message.
+ if ($rev == '5.28.alpha1') {
+ $postUpgradeMessage .= CRM_Upgrade_Incremental_php_FiveTwentyEight::createWpFilesMessage();
+ }
+ }
+
+ public static function createWpFilesMessage() {
+ if (!function_exists('civi_wp')) {
+ return '';
+ }
+
+ if (isset($GLOBALS['civicrm_paths']['civicrm.files']['path'])) {
+ // They've explicitly chosen to use a non-default path.
+ return '';
+ }
+
+ $table = '<table><tbody>'
+ . sprintf('<tr><th colspan="2">%s</th></tr>', ts('<b>[civicrm.files]</b> Path'))
+ . sprintf('<tr><td>%s</td><td><code>%s</code></td></tr>', ts('5.29 Default:'), wp_upload_dir()['basedir'] . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR)
+ . sprintf('<tr><td>%s</td><td><code>%s</code></td></tr>', ts('5.28 Default:'), CRM_Core_Config::singleton()->userSystem->getDefaultFileStorage()['path'])
+ . sprintf('<tr><td>%s</td><td><code>%s</code></td></tr>', ts('Active Value:'), Civi::paths()->getVariable('civicrm.files', 'path'))
+ . sprintf('<tr><th colspan="2">%s</th></tr>', ts('<b>[civicrm.files]</b> URL'))
+ . sprintf('<tr><td>%s</td><td><code>%s</code></td></tr>', ts('5.29 Default:'), wp_upload_dir()['baseurl'] . '/civicrm/')
+ . sprintf('<tr><td>%s</td><td><code>%s</code></td></tr>', ts('5.28 Default:'), CRM_Core_Config::singleton()->userSystem->getDefaultFileStorage()['url'])
+ . sprintf('<tr><td>%s</td><td><code>%s</code></td></tr>', ts('Active Value:'), Civi::paths()->getVariable('civicrm.files', 'url'))
+ . '</tbody></table>';
+
+ return '<p>' . ts('Starting with version 5.29.0, CiviCRM on WordPress may make a subtle change in the calculation of <code>[civicrm.files]</code>.
+ To ensure a smooth upgrade, please review the following table. All paths and URLs should appear the same. If there is <strong><em>any</em></strong> discrepancy,
+ then consult <a href=\'%1\' target=\'_blank\'>the upgrade documentation</a>.', [
+ 1 => 'https://docs.civicrm.org/sysadmin/en/latest/upgrade/version-specific/#civicrm-5.29',
+ 2 => '...wp-content/uploads/civicrm',
+ ]) . '</p>' . $table;
}
/*
* @param string $rev
*/
public function upgrade_5_28_alpha1($rev) {
- $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
$this->addTask('Populate missing Contact Type name fields', 'populateMissingContactTypeName');
+ $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
$this->addTask('Add icon column to civicrm_custom_group', 'addColumn',
'civicrm_custom_group', 'icon', "varchar(255) COMMENT 'crm-i icon class' DEFAULT NULL");
$this->addTask('Remove index on medium_id from civicrm_activity', 'dropIndex', 'civicrm_activity', 'index_medium_id');
{* file to handle db changes in 5.29.alpha1 during upgrade *}
+{* https://github.com/civicrm/civicrm-core/pull/17824 *}
+UPDATE civicrm_status_pref SET name = 'checkExtensionsOk' WHERE name = 'extensionsOk';
+UPDATE civicrm_status_pref SET name = 'checkExtensionsUpdates' WHERE name = 'extensionUpdates';
+
-- The RelationshipCache is a high-level index/cache for querying relationships.
DROP TABLE IF EXISTS `civicrm_relationship_cache`;
CREATE TABLE `civicrm_relationship_cache` (
CONSTRAINT FK_civicrm_relationship_cache_near_contact_id FOREIGN KEY (`near_contact_id`) REFERENCES `civicrm_contact`(`id`) ON DELETE CASCADE,
CONSTRAINT FK_civicrm_relationship_cache_far_contact_id FOREIGN KEY (`far_contact_id`) REFERENCES `civicrm_contact`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
+
+-- Fix missing resubscribeUrl token. There doesn't seem to be any precedent
+-- for doing an upgrade for these, since the last update was in 2009 when
+-- the token went missing and it had no upgrade script for it. Also unlike
+-- message templates, there doesn't seem to be a way to tell whether it's
+-- been changed. Using ts is a bit unreliable if the translation has changed
+-- but it would be no worse than now and just end up not updating it.
+-- Also, I'm drawing a blank on why the %3 is replaced differently during
+-- install than during upgrade, hence the OR clause.
+{capture assign=unsubgroup}{ldelim}unsubscribe.group{rdelim}{/capture}
+{capture assign=actresub}{ldelim}action.resubscribe{rdelim}{/capture}
+{capture assign=actresuburl}{ldelim}action.resubscribeUrl{rdelim}{/capture}
+UPDATE civicrm_mailing_component
+SET body_text = '{ts escape="sql" 1=$unsubgroup 2=$actresub 3=$actresuburl}You have been un-subscribed from the following groups: %1. You can re-subscribe by mailing %2 or clicking %3{/ts}'
+WHERE component_type = 'Unsubscribe'
+AND (body_text = '{ts escape="sql" 1=$unsubgroup 2=$actresub}You have been un-subscribed from the following groups: %1. You can re-subscribe by mailing %2 or clicking %3{/ts}'
+ OR body_text = '{ts escape="sql" 1=$unsubgroup 2=$actresub}You have been un-subscribed from the following groups: %1. You can re-subscribe by mailing %2 or clicking {/ts}');
}
/**
- * Run all system checks.
+ * Run all enabled system checks.
*
* This functon is wrapped by the System.check api.
*
* @param bool $max
* Whether to return just the maximum non-hushed severity
*
- * @return array
- * Array of CRM_Utils_Check_Message objects
+ * @return CRM_Utils_Check_Message[]
*/
public static function checkAll($max = FALSE) {
- $messages = [];
- foreach (glob(__DIR__ . '/Check/Component/*.php') as $filePath) {
- $className = 'CRM_Utils_Check_Component_' . basename($filePath, '.php');
- /* @var CRM_Utils_Check_Component $check */
- $check = new $className();
- if ($check->isEnabled()) {
- $messages = array_merge($messages, $check->checkAll());
- }
- }
-
- CRM_Utils_Hook::check($messages);
+ $messages = self::checkStatus();
uasort($messages, [__CLASS__, 'severitySort']);
return ($max) ? $maxSeverity : $messages;
}
+ /**
+ * @param array $statusNames
+ * Optionally specify the names of specific checks to run, or leave empty to run all
+ * @param bool $includeDisabled
+ * Run checks that have been explicitly disabled (default false)
+ *
+ * @return CRM_Utils_Check_Message[]
+ */
+ public static function checkStatus($statusNames = [], $includeDisabled = FALSE) {
+ $messages = [];
+ $checksNeeded = $statusNames;
+ foreach (glob(__DIR__ . '/Check/Component/*.php') as $filePath) {
+ $className = 'CRM_Utils_Check_Component_' . basename($filePath, '.php');
+ /* @var CRM_Utils_Check_Component $component */
+ $component = new $className();
+ if ($includeDisabled || $component->isEnabled()) {
+ $messages = array_merge($messages, $component->checkAll($statusNames, $includeDisabled));
+ }
+ if ($statusNames) {
+ // Early return if we have already run (or skipped) all the requested checks.
+ $checksNeeded = array_diff($checksNeeded, $component->getAllChecks());
+ if (!$checksNeeded) {
+ return $messages;
+ }
+ }
+ }
+
+ CRM_Utils_Hook::check($messages, $statusNames, $includeDisabled);
+
+ return $messages;
+ }
+
/**
* @param int $level
* @return string
return TRUE;
}
+ /**
+ * Get the names of all check functions in this class
+ *
+ * @return string[]
+ */
+ public function getAllChecks() {
+ return array_filter(get_class_methods($this), function($method) {
+ return $method !== 'checkAll' && strpos($method, 'check') === 0;
+ });
+ }
+
/**
* Run all checks in this class.
*
- * @return array
- * [CRM_Utils_Check_Message]
+ * @param array $requestedChecks
+ * Optionally specify the names of specific checks requested, or leave empty to run all
+ * @param bool $includeDisabled
+ * Run checks that have been explicitly disabled (default false)
*
- * @throws \API_Exception
+ * @return CRM_Utils_Check_Message[]
+ *
+ * @throws API_Exception
* @throws \Civi\API\Exception\UnauthorizedException
*/
- public function checkAll() {
+ public function checkAll($requestedChecks = [], $includeDisabled = FALSE) {
$messages = [];
- foreach (get_class_methods($this) as $method) {
+ foreach ($this->getAllChecks() as $method) {
// Note that we should check if the test is disabled BEFORE running it in case it's disabled for performance.
- if ($method !== 'checkAll' && strpos($method, 'check') === 0 && !$this->isDisabled($method)) {
- $messages = array_merge($messages, $this->$method());
+ if ($this->isRequested($method, $requestedChecks) && ($includeDisabled || !$this->isDisabled($method))) {
+ $messages = array_merge($messages, $this->$method($includeDisabled));
}
}
return $messages;
}
+ /**
+ * Is this check one of those requested
+ *
+ * @param string $method
+ * @param array $requestedChecks
+ * @return bool
+ */
+ private function isRequested($method, $requestedChecks) {
+ if (!$requestedChecks) {
+ return TRUE;
+ }
+ foreach ($requestedChecks as $name) {
+ if (strpos($name, $method) === 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
/**
* Is the specified check disabled.
*
}
/**
+ * @param bool $force
* @return CRM_Utils_Check_Message[]
*/
- public function checkOutboundMail() {
+ public function checkOutboundMail($force = FALSE) {
$messages = [];
// CiviMail doesn't work in non-production environments; skip.
- if (CRM_Core_Config::environment() != 'Production') {
+ if (!$force && CRM_Core_Config::environment() != 'Production') {
return $messages;
}
/**
* Check that domain email and org name are set
+ * @param bool $force
* @return CRM_Utils_Check_Message[]
*/
- public function checkDomainNameEmail() {
+ public function checkDomainNameEmail($force = FALSE) {
$messages = [];
// CiviMail doesn't work in non-production environments; skip.
- if (CRM_Core_Config::environment() != 'Production') {
+ if (!$force && CRM_Core_Config::environment() != 'Production') {
return $messages;
}
/**
* Checks if a default bounce handling mailbox is set up
+ * @param bool $force
* @return CRM_Utils_Check_Message[]
*/
- public function checkDefaultMailbox() {
+ public function checkDefaultMailbox($force = FALSE) {
$messages = [];
// CiviMail doesn't work in non-production environments; skip.
- if (CRM_Core_Config::environment() != 'Production') {
+ if (!$force && CRM_Core_Config::environment() != 'Production') {
return $messages;
}
/**
* Checks if cron has run in the past hour (3600 seconds)
+ * @param bool $force
* @return CRM_Utils_Check_Message[]
* @throws CRM_Core_Exception
*/
- public function checkLastCron() {
+ public function checkLastCron($force = FALSE) {
$messages = [];
// Cron doesn't work in non-production environments; skip.
- if (CRM_Core_Config::environment() != 'Production') {
+ if (!$force && CRM_Core_Config::environment() != 'Production') {
return $messages;
}
// After 1 day (86400 seconds) increase the error level
$level = ($lastCron > $now - 86400) ? \Psr\Log\LogLevel::WARNING : \Psr\Log\LogLevel::ERROR;
}
- $msg .= '<p>' . ts('To enable scheduling support, please set up the cron job.') .
+ $msg .= '<p>' . ts('A cron job is required to execute scheduled jobs automatically.') .
'<br />' . CRM_Utils_System::docURL2('sysadmin/setup/jobs/') . '</p>';
}
if (!$okextensions && !$updates && !$errors) {
$messages[] = new CRM_Utils_Check_Message(
- 'extensionsOk',
+ __FUNCTION__ . 'Ok',
ts('No extensions installed. <a %1>Browse available extensions</a>.', [
1 => 'href="' . CRM_Utils_System::url('civicrm/admin/extensions', 'reset=1') . '"',
]),
if ($updates) {
$messages[] = new CRM_Utils_Check_Message(
- 'extensionUpdates',
+ __FUNCTION__ . 'Updates',
'<ul><li>' . implode('</li><li>', $updates) . '</li></ul>',
ts('Extension Update Available', ['plural' => '%count Extension Updates Available', 'count' => count($updates)]),
\Psr\Log\LogLevel::WARNING,
$message = ts('All extensions are up-to-date:');
}
$messages[] = new CRM_Utils_Check_Message(
- 'extensionsOk',
+ __FUNCTION__ . 'Ok',
$message . '<ul><li>' . implode('</li><li>', $okextensions) . '</li></ul>',
ts('Extensions'),
\Psr\Log\LogLevel::INFO,
/**
* Ensure reply id is set to any default value
+ * @param bool $force
* @return CRM_Utils_Check_Message[]
*/
- public function checkReplyIdForMailing() {
+ public function checkReplyIdForMailing($force = FALSE) {
$messages = [];
// CiviMail doesn't work in non-production environments; skip.
- if (CRM_Core_Config::environment() != 'Production') {
+ if (!$force && CRM_Core_Config::environment() != 'Production') {
return $messages;
}
* but also accepts enough information to support Symfony Event
* dispatching.
*
- * @param array|int $names
+ * @param array $names
* (Recommended) Array of parameter names, in order.
* Using an array is recommended because it enables full
* event-broadcasting behaviors.
if (!is_array($names)) {
// We were called with the old contract wherein $names is actually an int.
// Symfony dispatcher requires some kind of name.
- // TODO: Emit a warning, eg
- // error_log("Warning: hook_$fnSuffix does not give names for its parameters. It will present odd names to any Symfony event listeners.");
+ Civi::log()->warning("hook_$fnSuffix should be updated to pass an array of parameter names to CRM_Utils_Hook::invoke().", ['civi.tag' => 'deprecated']);
$compatNames = ['arg1', 'arg2', 'arg3', 'arg4', 'arg5', 'arg6'];
$names = array_slice($compatNames, 0, (int) $names);
}
$event = \Civi\Core\Event\GenericHookEvent::createOrdered(
$names,
- array(&$arg1, &$arg2, &$arg3, &$arg4, &$arg5, &$arg6)
+ [&$arg1, &$arg2, &$arg3, &$arg4, &$arg5, &$arg6]
);
\Civi::dispatcher()->dispatch('hook_' . $fnSuffix, $event);
return $event->getReturnValues();
* the return value is ignored
*/
public static function activeTheme(&$theme, $context) {
- return self::singleton()->invoke(array('theme', 'context'), $theme, $context,
+ return self::singleton()->invoke(['theme', 'context'], $theme, $context,
self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject,
'civicrm_activeTheme'
);
* @return mixed
*/
public static function alterAdminPanel(&$panels) {
- return self::singleton()->invoke(array('panels'), $panels,
+ return self::singleton()->invoke(['panels'], $panels,
self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject,
'civicrm_alterAdminPanel'
);
/**
* Check system status.
*
- * @param array $messages
- * Array<CRM_Utils_Check_Message>. A list of messages regarding system status.
+ * @param CRM_Utils_Check_Message[] $messages
+ * A list of messages regarding system status
+ * @param array $statusNames
+ * If specified, only these checks are being requested and others should be skipped
+ * @param bool $includeDisabled
+ * Run checks that have been explicitly disabled (default false)
* @return mixed
*/
- public static function check(&$messages) {
- return self::singleton()
- ->invoke(['messages'], $messages, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, 'civicrm_check');
+ public static function check(&$messages, $statusNames = [], $includeDisabled = FALSE) {
+ return self::singleton()->invoke(['messages'],
+ $messages, $statusNames, $includeDisabled,
+ self::$_nullObject, self::$_nullObject, self::$_nullObject,
+ 'civicrm_check'
+ );
}
/**
* text : text of the message
* html : html version of the message
* replyTo : reply-to header in the email
+ * returnpath : email address for bounces to be sent to
+ * messageId : Message ID for this email mesage
* attachments: an associative array of
* fullPath : complete pathname to the file
* mime_type: mime type of the attachment
}
$headers['Date'] = date('r');
if ($includeMessageId) {
- $headers['Message-ID'] = '<' . uniqid('civicrm_', TRUE) . "@$emailDomain>";
+ $headers['Message-ID'] = $params['messageId'] ?? '<' . uniqid('civicrm_', TRUE) . "@$emailDomain>";
}
if (!empty($params['autoSubmitted'])) {
$headers['Auto-Submitted'] = "Auto-Generated";
// interface can be disabled in more change to the configuration file.
// first check for civicrm site key
if (!CRM_Utils_System::authenticateKey(FALSE)) {
- $docLink = CRM_Utils_System::docURL2("Managing Scheduled Jobs", TRUE, NULL, NULL, NULL, "wiki");
+ $docLink = CRM_Utils_System::docURL2('sysadmin/setup/jobs', TRUE);
$key = $requestParams['key'] ?? NULL;
if (empty($key)) {
return self::error("FATAL: mandatory param 'key' missing. More info at: " . $docLink);
return '';
}
$dbUTF = CRM_Core_BAO_SchemaHandler::getDBCollation();
- if (in_array($dbUTF, ['utf8_unicode_ci', 'utf8mb4_unicode_ci'])
- && in_array($dbUTF, ['utf8', 'utf8mb4'])) {
+ if (strpos($dbUTF, 'utf8') !== FALSE) {
return '';
}
return self::UTF8;
$this->toSQL('CREATE'),
$columns,
$this->memory ? self::MEMORY : self::INNODB,
- $this->utf8 ? self::UTF8 : ''
+ $this->getUtf8String()
);
CRM_Core_DAO::executeQuery($sql, [], TRUE, NULL, TRUE, FALSE);
$this->createSql = $sql;
// also make sure the key is sent and is valid
$key = trim(CRM_Utils_Array::value('key', $_REQUEST));
- $docAdd = "More info at:" . CRM_Utils_System::docURL2("Managing Scheduled Jobs", TRUE, NULL, NULL, NULL, "wiki");
+ $docAdd = "More info at: " . CRM_Utils_System::docURL2('sysadmin/setup/jobs', TRUE);
if (!$key) {
return self::authenticateAbort(
= CRM_Contribute_BAO_Contribution::$_exportableFields
= CRM_Pledge_BAO_Pledge::$_exportableFields
= CRM_Core_BAO_CustomField::$_importFields
- = CRM_Core_BAO_Cache::$_cache = CRM_Core_DAO::$_dbColumnValueCache = NULL;
+ = CRM_Core_DAO::$_dbColumnValueCache = NULL;
CRM_Core_OptionGroup::flushAll();
CRM_Utils_PseudoConstant::flushAll();
// Validate the user object
$violations = $account->validate();
if (count($violations)) {
+ foreach ($violations as $violation) {
+ CRM_Core_Session::setStatus($violation->getPropertyPath() . ': ' . $violation->getMessage(), '', 'alert');
+ }
return FALSE;
}
};
Civi::paths()->register('cms', $cmsRoot);
Civi::paths()->register('cms.root', $cmsRoot);
- Civi::paths()->register('civicrm.files', function () {
- $upload_dir = wp_get_upload_dir();
- return [
- 'path' => $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR,
- 'url' => $upload_dir['baseurl'] . '/civicrm/',
- ];
- });
Civi::paths()->register('civicrm.root', function () {
return [
'path' => CIVICRM_PLUGIN_DIR . 'civicrm' . DIRECTORY_SEPARATOR,
* Moved from CRM_Utils_System_Base
*/
public function getDefaultFileStorage() {
+ // NOTE: On WordPress, this will be circumvented in the future. However,
+ // should retain it to allow transitional/upgrade code determine the old value.
+
$config = CRM_Core_Config::singleton();
$cmsUrl = CRM_Utils_System::languageNegotiationURL($config->userFrameworkBaseURL, FALSE, TRUE);
$cmsPath = $this->cmsRootPath();
/**
* Retrieve system notices, warnings, errors, etc.
+ * @method bool getIncludeDisabled()
*/
class Check extends \Civi\Api4\Generic\BasicGetAction {
+ /**
+ * Run checks that have been explicitly disabled (default false)
+ * @var bool
+ */
+ protected $includeDisabled = FALSE;
+
+ /**
+ * @param bool $includeDisabled
+ * @return Check
+ */
+ public function setIncludeDisabled(bool $includeDisabled): Check {
+ $this->includeDisabled = $includeDisabled;
+ return $this;
+ }
+
protected function getRecords() {
- $messages = [];
- foreach (\CRM_Utils_Check::checkAll() as $message) {
+ $messages = $names = [];
+
+ // Filtering by name relies on the component check rather than the api arrayQuery
+ // @see \CRM_Utils_Check_Component::isCheckable
+ foreach ($this->where as $i => $clause) {
+ if ($clause[0] == 'name' && !empty($clause[2]) && in_array($clause[1], ['=', 'IN'], TRUE)) {
+ $names = (array) $clause[2];
+ unset($this->where[$i]);
+ break;
+ }
+ }
+
+ foreach (\CRM_Utils_Check::checkStatus($names, $this->includeDisabled) as $message) {
$messages[] = $message->toArray();
}
return $messages;
protected function _itemsToGet($field) {
foreach ($this->where as $clause) {
// Look for exact-match operators (=, IN, or LIKE with no wildcard)
- if ($clause[0] == $field && (in_array($clause[1], ['=', 'IN']) || ($clause[1] == 'LIKE' && !(is_string($clause[2]) && strpos($clause[2], '%') !== FALSE)))) {
+ if ($clause[0] == $field && (in_array($clause[1], ['=', 'IN'], TRUE) || ($clause[1] == 'LIKE' && !(is_string($clause[2]) && strpos($clause[2], '%') !== FALSE)))) {
return (array) $clause[2];
}
}
namespace Civi\Api4\Generic;
/**
- * Base class for all `Save` api actions.
+ * Create or update one or more $ENTITIES.
+ *
+ * Pass an array of one or more $ENTITY to save in the `records` param.
+ *
+ * If creating more than one $ENTITY with similar values, use the `defaults` param.
+ *
+ * Set `reload` if you need the api to return complete records for each saved $ENTITY
+ * (including values that were unchanged in from updated $ENTITIES).
*
* @method $this setRecords(array $records) Set array of records to be saved.
* @method array getRecords()
use Civi\API\Exception\NotImplementedException;
/**
- * $ACTION one or more $ENTITIES.
- *
- * If saving more than one new $ENTITY with similar values, use the `defaults` parameter.
- *
- * Set `reload` if you need the api to return complete $ENTITY records.
+ * @inheritDoc
*/
class BasicSaveAction extends AbstractSaveAction {
private $setter;
/**
- * Basic Create constructor.
+ * Basic Save constructor.
*
* @param string $entityName
* @param string $actionName
namespace Civi\Api4\Generic;
/**
- * Create or update one or more $ENTITIES.
- *
- * If creating more than one $ENTITY with similar values, use the `defaults` param.
- *
- * Set `reload` if you need the api to return complete records for each saved $ENTITY.
+ * @inheritDoc
*/
class DAOSaveAction extends AbstractSaveAction {
use Traits\DAOActionTrait;
* @return bool
*/
private function evaluateFilters($row) {
- $where = $this->getWhere();
+ $where = array_values($this->getWhere());
$allConditions = in_array($where[0], ['AND', 'OR', 'NOT']) ? $where : ['AND', $where];
return $this->walkFilters($row, $allConditions);
}
->setFactory('CRM_Utils_Mail::createMailer');
if (empty(\Civi::$statics[__CLASS__]['boot'])) {
- throw new \RuntimeException("Cannot initialize container. Boot services are undefined.");
+ throw new \RuntimeException('Cannot initialize container. Boot services are undefined.');
}
foreach (\Civi::$statics[__CLASS__]['boot'] as $bootService => $def) {
$container->setDefinition($bootService, new Definition())->setSynthetic(TRUE)->setPublic(TRUE);
*/
public static function createPrevNextCache($container) {
$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', '<');
+ if (!$setting || $setting === 'default') {
$cacheDriver = \CRM_Utils_Cache::getCacheDriver();
$service = 'prevnext.driver.' . strtolower($cacheDriver);
- return $container->has($service) && !$isTransitional
+ return $container->has($service)
? $container->get($service)
: $container->get('prevnext.driver.sql');
}
- else {
- return $container->get('prevnext.driver.' . $setting);
- }
+ return $container->get('prevnext.driver.' . $setting);
}
+ /**
+ * @return \ArrayObject
+ */
public static function createCacheConfig() {
$driver = \CRM_Utils_Cache::getCacheDriver();
$settings = \CRM_Utils_Cache::getCacheSettings($driver);
}
}
+ /**
+ * @param string $name
+ *
+ * @return mixed
+ */
public static function getBootService($name) {
return \Civi::$statics[__CLASS__]['boot'][$name];
}
* @return array
*/
public function checkMysqlVersion(array $db_config) {
+ if (!class_exists('\CRM_Upgrade_Incremental_General')) {
+ require_once dirname(__FILE__) . '/../../CRM/Upgrade/Incremental/General.php';
+ }
$min = \CRM_Upgrade_Incremental_General::MIN_INSTALL_MYSQL_VER;
$results = [
'title' => 'CiviCRM MySQL Version',
class="crm-hover-button action-item"
ng-href="{{statUrl(am.mailing, statType, 'report')}}"
title="{{ts('Reports for \'%1\'', {1: statType.title})}}"
- crm-icon="clipboard"
+ crm-icon="fa-clipboard"
></a>
</td>
<td ng-show="abtest.ab.status == 'Testing'"></td>
})
// Example for Font Awesome: <button crm-icon="fa-check">Save</button>
- // Example for jQuery UI (deprecated): <button crm-icon="check">Save</button>
+ // Example for jQuery UI (deprecated): <button crm-icon="fa-check">Save</button>
.directive('crmIcon', function() {
return {
restrict: 'EA',
* @throws Exception
*/
function civicrm_api3_contribution_sendconfirmation($params) {
- $ids = $values = [];
+ $ids = [];
$allowedParams = [
'receipt_from_email',
'receipt_from_name',
'payment_processor_id',
];
$input = array_intersect_key($params, array_flip($allowedParams));
- $input['is_email_receipt'] = TRUE;
- CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $params['id'], $values);
+ CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $params['id']);
}
/**
elseif ($contribution->contribution_status_id == CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed')) {
throw new API_Exception(ts('Contribution already completed'), 'contribution_completed');
}
- $input['trxn_id'] = !empty($params['trxn_id']) ? $params['trxn_id'] : $contribution->trxn_id;
+ $input['trxn_id'] = $params['trxn_id'] ?? $contribution->trxn_id;
+
if (!empty($params['fee_amount'])) {
$input['fee_amount'] = $params['fee_amount'];
}
}
$input['card_type_id'] = $params['card_type_id'] ?? NULL;
$input['pan_truncation'] = $params['pan_truncation'] ?? NULL;
- return CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $objects, NULL,
+ return CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $objects,
$params['is_post_payment_create'] ?? NULL);
}
civicrm_api3_verify_one_mandatory($params, NULL, ['line_items', 'total_amount']);
$entity = NULL;
$entityIds = [];
- $contributionStatus = $params['contribution_status_id'] ?? NULL;
- if ($contributionStatus !== 'Pending' && 'Pending' !== CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_Contribution', 'contribution_status_id', $contributionStatus)) {
- CRM_Core_Error::deprecatedFunctionWarning("Creating a Order with a status other than pending is deprecated. Currently empty defaults to 'Completed' so as a transition not passing in 'Pending' is deprecated. You can chain payment creation e.g civicrm_api3('Order', 'create', ['blah' => 'blah', 'contribution_status_id' => 'Pending', 'api.Payment.create => ['total_amount' => 5]]");
+ $params['contribution_status_id'] = $params['contribution_status_id'] ?? 'Pending';
+ if ($params['contribution_status_id'] !== 'Pending' && 'Pending' !== CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_Contribution', 'contribution_status_id', $params['contribution_status_id'])) {
+ CRM_Core_Error::deprecatedFunctionWarning("Creating a Order with a status other than pending is deprecated. Please do not set contribution_status_id, it will default to Pending. You can chain payment creation e.g civicrm_api3('Order', 'create', ['blah' => 'blah', 'contribution_status_id' => 'Pending', 'api.Payment.create => ['total_amount' => 5]]");
}
if (!empty($params['line_items']) && is_array($params['line_items'])) {
if ($entityParams) {
if (in_array($entity, ['participant', 'membership'])) {
$entityParams['skipLineItem'] = TRUE;
- if ($contributionStatus === 'Pending') {
- $entityParams['status_id'] = ($entity === 'participant' ? 'Pending from incomplete transaction' : 'Pending');
- }
+ $entityParams['status_id'] = ($entity === 'participant' ? 'Pending from incomplete transaction' : 'Pending');
$entityResult = civicrm_api3($entity, 'create', $entityParams);
$params['contribution_mode'] = $entity;
$entityIds[] = $params[$entity . '_id'] = $entityResult['id'];
.crm-container .crm-button input {
background: none;
- _background: #6C6C6C;
- /* IE6 only */
border: medium none;
color: #FFF;
cursor: pointer;
.crm-container .crm-button-type-back {
margin-left: 20px;
}
-.crm-container .crm-button-type-cancel input {
- color: #E6E6DC!important;
+
+/* Reset WP backend min-height for buttons */
+
+.wp-core-ui .crm-container .button {
+ min-height: 0;
}
.crm-container a.button,
.crm-container input[type=button],
.crm-container .crm-button {
text-shadow: 0 1px 0 black;
- background: #70716B url(../i/crm-button-bg.gif) repeat-x top left;
+ background: #696969;
color: #FFF;
font-size: 13px;
font-weight: normal;
border: 1px solid #3e3e3e;
}
+.crm-container a.button,
+.crm-container a.button:link,
+.crm-container a.button:visited,
.crm-container span.crm-button {
display: block;
- float: left !important;
+ float: left;
overflow: hidden;
- padding: 1px;
+ line-height: 135%;
+}
+
+/* Preserving the important but not sure why */
+.crm-container span.crm-button {
+ float: left !important;
}
.crm-container button.crm-button {
.crm-container .crm-button input[type=button],
.crm-container .crm-button input.crm-form-submit {
- padding: 3px 5px 2px;
+ padding: 0;
margin: 0;
background: none;
- _background: #6C6C6C;
- /* IE6 only */
border: none;
}
-.crm-container a.button,
-.crm-container a.button:link,
-.crm-container a.button:visited {
- display: block;
- float: left;
- line-height: 135%;
-}
-
.crm-container .crm-button:hover,
.crm-container .crm-button:focus,
.crm-container input[type=submit]:hover,
.crm-container .ui-dialog-buttonset .ui-button:focus,
.crm-container a.button:hover,
.crm-container a.button:focus {
- background-position: 0 -25px;
+ background: #3e3e3e;
}
.crm-container .crm-button-disabled,
.crm-container .crm-button[disabled] {
opacity: .6;
cursor: default;
- background-position: top left;
}
.crm-container .crm-button-disabled input[disabled] {
margin-left: 3px;
}
-.crm-container .crm-button.crm-icon-button {
- padding: 2px 2px 1px 4px;
-}
-
-.crm-container .crm-button.crm-icon-button input {
- padding-left: 18px;
-}
-
-.crm-container .crm-button.button-crm-i {
- padding: 2px 0 1px 5px;
-}
-
-.crm-container .crm-button.button-crm-i input {
- padding-left: 0;
-}
-
-.crm-container .crm-button-icon {
- background-image: url("../i/icons/jquery-ui-FFFFFF.png");
- height: 16px;
- width: 16px;
- display: block;
- position: absolute;
- pointer-events: none;
-}
-
.crm-container .delete-icon {
background-position: -176px -96px;
}
color: #86c661;
}
-.crm-i-button {
- position: relative;
-}
-
-.crm-i-button>.crm-i {
- position: absolute;
- pointer-events: none;
- top: .4em;
- left: .4em;
-}
-
-.crm-container .crm-button.crm-i-button input[type="button"],
-.crm-container .crm-button.crm-i-button input.crm-form-submit {
- padding-left: 1.6em;
-}
-
-.crm-container .inform-icon {
- background-position: -16px -144px;
- margin-right: 5px;
-}
-
.crm-container a.helpicon {
opacity: .8;
}
right: 0;
}
.crm-container .ui-dialog-titlebar.ui-widget-header {
- background: url("../i/crm-button-bg.gif") repeat-x scroll left center #70716B;
+ background: #5D677B;
color: #F5F6F1;
}
.crm-container .ui-dialog-title {
<url desc="Support">http://civicrm.stackexchange.com/</url>
<url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
</urls>
- <releaseDate>2019-11-26</releaseDate>
- <version>1.1.1</version>
- <develStage>alpha</develStage>
+ <releaseDate>2020-08-05</releaseDate>
+ <version>1.1.2</version>
+ <develStage>stable</develStage>
<comments>
FlexMailer is an email delivery engine which replaces the internal guts
of CiviMail. It is a drop-in replacement which enables *other* extensions
to provide richer email features.
</comments>
<compatibility>
- <ver>5.13</ver>
+ <ver>5.29</ver>
</compatibility>
<classloader>
<psr4 prefix="Civi\FlexMailer\" path="src"/>
var that = this;
validator.settings = $.extend({}, validator.settings, CRM.validate._defaults, CRM.validate.params);
// Call our custom validation handler.
- $(validator.currentForm).on("invalid-form.validate", validator.settings.invalidHandler );
+ $(validator.currentForm).on("invalid-form.validate", validator.settings.invalidHandler);
// Call any post-initialization callbacks
if (CRM.validate.functions && CRM.validate.functions.length) {
$.each(CRM.validate.functions, function(i, func) {
added.push(identifier);
}
// display:none causes the form to not submit when pressing "enter"
- $el.parents(buttonContainers).css({height: 0, padding: 0, margin: 0, overflow: 'hidden'}).find('.crm-button-icon').hide();
+ $el.parents(buttonContainers).css({height: 0, padding: 0, margin: 0, overflow: 'hidden'});
});
$el.dialog('option', 'buttons', buttons);
}
- **[Credits](release-notes/5.28.0.md#credits)**
- **[Feedback](release-notes/5.28.0.md#feedback)**
+## CiviCRM 5.27.4
+
+Released August 3, 2020
+
+- **[Synopsis](release-notes/5.27.4.md#synopsis)**
+- **[Bugs resolved](release-notes/5.27.4.md#bugs)**
+- **[Credits](release-notes/5.27.4.md#credits)**
+- **[Feedback](release-notes/5.27.4.md#feedback)**
+
## CiviCRM 5.27.3
Released July 23, 2020
--- /dev/null
+# CiviCRM 5.27.4
+
+Released August 3, 2020
+
+- **[Synopsis](#synopsis)**
+- **[Bugs resolved](#bugs)**
+- **[Credits](#credits)**
+- **[Feedback](#feedback)**
+
+## <a name="synopsis"></a>Synopsis
+
+| *Does this version...?* | |
+|:--------------------------------------------------------------- |:-------:|
+| Fix security vulnerabilities? | no |
+| Change the database schema? | no |
+| Alter the API? | no |
+| **Require attention to configuration options?** | **yes** |
+| **Fix problems installing or upgrading to a previous version?** | **yes** |
+| Introduce features? | no |
+| **Fix bugs?** | **yes** |
+
+## <a name="bugs"></a>Bugs resolved
+
+* **_CiviCase_: Action links are missing text labels ([dev/core#1899](https://lab.civicrm.org/dev/core/-/issues/1899):
+ [#17947](https://github.com/civicrm/civicrm-core/pull/17947))**
+* **_CiviContribute_: When editing "Amounts", default is mis-saved ([dev/core#1911](https://lab.civicrm.org/dev/core/-/issues/1911):
+ [#17960](https://github.com/civicrm/civicrm-core/pull/17960))**
+
+ If you recently edited any "Amounts", then please review and verify that the default is correct.
+ Mis-saved defaults can cause problems when submitting contributions.
+
+* **_CiviMail_: Blasts sent via Job Manager do not recover from errors ([dev/mail#72](https://lab.civicrm.org/dev/mail/-/issues/72):
+ [#18017](https://github.com/civicrm/civicrm-core/pull/18017))**
+* **_WordPress_: `[civicrm.files]` is incorrect on older sites ([dev/wordpress#66](https://lab.civicrm.org/dev/wordpress/-/issues/66):
+ [#17868](https://github.com/civicrm/civicrm-core/pull/17868))**
+
+ This fixes a regression affecting older WordPress deployments by partially reverting
+ [dev/wordpress#47](https://lab.civicrm.org/dev/wordpress/-/issues/47). This means that some WordPress configurations
+ (eg Polylang) may return to being unsupported. The issue is scheduled to be revisited circa 5.29.
+
+## <a name="credits"></a>Credits
+
+<!-- X: TIP: In buildkit, the CLI command civicredits.php can help autocomplete contributor names with the typical formatting. -->
+
+This release was developed by the following authors and reviewers:
+
+Wikimedia Foundation - Eileen McNaughton; Team Expansion - Greg Harris; Tadpole Collective - Kevin
+Cristiano; Megaphone Technology Consulting - Jon Goldberg; MJW Consulting - Matthew Wire; JMA
+Consulting - Seamus Lee; Dave D; CiviCRM - Tim Otten; Christian Wach; Agileware - Justin Freeman;
+AGH Strategies - Andrew Hunt
+
+## <a name="feedback"></a>Feedback
+
+These release notes are edited by Tim Otten and Andrew Hunt. If you'd like to
+provide feedback on them, please login to https://chat.civicrm.org/civicrm and
+contact `@agh1`.
LOCK TABLES `civicrm_mailing_component` WRITE;
/*!40000 ALTER TABLE `civicrm_mailing_component` DISABLE KEYS */;
-INSERT INTO `civicrm_mailing_component` (`id`, `name`, `component_type`, `subject`, `body_html`, `body_text`, `is_default`, `is_active`) VALUES (1,'Mailing Header','Header','Descriptive Title for this Header','Sample Header for HTML formatted content.','Sample Header for TEXT formatted content.',1,1),(2,'Mailing Footer','Footer','Descriptive Title for this Footer.','Sample Footer for HTML formatted content<br/><a href=\"{action.optOutUrl}\">Unsubscribe</a> <br/> {domain.address}','to unsubscribe: {action.optOutUrl}\n{domain.address}',1,1),(3,'Subscribe Message','Subscribe','Subscription Confirmation Request','You have a pending subscription to the {subscribe.group} mailing list. To confirm this subscription, reply to this email or click <a href=\"{subscribe.url}\">here</a>.','You have a pending subscription to the {subscribe.group} mailing list. To confirm this subscription, reply to this email or click on this link: {subscribe.url}',1,1),(4,'Welcome Message','Welcome','Your Subscription has been Activated','Welcome. Your subscription to the {welcome.group} mailing list has been activated.','Welcome. Your subscription to the {welcome.group} mailing list has been activated.',1,1),(5,'Unsubscribe Message','Unsubscribe','Un-subscribe Confirmation','You have been un-subscribed from the following groups: {unsubscribe.group}. You can re-subscribe by mailing {action.resubscribe} or clicking <a href=\"{action.resubscribeUrl}\">here</a>.','You have been un-subscribed from the following groups: {unsubscribe.group}. You can re-subscribe by mailing {action.resubscribe} or clicking ',1,1),(6,'Resubscribe Message','Resubscribe','Re-subscribe Confirmation','You have been re-subscribed to the following groups: {resubscribe.group}. You can un-subscribe by mailing {action.unsubscribe} or clicking <a href=\"{action.unsubscribeUrl}\">here</a>.','You have been re-subscribed to the following groups: {resubscribe.group}. You can un-subscribe by mailing {action.unsubscribe} or clicking {action.unsubscribeUrl}',1,1),(7,'Opt-out Message','OptOut','Opt-out Confirmation','Your email address has been removed from {domain.name} mailing lists.','Your email address has been removed from {domain.name} mailing lists.',1,1),(8,'Auto-responder','Reply','Please Send Inquiries to Our Contact Email Address','This is an automated reply from an un-attended mailbox. Please send any inquiries to the contact email address listed on our web-site.','This is an automated reply from an un-attended mailbox. Please send any inquiries to the contact email address listed on our web-site.',1,1);
+INSERT INTO `civicrm_mailing_component` (`id`, `name`, `component_type`, `subject`, `body_html`, `body_text`, `is_default`, `is_active`) VALUES (1,'Mailing Header','Header','Descriptive Title for this Header','Sample Header for HTML formatted content.','Sample Header for TEXT formatted content.',1,1),(2,'Mailing Footer','Footer','Descriptive Title for this Footer.','Sample Footer for HTML formatted content<br/><a href=\"{action.optOutUrl}\">Unsubscribe</a> <br/> {domain.address}','to unsubscribe: {action.optOutUrl}\n{domain.address}',1,1),(3,'Subscribe Message','Subscribe','Subscription Confirmation Request','You have a pending subscription to the {subscribe.group} mailing list. To confirm this subscription, reply to this email or click <a href=\"{subscribe.url}\">here</a>.','You have a pending subscription to the {subscribe.group} mailing list. To confirm this subscription, reply to this email or click on this link: {subscribe.url}',1,1),(4,'Welcome Message','Welcome','Your Subscription has been Activated','Welcome. Your subscription to the {welcome.group} mailing list has been activated.','Welcome. Your subscription to the {welcome.group} mailing list has been activated.',1,1),(5,'Unsubscribe Message','Unsubscribe','Un-subscribe Confirmation','You have been un-subscribed from the following groups: {unsubscribe.group}. You can re-subscribe by mailing {action.resubscribe} or clicking <a href=\"{action.resubscribeUrl}\">here</a>.','You have been un-subscribed from the following groups: {unsubscribe.group}. You can re-subscribe by mailing {action.resubscribe} or clicking {action.resubscribeUrl}',1,1),(6,'Resubscribe Message','Resubscribe','Re-subscribe Confirmation','You have been re-subscribed to the following groups: {resubscribe.group}. You can un-subscribe by mailing {action.unsubscribe} or clicking <a href=\"{action.unsubscribeUrl}\">here</a>.','You have been re-subscribed to the following groups: {resubscribe.group}. You can un-subscribe by mailing {action.unsubscribe} or clicking {action.unsubscribeUrl}',1,1),(7,'Opt-out Message','OptOut','Opt-out Confirmation','Your email address has been removed from {domain.name} mailing lists.','Your email address has been removed from {domain.name} mailing lists.',1,1),(8,'Auto-responder','Reply','Please Send Inquiries to Our Contact Email Address','This is an automated reply from an un-attended mailbox. Please send any inquiries to the contact email address listed on our web-site.','This is an automated reply from an un-attended mailbox. Please send any inquiries to the contact email address listed on our web-site.',1,1);
/*!40000 ALTER TABLE `civicrm_mailing_component` ENABLE KEYS */;
UNLOCK TABLES;
<div class="crm-block crm-form-block crm-acl-form-block">
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Delete will remove this permission from the specified ACL Role.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
{if $action eq 8}
<div class="messages status no-popup">
<dl>
- <dt><div class="icon inform-icon"></div></dt>
+ <dt>{icon icon="fa-info-circle"}{/icon}</dt>
<dd>
{ts}WARNING: Delete will remove this permission from the specified ACL Role.{/ts} {ts}Do you want to continue?{/ts}
</dd>
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Deleting this option will remove this ACL Role Assignment.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
*}
{* No matches for submitted search request. *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $qill}{ts}No matches found for:{/ts}
{include file="CRM/common/displaySearchCriteria.tpl"}
{else}
<div class="crm-block crm-form-block crm-activity_delete-form-block">
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<p>{ts}Are you sure you want to delete the selected Activities?{/ts}</p>
<p>{include file="CRM/Activity/Form/Task.tpl"}</p>
</div>
{include file="CRM/common/formButtons.tpl" location="bottom"}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no records selected for Print.{/ts}
</div>
{/if}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no records selected.{/ts}
</div>
{/if}
{/strip}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no scheduled activities assigned to you.{/ts}
</div>
<div class="crm-block crm-form-block crm-contact-type-form-block">
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: {ts}This action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}{/ts}
</div>
{else}
<div class="crm-block crm-form-block crm-admin-optionvalue-form-block">
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
- {ts}WARNING: Uninstalling this extension might result in the loss of all records which use the extension.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone. Please review the extension information below before you make final decision.{/ts} {ts}Do you want to continue?{/ts}
+ {icon icon="fa-info-circle"}{/icon}
+ {ts}WARNING: Uninstalling this extension might result in the loss of all records which use the extension.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone. Please review the extension information below before you make final decision.{/ts} {ts}Do you want to continue?{/ts}
</div>
{/if}
{if $action eq 1}
- <div class="messages status no-popup">
- <div class="icon inform-icon"></div>
- {ts}Installing this extension will provide you with new functionality. Please make sure that the extension you're installing comes from a trusted source.{/ts} {ts}Do you want to continue?{/ts}
+ <div class="messages status no-popup">
+ {icon icon="fa-info-circle"}{/icon}
+ {ts}Installing this extension will provide you with new functionality. Please make sure that the extension you're installing comes from a trusted source.{/ts} {ts}Do you want to continue?{/ts}
</div>
{/if}
{if $action eq 2}
- <div class="messages status no-popup">
- <div class="icon inform-icon"></div>
- {ts}Downloading this extension will provide you with new functionality. Please make sure that the extension you're installing or upgrading comes from a trusted source.{/ts} {ts}Do you want to continue?{/ts}
+ <div class="messages status no-popup">
+ {icon icon="fa-info-circle"}{/icon}
+ {ts}Downloading this extension will provide you with new functionality. Please make sure that the extension you're installing or upgrading comes from a trusted source.{/ts} {ts}Do you want to continue?{/ts}
</div>
{/if}
{if $action eq 8 or $action eq 1 or $action eq 2}
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Deleting this Scheduled Job will cause some important site functionality to stop working.{/ts} {ts}Do you want to continue?{/ts}
</div>
{elseif $action eq 4}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$jobName}Are you sure you would like to execute %1 job?{/ts}
</div>
{else}
<div class="crm-block crm-form-block crm-labelFormat-form-block">
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$formatName}WARNING: You are about to delete the Label Format titled <strong>%1</strong>.{/ts} {ts}Do you want to continue?{/ts}
</div>
{elseif $action eq 16384}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$formatName}Are you sure you would like to make a copy of the Label Format titled <strong>%1</strong>?{/ts}
</div>
{else}
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Deleting this option will result in the loss of all location type records which use the option.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Deleting this option will result in the loss of mail settings data.{/ts} {ts}Do you want to continue?{/ts}
</div>
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
</table>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$mappingName}WARNING: Are you sure you want to delete mapping '<b>%1</b>'?{/ts} {ts}This action cannot be undone.{/ts}
</div>
<br />
<div class="form-item" id="message_templates">
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{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>
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Deleting this option gruop will result in the loss of all records which use the option.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$gLabel}WARNING: Deleting this option will result in the loss of all %1 related records which use the option.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Deleting this Participant Status will remove all of its settings.{/ts} {ts}Do you want to continue?{/ts}
</div>
<div>{include file="CRM/common/formButtons.tpl"}
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{$deleteMessage|escape}
</div>
{else}
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}Do you want to continue?{/ts}
</div>
{else}
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$formatName}WARNING: You are about to delete the PDF Page Format titled <strong>%1</strong>.{/ts}<p>{ts}This will remove the format from all Message Templates that use it. Do you want to continue?{/ts}</p>
</div>
{else}
<td>
{$form.editor_id.html}
- <span class="crm-button crm-icon-button" style="display:inline-block;vertical-align:middle;float:none!important;">
- <i class="crm-i fa-wrench" style="margin: 0 -18px 0 2px;" aria-hidden="true"></i>
+ <span class="crm-button" style="display:inline-block;vertical-align:middle;float:none!important;">
+ <i class="crm-i fa-wrench" aria-hidden="true"></i>
{$form.ckeditor_config.html}
</span>
</td>
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$reminderName}WARNING: You are about to delete the Reminder titled <strong>%1</strong>.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
</table>
</div>
<div class="crm-submit-buttons">
- <span class="crm-button crm-i-button">
- <i class="crm-i fa-bolt" aria-hidden="true"></i><input type="submit" value="{ts}Execute{/ts}" class="crm-form-submit" accesskey="S" title="{ts}Execute API call and display results{/ts}"/>
+ <span class="crm-button">
+ <i class="crm-i fa-bolt" aria-hidden="true"></i> <input type="submit" value="{ts}Execute{/ts}" class="crm-form-submit" accesskey="S" title="{ts}Execute API call and display results{/ts}"/>
</span>
</div>
</div>
<div class="crm-submit-buttons">
- <span class="crm-button crm-i-button">
+ <span class="crm-button">
<i class="crm-i fa-wrench" aria-hidden="true"></i> <input type="submit" value="{ts}Save{/ts}" name="save" class="crm-form-submit" accesskey="S"/>
</span>
- <span class="crm-button crm-i-button">
+ <span class="crm-button">
<i class="crm-i fa-times" aria-hidden="true"></i> <input type="submit" value="{ts}Revert to Default{/ts}" name="revert" class="crm-form-submit" onclick="return confirm('{$revertConfirm}');"/>
</span>
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{capture assign=crmURL}{crmURL p='civicrm/event/add' q="action=add&is_template=1&reset=1"}{/capture}
{ts 1=$crmURL}There are no Event Templates present. You can <a href='%1'>add one</a>.{/ts}
</div>
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no extensions to display. Please click "Refresh" to update information about available extensions.{/ts}
</div>
{/if}
<div class="crm-content-block crm-block">
{foreach from=$extAddNewReqs item=req}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{$req.title}<br/>
{$req.message}
</div>
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1="https://civicrm.org/extensions"}There are no extensions to display. Click the "Add New" tab to browse and install extensions posted on the <a href="%1">public CiviCRM Extensions Directory</a>. If you have downloaded extensions manually and don't see them here, try clicking the "Refresh" button.{/ts}
</div>
{/if}
</div>
{elseif $action ne 1}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no jobs configured.{/ts}
</div>
<div class="action-link">
</div>
{elseif $action ne 1}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $jobId}
{ts}This scheduled job does not have any log entries.{/ts}
{else}
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{capture assign=crmURL}{crmURL p='civicrm/admin/labelFormats' q="action=add&reset=1"}{/capture}
{ts 1=$crmURL}There are no Label Formats configured. You can<a href='%1'>add one</a>.{/ts}
</div>
{if empty( $template_row) }
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$crmURL}There are no User-driven Message Templates entered. You can <a href='%1'>add one</a>.{/ts}
</div>
{/if}
</div>
{elseif $action ne 1}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no Payment Processors entered.{/ts}
</div>
<div class="action-link">
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}None found.{/ts}
</div>
{/if}
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}None found.{/ts}
</div>
{/if}
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}This may mean the loss of a substantial amount of data, and the action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Deleting this batch will result in the loss of all data entered for the batch.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
<table class="form-layout">
<tr>
<td colspan="2">
- <div class="status"><div class="icon inform-icon"></div> {ts}Are you sure you want to delete this Campaign?{/ts}</div>
+ <div class="status">{icon icon="fa-info-circle"}{/icon}{ts}Are you sure you want to delete this Campaign?{/ts}</div>
</td>
</tr>
</table>
{if $errorMessages}
<div class="messages status crm-error no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<ul>
{foreach from=$errorMessages item=errorMsg}
<li>{ts}{$errorMsg}{/ts}</li>
<tr>
<td colspan="2">
<div class="status">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}Are you sure you want to delete this Petition?{/ts}</div>
</td>
</tr>
{if !$hasCampaigns}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}None found.{/ts}
</div>
*}
{* No matches for submitted search request. *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $qill}{ts}No matches found for:{/ts}
{include file="CRM/common/displaySearchCriteria.tpl"}
{else}
{if !$hasPetitions}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}None found.{/ts}
</div>
{if !$hasSurveys}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}None found.{/ts}
</div>
<table class="form-layout">
<tr>
<td colspan="2">
- <div class="status"><div class="icon inform-icon"></div> {ts 1=$surveyTitle}Are you sure you want to delete the %1 survey?{/ts}</div>
+ <div class="status">{icon icon="fa-info-circle"}{/icon}{ts 1=$surveyTitle}Are you sure you want to delete the %1 survey?{/ts}</div>
</td>
</tr>
</table>
*}
{if $votingTab and $errorMessages}
<div class='messages status'>
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<ul>
{foreach from=$errorMessages item=errorMsg}
<li>{ts}{$errorMsg}{/ts}</li>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"/>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no records selected for Print.{/ts}
</div>
{/if}
<tr class="crm-campaign-task-release-form-block-surveytitle">
<td colspan=2>
<div class="status">
- <div class="icon inform-icon"></div> {ts 1=$surveyTitle}Do you want to release respondents for '%1' ?{/ts}
+ {icon icon="fa-info-circle"}{/icon}{ts 1=$surveyTitle}Do you want to release respondents for '%1' ?{/ts}
</div>
</td>
</tr>
<tr class="crm-campaign-task-reserve-form-block-surveytitle">
<td colspan=2>
<div class="status">
- <div class="icon inform-icon"></div> {ts 1=$surveyTitle}Do you want to reserve respondents for '%1' ?{/ts}
+ {icon icon="fa-info-circle"}{/icon}{ts 1=$surveyTitle}Do you want to reserve respondents for '%1' ?{/ts}
</div>
</td>
</tr>
{else}
<div class="status">
- <div class="icon inform-icon"></div> {ts}None found.{/ts}
+ {icon icon="fa-info-circle"}{/icon}{ts}None found.{/ts}
</div>
{/if}
<div class="action-link">
+--------------------------------------------------------------------+
*}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $success}
{ts 1=$display_name 2=$email}<strong>%1 - your email address '%2' has been successfully verified.</strong>{/ts}
{else}
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon">
- {ts p=$addSurveyType.0 q=$addSurveyType.1}There are no survey types entered. You can <a href='%1'>add one</a>.{/ts}</div>
+ {icon icon="fa-info-circle"}{/icon}
+ {ts p=$addSurveyType.0 q=$addSurveyType.1}There are no survey types entered. You can <a href='%1'>add one</a>.{/ts}
</div>
{/if}
{/if}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}You are not authorized to access this page.{/ts}
</div>
{/if}
<h3>{if $action eq 8}{ts}Delete Case{/ts}{elseif $action eq 32768}{ts}Restore Case{/ts}{/if}</h3>
{if $action eq 8 or $action eq 32768 }
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $action eq 8}
{ts}Click Delete to move this case and all associated activities to the Trash.{/ts}
{else}
{* template for assigning the current case to another client*}
<div class="crm-block crm-form-block crm-case-editclient-form-block">
<div class="messages status no-popup">
- <div class="icon inform-icon"></div> {ts 1=$currentClientName}This is case is currently assigned to %1.{/ts}
+ {icon icon="fa-info-circle"}{/icon} {ts 1=$currentClientName}This is case is currently assigned to %1.{/ts}
</div>
<div class="crm-form-block">
<table class="form-layout-compressed">
*}
{* No matches for submitted search request. *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $qill}{ts}No matches found for:{/ts}
{include file="CRM/common/displaySearchCriteria.tpl"}
{else}
*}
{* Confirmation of contribution deletes *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}Are you sure you want to delete the selected cases? This will move the case(s) and all associated activities to the Trash.{/ts}<br/>
<p>{include file="CRM/Case/Form/Task.tpl"}</p>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no records selected for Print.{/ts}
</div>
{/if}
*}
{* Confirmation of contribution deletes *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}Are you sure you want to restore the selected cases? This operation will retrieve the case(s) and all associated activities from Trash.{/ts}</p>
<p>{include file="CRM/Case/Form/Task.tpl"}</p>
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no records selected.{/ts}
</div>
{/if}
{capture assign=docLink}{docURL page="user/case-management/set-up" text="CiviCase Setup documentation"}{/capture}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<strong>{ts}You need to setup and load Case and Activity configuration files before you can begin using the CiviCase component.{/ts}</strong>
{ts 1=$docLink}Refer to the %1 to learn about this process.{/ts}
</div>
{elseif $redirectToCaseAdmin}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<strong>{ts}Oops, It looks like there are no active case types.{/ts}</strong>
{if call_user_func(array('CRM_Core_Permission','check'), ' administer CiviCase')}
{capture assign=adminCaseTypeURL}{crmURL p='civicrm/a/#/caseType'}
{include file="CRM/Case/Form/Selector.tpl"}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no case records for this contact.{/ts}
</div>
{/if}
{if $blockId gt 1}<fieldset><legend>{ts}Supplemental Address{/ts}</legend>{/if}
<table class="form-layout-compressed crm-edit-address-form">
{if $masterAddress.$blockId gt 0 }
- <tr><td><div class="message status"><div class="icon inform-icon"></div> {ts 1=$masterAddress.$blockId}This address is shared with %1 contact record(s). Modifying this address will automatically update the shared address for these contacts.{/ts}</div></td></tr>
+ <tr><td><div class="message status">{icon icon="fa-info-circle"}{/icon} {ts 1=$masterAddress.$blockId}This address is shared with %1 contact record(s). Modifying this address will automatically update the shared address for these contacts.{/ts}</div></td></tr>
{/if}
{if $className eq 'CRM_Contact_Form_Contact'}
</div>
<div class="message status">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<strong>{ts}WARNING: The duplicate contact record WILL BE DELETED after the merge is complete.{/ts}</strong>
</div>
{if $user}
<div class="message status">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<strong>{ts 1=$config->userFramework}WARNING: There are %1 user accounts associated with both the original and duplicate contacts. Ensure that the %1 user you want to retain is on the right - if necessary use the 'Flip between original and duplicate contacts.' option at top to swap the positions of the two records before doing the merge.
The user record associated with the duplicate contact will not be deleted, but will be unlinked from the associated contact record (which will be deleted).
You will need to manually delete that user (click on the link to open the %1 user account in new screen). You may need to give thought to how you handle any content or contents associated with that user.{/ts}</strong>
*}
{* Custom searches. Default template for NO MATCHES on submitted search request. *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $qill}
{ts}No matches found for:{/ts}
{include file="CRM/common/displaySearchCriteria.tpl"}
{if !$table and $summary.addShowAllLink.Contact}
<div class="crm-section full-text-view-all-section">
<a href="{crmURL p='civicrm/contact/search/custom' q="csid=`$csID`&reset=1&force=1&table=Contact&text=$text"}"
- title="{ts}View all results for contacts{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for contacts{/ts}</a>
+ title="{ts}View all results for contacts{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for contacts{/ts}</a>
</div>{/if}
{* note we using location="below" because we don't want to use rows per page for now. And therefore don't put location="bottom" for now. *}
{if $table}{include file="CRM/common/pager.tpl" location="below"}{/if}
{if !$table and $summary.addShowAllLink.Activity}
<div class="crm-section full-text-view-all-section">
<a href="{crmURL p='civicrm/contact/search/custom' q="csid=`$csID`&reset=1&force=1&table=Activity&text=$text"}"
- title="{ts}View all results for activities{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for activities{/ts}</a>
+ title="{ts}View all results for activities{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for activities{/ts}</a>
</div>
{/if}
{if $table}{include file="CRM/common/pager.tpl" location="below"}{/if}
{if !$table and $summary.addShowAllLink.Case}
<div class="crm-section full-text-view-all-section">
<a href="{crmURL p='civicrm/contact/search/custom' q="csid=`$csID`&reset=1&force=1&table=Case&text=$text"}"
- title="{ts}View all results for cases{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for cases{/ts}</a>
+ title="{ts}View all results for cases{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for cases{/ts}</a>
</div>
{/if}
{if $table}{include file="CRM/common/pager.tpl" location="below"}{/if}
{if !$table and $summary.addShowAllLink.Contribution}
<div class="crm-section full-text-view-all-section">
<a href="{crmURL p='civicrm/contact/search/custom' q="csid=`$csID`&reset=1&force=1&table=Contribution&text=$text"}"
- title="{ts}View all results for contributions{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for contributions{/ts}</a>
+ title="{ts}View all results for contributions{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for contributions{/ts}</a>
</div>
{/if}
{if $table}{include file="CRM/common/pager.tpl" location="below"}{/if}
{if !$table and $summary.addShowAllLink.Participant}
<div class="crm-section full-text-view-all-section"><a
href="{crmURL p='civicrm/contact/search/custom' q="csid=`$csID`&reset=1&force=1&table=Participant&text=$text"}"
- title="{ts}View all results for participants{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for participants{/ts}</a>
+ title="{ts}View all results for participants{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for participants{/ts}</a>
</div>{/if}
{if $table}{include file="CRM/common/pager.tpl" location="below"}{/if}
{* END Actions/Results section *}
{if !$table and $summary.addShowAllLink.Membership}
<div class="crm-section full-text-view-all-section">
<a href="{crmURL p='civicrm/contact/search/custom' q="csid=`$csID`&reset=1&force=1&table=Membership&text=$text"}"
- title="{ts}View all results for memberships{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for memberships{/ts}</a>
+ title="{ts}View all results for memberships{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for memberships{/ts}</a>
</div>
{/if}
{if $table}{include file="CRM/common/pager.tpl" location="below"}{/if}
{if !$table and $summary.addShowAllLink.File}
<div class="crm-section full-text-view-all-section">
<a href="{crmURL p='civicrm/contact/search/custom' q="csid=`$csID`&reset=1&force=1&table=File&text=$text"}"
- title="{ts}View all results for files{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for files{/ts}</a>
+ title="{ts}View all results for files{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for files{/ts}</a>
</div>{/if}
{if $table}{include file="CRM/common/pager.tpl" location="below"}{/if}
{* END Actions/Results section *}
*}
{* No matches for submitted search request or viewing an empty group. *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $context EQ 'smog'}
{capture assign=crmURL}{crmURL q="context=amtg&amtgID=`$group.id`&reset=1"}{/capture}{ts 1=$group.title 2=$crmURL}%1 has no contacts which match your search criteria. You can <a href='%2'>add contacts here.</a>{/ts}
{else}
{* Confirmation of contact deletes *}
<div class="crm-block crm-form-block crm-contact-task-delete-form-block">
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $restore}
{ts}Are you sure you want to restore the selected contact(s)? The contact(s) and all related data will be fully restored.{/ts}
{elseif $trash}
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no records selected for Print.{/ts}
</div>
{/if}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no records selected for Print.{/ts}
</div>
{/if}
<div class="crm-block crm-form-block crm-unhold-form-block">
<div class="spacer"></div>
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<p>{ts}Are you sure you want to unhold email of selected contact(s)?.{/ts} {ts}This action cannot be undone.{/ts}</p>
<p>{include file="CRM/Contact/Form/Task.tpl"}</p>
</div>
<div class="section-shown">
{if !$groupSmart AND !$groupParent}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}This contact does not currently belong to any smart groups.{/ts}
</div>
{/if}
*}
{* Confirmation of contact deletes *}
<div class="messages status no-popup">
-<div class="icon inform-icon"></div>
+{icon icon="fa-info-circle"}{/icon}
<p>{ts 1=$displayName}Are you sure you want to delete the contact record and all related information for <strong>%1</strong>?{/ts}</p>
<p>{ts}This action cannot be undone.{/ts}</p>
</div>
</table>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}This contact does not belong to any groups.{/ts}
</div>
{/if}
<div class="view-content view-contact-groups">
{if $groupCount eq 0}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}This contact does not currently belong to any groups.{/ts}
</div>
{else}
</table>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}None found.{/ts}
</div>
{/if}
</div>
{elseif ($action eq 16)}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no Notes for this contact.{/ts}
</div>
{/if}
<div class="view-content">
{if $groupCount eq 0 }
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}You are not currently subscribed to any Groups.{/ts}
</div>
{/if}
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: If you delete this option, contributors will not be able to use this credit card type on your Online Contribution pages.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
{if !$email}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div> {ts}You will not be able to send an automatic email receipt for this payment because there is no email address recorded for this contact. If you want a receipt to be sent when this payment is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the payment.{/ts}
+ {icon icon="fa-info-circle"}{/icon}{ts}You will not be able to send an automatic email receipt for this payment because there is no email address recorded for this contact. If you want a receipt to be sent when this payment is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the payment.{/ts}
</div>
{/if}
{if $newCredit AND $contributionMode EQ null}
<div class="crm-block crm-form-block crm-auto-renew-membership-cancellation">
<div class="help">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{$cancelRecurDetailText}
{if $cancelRecurNotSupportedText}
<div class="status-warning">{$cancelRecurNotSupportedText}</div>
{if !$email and $action neq 8 and $context neq 'standalone'}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div> {ts}You will not be able to send an automatic email receipt for this contribution because there is no email address recorded for this contact. If you want a receipt to be sent when this contribution is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the contribution.{/ts}
+ {icon icon="fa-info-circle"}{/icon}{ts}You will not be able to send an automatic email receipt for this contribution because there is no email address recorded for this contact. If you want a receipt to be sent when this contribution is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the contribution.{/ts}
</div>
{/if}
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Deleting this contribution will result in the loss of the associated financial transactions (if any).{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
</div>
{/if}
+ {if call_user_func(array('CRM_Core_Permission','check'), 'administer CiviCRM') }
+ {capture assign="buttonTitle"}{ts}Configure Contribution Page{/ts}{/capture}
+ {crmButton target="_blank" p="civicrm/admin/contribute/settings" q="reset=1&action=update&id=`$contributionPageID`" title="$buttonTitle" icon="fa-wrench"}{ts}Configure{/ts}{/crmButton}
+ <div class='clear'></div>
+ {/if}
{include file="CRM/common/TrackingFields.tpl"}
<div class="crm-contribution-page-id-{$contributionPageID} crm-block crm-contribution-main-form-block">
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}Are you sure you want to remove this premium product from this Contribution page?{/ts}
</div>
{elseif $action eq 1024}
<tr id="minMaxFields" class="crm-contribution-form-block-minMaxFields"><td> </td><td>
<table class="form-layout-compressed">
<tr class="crm-contribution-form-block-min_amount"><th scope="row" class="label">{$form.min_amount.label}</th>
- <td>{$form.min_amount.html|crmMoney}</td></tr>
+ <td>{$form.min_amount.html}</td></tr>
<tr class="crm-contribution-form-block-max_amount"><th scope="row" class="label">{$form.max_amount.label}</th>
- <td>{$form.max_amount.html|crmMoney}<br />
+ <td>{$form.max_amount.html}<br />
<span class="description">{ts 1=5|crmMoney}If you have chosen to <strong>Allow Other Amounts</strong>, you can use the fields above to control minimum and/or maximum acceptable values (e.g. don't allow contribution amounts less than %1).{/ts}</span></td></tr>
</table>
</td></tr>
<tr class="columnheader" ><th scope="column">{ts}Contribution Label{/ts}</th><th scope="column">{ts}Amount{/ts}</th><th scope="column">{ts}Default?{/ts}<br />{$form.default.0.html}</th></tr>
{section name=loop start=1 loop=11}
{assign var=idx value=$smarty.section.loop.index}
- <tr><td class="even-row">{$form.label.$idx.html}</td><td>{$form.value.$idx.html|crmMoney}</td><td class="even-row">{$form.default.$idx.html}</td></tr>
+ <tr><td class="even-row">{$form.label.$idx.html}</td><td>{$form.value.$idx.html}</td><td class="even-row">{$form.default.$idx.html}</td></tr>
{/section}
</table>
</fieldset>
*}
{* this template is used for confirmation of delete for a group *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $relatedContributions}
{ts 1=$title}You cannot delete this Contribution Page because it has already been used to submit a contribution or membership payment. It is recommended that your disable the page instead of deleting it, to preserve the integrity of your contribution records. If you do want to completely delete this contribution page, you first need to search for and delete all of the contribution transactions associated with this page in CiviContribute.{/ts}
{else}
<h3>{ts}Configure Widget{/ts}</h3>
{if $showStatus}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}It looks like you may have posted and / or distributed the flash version of the Contribution widget. We won't be supporting the flash version in next release. You should try and get all sites using the flash widget to update to the improved HTML widget code below as soon as possible.{/ts}
</div>
{/if}
<div class="crm-block crm-form-block crm-contribution-manage_premiums-form-block">
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}Are you sure you want to delete this premium?{/ts} {ts}This action cannot be undone.{/ts} {ts}This will also remove the premium from any contribution pages that currently include it.{/ts}
</div>
{elseif $action eq 1024}
{* this template is used for confirmation of delete for a group *}
<fieldset><legend>{ts}Delete Campaign Page {/ts}</legend>
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$title}Are you sure you want to delete Campaign Page '%1'?{/ts}<br />
{ts}This action cannot be undone.{/ts}
</div>
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Deleting this option will result in the loss of all contribution records which use this option.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
*}
{* No matches for submitted search request. *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $qill}{ts}No matches found for:{/ts}
{include file="CRM/common/displaySearchCriteria.tpl"}
{else}
*}
{* Confirmation of contribution deletes *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<p>{ts}Are you sure you want to delete the selected contributions? This delete operation cannot be undone and will delete all transactions and activity associated with these contributions.{/ts}</p>
<p>{include file="CRM/Contribute/Form/Task.tpl"}</p>
</div>
+--------------------------------------------------------------------+
*}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{include file="CRM/Contribute/Form/Task.tpl"}
</div>
{if $selectedOutput ne 'email'}
+--------------------------------------------------------------------+
*}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{include file="CRM/Contribute/Form/Task.tpl"}
</div>
<div class="help">
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"/>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no records selected for Print.{/ts}
</div>
{/if}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no records selected.{/ts}
</div>
{/if}
+--------------------------------------------------------------------+
*}
<div class="form-item crm-block crm-form-block crm-contribution-form-block">
-<div class="help">
- {ts}Use this form to record received payments for 'pay later' online contributions, membership signups and event registrations. You can use the Transaction ID field to record account+check number, bank transfer identifier, or other unique payment identifier.{/ts}
-</div>
-<fieldset>
- <legend>{ts}Update Contribution Status{/ts}</legend>
- <table class="form-layout-compressed">
- <tr class="crm-contribution-form-block-contribution_status_id"><td class="label">{$form.contribution_status_id.label}</td><td class="html-adjust">{$form.contribution_status_id.html}<br />
- <span class="description">{ts}Assign the selected status to all contributions listed below.{/ts}</td></tr>
- <tr class="crm-contribution-form-block-is_email_receipt"><td class="label">{$form.is_email_receipt.label}</td>
- <td class="html-adjust">{$form.is_email_receipt.html}<br />
- <span class="description">{ts}When checked CiviCRM will send an e-mail receipt to the donor. Leave unchecked when you don't want to send an e-mail.{/ts}
- </td>
- </tr>
- </table>
-<table>
-<tr class="columnheader">
- <th>{ts}Name{/ts}</th>
- <th class="right">{ts}Amount{/ts} </th>
- <th>{ts}Source{/ts}</th>
- <th>{ts}Fee Amount{/ts}</th>
- <th>{ts}Payment Method{/ts}</th>
- <th>{ts}Check{/ts} #</th>
- <th>{ts}Transaction ID{/ts}</th>
- <th>{ts}Transaction Date{/ts}</th>
-</tr>
+ <h3>{ts}Record payments for contributions{/ts}</h3>
+ <div class="help">
+ <p>{ts}Use this form to record received payments for "pay later" online contributions, membership signups and event registrations. You can use the Transaction ID field to record account+check number, bank transfer identifier, or other unique payment identifier.{/ts}</p>
+ <p>{ts}The contribution status will be updated as appropriate. To update contribution statuses directly, return to the search results and select "Update multiple contributions".{/ts}</p>
+ </div>
+
+ <table class="form-layout-compressed">
+ <tr class="crm-contribution-form-block-is_email_receipt">
+ <td class="label">{$form.is_email_receipt.label}</td>
+ <td class="html-adjust">{$form.is_email_receipt.html}<br />
+ <span class="description">{ts}When checked CiviCRM will send an e-mail receipt to the donor. Leave unchecked when you don't want to send an e-mail.{/ts}</span>
+ </td>
+ </tr>
+ </table>
+ <table>
+ <tr class="columnheader">
+ <th>{ts}Name{/ts}</th>
+ <th class="right">{ts}Amount{/ts} </th>
+ <th>{ts}Source{/ts}</th>
+ <th>{ts}Fee Amount{/ts}</th>
+ <th>{ts}Payment Method{/ts}</th>
+ <th>{ts}Check{/ts} #</th>
+ <th>{ts}Transaction ID{/ts}</th>
+ <th>{ts}Transaction Date{/ts}</th>
+ </tr>
-{foreach from=$rows item=row}
-<tr class="{cycle values="odd-row,even-row"}">
- <td>{$row.display_name}</td>
- <td class="right nowrap">{$row.amount|crmMoney} </td>
- <td>{$row.source}</td>
- {assign var="element_name" value="fee_amount_"|cat:$row.contribution_id}
- <td>{$form.$element_name.html}</td>
- {assign var="element_name" value="payment_instrument_id_"|cat:$row.contribution_id}
- <td class="form-text four">{$form.$element_name.html}</td>
- {assign var="element_name" value="check_number_"|cat:$row.contribution_id}
- <td class="form-text four">{$form.$element_name.html|crmAddClass:four}</td>
- {assign var="element_name" value="trxn_id_"|cat:$row.contribution_id}
- <td>{$form.$element_name.html|crmAddClass:eight}</td>
- {assign var="element_name" value="trxn_date_"|cat:$row.contribution_id}
- <td>{$form.$element_name.html}</td>
-</tr>
-{/foreach}
-</table>
+ {foreach from=$rows item=row}
+ <tr class="{cycle values="odd-row,even-row"}">
+ <td>{$row.display_name}</td>
+ <td class="right nowrap">{$row.amount|crmMoney} </td>
+ <td>{$row.source}</td>
+ {assign var="element_name" value="fee_amount_"|cat:$row.contribution_id}
+ <td>{$form.$element_name.html}</td>
+ {assign var="element_name" value="payment_instrument_id_"|cat:$row.contribution_id}
+ <td class="form-text four">{$form.$element_name.html}</td>
+ {assign var="element_name" value="check_number_"|cat:$row.contribution_id}
+ <td class="form-text four">{$form.$element_name.html|crmAddClass:four}</td>
+ {assign var="element_name" value="trxn_id_"|cat:$row.contribution_id}
+ <td>{$form.$element_name.html|crmAddClass:eight}</td>
+ {assign var="element_name" value="trxn_date_"|cat:$row.contribution_id}
+ <td>{$form.$element_name.html}</td>
+ </tr>
+ {/foreach}
+ </table>
<div class="crm-submit-buttons">{$form.buttons.html}</div>
-</fieldset>
</div>
+--------------------------------------------------------------------+
*}
<div class="help">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $mode eq 'auto_renew'}
{ts}Use this form to update the credit card and billing name and address used with the auto-renewal option for your {$membershipType} membership.{/ts}
{else}
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$newPageURL}No contribution pages have been created yet. Click <a accesskey="N" href='%1'>here</a> to create a new contribution page.{/ts}
</div>
{/if}
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}No contributions have been recorded for this recurring contribution.{/ts}
</div>
{/if}
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}None found.{/ts}
</div>
{/if}
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}You do not have any active Personal Campaign pages.{/ts}
</div>
{/if}
{if $showForm eq false}
<div class="messages status no-popup">
{if $products ne null }
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{capture assign=crmURL}{crmURL p='civicrm/admin/contribute/addProductToPage' q="reset=1&action=update&id=$id"}{/capture}
{ts 1=$crmURL}There are no premiums offered on this contribution page yet. You can <a href='%1'>add one</a>.{/ts}
{else}
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$managePremiumsURL}There are no active premiums for your site. You can <a href='%1'>create and/or enable premiums here</a>.{/ts}
{/if}
</div>
{include file="CRM/Contribute/Form/Selector.tpl"}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}No contributions have been recorded from this contact.{/ts}
</div>
{/if}
{/if}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no contributions on record for you.{/ts}
</div>
{/if}
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{$deleteMessage|escape}
</div>
{else}
*}
<div class="crm-block crm-form-block crm-custom-field-form-block">
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
- <div class='status'><div class="icon inform-icon"></div>
+ <div class='status'>{icon icon="fa-info-circle"}{/icon}
{ts}Warning: This functionality is currently in beta stage. Consider backing up your database before using it. Click "Cancel" to return to the "edit custom field" form without making changes.{/ts}
</div>
<table class="form-layout">
{* this template is used for confirmation of delete for a Fields *}
<div class="crm-block crm-form-block crm-custom-deletefield-form-block">
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$title}WARNING: Deleting this custom field will result in the loss of all '%1' data. Any Profile form and listings field(s) linked with '%1' will also be deleted.{/ts} {ts}This action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
</div>
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
<fieldset><legend>{ts}Delete Attached File{/ts}</legend>
<div class="status">
<dl>
- <dt><div class="icon inform-icon"></div></dt>
+ <dt>{icon icon="fa-info-circle"}{/icon}</dt>
<dd>
{ts}WARNING: Are you sure you want to delete the attached file?{/ts}
</dd>
{include file="CRM/common/formButtons.tpl" location="top"}
</div>
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$title}WARNING: Deleting this custom field set will result in the loss of all '%1' data.{/ts} {ts}This action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
</div>
<div class="crm-submit-buttons">
{/if} {* $action ne view *}
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Deleting this custom field option will result in the loss of all related data.{/ts} {ts}This action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
{else}
{if $reusedNames}
<div class="message status">
- <div class="icon inform-icon"></div> {ts 1=$reusedNames}These Multiple Choice Options are shared by the following custom fields: %1{/ts}
+ {icon icon="fa-info-circle"}{/icon} {ts 1=$reusedNames}These Multiple Choice Options are shared by the following custom fields: %1{/ts}
</div>
{/if}
{/foreach}
{if !$feeds}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}Sorry but we are not able to provide this at the moment.{/ts}
</div>
{/if}
{include file="CRM/common/formButtons.tpl" location="top"}
</div>
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<div>
{if $isTemplate}
{ts}Warning: Deleting this event template will also delete associated Event Registration Page and Event Fee configurations.{/ts} {ts}This action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
{if $action eq 8} {* If action is Delete *}
<div class="crm-participant-form-block-delete messages status no-popup">
<div class="crm-content">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Deleting this registration will result in the loss of related payment records (if any).{/ts} {ts}Do you want to continue?{/ts}
</div>
{if $additionalParticipant}
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
{if !$email}
<div class="messages status no-popup">
- <i class="crm-i fa-info-circle" aria-hidden="true"></i> {ts}You will not be able to send an automatic email receipt for this payment because there is no email address recorded for this contact. If you want a receipt to be sent when this payment is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the payment.{/ts}
+ <i class="crm-i fa-info-circle" aria-hidden="true"></i> {ts}You will not be able to send an automatic email receipt for this payment because there is no email address recorded for this contact. If you want a receipt to be sent when this payment is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the payment.{/ts}
</div>
{/if}
<table class="form-layout">
| and copyright information, see https://civicrm.org/licensing |
+--------------------------------------------------------------------+
*}
+{if call_user_func(array('CRM_Core_Permission','check'), 'administer CiviCRM') }
+ {capture assign="buttonTitle"}{ts}Configure Event{/ts}{/capture}
+ {crmButton target="_blank" p="civicrm/event/manage/settings" q="reset=1&action=update&id=`$event.id`" title="$buttonTitle" icon="fa-wrench"}{ts}Configure{/ts}{/crmButton}
+ <div class='clear'></div>
+{/if}
{* Callback snippet: Load payment processor *}
{if $action & 1024}
{include file="CRM/Event/Form/Registration/PreviewHeader.tpl"}
*}
{* No matches for submitted search request. *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $qill}{ts}No matches found for:{/ts}
{include file="CRM/common/displaySearchCriteria.tpl"}
{else}
{* Confirmation of Cancel Registration *}
<div class="crm-block crm-form-block crm-event-cancel-form-block">
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<div>
<p>{ts}Are you sure you want to set status to Cancelled for the selected participants?{/ts}</p>
<p>{include file="CRM/Event/Form/Task.tpl"}</p>
{* Confirmation of participation deletes *}
<div class="crm-block crm-form-block crm-event-delete-form-block">
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<div>
<p>{ts}Are you sure you want to delete the selected participations? This delete operation cannot be undone and will delete all transactions and activity associated with these participations.{/ts}</p>
<p>{include file="CRM/Event/Form/Task.tpl"}</p>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div> {ts}There are no records selected for Print.{/ts}
+ {icon icon="fa-info-circle"}{/icon}{ts}There are no records selected for Print.{/ts}
</div>
{/if}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div> {ts}There are no records selected.{/ts}
+ {icon icon="fa-info-circle"}{/icon}{ts}There are no records selected.{/ts}
</div>
{/if}
{if $actionColumn}
<td class="crm-event-isMap">
{if $values.isMap}
- <a href="{$values.isMap}" title="{ts}Map event location{/ts}"><i class="crm-i fa-map-marker" aria-hidden="true"></i> {ts}Map{/ts}</a>
+ <a href="{$values.isMap}" title="{ts}Map event location{/ts}"><i class="crm-i fa-map-marker" aria-hidden="true"></i> {ts}Map{/ts}</a>
|
{/if}
{if $values.configure}
<br />
<div class="messages status no-popup">
<table>
- <tr><div class="icon inform-icon"></div></tr>
+ <tr>{icon icon="fa-info-circle"}{/icon}</tr>
<tr>
{ts}There are no active Events to display.{/ts}
{ts 1=$newEventURL}You can <a href="%1">Create a New Event</a> now.{/ts}
{else}
{if $isSearch eq 1}
<div class="status messages">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{capture assign=browseURL}{crmURL p='civicrm/event/manage' q="reset=1"}{/capture}
{ts}No available Events match your search criteria. Suggestions:{/ts}
<div class="spacer"></div>
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$newEventURL}There are no events scheduled for the date range. You can <a href='%1'>add one</a>.{/ts}
</div>
{/if}
{else}
<div class='spacer'></div>
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are currently no participants registered for this event.{/ts}
</div>
{/if}
{else}
<div class='spacer'></div>
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are currently no participants registered for this event.{/ts}
</div>
{/if}
{else}
<div class='spacer'></div>
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are currently no participants registered for this event.{/ts}
</div>
{/if}
{else}
<div class="messages status no-popup">
<table class="form-layout">
- <tr><div class="icon inform-icon"></div>
+ <tr>{icon icon="fa-info-circle"}{/icon}
{ts}No event registrations have been recorded for this contact.{/ts}
</tr>
</table>
{/strip}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}You are not registered for any current or upcoming Events.{/ts}
</div>
{/if}
{* Confirmation of Export Batch(s) *}
<h3>{ts}Export Batch{/ts}</h3>
<div class="messages status">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}Warning: You will not be able to reopen or change the batch after it is exported. Are you sure you want to export?{/ts}
</div>
<div class="crm-block crm-form-block crm-export_batch-form-block">
<div class="crm-block crm-form-block crm-contribution_type-form-block crm-financial_type-form-block">
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: You cannot delete a {$delName} Financial Account if it is currently used by any Financial Types. Consider disabling this option instead.{/ts} {ts}Deleting a financial type cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
<div class="crm-block crm-form-block crm-financial_type-form-block">
{if $action eq 8}
<div class="messages status">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: You cannot delete a financial type if it is currently used by any Contributions, Contribution Pages or Membership Types. Consider disabling this option instead.{/ts} {ts}Deleting a financial type cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
<div class="crm-block crm-form-block crm-financial_type-form-block">
{if $action eq 8}
<div class="messages status">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: You cannot delete a financial type if it is currently used by any Contributions, Contribution Pages or Membership Types. Consider disabling this option instead.{/ts} {ts}Deleting a financial type cannot be undone. Unbalanced transactions may be created if you delete this account.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
</div>
{else}
<div class="messages status">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{capture assign=crmURL}{crmURL q="action=add&reset=1"}{/capture}
{ts 1=$crmURL}There are no Financial Account entered. You can <a href='%1'>add one</a>.{/ts}
</div>
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}None found.{/ts}
</div>
{/if}
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{capture assign=crmURL}{crmURL q="action=add&reset=1&aid=$aid"}{/capture}
{ts 1=$crmURL}There are no financial accounts assigned to this financial type. You can <a href='%1'>assign one</a>.{/ts}
</div>
<div class="crm-block crm-form-block crm-grant-form-block">
{if $action eq 8}
<div class="messages status">
- <p><div class="icon inform-icon"></div>
+ <p>{icon icon="fa-info-circle"}{/icon}
{ts}Are you sure you want to delete this Grant?{/ts} {ts}This action cannot be undone.{/ts}</p>
<p>{include file="CRM/Grant/Form/Task.tpl"}</p>
</div>
*}
{* No matches for submitted search request. *}
<div class="messages status">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $qill}{ts}No matches found for:{/ts}
{include file="CRM/common/displaySearchCriteria.tpl"}
{else}
{* Confirmation of Grant delete *}
<div class="crm-block crm-form-block crm-grant-task-delete-form-block">
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}Are you sure you want to delete the selected Grants? This delete operation cannot be undone and will delete all transactions associated with these grants.{/ts}
<p>{include file="CRM/Grant/Form/Task.tpl"}</p>
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no records selected for Print.{/ts}
</div>
{/if}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no records selected.{/ts}
</div>
{/if}
{include file="CRM/Grant/Form/Selector.tpl"}
{else}
<div class="messages status">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}No grants have been recorded for this contact.{/ts}
</div>
{/if}
{if $raw}
<div class="status">
<dl>
- <dt><div class="icon inform-icon"></div></dt>
+ <dt>{icon icon="fa-info-circle"}{/icon}</dt>
<dd>
{ts}WARNING: Are you sure you want to revert the below changes?{/ts}
</dd>
{/if}
{else}
<div class='messages status'>
- <div class='icon inform-icon'></div> {ts}This report can not be displayed because there are no relevant entries in the logging tables.{/ts}
+ {icon icon="fa-info-circle"}{/icon}{ts}This report can not be displayed because there are no relevant entries in the logging tables.{/ts}
</div>
{/if}
{if $layout neq 'overlay'}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"/>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no records selected for Print.{/ts}
</div>
{/if}
{/if}
<div class="status messages">
<table class="form-layout">
- <tr><div class="icon inform-icon"></div>
+ <tr>{icon icon="fa-info-circle"}{/icon}
{ts 1=$componentName}No %1 match your search criteria. Suggestions:{/ts}
</tr>
<div class="spacer"></div>
{elseif $unscheduled}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{capture assign=crmURL}{crmURL p=$newMassUrl q='reset=1'}{/capture}
{ts 1=$componentName}There are no Unscheduled %1.{/ts}
{if $showLinks}{ts 1=$crmURL}You can <a href='%1'>create and send one</a>.{/ts}{/if}
{elseif $archived}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div> 
+ {icon icon="fa-info-circle"}{/icon} 
{capture assign=crmURL}{crmURL p='civicrm/mailing/browse/scheduled' q='scheduled=true&reset=1'}{$qVal}{/capture}
{ts 1=$crmURL 2=$componentName}There are no Archived %2. You can archive %2 from <a href='%1'>Scheduled or Sent %2</a>.{/ts}
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{capture assign=crmURL}{crmURL p=$newMassUrl q='reset=1'}{/capture}
{capture assign=archiveURL}{crmURL p='civicrm/mailing/browse/archived' q='reset=1'}{$qVal}{/capture}
{ts 1=$componentName}There are no Scheduled or Sent %1.{/ts}
+--------------------------------------------------------------------+
*}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $success}
{ts 1=$display_name 2=$email 3=$group}<strong>%1 (%2)</strong> has been successfully subscribed to the <strong>%3</strong> mailing list.{/ts}
{else}
{/strip}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$title}There are currently no %1.{/ts}
</div>
*}
{if $confirm}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<label>{$display_name} ({$email})</label> {ts}has been successfully resubscribed.{/ts}
</div>
{else}
{* this template is used for adding/editing/deleting memberships for a contact *}
{if $isRecur}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<p>{ts}This membership is set to renew automatically {if $endDate}on {$endDate|crmDate}{/if}. Please be aware that any changes that you make here may not be reflected in the payment processor. Please ensure that you alter the related subscription at the payment processor.{/ts}</p>
{if $cancelAutoRenew}<p>{ts 1=$cancelAutoRenew}To stop the automatic renewal:
<a href="%1">Cancel auto-renew</a>
{/if}
{if !$emailExists and $action neq 8 and $context neq 'standalone'}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<p>{ts}You will not be able to send an automatic email receipt for this Membership because there is no email address recorded for this contact. If you want a receipt to be sent when this Membership is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the Membership.{/ts}</p>
</div>
{/if}
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{$deleteMessage}
</div>
{else}
{/if}
{if !$email}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<p>{ts}You will not be able to send an automatic email receipt for this Renew Membership because there is no email address recorded for this contact. If you want a receipt to be sent when this Membership is recorded, click Cancel and then click Edit from the Summary tab to add an email address before Renewal the Membership.{/ts}</p>
</div>
{/if}
{if $action eq 32768}
{if $cancelAutoRenew}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<p>{ts 1=$cancelAutoRenew}This membership is set to renew automatically {if $renewalDate}on {$renewalDate|crmDate}{/if}. You will need to cancel the auto-renew option if you want to modify the Membership Type, End Date or Membership Status.
<a href="%1">Click here</a>
if you want to cancel the automatic renewal option.{/ts}</p>
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{$deleteMessage|escape}
</div>
{else}
<fieldset><legend>{ts}Renewal Reminders{/ts}</legend>
<div class="help">
{capture assign=reminderLink}{crmURL p='civicrm/admin/scheduleReminders' q='reset=1'}{/capture}
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$reminderLink}Configure membership renewal reminders using <a href="%1">Schedule Reminders</a>. If you have previously configured renewal reminder templates, you can re-use them with your new scheduled reminders.{/ts} {docURL page="user/email/scheduled-reminders"}
</div>
</fieldset>
*}
{* No matches for submitted search request. *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $qill}{ts}No matches found for:{/ts}
{include file="CRM/common/displaySearchCriteria.tpl"}
{else}
{* Confirmation of membership deletes *}
<div class="crm-block crm-form-block crm-member-task-delete-form-block">
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<span>{ts}Are you sure you want to delete the selected memberships? This delete operation cannot be undone and will delete all transactions and activity associated with these memberships.{/ts}</span>
<p>{include file="CRM/Member/Form/Task.tpl"}</p>
</div>
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no records selected.{/ts}
</div>
{/if}
{capture assign=reminderLink}{crmURL p='civicrm/admin/scheduleReminders' q='reset=1'}{/capture}
<div class="help">
- <p><div class="icon inform-icon"></div> {ts}Membership types are used to categorize memberships. You can define an unlimited number of types. Each type incorporates a 'name' (Gold Member, Honor Society Member...), a description, a minimum fee (can be $0), and a duration (can be 'lifetime'). Each member type is specifically linked to the membership entity (organization) - e.g. Bay Area Chapter.{/ts} {docURL page="user/membership/defining-memberships/"}</p>
+ <p>{icon icon="fa-info-circle"}{/icon}{ts}Membership types are used to categorize memberships. You can define an unlimited number of types. Each type incorporates a 'name' (Gold Member, Honor Society Member...), a description, a minimum fee (can be $0), and a duration (can be 'lifetime'). Each member type is specifically linked to the membership entity (organization) - e.g. Bay Area Chapter.{/ts} {docURL page="user/membership/defining-memberships/"}</p>
<p>{ts 1=$reminderLink}Configure membership renewal reminders using <a href="%1">Schedule Reminders</a>.{/ts} {docURL page="user/email/scheduled-reminders"}</p>
</div>
{/if}
{if NOT ($activeMembers or $inActiveMembers) and $action ne 2 and $action ne 1 and $action ne 8 and $action ne 4 and $action ne 32768}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}No memberships have been recorded for this contact.{/ts}
</div>
{/if}
{if NOT ($activeMembers or $inActiveMembers)}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div></dt>
+ {icon icon="fa-info-circle"}{/icon}</dt>
{ts}There are no memberships on record for you.{/ts}
</div>
{/if}
{* this template is used for confirmation of delete for a group *}
<fieldset><legend>{ts}Delete Campaign Page {/ts}</legend>
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$title}Are you sure you want to delete Campaign Page '%1'?{/ts}<br />
{ts}This action cannot be undone.{/ts}
</div>
</div>
{else}
<div class="messages status no-popup">
-<div class="icon inform-icon"></div>
+{icon icon="fa-info-circle"}{/icon}
{if $isSearch}
{ts}There are no Personal Campaign Pages which match your search criteria.{/ts}
{else}
{* this template is used for displaying PCP information *}
{if $owner}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<p><strong>{ts}Personal Campaign Preview{/ts}</strong> - {ts}This is a preview of your Personal Campaign Page in support of{/ts} <a href="{$parentURL}"><strong>{$pageName}</strong></a>.</p>
{ts}The current status of your page is{/ts}: <strong {if $pcp.status_id NEQ 2}class=disabled {/if}>{$owner.status}</strong>.
{if $pcp.status_id NEQ 2}<br /><span class="description">{ts}You will receive an email notification when your page is Approved and you can begin promoting your campaign.{/ts}</span>{/if}
{else}
{if !$email and $action neq 8 and $context neq 'standalone'}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<p>{ts}You will not be able to send an acknowledgment for this pledge because there is no email address recorded for this contact. If you want a acknowledgment to be sent when this pledge is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the pledge.{/ts}</p>
</div>
{/if}
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<span class="font-red bold">{ts}WARNING: Deleting this pledge will also delete any related pledge payments.{/ts} {ts}This action cannot be undone.{/ts}</span>
<p>{ts}Consider cancelling the pledge instead if you want to maintain an audit trail and avoid losing payment data. To set the pledge status to Cancelled and cancel any not-yet-paid pledge payments, first click Cancel on this form. Then click the more > link from the pledge listing, and select the Cancel action.{/ts}</p>
</div>
<td class="label">{$form.amount.label}</td>
<td>
<span>{$form.currency.html|crmAddClass:eight} {$form.amount.html|crmAddClass:eight}</span>
- {if $originalPledgeAmount}<div class="messages status no-popup"><div class="icon inform-icon"></div> {ts 1=$originalPledgeAmount|crmMoney:$currency} Pledge total has changed due to payment adjustments. Original pledge amount was %1.{/ts}</div>{/if}
+ {if $originalPledgeAmount}<div class="messages status no-popup">{icon icon="fa-info-circle"}{/icon}{ts 1=$originalPledgeAmount|crmMoney:$currency} Pledge total has changed due to payment adjustments. Original pledge amount was %1.{/ts}</div>{/if}
</td>
</tr>
<tr class="crm-pledge-form-block-installments">
<tr class="crm-pledge-form-block-amount">
<td class="label">{ts}Total Pledge Amount{/ts}</td>
<td><span class="bold">{$amount|crmMoney:$currency}</span>
- {if $originalPledgeAmount}<div class="messages status no-popup"><div class="icon inform-icon"></div>{ts 1=$originalPledgeAmount|crmMoney:$currency} Pledge total has changed due to payment adjustments. Original pledge amount was %1.{/ts}</div>{/if}
+ {if $originalPledgeAmount}<div class="messages status no-popup">{icon icon="fa-info-circle"}{/icon}{ts 1=$originalPledgeAmount|crmMoney:$currency} Pledge total has changed due to payment adjustments. Original pledge amount was %1.{/ts}</div>{/if}
</td>
</tr>
<tr class="crm-pledge-form-block-installments"><td class="label">{ts}To be paid in{/ts}</td><td>{$installments} {ts}installments of{/ts} {$original_installment_amount|crmMoney:$currency} {ts}every{/ts} {$frequency_interval} {$frequencyUnit}</td></tr>
*}
{* No matches for submitted search request. *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $qill}{ts}No matches found for:{/ts}
{include file="CRM/common/displaySearchCriteria.tpl"}
{else}
*}
{* Confirmation of participation deletes *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<p>{ts}Are you sure you want to delete the selected pledges? This delete operation cannot be undone and will delete all transactions associated with these pledges.{/ts}</p>
<p>{include file="CRM/Pledge/Form/Task.tpl"}</p>
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no records selected for Print.{/ts}
</div>
{/if}
{else}
<div class="messages status no-popup">
- <dt><div class="icon inform-icon"></div>
+ <dt>{icon icon="fa-info-circle"}{/icon}
{ts}There are no records selected.{/ts}
</dl>
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}No pledges have been recorded from this contact.{/ts}
</div>
{/if}
{crmScript file='js/crm.expandRow.js'}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}There are no Pledges for your record.{/ts}
</div>
{/if}
{* this template is used for confirmation of delete for a Fields *}
<div class="crm-block crm-form-block crm-price_field_delete-form-block">
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$title}WARNING: Deleting this price field will result in the loss of all '%1' data.{/ts} {ts}This action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
</div>
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
<div class="crm-form-block">
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Deleting this option will result in the loss of all data.{/ts} {ts}This action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
{assign var='adminFld' value=false}
{if call_user_func(array('CRM_Core_Permission','check'), 'administer CiviCRM') }
{assign var='adminFld' value=true}
+ {if $priceSet.id && !$priceSet.is_quick_config}
+ <div class='float-right'>
+ <a class="crm-hover-button" target="_blank" href="{crmURL p="civicrm/admin/price/field" q="reset=1&action=browse&sid=`$priceSet.id`"}">
+ {icon icon="fa-wrench"}{ts}Edit Price Set{/ts}{/icon}
+ </a>
+ </div>
+ {/if}
{/if}
{foreach from=$priceSet.fields item=element key=field_id}
{include file="CRM/Price/Form/Preview.tpl"}
{elseif ($usedBy and $action eq 8) or $usedBy.civicrm_event or $usedBy.civicrm_contribution_page}
<div id="price_set_used_by" class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $action eq 8}
{ts 1=$usedPriceSetTitle}Unable to delete the '%1' Price Field - it is currently in use by one or more active events or contribution pages or contributions or event templates.{/ts}
{/if}
{else}
{if $action eq 16}
<div class="messages status no-popup crm-empty-table">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}None found.{/ts}
</div>
<div class="action-link">
{elseif $usedBy}
<div class='spacer'></div>
<div id="price_set_used_by" class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $action eq 8}
{ts 1=$usedPriceSetTitle}Unable to delete the '%1' Price Field Option - it is currently in use by one or more active events or contribution pages or contributions.{/ts}
{/if}
{if $usedBy}
<div class='spacer'></div>
<div id="price_set_used_by" class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $action eq 8}
{ts 1=$usedPriceSetTitle}Unable to delete the '%1' price set - it is currently in use by one or more active events or contribution pages or contributions or event templates.{/ts}
{/if}
cms account edit (mode=8) or civicrm/profile (mode=4) pages *}
{if $deleteRecord}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}Are you sure you want to delete this record?{/ts}
</div>
{if ($action eq 1 and $mode eq 4 ) or ($action eq 2) or ($action eq 8192)}
{if $action eq 2 and $multiRecordFieldListing}
- {include file="CRM/Profile/Page/MultipleRecordFieldsListing.tpl" showListing=true}
- {assign var=floatStyle value='float:right'}
+ <div class="crm-multi-record-custom-field-listing">
+ {include file="CRM/Profile/Page/MultipleRecordFieldsListing.tpl" showListing=true}
+ {assign var=floatStyle value='float:right'}
+ </div>
{/if}
<div class="crm-submit-buttons" style='{$floatStyle}'>
{include file="CRM/common/formButtons.tpl"}{if $isDuplicate}<span class="crm-button">{$form._qf_Edit_upload_duplicate.html}</span>{/if}
}
{elseif $statusMessage}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{$statusMessage}
</div>
{/if}
{elseif $statusMessage}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{$statusMessage}
</div>
{else} {* empty fields *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}No fields in this Profile have been configured as searchable. Ask the site administrator to check the Profile setup.{/ts}
</div>
{/if}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}No fields in this Profile have been configured to display as a result column in the search results table. Ask the site administrator to check the Profile setup.{/ts}
</div>
{/if}
<div id='{$dialogId}' class="hiddenElement"></div>
{elseif !$records}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts 1=$customGroupTitle}No records of type '%1' found.{/ts}
</div>
<tr>
{include file="CRM/common/tasks.tpl" location="botton"}
{if $instanceUrl}
- <td> <i class="crm-i fa-chevron-right" aria-hidden="true"></i> <a href="{$instanceUrl}">{ts}Existing report(s) from this template{/ts}</a></td>
+ <td> <i class="crm-i fa-chevron-right" aria-hidden="true"></i> <a href="{$instanceUrl}">{ts}Existing report(s) from this template{/ts}</a></td>
{/if}
</tr>
</table>
*}
{if $outputMode eq 'html' && !$rows}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div> {ts}None found.{/ts}
+ {icon icon="fa-info-circle"}{/icon} {ts}None found.{/ts}
</div>
{/if}
<tr>
<td colspan=2>
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Deleting this option will result in the loss of all Report related records which use the option. This may mean the loss of a substantial amount of data, and the action cannot be undone. Do you want to continue?{/ts}
</div>
</td>
{else}
<div class="crm-content-block">
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{if $myReports}
{ts}You do not have any private reports. To add a report to this section, edit the Report Settings for a report and set 'Add to My Reports' to Yes.{/ts}
{else}
{/foreach}
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div> {ts}There are currently no Report Templates.{/ts}
+ {icon icon="fa-info-circle"}{/icon} {ts}There are currently no Report Templates.{/ts}
</div>
{/if}
{/strip}
*}
{if $groupCount == 0 and $mailingCount == 0}
<div class="status">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}To send a Mass SMS, you must have a valid group of recipients - either at least one group that's a Mailing List{/ts}
</div>
{else}
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}Do you want to continue?{/ts}
</div>
{elseif $action eq 128}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}Are you sure you would like to execute this job?{/ts}
</div>
{else}
</div>
{else}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}None found.{/ts}
</div>
<% {rdelim} %>
<div class="crm-submit-buttons">
<a href="{crmURL p="civicrm/tag/edit" q="action=add&parent_id="}<%= tagset || '' %>" class="button crm-popup">
- <span><i class="crm-i fa-plus" aria-hidden="true"></i> {ts}Add Tag{/ts}</span>
+ <span><i class="crm-i fa-plus" aria-hidden="true"></i> {ts}Add Tag{/ts}</span>
</a>
<% if(tagset && adminTagsets) {ldelim} %>
<a href="{crmURL p="civicrm/tag/edit" q="action=update&id="}<%= tagset %>" class="button crm-popup tagset-action-update">
- <span><i class="crm-i fa-pencil" aria-hidden="true"></i> {ts}Edit Set{/ts}</span>
+ <span><i class="crm-i fa-pencil" aria-hidden="true"></i> {ts}Edit Set{/ts}</span>
</a>
<% {rdelim} %>
<% if(tagset && !length && adminTagsets && (!is_reserved || adminReserved)) {ldelim} %>
<a href="{crmURL p="civicrm/tag/edit" q="action=delete&id="}<%= tagset %>" class="button crm-popup small-popup tagset-action-delete">
- <span><i class="crm-i fa-trash" aria-hidden="true"></i> {ts}Delete Set{/ts}</span>
+ <span><i class="crm-i fa-trash" aria-hidden="true"></i> {ts}Delete Set{/ts}</span>
</a>
<% {rdelim} %>
</div>
<div class="crm-submit-buttons">
<% if(!tagset) {ldelim} %>
<a href="{crmURL p="civicrm/tag/edit" q="action=add&parent_id="}<%= id %>" class="button crm-popup" title="{ts}Create new tag under this one{/ts}">
- <span><i class="crm-i fa-plus" aria-hidden="true"></i> {ts}Add Child{/ts}</span>
+ <span><i class="crm-i fa-plus" aria-hidden="true"></i> {ts}Add Child{/ts}</span>
</a>
<% {rdelim} %>
<a href="{crmURL p="civicrm/tag/edit" q="action=add&clone_from="}<%= id %>" class="button crm-popup" title="{ts}Duplicate this tag{/ts}">
- <span><i class="crm-i fa-copy" aria-hidden="true"></i> {ts}Clone Tag{/ts}</span>
+ <span><i class="crm-i fa-copy" aria-hidden="true"></i> {ts}Clone Tag{/ts}</span>
</a>
<% if(!data.is_reserved || adminReserved) {ldelim} %>
<% if(tagsetCount) {ldelim} %>
<a href="#move" class="button move-tag-button" title="{ts}Move to a different tagset{/ts}">
- <span><i class="crm-i fa-share-square-o" aria-hidden="true"></i> {ts}Move Tag{/ts}</span>
+ <span><i class="crm-i fa-share-square-o" aria-hidden="true"></i> {ts}Move Tag{/ts}</span>
</a>
<% {rdelim} %>
<% if(!hasChildren) {ldelim} %>
<a href="{crmURL p="civicrm/tag/edit" q="action=delete&id="}<%= id %>" class="button crm-popup small-popup">
- <span><i class="crm-i fa-trash" aria-hidden="true"></i> {ts}Delete{/ts}</span>
+ <span><i class="crm-i fa-trash" aria-hidden="true"></i> {ts}Delete{/ts}</span>
</a>
<% {rdelim} %>
<% {rdelim} %>
<div class="crm-submit-buttons">
<% if(!reserved || adminReserved) {ldelim} %>
<a href="{crmURL p="civicrm/tag/merge" q="id="}<%= items.join() %>" class="button crm-popup small-popup" title="{ts}Combine tags into one{/ts}">
- <span><i class="crm-i fa-compress" aria-hidden="true"></i> {ts}Merge Tags{/ts}</span>
+ <span><i class="crm-i fa-compress" aria-hidden="true"></i> {ts}Merge Tags{/ts}</span>
</a>
<% if(tagsetCount) {ldelim} %>
<a href="#move" class="button move-tag-button" title="{ts}Move to a different tagset{/ts}">
- <span><i class="crm-i fa-share-square-o" aria-hidden="true"></i> {ts}Move Tags{/ts}</span>
+ <span><i class="crm-i fa-share-square-o" aria-hidden="true"></i> {ts}Move Tags{/ts}</span>
</a>
<% {rdelim} %>
<% if(!hasChildren) {ldelim} %>
<a href="{crmURL p="civicrm/tag/edit" q="action=delete&id="}<%= items.join() %>" class="button crm-popup small-popup">
- <span><i class="crm-i fa-trash" aria-hidden="true"></i> {ts}Delete All{/ts}</span>
+ <span><i class="crm-i fa-trash" aria-hidden="true"></i> {ts}Delete All{/ts}</span>
</a>
<% {rdelim} %>
<% {rdelim} %>
<div class="crm-block crm-form-block crm-uf-field-form-block">
{if $action eq 8}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Deleting this profile field will remove it from Profile forms and listings. If this field is used in any 'stand-alone' Profile forms, you will need to update those forms to remove this field.{/ts} {ts}Do you want to continue?{/ts}
</div>
{else}
{if $action eq 8 or $action eq 64}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{$message}
</div>
{else}
{if $action eq 16}
{capture assign=crmURL}{crmURL p="civicrm/admin/uf/group/field/add" q="reset=1&action=add&gid=$gid"}{/capture}
<div class="messages status no-popup crm-empty-table">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{ts}None found.{/ts}
</div>
<div class="action-link">
{else}
{if $action ne 1} {* When we are adding an item, we should not display this message *}
<div class="messages status no-popup">
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
{capture assign=crmURL}{crmURL p='civicrm/admin/uf/group/add' q='action=add&reset=1'}{/capture}{ts 1=$crmURL}No CiviCRM Profiles have been created yet. You can <a href='%1'>add one now</a>.{/ts}
</div>
{/if}
// define('CIVICRM_MYSQL_STRICT', TRUE );
// }
-/**
- * Specify whether the CRM_Core_BAO_Cache should use the legacy
- * direct-to-SQL-mode or the interim PSR-16 adapter.
- */
-// define('CIVICRM_BAO_CACHE_ADAPTER', 'CRM_Core_BAO_Cache_Psr16');
-
if (CIVICRM_UF === 'UnitTests') {
if (!defined('CIVICRM_CONTAINER_CACHE')) define('CIVICRM_CONTAINER_CACHE', 'auto');
if (!defined('CIVICRM_MYSQL_STRICT')) define('CIVICRM_MYSQL_STRICT', true);
{crmGetAttribute html=$html attr='crm-icon' assign='icon'}
{capture assign=iconPrefix}{$icon|truncate:3:"":true}{/capture}
{if $icon && $iconPrefix eq 'fa-'}
- {assign var='buttonClass' value=' crm-i-button'}
{capture assign=iconDisp}<i class="crm-i {$icon}" aria-hidden="true"></i>{/capture}
- {elseif $icon}
- {assign var='buttonClass' value=' crm-icon-button'}
- {capture assign=iconDisp}<span class="crm-button-icon ui-icon-{$icon}"> </span>{/capture}
{/if}
{crmGetAttribute html=$html attr='disabled' assign='disabled'}
- <span class="crm-button crm-button-type-{$key|crmBtnType} crm-button{$key}{$buttonClass}{if $disabled} crm-button-disabled{/if}"{if $buttonStyle} style="{$buttonStyle}"{/if}>
+ <span class="crm-button crm-button-type-{$key|crmBtnType} crm-button{$key}{if $disabled} crm-button-disabled{/if}"{if $buttonStyle} style="{$buttonStyle}"{/if}>
{$iconDisp}
{$html}
</span>
{* Handles display of passed $infoMessage. *}
{if $infoMessage or $infoTitle}
<div class="messages status {$infoType}"{if $infoOptions} data-options='{$infoOptions}'{/if}>
- <div class="icon inform-icon"></div>
+ {icon icon="fa-info-circle"}{/icon}
<span class="msg-title">{$infoTitle}</span>
<span class="msg-text">{$infoMessage}</span>
</div>
errorClass: 'crm-inline-error alert-danger',
messages: {},
ignore: '.select2-offscreen, [readonly], :hidden:not(.crm-select2), .crm-no-validate',
- ignoreTitle: true
+ ignoreTitle: true,
+ errorPlacement: function(error, element) {
+ if (element.prop('type') === 'radio') {
+ error.appendTo(element.parent('div.content'));
+ }
+ else {
+ error.insertAfter(element);
+ }
+ }
};
// use civicrm notifications when there are errors
* Include dataProvider for tests
* @group headless
*/
-class CRM_Case_BAO_QueryTest extends CiviUnitTestCase {
-
- /**
- * Set up function.
- *
- * Ensure CiviCase is enabled.
- */
- public function setUp() {
- parent::setUp();
- CRM_Core_BAO_ConfigSetting::enableComponent('CiviCase');
- }
+class CRM_Case_BAO_QueryTest extends CiviCaseTestCase {
/**
* Check that Qill is calculated correctly.
* CRM-17120 check the qill is still calculated after changing function used
* to retrieve function.
*
- * Note that the Qill doesn't actually appear to have the correct labels to
- * start with. I didn't attempt to fix that. I just prevented regression.
- *
* I could not find anyway to actually do this search with the relevant fields
* as parameters & don't know if they exist as legitimate code or code cruft so
* this test was the only way I could verify the change.
- * - case_recent_activity_type
+ * - case_activity_type
* - case_activity_status_id
* - case_activity_medium_id
*/
public function testWhereClauseSingle() {
$params = [
0 => [
- 0 => 'case_recent_activity_type',
+ 0 => 'case_activity_type',
1 => '=',
2 => 6,
3 => 1,
$this->assertEquals(
[
0 => 'Activity Type = Contribution',
- 1 => 'Activity Type = Scheduled',
+ 1 => 'Activity Status = Scheduled',
2 => 'Activity Medium = In Person',
],
$queryObj->_qill[1]
);
}
+ /**
+ * Test the qill for a find cases search.
+ */
+ public function testFindCasesQuery() {
+ $params = [
+ [
+ 0 => 'case_type_id',
+ 1 => 'IN',
+ 2 => [1],
+ 3 => 0,
+ 4 => 0,
+ ],
+ [
+ 0 => 'case_status_id',
+ 1 => 'IN',
+ 2 => [1],
+ 3 => 0,
+ 4 => 0,
+ ],
+ [
+ 0 => 'case_deleted',
+ 1 => '=',
+ 2 => 0,
+ 3 => 0,
+ 4 => 0,
+ ],
+ [
+ 0 => 'case_owner',
+ 1 => '=',
+ 2 => 1,
+ 3 => 0,
+ 4 => 0,
+ ],
+ ];
+
+ $query = new CRM_Contact_BAO_Query($params, NULL, NULL, FALSE, FALSE, CRM_Contact_BAO_Query::MODE_CASE);
+
+ $this->assertEquals(
+ [
+ 0 => [
+ 0 => 'Case Type(s) In Housing Support',
+ 1 => 'Case Status(s) In Ongoing',
+ 2 => 'Case = All Cases',
+ ],
+ ],
+ $query->_qill
+ );
+
+ $this->assertEquals(
+ [
+ 0 => [
+ 0 => 'civicrm_case.case_type_id IN ("1")',
+ 1 => 'civicrm_case.status_id IN ("1")',
+ 2 => 'civicrm_case.is_deleted = 0',
+ 3 => 'civicrm_case_contact.contact_id = contact_a.id',
+ ],
+ ],
+ $query->_where
+ );
+ }
+
}
--- /dev/null
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved. |
+ | |
+ | This work is published under the GNU AGPLv3 license with some |
+ | permitted exceptions and without any warranty. For full license |
+ | and copyright information, see https://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+ */
+
+ /**
+ * @group headless
+ */
+class CRM_Contact_Form_Task_UseraddTest extends CiviUnitTestCase {
+
+ /**
+ * Test postProcess failure.
+ *
+ * In unit tests, the CMS user creation will always fail, but that's
+ * ok because that's what we're testing here.
+ */
+ public function testUserCreateFail() {
+ $form = new CRM_Contact_Form_Task_Useradd();
+ // We don't need to set params or anything because we're testing fail,
+ // which the user creation will do in unit tests no matter what we set.
+ // But before the patch, the status messages were always success no
+ // matter what.
+ try {
+ $form->postProcess();
+ }
+ catch (CRM_Core_Exception_PrematureExitException $e) {
+ }
+ $statuses = CRM_Core_Session::singleton()->getStatus(TRUE);
+ $this->assertEquals('alert', $statuses[0]['type']);
+ }
+
+}
* @throws \Exception
*/
public function testSelectorQuery($dataSet) {
+ if (!empty($dataSet['limitedPermissions'])) {
+ CRM_Core_Config::singleton()->userPermissionClass->permissions = [
+ 'access CiviCRM',
+ 'access deleted contacts',
+ ];
+ }
$params = CRM_Contact_BAO_Query::convertFormValues($dataSet['form_values'], 0, FALSE, NULL, []);
$isDeleted = in_array(['deleted_contacts', '=', 1, 0, 0], $params);
foreach ($dataSet['settings'] as $setting) {
$selector->getQueryObject()->getCachedContacts([$contactID], FALSE);
}
}
+ if (!empty($dataSet['limitedPermissions'])) {
+ $this->cleanUpAfterACLs();
+ }
}
/**
2 => "WHERE ( civicrm_email.email LIKE 'mickey@mouseville.com%' AND ( ( ( contact_a.sort_name LIKE 'Mouse%' ) OR ( civicrm_email.email LIKE 'Mouse%' ) ) ) ) AND (contact_a.is_deleted)",
],
],
+ ],
+ [
+ [
+ 'description' => 'Ensure that the Join to the acl contact cache is correct and that if we are searching in deleted contacts appropriate where clause is added',
+ 'class' => 'CRM_Contact_Selector',
+ 'settings' => [['name' => 'includeWildCardInName', 'value' => FALSE]],
+ 'form_values' => ['email' => 'mickey@mouseville.com', 'sort_name' => 'Mouse', 'deleted_contacts' => 1],
+ 'params' => [],
+ 'return_properties' => NULL,
+ 'context' => 'advanced',
+ 'action' => CRM_Core_Action::ADVANCED,
+ 'includeContactIds' => NULL,
+ 'searchDescendentGroups' => FALSE,
+ 'limitedPermissions' => TRUE,
+ 'expected_query' => [
+ 0 => 'default',
+ 1 => 'FROM civicrm_contact contact_a LEFT JOIN civicrm_address ON ( contact_a.id = civicrm_address.contact_id AND civicrm_address.is_primary = 1 ) LEFT JOIN civicrm_country ON ( civicrm_address.country_id = civicrm_country.id ) LEFT JOIN civicrm_email ON (contact_a.id = civicrm_email.contact_id AND civicrm_email.is_primary = 1) LEFT JOIN civicrm_phone ON (contact_a.id = civicrm_phone.contact_id AND civicrm_phone.is_primary = 1) LEFT JOIN civicrm_im ON (contact_a.id = civicrm_im.contact_id AND civicrm_im.is_primary = 1) LEFT JOIN civicrm_worldregion ON civicrm_country.region_id = civicrm_worldregion.id INNER JOIN civicrm_acl_contact_cache aclContactCache ON contact_a.id = aclContactCache.contact_id',
+ 2 => "WHERE ( civicrm_email.email LIKE 'mickey@mouseville.com%' AND ( ( ( contact_a.sort_name LIKE 'Mouse%' ) OR ( civicrm_email.email LIKE 'Mouse%' ) ) ) ) AND aclContactCache.user_id = 0 AND (contact_a.is_deleted)",
+ ],
+ ],
+ ],
+ [
[
'description' => 'Use of quotes for exact string',
'use_case_comments' => 'This is something that was in the code but seemingly not working. No UI info on it though!',
'contribution_recur_id' => $contributionRecur['id'],
'total_amount' => '3.00',
'financial_type_id' => 1,
+ 'source' => 'Template Contribution',
'payment_instrument_id' => 1,
- 'currency' => 'USD',
+ 'currency' => 'AUD',
'contact_id' => $this->individualCreate(),
'contribution_status_id' => 1,
'receive_date' => 'yesterday',
'contribution_recur_id' => $contributionRecur['id'],
'total_amount' => '3.00',
'financial_type_id' => 1,
+ 'source' => 'Non-template Contribution',
'payment_instrument_id' => 1,
'currency' => 'USD',
'contact_id' => $this->individualCreate(),
$fetchedTemplate = CRM_Contribute_BAO_ContributionRecur::getTemplateContribution($contributionRecur['id']);
// Fetched template should be the is_template, not the latest contrib
$this->assertEquals($fetchedTemplate['id'], $templateContrib['id']);
+
+ $repeatContribution = $this->callAPISuccess('Contribution', 'repeattransaction', [
+ 'contribution_status_id' => 'Completed',
+ 'contribution_recur_id' => $contributionRecur['id'],
+ ]);
+ $this->assertEquals('Template Contribution', $repeatContribution['values'][$repeatContribution['id']]['source']);
+ $this->assertEquals('AUD', $repeatContribution['values'][$repeatContribution['id']]['currency']);
}
/**
'contact_id' => $contactId1,
'receive_date' => '2010-01-20',
'financial_type_id' => 'Member Dues',
- 'contribution_status_id' => 'Pending',
'contribution_recur_id' => $contributionRecurId,
'total_amount' => 150,
'api.Payment.create' => ['total_amount' => 150],
'contact_id' => $contactId,
'membership_type_id' => $priceField['membership_type_id'],
'source' => 'Payment',
- 'join_date' => '2020-04-28',
- 'start_date' => '2020-04-28',
+ 'join_date' => date('Y-m', strtotime('1 month ago')) . '-28',
+ 'start_date' => date('Y-m') . '-28',
'contribution_recur_id' => $contributionRecurId,
'status_id' => 'Pending',
'is_override' => 1,
$this->validateAllCounts($membershipId1, 4);
$this->validateAllCounts($membershipId2, 4);
+ $expectedDate = $this->getYearAndMonthFromOffset(4);
// check membership end date.
foreach ([$membershipId1, $membershipId2] as $mId) {
$endDate = $this->callAPISuccessGetValue('Membership', [
'id' => $mId,
'return' => 'end_date',
]);
- $this->assertEquals($endDate, '2020-08-27', ts('End date incorrect.'));
+ $this->assertEquals("{$expectedDate['year']}-{$expectedDate['month']}-27", $endDate, ts('End date incorrect.'));
}
// At this moment Contact 2 is deceased, but we wait until payment is recorded in civi before marking the contact deceased.
'id' => $membershipId1,
'return' => 'end_date',
]);
- $this->assertEquals($endDate, '2020-10-27', ts('End date incorrect.'));
+ $expectedDate = $this->getYearAndMonthFromOffset(6);
+ $this->assertEquals("{$expectedDate['year']}-{$expectedDate['month']}-27", $endDate, ts('End date incorrect.'));
// check line item and membership payment count.
$this->validateAllCounts($membershipId1, 6);
$this->validateAllCounts($membershipId2, 4);
$this->callAPISuccessGetCount('MembershipPayment', $memPayParams, $count);
}
+ /**
+ * Given a number of months offset, get the year and month.
+ * Note the way php arithmetic works, using strtotime('+x months') doesn't
+ * work because it will roll over the day accounting for different number
+ * of days in the month, but we want the same day of the month, x months
+ * from now.
+ * e.g. July 31 + 4 months will return Dec 1 if using php functions, but
+ * we want Nov 31.
+ *
+ * @param int $offset
+ * @param int $year Optional input year to start
+ * @param int $month Optional input month to start
+ *
+ * @return array
+ * ['year' => int, 'month' => int]
+ */
+ private function getYearAndMonthFromOffset(int $offset, int $year = NULL, int $month = NULL) {
+ $dateInfo = [
+ 'year' => $year ?? date('Y'),
+ 'month' => ($month ?? date('m')) + $offset,
+ ];
+ if ($dateInfo['month'] > 12) {
+ $dateInfo['year']++;
+ $dateInfo['month'] -= 12;
+ }
+ if ($dateInfo['month'] < 10) {
+ $dateInfo['month'] = "0{$dateInfo['month']}";
+ }
+
+ return $dateInfo;
+ }
+
+ /**
+ * Test getYearAndMonthFromOffset
+ * @dataProvider yearMonthProvider
+ *
+ * @param array $input
+ * @param array $expected
+ */
+ public function testGetYearAndMonthFromOffset($input, $expected) {
+ $this->assertEquals($expected, $this->getYearAndMonthFromOffset($input[0], $input[1], $input[2]));
+ }
+
+ /**
+ * data provider for testGetYearAndMonthFromOffset
+ */
+ public function yearMonthProvider() {
+ return [
+ // input = offset, year, current month
+ ['input' => [4, 2020, 1], 'output' => ['year' => '2020', 'month' => '05']],
+ ['input' => [6, 2020, 1], 'output' => ['year' => '2020', 'month' => '07']],
+ ['input' => [4, 2020, 2], 'output' => ['year' => '2020', 'month' => '06']],
+ ['input' => [6, 2020, 2], 'output' => ['year' => '2020', 'month' => '08']],
+ ['input' => [4, 2020, 3], 'output' => ['year' => '2020', 'month' => '07']],
+ ['input' => [6, 2020, 3], 'output' => ['year' => '2020', 'month' => '09']],
+ ['input' => [4, 2020, 4], 'output' => ['year' => '2020', 'month' => '08']],
+ ['input' => [6, 2020, 4], 'output' => ['year' => '2020', 'month' => '10']],
+ ['input' => [4, 2020, 5], 'output' => ['year' => '2020', 'month' => '09']],
+ ['input' => [6, 2020, 5], 'output' => ['year' => '2020', 'month' => '11']],
+ ['input' => [4, 2020, 6], 'output' => ['year' => '2020', 'month' => '10']],
+ ['input' => [6, 2020, 6], 'output' => ['year' => '2020', 'month' => '12']],
+ ['input' => [4, 2020, 7], 'output' => ['year' => '2020', 'month' => '11']],
+ ['input' => [6, 2020, 7], 'output' => ['year' => '2021', 'month' => '01']],
+ ['input' => [4, 2020, 8], 'output' => ['year' => '2020', 'month' => '12']],
+ ['input' => [6, 2020, 8], 'output' => ['year' => '2021', 'month' => '02']],
+ ['input' => [4, 2020, 9], 'output' => ['year' => '2021', 'month' => '01']],
+ ['input' => [6, 2020, 9], 'output' => ['year' => '2021', 'month' => '03']],
+ ['input' => [4, 2020, 10], 'output' => ['year' => '2021', 'month' => '02']],
+ ['input' => [6, 2020, 10], 'output' => ['year' => '2021', 'month' => '04']],
+ ['input' => [4, 2020, 11], 'output' => ['year' => '2021', 'month' => '03']],
+ ['input' => [6, 2020, 11], 'output' => ['year' => '2021', 'month' => '05']],
+ ['input' => [4, 2020, 12], 'output' => ['year' => '2021', 'month' => '04']],
+ ['input' => [6, 2020, 12], 'output' => ['year' => '2021', 'month' => '06']],
+ ];
+ }
+
}
/**
* Add participant with contribution
*
- * @return array
+ * @return CRM_Contribute_BAO_Contribution
*
* @throws \CRM_Core_Exception
* @throws \CiviCRM_API3_Exception
$this->_contactId = $this->individualCreate();
$event = $this->eventCreatePaid([]);
$this->_eventId = $event['id'];
- $priceSetId = $this->priceSetID;
+ $priceSetID = $this->ids['PriceSet']['event'];
$paramsField = [
'label' => 'Price Field',
'name' => CRM_Utils_String::titleToVar('Price Field'),
'weight' => 1,
'options_per_line' => 1,
'is_active' => ['1' => 1, '2' => 1],
- 'price_set_id' => $this->priceSetID,
+ 'price_set_id' => $priceSetID,
'is_enter_qty' => 1,
'financial_type_id' => CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', 'Event Fee', 'id', 'name'),
];
'is_monetary' => 1,
];
CRM_Event_BAO_Event::create($eventParams);
- CRM_Price_BAO_PriceSet::addTo('civicrm_event', $this->_eventId, $priceSetId);
+ CRM_Price_BAO_PriceSet::addTo('civicrm_event', $this->_eventId, $priceSetID);
$priceFields = $this->callAPISuccess('PriceFieldValue', 'get', ['price_field_id' => $priceField->id]);
$participantParams = [
$this->membershipDelete($membership['id']);
}
+ /**
+ * Test no warnings or errors during preProcess when editing.
+ */
+ public function testPreProcessContributionEdit() {
+ // Simulate a contribution in pending status
+ $contribution = $this->callAPISuccess(
+ 'Contribution',
+ 'create',
+ array_merge($this->_params, ['contribution_status_id' => 'Pending'])
+ );
+
+ // set up the form to edit the contribution and call preProcess
+ $form = $this->getFormObject('CRM_Contribute_Form_Contribution');
+ $_REQUEST['cid'] = $this->_individualId;
+ $_REQUEST['id'] = $contribution['id'];
+ $form->_action = CRM_Core_Action::UPDATE;
+ $form->preProcess();
+
+ // Check something while we're here
+ $this->assertEquals($contribution['id'], $form->_values['contribution_id']);
+
+ unset($_REQUEST['cid']);
+ unset($_REQUEST['id']);
+ }
+
}
return $total;
}),
'financial_type_id' => $priceFieldValues['values'][0]['financial_type_id'],
- 'contribution_status_id' => 'Pending',
'currency' => 'USD',
'line_items' => $lineItemParams,
];
// Wipe out any in-memory copies of the cache. Check to see if the SQL
// read is correct.
- CRM_Core_BAO_Cache::$_cache = NULL;
CRM_Utils_Cache::$_singleton = NULL;
$this->a->values = [];
$return_2 = $this->a->get('testSetGetItem');
'billing_country_id-5' => 1228,
'frequency_interval' => 1,
'frequency_unit' => 'month',
- 'installments' => '',
+ 'installments' => 2,
'hidden_AdditionalDetail' => 1,
'hidden_Premium' => 1,
'payment_processor_id' => $this->_paymentProcessorID,
$this->_contributionID = $contribution->id;
$this->ids['Contribution'][0] = $contribution->id;
$this->_contributionRecurID = $contribution->contribution_recur_id;
- $recur_params = [
- 'id' => $this->_contributionRecurID,
- 'return' => 'processor_id',
- ];
- $processor_id = civicrm_api3('ContributionRecur', 'getvalue', $recur_params);
- // Process the initial one.
+
+ $contributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', ['id' => $this->_contributionRecurID]);
+ $processor_id = $contributionRecur['processor_id'];
+ $this->assertEquals('Pending', CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_Contribution', 'contribution_status_id', $contributionRecur['contribution_status_id']));
+ // Process the initial one after a second's break to ensure modified date really is later.
+ sleep(1);
$IPN = new CRM_Core_Payment_AuthorizeNetIPN(
$this->getRecurTransaction(['x_subscription_id' => $processor_id])
);
$IPN->main();
+ $updatedContributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', ['id' => $this->_contributionRecurID]);
+ $this->assertEquals('In Progress', CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', $updatedContributionRecur['contribution_status_id']));
+ $this->assertTrue(strtotime($updatedContributionRecur['modified_date']) > strtotime($contributionRecur['modified_date']));
// Now send a second one (authorize seems to treat first and second contributions
// differently.
- $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurSubsequentTransaction(
- ['x_subscription_id' => $processor_id]
- ));
+ $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurSubsequentTransaction([
+ 'x_subscription_id' => $processor_id,
+ 'x_subscription_paynum' => 2,
+ ]));
$IPN->main();
-
+ $updatedContributionRecurAgain = $this->callAPISuccessGetSingle('ContributionRecur', ['id' => $this->_contributionRecurID]);
+ $this->assertEquals('Completed', CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', $updatedContributionRecurAgain['contribution_status_id']));
+ $this->assertEquals(date('Y-m-d'), substr($updatedContributionRecurAgain['end_date'], 0, 10));
// There should not be any email.
$mut->assertMailLogEmpty();
}
*/
public function tearDown() {
$this->quickCleanUpFinancialEntities();
- CRM_Member_PseudoConstant::membershipType(NULL, TRUE);
CRM_Member_PseudoConstant::membershipStatus(NULL, NULL, 'name', TRUE);
}
$this->_setUpMembershipObjects();
$this->_setUpRecurringContribution();
$this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId);
- $this->assertFalse(empty($this->objects['membership']));
+ $this->assertNotEmpty($this->objects['membership']);
$this->assertArrayHasKey($this->_membershipTypeID, $this->objects['membership']);
$this->assertTrue(is_a($this->objects['membership'][$this->_membershipTypeID], 'CRM_Member_BAO_Membership'));
$this->assertTrue(is_a($this->objects['financialType'], 'CRM_Financial_BAO_FinancialType'));
- $this->assertFalse(empty($this->objects['contributionRecur']));
- $this->assertFalse(empty($this->objects['paymentProcessor']));
+ $this->assertNotEmpty($this->objects['contributionRecur']);
+ $this->assertNotEmpty($this->objects['paymentProcessor']);
}
/**
$contribution->id = $this->_contributionId;
$contribution->find(TRUE);
$contribution->loadRelatedObjects($this->input, $this->ids, TRUE);
- $this->assertFalse(empty($contribution->_relatedObjects['membership']));
+ $this->assertNotEmpty($contribution->_relatedObjects['membership']);
$this->assertArrayHasKey($this->_membershipTypeID, $contribution->_relatedObjects['membership']);
$this->assertTrue(is_a($contribution->_relatedObjects['membership'][$this->_membershipTypeID], 'CRM_Member_BAO_Membership'));
$this->assertTrue(is_a($contribution->_relatedObjects['financialType'], 'CRM_Financial_BAO_FinancialType'));
/**
* Test the LoadObjects function with recurring membership data.
*/
- public function testsendMailMembershipObjects() {
+ public function testSendMailMembershipObjects() {
$this->_setUpMembershipObjects();
+ $contribution = new CRM_Contribute_BAO_Contribution();
+ $contribution->id = $this->_contributionId;
$values = [];
- $this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId);
- $msg = $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, TRUE);
- $this->assertTrue(is_array($msg), "Message returned as an array in line");
+ $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
+ $this->assertInternalType('array', $msg, 'Message returned as an array in line');
$this->assertEquals('Mr. Anthony Anderson II', $msg['to']);
$this->assertContains('Membership Type: General', $msg['body']);
}
*/
public function testSendMailMembershipObjectsNoLeakage() {
$this->_setUpMembershipObjects();
+ $contribution = new CRM_Contribute_BAO_Contribution();
$values = [];
- $this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId);
- $msg = $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, TRUE);
+ $contribution->id = $this->_contributionId;
+ $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
$this->assertEquals('Mr. Anthony Anderson II', $msg['to']);
$this->assertContains('Membership Type: General', $msg['body']);
$this->input['invoiceID'] = 'abc';
$this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId);
$this->assertEquals('Donald', $this->objects['contact']->first_name);
- $msg = $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, TRUE);
+ $contribution = new CRM_Contribute_BAO_Contribution();
+ $contribution->id = $this->_contributionId;
+ $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
$this->assertEquals('Dr. Donald Duck II', $msg['to']);
$this->assertContains('Membership Type: Fowl', $msg['body']);
}
/**
* Test the LoadObjects function with recurring membership data.
*/
- public function testsendMailMembershipWithoutLoadObjects() {
+ public function testSendMailMembershipWithoutLoadObjects() {
$this->_setUpMembershipObjects();
- $values = [];
- $msg = $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, TRUE);
- $this->assertTrue(is_array($msg), "Message returned as an array in line" . __LINE__);
+ $contribution = new CRM_Contribute_BAO_Contribution();
+ $contribution->id = $this->_contributionId;
+ $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
+ $this->assertInternalType('array', $msg, 'Message not returned as an array');
$this->assertEquals('Mr. Anthony Anderson II', $msg['to']);
$this->assertContains('Membership Type: General', $msg['body']);
}
$this->assertFalse(empty($this->objects['event']));
$this->assertTrue(is_a($this->objects['event'], 'CRM_Event_BAO_Event'));
$this->assertTrue(is_a($this->objects['contribution'], 'CRM_Contribute_BAO_Contribution'));
- $this->assertFalse(empty($this->objects['event']->id));
+ $this->assertNotEmpty($this->objects['event']->id);
}
/**
$this->_setUpParticipantObjects();
$this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId);
$values = [];
- $this->assertFalse(empty($this->objects['event']));
- $msg = $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, TRUE);
+ $this->assertNotEmpty($this->objects['event']);
+ $contribution = new CRM_Contribute_BAO_Contribution();
+ $contribution->id = $this->_contributionId;
+ $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
$this->assertContains('registration has been received and your status has been updated to Attended.', $msg['body']);
$this->assertContains('Annual CiviCRM meet', $msg['html']);
}
*/
public function testComposeMailParticipantObjects() {
$this->_setUpParticipantObjects();
- $values = [];
- $msg = $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, TRUE);
- $this->assertTrue(is_array($msg), "Message returned as an array in line" . __LINE__);
+ $contribution = new CRM_Contribute_BAO_Contribution();
+ $contribution->id = $this->_contributionId;
+ $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
$this->assertEquals('Mr. Anthony Anderson II', $msg['to']);
$this->assertContains('Thank you for your registration', $msg['body']);
}
/**
* Test the LoadObjects function with recurring membership data.
*/
- public function testsendMailParticipantObjectsCheckLog() {
+ public function testSendMailParticipantObjectsCheckLog() {
$this->_setUpParticipantObjects();
- $values = [];
$mut = new CiviMailUtils($this, TRUE);
- $this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId);
- $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, FALSE);
+ $this->callAPISuccess('Contribution', 'sendconfirmation', [
+ 'id' => $this->_contributionId,
+ ]);
$mut->checkMailLog([
'Thank you for your registration',
'Annual CiviCRM meet',
];
$this->quickCleanup($tablesToTruncate, FALSE);
$mut = new CiviMailUtils($this, TRUE);
- $this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId);
- $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, FALSE);
+ $contribution = new CRM_Contribute_BAO_Contribution();
+ $contribution->id = $this->_contributionId;
+ $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
$mut->assertMailLogEmpty('no mail should have been send as event set to no confirm');
$mut->stop();
}
/**
* Test the LoadObjects function with a pledge.
*/
- public function testsendMailPledge() {
+ public function testSendMailPledge() {
$this->_setUpPledgeObjects();
- $values = [];
- $this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, NULL);
- $msg = $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, TRUE);
+ $contribution = new CRM_Contribute_BAO_Contribution();
+ $contribution->id = $this->_contributionId;
+ $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
$this->assertContains('Contribution Information', $msg['html']);
}
*/
class CRM_Event_BAO_EventPermissionsTest extends CiviUnitTestCase {
+ use CRMTraits_ACL_PermissionTrait;
+
public function setUp() {
parent::setUp();
$this->_contactId = $this->createLoggedInUser();
$this->assertTrue($permissions);
}
+ /**
+ * Test that the contact can view an event with an ACL permitting everyone to view it.
+ */
+ public function testViewAclEventAllowed() {
+ $this->setupScenarioCoreACLEveryonePermittedToEvent();
+ $permittedEventID = CRM_Core_Permission::event(CRM_Core_Permission::VIEW, $this->scenarioIDs['Event']['permitted_event']);
+ $this->assertEquals($this->scenarioIDs['Event']['permitted_event'], $permittedEventID);
+ }
+
public function testEditOtherEventDenied() {
$this->_loggedInUser = CRM_Core_Session::singleton()->get('userID');
- self::setViewAllEventPermissions();
+ $this->setViewAllEventPermissions();
unset(\Civi::$statics['CRM_Event_BAO_Event']['permissions']);
$permissions = CRM_Event_BAO_Event::checkPermission($this->_otherEventId, CRM_Core_Permission::EDIT);
$this->assertFalse($permissions);
'start_date' => $startDate,
]);
$url = CRM_Utils_System::url('civicrm/event/info', "reset=1&id={$this->_eventId}");
- // If we return without an error, then success. But we don't always expect success.
- try {
- CRM_Event_BAO_Participant::getSelfServiceEligibility($participantId, $url, $isBackOffice);
- }
- catch (\Exception $e) {
- if ($successExpected === FALSE) {
- return;
- }
- else {
- $this->fail();
- }
- }
- if ($successExpected === FALSE) {
- $this->fail();
- }
+ $details = CRM_Event_BAO_Participant::getSelfServiceEligibility($participantId, $url, $isBackOffice);
+ $this->assertEquals($details['eligible'], $successExpected);
}
public function selfServiceScenarios() {
// Standard pass scenario
$scenarios[] = [
- 'selfSvcEnabled' => TRUE,
+ 'selfSvcEnabled' => 1,
'selfSvcHours' => 12,
'hoursToEvent' => 16,
'participantStatusId' => 1,
];
// Too late to self-service
$scenarios[] = [
- 'selfSvcEnabled' => TRUE,
+ 'selfSvcEnabled' => 1,
'selfSvcHours' => 12,
'hoursToEvent' => 8,
'participantStatusId' => 1,
];
// Participant status is other than "Registered".
$scenarios[] = [
- 'selfSvcEnabled' => TRUE,
+ 'selfSvcEnabled' => 1,
'selfSvcHours' => 12,
'hoursToEvent' => 16,
'participantStatusId' => 2,
'isBackOffice' => FALSE,
'successExpected' => FALSE,
];
+ // Event doesn't allow self-service
+ $scenarios[] = [
+ 'selfSvcEnabled' => 0,
+ 'selfSvcHours' => 12,
+ 'hoursToEvent' => 16,
+ 'participantStatusId' => 1,
+ 'isBackOffice' => FALSE,
+ 'successExpected' => FALSE,
+ ];
+ // Cancellation deadline is > 24 hours, still ok to cancel
+ $scenarios[] = [
+ 'selfSvcEnabled' => 1,
+ 'selfSvcHours' => 36,
+ 'hoursToEvent' => 46,
+ 'participantStatusId' => 1,
+ 'isBackOffice' => FALSE,
+ 'successExpected' => TRUE,
+ ];
+ // Cancellation deadline is > 24 hours, too late to cancel
+ $scenarios[] = [
+ 'selfSvcEnabled' => 1,
+ 'selfSvcHours' => 36,
+ 'hoursToEvent' => 25,
+ 'participantStatusId' => 1,
+ 'isBackOffice' => FALSE,
+ 'successExpected' => FALSE,
+ ];
return $scenarios;
}
* @return int
*/
protected function getEventID(): int {
- return $this->ids['event']['event'];
+ return $this->ids['Event']['event'];
}
/**
--- /dev/null
+<?php
+
+/**
+ * Test CRM_Event_Form_Registration functions.
+ *
+ * @package CiviCRM
+ * @group headless
+ */
+class CRM_Event_Form_Task_ParticipantStatusTest extends CiviUnitTestCase {
+
+ /**
+ * Test the the submit function on the event participant submit function.
+ *
+ * @todo extract submit functions on other Batch update classes, use dataprovider to test on all.
+ */
+ public function testSubmit() {
+ $group = $this->customGroupCreate(['extends' => 'Participant', 'title' => 'Participant']);
+ $field = $this->customFieldCreate(['custom_group_id' => $group['id'], 'html_type' => 'CheckBox', 'option_values' => ['two' => 'A couple', 'three' => 'A few', 'four' => 'Too Many']]);
+ $participantID = $this->participantCreate();
+ $participant = $this->callAPISuccessGetSingle('Participant', ['id' => $participantID]);
+ $this->assertEquals(2, $participant['participant_status_id']);
+
+ $form = $this->getFormObject('CRM_Event_Form_Task_Batch');
+ $form->submit(['field' => [$participantID => ['participant_status_id' => 1, 'custom_' . $field['id'] => ['two' => 1, 'four' => 1]]]]);
+
+ $participant = $this->callAPISuccessGetSingle('Participant', ['id' => $participantID]);
+ $this->assertEquals(1, $participant['participant_status_id']);
+ }
+
+}
'Phone Extension' => '',
'Phone Type' => '',
'Email' => 'home@example.com',
- 'On Hold' => '',
+ 'On Hold' => 'No',
'Use for Bulk Mail' => '',
'Signature Text' => '',
'Signature Html' => '',
'Phone Extension' => '',
'Phone Type' => '',
'Email' => 'home@example.com',
- 'On Hold' => '',
+ 'On Hold' => 'No',
'Use for Bulk Mail' => '',
'Signature Text' => '',
'Signature Html' => '',
'case_type' => 1,
'case_role' => 1,
'case_deleted' => 1,
- 'case_recent_activity_date' => 1,
- 'case_recent_activity_type' => 1,
- 'case_scheduled_activity_date' => 1,
+ 'case_activity_date_time' => 1,
+ 'case_activity_type' => 1,
];
}
return [
82 => 'Contact ID',
83 => 'Case ID',
- 84 => 'case_activity_subject',
+ 84 => 'Subject',
85 => 'Case Subject',
86 => 'Case Status',
87 => 'Case Type',
88 => 'Role in Case',
89 => 'Case is in the Trash',
- 90 => 'case_recent_activity_date',
- 91 => 'case_recent_activity_type',
- 92 => 'case_scheduled_activity_date',
+ 90 => 'Activity Date',
+ 91 => 'Activity Type',
93 => 'Case Start Date',
94 => 'Case End Date',
- 95 => 'case_source_contact_id',
- 96 => 'case_activity_status',
- 97 => 'case_activity_duration',
- 98 => 'case_activity_medium_id',
- 99 => 'case_activity_details',
- 100 => 'case_activity_is_auto',
+ 95 => 'Activity Reporter',
+ 96 => 'Activity Status',
+ 97 => 'Duration',
+ 98 => 'Activity Medium',
+ 99 => 'Details',
+ 100 => 'Activity Auto-generated?',
];
}
'case_end_date' => '`case_end_date` varchar(32)',
'case_subject' => '`case_subject` varchar(128)',
'case_source_contact_id' => '`case_source_contact_id` varchar(255)',
- 'case_activity_status' => '`case_activity_status` text',
- 'case_activity_duration' => '`case_activity_duration` text',
- 'case_activity_medium_id' => '`case_activity_medium_id` varchar(255)',
- 'case_activity_details' => '`case_activity_details` text',
- 'case_activity_is_auto' => '`case_activity_is_auto` text',
+ 'case_activity_status' => '`case_activity_status` varchar(255)',
+ 'case_activity_duration' => '`case_activity_duration` varchar(16)',
+ 'case_activity_medium_id' => '`case_activity_medium_id` varchar(16)',
+ 'case_activity_details' => '`case_activity_details` longtext',
+ 'case_activity_is_auto' => '`case_activity_is_auto` varchar(16)',
'contact_id' => '`contact_id` varchar(16)',
'case_id' => '`case_id` varchar(16)',
- 'case_activity_subject' => '`case_activity_subject` text',
+ 'case_activity_subject' => '`case_activity_subject` varchar(255)',
'case_status' => '`case_status` text',
'case_type' => '`case_type` text',
'case_role' => '`case_role` text',
'case_deleted' => '`case_deleted` varchar(16)',
- 'case_recent_activity_date' => '`case_recent_activity_date` text',
- 'case_recent_activity_type' => '`case_recent_activity_type` text',
- 'case_scheduled_activity_date' => '`case_scheduled_activity_date` text',
+ 'case_activity_date_time' => '`case_activity_date_time` varchar(32)',
+ 'case_activity_type' => '`case_activity_type` varchar(255)',
];
}
$this->assertContains($row[$key], $alternatives[$key]);
}
else {
- $this->assertEquals($value, $row[$key]);
+ $this->assertEquals($value, $row[$key], 'mismatch on ' . $key);
}
}
}
'Database check on updated membership status record.'
);
$this->assertEquals($result, 'pending', 'Verify membership status is_active.');
+
+ $this->callAPISuccess('MembershipStatus', 'Delete', ['id' => $membershipStatus->id]);
}
public function testRetrieve() {
'Database check on updated membership status record.'
);
$this->assertEquals($isActive, 0, 'Verify membership status is_active.');
+
+ $this->callAPISuccess('MembershipStatus', 'Delete', ['id' => $membershipStatus->id]);
}
public function testGetMembershipStatus() {
$membershipStatus = CRM_Member_BAO_MembershipStatus::add($params);
$result = CRM_Member_BAO_MembershipStatus::getMembershipStatus($membershipStatus->id);
$this->assertEquals($result['name'], 'pending', 'Verify membership status name.');
+
+ $this->callAPISuccess('MembershipStatus', 'Delete', ['id' => $membershipStatus->id]);
}
public function testDel() {
'is_active' => 1,
'is_reserved' => 0,
]);
+ CRM_Core_DAO::executeQuery("UPDATE civicrm_membership_status SET id=4 WHERE name='Expired'");
}
$result = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($toDate, $toDate, $toDate, 'today', TRUE, NULL, $params);
$this->assertEquals($result['name'], 'Current', 'Verify membership status record.');
+
+ $this->callAPISuccess('MembershipStatus', 'Delete', ['id' => $membershipStatus->id]);
+ }
+
+ /**
+ * Test getMembershipStatusByDate more
+ *
+ * @dataProvider statusByDateProvider
+ *
+ * @param array $input
+ * @param array $expected
+ */
+ public function testGetMembershipStatusByDateMore($input, $expected) {
+ // Sanity check we have something close to the stock install.
+ $this->assertEquals(7, $this->callAPISuccess('MembershipStatus', 'getcount'));
+
+ $this->assertEquals(
+ $expected,
+ CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate(
+ $input['startDate'],
+ $input['endDate'],
+ $input['joinDate'],
+ $input['statusDate']
+ )
+ );
+ }
+
+ /**
+ * Data provider for testGetMembershipStatusByDateMore
+ * @return array
+ */
+ public function statusByDateProvider():array {
+ return [
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '2020-04-30',
+ 'joinDate' => '2020-01-01',
+ 'statusDate' => '2020-03-01',
+ ],
+ [
+ 'id' => '1',
+ 'name' => 'New',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '2020-04-30',
+ 'joinDate' => '2020-01-01',
+ 'statusDate' => '2020-04-29',
+ ],
+ [
+ 'id' => '2',
+ 'name' => 'Current',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '2020-04-30',
+ 'joinDate' => '2020-01-01',
+ 'statusDate' => '2020-05-01',
+ ],
+ [
+ 'id' => '3',
+ 'name' => 'Grace',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '2020-04-30',
+ 'joinDate' => '2020-01-01',
+ 'statusDate' => '2020-06-01',
+ ],
+ [
+ 'id' => '4',
+ 'name' => 'Expired',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '2020-04-30',
+ 'joinDate' => '2019-01-01',
+ 'statusDate' => '2020-03-01',
+ ],
+ [
+ 'id' => '2',
+ 'name' => 'Current',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '2020-04-30',
+ 'joinDate' => '2019-01-01',
+ 'statusDate' => '2020-04-29',
+ ],
+ [
+ 'id' => '2',
+ 'name' => 'Current',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '2020-04-30',
+ 'joinDate' => '2019-01-01',
+ 'statusDate' => '2020-05-01',
+ ],
+ [
+ 'id' => '3',
+ 'name' => 'Grace',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '2020-04-30',
+ 'joinDate' => '2019-01-01',
+ 'statusDate' => '2020-06-01',
+ ],
+ [
+ 'id' => '4',
+ 'name' => 'Expired',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '2021-01-31',
+ 'joinDate' => '2020-01-01',
+ 'statusDate' => '2020-03-01',
+ ],
+ [
+ 'id' => '1',
+ 'name' => 'New',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '2021-01-31',
+ 'joinDate' => '2020-01-01',
+ 'statusDate' => '2020-04-29',
+ ],
+ [
+ 'id' => '2',
+ 'name' => 'Current',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '2021-01-31',
+ 'joinDate' => '2020-01-01',
+ 'statusDate' => '2020-12-30',
+ ],
+ [
+ 'id' => '2',
+ 'name' => 'Current',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '2021-01-31',
+ 'joinDate' => '2020-01-01',
+ 'statusDate' => '2021-01-01',
+ ],
+ [
+ 'id' => '2',
+ 'name' => 'Current',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '2021-01-31',
+ 'joinDate' => '2020-01-01',
+ 'statusDate' => '2021-01-31',
+ ],
+ [
+ 'id' => '2',
+ 'name' => 'Current',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '2021-01-31',
+ 'joinDate' => '2020-01-01',
+ 'statusDate' => '2021-02-21',
+ ],
+ [
+ 'id' => '3',
+ 'name' => 'Grace',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '2021-01-31',
+ 'joinDate' => '2020-01-01',
+ 'statusDate' => '2021-03-21',
+ ],
+ [
+ 'id' => '4',
+ 'name' => 'Expired',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '',
+ 'joinDate' => '2020-01-01',
+ 'statusDate' => '2020-03-01',
+ ],
+ [
+ 'id' => '1',
+ 'name' => 'New',
+ ],
+ ],
+ [
+ [
+ 'startDate' => '2020-02-01',
+ 'endDate' => '',
+ 'joinDate' => '2020-01-01',
+ 'statusDate' => '2020-06-01',
+ ],
+ [
+ 'id' => '2',
+ 'name' => 'Current',
+ ],
+ ],
+ ];
}
public function testgetMembershipStatusCurrent() {
$result = CRM_Member_BAO_MembershipStatus::getMembershipStatusCurrent();
$this->assertEquals(empty($result), FALSE, 'Verify membership status records is_current_member.');
+
+ $this->callAPISuccess('MembershipStatus', 'Delete', ['id' => $membershipStatus->id]);
}
}
], CRM_PCP_BAO_PCP::getPcpDashboardInfo($contactID));
}
+ /**
+ * Test that CRM_Contribute_BAO_Contribution::_gatherMessageValues() works
+ * with PCP.
+ */
+ public function testGatherMessageValuesForPCP() {
+ // set up a pcp page
+ $block = CRM_PCP_BAO_PCPBlock::create($this->pcpBlockParams());
+ // The owner of the pcp, who gets the soft credit
+ $contact_owner = $this->individualCreate([], 0, TRUE);
+ $contributionPage = $this->callAPISuccessGetSingle('ContributionPage', []);
+ $pcp = $this->callAPISuccess('Pcp', 'create', [
+ 'contact_id' => $contact_owner,
+ 'title' => 'pcp',
+ 'page_id' => $contributionPage['id'],
+ 'pcp_block_id' => $block->id,
+ 'is_active' => TRUE,
+ 'status_id' => 'Approved',
+ ]);
+
+ // set up a payment processor
+ $payment_processor_type = $this->callAPISuccess('PaymentProcessorType', 'get', ['name' => 'Dummy']);
+ $payment_processor = $this->callAPISuccess('PaymentProcessor', 'create', [
+ 'name' => 'Dummy PP',
+ 'payment_processor_type_id' => $payment_processor_type['id'],
+ 'class_name' => $payment_processor_type['values'][$payment_processor_type['id']]['class_name'],
+ ]);
+
+ // create a contribution with the pcp soft credit
+ $contact_contributor = $this->individualCreate([], 1, TRUE);
+ $address = $this->callAPISuccess('address', 'create', [
+ 'address_name' => "Giver {$contact_contributor}",
+ 'street_address' => '123 Main St.',
+ 'location_type_id' => 'Billing',
+ 'is_billing' => 1,
+ 'contact_id' => $contact_contributor,
+ ]);
+ $contribution = $this->callAPISuccess('Contribution', 'create', [
+ 'contact_id' => $contact_contributor,
+ 'address_id' => $address['id'],
+ 'total_amount' => 10,
+ 'receive_date' => date('YmdHis'),
+ 'financial_type_id' => 'Donation',
+ 'payment_processor' => $payment_processor['id'],
+ 'payment_instrument_id' => 'Credit Card',
+ ]);
+ $contribution_soft = $this->callAPISuccess('ContributionSoft', 'create', [
+ 'contribution_id' => $contribution['id'],
+ 'amount' => 10,
+ 'contact_id' => $contact_owner,
+ 'pcp_id' => $pcp['id'],
+ 'pcp_display_in_roll' => 1,
+ 'pcp_roll_nickname' => "Giver {$contact_contributor}",
+ 'soft_credit_type_id' => 'pcp',
+ ]);
+
+ // Retrieve it using BAO so we can call gatherMessageValues
+ $contribution_bao = new CRM_Contribute_BAO_Contribution();
+ $contribution_bao->id = $contribution['id'];
+ $contribution_bao->find(TRUE);
+
+ $contribution_bao->_component = 'contribute';
+
+ // call and check result. $values has to be defined since it's pass-by-ref.
+ $values = [
+ 'receipt_from_name' => 'CiviCRM Fundraising Dept.',
+ 'receipt_from_email' => 'donationFake@civicrm.org',
+ 'contribution_status' => 'Completed',
+ ];
+ $gathered_values = $contribution_bao->_gatherMessageValues(
+ [
+ 'payment_processor_id' => $payment_processor['id'],
+ 'is_email_receipt' => TRUE,
+ ],
+ $values,
+ [
+ 'component' => 'contribute',
+ 'contact_id' => $contact_contributor,
+ 'contact' => $contact_contributor,
+ 'financialType' => $contribution['values'][$contribution['id']]['financial_type_id'],
+ 'contributionType' => $contribution['values'][$contribution['id']]['contribution_type_id'],
+ 'contributionPage' => $contributionPage['id'],
+ 'membership' => [],
+ 'paymentProcessor' => $payment_processor['id'],
+ 'contribution' => $contribution['id'],
+ ]
+ );
+
+ $this->assertEquals([
+ 'receipt_from_name' => 'CiviCRM Fundraising Dept.',
+ 'receipt_from_email' => 'donationFake@civicrm.org',
+ 'contribution_status' => 'Completed',
+ 'billingName' => "Giver {$contact_contributor}",
+ 'address' => "Giver {$contact_contributor}\n123 Main St.\n",
+ 'softContributions' => NULL,
+ 'title' => 'Contribution',
+ 'priceSetID' => '1',
+ 'useForMember' => FALSE,
+ 'lineItem' => [
+ 0 => [
+ 1 => [
+ 'qty' => 1.0,
+ 'label' => 'Contribution Amount',
+ 'unit_price' => '10.00',
+ 'line_total' => '10.00',
+ 'price_field_id' => '1',
+ 'participant_count' => NULL,
+ 'price_field_value_id' => '1',
+ 'field_title' => 'Contribution Amount',
+ 'html_type' => 'Text',
+ 'description' => NULL,
+ 'entity_id' => '1',
+ 'entity_table' => 'civicrm_contribution',
+ 'contribution_id' => '1',
+ 'financial_type_id' => '1',
+ 'financial_type' => 'Donation',
+ 'membership_type_id' => NULL,
+ 'membership_num_terms' => NULL,
+ 'tax_amount' => 0.0,
+ 'price_set_id' => '1',
+ 'tax_rate' => FALSE,
+ 'subTotal' => 10.0,
+ ],
+ ],
+ ],
+ 'customGroup' => [],
+ 'is_pay_later' => '0',
+ ], $gathered_values);
+ }
+
}
$message->toContactID = $testSourceContact;
}
+ /**
+ * Some providers, like the mock one for these tests at the time of writing,
+ * or the dummy SMS provider extension, might not provide a default url,
+ * but the form shouldn't fail because of that.
+ */
+ public function testMissingUrl() {
+ $form = $this->getFormObject('CRM_SMS_Form_Provider');
+ $_REQUEST['key'] = 'CiviTestSMSProvider';
+
+ // This shouldn't give a notice
+ $defaults = $form->setDefaultValues();
+
+ $this->assertEquals([
+ 'name' => 'CiviTestSMSProvider',
+ 'api_url' => '',
+ 'is_default' => 1,
+ 'is_active' => 1,
+ ], $defaults);
+
+ unset($_REQUEST['key']);
+ }
+
}
}
+ /**
+ * Test that with an extension adding in UF Fields for an enttiy that isn't supplied by Core e.g. Grant
+ * That an appropriate entitytype can be specfied in the backbone.marionette profile editor e.g. GrantModel
+ */
+ public function testGetSchemaWithHooks() {
+ CRM_Utils_Hook::singleton()->setHook('civicrm_alterUFFields', [$this, 'hook_civicrm_alterUFFIelds']);
+ $schema = CRM_UF_Page_ProfileEditor::getSchema(['IndividualModel', 'GrantModel']);
+ $this->assertEquals('Grant', $schema['GrantModel']['schema']['grant_decision_date']['civiFieldType']);
+ }
+
+ /**
+ * Tries to load up the profile schema for a model where there is no corresponding set of fields avaliable.
+ *
+ * @expectedException \CRM_Core_Exception
+ */
+ public function testGetSchemaWithHooksWithInvalidModel() {
+ CRM_Utils_Hook::singleton()->setHook('civicrm_alterUFFields', [$this, 'hook_civicrm_alterUFFIelds']);
+ $schema = CRM_UF_Page_ProfileEditor::getSchema(['IndividualModel', 'GrantModel', 'PledgeModel']);
+ }
+
+ public function hook_civicrm_alterUFFIelds(&$fields) {
+ $fields['Grant'] = CRM_Grant_BAO_Grant::exportableFields();
+ }
+
}
*
* @throws CRM_Core_Exception
*/
- public function setupCoreACLPermittedToGroup($permissionedEntities = [], $groupAllowedAccess = 'Everyone', $operation = 'View', $entity = 'Group') {
+ public function setupCoreACLPermittedAcl($permissionedEntities = [], $groupAllowedAccess = 'Everyone', $operation = 'View', $entity = 'Group') {
$tableMap = ['Group' => 'civicrm_saved_search', 'CustomGroup' => 'civicrm_custom_group', 'Profile' => 'civicrm_uf_match', 'Event' => 'civicrm_event'];
$entityTable = $tableMap[$entity];
$result = $this->callAPISuccess('GroupContact', 'create', ['group_id' => $this->scenarioIDs['Group']['permitted_group'], 'contact_id' => $this->scenarioIDs['Contact']['permitted_contact'], 'status' => 'Added']);
$this->scenarioIDs['Contact']['non_permitted_contact'] = $this->individualCreate();
CRM_Core_Config::singleton()->userPermissionClass->permissions = [];
- $this->setupCoreACLPermittedToGroup([$this->scenarioIDs['Group']['permitted_group']]);
+ $this->setupCoreACLPermittedAcl([$this->scenarioIDs['Group']['permitted_group']]);
+ }
+
+ /**
+ * Set up a scenario where everyone can access the permissioned group.
+ *
+ * A scenario in this class involves multiple defined assets. In this case we create
+ * - a group to which the everyone has permission
+ * - a contact in the group
+ * - a contact not in the group
+ *
+ * These are arrayed as follows
+ * $this->scenarioIDs['Contact'] = ['permitted_contact' => x, 'non_permitted_contact' => y]
+ * $this->scenarioIDs['Group'] = ['permitted_group' => x]
+ */
+ public function setupScenarioCoreACLEveryonePermittedToEvent() {
+ $this->quickCleanup(['civicrm_acl_cache', 'civicrm_acl_contact_cache']);
+ $this->scenarioIDs['Event']['permitted_event'] = $this->eventCreate()['id'];
+ $this->scenarioIDs['Contact']['permitted_contact'] = $this->individualCreate();
+ CRM_Core_Config::singleton()->userPermissionClass->permissions = ['view event info'];
+ $this->setupCoreACLPermittedAcl([$this->scenarioIDs['Event']['permitted_event']], 'Everyone', 'View', 'Event');
}
/**
* @throws \CRM_Core_Exception
*/
protected function eventCreatePaid($params, $options = [['name' => 'hundy', 'amount' => 100]], $key = 'event') {
+ $params['is_monetary'] = TRUE;
$event = $this->eventCreate($params);
- $this->ids['event'][$key] = (int) $event['id'];
- $this->priceSetID = $this->ids['PriceSet'][] = $this->eventPriceSetCreate(55, 0, 'Radio', $options);
- CRM_Price_BAO_PriceSet::addTo('civicrm_event', $event['id'], $this->priceSetID);
- $priceSet = CRM_Price_BAO_PriceSet::getSetDetail($this->priceSetID, TRUE, FALSE);
- $priceSet = $priceSet[$this->priceSetID] ?? NULL;
+ $this->ids['Event'][$key] = (int) $event['id'];
+ $this->ids['PriceSet'][$key] = $this->eventPriceSetCreate(55, 0, 'Radio', $options);
+ CRM_Price_BAO_PriceSet::addTo('civicrm_event', $event['id'], $this->ids['PriceSet'][$key]);
+ $priceSet = CRM_Price_BAO_PriceSet::getSetDetail($this->ids['PriceSet'][$key], TRUE, FALSE);
+ $priceSet = $priceSet[$this->ids['PriceSet'][$key]] ?? NULL;
$this->eventFeeBlock = $priceSet['fields'] ?? NULL;
return $event;
}
protected function swapMessageTemplateForTestTemplate($templateName = 'contribution_online_receipt', $type = 'html') {
$testTemplate = file_get_contents(__DIR__ . '/../../templates/message_templates/' . $templateName . '_' . $type . '.tpl');
CRM_Core_DAO::executeQuery(
- "UPDATE civicrm_option_group og
- LEFT JOIN civicrm_option_value ov ON ov.option_group_id = og.id
- LEFT JOIN civicrm_msg_template m ON m.workflow_id = ov.id
- SET m.msg_{$type} = %1
- WHERE og.name LIKE 'msg_tpl_workflow_%'
- AND ov.name = '{$templateName}'
- AND m.is_default = 1", [1 => [$testTemplate, 'String']]
+ "UPDATE civicrm_msg_template
+ SET msg_{$type} = %1
+ WHERE workflow_name = '{$templateName}'
+ AND is_default = 1", [1 => [$testTemplate, 'String']]
);
}
}
+ /**
+ * Test that a blank location does not overwrite a location with data.
+ *
+ * This is a poor data edge case where a contact has an address record with no meaningful data.
+ * This record should be removed in favour of the one with data.
+ *
+ * @dataProvider getBooleanDataProvider
+ *
+ * @param bool $isReverse
+ *
+ * @throws \CRM_Core_Exception
+ */
+ public function testMergeWithBlankLocationData($isReverse) {
+ $this->createLoggedInUser();
+ $this->ids['contact'][0] = $this->callAPISuccess('contact', 'create', $this->_params)['id'];
+ $this->ids['contact'][1] = $this->callAPISuccess('contact', 'create', $this->_params)['id'];
+ $contactIDWithBlankAddress = ($isReverse ? $this->ids['contact'][1] : $this->ids['contact'][0]);
+ $contactIDWithoutBlankAddress = ($isReverse ? $this->ids['contact'][0] : $this->ids['contact'][1]);
+ $this->callAPISuccess('Address', 'create', [
+ 'contact_id' => $contactIDWithBlankAddress,
+ 'location_type_id' => 1,
+ ]);
+ $this->callAPISuccess('Address', 'create', [
+ 'country_id' => 'MX',
+ 'contact_id' => $contactIDWithoutBlankAddress,
+ 'street_address' => 'First on the left after you cross the border',
+ 'postal_code' => 90210,
+ 'location_type_id' => 1,
+ ]);
+
+ $contact = $this->doMerge($isReverse);
+ $this->assertEquals('Mexico', $contact['country']);
+ $this->assertEquals('90210', $contact['postal_code']);
+ $this->assertEquals('First on the left after you cross the border', $contact['street_address']);
+ }
+
/**
* Test merging 2 contacts with custom fields.
*
$this->callAPISuccess('Contact', 'delete', ['id' => $contact2, 'skip_undelete' => 1]);
}
+ /**
+ * Do the merge on the 2 contacts.
+ *
+ * @param bool $isReverse
+ *
+ * @return array|int
+ * @throws \CRM_Core_Exception
+ */
+ protected function doMerge($isReverse = FALSE) {
+ $this->callAPISuccess('Contact', 'merge', [
+ 'to_keep_id' => $isReverse ? $this->ids['contact'][1] : $this->ids['contact'][0],
+ 'to_remove_id' => $isReverse ? $this->ids['contact'][0] : $this->ids['contact'][1],
+ 'auto_flip' => FALSE,
+ ]);
+ return $this->callAPISuccessGetSingle('Contact', ['id' => $isReverse ? $this->ids['contact'][1] : $this->ids['contact'][0]]);
+ }
+
}
+--------------------------------------------------------------------+
*/
+use Civi\Api4\Contribution;
+
/**
* Test APIv3 civicrm_contribute_* functions
*
*/
public function tearDown() {
$this->quickCleanUpFinancialEntities();
- $this->quickCleanup(['civicrm_uf_match']);
+ $this->quickCleanup(['civicrm_uf_match'], TRUE);
$financialAccounts = $this->callAPISuccess('FinancialAccount', 'get', []);
foreach ($financialAccounts['values'] as $financialAccount) {
if ($financialAccount['name'] === 'Test Tax financial account ' || $financialAccount['name'] === 'Test taxable financial Type') {
], 'online');
}
+ /**
+ * Test custom data is copied over from the template transaction.
+ *
+ * (Over time various discussions have deemed this to be the most recent one, allowing
+ * users to alter custom data going forwards. This is implemented for line items already.
+ *
+ * @throws \API_Exception
+ * @throws \CRM_Core_Exception
+ */
+ public function testRepeatTransactionWithCustomData() {
+ $this->createCustomGroupWithFieldOfType(['extends' => 'Contribution', 'name' => 'Repeat'], 'text');
+ $originalContribution = $this->setUpRepeatTransaction([], 'single', [$this->getCustomFieldName('text') => 'first']);
+ $this->callAPISuccess('contribution', 'repeattransaction', [
+ 'contribution_recur_id' => $originalContribution['contribution_recur_id'],
+ 'contribution_status_id' => 'Completed',
+ 'trxn_id' => 'my_trxn',
+ ]);
+
+ $contribution = Contribution::get()
+ ->addWhere('trxn_id', '=', 'my_trxn')
+ ->addSelect('Custom_Group.Enter_text_here')
+ ->addSelect('id')
+ ->execute()->first();
+ $this->assertEquals('first', $contribution['Custom_Group.Enter_text_here']);
+
+ Contribution::update()->setValues(['Custom_Group.Enter_text_here' => 'second'])->addWhere('id', '=', $contribution['id'])->execute();
+
+ $this->callAPISuccess('contribution', 'repeattransaction', [
+ 'original_contribution_id' => $originalContribution['id'],
+ 'contribution_status_id' => 'Completed',
+ 'trxn_id' => 'number_3',
+ ]);
+
+ $contribution = Contribution::get()
+ ->addWhere('trxn_id', '=', 'number_3')
+ ->setSelect(['id', 'Custom_Group.Enter_text_here'])
+ ->execute()->first();
+ $this->assertEquals('second', $contribution['Custom_Group.Enter_text_here']);
+ }
+
/**
* Test repeat contribution successfully creates line items (plural).
*
$this->callAPISuccessGetCount('MembershipPayment', ['membership_id' => $membership['id']]);
}
+ /**
+ * This is one of those tests that locks in existing behaviour.
+ *
+ * I feel like correct behaviour is arguable & has been discussed in the past. However, if the membership has
+ * a date which says it should be expired then the result of repeattransaction is to push that date
+ * to be one membership term from 'now' with status 'new'.
+ */
+ public function testRepeattransactionRenewMembershipOldMembership() {
+ $entities = $this->setUpAutoRenewMembership();
+ $newStatusID = CRM_Core_PseudoConstant::getKey('CRM_Member_BAO_Membership', 'status_id', 'New');
+ $membership = $this->callAPISuccess('Membership', 'create', [
+ 'id' => $entities[1]['id'],
+ 'join_date' => '4 months ago',
+ 'start_date' => '3 months ago',
+ 'end_date' => '2 months ago',
+ ]);
+ $membership = $membership['values'][$membership['id']];
+
+ // This status does not appear to be calculated at all and is set to 'new'. Feels like a bug.
+ $this->assertEquals($newStatusID, $membership['status_id']);
+
+ // So it seems renewing this expired membership results in it's new status being current and it being pushed to a future date
+ $this->callAPISuccess('Contribution', 'repeattransaction', ['original_contribution_id' => $entities[0]['id'], 'contribution_status_id' => 'Completed']);
+ $membership = $this->callAPISuccessGetSingle('Membership', ['id' => $membership['id']]);
+ // If this date calculation winds up being flakey the spirit of the test would be maintained by just checking
+ // date is greater than today.
+ $this->assertEquals(date('Y-m-d', strtotime('+ 1 month -1 day')), $membership['end_date']);
+ $this->assertEquals($newStatusID, $membership['membership_type_id']);
+ }
+
/**
* CRM-19945 Tests that Contribute.repeattransaction DOES NOT renew a membership when contribution status=Failed
*
}
/**
- * CRM-17718 test appropriate action if financial type has changed for single line items.
+ * Test financial_type_id override behaviour with a single line item.
+ *
+ * CRM-17718 a passed in financial_type_id is allowed to override the original contribution where there
+ * is only one line item.
*/
public function testRepeatTransactionPassedInFinancialType() {
$originalContribution = $this->setUpRecurringContribution();
],
];
- $this->callAPISuccessGetSingle('contribution', [
+ $this->callAPISuccessGetSingle('Contribution', [
'total_amount' => 100,
'financial_type_id' => 2,
]);
$this->assertEquals($expectedLineItem, $lineItem2['values'][0]);
}
+ /**
+ * Test financial_type_id override behaviour with a single line item.
+ *
+ * CRM-17718 a passed in financial_type_id is not allowed to override the original contribution where there
+ * is more than one line item.
+ */
+ public function testRepeatTransactionPassedInFinancialTypeTwoLineItems() {
+ $this->_params = $this->getParticipantOrderParams();
+ $originalContribution = $this->setUpRecurringContribution();
+
+ $this->callAPISuccess('Contribution', 'repeattransaction', [
+ 'original_contribution_id' => $originalContribution['id'],
+ 'contribution_status_id' => 'Completed',
+ 'trxn_id' => 'repeat',
+ 'financial_type_id' => 2,
+ ]);
+
+ // Retrieve the new contribution and note the financial type passed in has been ignored.
+ $contribution = $this->callAPISuccessGetSingle('Contribution', [
+ 'trxn_id' => 'repeat',
+ ]);
+ $this->assertEquals(4, $contribution['financial_type_id']);
+
+ $lineItems = $this->callAPISuccess('line_item', 'get', [
+ 'entity_id' => $contribution['id'],
+ ])['values'];
+ foreach ($lineItems as $lineItem) {
+ $this->assertNotEquals(2, $lineItem['financial_type_id']);
+ }
+ }
+
/**
* CRM-17718 test appropriate action if financial type has changed for single line items.
*/
$this->callAPISuccess('contribution', 'completetransaction', ['id' => $contribution['id'], 'trxn_date' => date('Y-m-d')]);
$contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id'], 'sequential' => 1]);
$this->assertEquals('Completed', $contribution['values'][0]['contribution_status']);
- $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($contribution['values'][0]['receive_date'])));
+ // Make sure receive_date is original date and make sure payment date is today
+ $this->assertEquals('2012-05-11', date('Y-m-d', strtotime($contribution['values'][0]['receive_date'])));
+ $payment = $this->callAPISuccess('payment', 'get', ['contribution_id' => $contribution['id'], 'sequential' => 1]);
+ $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($payment['values'][0]['trxn_date'])));
$mut->checkMailLog([
'Receipt - Contribution',
'receipt_date:::' . date('Ymd'),
* Test that $is_recur is assigned to the receipt.
*/
public function testCompleteTransactionForRecurring() {
-
+ $this->mut = new CiviMailUtils($this, TRUE);
$this->swapMessageTemplateForTestTemplate();
$recurring = $this->setUpRecurringContribution();
$contributionPage = $this->createReceiptableContributionPage(['is_recur' => TRUE, 'recur_frequency_unit' => 'month', 'recur_interval' => 1]);
$this->assertEquals(1, $status);
$mut->checkMailLog([
'amount:::500.00',
- 'receive_date:::20130201000000',
+ // The `receive_date` should remain as it was created.
+ // TODO: the latest payment transaction date (and maybe other details,
+ // such as amount and payment instrument) would be a useful token to make
+ // available.
+ 'receive_date:::20120511000000',
"receipt_date:::\n",
]);
$mut->stop();
}
/**
- * Test membership is renewed when transaction completed.
+ * Test membership is renewed for 2 terms when transaction completed based on the line item having 2 terms as qty.
+ *
+ * Also check that altering the qty for the most recent contribution results in repeattransaction picking it up.
*/
public function testCompleteTransactionMembershipPriceSetTwoTerms() {
$this->createPriceSetWithPage('membership');
$this->setUpPendingContribution($this->_ids['price_field_value'][1]);
$this->callAPISuccess('contribution', 'completetransaction', ['id' => $this->_ids['contribution']]);
- $membership = $this->callAPISuccess('membership', 'getsingle', ['id' => $this->_ids['membership']]);
+ $membership = $this->callAPISuccessGetSingle('membership', ['id' => $this->_ids['membership']]);
$this->assertEquals(date('Y-m-d', strtotime('yesterday + 2 years')), $membership['end_date']);
+
+ $paymentProcessorID = $this->paymentProcessorAuthorizeNetCreate();
+
+ $contributionRecurID = $this->callAPISuccess('ContributionRecur', 'create', ['contact_id' => $membership['contact_id'], 'payment_processor_id' => $paymentProcessorID, 'amount' => 20, 'frequency_interval' => 1])['id'];
+ $this->callAPISuccess('Contribution', 'create', ['id' => $this->_ids['contribution'], 'contribution_recur_id' => $contributionRecurID]);
+ $this->callAPISuccess('contribution', 'repeattransaction', ['contribution_recur_id' => $contributionRecurID, 'contribution_status_id' => 'Completed']);
+ $membership = $this->callAPISuccessGetSingle('membership', ['id' => $this->_ids['membership']]);
+ $this->assertEquals(date('Y-m-d', strtotime('yesterday + 4 years')), $membership['end_date']);
+
+ // Update the most recent contribution to have a qty of 1 in it's line item and then repeat, expecting just 1 year to be added.
+ $contribution = Contribution::get()->setOrderBy(['id' => 'DESC'])->setSelect(['id'])->execute()->first();
+ CRM_Core_DAO::executeQuery('UPDATE civicrm_line_item SET price_field_value_id = ' . $this->_ids['price_field_value'][0] . ' WHERE contribution_id = ' . $contribution['id']);
+ $this->callAPISuccess('contribution', 'repeattransaction', ['contribution_recur_id' => $contributionRecurID, 'contribution_status_id' => 'Completed']);
+ $membership = $this->callAPISuccessGetSingle('membership', ['id' => $this->_ids['membership']]);
+ $this->assertEquals(date('Y-m-d', strtotime('yesterday + 5 years')), $membership['end_date']);
+
$this->cleanUpAfterPriceSets();
}
* Parameters to merge into the recur only.
*
* @return array|int
+ * @throws \CRM_Core_Exception
*/
protected function setUpRecurringContribution($generalParams = [], $recurParams = []) {
$contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array_merge([
'frequency_unit' => 'month',
'payment_processor_id' => $this->paymentProcessorID,
], $generalParams, $recurParams));
- $originalContribution = $this->callAPISuccess('contribution', 'create', array_merge(
+ $contributionParams = array_merge(
$this->_params,
[
'contribution_recur_id' => $contributionRecur['id'],
- ], $generalParams)
- );
+ 'contribution_status_id' => 'Pending',
+ ], $generalParams);
+ $contributionParams['api.Payment.create'] = ['total_amount' => $contributionParams['total_amount']];
+ $originalContribution = $this->callAPISuccess('Order', 'create', $contributionParams);
return $originalContribution;
}
$params = array_merge($params, $contributionParams);
$originalContribution = $this->callAPISuccess('contribution', 'create', $params);
}
+ $originalContribution['contribution_recur_id'] = $contributionRecur['id'];
$originalContribution['payment_processor_id'] = $paymentProcessorID;
return $originalContribution;
}
return $result;
}
+ /**
+ * Make sure that recording a payment doesn't alter the receive_date of a
+ * pending contribution.
+ */
+ public function testPaymentDontChangeReceiveDate() {
+ $params = [
+ 'contact_id' => $this->_individualId,
+ 'total_amount' => 100,
+ 'receive_date' => '2020-02-02',
+ 'contribution_status_id' => 'Pending',
+ ];
+ $contributionID = $this->contributionCreate($params);
+ $paymentParams = [
+ 'contribution_id' => $contributionID,
+ 'total_amount' => 100,
+ 'trxn_date' => '2020-03-04',
+ ];
+ $this->callAPISuccess('payment', 'create', $paymentParams);
+
+ //check if contribution status is set to "Completed".
+ $contribution = $this->callAPISuccess('Contribution', 'getSingle', [
+ 'id' => $contributionID,
+ ]);
+ $this->assertEquals('2020-02-02 00:00:00', $contribution['receive_date']);
+ }
+
}
* Test civicrm_mailing_group_event_subscribe and civicrm_mailing_event_confirm functions - success expected.
*/
public function testMailerProcess() {
+ $this->callAPISuccess('MailSettings', 'create', [
+ 'domain_id' => 1,
+ 'name' => "my mail setting",
+ 'domain' => 'setting.com',
+ 'localpart' => 'civicrm+',
+ 'server' => "localhost",
+ 'username' => 'sue',
+ 'password' => 'pass',
+ 'is_default' => 1,
+ ]);
+ $mut = new CiviMailUtils($this, TRUE);
+ Civi::settings()->set('include_message_id', 1);
$params = [
'first_name' => 'Test',
'last_name' => 'Test',
'time_stamp' => '20101212121212',
];
$result = $this->callAPISuccess('mailing_event_subscribe', 'create', $params);
+ // Check that subscription email has been sent.
+ $msgs = $mut->getAllMessages();
+ $this->assertCount(1, $msgs, 'Subscription email failed to send');
+ $mut->checkMailLog([
+ 'Message-ID: <civicrm+s',
+ 'To confirm this subscription, reply to this email or click',
+ ]);
$this->assertEquals($result['values'][$result['id']]['contact_id'], $contactID);
$this->callAPISuccess('mailing_event_confirm', 'create', $params);
$this->contactDelete($contactID);
+ Civi::settings()->set('include_message_id', 0);
}
}
]);
$this->_membershipStatusID = $this->membershipStatusCreate('test status');
- CRM_Member_PseudoConstant::membershipType(NULL, TRUE);
CRM_Member_PseudoConstant::membershipStatus(NULL, NULL, 'name', TRUE);
CRM_Core_PseudoConstant::activityType(TRUE, TRUE, TRUE, 'name');
'total_amount' => 100,
'contact_id' => $this->_params['contact_id'],
]);
- $membershipPaymentCreate = $this->callAPISuccess('MembershipPayment', 'create', [
+ $this->callAPISuccess('MembershipPayment', 'create', [
'sequential' => 1,
'contribution_id' => $ContributionCreate['values'][0]['id'],
'membership_id' => $membershipID,
public function testActivityForCancelledContribution() {
$contactId = $this->createLoggedInUser();
$membershipID = $this->contactMembershipCreate($this->_params);
- $this->assertDBRowExist('CRM_Member_DAO_Membership', $membershipID);
$ContributionCreate = $this->callAPISuccess('Contribution', 'create', [
- 'financial_type_id' => "Member Dues",
+ 'financial_type_id' => 'Member Dues',
'total_amount' => 100,
'contact_id' => $this->_params['contact_id'],
]);
- $membershipPaymentCreate = $this->callAPISuccess('MembershipPayment', 'create', [
+ $this->callAPISuccess('MembershipPayment', 'create', [
'sequential' => 1,
'contribution_id' => $ContributionCreate['id'],
'membership_id' => $membershipID,
]);
- $instruments = $this->callAPISuccess('contribution', 'getoptions', ['field' => 'payment_instrument_id']);
- $this->paymentInstruments = $instruments['values'];
$form = new CRM_Contribute_Form_Contribution();
$form->_id = $ContributionCreate['id'];
'total_amount' => 100,
'financial_type_id' => 1,
'contact_id' => $contactId,
- 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
+ 'payment_instrument_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Check'),
'contribution_status_id' => 3,
],
CRM_Core_Action::UPDATE);
- $activity = $this->callAPISuccess('Activity', 'get', [
- 'activity_type_id' => "Change Membership Status",
+ $this->callAPISuccessGetSingle('Activity', [
+ 'activity_type_id' => 'Membership Signup',
+ 'source_record_id' => $membershipID,
+ 'subject' => 'General - Payment - Status: test status',
+ ]);
+ $this->callAPISuccessGetSingle('Activity', [
+ 'activity_type_id' => 'Change Membership Status',
'source_record_id' => $membershipID,
]);
- $this->assertNotEmpty($activity['values']);
}
/**
}
/**
- * Test create payment api for pay later contribution with partial payment.
+ * Test create payment api for failed contribution.
*
* @throws \CRM_Core_Exception
*/
- public function testCreatePaymentPayLaterPartialPayment() {
+ public function testCreatePaymentOnFailedContribution() {
$this->createLoggedInUser();
+ //Create a direct Failed Contribution (no ft record inserted).
+ $contributionParams = [
+ 'total_amount' => 50,
+ 'currency' => 'USD',
+ 'contact_id' => $this->_individualId,
+ 'financial_type_id' => 1,
+ 'contribution_status_id' => 'Failed',
+ ];
+ $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams);
+
+ //Complete the payment in a single call.
+ $params = [
+ 'contribution_id' => $contribution['id'],
+ 'total_amount' => 50,
+ ];
+ $payment = $this->callAPISuccess('Payment', 'create', $params);
+
+ //Verify 2 rows are added to the financial trxn as payment is moved from
+ //Failed -> Pending -> Completed, i.e, 0 -> 7(Account receivable) -> 6 (Deposit Bank).
+ $params = [
+ 'entity_id' => $contribution['id'],
+ 'entity_table' => 'civicrm_contribution',
+ ];
+ $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
+ $this->assertEquals($eft['count'], 2);
+
+ //Test 2
+ //Create a Pending Contribution so an FT record is inserted.
$contributionParams = [
'total_amount' => 100,
'currency' => 'USD',
'contact_id' => $this->_individualId,
'financial_type_id' => 1,
- 'contribution_status_id' => 2,
+ 'contribution_status_id' => 'Pending',
'is_pay_later' => 1,
];
$contribution = $this->callAPISuccess('Order', 'create', $contributionParams);
- //Create partial payment
+
+ //Mark it as failed. No FT record inserted on this update
+ //so the payment is still in the account receivable account id 7.
+ $this->callAPISuccess('Contribution', 'create', [
+ 'id' => $contribution['id'],
+ 'contribution_status_id' => 'Failed',
+ ]);
+ $this->createPartialPaymentOnContribution($contribution['id'], 60, 100.00);
+
+ //Call payment create on the failed contribution.
$params = [
'contribution_id' => $contribution['id'],
- 'total_amount' => 60,
+ 'total_amount' => 40,
];
$payment = $this->callAPISuccess('Payment', 'create', $params);
$expectedResult = [
$payment['id'] => [
- 'total_amount' => 60,
+ 'from_financial_account_id' => 7,
+ 'to_financial_account_id' => 6,
+ 'total_amount' => 40,
'status_id' => 1,
'is_payment' => 1,
],
];
$this->checkPaymentResult($payment, $expectedResult);
- // Check entity financial trxn created properly
+
+ //Check total ft rows are 4: 2 from initial pending + partial payment
+ //+ 2 for failed -> completed transition.
$params = [
'entity_id' => $contribution['id'],
'entity_table' => 'civicrm_contribution',
+ ];
+ $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
+ $this->assertEquals($eft['count'], 4);
+
+ $this->validateAllPayments();
+ }
+
+ /**
+ * Create partial payment for contribution
+ *
+ * @param $contributionID
+ * @param $partialAmount
+ * @param $totalAmount
+ */
+ public function createPartialPaymentOnContribution($contributionID, $partialAmount, $totalAmount) {
+ //Create partial payment
+ $params = [
+ 'contribution_id' => $contributionID,
+ 'total_amount' => $partialAmount,
+ ];
+ $payment = $this->callAPISuccess('Payment', 'create', $params);
+ $expectedResult = [
+ $payment['id'] => [
+ 'total_amount' => $partialAmount,
+ 'status_id' => 1,
+ 'is_payment' => 1,
+ ],
+ ];
+ $this->checkPaymentResult($payment, $expectedResult);
+ // Check entity financial trxn created properly
+ $params = [
+ 'entity_id' => $contributionID,
+ 'entity_table' => 'civicrm_contribution',
'financial_trxn_id' => $payment['id'],
];
$eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
- $this->assertEquals($eft['values'][$eft['id']]['amount'], 60);
+ $this->assertEquals($eft['values'][$eft['id']]['amount'], $partialAmount);
$params = [
'entity_table' => 'civicrm_financial_item',
'financial_trxn_id' => $payment['id'],
];
$eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
- $this->assertEquals($eft['values'][$eft['id']]['amount'], 60);
- $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]);
+ $this->assertEquals($eft['values'][$eft['id']]['amount'], $partialAmount);
+ $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contributionID]);
$this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Partially paid');
- $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00);
+ $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], $totalAmount);
+ }
+
+ /**
+ * Test create payment api for pay later contribution with partial payment.
+ *
+ * @throws \CRM_Core_Exception
+ */
+ public function testCreatePaymentPayLaterPartialPayment() {
+ $this->createLoggedInUser();
+ $contributionParams = [
+ 'total_amount' => 100,
+ 'currency' => 'USD',
+ 'contact_id' => $this->_individualId,
+ 'financial_type_id' => 1,
+ 'contribution_status_id' => 2,
+ 'is_pay_later' => 1,
+ ];
+ $contribution = $this->callAPISuccess('Order', 'create', $contributionParams);
+ $this->createPartialPaymentOnContribution($contribution['id'], 60, 100.00);
+
//Create full payment
$params = [
'contribution_id' => $contribution['id'],
$this->assertEquals($trxnID, $contribution['trxn_id'],
"Contribution trxn_id should have been set to that of the payment.");
- // change $trxnDate for $receiveDate if we agree that transactions should NOT
- // update contributions.
- $this->assertEquals($trxnDate, $contribution['receive_date'],
+ $this->assertEquals($originalReceiveDate, $contribution['receive_date'],
"Contribution receive date was changed, but should not have been.");
$this->validateAllPayments();
--- /dev/null
+<?php
+
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved. |
+ | |
+ | This work is published under the GNU AGPLv3 license with some |
+ | permitted exceptions and without any warranty. For full license |
+ | and copyright information, see https://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC https://civicrm.org/licensing
+ */
+
+
+namespace api\v4\Entity;
+
+use Civi\Api4\Setting;
+use Civi\Api4\StatusPreference;
+use Civi\Api4\System;
+use api\v4\UnitTestCase;
+
+/**
+ * @group headless
+ */
+class SystemTest extends UnitTestCase {
+
+ public function testSystemCheck() {
+ $origEnv = \CRM_Core_Config::environment();
+ $hooks = \CRM_Utils_Hook::singleton();
+ $hooks->setHook('civicrm_check', [$this, 'hook_civicrm_check']);
+
+ // Test on non-prod site
+ Setting::set()->addValue('environment', 'Development')->setCheckPermissions(FALSE)->execute();
+
+ StatusPreference::delete()->setCheckPermissions(FALSE)->addWhere('name', '=', 'checkLastCron')->execute();
+
+ // Won't run on non-prod site without $includeDisabled
+ $check = System::check()->addWhere('name', '=', 'checkLastCron')->execute();
+ // Will have skipped our hook because name matched a core check
+ $this->assertCount(0, $check);
+
+ // This should only run the php check
+ $check = System::check()->addWhere('name', '=', 'checkPhpVersion')->setIncludeDisabled(TRUE)->execute();
+ // Hook should have been skipped because name clause was fulfilled
+ $this->assertCount(1, $check);
+
+ // Ensure cron check has not run
+ $this->assertCount(0, StatusPreference::get()->setCheckPermissions(FALSE)->addWhere('name', '=', 'checkLastCron')->execute());
+
+ // Will run on non-prod site with $includeDisabled.
+ // Giving a more-specific name will run all checks with less-specific names too
+ $check = System::check()->addWhere('name', '=', 'checkLastCronAbc')->setIncludeDisabled(TRUE)->execute()->indexBy('name');
+ // Will have run our hook too because name wasn't an exact match
+ $this->assertCount(2, $check);
+ $this->assertEquals('Ok', $check['hook_civicrm_check']['title']);
+
+ // We know the cron check has run because it would have left a record marked 'new'
+ $record = StatusPreference::get()->setCheckPermissions(FALSE)->addWhere('name', '=', 'checkLastCron')->execute()->first();
+ $this->assertEquals('new', $record['prefs']);
+
+ // Restore env
+ Setting::set()->addValue('environment', $origEnv)->setCheckPermissions(FALSE)->execute();
+ $hooks->reset();
+ }
+
+ public function hook_civicrm_check(&$messages, $statusNames, $includeDisabled) {
+ $messages[] = new \CRM_Utils_Check_Message(
+ __FUNCTION__,
+ 'Hook running',
+ 'Ok',
+ \Psr\Log\LogLevel::DEBUG
+ );
+ }
+
+}
{ldelim}domain.address{rdelim}{/ts}',1,1),
('{ts escape="sql"}Subscribe Message{/ts}','Subscribe','{ts escape="sql"}Subscription Confirmation Request{/ts}','{ts escape="sql" 1=$subgroup 2=$suburl}You have a pending subscription to the %1 mailing list. To confirm this subscription, reply to this email or click <a href="%2">here</a>.{/ts}','{ts escape="sql" 1=$subgroup 2=$suburl}You have a pending subscription to the %1 mailing list. To confirm this subscription, reply to this email or click on this link: %2{/ts}',1,1),
('{ts escape="sql"}Welcome Message{/ts}','Welcome','{ts escape="sql"}Your Subscription has been Activated{/ts}','{ts escape="sql" 1=$welgroup}Welcome. Your subscription to the %1 mailing list has been activated.{/ts}','{ts escape="sql" 1=$welgroup}Welcome. Your subscription to the %1 mailing list has been activated.{/ts}',1,1),
- ('{ts escape="sql"}Unsubscribe Message{/ts}','Unsubscribe','{ts escape="sql"}Un-subscribe Confirmation{/ts}','{ts escape="sql" 1=$unsubgroup 2=$actresub 3=$actresuburl}You have been un-subscribed from the following groups: %1. You can re-subscribe by mailing %2 or clicking <a href="%3">here</a>.{/ts}','{ts escape="sql" 1=$unsubgroup 2=$actresub}You have been un-subscribed from the following groups: %1. You can re-subscribe by mailing %2 or clicking %3{/ts}',1,1),
+ ('{ts escape="sql"}Unsubscribe Message{/ts}','Unsubscribe','{ts escape="sql"}Un-subscribe Confirmation{/ts}','{ts escape="sql" 1=$unsubgroup 2=$actresub 3=$actresuburl}You have been un-subscribed from the following groups: %1. You can re-subscribe by mailing %2 or clicking <a href="%3">here</a>.{/ts}','{ts escape="sql" 1=$unsubgroup 2=$actresub 3=$actresuburl}You have been un-subscribed from the following groups: %1. You can re-subscribe by mailing %2 or clicking %3{/ts}',1,1),
('{ts escape="sql"}Resubscribe Message{/ts}','Resubscribe','{ts escape="sql"}Re-subscribe Confirmation{/ts}','{ts escape="sql" 1=$resubgroup 2=$actunsub 3=$actunsuburl}You have been re-subscribed to the following groups: %1. You can un-subscribe by mailing %2 or clicking <a href="%3">here</a>.{/ts}','{ts escape="sql" 1=$resubgroup 2=$actunsub 3=$actunsuburl}You have been re-subscribed to the following groups: %1. You can un-subscribe by mailing %2 or clicking %3{/ts}',1,1),
('{ts escape="sql"}Opt-out Message{/ts}','OptOut','{ts escape="sql"}Opt-out Confirmation{/ts}','{ts escape="sql" 1=$domname}Your email address has been removed from %1 mailing lists.{/ts}','{ts escape="sql" 1=$domname}Your email address has been removed from %1 mailing lists.{/ts}',1,1),
('{ts escape="sql"}Auto-responder{/ts}','Reply','{ts escape="sql"}Please Send Inquiries to Our Contact Email Address{/ts}','{ts escape="sql"}This is an automated reply from an un-attended mailbox. Please send any inquiries to the contact email address listed on our web-site.{/ts}','{ts escape="sql"}This is an automated reply from an un-attended mailbox. Please send any inquiries to the contact email address listed on our web-site.{/ts}',1,1);