commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / webform_civicrm / includes / wf_crm_webform_preprocess.inc
1 <?php
2
3 /**
4 * @file
5 * Front-end form pre-processor.
6 */
7
8 module_load_include('inc', 'webform_civicrm', 'includes/wf_crm_webform_base');
9
10 class wf_crm_webform_preprocess extends wf_crm_webform_base {
11 private $form;
12 private $form_state;
13 private $info = array();
14 private $all_fields;
15 private $all_sets;
16
17 function __construct(&$form, &$form_state) {
18 civicrm_initialize();
19 $this->form = &$form;
20 $this->form_state = &$form_state;
21 $this->node = $form['#node'];
22 $this->settings = $this->node->webform_civicrm;
23 $this->data = $this->settings['data'];
24 $this->ent['contact'] = array();
25 $this->all_fields = wf_crm_get_fields();
26 $this->all_sets = wf_crm_get_fields('sets');
27 $this->enabled = wf_crm_enabled_fields($this->node);
28 $this->line_items = wf_crm_aval($form_state, 'civicrm:line_items', array());
29 }
30
31 /**
32 * Alter front-end of webforms: Called by hook_form_alter() when rendering a civicrm-enabled webform
33 * Add custom prefix.
34 * Display messages.
35 * Block users who should not have access.
36 * Set webform default values.
37 */
38 public function alterForm() {
39 // Add css & js
40 $this->addResources();
41 // Add validation handler
42 $this->form['#validate'][] = 'wf_crm_validate';
43 // Keep track of cids across multipage forms
44 if (!empty($this->form_state['values']['submitted']) && wf_crm_aval($this->form_state, 'webform:page_count') > 1) {
45 foreach ($this->enabled as $k => $v) {
46 if (substr($k, -8) == 'existing' && !empty($this->form_state['values']['submitted'][$v])) {
47 list(, $c) = explode('_', $k);
48 $cid_data["cid$c"] = $this->form_state['values']['submitted'][$v];
49 }
50 }
51 if (!empty($cid_data)) {
52 $this->form['#attributes']['data-civicrm-ids'] = json_encode($cid_data);
53 }
54 }
55 // Early return if the form (or page) was already submitted
56 if (wf_crm_aval($this->form_state, 'triggering_element:#id') == 'edit-previous'
57 || (empty($this->form_state['rebuild']) && !empty($this->form_state['storage']) && $this->form['#submission']->is_draft != '1' )) {
58 $this->fillForm($this->form['submitted']);
59 return;
60 }
61 // If this is an edit op, use the original IDs and return
62 if (isset($this->form['#submission']->sid) && $this->form['#submission']->is_draft != '1') {
63 if (isset($this->form['#submission']->civicrm)) {
64 $this->form_state['civicrm']['ent'] = $this->form['#submission']->civicrm;
65 foreach ($this->form_state['civicrm']['ent']['contact'] as $c => $contact) {
66 $this->info['contact'][$c]['contact'][1]['existing'] = wf_crm_aval($contact, 'id', 0);
67 }
68 }
69 $this->fillForm($this->form['submitted']);
70 return;
71 }
72 // If this form is already in-process, IDs will be stored
73 if (!empty($this->form_state['civicrm'])) {
74 $this->ent = $this->form_state['civicrm']['ent'];
75 }
76 else {
77 // Search for existing contacts
78 for ($i = 1; $i <= count($this->data['contact']); ++$i) {
79 $this->ent['contact'][$i] = array();
80 $existing_component = $this->getComponent("civicrm_{$i}_contact_1_contact_existing");
81 if ($existing_component) {
82 $this->findContact($existing_component);
83 }
84 // Fill cid with '0' if unknown
85 $this->ent['contact'][$i] += array('id' => 0);
86 }
87 // Search for other existing entities
88 if (!empty($this->data['case']['number_of_case'])) {
89 $this->findExistingCases();
90 }
91 if (!empty($this->data['activity']['number_of_activity'])) {
92 $this->findExistingActivities();
93 }
94 if (isset($this->data['grant']['number_of_grant'])) {
95 $this->findExistingGrants();
96 }
97 }
98 // Form alterations for unknown contacts
99 if (empty($this->ent['contact'][1]['id'])) {
100 if ($this->settings['prefix_unknown']) {
101 $this->form['#prefix'] = wf_crm_aval($this->form, '#prefix', '') . '<div class="webform-civicrm-prefix contact-unknown">' . nl2br($this->settings['prefix_unknown']) . '</div>';
102 }
103 if ($this->settings['block_unknown_users']) {
104 $this->form['submitted']['#access'] = $this->form['actions']['#access'] = FALSE;
105 $this->setMessage(t('Sorry, you do not have permission to access this form.'), 'warning');
106 return;
107 }
108 }
109 if (!empty($this->data['participant_reg_type'])) {
110 $this->populateEvents();
111 }
112 // Form alterations for known contacts
113 foreach ($this->ent['contact'] as $c => $contact) {
114 if (!empty($contact['id'])) {
115 // Retrieve contact data
116 $this->info['contact'][$c] = $this->loadContact($c);
117 $this->info['contact'][$c]['contact'][1]['existing'] = $contact['id'];
118 // Retrieve participant data
119 if ($this->events && ($c == 1 || $this->data['participant_reg_type'] == 'separate')) {
120 $this->loadParticipants($c);
121 }
122 // Membership
123 if (!empty($this->data['membership'][$c]['number_of_membership'])) {
124 $this->loadMemberships($c, $contact['id']);
125 }
126 }
127 // Load events from url if enabled, this will override loadParticipants
128 if (!empty($this->data['reg_options']['allow_url_load'])) {
129 $this->loadURLEvents($c);
130 }
131 }
132 // Prefill other existing entities
133 foreach (array('case', 'activity', 'grant') as $entity) {
134 if (!empty($this->ent[$entity])) {
135 $this->populateExistingEntity($entity);
136 }
137 }
138 if (!empty($this->ent['contact'][1]['id'])) {
139 if ($this->settings['prefix_known']) {
140 $this->form['#prefix'] = wf_crm_aval($this->form, '#prefix', '') . '<div class="webform-civicrm-prefix contact-known">' . nl2br($this->replaceTokens($this->settings['prefix_known'], $this->info['contact'][1]['contact'][1])) . '</div>';
141 }
142 if ($this->settings['message']) {
143 $this->showNotYouMessage($this->settings['message'], $this->info['contact'][1]['contact'][1]);
144 }
145 }
146 // Store ids
147 $this->form_state['civicrm']['ent'] = $this->ent;
148 // Set default values and other attributes for CiviCRM form elements
149 // Passing $submitted helps avoid overwriting values that have been entered on a multi-step form
150 $submitted = wf_crm_aval($this->form_state, 'values:submitted', array());
151 $this->fillForm($this->form['submitted'], $submitted);
152 }
153
154 /**
155 * Add necessary js & css to the form
156 */
157 private function addResources() {
158 $this->form['#attached']['js'][] = array(
159 'data' => drupal_get_path('module', 'webform_civicrm') . '/js/webform_civicrm_forms.js',
160 'scope' => 'footer',
161 );
162 $this->form['#attached']['css'][] = drupal_get_path('module', 'webform_civicrm') . '/css/webform_civicrm_forms.css';
163 $config = CRM_Core_Config::singleton();
164 // Variables to push to the client-side
165 $js_vars = array();
166 // JS Cache eliminates the need for most ajax state/province callbacks
167 foreach ($this->data['contact'] as $c) {
168 if (!empty($c['number_of_address'])) {
169 $js_vars += array(
170 'defaultCountry' => $config->defaultContactCountry,
171 'defaultStates' => wf_crm_get_states($config->defaultContactCountry),
172 'noCountry' => t('- First Choose a Country -'),
173 'callbackPath' => url('webform-civicrm/js', array('alias' => TRUE)),
174 );
175 break;
176 }
177 }
178 // Preprocess contribution page
179 if (!empty($this->data['contribution'])) {
180 $this->addPaymentJs();
181 $this->form['#attached']['js'][] = array(
182 'data' => drupal_get_path('module', 'webform_civicrm') . '/js/webform_civicrm_payment.js',
183 'scope' => 'footer',
184 );
185 $page_id = $this->data['contribution'][1]['contribution'][1]['contribution_page_id'];
186 if (version_compare($this->civicrm_version, '4.7', '>=')) {
187 $currency = $this->contribution_page['currency'];
188 $contributionCallbackQuery = array('currency' => $currency, 'snippet' => 4);
189 $contributionCallbackUrl = 'civicrm/payment/form';
190 $js_vars['processor_id_key'] = 'processor_id';
191 }
192 else {
193 $contributionCallbackQuery = array('reset' => 1, 'id' => $page_id, 'qfKey' => $this->getQfKey(), 'snippet' => 4);
194 $contributionCallbackUrl = 'civicrm/contribute/transact';
195 $js_vars['processor_id_key'] = 'type';
196 }
197 if (!empty($this->data['contribution'][1]['contribution'][1]['is_test'])) {
198 // RM: This is needed in order for CiviCRM to know that this is a 'test' (i.e. 'preview' action in CiviCRM) transaction - otherwise, CiviCRM defaults to 'live' and returns the payment form with public key for the live payment processor!
199 $contributionCallbackQuery['action'] = CRM_Core_Action::description(CRM_Core_Action::PREVIEW);
200 }
201 $js_vars['contributionCallback'] = url($contributionCallbackUrl, array('query' => $contributionCallbackQuery, 'alias' => TRUE));
202 // Add payment processor - note we have to search in 2 places because $this->loadMultipageData hasn't been run. Maybe it should be?
203 $fid = 'civicrm_1_contribution_1_contribution_payment_processor_id';
204 if (!empty($this->enabled[$fid])) {
205 $js_vars['paymentProcessor'] = wf_crm_aval($this->form_state, 'storage:submitted:' . $this->enabled[$fid]);
206 }
207 else {
208 $js_vars['paymentProcessor'] = $this->getData($fid);
209 }
210 }
211 if ($js_vars) {
212 $this->form['#attached']['js'][] = array(
213 'data' => array('webform_civicrm' => $js_vars),
214 'type' => 'setting',
215 );
216 }
217 }
218
219 /**
220 * Check if events are open to registration and take appropriate action
221 */
222 private function populateEvents() {
223 $reg = wf_crm_aval($this->data, 'reg_options', array());
224 // Fetch events set in back-end
225 $this->data += array('participant' => array());
226 foreach ($this->data['participant'] as $e => $par) {
227 if (!empty($par['participant'])) {
228 foreach ($par['participant'] as $n => $p) {
229 if (!empty($p['event_id'])) {
230 // Handle multi-valued event selection
231 foreach ((array) $p['event_id'] as $eid) {
232 if ($eid = (int) $eid) {
233 $this->events[$eid]['ended'] = TRUE;
234 $this->events[$eid]['title'] = t('this event');
235 $this->events[$eid]['count'] = wf_crm_aval($this->events, "$eid:count", 0) + 1;
236 $status_fid = "civicrm_{$e}_participant_{$n}_participant_status_id";
237 $this->events[$eid]['form'][] = array(
238 'contact' => $e,
239 'num' => $n,
240 'eid' => NULL,
241 'status_id' => (array) $this->getData($status_fid, array_keys($this->getExposedOptions($status_fid))),
242 );
243 }
244 }
245 }
246 }
247 }
248 }
249 // Add events exposed to the form
250 foreach ($this->enabled as $field => $fid) {
251 if (strpos($field, 'participant_event_id')) {
252 foreach ($this->getExposedOptions($field) as $p => $label) {
253 list($eid) = explode('-', $p);
254 $this->events[$eid]['ended'] = TRUE;
255 $this->events[$eid]['title'] = $label;
256 list(, $e, , $n) = explode('_', $field);
257 $status_fid = "civicrm_{$e}_participant_{$n}_participant_status_id";
258 $this->events[$eid]['form'][] = array(
259 'contact' => $e,
260 'num' => $n,
261 'eid' => $p,
262 'status_id' => (array) $this->getData($status_fid, array_keys($this->getExposedOptions($status_fid))),
263 );
264 }
265 }
266 }
267 if ($this->events && (!empty($reg['show_remaining']) || !empty($reg['block_form']))) {
268 $this->loadEvents();
269 foreach ($this->events as $eid => $event) {
270 if ($event['ended']) {
271 if (!empty($reg['show_remaining'])) {
272 $this->setMessage(t('Sorry, %event has ended.', array('%event' => $event['title'])), 'warning');
273 }
274 }
275 elseif ($event['full']) {
276 if (!empty($reg['show_remaining'])) {
277 $this->setMessage('<em>' . check_plain($event['title']) . '</em>: ' . check_plain($event['full_message']), 'warning');
278 }
279 }
280 else {
281 $reg['block_form'] = FALSE;
282 if ($event['max_participants'] && ($reg['show_remaining'] == 'always' || intval($reg['show_remaining']) >= $event['remaining'])) {
283 $this->setMessage(format_plural($event['remaining'],
284 '%event has 1 remaining space.',
285 '%event has @count remaining spaces.',
286 array('%event' => $event['title'])));
287 }
288 }
289 }
290 if ($reg['block_form']) {
291 $this->form['submitted']['#access'] = $this->form['actions']['#access'] = FALSE;
292 return;
293 }
294 }
295 }
296
297 /**
298 * Load participant data for a contact
299 * @param int $c
300 */
301 private function loadParticipants($c) {
302 $select = array('id', 'event_id', 'role_id', 'status_id');
303 if (array_key_exists('participant_campaign_id', $this->all_fields)) {
304 $select[] = 'campaign_id';
305 }
306 $status_types = wf_crm_apivalues('participant_status_type', 'get');
307 $dao = CRM_Core_DAO::executeQuery('SELECT ' . implode(',', $select) . '
308 FROM civicrm_participant
309 WHERE contact_id = ' . $this->ent['contact'][$c]['id'] . ' AND event_id IN (' . implode(',', array_keys($this->events)) . ")"
310 );
311 while ($dao->fetch()) {
312 $par = array();
313 foreach ($select as $sel) {
314 $par['participant'][1][$sel] = $dao->$sel;
315 }
316 $par += $this->getCustomData($dao->id, 'Participant');
317 $status = $status_types[$dao->status_id];
318 foreach ($this->events[$dao->event_id]['form'] as $event) {
319 if ($event['contact'] == $c) {
320 // If status has been set by admin or exposed to the form, use it as a filter
321 if (in_array($status['id'], $event['status_id']) ||
322 // If status is "Automatic" (empty) then make sure the participant is registered
323 (empty($event['status_id']) && $status['class'] != 'Negative')
324 ) {
325 $n = $event['contact'];
326 $i = $event['num'];
327 // Support multi-valued form elements as best we can
328 $event_ids = wf_crm_aval($this->info, "participant:$n:participant:$i:event_id", array());
329 if ($event['eid']) {
330 $event_ids[] = $event['eid'];
331 }
332 foreach ($par as $k => $v) {
333 $this->info['participant'][$n][$k][$i] = $v[1];
334 }
335 $this->info['participant'][$n]['participant'][$i]['event_id'] = $event_ids;
336 }
337 }
338 }
339 }
340 $dao->free();
341 }
342
343 /**
344 * Load event data for the url
345 * @param int $c
346 */
347 private function loadURLEvents($c) {
348 $n = $this->data['participant_reg_type'] == 'separate' ? $c : 1;
349 $p = wf_crm_aval($this->data, "participant:$n:participant");
350 if ($p) {
351 foreach ($p as $e => $value) {
352 $event_ids = array();
353 // Get the available event list from the component
354 $fid = "civicrm_{$c}_participant_{$e}_participant_event_id";
355 $eids = array();
356 foreach ($this->getExposedOptions($fid) as $eid => $title) {
357 $id = explode('-', $eid);
358 $eids[$id[0]] = $eid;
359 }
360 if ($this->data['participant_reg_type'] == 'all') {
361 $urlParam = "event$e";
362 }
363 else {
364 $urlParam = "c{$c}event{$e}";
365 }
366 foreach (explode(',', wf_crm_aval($_GET, $urlParam)) as $key => $value) {
367 if (isset($eids[$value])){
368 $event_ids[] = $eids[$value];
369 }
370 }
371 $this->info['participant'][$c]['participant'][$e]['event_id'] = $event_ids;
372 }
373 }
374 }
375
376 /**
377 * Load existing membership information and display a message to members.
378 * @param int $c
379 * @param int $cid
380 */
381 private function loadMemberships($c, $cid) {
382 $today = date('Y-m-d');
383 foreach ($this->findMemberships($cid) as $num => $membership) {
384 // Only show 1 expired membership, and only if there are no active ones
385 if (!$membership['is_active'] && $num) {
386 break;
387 }
388 $type = $membership['membership_type_id'];
389 $msg = t('@type membership for @contact has a status of "@status".', array(
390 '@type' => $this->getMembershipTypeField($type, 'name'),
391 '@contact' => $this->info['contact'][$c]['contact'][1]['display_name'],
392 '@status' => $membership['status'],
393 ));
394 if (!empty($membership['end_date'])) {
395 $end = array('@date' => CRM_Utils_Date::customFormat($membership['end_date']));
396 $msg .= ' ' . ($membership['end_date'] > $today ? t('Expires @date.', $end) : t('Expired @date.', $end));
397 }
398 $this->setMessage($msg);
399 for ($n = 1; $n <= $this->data['membership'][$c]['number_of_membership']; ++$n) {
400 $fid = "civicrm_{$c}_membership_{$n}_membership_membership_type_id";
401 if (empty($info['membership'][$c]['membership'][$n]) && ($this->getData($fid) == $type ||
402 array_key_exists($type, $this->getExposedOptions($fid)))
403 ) {
404 $this->info['membership'][$c]['membership'][$n] = $membership;
405 break;
406 }
407 }
408 }
409 }
410
411 /**
412 * Find an existing contact based on matching criteria
413 * Used to populate a webform existing contact field
414 *
415 * @param array $component
416 * Webform component of type 'civicrm_contact'
417 */
418 private function findContact($component) {
419 module_load_include('inc', 'webform_civicrm', 'includes/contact_component');
420 list(, $c,) = explode('_', $component['form_key'], 3);
421 $filters = wf_crm_search_filters($this->node, $component);
422 // Start with the url - that trumps everything.
423 if (isset($_GET["cid$c"]) || ($c == 1 && isset($_GET['cid']))) {
424 $cid = isset($_GET["cid$c"]) ? $_GET["cid$c"] : $_GET['cid'];
425 if (wf_crm_is_positive($cid) || $cid == '0') {
426 $cid = (int) $cid;
427 if ($cid === 0) {
428 $this->ent['contact'][$c]['id'] = $cid;
429 }
430 // This property may not exist in components created before v4.12 so default to TRUE if not set
431 elseif (wf_crm_aval($component['extra'], 'allow_url_autofill', TRUE, TRUE)) {
432 if (wf_crm_contact_access($component, $filters, $cid) !== FALSE) {
433 $this->ent['contact'][$c]['id'] = $cid;
434 }
435 }
436 }
437 }
438 if (!isset($this->ent['contact'][$c]['id'])) {
439 $found = array();
440 switch ($component['extra']['default']) {
441 case 'user':
442 $cid = wf_crm_user_cid();
443 $found = ($c == 1 && $cid) ? array($cid) : array();
444 break;
445 case 'contact_id':
446 if ($component['extra']['default_contact_id']) {
447 $found = array($component['extra']['default_contact_id']);
448 }
449 break;
450 case 'relationship':
451 if (!empty($this->ent['contact'][1]['id'])) {
452 $found = wf_crm_find_relations($this->ent['contact'][1]['id'], $component['extra']['default_relationship']);
453 }
454 break;
455 case 'auto':
456 $component['extra']['allow_create'] = FALSE;
457 $found = array_keys(wf_crm_contact_search($this->node, $component, $filters));
458 break;
459 }
460 if ($component['extra']['randomize']) {
461 shuffle($found);
462 }
463 if (in_array($component['extra']['default'], array('user', 'contact_id'))) {
464 $dupes_allowed = TRUE;
465 }
466 else {
467 $dupes_allowed = $component['extra']['dupes_allowed'];
468 }
469 foreach ($found as $cid) {
470 // Don't pick the same contact twice unless explicitly told to do so
471 if (!$dupes_allowed) {
472 foreach($this->ent['contact'] as $contact) {
473 if (!empty($contact['id']) && $cid == $contact['id']) {
474 continue 2;
475 }
476 }
477 }
478 // Check filters except for 'auto' which already applied them
479 if ($component['extra']['default'] == 'auto' || wf_crm_contact_access($component, $filters, $cid) !== FALSE) {
480 $this->ent['contact'][$c]['id'] = $cid;
481 break;
482 }
483 }
484 }
485 }
486
487 /**
488 * Recursively walk through form array and set properties of CiviCRM fields
489 *
490 * @param array $elements (reference)
491 * FAPI form array
492 * @param array $submitted
493 * Existing submission (optional)
494 */
495 private function fillForm(&$elements, $submitted = array()) {
496 foreach ($elements as $eid => &$element) {
497 if ($eid[0] == '#' || !is_array($element)) {
498 continue;
499 }
500 // Recurse through nested elements
501 $this->fillForm($element, $submitted);
502 if (empty($element['#type']) || $element['#type'] == 'fieldset') {
503 continue;
504 }
505 if (!empty($element['#webform_component']) && $pieces = wf_crm_explode_key($eid)) {
506 list( , $c, $ent, $n, $table, $name) = $pieces;
507 // Separate out time fields
508 if (substr($name, -8) === 'timepart') {
509 $name = str_replace('_timepart', '', $name);
510 }
511 if ($field = wf_crm_aval($this->all_fields, $table . '_' . $name)) {
512 $component = $element['#webform_component'];
513 $element['#attributes']['class'][] = 'civicrm-enabled';
514 $dt = NULL;
515 if (!empty($field['data_type'])) {
516 $dt = $element['#civicrm_data_type'] = $field['data_type'];
517 }
518 // Provide live options from the Civi DB
519 if (!empty($component['extra']['civicrm_live_options']) && isset($element['#options'])) {
520 $params = array('extra' => wf_crm_aval($field, 'extra', array())) + $component;
521 $new = wf_crm_field_options($params, 'live_options', $this->data);
522 $old = $element['#options'];
523 $resave = FALSE;
524 // If an item doesn't exist, we add it. If it's changed, we update it.
525 // But we don't subtract items that have been removed in civi - this prevents
526 // breaking the display of old submissions.
527 foreach ($new as $k => $v) {
528 if (!isset($old[$k]) || $old[$k] != $v) {
529 $old[$k] = $v;
530 $resave = TRUE;
531 }
532 }
533 if ($resave) {
534 $component['extra']['items'] = wf_crm_array2str($old);
535 webform_component_update($component);
536 }
537 $element['#options'] = $new;
538 }
539 // If the user has already entered a value for this field, don't change it
540 if (isset($this->info[$ent][$c][$table][$n][$name])
541 && !(isset($component['cid']) && isset($submitted[$component['cid']]))) {
542 $val = $this->info[$ent][$c][$table][$n][$name];
543 if (($element['#type'] == 'checkboxes' || !empty($element['#multiple'])) && !is_array($val)) {
544 $val = wf_crm_explode_multivalue_str($val);
545 }
546 if ($element['#type'] != 'checkboxes' && $element['#type'] != 'date'
547 && empty($element['#multiple']) && is_array($val)) {
548 // If there's more than one value for a non-multi field, pick the most appropriate
549 if (!empty($element['#options'])) {
550 foreach ($element['#options'] as $k => $v) {
551 if (in_array($k, $val)) {
552 $val = $k;
553 break;
554 }
555 }
556 }
557 else {
558 $val = array_pop($val);
559 }
560 }
561 // Contact image & custom file fields
562 if ($dt == 'File') {
563 $fileInfo = $this->getFileInfo($name, $val, $ent, $n);
564 if ($fileInfo && in_array($element['#type'], array('file', 'managed_file'))) {
565 $fileInfo = json_encode($fileInfo);
566 $js = "jQuery(function() {wfCivi.initFileField('$eid', $fileInfo)});";
567 $element['#attached']['js'][$js] = array('type' => 'inline');
568 }
569 }
570 // Set value for "secure value" elements
571 elseif ($element['#type'] == 'value') {
572 $element['#value'] = $val;
573 }
574 // Set default value
575 else {
576 $element['#default_value'] = $val;
577 }
578 }
579 if ($name == 'existing') {
580 wf_crm_fill_contact_value($this->node, $component, $element);
581 }
582 if ($name == 'contribution_page_id') {
583 $element['#prefix'] = $this->displayLineItems();
584 $element['#suffix'] = '<div class="crm-container crm-public" id="billing-payment-block"></div>';
585 $element['#value'] = wf_crm_aval($this->data, 'contribution:1:contribution:1:contribution_page_id');
586 unset($element['#default_value']);
587 }
588 }
589 }
590 }
591 }
592
593 /**
594 * Format line-items to appear on front-end of webform
595 * @return string
596 */
597 private function displayLineItems() {
598 $rows = array();
599 $total = 0;
600 // Support hidden contribution field
601 $fid = 'civicrm_1_contribution_1_contribution_total_amount';
602 if (!$this->line_items && isset($this->enabled[$fid])) {
603 $field = $this->node->webform['components'][$this->enabled[$fid]];
604 if ($field['type'] == 'hidden') {
605 $this->line_items[] = array(
606 'line_total' => $field['value'],
607 'qty' => 1,
608 'element' => 'civicrm_1_contribution_1',
609 'label' => !empty($field['name']) ? $field['name'] : t('Contribution Amount'),
610 );
611 }
612 }
613 foreach ($this->line_items as $item) {
614 $total += $item['line_total'];
615 // tax integration
616 if (!is_null($this->tax_rate)) {
617 // Change the line item label to display the tax rate it contains
618 $taxSettings = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME, 'contribution_invoice_settings');
619
620 if ($taxSettings['tax_display_settings'] != 'Do_not_show') {
621 $item['label'] .= ' (' . t('includes !rate @tax', array('!rate' => $this->tax_rate . '%', '@tax' => $taxSettings['tax_term'])) . ')';
622 }
623
624 // Add calculation for financial type that contains tax
625 $item['tax_amount'] = ($this->tax_rate / 100) * $item['line_total'];
626 $total += $item['line_total'] * (($this->tax_rate / 100) + 1);
627 $label = $item['label'] . ($item['qty'] > 1 ? " ({$item['qty']})" : '');
628 $rows[] = array(
629 'data' => array($label, CRM_Utils_Money::format($item['line_total'] * (($this->tax_rate / 100) + 1))),
630 'class' => array($item['element'], 'line-item'),
631 'data-amount' => $item['line_total'] * (($this->tax_rate / 100) + 1),
632 'data-tax' => (int)$this->tax_rate,
633 );
634 }else{
635 $total += $item['line_total'];
636
637 $label = $item['label'] . ($item['qty'] > 1 ? " ({$item['qty']})" : '');
638 $rows[] = array(
639 'data' => array($label, CRM_Utils_Money::format($item['line_total'])),
640 'class' => array($item['element'], 'line-item'),
641 'data-amount' => $item['line_total'],
642 );
643 }
644 }
645 $rows[] = array(
646 'data' => array(t('Total'), CRM_Utils_Money::format($total)),
647 'id' => 'wf-crm-billing-total',
648 'data-amount' => $total,
649 );
650 return theme('table', array(
651 'sticky' => FALSE,
652 'caption' => $this->contribution_page['title'],
653 'header' => array(),
654 'rows' => $rows,
655 'attributes' => array('id' => "wf-crm-billing-items"),
656 ));
657 }
658
659 /**
660 * Find case ids based on url input or "existing case" settings
661 */
662 private function findExistingCases() {
663 // Support legacy url param
664 if (empty($_GET["case1"]) && !empty($_GET["caseid"])) {
665 $_GET["case1"] = $_GET["caseid"];
666 }
667 for ($n = 1; $n <= $this->data['case']['number_of_case']; ++$n) {
668 if (!empty($this->data['case'][$n]['case'][1]['client_id'])) {
669 $clients = array();
670 foreach ((array)$this->data['case'][$n]['case'][1]['client_id'] as $c) {
671 if (!empty($this->ent['contact'][$c]['id'])) {
672 $clients[] = $this->ent['contact'][$c]['id'];
673 }
674 }
675 if ($clients) {
676 // Populate via url argument
677 if (isset($_GET["case$n"]) && wf_crm_is_positive($_GET["case$n"])) {
678 $id = $_GET["case$n"];
679 $item = wf_civicrm_api('case', 'getsingle', array('id' => $id));
680 if (array_intersect((array)wf_crm_aval($item, 'client_id'), $clients)) {
681 $this->ent['case'][$n] = array('id' => $id);
682 }
683 }
684 // Populate via search
685 elseif (!empty($this->data['case'][$n]['existing_case_status'])) {
686 $item = $this->findCaseForContact($clients, array(
687 'case_type_id' => wf_crm_aval($this->data['case'][$n], 'case:1:case_type_id'),
688 'status_id' => $this->data['case'][$n]['existing_case_status']
689 ));
690 if ($item) {
691 $this->ent['case'][$n] = array('id' => $item['id']);
692 }
693 }
694 }
695 }
696 }
697 }
698
699 /**
700 * Find activity ids based on url input or "existing activity" settings
701 */
702 private function findExistingActivities() {
703 // Support legacy url param
704 if (empty($_GET["activity1"]) && !empty($_GET["aid"])) {
705 $_GET["activity1"] = $_GET["aid"];
706 }
707 for ($n = 1; $n <= $this->data['activity']['number_of_activity']; ++$n) {
708 if (!empty($this->data['activity'][$n]['activity'][1]['target_contact_id'])) {
709 $targets = array();
710 foreach ($this->data['activity'][$n]['activity'][1]['target_contact_id'] as $c) {
711 if (!empty($this->ent['contact'][$c]['id'])) {
712 $targets[] = $this->ent['contact'][$c]['id'];
713 }
714 }
715 if ($targets) {
716 if (isset($_GET["activity$n"]) && wf_crm_is_positive($_GET["activity$n"])) {
717 $id = $_GET["activity$n"];
718 $item = wf_civicrm_api('activity', 'getsingle', array('id' => $id, 'return' => array('target_contact_id')));
719 if (array_intersect($targets, $item['target_contact_id'])) {
720 $this->ent['activity'][$n] = array('id' => $id);
721 }
722 }
723 elseif (!empty($this->data['activity'][$n]['existing_activity_status'])) {
724 // If the activity type hasn't been set, bail.
725 if (empty($this->data['activity'][$n]['activity'][1]['activity_type_id'])) {
726 watchdog('webform_civicrm', "Activity type to update hasn't been set, so won't try to update activity. location = %1, webform activity number : %2", array('%1' => request_uri(), '%2' => $n), WATCHDOG_ERROR);
727 continue;
728 }
729 // The api doesn't accept an array of target contacts so we'll do it as a loop
730 // If targets has more than one entry, the below could result in the wrong activity getting updated.
731 foreach ($targets as $cid) {
732 $params = array(
733 'sequential' => 1,
734 'target_contact_id' => $cid,
735 'status_id' => array('IN' => (array)$this->data['activity'][$n]['existing_activity_status']),
736 'is_deleted' => '0',
737 'is_current_revision' => '1',
738 'options' => array('limit' => 1),
739 );
740 $params['activity_type_id'] = $this->data['activity'][$n]['activity'][1]['activity_type_id'];
741 $items = wf_crm_apivalues('activity', 'get', $params);
742 if (isset($items[0]['id'])) {
743 $this->ent['activity'][$n] = array('id' => $items[0]['id']);
744 break;
745 }
746 }
747 }
748 }
749 }
750 }
751 }
752
753 /**
754 * Find grant ids based on url input or "existing grant" settings
755 */
756 private function findExistingGrants() {
757 for ($n = 1; $n <= $this->data['grant']['number_of_grant']; ++$n) {
758 if (!empty($this->data['grant'][$n]['grant'][1]['contact_id'])) {
759 $cid = $this->ent['contact'][$this->data['grant'][$n]['grant'][1]['contact_id']]['id'];
760 if ($cid) {
761 if (isset($_GET["grant$n"]) && wf_crm_is_positive($_GET["grant$n"])) {
762 $id = $_GET["grant$n"];
763 $item = wf_civicrm_api('grant', 'getsingle', array('id' => $id));
764 if ($cid == $item['contact_id']) {
765 $this->ent['grant'][$n] = array('id' => $id);
766 }
767 }
768 elseif (!empty($this->data['grant'][$n]['existing_grant_status'])) {
769 $params = array(
770 'sequential' => 1,
771 'contact_id' => $cid,
772 'status_id' => array('IN' => (array)$this->data['grant'][$n]['existing_grant_status']),
773 'options' => array('limit' => 1),
774 );
775 if (!empty($this->data['grant'][$n]['grant'][1]['grant_type_id'])) {
776 $params['grant_type_id'] = $this->data['grant'][$n]['grant'][1]['grant_type_id'];
777 }
778 $items = wf_crm_apivalues('grant', 'get', $params);
779 if (isset($items[0]['id'])) {
780 $this->ent['grant'][$n] = array('id' => $items[0]['id']);
781 }
782 }
783 }
784 }
785 }
786 }
787
788 /**
789 * Populate existing entity data
790 * @param string $type entity type (activity, case, grant)
791 */
792 private function populateExistingEntity($type) {
793 $items = array();
794 foreach ($this->ent[$type] as $key => $item) {
795 if (!empty($item['id'])) {
796 $items[$key] = $item['id'];
797 }
798 }
799 if ($items) {
800 $values = wf_crm_apivalues($type, 'get', array('id' => array('IN' => array_values($items))));
801 foreach ($items as $n => $id) {
802 if (isset($values[$id])) {
803 // Load core + custom data
804 $this->info[$type][$n] = array($type => array(1 => $values[$id])) + $this->getCustomData($id, $type);
805 // Load file attachments
806 if (!empty($this->all_sets["{$type}upload"])) {
807 foreach ($this->getAttachments($type, $id) as $f => $file) {
808 $this->info[$type][$n]["{$type}upload"][1]["file_$f"] = $file['file_id'];
809 }
810 }
811 }
812 }
813 }
814 }
815
816 /**
817 * Wrapper for drupal_set_message
818 * Ensures we only set the message on the first page of the node display
819 * @param $message
820 * @param string $type
821 */
822 function setMessage($message, $type='status') {
823 if (node_is_page($this->node) && empty($_POST)) {
824 drupal_set_message($message, $type, FALSE);
825 }
826 }
827
828 /**
829 * Displays the admin-defined message with "not you?" link to known contacts
830 *
831 * @param string $message
832 * Raw message with tokens
833 * @param array $contact
834 * CiviCRM contact array
835 */
836 private function showNotYouMessage($message, $contact) {
837 $message = $this->replaceTokens($message, $contact);
838 preg_match_all('#\{([^}]+)\}#', $message, $matches);
839 if (!empty($matches[0])) {
840 $q = $_GET;
841 unset($q['q'], $q['cs'], $q['cid'], $q['cid1']);
842 if (empty($_GET['cid']) && empty($_GET['cid1'])) {
843 $q['cid1'] = 0;
844 }
845 foreach ($matches[0] as $pos => $match) {
846 $link = l($matches[1][$pos], $_GET['q'], array('query' => $q, 'alias' => TRUE));
847 $message = str_replace($match, $link, $message);
848 }
849 }
850 $this->setMessage($message);
851 }
852
853 /**
854 * Token replacement for form messages
855 *
856 * @param $str
857 * Raw message with tokens
858 * @param $contact
859 * CiviCRM contact array
860 * @return mixed
861 */
862 private function replaceTokens($str, $contact) {
863 $tokens = wf_crm_get_fields('tokens');
864 $values = array();
865 foreach ($tokens as $k => &$t) {
866 if (empty($contact[$k])) {
867 $contact[$k] = '';
868 }
869 $value = $contact[$k];
870 if (is_array($value)) {
871 $value = implode(', ', $value);
872 }
873 $values[] = implode(' &amp; ', wf_crm_explode_multivalue_str(check_plain($value)));
874 $t = "[$t]";
875 }
876 return str_ireplace($tokens, $values, $str);
877 }
878
879 }