Merge remote-tracking branch 'upstream/4.5' into 4.5-master-2014-12-16-01-08-03
[civicrm-core.git] / CRM / Core / Form / RecurringEntity.php
CommitLineData
e8cca51a 1<?php\r
2/*\r
3 +--------------------------------------------------------------------+\r
4 | CiviCRM version 4.4 |\r
5 +--------------------------------------------------------------------+\r
6 | Copyright CiviCRM LLC (c) 2004-2013 |\r
7 +--------------------------------------------------------------------+\r
8 | This file is a part of CiviCRM. |\r
9 | |\r
10 | CiviCRM is free software; you can copy, modify, and distribute it |\r
11 | under the terms of the GNU Affero General Public License |\r
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |\r
13 | |\r
14 | CiviCRM is distributed in the hope that it will be useful, but |\r
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |\r
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |\r
17 | See the GNU Affero General Public License for more details. |\r
18 | |\r
19 | You should have received a copy of the GNU Affero General Public |\r
20 | License and the CiviCRM Licensing Exception along |\r
21 | with this program; if not, contact CiviCRM LLC |\r
22 | at info[AT]civicrm[DOT]org. If you have questions about the |\r
23 | GNU Affero General Public License or the licensing of CiviCRM, |\r
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |\r
25 +--------------------------------------------------------------------+\r
26*/\r
27\r
28/**\r
29 *\r
30 *\r
31 * @package CRM\r
32 * @copyright CiviCRM LLC (c) 2004-2013\r
33 * $Id$\r
34 *\r
35 */\r
36/**\r
37 * This class generates form components for processing Entity\r
38 *\r
39 */\r
40class CRM_Core_Form_RecurringEntity {\r
41 /**\r
42 * Current entity id\r
43 */\r
44 protected static $_entityId = NULL;\r
45\r
46 /**\r
47 * Schedule Reminder ID\r
48 */\r
49 protected static $_scheduleReminderID = NULL;\r
50\r
51 /**\r
52 * Schedule Reminder data\r
53 */\r
54 protected static $_scheduleReminderDetails = array();\r
55\r
56 /**\r
57 * Parent Entity ID\r
58 */\r
59 protected static $_parentEntityId = NULL;\r
60\r
61 /**\r
62 * Exclude date information\r
63 */\r
64 public static $_excludeDateInfo = array();\r
65\r
66 /**\r
67 * Entity Table\r
68 */\r
69 public static $_entityTable;\r
70\r
71 /**\r
72 * Checks current entityID has parent\r
73 */\r
74 public static $_hasParent = FALSE;\r
75\r
76 static function preProcess($entityTable) {\r
77 self::$_entityId = (int) CRM_Utils_Request::retrieve('id', 'Positive');\r
78 self::$_entityTable = $entityTable;\r
79\r
80 if (self::$_entityId && $entityTable) {\r
81 $checkParentExistsForThisId = CRM_Core_BAO_RecurringEntity::getParentFor(self::$_entityId, $entityTable);\r
82 if ($checkParentExistsForThisId) {\r
83 self::$_hasParent = TRUE;\r
84 self::$_parentEntityId = $checkParentExistsForThisId;\r
85 self::$_scheduleReminderDetails = CRM_Core_BAO_RecurringEntity::getReminderDetailsByEntityId($checkParentExistsForThisId, $entityTable);\r
86 }\r
87 else {\r
88 self::$_parentEntityId = self::$_entityId;\r
89 self::$_scheduleReminderDetails = CRM_Core_BAO_RecurringEntity::getReminderDetailsByEntityId(self::$_entityId, $entityTable);\r
90 }\r
fd216007 91 if (property_exists(self::$_scheduleReminderDetails, 'id')) {\r
92 self::$_scheduleReminderID = self::$_scheduleReminderDetails->id;\r
93 }\r
e8cca51a 94 }\r
95 if ($entityTable) {\r
96 CRM_Core_OptionValue::getValues(array('name' => $entityTable.'_repeat_exclude_dates_'.self::$_parentEntityId), $optionValue);\r
97 $excludeOptionValues = array();\r
98 if (!empty($optionValue)) {\r
99 foreach($optionValue as $key => $val) {\r
100 $excludeOptionValues[$val['value']] = date('m/d/Y', strtotime($val['value']));\r
101 }\r
102 self::$_excludeDateInfo = $excludeOptionValues;\r
103 }\r
104 }\r
105 }\r
106\r
107 /**\r
c490a46a 108 * Set default values for the form. For edit/view mode\r
e8cca51a 109 * the default values are retrieved from the database\r
110 *\r
111 * @access public\r
112 *\r
113 * @return None\r
114 */\r
115 static function setDefaultValues() {\r
116 $defaults = array();\r
117 if (self::$_scheduleReminderID) {\r
118 $defaults['repetition_frequency_unit'] = self::$_scheduleReminderDetails->repetition_frequency_unit;\r
119 $defaults['repetition_frequency_interval'] = self::$_scheduleReminderDetails->repetition_frequency_interval;\r
120 $defaults['start_action_condition'] = array_flip(explode(",",self::$_scheduleReminderDetails->start_action_condition));\r
121 foreach($defaults['start_action_condition'] as $key => $val) {\r
122 $val = 1;\r
123 $defaults['start_action_condition'][$key] = $val;\r
124 }\r
125 $defaults['start_action_offset'] = self::$_scheduleReminderDetails->start_action_offset;\r
126 if (self::$_scheduleReminderDetails->start_action_offset) {\r
127 $defaults['ends'] = 1;\r
128 }\r
129 list($defaults['repeat_absolute_date']) = CRM_Utils_Date::setDateDefaults(self::$_scheduleReminderDetails->absolute_date);\r
130 if (self::$_scheduleReminderDetails->absolute_date) {\r
131 $defaults['ends'] = 2;\r
132 }\r
133 $defaults['limit_to'] = self::$_scheduleReminderDetails->limit_to;\r
134 if (self::$_scheduleReminderDetails->limit_to) {\r
135 $defaults['repeats_by'] = 1;\r
136 }\r
137 $explodeStartActionCondition = array();\r
138 if (self::$_scheduleReminderDetails->entity_status) {\r
139 $explodeStartActionCondition = explode(" ", self::$_scheduleReminderDetails->entity_status);\r
140 $defaults['entity_status_1'] = $explodeStartActionCondition[0];\r
141 $defaults['entity_status_2'] = $explodeStartActionCondition[1];\r
142 }\r
143 if (self::$_scheduleReminderDetails->entity_status) {\r
144 $defaults['repeats_by'] = 2;\r
145 }\r
146 }\r
147 return $defaults;\r
148 }\r
149\r
150 static function buildQuickForm(&$form) {\r
81fead68 151 if (self::$_entityTable) {\r
152 $entityType = explode("_", self::$_entityTable);\r
153 if ($entityType[1]) {\r
154 $form->assign('entityType', ucwords($entityType[1]));\r
155 }\r
156 }\r
e8cca51a 157 $form->assign('currentEntityId', self::$_entityId);\r
158 $form->assign('entityTable', self::$_entityTable);\r
159 $form->assign('scheduleReminderId', self::$_scheduleReminderID);\r
160 $form->assign('hasParent', self::$_hasParent);\r
161\r
162 $form->_freqUnits = array('hour' => 'hour') + CRM_Core_OptionGroup::values('recur_frequency_units');\r
163 foreach ($form->_freqUnits as $val => $label) {\r
164 if ($label == "day") {\r
165 $label = "dai";\r
166 }\r
167 $freqUnitsDisplay[$val] = ts('%1ly', array(1 => $label));\r
168 }\r
169 // echo "<pre>";print_r($freqUnitsDisplay);\r
170 $dayOfTheWeek = array('monday' => 'Monday',\r
171 'tuesday' => 'Tuesday',\r
172 'wednesday' => 'Wednesday',\r
173 'thursday' => 'Thursday',\r
174 'friday' => 'Friday',\r
175 'saturday' => 'Saturday',\r
176 'sunday' => 'Sunday'\r
177 );\r
178 $form->add('select', 'repetition_frequency_unit', ts('Repeats:'), $freqUnitsDisplay);\r
179 $numericOptions = CRM_Core_SelectValues::getNumericOptions(1, 30);\r
180 $form->add('select', 'repetition_frequency_interval', ts('Repeats every:'), $numericOptions, '', array('style' => 'width:55px;'));\r
181 $form->addDateTime('repetition_start_date', ts('Repetition Start Date'), FALSE, array('formatType' => 'activityDateTime'));\r
182 foreach($dayOfTheWeek as $key => $val) {\r
183 $startActionCondition[] = $form->createElement('checkbox', $key, NULL, substr($val."&nbsp;", 0, 3));\r
184 }\r
185 $form->addGroup($startActionCondition, 'start_action_condition', ts('Repeats on'));\r
186 $roptionTypes = array('1' => ts('day of the month'),\r
187 '2' => ts('day of the week'),\r
188 );\r
189 $form->addRadio('repeats_by', ts("Repeats By:"), $roptionTypes, array(), NULL);\r
190 $getMonths = CRM_Core_SelectValues::getNumericOptions(1, 31);\r
191 $form->add('select', 'limit_to', '', $getMonths, FALSE, array('style' => 'width:55px;'));\r
192 $dayOfTheWeekNo = array('first' => 'First',\r
193 'second'=> 'Second',\r
194 'third' => 'Third',\r
195 'fourth'=> 'Fourth',\r
196 'last' => 'Last'\r
197 );\r
198 $form->add('select', 'entity_status_1', ts(''), $dayOfTheWeekNo);\r
199 $form->add('select', 'entity_status_2', ts(''), $dayOfTheWeek);\r
200 $eoptionTypes = array('1' => ts('After'),\r
201 '2' => ts('On'),\r
202 );\r
203 $form->addRadio('ends', ts("Ends:"), $eoptionTypes, array(), NULL);\r
204 $form->add('text', 'start_action_offset', ts(''), array('size' => 3, 'maxlength' => 2));\r
205 $form->addFormRule(array('CRM_Core_Form_RecurringEntity', 'formRule'));\r
206 $form->addDate('repeat_absolute_date', ts('On'), FALSE, array('formatType' => 'mailing'));\r
207 $form->addDate('exclude_date', ts('Exclude Date(s)'), FALSE);\r
208 $select = $form->add('select', 'exclude_date_list', ts(''), self::$_excludeDateInfo, FALSE, array('style' => 'width:150px;', 'size' => 4));\r
209 $select->setMultiple(TRUE);\r
210 $form->addElement('button','add_to_exclude_list','>>','onClick="addToExcludeList(document.getElementById(\'exclude_date\').value);"');\r
211 $form->addElement('button','remove_from_exclude_list', '<<', 'onClick="removeFromExcludeList(\'exclude_date_list\')"');\r
212 $form->addElement('hidden', 'copyExcludeDates', '', array('id' => 'copyExcludeDates'));\r
213 $form->addElement('hidden', 'allowRepeatConfigToSubmit', '', array('id' => 'allowRepeatConfigToSubmit'));\r
214 $form->addButtons(array(\r
215 array(\r
216 'type' => 'submit',\r
217 'name' => ts('Save'),\r
218 'isDefault' => TRUE,\r
219 ),\r
220 array(\r
221 'type' => 'cancel',\r
222 'name' => ts('Cancel')\r
223 ),\r
224 )\r
225 );\r
226 }\r
227\r
228 /**\r
100fef9d 229 * Global validation rules for the form\r
e8cca51a 230 *\r
231 * @param array $fields posted values of the form\r
232 *\r
233 * @return array list of errors to be posted back to the form\r
234 * @static\r
235 * @access public\r
236 */\r
237 static function formRule($values) {\r
238 $errors = array();\r
239 //Process this function only when you get this variable\r
240 if ($values['allowRepeatConfigToSubmit'] == 1) {\r
fe87e754 241 $dayOfTheWeek = array('monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday');\r
e8cca51a 242 //Repeats\r
243 if (!CRM_Utils_Array::value('repetition_frequency_unit', $values)) {\r
244 $errors['repetition_frequency_unit'] = ts('This is a required field');\r
245 }\r
246 //Repeats every\r
247 if (!CRM_Utils_Array::value('repetition_frequency_interval', $values)) {\r
248 $errors['repetition_frequency_interval'] = ts('This is a required field');\r
249 }\r
250 //Ends\r
251 if (CRM_Utils_Array::value('ends', $values)) {\r
252 if ($values['ends'] == 1) {\r
253 if (empty($values['start_action_offset'])) {\r
254 $errors['start_action_offset'] = ts('This is a required field');\r
255 }\r
256 else if ($values['start_action_offset'] > 30) {\r
257 $errors['start_action_offset'] = ts('Occurrences should be less than or equal to 30');\r
258 }\r
259 }\r
260 if ($values['ends'] == 2) {\r
261 if (CRM_Utils_Array::value('repeat_absolute_date', $values)) {\r
262 $entityStartDate = CRM_Utils_Date::processDate($values['repetition_start_date']);\r
263 $end = CRM_Utils_Date::processDate($values['repeat_absolute_date']);\r
264 if (($end < $entityStartDate) && ($end != 0)) {\r
265 $errors['repeat_absolute_date'] = ts('End date should be after current entity\'s start date');\r
266 }\r
267 }\r
268 else {\r
269 $errors['repeat_absolute_date'] = ts('This is a required field');\r
270 }\r
271 }\r
272 }\r
273 else {\r
274 $errors['ends'] = ts('This is a required field');\r
275 }\r
276\r
277 //Repeats BY\r
278 if (CRM_Utils_Array::value('repeats_by', $values)) {\r
279 if ($values['repeats_by'] == 1) {\r
280 if (CRM_Utils_Array::value('limit_to', $values)) {\r
281 if ($values['limit_to'] < 1 && $values['limit_to'] > 31) {\r
282 $errors['limit_to'] = ts('Invalid day of the month');\r
283 }\r
284 }\r
285 else {\r
286 $errors['limit_to'] = ts('Invalid day of the month');\r
287 }\r
288 }\r
289 if ($values['repeats_by'] == 2) {\r
290 if (CRM_Utils_Array::value('entity_status_1', $values)) {\r
291 $dayOfTheWeekNo = array(first, second, third, fourth, last);\r
292 if (!in_array($values['entity_status_1'], $dayOfTheWeekNo)) {\r
293 $errors['entity_status_1'] = ts('Invalid option');\r
294 }\r
295 }\r
296 else {\r
297 $errors['entity_status_1'] = ts('Invalid option');\r
298 }\r
299 if (CRM_Utils_Array::value('entity_status_2', $values)) {\r
300 if (!in_array($values['entity_status_2'], $dayOfTheWeek)) {\r
301 $errors['entity_status_2'] = ts('Invalid day name');\r
302 }\r
303 }\r
304 else {\r
305 $errors['entity_status_2'] = ts('Invalid day name');\r
306 }\r
307 }\r
308 }\r
309 }\r
310 return $errors;\r
311 }\r
312\r
313 /**\r
c490a46a 314 * Process the form submission\r
e8cca51a 315 *\r
316 * @access public\r
317 *\r
318 * @return None\r
319 */\r
320 static function postProcess($params = array(), $type, $linkedEntities = array()) {\r
321 //Check entity_id not present in params take it from class variable\r
322 if (!CRM_Utils_Array::value('entity_id', $params)) {\r
323 $params['entity_id'] = self::$_entityId;\r
324 }\r
325 //Process this function only when you get this variable\r
326 if ($params['allowRepeatConfigToSubmit'] == 1) {\r
327 if (CRM_Utils_Array::value('entity_table', $params) && CRM_Utils_Array::value('entity_id', $params) && $type) {\r
328 $params['used_for'] = $type;\r
329 if (!CRM_Utils_Array::value('parent_entity_id', $params)) {\r
330 $params['parent_entity_id'] = self::$_parentEntityId;\r
331 }\r
332 if (CRM_Utils_Array::value('schedule_reminder_id', $params)) {\r
333 $params['id'] = $params['schedule_reminder_id'];\r
334 }\r
335 else {\r
336 $params['id'] = self::$_scheduleReminderID;\r
337 }\r
338\r
339 //Save post params to the schedule reminder table\r
fe87e754 340 $recurobj = new CRM_Core_BAO_RecurringEntity();\r
341 $dbParams = $recurobj->mapFormValuesToDB($params);\r
e8cca51a 342\r
343 //Delete repeat configuration and rebuild\r
344 if (CRM_Utils_Array::value('id', $params)) {\r
345 CRM_Core_BAO_ActionSchedule::del($params['id']);\r
346 unset($params['id']);\r
347 }\r
348 $actionScheduleObj = CRM_Core_BAO_ActionSchedule::add($dbParams);\r
349\r
350 //exclude dates\r
351 $excludeDateList = array();\r
352 if (CRM_Utils_Array::value('copyExcludeDates', $params) && CRM_Utils_Array::value('parent_entity_id', $params) && $actionScheduleObj->entity_value) {\r
353 //Since we get comma separated values lets get them in array\r
354 $excludeDates = array();\r
355 $excludeDates = explode(",", $params['copyExcludeDates']);\r
356\r
357 //Check if there exists any values for this option group\r
358 $optionGroupIdExists = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup',\r
359 $type.'_repeat_exclude_dates_'.$params['parent_entity_id'],\r
360 'id',\r
361 'name'\r
362 );\r
363 if ($optionGroupIdExists) {\r
364 CRM_Core_BAO_OptionGroup::del($optionGroupIdExists);\r
365 }\r
366 $optionGroupParams =\r
367 array(\r
368 'name' => $type.'_repeat_exclude_dates_'.$actionScheduleObj->entity_value,\r
369 'title' => $type.' recursion',\r
370 'is_reserved' => 0,\r
371 'is_active' => 1\r
372 );\r
373 $opGroup = CRM_Core_BAO_OptionGroup::add($optionGroupParams);\r
374 if ($opGroup->id) {\r
375 $oldWeight= 0;\r
376 $fieldValues = array('option_group_id' => $opGroup->id);\r
377 foreach($excludeDates as $val) {\r
378 $optionGroupValue =\r
379 array(\r
380 'option_group_id' => $opGroup->id,\r
381 'label' => CRM_Utils_Date::processDate($val),\r
382 'value' => CRM_Utils_Date::processDate($val),\r
383 'name' => $opGroup->name,\r
384 'description' => 'Used for recurring '.$type,\r
385 'weight' => CRM_Utils_Weight::updateOtherWeights('CRM_Core_DAO_OptionValue', $oldWeight, CRM_Utils_Array::value('weight', $params), $fieldValues),\r
386 'is_active' => 1\r
387 );\r
388 $excludeDateList[] = $optionGroupValue['value'];\r
389 CRM_Core_BAO_OptionValue::add($optionGroupValue);\r
390 }\r
391 }\r
392 }\r
393\r
394 //Set type for API\r
395 $apiEntityType = array();\r
396 $apiEntityType = explode("_", $type);\r
397 if (!empty($apiEntityType[1])) {\r
398 $apiType = $apiEntityType[1];\r
399 }\r
400 //Delete relations if any from recurring entity tables before inserting new relations for this entity id\r
401 if ($params['entity_id']) {\r
402 //If entity has any pre delete function, consider that first\r
403 if (CRM_Utils_Array::value('pre_delete_func', CRM_Core_BAO_RecurringEntity::$_recurringEntityHelper[$params['entity_table']]) &&\r
404 CRM_Utils_Array::value('helper_class', CRM_Core_BAO_RecurringEntity::$_recurringEntityHelper[$params['entity_table']])) {\r
405 call_user_func(array(\r
406 CRM_Core_BAO_RecurringEntity::$_recurringEntityHelper[$params['entity_table']]['helper_class'],\r
407 call_user_func_array(CRM_Core_BAO_RecurringEntity::$_recurringEntityHelper[$params['entity_table']]['pre_delete_func'], array($params['entity_id'])))\r
408 );\r
409 }\r
410 //Ready to execute delete on entities if it has delete function set\r
411 if (CRM_Utils_Array::value('delete_func', CRM_Core_BAO_RecurringEntity::$_recurringEntityHelper[$params['entity_table']]) &&\r
412 CRM_Utils_Array::value('helper_class', CRM_Core_BAO_RecurringEntity::$_recurringEntityHelper[$params['entity_table']])) {\r
413 //Check if pre delete function has some ids to be deleted\r
414 if (!empty(CRM_Core_BAO_RecurringEntity::$_entitiesToBeDeleted)) {\r
415 foreach (CRM_Core_BAO_RecurringEntity::$_entitiesToBeDeleted as $eid) {\r
416 $result = civicrm_api3(\r
417 ucfirst(strtolower($apiType)),\r
418 CRM_Core_BAO_RecurringEntity::$_recurringEntityHelper[$params['entity_table']]['delete_func'],\r
419 array(\r
420 'sequential' => 1,\r
421 'id' => $eid,\r
422 )\r
423 );\r
424 if ($result['error']) {\r
425 CRM_Core_Error::statusBounce('Error creating recurring list');\r
426 }\r
427 }\r
428 }\r
429 else {\r
430 $getRelatedEntities = CRM_Core_BAO_RecurringEntity::getEntitiesFor($params['entity_id'], $params['entity_table'], FALSE);\r
431 foreach ($getRelatedEntities as $key => $value) {\r
432 $result = civicrm_api3(\r
433 ucfirst(strtolower($apiType)),\r
434 CRM_Core_BAO_RecurringEntity::$_recurringEntityHelper[$params['entity_table']]['delete_func'],\r
435 array(\r
436 'sequential' => 1,\r
437 'id' => $value['id'],\r
438 )\r
439 );\r
440 if ($result['error']) {\r
441 CRM_Core_Error::statusBounce('Error creating recurring list');\r
442 }\r
443 }\r
444 }\r
445 }\r
f5da9c3d 446\r
447 // find all entities from the recurring set. At this point we 'll get entities which were not deleted \r
448 // for e.g due to participants being present. We need to delete them from recurring tables anyway.\r
449 $pRepeatingEntities = CRM_Core_BAO_RecurringEntity::getEntitiesFor($params['entity_id'], $params['entity_table']);\r
450 foreach($pRepeatingEntities as $val) {\r
451 CRM_Core_BAO_RecurringEntity::delEntity($val['id'], $val['table'], TRUE);\r
452 }\r
e8cca51a 453 }\r
454\r
455 $recursion = new CRM_Core_BAO_RecurringEntity();\r
456 $recursion->dateColumns = $params['dateColumns'];\r
457 $recursion->scheduleId = $actionScheduleObj->id;\r
458\r
459 if (!empty($excludeDateList)) {\r
460 $recursion->excludeDates = $excludeDateList;\r
461 $recursion->excludeDateRangeColumns = $params['excludeDateRangeColumns'];\r
462 }\r
fe87e754 463 if (CRM_Utils_Array::value('intervalDateColumns', $params)) {\r
464 $recursion->intervalDateColumns = $params['intervalDateColumns'];\r
465 }\r
e8cca51a 466 $recursion->entity_id = $params['entity_id'];\r
467 $recursion->entity_table = $params['entity_table'];\r
468 if (!empty($linkedEntities)) {\r
469 $recursion->linkedEntities = $linkedEntities;\r
470 }\r
471\r
472 $recurResult = $recursion->generate();\r
473\r
474 $status = ts('Repeat Configuration has been saved');\r
475 CRM_Core_Session::setStatus($status, ts('Saved'), 'success');\r
476 }\r
477 }\r
478 }\r
e8cca51a 479\r
480 /**\r
481 * Return a descriptive name for the page, used in wizard header\r
482 *\r
483 * @return string\r
484 * @access public\r
485 */\r
486 public function getTitle() {\r
487 return ts('Repeat Entity');\r
488 }\r
489\r
490}\r