Merge pull request #13783 from eileenmcnaughton/confirm_btn
[civicrm-core.git] / CRM / Member / ActionMapping.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 use Civi\ActionSchedule\RecipientBuilder;
29
30 /**
31 * Class CRM_Member_ActionMapping
32 *
33 * This defines the scheduled-reminder functionality for CiviMember
34 * memberships. It allows one to target reminders based on join date
35 * or end date, with additional filtering based on membership-type.
36 */
37 class CRM_Member_ActionMapping extends \Civi\ActionSchedule\Mapping {
38
39 /**
40 * The value for civicrm_action_schedule.mapping_id which identifies the
41 * "Membership Type" mapping.
42 *
43 * Note: This value is chosen to match legacy DB IDs.
44 */
45 const MEMBERSHIP_TYPE_MAPPING_ID = 4;
46
47 /**
48 * Register CiviMember-related action mappings.
49 *
50 * @param \Civi\ActionSchedule\Event\MappingRegisterEvent $registrations
51 */
52 public static function onRegisterActionMappings(\Civi\ActionSchedule\Event\MappingRegisterEvent $registrations) {
53 $registrations->register(CRM_Member_ActionMapping::create(array(
54 'id' => CRM_Member_ActionMapping::MEMBERSHIP_TYPE_MAPPING_ID,
55 'entity' => 'civicrm_membership',
56 'entity_label' => ts('Membership'),
57 'entity_value' => 'civicrm_membership_type',
58 'entity_value_label' => ts('Membership Type'),
59 'entity_status' => 'auto_renew_options',
60 'entity_status_label' => ts('Auto Renew Options'),
61 )));
62 }
63
64 /**
65 * Get a list of available date fields.
66 *
67 * @return array
68 * Array(string $fieldName => string $fieldLabel).
69 */
70 public function getDateFields() {
71 return array(
72 'join_date' => ts('Membership Join Date'),
73 'start_date' => ts('Membership Start Date'),
74 'end_date' => ts('Membership End Date'),
75 );
76 }
77
78 /**
79 * Generate a query to locate recipients who match the given
80 * schedule.
81 *
82 * @param \CRM_Core_DAO_ActionSchedule $schedule
83 * The schedule as configured by the administrator.
84 * @param string $phase
85 * See, e.g., RecipientBuilder::PHASE_RELATION_FIRST.
86 * @param array $defaultParams
87 *
88 * @return \CRM_Utils_SQL_Select
89 * @see RecipientBuilder
90 */
91 public function createQuery($schedule, $phase, $defaultParams) {
92 $selectedValues = (array) \CRM_Utils_Array::explodePadded($schedule->entity_value);
93 $selectedStatuses = (array) \CRM_Utils_Array::explodePadded($schedule->entity_status);
94
95 $query = \CRM_Utils_SQL_Select::from("{$this->entity} e")->param($defaultParams);
96 $query['casAddlCheckFrom'] = 'civicrm_membership e';
97 $query['casContactIdField'] = 'e.contact_id';
98 $query['casEntityIdField'] = 'e.id';
99 $query['casContactTableAlias'] = NULL;
100
101 // Leaving this in case of legacy databases
102 $query['casDateField'] = str_replace('membership_', 'e.', $schedule->start_action_date);
103
104 // Options currently are just 'join_date', 'start_date', and 'end_date':
105 // they need an alias
106 if (strpos($query['casDateField'], 'e.') !== 0) {
107 $query['casDateField'] = 'e.' . $query['casDateField'];
108 }
109
110 // FIXME: Numbers should be constants.
111 if (in_array(2, $selectedStatuses)) {
112 //auto-renew memberships
113 $query->where("e.contribution_recur_id IS NOT NULL");
114 }
115 elseif (in_array(1, $selectedStatuses)) {
116 $query->where("e.contribution_recur_id IS NULL");
117 }
118
119 if (!empty($selectedValues)) {
120 $query->where("e.membership_type_id IN (@memberTypeValues)")
121 ->param('memberTypeValues', $selectedValues);
122 }
123 else {
124 // FIXME: The membership type is never null, so nobody will ever get a
125 // reminder if no membership types are selected. Either this should be a
126 // validation on the reminder form or all types should get a reminder if
127 // no types are selected.
128 $query->where("e.membership_type_id IS NULL");
129 }
130
131 // FIXME: This makes a lot of sense for renewal reminders, but a user
132 // scheduling another kind of reminder might not expect members to be
133 // excluded if they have status overrides. Ideally there would be some kind
134 // of setting per reminder.
135 $query->where("( e.is_override IS NULL OR e.is_override = 0 )");
136
137 // FIXME: Similarly to overrides, excluding contacts who can't edit the
138 // primary member makes sense in the context of renewals (see CRM-11342) but
139 // would be a surprise for other use cases.
140 $query->merge($this->prepareMembershipPermissionsFilter());
141
142 // FIXME: A lot of undocumented stuff happens with regard to
143 // `is_current_member`, and this is no exception. Ideally there would be an
144 // opportunity to pick statuses when setting up the scheduled reminder
145 // rather than making the assumptions here.
146 $query->where("e.status_id IN (#memberStatus)")
147 ->param('memberStatus', \CRM_Member_PseudoConstant::membershipStatus(NULL, "(is_current_member = 1 OR name = 'Expired')", 'id'));
148
149 // Why is this only for civicrm_membership?
150 if ($schedule->start_action_date && $schedule->is_repeat == FALSE) {
151 $query['casUseReferenceDate'] = TRUE;
152 }
153
154 return $query;
155 }
156
157 /**
158 * Filter out the memberships that are inherited from a contact that the
159 * recipient cannot edit.
160 *
161 * @return CRM_Utils_SQL_Select
162 */
163 protected function prepareMembershipPermissionsFilter() {
164 $joins = [
165 'cm' => 'LEFT JOIN civicrm_membership cm ON cm.id = e.owner_membership_id',
166 'rela' => 'LEFT JOIN civicrm_relationship rela ON rela.contact_id_a = e.contact_id AND rela.contact_id_b = cm.contact_id AND rela.is_permission_a_b = #editPerm',
167 'relb' => 'LEFT JOIN civicrm_relationship relb ON relb.contact_id_a = cm.contact_id AND relb.contact_id_b = e.contact_id AND relb.is_permission_b_a = #editPerm',
168 ];
169
170 return \CRM_Utils_SQL_Select::fragment()
171 ->join(NULL, $joins)
172 ->param('#editPerm', CRM_Contact_BAO_Relationship::EDIT)
173 ->where('!( e.owner_membership_id IS NOT NULL AND rela.id IS NULL and relb.id IS NULL )');
174 }
175
176 }