Commit | Line | Data |
---|---|---|
0775436c TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
0775436c | 5 | | | |
bc77d7c0 TO |
6 | | This work is published under the GNU AGPLv3 license with some | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
0775436c | 9 | +--------------------------------------------------------------------+ |
d25dd0ee | 10 | */ |
0775436c TO |
11 | |
12 | /** | |
13 | * | |
14 | * @package CRM | |
ca5cec67 | 15 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
0775436c TO |
16 | */ |
17 | ||
2ba9aad6 | 18 | use When\When; |
0775436c | 19 | |
1cd3ffa9 | 20 | /** |
8eedd10a | 21 | * Class CRM_Core_BAO_RecurringEntity. |
1cd3ffa9 | 22 | */ |
0775436c TO |
23 | class CRM_Core_BAO_RecurringEntity extends CRM_Core_DAO_RecurringEntity { |
24 | ||
25 | const RUNNING = 1; | |
be2fb01f | 26 | public $schedule = []; |
0775436c | 27 | public $scheduleId = NULL; |
be2fb01f | 28 | public $scheduleFormValues = []; |
0775436c | 29 | |
be2fb01f CW |
30 | public $dateColumns = []; |
31 | public $overwriteColumns = []; | |
32 | public $intervalDateColumns = []; | |
33 | public $excludeDates = []; | |
0775436c | 34 | |
be2fb01f | 35 | public $linkedEntities = []; |
0775436c TO |
36 | |
37 | public $isRecurringEntityRecord = TRUE; | |
38 | ||
39 | protected $recursion = NULL; | |
40 | protected $recursion_start_date = NULL; | |
41 | ||
be2fb01f | 42 | public static $_entitiesToBeDeleted = []; |
0775436c TO |
43 | |
44 | public static $status = NULL; | |
45 | ||
518fa0ee | 46 | public static $_recurringEntityHelper |
be2fb01f CW |
47 | = [ |
48 | 'civicrm_event' => [ | |
0775436c TO |
49 | 'helper_class' => 'CRM_Event_DAO_Event', |
50 | 'delete_func' => 'delete', | |
e7483cbe | 51 | 'pre_delete_func' => 'CRM_Event_Form_ManageEvent_Repeat::checkRegistrationForEvents', |
be2fb01f CW |
52 | ], |
53 | 'civicrm_activity' => [ | |
0775436c TO |
54 | 'helper_class' => 'CRM_Activity_DAO_Activity', |
55 | 'delete_func' => 'delete', | |
e7483cbe | 56 | 'pre_delete_func' => '', |
be2fb01f CW |
57 | ], |
58 | ]; | |
0775436c | 59 | |
518fa0ee | 60 | public static $_dateColumns |
be2fb01f CW |
61 | = [ |
62 | 'civicrm_event' => [ | |
63 | 'dateColumns' => ['start_date'], | |
64 | 'excludeDateRangeColumns' => ['start_date', 'end_date'], | |
65 | 'intervalDateColumns' => ['end_date'], | |
66 | ], | |
67 | 'civicrm_activity' => [ | |
68 | 'dateColumns' => ['activity_date_time'], | |
69 | ], | |
70 | ]; | |
0775436c | 71 | |
518fa0ee | 72 | public static $_tableDAOMapper |
be2fb01f | 73 | = [ |
353ffa53 | 74 | 'civicrm_event' => 'CRM_Event_DAO_Event', |
0775436c | 75 | 'civicrm_price_set_entity' => 'CRM_Price_DAO_PriceSetEntity', |
353ffa53 | 76 | 'civicrm_uf_join' => 'CRM_Core_DAO_UFJoin', |
0775436c | 77 | 'civicrm_tell_friend' => 'CRM_Friend_DAO_Friend', |
353ffa53 TO |
78 | 'civicrm_pcp_block' => 'CRM_PCP_DAO_PCPBlock', |
79 | 'civicrm_activity' => 'CRM_Activity_DAO_Activity', | |
80 | 'civicrm_activity_contact' => 'CRM_Activity_DAO_ActivityContact', | |
be2fb01f | 81 | ]; |
0775436c | 82 | |
518fa0ee | 83 | public static $_updateSkipFields |
be2fb01f CW |
84 | = [ |
85 | 'civicrm_event' => ['start_date', 'end_date'], | |
86 | 'civicrm_tell_friend' => ['entity_id'], | |
87 | 'civicrm_pcp_block' => ['entity_id'], | |
88 | 'civicrm_activity' => ['activity_date_time'], | |
89 | ]; | |
0775436c | 90 | |
518fa0ee | 91 | public static $_linkedEntitiesInfo |
be2fb01f CW |
92 | = [ |
93 | 'civicrm_tell_friend' => [ | |
353ffa53 | 94 | 'entity_id_col' => 'entity_id', |
e7483cbe | 95 | 'entity_table_col' => 'entity_table', |
be2fb01f CW |
96 | ], |
97 | 'civicrm_price_set_entity' => [ | |
353ffa53 | 98 | 'entity_id_col' => 'entity_id', |
0775436c | 99 | 'entity_table_col' => 'entity_table', |
353ffa53 | 100 | 'is_multirecord' => TRUE, |
be2fb01f CW |
101 | ], |
102 | 'civicrm_uf_join' => [ | |
353ffa53 | 103 | 'entity_id_col' => 'entity_id', |
0775436c | 104 | 'entity_table_col' => 'entity_table', |
353ffa53 | 105 | 'is_multirecord' => TRUE, |
be2fb01f CW |
106 | ], |
107 | 'civicrm_pcp_block' => [ | |
353ffa53 | 108 | 'entity_id_col' => 'entity_id', |
e7483cbe | 109 | 'entity_table_col' => 'entity_table', |
be2fb01f CW |
110 | ], |
111 | ]; | |
0775436c | 112 | |
b0f2e06f RJ |
113 | //Define global CLASS CONSTANTS for recurring entity mode types |
114 | const MODE_THIS_ENTITY_ONLY = 1; | |
115 | const MODE_NEXT_ALL_ENTITY = 2; | |
116 | const MODE_ALL_ENTITY_IN_SERIES = 3; | |
117 | ||
2e2605fe EM |
118 | /** |
119 | * Getter for status. | |
120 | * | |
121 | * @return string | |
122 | */ | |
0775436c TO |
123 | public static function getStatus() { |
124 | return self::$status; | |
125 | } | |
126 | ||
2e2605fe EM |
127 | /** |
128 | * Setter for status. | |
129 | * | |
130 | * @param string $status | |
131 | */ | |
0775436c TO |
132 | public static function setStatus($status) { |
133 | self::$status = $status; | |
134 | } | |
353ffa53 | 135 | |
0775436c | 136 | /** |
2e2605fe | 137 | * Save records in civicrm_recurring_entity table. |
0775436c | 138 | * |
6a0b768e | 139 | * @param array $params |
2e2605fe | 140 | * Reference array contains the values submitted by the form. |
0775436c TO |
141 | * |
142 | * @return object | |
143 | */ | |
144 | public static function add(&$params) { | |
b53cbfbc | 145 | if (!empty($params['id'])) { |
0775436c TO |
146 | CRM_Utils_Hook::pre('edit', 'RecurringEntity', $params['id'], $params); |
147 | } | |
148 | else { | |
149 | CRM_Utils_Hook::pre('create', 'RecurringEntity', NULL, $params); | |
150 | } | |
151 | ||
152 | $daoRecurringEntity = new CRM_Core_DAO_RecurringEntity(); | |
153 | $daoRecurringEntity->copyValues($params); | |
154 | $daoRecurringEntity->find(TRUE); | |
155 | $result = $daoRecurringEntity->save(); | |
156 | ||
b53cbfbc | 157 | if (!empty($params['id'])) { |
0775436c TO |
158 | CRM_Utils_Hook::post('edit', 'RecurringEntity', $daoRecurringEntity->id, $daoRecurringEntity); |
159 | } | |
160 | else { | |
161 | CRM_Utils_Hook::post('create', 'RecurringEntity', $daoRecurringEntity->id, $daoRecurringEntity); | |
162 | } | |
163 | return $result; | |
164 | } | |
165 | ||
166 | /** | |
167 | * Wrapper for the function add() to add entry in recurring entity | |
168 | * | |
6a0b768e TO |
169 | * @param int $parentId |
170 | * Parent entity id . | |
171 | * @param int $entityId | |
172 | * Child entity id . | |
173 | * @param string $entityTable | |
174 | * Name of the entity table . | |
0775436c | 175 | * |
0775436c TO |
176 | * |
177 | * @return object | |
178 | */ | |
179 | public static function quickAdd($parentId, $entityId, $entityTable) { | |
e7483cbe | 180 | $params |
be2fb01f | 181 | = [ |
353ffa53 TO |
182 | 'parent_id' => $parentId, |
183 | 'entity_id' => $entityId, | |
e7483cbe | 184 | 'entity_table' => $entityTable, |
be2fb01f | 185 | ]; |
0775436c TO |
186 | return self::add($params); |
187 | } | |
188 | ||
189 | /** | |
fe482240 | 190 | * This function updates the mode column in the civicrm_recurring_entity table. |
0775436c | 191 | * |
6a0b768e | 192 | * @param int $mode |
8eedd10a | 193 | * Mode of the entity to cascade changes across parent/child relations eg 1 - only this entity, 2 - this and the following entities, 3 - All the entity. |
0775436c TO |
194 | */ |
195 | public function mode($mode) { | |
196 | if ($this->entity_id && $this->entity_table) { | |
197 | if ($this->find(TRUE)) { | |
198 | $this->mode = $mode; | |
199 | } | |
200 | else { | |
201 | $this->parent_id = $this->entity_id; | |
202 | $this->mode = $mode; | |
203 | } | |
204 | $this->save(); | |
205 | } | |
206 | } | |
207 | ||
208 | /** | |
fe482240 | 209 | * This function generates all new entities based on object vars. |
0775436c TO |
210 | * |
211 | * @return array | |
212 | */ | |
213 | public function generate() { | |
214 | $this->generateRecursiveDates(); | |
215 | ||
216 | return $this->generateEntities(); | |
217 | } | |
218 | ||
219 | /** | |
220 | * This function builds a "When" object based on schedule/reminder params | |
221 | * | |
a6c01b45 CW |
222 | * @return object |
223 | * When object | |
0775436c TO |
224 | */ |
225 | public function generateRecursion() { | |
226 | // return if already generated | |
30aa3e54 | 227 | if (is_a($this->recursion, 'When\When')) { |
0775436c TO |
228 | return $this->recursion; |
229 | } | |
230 | ||
231 | if ($this->scheduleId) { | |
232 | // get params by ID | |
233 | $this->schedule = $this->getScheduleParams($this->scheduleId); | |
234 | } | |
235 | elseif (!empty($this->scheduleFormValues)) { | |
236 | $this->schedule = $this->mapFormValuesToDB($this->scheduleFormValues); | |
237 | } | |
238 | ||
239 | if (!empty($this->schedule)) { | |
240 | $this->recursion = $this->getRecursionFromSchedule($this->schedule); | |
241 | } | |
242 | return $this->recursion; | |
243 | } | |
244 | ||
245 | /** | |
fe482240 | 246 | * Generate new DAOs and along with entries in civicrm_recurring_entity table. |
0775436c TO |
247 | * |
248 | * @return array | |
249 | */ | |
250 | public function generateEntities() { | |
251 | self::setStatus(self::RUNNING); | |
252 | ||
be2fb01f CW |
253 | $newEntities = []; |
254 | $findCriteria = []; | |
0775436c TO |
255 | if (!empty($this->recursionDates)) { |
256 | if ($this->entity_id) { | |
be2fb01f | 257 | $findCriteria = ['id' => $this->entity_id]; |
0775436c TO |
258 | |
259 | // save an entry with initiating entity-id & entity-table | |
260 | if ($this->entity_table && !$this->find(TRUE)) { | |
261 | $this->parent_id = $this->entity_id; | |
262 | $this->save(); | |
263 | } | |
264 | } | |
265 | if (empty($findCriteria)) { | |
266 | CRM_Core_Error::fatal("Find criteria missing to generate form. Make sure entity_id and table is set."); | |
267 | } | |
268 | ||
269 | $count = 0; | |
270 | foreach ($this->recursionDates as $key => $dateCols) { | |
271 | $newCriteria = $dateCols; | |
272 | foreach ($this->overwriteColumns as $col => $val) { | |
273 | $newCriteria[$col] = $val; | |
274 | } | |
275 | // create main entities | |
276 | $obj = CRM_Core_BAO_RecurringEntity::copyCreateEntity($this->entity_table, | |
277 | $findCriteria, | |
278 | $newCriteria, | |
279 | $this->isRecurringEntityRecord | |
280 | ); | |
281 | ||
282 | if (is_a($obj, 'CRM_Core_DAO') && $obj->id) { | |
be2fb01f | 283 | $newCriteria = []; |
0775436c TO |
284 | $newEntities[$this->entity_table][$count] = $obj->id; |
285 | ||
286 | foreach ($this->linkedEntities as $linkedInfo) { | |
287 | foreach ($linkedInfo['linkedColumns'] as $col) { | |
288 | $newCriteria[$col] = $obj->id; | |
289 | } | |
290 | // create linked entities | |
291 | $linkedObj = CRM_Core_BAO_RecurringEntity::copyCreateEntity($linkedInfo['table'], | |
292 | $linkedInfo['findCriteria'], | |
293 | $newCriteria, | |
294 | CRM_Utils_Array::value('isRecurringEntityRecord', $linkedInfo, TRUE) | |
295 | ); | |
296 | ||
297 | if (is_a($linkedObj, 'CRM_Core_DAO') && $linkedObj->id) { | |
298 | $newEntities[$linkedInfo['table']][$count] = $linkedObj->id; | |
299 | } | |
300 | } | |
301 | } | |
302 | $count++; | |
303 | } | |
304 | } | |
305 | ||
306 | self::$status = NULL; | |
307 | return $newEntities; | |
308 | } | |
309 | ||
310 | /** | |
b44e3f84 | 311 | * This function iterates through when object criteria and |
0775436c TO |
312 | * generates recursive dates based on that |
313 | * | |
a6c01b45 CW |
314 | * @return array |
315 | * array of dates | |
0775436c TO |
316 | */ |
317 | public function generateRecursiveDates() { | |
318 | $this->generateRecursion(); | |
319 | ||
be2fb01f | 320 | $recursionDates = []; |
2ba9aad6 | 321 | if (is_a($this->recursion, 'When\When')) { |
0775436c TO |
322 | $initialCount = CRM_Utils_Array::value('start_action_offset', $this->schedule); |
323 | ||
324 | $exRangeStart = $exRangeEnd = NULL; | |
325 | if (!empty($this->excludeDateRangeColumns)) { | |
326 | $exRangeStart = $this->excludeDateRangeColumns[0]; | |
353ffa53 | 327 | $exRangeEnd = $this->excludeDateRangeColumns[1]; |
0775436c TO |
328 | } |
329 | ||
30aa3e54 PZ |
330 | if (CRM_Core_Config::singleton()->userFramework == 'UnitTests') { |
331 | $this->recursion->RFC5545_COMPLIANT = When::IGNORE; | |
332 | } | |
0775436c | 333 | $count = 1; |
30aa3e54 PZ |
334 | $result = $this->recursion_start_date; |
335 | while ($result = $this->getNextOccurrence($result)) { | |
336 | $skip = FALSE; | |
337 | if ($result == $this->recursion_start_date) { | |
338 | // skip the recursion-start-date from the list we going to generate | |
339 | $skip = TRUE; | |
5e73744d | 340 | } |
1043bac2 | 341 | $baseDate = $result->format('YmdHis'); |
0775436c TO |
342 | |
343 | foreach ($this->dateColumns as $col) { | |
344 | $recursionDates[$count][$col] = $baseDate; | |
345 | } | |
346 | foreach ($this->intervalDateColumns as $col => $interval) { | |
347 | $newDate = new DateTime($baseDate); | |
348 | $newDate->add($interval); | |
1043bac2 | 349 | $recursionDates[$count][$col] = $newDate->format('YmdHis'); |
0775436c TO |
350 | } |
351 | if ($exRangeStart) { | |
3b39fda2 CW |
352 | $exRangeStartDate = CRM_Utils_Date::processDate(CRM_Utils_Array::value($exRangeStart, $recursionDates[$count]), NULL, FALSE, 'Ymd'); |
353 | $exRangeEndDate = CRM_Utils_Date::processDate(CRM_Utils_Array::value($exRangeEnd, $recursionDates[$count]), NULL, FALSE, 'Ymd'); | |
0775436c TO |
354 | } |
355 | ||
356 | foreach ($this->excludeDates as $exDate) { | |
357 | $exDate = CRM_Utils_Date::processDate($exDate, NULL, FALSE, 'Ymd'); | |
358 | if (!$exRangeStart) { | |
359 | if ($exDate == $result->format('Ymd')) { | |
360 | $skip = TRUE; | |
361 | break; | |
362 | } | |
363 | } | |
364 | else { | |
365 | if (($exDate == $exRangeStartDate) || | |
366 | ($exRangeEndDate && ($exDate > $exRangeStartDate) && ($exDate <= $exRangeEndDate)) | |
367 | ) { | |
368 | $skip = TRUE; | |
369 | break; | |
370 | } | |
371 | } | |
372 | } | |
373 | ||
30aa3e54 PZ |
374 | if ($skip) { |
375 | unset($recursionDates[$count]); | |
376 | if ($initialCount && ($initialCount > 0)) { | |
377 | // lets increase the counter, so we get correct number of occurrences | |
378 | $initialCount++; | |
379 | $this->recursion->count($initialCount); | |
380 | } | |
381 | continue; | |
382 | } | |
0775436c TO |
383 | $count++; |
384 | } | |
385 | } | |
386 | $this->recursionDates = $recursionDates; | |
387 | ||
388 | return $recursionDates; | |
389 | } | |
390 | ||
391 | /** | |
fe482240 | 392 | * This function gets all the children for a particular parent entity. |
0775436c | 393 | * |
6a0b768e TO |
394 | * @param int $parentId |
395 | * Parent entity id . | |
396 | * @param string $entityTable | |
397 | * Name of the entity table . | |
398 | * @param bool $includeParent | |
399 | * If true parent id is included in result set and vice versa . | |
400 | * @param int $mode | |
401 | * 1. retrieve only one entity. 2. retrieve all future entities in the repeating set. 3. all entities in the repeating set. . | |
402 | * @param int $initiatorId | |
403 | * The instance where this function is invoked from . | |
0775436c | 404 | * |
0775436c | 405 | * |
a6c01b45 CW |
406 | * @return array |
407 | * an array of child ids | |
0775436c | 408 | */ |
518fa0ee | 409 | public static function getEntitiesForParent($parentId, $entityTable, $includeParent = TRUE, $mode = 3, $initiatorId = NULL) { |
be2fb01f | 410 | $entities = []; |
0775436c TO |
411 | if (empty($parentId) || empty($entityTable)) { |
412 | return $entities; | |
413 | } | |
414 | ||
415 | if (!$initiatorId) { | |
416 | $initiatorId = $parentId; | |
417 | } | |
418 | ||
be2fb01f CW |
419 | $queryParams = [ |
420 | 1 => [$parentId, 'Integer'], | |
421 | 2 => [$entityTable, 'String'], | |
422 | 3 => [$initiatorId, 'Integer'], | |
423 | ]; | |
0775436c TO |
424 | |
425 | if (!$mode) { | |
426 | $mode = CRM_Core_DAO::singleValueQuery("SELECT mode FROM civicrm_recurring_entity WHERE entity_id = %3 AND entity_table = %2", $queryParams); | |
427 | } | |
428 | ||
429 | $query = "SELECT * | |
430 | FROM civicrm_recurring_entity | |
431 | WHERE parent_id = %1 AND entity_table = %2"; | |
432 | if (!$includeParent) { | |
433 | $query .= " AND entity_id != " . ($initiatorId ? "%3" : "%1"); | |
434 | } | |
435 | ||
e7483cbe J |
436 | // MODE = SINGLE |
437 | if ($mode == '1') { | |
0775436c TO |
438 | $query .= " AND entity_id = %3"; |
439 | } | |
e7483cbe J |
440 | // MODE = FUTURE |
441 | elseif ($mode == '2') { | |
0775436c TO |
442 | $recurringEntityID = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_recurring_entity WHERE entity_id = %3 AND entity_table = %2", $queryParams); |
443 | if ($recurringEntityID) { | |
444 | $query .= $includeParent ? " AND id >= %4" : " AND id > %4"; | |
518fa0ee SL |
445 | // FIXME: change to order by dates |
446 | $query .= " ORDER BY id ASC"; | |
be2fb01f | 447 | $queryParams[4] = [$recurringEntityID, 'Integer']; |
0775436c TO |
448 | } |
449 | else { | |
450 | // something wrong, return empty | |
be2fb01f | 451 | return []; |
0775436c TO |
452 | } |
453 | } | |
454 | ||
455 | $dao = CRM_Core_DAO::executeQuery($query, $queryParams); | |
456 | while ($dao->fetch()) { | |
457 | $entities["{$dao->entity_table}_{$dao->entity_id}"]['table'] = $dao->entity_table; | |
458 | $entities["{$dao->entity_table}_{$dao->entity_id}"]['id'] = $dao->entity_id; | |
459 | } | |
460 | return $entities; | |
461 | } | |
462 | ||
463 | /** | |
464 | * This function when passed an entity id checks if it has parent and | |
465 | * returns all other entities that are connected to same parent. | |
466 | * | |
6a0b768e TO |
467 | * @param int $entityId |
468 | * Entity id . | |
469 | * @param string $entityTable | |
470 | * Entity table name . | |
471 | * @param bool $includeParent | |
472 | * Include parent in result set . | |
473 | * @param int $mode | |
474 | * 1. retrieve only one entity. 2. retrieve all future entities in the repeating set. 3. all entities in the repeating set. . | |
0775436c | 475 | * |
0775436c | 476 | * |
a6c01b45 CW |
477 | * @return array |
478 | * array of connected ids | |
0775436c | 479 | */ |
518fa0ee | 480 | public static function getEntitiesFor($entityId, $entityTable, $includeParent = TRUE, $mode = 3) { |
0775436c TO |
481 | $parentId = self::getParentFor($entityId, $entityTable); |
482 | if ($parentId) { | |
483 | return self::getEntitiesForParent($parentId, $entityTable, $includeParent, $mode, $entityId); | |
484 | } | |
be2fb01f | 485 | return []; |
0775436c TO |
486 | } |
487 | ||
488 | /** | |
fe482240 | 489 | * This function gets the parent for the entity id passed to it. |
0775436c | 490 | * |
6a0b768e TO |
491 | * @param int $entityId |
492 | * Entity ID . | |
493 | * @param string $entityTable | |
494 | * Entity table name . | |
495 | * @param bool $includeParent | |
496 | * Include parent in result set . | |
0775436c | 497 | * |
0775436c | 498 | * |
a6c01b45 CW |
499 | * @return int |
500 | * unsigned $parentId Parent ID | |
0775436c | 501 | */ |
518fa0ee | 502 | public static function getParentFor($entityId, $entityTable, $includeParent = TRUE) { |
0775436c TO |
503 | if (empty($entityId) || empty($entityTable)) { |
504 | return NULL; | |
505 | } | |
506 | ||
507 | $query = " | |
508 | SELECT parent_id | |
509 | FROM civicrm_recurring_entity | |
510 | WHERE entity_id = %1 AND entity_table = %2"; | |
511 | if (!$includeParent) { | |
512 | $query .= " AND parent_id != %1"; | |
513 | } | |
e7483cbe J |
514 | $parentId |
515 | = CRM_Core_DAO::singleValueQuery($query, | |
be2fb01f CW |
516 | [ |
517 | 1 => [$entityId, 'Integer'], | |
518 | 2 => [$entityTable, 'String'], | |
519 | ] | |
0775436c TO |
520 | ); |
521 | return $parentId; | |
522 | } | |
523 | ||
04374d9d CW |
524 | /** |
525 | * Finds the position of this entity as well as total count of the repeating set | |
526 | * | |
527 | * @param $entityId | |
528 | * @param $entityTable | |
529 | * @return array|null | |
530 | */ | |
518fa0ee | 531 | public static function getPositionAndCount($entityId, $entityTable) { |
04374d9d CW |
532 | $position = $count = 0; |
533 | ||
534 | $query = " | |
535 | SELECT entity_id | |
536 | FROM civicrm_recurring_entity | |
537 | WHERE parent_id = (SELECT parent_id FROM civicrm_recurring_entity WHERE entity_id = %1 AND entity_table = %2) AND entity_table = %2"; | |
538 | ||
539 | $dao = CRM_Core_DAO::executeQuery($query, | |
be2fb01f CW |
540 | [ |
541 | 1 => [$entityId, 'Integer'], | |
542 | 2 => [$entityTable, 'String'], | |
543 | ] | |
04374d9d CW |
544 | ); |
545 | ||
546 | while ($dao->fetch()) { | |
547 | ++$count; | |
548 | if ($dao->entity_id <= $entityId) { | |
549 | ++$position; | |
550 | } | |
551 | } | |
552 | if ($count) { | |
be2fb01f | 553 | return [$position, $count]; |
04374d9d CW |
554 | } |
555 | return NULL; | |
556 | } | |
557 | ||
0775436c | 558 | /** |
fe482240 | 559 | * This function copies the information from parent entity and creates other entities with same information. |
0775436c | 560 | * |
6a0b768e TO |
561 | * @param string $entityTable |
562 | * Entity table name . | |
563 | * @param array $fromCriteria | |
564 | * Array of all the fields & values on which basis to copy . | |
565 | * @param array $newParams | |
566 | * Array of all the fields & values to be copied besides the other fields . | |
567 | * @param bool $createRecurringEntity | |
568 | * If to create a record in recurring_entity table . | |
0775436c | 569 | * |
0775436c TO |
570 | * |
571 | * @return object | |
572 | */ | |
518fa0ee | 573 | public static function copyCreateEntity($entityTable, $fromCriteria, $newParams, $createRecurringEntity = TRUE) { |
0775436c TO |
574 | $daoName = self::$_tableDAOMapper[$entityTable]; |
575 | if (!$daoName) { | |
576 | CRM_Core_Error::fatal("DAO Mapper missing for $entityTable."); | |
577 | } | |
578 | $newObject = CRM_Core_DAO::copyGeneric($daoName, $fromCriteria, $newParams); | |
579 | ||
580 | if (is_a($newObject, 'CRM_Core_DAO') && $newObject->id && $createRecurringEntity) { | |
353ffa53 | 581 | $object = new $daoName(); |
0775436c TO |
582 | foreach ($fromCriteria as $key => $value) { |
583 | $object->$key = $value; | |
584 | } | |
585 | $object->find(TRUE); | |
586 | ||
587 | CRM_Core_BAO_RecurringEntity::quickAdd($object->id, $newObject->id, $entityTable); | |
588 | } | |
589 | return $newObject; | |
590 | } | |
591 | ||
592 | /** | |
8eedd10a | 593 | * This function acts as a listener to dao->update whenever there is an update. |
0775436c | 594 | * |
8eedd10a | 595 | * It propagates any changes to all related entities present in recurring entity table |
0775436c | 596 | * |
8eedd10a | 597 | * @param object $event |
598 | * An object of /Civi/Core/DAO/Event/PostUpdate containing dao object that was just updated. | |
0775436c | 599 | */ |
518fa0ee | 600 | public static function triggerUpdate($event) { |
0775436c TO |
601 | // if DB version is earlier than 4.6 skip any processing |
602 | static $currentVer = NULL; | |
603 | if (!$currentVer) { | |
604 | $currentVer = CRM_Core_BAO_Domain::version(); | |
605 | } | |
606 | if (version_compare($currentVer, '4.6.alpha1') < 0) { | |
607 | return; | |
608 | } | |
609 | ||
be2fb01f | 610 | static $processedEntities = []; |
0775436c TO |
611 | $obj =& $event->object; |
612 | if (empty($obj->id) || empty($obj->__table)) { | |
8eedd10a | 613 | return; |
0775436c TO |
614 | } |
615 | $key = "{$obj->__table}_{$obj->id}"; | |
616 | ||
617 | if (array_key_exists($key, $processedEntities)) { | |
618 | // already processed | |
8eedd10a | 619 | return; |
0775436c TO |
620 | } |
621 | ||
622 | // get related entities | |
623 | $repeatingEntities = self::getEntitiesFor($obj->id, $obj->__table, FALSE, NULL); | |
624 | if (empty($repeatingEntities)) { | |
625 | // return if its not a recurring entity parent | |
8eedd10a | 626 | return; |
0775436c TO |
627 | } |
628 | // mark being processed | |
629 | $processedEntities[$key] = 1; | |
630 | ||
631 | // to make sure we not copying to source itself | |
632 | unset($repeatingEntities[$key]); | |
633 | ||
634 | foreach ($repeatingEntities as $key => $val) { | |
635 | $entityID = $val['id']; | |
636 | $entityTable = $val['table']; | |
637 | ||
638 | $processedEntities[$key] = 1; | |
639 | ||
640 | if (array_key_exists($entityTable, self::$_tableDAOMapper)) { | |
353ffa53 | 641 | $daoName = self::$_tableDAOMapper[$entityTable]; |
0775436c | 642 | |
be2fb01f | 643 | $skipData = []; |
0775436c TO |
644 | if (array_key_exists($entityTable, self::$_updateSkipFields)) { |
645 | $skipFields = self::$_updateSkipFields[$entityTable]; | |
646 | foreach ($skipFields as $sfield) { | |
647 | $skipData[$sfield] = NULL; | |
648 | } | |
649 | } | |
650 | ||
651 | $updateDAO = CRM_Core_DAO::cascadeUpdate($daoName, $obj->id, $entityID, $skipData); | |
0775436c TO |
652 | } |
653 | else { | |
654 | CRM_Core_Error::fatal("DAO Mapper missing for $entityTable."); | |
655 | } | |
656 | } | |
657 | // done with processing. lets unset static var. | |
658 | unset($processedEntities); | |
659 | } | |
660 | ||
661 | /** | |
662 | * This function acts as a listener to dao->save, | |
663 | * and creates entries for linked entities in recurring entity table | |
664 | * | |
6a0b768e | 665 | * @param object $event |
8eedd10a | 666 | * An object of /Civi/Core/DAO/Event/PostUpdate containing dao object that was just inserted. |
0775436c | 667 | */ |
518fa0ee | 668 | public static function triggerInsert($event) { |
0775436c TO |
669 | $obj =& $event->object; |
670 | if (!array_key_exists($obj->__table, self::$_linkedEntitiesInfo)) { | |
8eedd10a | 671 | return; |
0775436c TO |
672 | } |
673 | ||
674 | // if DB version is earlier than 4.6 skip any processing | |
675 | static $currentVer = NULL; | |
676 | if (!$currentVer) { | |
677 | $currentVer = CRM_Core_BAO_Domain::version(); | |
678 | } | |
679 | if (version_compare($currentVer, '4.6.alpha1') < 0) { | |
680 | return; | |
681 | } | |
682 | ||
be2fb01f | 683 | static $processedEntities = []; |
0775436c | 684 | if (empty($obj->id) || empty($obj->__table)) { |
8eedd10a | 685 | return; |
0775436c TO |
686 | } |
687 | $key = "{$obj->__table}_{$obj->id}"; | |
688 | ||
689 | if (array_key_exists($key, $processedEntities)) { | |
690 | // already being processed. Exit recursive calls. | |
8eedd10a | 691 | return; |
0775436c TO |
692 | } |
693 | ||
694 | if (self::getStatus() == self::RUNNING) { | |
695 | // if recursion->generate() is doing some work, lets not intercept | |
8eedd10a | 696 | return; |
0775436c TO |
697 | } |
698 | ||
699 | // mark being processed | |
700 | $processedEntities[$key] = 1; | |
701 | ||
702 | // get related entities for table being saved | |
703 | $hasaRecurringRecord = self::getParentFor($obj->id, $obj->__table); | |
704 | ||
705 | if (empty($hasaRecurringRecord)) { | |
706 | // check if its a linked entity | |
707 | if (array_key_exists($obj->__table, self::$_linkedEntitiesInfo) && | |
353ffa53 TO |
708 | !CRM_Utils_Array::value('is_multirecord', self::$_linkedEntitiesInfo[$obj->__table]) |
709 | ) { | |
0775436c TO |
710 | $linkedDAO = new self::$_tableDAOMapper[$obj->__table](); |
711 | $linkedDAO->id = $obj->id; | |
712 | if ($linkedDAO->find(TRUE)) { | |
713 | $idCol = self::$_linkedEntitiesInfo[$obj->__table]['entity_id_col']; | |
714 | $tableCol = self::$_linkedEntitiesInfo[$obj->__table]['entity_table_col']; | |
715 | ||
353ffa53 | 716 | $pEntityID = $linkedDAO->$idCol; |
0775436c TO |
717 | $pEntityTable = $linkedDAO->$tableCol; |
718 | ||
719 | // find all parent recurring entity set | |
720 | $pRepeatingEntities = self::getEntitiesFor($pEntityID, $pEntityTable); | |
721 | ||
722 | if (!empty($pRepeatingEntities)) { | |
723 | // for each parent entity in the set, find out a similar linked entity, | |
724 | // if doesn't exist create one, and also create entries in recurring_entity table | |
725 | ||
726 | foreach ($pRepeatingEntities as $key => $val) { | |
727 | if (array_key_exists($key, $processedEntities)) { | |
728 | // this graph is already being processed | |
8eedd10a | 729 | return; |
0775436c TO |
730 | } |
731 | $processedEntities[$key] = 1; | |
732 | } | |
733 | ||
734 | // start with first entry with just itself | |
735 | CRM_Core_BAO_RecurringEntity::quickAdd($obj->id, $obj->id, $obj->__table); | |
736 | ||
737 | foreach ($pRepeatingEntities as $key => $val) { | |
738 | $rlinkedDAO = new self::$_tableDAOMapper[$obj->__table](); | |
739 | $rlinkedDAO->$idCol = $val['id']; | |
740 | $rlinkedDAO->$tableCol = $val['table']; | |
741 | if ($rlinkedDAO->find(TRUE)) { | |
742 | CRM_Core_BAO_RecurringEntity::quickAdd($obj->id, $rlinkedDAO->id, $obj->__table); | |
743 | } | |
744 | else { | |
745 | // linked entity doesn't exist. lets create them | |
be2fb01f | 746 | $newCriteria = [ |
353ffa53 | 747 | $idCol => $val['id'], |
e7483cbe | 748 | $tableCol => $val['table'], |
be2fb01f | 749 | ]; |
0775436c | 750 | $linkedObj = CRM_Core_BAO_RecurringEntity::copyCreateEntity($obj->__table, |
be2fb01f | 751 | ['id' => $obj->id], |
0775436c TO |
752 | $newCriteria, |
753 | TRUE | |
754 | ); | |
755 | if ($linkedObj->id) { | |
756 | CRM_Core_BAO_RecurringEntity::quickAdd($obj->id, $linkedObj->id, $obj->__table); | |
757 | } | |
758 | } | |
759 | } | |
760 | } | |
761 | } | |
762 | } | |
763 | } | |
764 | ||
765 | // done with processing. lets unset static var. | |
766 | unset($processedEntities); | |
767 | } | |
768 | ||
769 | /** | |
770 | * This function acts as a listener to dao->delete, and deletes an entry from recurring_entity table | |
771 | * | |
6a0b768e | 772 | * @param object $event |
8eedd10a | 773 | * An object of /Civi/Core/DAO/Event/PostUpdate containing dao object that was just deleted. |
0775436c | 774 | */ |
518fa0ee | 775 | public static function triggerDelete($event) { |
0775436c TO |
776 | $obj =& $event->object; |
777 | ||
778 | // if DB version is earlier than 4.6 skip any processing | |
779 | static $currentVer = NULL; | |
780 | if (!$currentVer) { | |
781 | $currentVer = CRM_Core_BAO_Domain::version(); | |
782 | } | |
783 | if (version_compare($currentVer, '4.6.alpha1') < 0) { | |
784 | return; | |
785 | } | |
786 | ||
be2fb01f | 787 | static $processedEntities = []; |
0775436c | 788 | if (empty($obj->id) || empty($obj->__table) || !$event->result) { |
8eedd10a | 789 | return; |
0775436c TO |
790 | } |
791 | $key = "{$obj->__table}_{$obj->id}"; | |
792 | ||
793 | if (array_key_exists($key, $processedEntities)) { | |
794 | // already processed | |
8eedd10a | 795 | return; |
0775436c TO |
796 | } |
797 | ||
798 | // mark being processed | |
799 | $processedEntities[$key] = 1; | |
800 | ||
801 | $parentID = self::getParentFor($obj->id, $obj->__table); | |
802 | if ($parentID) { | |
803 | CRM_Core_BAO_RecurringEntity::delEntity($obj->id, $obj->__table, TRUE); | |
804 | } | |
805 | } | |
806 | ||
807 | /** | |
ad37ac8e | 808 | * This function deletes main entity and related linked entities from recurring-entity table. |
0775436c | 809 | * |
6a0b768e | 810 | * @param int $entityId |
72b3a70c | 811 | * Entity id |
6a0b768e | 812 | * @param string $entityTable |
72b3a70c | 813 | * Name of the entity table |
0775436c | 814 | * |
ad37ac8e | 815 | * @param bool $isDelLinkedEntities |
0775436c | 816 | * |
ad37ac8e | 817 | * @return bool|\CRM_Core_DAO_RecurringEntity |
818 | * @throws \Exception | |
0775436c | 819 | */ |
518fa0ee | 820 | public static function delEntity($entityId, $entityTable, $isDelLinkedEntities = FALSE) { |
0775436c TO |
821 | if (empty($entityId) || empty($entityTable)) { |
822 | return FALSE; | |
823 | } | |
824 | $dao = new CRM_Core_DAO_RecurringEntity(); | |
825 | $dao->entity_id = $entityId; | |
826 | $dao->entity_table = $entityTable; | |
827 | if ($dao->find(TRUE)) { | |
828 | // make sure its not a linked entity thats being deleted | |
829 | if ($isDelLinkedEntities && !array_key_exists($entityTable, self::$_linkedEntitiesInfo)) { | |
830 | // delete all linked entities from recurring entity table | |
831 | foreach (self::$_linkedEntitiesInfo as $linkedTable => $linfo) { | |
832 | $daoName = self::$_tableDAOMapper[$linkedTable]; | |
833 | if (!$daoName) { | |
834 | CRM_Core_Error::fatal("DAO Mapper missing for $linkedTable."); | |
835 | } | |
836 | ||
837 | $linkedDao = new $daoName(); | |
6ef04c72 MM |
838 | $linkedDao->{$linfo['entity_id_col']} = $entityId; |
839 | $linkedDao->{$linfo['entity_table_col']} = $entityTable; | |
0775436c TO |
840 | $linkedDao->find(); |
841 | while ($linkedDao->fetch()) { | |
842 | CRM_Core_BAO_RecurringEntity::delEntity($linkedDao->id, $linkedTable, FALSE); | |
843 | } | |
844 | } | |
845 | } | |
846 | // delete main entity | |
847 | return $dao->delete(); | |
848 | } | |
849 | return FALSE; | |
850 | } | |
851 | ||
852 | /** | |
fe482240 | 853 | * This function maps values posted from form to civicrm_action_schedule columns. |
0775436c | 854 | * |
6a0b768e TO |
855 | * @param array $formParams |
856 | * And array of form values posted . | |
0775436c TO |
857 | * |
858 | * @return array | |
859 | */ | |
be2fb01f CW |
860 | public function mapFormValuesToDB($formParams = []) { |
861 | $dbParams = []; | |
b53cbfbc | 862 | if (!empty($formParams['used_for'])) { |
0775436c TO |
863 | $dbParams['used_for'] = $formParams['used_for']; |
864 | } | |
865 | ||
b53cbfbc | 866 | if (!empty($formParams['entity_id'])) { |
0775436c TO |
867 | $dbParams['entity_value'] = $formParams['entity_id']; |
868 | } | |
869 | ||
b53cbfbc CW |
870 | if (!empty($formParams['repetition_start_date'])) { |
871 | if (!empty($formParams['repetition_start_date_display'])) { | |
0775436c TO |
872 | $repetitionStartDate = $formParams['repetition_start_date_display']; |
873 | } | |
874 | else { | |
875 | $repetitionStartDate = $formParams['repetition_start_date']; | |
876 | } | |
b53cbfbc | 877 | if (!empty($formParams['repetition_start_date_time'])) { |
0775436c TO |
878 | $repetitionStartDate = $repetitionStartDate . " " . $formParams['repetition_start_date_time']; |
879 | } | |
880 | $repetition_start_date = new DateTime($repetitionStartDate); | |
1043bac2 | 881 | $dbParams['start_action_date'] = $repetition_start_date->format('YmdHis'); |
0775436c TO |
882 | } |
883 | ||
b53cbfbc | 884 | if (!empty($formParams['repetition_frequency_unit'])) { |
0775436c TO |
885 | $dbParams['repetition_frequency_unit'] = $formParams['repetition_frequency_unit']; |
886 | } | |
887 | ||
b53cbfbc | 888 | if (!empty($formParams['repetition_frequency_interval'])) { |
0775436c TO |
889 | $dbParams['repetition_frequency_interval'] = $formParams['repetition_frequency_interval']; |
890 | } | |
891 | ||
892 | //For Repeats on:(weekly case) | |
893 | if ($formParams['repetition_frequency_unit'] == 'week') { | |
b53cbfbc | 894 | if (!empty($formParams['start_action_condition'])) { |
0775436c TO |
895 | $repeats_on = CRM_Utils_Array::value('start_action_condition', $formParams); |
896 | $dbParams['start_action_condition'] = implode(",", array_keys($repeats_on)); | |
897 | } | |
898 | } | |
899 | ||
900 | //For Repeats By:(monthly case) | |
901 | if ($formParams['repetition_frequency_unit'] == 'month') { | |
902 | if ($formParams['repeats_by'] == 1) { | |
b53cbfbc | 903 | if (!empty($formParams['limit_to'])) { |
0775436c TO |
904 | $dbParams['limit_to'] = $formParams['limit_to']; |
905 | } | |
906 | } | |
907 | if ($formParams['repeats_by'] == 2) { | |
de6c59ca | 908 | if (!empty($formParams['entity_status_1']) && !empty($formParams['entity_status_2'])) { |
353ffa53 | 909 | $dbParams['entity_status'] = $formParams['entity_status_1'] . " " . $formParams['entity_status_2']; |
0775436c TO |
910 | } |
911 | } | |
912 | } | |
913 | ||
914 | //For "Ends" - After: | |
915 | if ($formParams['ends'] == 1) { | |
b53cbfbc | 916 | if (!empty($formParams['start_action_offset'])) { |
0775436c TO |
917 | $dbParams['start_action_offset'] = $formParams['start_action_offset']; |
918 | } | |
919 | } | |
920 | ||
921 | //For "Ends" - On: | |
922 | if ($formParams['ends'] == 2) { | |
b53cbfbc | 923 | if (!empty($formParams['repeat_absolute_date'])) { |
0775436c TO |
924 | $dbParams['absolute_date'] = CRM_Utils_Date::processDate($formParams['repeat_absolute_date']); |
925 | } | |
926 | } | |
927 | return $dbParams; | |
928 | } | |
929 | ||
930 | /** | |
931 | * This function gets all the columns of civicrm_action_schedule table based on id(primary key) | |
932 | * | |
6a0b768e TO |
933 | * @param int $scheduleReminderId |
934 | * Primary key of civicrm_action_schedule table . | |
0775436c | 935 | * |
0775436c TO |
936 | * |
937 | * @return object | |
938 | */ | |
518fa0ee | 939 | public static function getScheduleReminderDetailsById($scheduleReminderId) { |
0775436c TO |
940 | $query = "SELECT * |
941 | FROM civicrm_action_schedule WHERE 1"; | |
942 | if ($scheduleReminderId) { | |
943 | $query .= " | |
944 | AND id = %1"; | |
945 | } | |
946 | $dao = CRM_Core_DAO::executeQuery($query, | |
be2fb01f CW |
947 | [ |
948 | 1 => [$scheduleReminderId, 'Integer'], | |
949 | ] | |
0775436c TO |
950 | ); |
951 | $dao->fetch(); | |
952 | return $dao; | |
953 | } | |
954 | ||
955 | /** | |
fe482240 | 956 | * wrapper of getScheduleReminderDetailsById function. |
0775436c | 957 | * |
6a0b768e TO |
958 | * @param int $scheduleReminderId |
959 | * Primary key of civicrm_action_schedule table . | |
0775436c TO |
960 | * |
961 | * @return array | |
962 | */ | |
963 | public function getScheduleParams($scheduleReminderId) { | |
be2fb01f | 964 | $scheduleReminderDetails = []; |
0775436c TO |
965 | if ($scheduleReminderId) { |
966 | //Get all the details from schedule reminder table | |
967 | $scheduleReminderDetails = self::getScheduleReminderDetailsById($scheduleReminderId); | |
968 | $scheduleReminderDetails = (array) $scheduleReminderDetails; | |
969 | } | |
970 | return $scheduleReminderDetails; | |
971 | } | |
972 | ||
973 | /** | |
b44e3f84 | 974 | * This function takes criteria saved in civicrm_action_schedule table |
0775436c TO |
975 | * and creates recursion rule |
976 | * | |
6a0b768e | 977 | * @param array $scheduleReminderDetails |
b44e3f84 | 978 | * Array of repeat criteria saved in civicrm_action_schedule table . |
0775436c | 979 | * |
a6c01b45 CW |
980 | * @return object |
981 | * When object | |
0775436c | 982 | */ |
be2fb01f | 983 | public function getRecursionFromSchedule($scheduleReminderDetails = []) { |
0775436c TO |
984 | $r = new When(); |
985 | //If there is some data for this id | |
986 | if ($scheduleReminderDetails['repetition_frequency_unit']) { | |
987 | if ($scheduleReminderDetails['start_action_date']) { | |
988 | $currDate = date('Y-m-d H:i:s', strtotime($scheduleReminderDetails['start_action_date'])); | |
989 | } | |
990 | else { | |
991 | $currDate = date("Y-m-d H:i:s"); | |
992 | } | |
993 | $start = new DateTime($currDate); | |
994 | $this->recursion_start_date = $start; | |
30aa3e54 PZ |
995 | $repetition_frequency_unit = $scheduleReminderDetails['repetition_frequency_unit']; |
996 | if ($repetition_frequency_unit == "day") { | |
997 | $repetition_frequency_unit = "dai"; | |
0775436c | 998 | } |
30aa3e54 PZ |
999 | $repetition_frequency_unit = $repetition_frequency_unit . 'ly'; |
1000 | $r->startDate($start) | |
1001 | ->exclusions([$start]) | |
1002 | ->freq($repetition_frequency_unit); | |
0775436c TO |
1003 | |
1004 | if ($scheduleReminderDetails['repetition_frequency_interval']) { | |
1005 | $r->interval($scheduleReminderDetails['repetition_frequency_interval']); | |
1006 | } | |
1007 | else { | |
1008 | $r->errors[] = 'Repeats every: is a required field'; | |
1009 | } | |
1010 | ||
1011 | //week | |
1012 | if ($scheduleReminderDetails['repetition_frequency_unit'] == 'week') { | |
1013 | if ($scheduleReminderDetails['start_action_condition']) { | |
1014 | $startActionCondition = $scheduleReminderDetails['start_action_condition']; | |
1015 | $explodeStartActionCondition = explode(',', $startActionCondition); | |
be2fb01f | 1016 | $buildRuleArray = []; |
0775436c TO |
1017 | foreach ($explodeStartActionCondition as $key => $val) { |
1018 | $buildRuleArray[] = strtoupper(substr($val, 0, 2)); | |
1019 | } | |
1020 | $r->wkst('MO')->byday($buildRuleArray); | |
1021 | } | |
1022 | } | |
1023 | ||
1024 | //month | |
1025 | if ($scheduleReminderDetails['repetition_frequency_unit'] == 'month') { | |
1026 | if ($scheduleReminderDetails['entity_status']) { | |
1027 | $startActionDate = explode(" ", $scheduleReminderDetails['entity_status']); | |
1028 | switch ($startActionDate[0]) { | |
353ffa53 TO |
1029 | case 'first': |
1030 | $startActionDate1 = 1; | |
1031 | break; | |
ea100cb5 | 1032 | |
353ffa53 TO |
1033 | case 'second': |
1034 | $startActionDate1 = 2; | |
1035 | break; | |
ea100cb5 | 1036 | |
353ffa53 TO |
1037 | case 'third': |
1038 | $startActionDate1 = 3; | |
1039 | break; | |
ea100cb5 | 1040 | |
353ffa53 TO |
1041 | case 'fourth': |
1042 | $startActionDate1 = 4; | |
1043 | break; | |
ea100cb5 | 1044 | |
353ffa53 TO |
1045 | case 'last': |
1046 | $startActionDate1 = -1; | |
1047 | break; | |
0775436c | 1048 | } |
353ffa53 | 1049 | $concatStartActionDateBits = $startActionDate1 . strtoupper(substr($startActionDate[1], 0, 2)); |
be2fb01f | 1050 | $r->byday([$concatStartActionDateBits]); |
0775436c TO |
1051 | } |
1052 | elseif ($scheduleReminderDetails['limit_to']) { | |
be2fb01f | 1053 | $r->bymonthday([$scheduleReminderDetails['limit_to']]); |
0775436c TO |
1054 | } |
1055 | } | |
1056 | ||
1057 | //Ends | |
1058 | if ($scheduleReminderDetails['start_action_offset']) { | |
1059 | if ($scheduleReminderDetails['start_action_offset'] > 30) { | |
1060 | $r->errors[] = 'Occurrences should be less than or equal to 30'; | |
1061 | } | |
1062 | $r->count($scheduleReminderDetails['start_action_offset']); | |
1063 | } | |
1064 | ||
b53cbfbc | 1065 | if (!empty($scheduleReminderDetails['absolute_date'])) { |
0775436c | 1066 | $absoluteDate = CRM_Utils_Date::setDateDefaults($scheduleReminderDetails['absolute_date']); |
2069e839 | 1067 | // absolute_date column of scheduled-reminder table is of type date (and not datetime) |
1068 | // and we always want the date to be included, and therefore appending 23:59 | |
1069 | $endDate = new DateTime($absoluteDate[0] . ' ' . '23:59'); | |
0775436c TO |
1070 | $r->until($endDate); |
1071 | } | |
1072 | ||
1073 | if (!$scheduleReminderDetails['start_action_offset'] && !$scheduleReminderDetails['absolute_date']) { | |
1074 | $r->errors[] = 'Ends: is a required field'; | |
1075 | } | |
1076 | } | |
1077 | else { | |
1078 | $r->errors[] = 'Repeats: is a required field'; | |
1079 | } | |
1080 | return $r; | |
1081 | } | |
1082 | ||
0775436c | 1083 | /** |
fe482240 | 1084 | * This function gets time difference between the two datetime object. |
0775436c | 1085 | * |
6a0b768e TO |
1086 | * @param DateTime $startDate |
1087 | * Start Date . | |
1088 | * @param DateTime $endDate | |
1089 | * End Date . | |
0775436c | 1090 | * |
0775436c | 1091 | * |
a6c01b45 CW |
1092 | * @return object |
1093 | * DateTime object which contain time difference | |
0775436c | 1094 | */ |
518fa0ee | 1095 | public static function getInterval($startDate, $endDate) { |
0775436c TO |
1096 | if ($startDate && $endDate) { |
1097 | $startDate = new DateTime($startDate); | |
353ffa53 | 1098 | $endDate = new DateTime($endDate); |
0775436c TO |
1099 | return $startDate->diff($endDate); |
1100 | } | |
1101 | } | |
1102 | ||
1103 | /** | |
fe482240 | 1104 | * This function gets all columns from civicrm_action_schedule on the basis of event id. |
0775436c | 1105 | * |
6a0b768e TO |
1106 | * @param int $entityId |
1107 | * Entity ID . | |
1108 | * @param string $used_for | |
1109 | * Specifies for which entity type it's used for . | |
0775436c | 1110 | * |
0775436c TO |
1111 | * |
1112 | * @return object | |
1113 | */ | |
1114 | public static function getReminderDetailsByEntityId($entityId, $used_for) { | |
1115 | if ($entityId) { | |
1116 | $query = " | |
1117 | SELECT * | |
1118 | FROM civicrm_action_schedule | |
1119 | WHERE entity_value = %1"; | |
1120 | if ($used_for) { | |
1121 | $query .= " AND used_for = %2"; | |
1122 | } | |
be2fb01f CW |
1123 | $params = [ |
1124 | 1 => [$entityId, 'Integer'], | |
1125 | 2 => [$used_for, 'String'], | |
1126 | ]; | |
0775436c TO |
1127 | $dao = CRM_Core_DAO::executeQuery($query, $params); |
1128 | $dao->fetch(); | |
1129 | } | |
1130 | return $dao; | |
1131 | } | |
1132 | ||
1133 | /** | |
fe482240 | 1134 | * Update mode column in civicrm_recurring_entity table for event related tabs. |
0775436c | 1135 | * |
6a0b768e TO |
1136 | * @param int $entityId |
1137 | * Event id . | |
1138 | * @param string $linkedEntityTable | |
1139 | * Linked entity table name for this event . | |
ad37ac8e | 1140 | * @param string $mainEntityTable |
1141 | * | |
0775436c TO |
1142 | * @return array |
1143 | */ | |
1144 | public static function updateModeLinkedEntity($entityId, $linkedEntityTable, $mainEntityTable) { | |
be2fb01f | 1145 | $result = []; |
353ffa53 | 1146 | if ($entityId && $linkedEntityTable && $mainEntityTable) { |
0775436c TO |
1147 | if (CRM_Utils_Array::value($linkedEntityTable, self::$_tableDAOMapper)) { |
1148 | $dao = self::$_tableDAOMapper[$linkedEntityTable]; | |
1149 | } | |
1150 | else { | |
1151 | CRM_Core_Session::setStatus('Could not update mode for linked entities'); | |
e7483cbe | 1152 | return NULL; |
0775436c TO |
1153 | } |
1154 | $entityTable = $linkedEntityTable; | |
be2fb01f | 1155 | $params = [ |
353ffa53 | 1156 | 'entity_id' => $entityId, |
e7483cbe | 1157 | 'entity_table' => $mainEntityTable, |
be2fb01f CW |
1158 | ]; |
1159 | $defaults = []; | |
0775436c | 1160 | CRM_Core_DAO::commonRetrieve($dao, $params, $defaults); |
b53cbfbc | 1161 | if (!empty($defaults['id'])) { |
0775436c TO |
1162 | $result['entityId'] = $defaults['id']; |
1163 | $result['entityTable'] = $entityTable; | |
1164 | } | |
1165 | } | |
1166 | return $result; | |
1167 | } | |
96025800 | 1168 | |
543aa76e AP |
1169 | /** |
1170 | * Update mode in civicrm_recurring_entity table for event related data and price set in civicrm_price_set_entity. | |
1171 | * | |
1172 | * @param int $entityId | |
1173 | * Event id . | |
1174 | * @param string $entityTable | |
1175 | * @param string $mode | |
1176 | * @param string $linkedEntityTable | |
1177 | * Linked entity table name for this event . | |
1178 | * @param string $priceSet | |
1179 | * Price set of the event . | |
1180 | * | |
1181 | * @return array | |
1182 | */ | |
1183 | public static function updateModeAndPriceSet($entityId, $entityTable, $mode, $linkedEntityTable, $priceSet) { | |
be2fb01f | 1184 | $finalResult = []; |
543aa76e AP |
1185 | |
1186 | if (!empty($linkedEntityTable)) { | |
1187 | $result = CRM_Core_BAO_RecurringEntity::updateModeLinkedEntity($entityId, $linkedEntityTable, $entityTable); | |
1188 | } | |
1189 | ||
1190 | $dao = new CRM_Core_DAO_RecurringEntity(); | |
1191 | if (!empty($result)) { | |
1192 | $dao->entity_id = $result['entityId']; | |
1193 | $dao->entity_table = $result['entityTable']; | |
1194 | } | |
1195 | else { | |
1196 | $dao->entity_id = $entityId; | |
1197 | $dao->entity_table = $entityTable; | |
1198 | } | |
1199 | ||
1200 | if ($dao->find(TRUE)) { | |
1201 | $dao->mode = $mode; | |
1202 | $dao->save(); | |
1203 | ||
55d676f2 AP |
1204 | if ($priceSet) { |
1205 | //CRM-20787 Fix | |
1206 | //I am not sure about other fields, if mode = 3 apply for an event then other fields | |
1207 | //should be save for all other series events or not so applying for price set only for now here. | |
1208 | if (CRM_Core_BAO_RecurringEntity::MODE_ALL_ENTITY_IN_SERIES === $mode) { | |
1209 | //Step-1: Get all events of series | |
1210 | $seriesEventRecords = CRM_Core_BAO_RecurringEntity::getEntitiesFor($entityId, $entityTable); | |
1211 | foreach ($seriesEventRecords as $event) { | |
1212 | //Step-2: Save price set in other series events | |
518fa0ee SL |
1213 | //Remove existing priceset |
1214 | if (CRM_Price_BAO_PriceSet::removeFrom($event['table'], $event['id'])) { | |
55d676f2 AP |
1215 | CRM_Core_BAO_Discount::del($event['id'], $event['table']); |
1216 | } | |
518fa0ee SL |
1217 | //Add new price set |
1218 | CRM_Price_BAO_PriceSet::addTo($event['table'], $event['id'], $priceSet); | |
543aa76e AP |
1219 | } |
1220 | } | |
55d676f2 AP |
1221 | |
1222 | if (CRM_Core_BAO_RecurringEntity::MODE_NEXT_ALL_ENTITY === $mode) { | |
1223 | //Step-1: Get all events of series | |
1224 | $seriesEventRecords = CRM_Core_BAO_RecurringEntity::getEntitiesFor($entityId, $entityTable); | |
1225 | foreach ($seriesEventRecords as $event) { | |
1226 | //Step-2: Save price set in other series events | |
1227 | if ($entityId < $event["id"]) { | |
518fa0ee SL |
1228 | //Remove existing priceset |
1229 | if (CRM_Price_BAO_PriceSet::removeFrom($event['table'], $event['id'])) { | |
55d676f2 AP |
1230 | CRM_Core_BAO_Discount::del($event['id'], $event['table']); |
1231 | } | |
518fa0ee SL |
1232 | //Add new price set |
1233 | CRM_Price_BAO_PriceSet::addTo($event['table'], $event['id'], $priceSet); | |
55d676f2 AP |
1234 | } |
1235 | } | |
1236 | } | |
543aa76e | 1237 | } |
55d676f2 | 1238 | |
543aa76e AP |
1239 | //CRM-20787 - Fix end |
1240 | $finalResult['status'] = 'Done'; | |
1241 | } | |
1242 | else { | |
1243 | $finalResult['status'] = 'Error'; | |
1244 | } | |
1245 | ||
1246 | return $finalResult; | |
1247 | } | |
1248 | ||
30aa3e54 PZ |
1249 | /** |
1250 | * Get next occurrence for the given date | |
1251 | * | |
1252 | * @param \DateTime $occurDate | |
1253 | * @param bool $strictly_after | |
1254 | * | |
1255 | * @return bool | |
1256 | */ | |
1257 | private function getNextOccurrence($occurDate, $strictly_after = TRUE) { | |
1258 | try { | |
1259 | return $this->recursion->getNextOccurrence($occurDate, $strictly_after); | |
1260 | } | |
1261 | catch (Exception $exception) { | |
1262 | CRM_Core_Session::setStatus(ts($exception->getMessage())); | |
1263 | } | |
1264 | return FALSE; | |
1265 | } | |
1266 | ||
0775436c | 1267 | } |