Merge pull request #3746 from eileenmcnaughton/prtest
[civicrm-core.git] / CRM / Pledge / Form / Pledge.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
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 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2014
32 * $Id$
33 *
34 */
35
36 /**
37 * This class generates form components for processing a pledge
38 *
39 */
40 class CRM_Pledge_Form_Pledge extends CRM_Core_Form {
41 public $_action;
42
43 /**
44 * the id of the pledge that we are proceessing
45 *
46 * @var int
47 * @public
48 */
49 public $_id;
50
51 /**
52 * the id of the contact associated with this pledge
53 *
54 * @var int
55 * @public
56 */
57 public $_contactID;
58
59 /**
60 * The Pledge values if an existing pledge
61 * @public
62 */
63 public $_values;
64
65 /**
66 * The Pledge frequency Units
67 * @public
68 */
69 public $_freqUnits;
70
71 /**
72 * is current pledge pending.
73 * @public
74 */
75 public $_isPending = FALSE;
76
77 /**
78 * Function to set variables up before form is built
79 *
80 * @return void
81 * @access public
82 */
83 public function preProcess() {
84 $this->_contactID = CRM_Utils_Request::retrieve('cid', 'Positive', $this);
85 $this->_action = CRM_Utils_Request::retrieve('action', 'String',
86 $this, FALSE, 'add'
87 );
88 $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
89 $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this);
90
91 // check for action permissions.
92 if (!CRM_Core_Permission::checkActionPermission('CiviPledge', $this->_action)) {
93 CRM_Core_Error::fatal(ts('You do not have permission to access this page'));
94 }
95
96 $this->assign('action', $this->_action);
97 $this->assign('context', $this->_context);
98 if ($this->_action & CRM_Core_Action::DELETE) {
99 return;
100 }
101
102 $this->userDisplayName = $this->userEmail = NULL;
103 if ($this->_contactID) {
104 list($this->userDisplayName,
105 $this->userEmail
106 ) = CRM_Contact_BAO_Contact_Location::getEmailDetails($this->_contactID);
107 $this->assign('displayName', $this->userDisplayName);
108
109 // set title to "Pledge - "+Contact Name
110 $displayName = $this->userDisplayName;
111 $pageTitle = ts('Pledge by'). ' ' . $displayName;
112 $this->assign('pageTitle', $pageTitle);
113 CRM_Utils_System::setTitle($pageTitle);
114 }
115
116 //build custom data
117 CRM_Custom_Form_CustomData::preProcess($this, NULL, NULL, 1, 'Pledge', $this->_id);
118 $this->_values = array();
119 // current pledge id
120 if ($this->_id) {
121 //get the contribution id
122 $this->_contributionID = CRM_Core_DAO::getFieldValue('CRM_Pledge_DAO_PledgePayment',
123 $this->_id, 'contribution_id', 'pledge_id'
124 );
125 $params = array('id' => $this->_id);
126 CRM_Pledge_BAO_Pledge::getValues($params, $this->_values);
127
128 $this->_isPending = (CRM_Pledge_BAO_Pledge::pledgeHasFinancialTransactions($this->_id, CRM_Utils_Array::value('status_id', $this->_values))) ? FALSE : T;
129 }
130
131 //get the pledge frequency units.
132 $this->_freqUnits = CRM_Core_OptionGroup::values('recur_frequency_units');
133
134 $this->_fromEmails = CRM_Core_BAO_Email::getFromEmail();
135 }
136
137
138 /**
139 * This function sets the default values for the form.
140 * the default values are retrieved from the database
141 *
142 * @access public
143 *
144 * @return void
145 */
146 function setDefaultValues() {
147 $defaults = $this->_values;
148
149 $fields = array();
150 if ($this->_action & CRM_Core_Action::DELETE) {
151 return $defaults;
152 }
153
154 if (!empty($defaults['is_test'])) {
155 $this->assign('is_test', TRUE);
156 }
157
158 if ($this->_id) {
159 $startDate = CRM_Utils_Array::value('start_date', $this->_values);
160 $createDate = CRM_Utils_Array::value('create_date', $this->_values);
161 list($defaults['start_date']) = CRM_Utils_Date::setDateDefaults($startDate);
162 list($defaults['create_date']) = CRM_Utils_Date::setDateDefaults($createDate);
163
164 if ($ackDate = CRM_Utils_Array::value('acknowledge_date', $this->_values)) {
165 list($defaults['acknowledge_date']) = CRM_Utils_Date::setDateDefaults($ackDate);
166 }
167
168 //check is this pledge pending
169 // fix the display of the monetary value, CRM-4038
170 if ($this->_isPending) {
171 $defaults['eachPaymentAmount'] = $this->_values['amount'] / $this->_values['installments'];
172 $defaults['eachPaymentAmount'] = CRM_Utils_Money::format($defaults['eachPaymentAmount'], NULL, '%a');
173 }
174 else {
175 $this->assign('start_date', $startDate);
176 $this->assign('create_date', $createDate);
177 }
178 // fix the display of the monetary value, CRM-4038
179 if (isset($this->_values['amount'])) {
180 $defaults['amount'] = CRM_Utils_Money::format($this->_values['amount'], NULL, '%a');
181 }
182 $this->assign('amount', $this->_values['amount']);
183 $this->assign('installments', $defaults['installments']);
184 }
185 else {
186 //default values.
187 list($now) = CRM_Utils_Date::setDateDefaults();
188 $defaults['create_date'] = $now;
189 $defaults['start_date'] = $now;
190 $defaults['installments'] = 12;
191 $defaults['frequency_interval'] = 1;
192 $defaults['frequency_day'] = 1;
193 $defaults['initial_reminder_day'] = 5;
194 $defaults['max_reminders'] = 1;
195 $defaults['additional_reminder_day'] = 5;
196 $defaults['frequency_unit'] = array_search('month', $this->_freqUnits);
197 $defaults['financial_type_id'] = array_search( 'Donation', CRM_Contribute_PseudoConstant::financialType() );
198 }
199
200 $pledgeStatus = CRM_Contribute_PseudoConstant::contributionStatus();
201 $pledgeStatusNames = CRM_Core_OptionGroup::values('contribution_status',
202 FALSE, FALSE, FALSE, NULL, 'name', TRUE
203 );
204 // get default status label (pending)
205 $defaultPledgeStatus = CRM_Utils_Array::value(array_search('Pending', $pledgeStatusNames),
206 $pledgeStatus
207 );
208
209 //assign status.
210 $this->assign('status', CRM_Utils_Array::value(CRM_Utils_Array::value('status_id', $this->_values),
211 $pledgeStatus,
212 $defaultPledgeStatus
213 ));
214
215 if (isset($this->userEmail)) {
216 $this->assign('email', $this->userEmail);
217 }
218
219 // custom data set defaults
220 $defaults += CRM_Custom_Form_CustomData::setDefaultValues($this);
221
222 return $defaults;
223 }
224
225 /**
226 * Function to build the form
227 *
228 * @return void
229 * @access public
230 */
231 public function buildQuickForm() {
232 if ($this->_action & CRM_Core_Action::DELETE) {
233 $this->addButtons(array(
234 array(
235 'type' => 'next',
236 'name' => ts('Delete'),
237 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
238 'isDefault' => TRUE,
239 ),
240 array(
241 'type' => 'cancel',
242 'name' => ts('Cancel'),
243 ),
244 )
245 );
246 return;
247 }
248
249 if ($this->_context == 'standalone') {
250 $this->addEntityRef('contact_id', ts('Contact'), array('create' => TRUE, 'api' => array('extra' => array('email'))), TRUE);
251 }
252
253 $showAdditionalInfo = FALSE;
254 $this->_formType = CRM_Utils_Array::value('formType', $_GET);
255
256 $defaults = array();
257
258 $paneNames = array(
259 'Payment Reminders' => 'PaymentReminders',
260 );
261 foreach ($paneNames as $name => $type) {
262 $urlParams = "snippet=4&formType={$type}";
263 $allPanes[$name] = array('url' => CRM_Utils_System::url('civicrm/contact/view/pledge', $urlParams),
264 'open' => 'false',
265 'id' => $type,
266 );
267 //see if we need to include this paneName in the current form
268 if ($this->_formType == $type || !empty($_POST["hidden_{$type}"]) ||
269 CRM_Utils_Array::value("hidden_{$type}", $defaults)
270 ) {
271 $showAdditionalInfo = TRUE;
272 $allPanes[$name]['open'] = 'true';
273 }
274 $fnName = "build{$type}";
275 CRM_Contribute_Form_AdditionalInfo::$fnName($this);
276 }
277
278 $this->assign('allPanes', $allPanes);
279 $this->assign('showAdditionalInfo', $showAdditionalInfo);
280
281 if ($this->_formType) {
282 $this->assign('formType', $this->_formType);
283 return;
284 }
285
286 $this->applyFilter('__ALL__', 'trim');
287
288 //pledge fields.
289 $attributes = CRM_Core_DAO::getAttribute('CRM_Pledge_DAO_Pledge');
290
291 $this->assign('isPending', $this->_isPending);
292
293 $js = array(
294 'onblur' => "calculatedPaymentAmount( );",
295 'onkeyup' => "calculatedPaymentAmount( );",
296 );
297
298 $currencyFreeze = FALSE;
299 if ($this->_id &&
300 !$this->_isPending
301 ) {
302 $currencyFreeze = TRUE;
303 }
304
305 $element = $this->addMoney('amount', ts('Total Pledge Amount'), TRUE,
306 array_merge($attributes['pledge_amount'], $js), TRUE,
307 'currency', NULL, $currencyFreeze
308 );
309
310 if ($this->_id &&
311 !$this->_isPending
312 ) {
313 $element->freeze();
314 }
315
316 $element = &$this->add('text', 'installments', ts('To be paid in'),
317 array_merge($attributes['installments'], $js), TRUE
318 );
319 $this->addRule('installments', ts('Please enter a valid number of installments.'), 'positiveInteger');
320 if ($this->_id &&
321 !$this->_isPending
322 ) {
323 $element->freeze();
324 }
325
326 $element = &$this->add('text', 'frequency_interval', ts('every'),
327 $attributes['pledge_frequency_interval'], TRUE
328 );
329 $this->addRule('frequency_interval', ts('Please enter a number for frequency (e.g. every "3" months).'), 'positiveInteger');
330 if ($this->_id &&
331 !$this->_isPending
332 ) {
333 $element->freeze();
334 }
335
336 // Fix frequency unit display for use with frequency_interval
337 $freqUnitsDisplay = array();
338 foreach ($this->_freqUnits as $val => $label) {
339 $freqUnitsDisplay[$val] = ts('%1(s)', array(1 => $label));
340 }
341 $element = &$this->add('select', 'frequency_unit',
342 ts('Frequency'),
343 array(
344 '' => ts('- select -')) + $freqUnitsDisplay,
345 TRUE
346 );
347
348 if ($this->_id &&
349 !$this->_isPending
350 ) {
351 $element->freeze();
352 }
353
354 $element = &$this->add('text', 'frequency_day', ts('Payments are due on the'), $attributes['frequency_day'], TRUE);
355 $this->addRule('frequency_day', ts('Please enter a valid payment due day.'), 'positiveInteger');
356 if ($this->_id &&
357 !$this->_isPending
358 ) {
359 $element->freeze();
360 }
361
362 $this->add('text', 'eachPaymentAmount', ts('each'), array('size' => 10, 'style' => "background-color:#EBECE4", 'READONLY'));
363
364 //add various dates
365 if (!$this->_id || $this->_isPending) {
366 $this->addDate('create_date', ts('Pledge Made'), TRUE);
367 $this->addDate('start_date', ts('Payments Start'), TRUE);
368 }
369
370 if ($this->_id &&
371 !$this->_isPending
372 ) {
373 $eachPaymentAmount = $this->_values['original_installment_amount'];
374 $this->assign('currency', $this->_values['currency']);
375 $this->assign('eachPaymentAmount', $eachPaymentAmount);
376 $this->assign('hideCalender', TRUE);
377 }
378
379 if (CRM_Utils_Array::value('status_id', $this->_values) !=
380 array_search('Cancelled', CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'))
381 ) {
382
383 $this->addElement('checkbox', 'is_acknowledge', ts('Send Acknowledgment?'), NULL,
384 array('onclick' => "showHideByValue( 'is_acknowledge', '', 'acknowledgeDate', 'table-row', 'radio', true); showHideByValue( 'is_acknowledge', '', 'fromEmail', 'table-row', 'radio', false );")
385 );
386
387 $this->add('select', 'from_email_address', ts('Receipt From'), $this->_fromEmails);
388 }
389
390 $this->addDate('acknowledge_date', ts('Acknowledgment Date'));
391
392 $this->add('select', 'financial_type_id',
393 ts( 'Financial Type' ),
394 array(''=>ts( '- select -' )) + CRM_Contribute_PseudoConstant::financialType( ),
395 TRUE
396 );
397
398 //CRM-7362 --add campaigns.
399 CRM_Campaign_BAO_Campaign::addCampaign($this, CRM_Utils_Array::value('campaign_id', $this->_values));
400
401 $pageIds = array();
402 CRM_Core_DAO::commonRetrieveAll('CRM_Pledge_DAO_PledgeBlock', 'entity_table',
403 'civicrm_contribution_page', $pageIds, array('entity_id')
404 );
405 $pages = CRM_Contribute_PseudoConstant::contributionPage();
406 $pledgePages = array();
407 foreach ($pageIds as $key => $value) {
408 $pledgePages[$value['entity_id']] = $pages[$value['entity_id']];
409 }
410 $ele = $this->add('select', 'contribution_page_id', ts('Self-service Payments Page'),
411 array(
412 '' => ts('- select -')) + $pledgePages
413 );
414
415 $mailingInfo = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
416 'mailing_backend'
417 );
418 $this->assign('outBound_option', $mailingInfo['outBound_option']);
419
420 //build custom data
421 CRM_Custom_Form_CustomData::buildQuickForm($this);
422
423 // make this form an upload since we dont know if the custom data injected dynamically
424 // is of type file etc $uploadNames = $this->get( 'uploadNames' );
425 $this->addButtons(array(
426 array(
427 'type' => 'upload',
428 'name' => ts('Save'),
429 'js' => array('onclick' => "return verify( );"),
430 'isDefault' => TRUE,
431 ),
432 array(
433 'type' => 'upload',
434 'name' => ts('Save and New'),
435 'js' => array('onclick' => "return verify( );"),
436 'subName' => 'new',
437 ),
438 array(
439 'type' => 'cancel',
440 'name' => ts('Cancel'),
441 ),
442 )
443 );
444
445 $this->addFormRule(array('CRM_Pledge_Form_Pledge', 'formRule'), $this);
446
447 if ($this->_action & CRM_Core_Action::VIEW) {
448 $this->freeze();
449 }
450 }
451
452 /**
453 * global form rule
454 *
455 * @param array $fields the input form values
456 * @param array $files the uploaded files if any
457 * @param $self
458 *
459 * @internal param array $options additional user data
460 *
461 * @return true if no errors, else array of errors
462 * @access public
463 * @static
464 */
465 static function formRule($fields, $files, $self) {
466 $errors = array();
467
468 if ($fields['amount'] <= 0) {
469 $errors['amount'] = ts('Total Pledge Amount should be greater than zero.');
470 }
471 if ($fields['installments'] <= 0) {
472 $errors['installments'] = ts('Installments should be greater than zero.');
473 }
474
475 if ($fields['frequency_unit'] != 'week') {
476 if ($fields['frequency_day'] > 31 || $fields['frequency_day'] == 0) {
477 $errors['frequency_day'] = ts('Please enter a valid frequency day ie. 1 through 31.');
478 }
479 }
480 elseif ($fields['frequency_unit'] == 'week') {
481 if ($fields['frequency_day'] > 7 || $fields['frequency_day'] == 0) {
482 $errors['frequency_day'] = ts('Please enter a valid frequency day ie. 1 through 7.');
483 }
484 }
485 return $errors;
486 }
487
488 /**
489 * Function to process the form
490 *
491 * @access public
492 *
493 * @return void
494 */
495 public function postProcess() {
496 if ($this->_action & CRM_Core_Action::DELETE) {
497 CRM_Pledge_BAO_Pledge::deletePledge($this->_id);
498 return;
499 }
500
501 //get the submitted form values.
502 $formValues = $this->controller->exportValues($this->_name);
503
504 // set the contact, when contact is selected
505 if (!empty($formValues['contact_id'])) {
506 $this->_contactID = $formValues['contact_id'];
507 }
508
509 $session = CRM_Core_Session::singleton();
510
511 //get All Payments status types.
512 $paymentStatusTypes = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
513
514 $fields = array(
515 'frequency_unit',
516 'frequency_interval',
517 'frequency_day',
518 'installments',
519 'financial_type_id',
520 'initial_reminder_day',
521 'max_reminders',
522 'additional_reminder_day',
523 'contribution_page_id',
524 'campaign_id',
525 );
526 foreach ($fields as $f) {
527 $params[$f] = CRM_Utils_Array::value($f, $formValues);
528 }
529
530 //defaults status is "Pending".
531 //if update get status.
532 if ($this->_id) {
533 $params['pledge_status_id'] = $params['status_id'] = $this->_values['status_id'];
534 }
535 else {
536 $params['pledge_status_id'] = $params['status_id'] = array_search('Pending', $paymentStatusTypes);
537 }
538 //format amount
539 $params['amount'] = CRM_Utils_Rule::cleanMoney(CRM_Utils_Array::value('amount', $formValues));
540 $params['currency'] = CRM_Utils_Array::value('currency', $formValues);
541 $params['original_installment_amount'] = ($params['amount'] / $params['installments']);
542
543 $dates = array('create_date', 'start_date', 'acknowledge_date', 'cancel_date');
544 foreach ($dates as $d) {
545 if ($this->_id && (!$this->_isPending) && !empty($this->_values[$d])) {
546 if ($d == 'start_date') {
547 $params['scheduled_date'] = CRM_Utils_Date::processDate($this->_values[$d]);
548 }
549 $params[$d] = CRM_Utils_Date::processDate($this->_values[$d]);
550 }
551 elseif (!empty($formValues[$d]) && !CRM_Utils_System::isNull($formValues[$d])) {
552 if ($d == 'start_date') {
553 $params['scheduled_date'] = CRM_Utils_Date::processDate($formValues[$d]);
554 }
555 $params[$d] = CRM_Utils_Date::processDate($formValues[$d]);
556 }
557 else {
558 $params[$d] = 'null';
559 }
560 }
561
562 if (!empty($formValues['is_acknowledge'])) {
563 $params['acknowledge_date'] = date('Y-m-d');
564 }
565
566 // assign id only in update mode
567 if ($this->_action & CRM_Core_Action::UPDATE) {
568 $params['id'] = $this->_id;
569 }
570
571 $params['contact_id'] = $this->_contactID;
572
573 //format custom data
574 if (!empty($formValues['hidden_custom'])) {
575 $params['hidden_custom'] = 1;
576
577 $customFields = CRM_Core_BAO_CustomField::getFields('Pledge');
578 $params['custom'] = CRM_Core_BAO_CustomField::postProcess($formValues,
579 $customFields,
580 $this->_id,
581 'Pledge'
582 );
583 }
584
585 //handle pending pledge.
586 $params['is_pledge_pending'] = $this->_isPending;
587
588 //create pledge record.
589 $pledge = CRM_Pledge_BAO_Pledge::create($params);
590
591 $statusMsg = NULL;
592
593 if ($pledge->id) {
594 //set the status msg.
595 if ($this->_action & CRM_Core_Action::ADD) {
596 $statusMsg = ts('Pledge has been recorded and the payment schedule has been created.<br />');
597 }
598 elseif ($this->_action & CRM_Core_Action::UPDATE) {
599 $statusMsg = ts('Pledge has been updated.<br />');
600 }
601 }
602
603 //handle Acknowledgment.
604 if (!empty($formValues['is_acknowledge']) && $pledge->id) {
605
606 //calculate scheduled amount.
607 $params['scheduled_amount'] = round($params['amount'] / $params['installments']);
608 $params['total_pledge_amount'] = $params['amount'];
609 //get some required pledge values in params.
610 $params['id'] = $pledge->id;
611 $params['acknowledge_date'] = $pledge->acknowledge_date;
612 $params['is_test'] = $pledge->is_test;
613 $params['currency'] = $pledge->currency;
614 // retrieve 'from email id' for acknowledgement
615 $params['from_email_id'] = $formValues['from_email_address'];
616
617 $this->paymentId = NULL;
618 //send Acknowledgment mail.
619 CRM_Pledge_BAO_Pledge::sendAcknowledgment($this, $params);
620
621 if (!isset($this->userEmail)) {
622 list($this->userDisplayName,
623 $this->userEmail
624 ) = CRM_Contact_BAO_Contact_Location::getEmailDetails($this->_contactID);
625 }
626
627 $statusMsg .= ' ' . ts("An acknowledgment email has been sent to %1.<br />", array(1 => $this->userEmail));
628
629 //build the payment urls.
630 if ($this->paymentId) {
631 $urlParams = "reset=1&action=add&cid={$this->_contactID}&ppid={$this->paymentId}&context=pledge";
632 $contribURL = CRM_Utils_System::url('civicrm/contact/view/contribution', $urlParams);
633 $urlParams .= "&mode=live";
634 $creditURL = CRM_Utils_System::url('civicrm/contact/view/contribution', $urlParams);
635
636 //check if we can process credit card payment.
637 $processors = CRM_Core_PseudoConstant::paymentProcessor(FALSE, FALSE,
638 "billing_mode IN ( 1, 3 )"
639 );
640 if (count($processors) > 0) {
641 $statusMsg .= ' ' . ts("If a payment is due now, you can record <a href='%1'>a check, EFT, or cash payment for this pledge</a> OR <a href='%2'>submit a credit card payment</a>.", array(1 => $contribURL, 2 => $creditURL));
642 }
643 else {
644 $statusMsg .= ' ' . ts("If a payment is due now, you can record <a href='%1'>a check, EFT, or cash payment for this pledge</a>.", array(1 => $contribURL));
645 }
646 }
647 }
648 CRM_Core_Session::setStatus($statusMsg, ts('Payment Due'), 'info');
649
650 $buttonName = $this->controller->getButtonName();
651 if ($this->_context == 'standalone') {
652 if ($buttonName == $this->getButtonName('upload', 'new')) {
653 $session->replaceUserContext(CRM_Utils_System::url('civicrm/pledge/add',
654 'reset=1&action=add&context=standalone'
655 ));
656 }
657 else {
658 $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view',
659 "reset=1&cid={$this->_contactID}&selectedChild=pledge"
660 ));
661 }
662 }
663 elseif ($buttonName == $this->getButtonName('upload', 'new')) {
664 $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/pledge',
665 "reset=1&action=add&context=pledge&cid={$this->_contactID}"
666 ));
667 }
668 }
669 }
670