Contribution.php 62.9 KB
Newer Older
totten's avatar
totten committed
1
2
3
<?php
/*
 +--------------------------------------------------------------------+
Kurund Jalmi's avatar
Kurund Jalmi committed
4
 | CiviCRM version 4.7                                                |
totten's avatar
totten committed
5
 +--------------------------------------------------------------------+
colemanw's avatar
colemanw committed
6
 | Copyright CiviCRM LLC (c) 2004-2015                                |
totten's avatar
totten committed
7
8
9
10
11
12
13
 +--------------------------------------------------------------------+
 | This file is a part of CiviCRM.                                    |
 |                                                                    |
 | CiviCRM is free software; you can copy, modify, and distribute it  |
 | under the terms of the GNU Affero General Public License           |
 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
 |                                                                    |
Eileen McNaughton's avatar
Eileen McNaughton committed
14
 | CiviCRM is distributed in the hope that it will be useful, but   |
totten's avatar
totten committed
15
16
17
18
19
20
21
22
23
24
25
 | WITHOUT ANY WARRANTY; without even the implied warranty of         |
 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
 | See the GNU Affero General Public License for more details.        |
 |                                                                    |
 | You should have received a copy of the GNU Affero General Public   |
 | License and the CiviCRM Licensing Exception along                  |
 | with this program; if not, contact CiviCRM LLC                     |
 | at info[AT]civicrm[DOT]org. If you have questions about the        |
 | GNU Affero General Public License or the licensing of CiviCRM,     |
 | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
 +--------------------------------------------------------------------+
26
 */
totten's avatar
totten committed
27

28
29
use Civi\Payment\Exception\PaymentProcessorException;

totten's avatar
totten committed
30
/**
Eileen McNaughton's avatar
Eileen McNaughton committed
31
 * This class generates form components for processing a contribution.
totten's avatar
totten committed
32
33
34
 */
class CRM_Contribute_Form_Contribution extends CRM_Contribute_Form_AbstractEditPayment {
  /**
35
   * The id of the contribution that we are processing.
totten's avatar
totten committed
36
37
38
39
40
41
   *
   * @var int
   */
  public $_id;

  /**
42
   * The id of the premium that we are processing.
totten's avatar
totten committed
43
44
45
46
   *
   * @var int
   */
  public $_premiumID = NULL;
47
48
49
50

  /**
   * @var CRM_Contribute_DAO_ContributionProduct
   */
totten's avatar
totten committed
51
52
53
  public $_productDAO = NULL;

  /**
54
   * The id of the note.
totten's avatar
totten committed
55
56
57
58
59
60
   *
   * @var int
   */
  public $_noteID;

  /**
61
   * The id of the contact associated with this contribution.
totten's avatar
totten committed
62
63
64
65
66
67
   *
   * @var int
   */
  public $_contactID;

  /**
68
   * The id of the pledge payment that we are processing.
totten's avatar
totten committed
69
70
71
72
73
74
   *
   * @var int
   */
  public $_ppID;

  /**
75
   * Is this contribution associated with an online.
totten's avatar
totten committed
76
77
78
79
80
81
82
   * financial transaction
   *
   * @var boolean
   */
  public $_online = FALSE;

  /**
83
   * Stores all product options.
totten's avatar
totten committed
84
85
86
87
88
   *
   * @var array
   */
  public $_options;

89
90
91
92
93
94
95
  /**
   * Storage of parameters from form
   *
   * @var array
   */
  public $_params;

totten's avatar
totten committed
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  /**
   * Store the contribution Type ID
   *
   * @var array
   */
  public $_contributionType;

  /**
   * The contribution values if an existing contribution
   */
  public $_values;

  /**
   * The pledge values if this contribution is associated with pledge
   */
  public $_pledgeValues;

  public $_contributeMode = 'direct';

  public $_context;

117
  /**
118
   * Parameter with confusing name.
119
120
121
122
123
   * @todo what is it?
   * @var string
   */
  public $_compContext;

totten's avatar
totten committed
124
125
  public $_compId;

126
127
128
129
130
  /**
   * Possible From email addresses
   * @var array
   */
  public $_fromEmails;
131
132
133
134
135
136

  /**
   * ID of from email
   * @var integer
   */
  public $fromEmailId;
137
138

  /**
totten's avatar
totten committed
139
140
141
142
   * Store the line items if price set used.
   */
  public $_lineItems;

143
  /**
colemanw's avatar
colemanw committed
144
   * Line item
145
146
147
148
149
   * @todo explain why we use lineItem & lineItems
   * @var array
   */
  public $_lineItem;

Kurund Jalmi's avatar
Kurund Jalmi committed
150
  /**
Eileen McNaughton's avatar
Eileen McNaughton committed
151
   * @var array soft credit info
Kurund Jalmi's avatar
Kurund Jalmi committed
152
153
154
   */
  public $_softCreditInfo;

totten's avatar
totten committed
155
  protected $_formType;
Eileen McNaughton's avatar
Eileen McNaughton committed
156

monishdeb's avatar
monishdeb committed
157
  public $_honoreeProfileType;
totten's avatar
totten committed
158

159
  /**
colemanw's avatar
colemanw committed
160
   * Array of the payment fields to be displayed in the payment fieldset (pane) in billingBlock.tpl
161
162
163
164
   * this contains all the information to describe these fields from quickform. See CRM_Core_Form_Payment getPaymentFormFieldsMetadata
   *
   * @var array
   */
totten's avatar
totten committed
165
  public $_paymentFields = array();
166
  /**
167
   * Logged in user's email.
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
   * @var string
   */
  public $userEmail;

  /**
   * Price set ID
   * @var integer
   */
  public $_priceSetId;

  /**
   * Price set as an array
   * @var array
   */
  public $_priceSet;

184
185
186
187
188
189
  /**
   * User display name
   *
   * @var string
   */
  public $userDisplayName;
totten's avatar
totten committed
190

191
192
193
  /**
   * Status message to be shown to the user.
   *
194
   * @var array
195
   */
196
  protected $statusMessage = array();
197
198
199
200
201
202
203
204
205
206
207

  /**
   * Status message title to be shown to the user.
   *
   * Generally the payment processor message title is 'Complete' and offline is 'Saved'
   * although this might not be a good fit with the broad range of processors.
   *
   * @var string
   */
  protected $statusMessageTitle;

totten's avatar
totten committed
208
  /**
Eileen McNaughton's avatar
Eileen McNaughton committed
209
   * Set variables up before form is built.
totten's avatar
totten committed
210
211
   */
  public function preProcess() {
212
    // Check permission for action.
totten's avatar
totten committed
213
    if (!CRM_Core_Permission::checkActionPermission('CiviContribute', $this->_action)) {
214
      CRM_Core_Error::fatal(ts('You do not have permission to access this page.'));
totten's avatar
totten committed
215
216
    }

217
218
    parent::preProcess();

totten's avatar
totten committed
219
220
    $this->_formType = CRM_Utils_Array::value('formType', $_GET);

221
    // Get price set id.
totten's avatar
totten committed
222
223
224
225
    $this->_priceSetId = CRM_Utils_Array::value('priceSetId', $_GET);
    $this->set('priceSetId', $this->_priceSetId);
    $this->assign('priceSetId', $this->_priceSetId);

226
    // Get the pledge payment id
totten's avatar
totten committed
227
228
229
230
    $this->_ppID = CRM_Utils_Request::retrieve('ppid', 'Positive', $this);

    $this->assign('action', $this->_action);

231
    // Get the contribution id if update
totten's avatar
totten committed
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
    $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
    if (!empty($this->_id)) {
      $this->assign('contribID', $this->_id);
    }

    $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this);
    $this->assign('context', $this->_context);

    $this->_compId = CRM_Utils_Request::retrieve('compId', 'Positive', $this);

    $this->_compContext = CRM_Utils_Request::retrieve('compContext', 'String', $this);

    //set the contribution mode.
    $this->_mode = CRM_Utils_Request::retrieve('mode', 'String', $this);

    $this->assign('contributionMode', $this->_mode);
248
249
250
    if ($this->_action & CRM_Core_Action::DELETE) {
      return;
    }
totten's avatar
totten committed
251
252
253
254

    $this->assign('showCheckNumber', TRUE);

    $this->_fromEmails = CRM_Core_BAO_Email::getFromEmail();
255
    $this->assignPaymentRelatedVariables();
totten's avatar
totten committed
256

257
    if (in_array('CiviPledge', CRM_Core_Config::singleton()->enableComponents) && !$this->_formType) {
totten's avatar
totten committed
258
259
260
      $this->preProcessPledge();
    }

261
262
263
    if ($this->_id) {
      $this->showRecordLinkMesssage($this->_id);
    }
totten's avatar
totten committed
264
265
    $this->_values = array();

266
    // Current contribution id.
totten's avatar
totten committed
267
268
269
270
271
272
    if ($this->_id) {
      $this->assignPremiumProduct($this->_id);
      $this->buildValuesAndAssignOnline_Note_Type($this->_id, $this->_values);
    }

    // when custom data is included in this page
273
    if (!empty($_POST['hidden_custom'])) {
totten's avatar
totten committed
274
275
276
277
278
279
280
281
282
283
      $this->applyCustomData('Contribution', CRM_Utils_Array::value('financial_type_id', $_POST), $this->_id);
    }

    $this->_lineItems = array();
    if ($this->_id) {
      if (!empty($this->_compId) && $this->_compContext == 'participant') {
        $this->assign('compId', $this->_compId);
        $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_compId);
      }
      else {
284
        $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_id, 'contribution', 1, TRUE, TRUE);
totten's avatar
totten committed
285
286
287
288
289
290
291
      }
      empty($lineItem) ? NULL : $this->_lineItems[] = $lineItem;
    }

    $this->assign('lineItem', empty($this->_lineItems) ? FALSE : $this->_lineItems);

    // Set title
292
293
294
295
296
    if ($this->_mode) {
      $this->setPageTitle($this->_ppID ? ts('Credit Card Pledge Payment') : ts('Credit Card Contribution'));
    }
    else {
      $this->setPageTitle($this->_ppID ? ts('Pledge Payment') : ts('Contribution'));
totten's avatar
totten committed
297
    }
monishdeb's avatar
monishdeb committed
298
299
300
301

    if ($this->_id) {
      CRM_Contribute_Form_SoftCredit::preprocess($this);
    }
totten's avatar
totten committed
302
303
  }

304
305
306
307
308
  /**
   * Set default values.
   *
   * @return array
   */
309
  public function setDefaultValues() {
totten's avatar
totten committed
310
311
312

    $defaults = $this->_values;

313
    // Set defaults for pledge payment.
totten's avatar
totten committed
314
315
316
317
318
319
320
321
322
323
324
    if ($this->_ppID) {
      $defaults['total_amount'] = CRM_Utils_Array::value('scheduled_amount', $this->_pledgeValues['pledgePayment']);
      $defaults['financial_type_id'] = CRM_Utils_Array::value('financial_type_id', $this->_pledgeValues);
      $defaults['currency'] = CRM_Utils_Array::value('currency', $this->_pledgeValues);
      $defaults['option_type'] = 1;
    }

    if ($this->_action & CRM_Core_Action::DELETE) {
      return $defaults;
    }

325
326
327
    $defaults['frequency_interval'] = 1;
    $defaults['frequency_unit'] = 'month';

328
    // Set soft credit defaults.
Kurund Jalmi's avatar
Kurund Jalmi committed
329
    CRM_Contribute_Form_SoftCredit::setDefaultValues($defaults, $this);
Kurund Jalmi's avatar
Kurund Jalmi committed
330

totten's avatar
totten committed
331
332
    if ($this->_mode) {
      $config = CRM_Core_Config::singleton();
333
      // Set default country from config if no country set.
334
      if (empty($defaults["billing_country_id-{$this->_bltID}"])) {
totten's avatar
totten committed
335
336
        $defaults["billing_country_id-{$this->_bltID}"] = $config->defaultContactCountry;
      }
eileen's avatar
eileen committed
337

338
      if (empty($defaults["billing_state_province_id-{$this->_bltID}"])) {
totten's avatar
totten committed
339
340
341
        $defaults["billing_state_province_id-{$this->_bltID}"] = $config->defaultContactStateProvince;
      }

Dave Greenberg's avatar
Dave Greenberg committed
342
343
      $billingDefaults = $this->getProfileDefaults('Billing', $this->_contactID);
      $defaults = array_merge($defaults, $billingDefaults);
totten's avatar
totten committed
344
345
346
347
348
    }

    if ($this->_id) {
      $this->_contactID = $defaults['contact_id'];
    }
eileen's avatar
eileen committed
349

350
    // Set $newCredit variable in template to control whether link to credit card mode is included.
351
    $this->assign('newCredit', CRM_Core_Config::isEnabledBackOfficeCreditCardPayments());
eileen's avatar
eileen committed
352

353
    // Fix the display of the monetary value, CRM-4038.
totten's avatar
totten committed
354
    if (isset($defaults['total_amount'])) {
355
      if (!empty($defaults['tax_amount'])) {
356
357
358
359
        $componentDetails = CRM_Contribute_BAO_Contribution::getComponentDetails($this->_id);
        if (!(CRM_Utils_Array::value('membership', $componentDetails) || CRM_Utils_Array::value('participant', $componentDetails))) {
          $defaults['total_amount'] = CRM_Utils_Money::format($defaults['total_amount'] - $defaults['tax_amount'], NULL, '%a');
        }
360
361
362
363
      }
      else {
        $defaults['total_amount'] = CRM_Utils_Money::format($defaults['total_amount'], NULL, '%a');
      }
totten's avatar
totten committed
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
    }

    if (isset($defaults['non_deductible_amount'])) {
      $defaults['non_deductible_amount'] = CRM_Utils_Money::format($defaults['non_deductible_amount'], NULL, '%a');
    }

    if (isset($defaults['fee_amount'])) {
      $defaults['fee_amount'] = CRM_Utils_Money::format($defaults['fee_amount'], NULL, '%a');
    }

    if (isset($defaults['net_amount'])) {
      $defaults['net_amount'] = CRM_Utils_Money::format($defaults['net_amount'], NULL, '%a');
    }

    if ($this->_contributionType) {
      $defaults['financial_type_id'] = $this->_contributionType;
    }
381

382
    if (empty($defaults['payment_instrument_id'])) {
383
384
      $defaults['payment_instrument_id'] = key(CRM_Core_OptionGroup::values('payment_instrument', FALSE, FALSE, FALSE, 'AND is_default = 1'));
    }
totten's avatar
totten committed
385

386
    if (!empty($defaults['is_test'])) {
totten's avatar
totten committed
387
388
389
390
      $this->assign('is_test', TRUE);
    }

    $this->assign('showOption', TRUE);
391
    // For Premium section.
totten's avatar
totten committed
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
    if ($this->_premiumID) {
      $this->assign('showOption', FALSE);
      $options = isset($this->_options[$this->_productDAO->product_id]) ? $this->_options[$this->_productDAO->product_id] : "";
      if (!$options) {
        $this->assign('showOption', TRUE);
      }
      $options_key = CRM_Utils_Array::key($this->_productDAO->product_option, $options);
      if ($options_key) {
        $defaults['product_name'] = array($this->_productDAO->product_id, trim($options_key));
      }
      else {
        $defaults['product_name'] = array($this->_productDAO->product_id);
      }
      if ($this->_productDAO->fulfilled_date) {
        list($defaults['fulfilled_date']) = CRM_Utils_Date::setDateDefaults($this->_productDAO->fulfilled_date);
      }
    }

    if (isset($this->userEmail)) {
      $this->assign('email', $this->userEmail);
    }

414
    if (!empty($defaults['is_pay_later'])) {
totten's avatar
totten committed
415
416
417
418
      $this->assign('is_pay_later', TRUE);
    }
    $this->assign('contribution_status_id', CRM_Utils_Array::value('contribution_status_id', $defaults));

Eileen McNaughton's avatar
Eileen McNaughton committed
419
420
421
422
423
    $dates = array(
      'receive_date',
      'receipt_date',
      'cancel_date',
      'thankyou_date',
424
    );
totten's avatar
totten committed
425
    foreach ($dates as $key) {
426
      if (!empty($defaults[$key])) {
427
428
        list($defaults[$key], $defaults[$key . '_time'])
          = CRM_Utils_Date::setDateDefaults(CRM_Utils_Array::value($key, $defaults), 'activityDateTime');
totten's avatar
totten committed
429
430
431
      }
    }

432
    if (!$this->_id && empty($defaults['receive_date'])) {
totten's avatar
totten committed
433
434
435
436
437
438
439
440
441
442
      list($defaults['receive_date'],
        $defaults['receive_date_time']
        ) = CRM_Utils_Date::setDateDefaults(NULL, 'activityDateTime');
    }

    $this->assign('receive_date', CRM_Utils_Date::processDate(CRM_Utils_Array::value('receive_date', $defaults),
      CRM_Utils_Array::value('receive_date_time', $defaults)
    ));
    $currency = CRM_Utils_Array::value('currency', $defaults);
    $this->assign('currency', $currency);
443
    // Hack to get currency info to the js layer. CRM-11440.
totten's avatar
totten committed
444
445
446
447
    CRM_Utils_Money::format(1);
    $this->assign('currencySymbol', CRM_Utils_Array::value($currency, CRM_Utils_Money::$_currencySymbols));
    $this->assign('totalAmount', CRM_Utils_Array::value('total_amount', $defaults));

448
    // Inherit campaign from pledge.
449
    if ($this->_ppID && !empty($this->_pledgeValues['campaign_id'])) {
totten's avatar
totten committed
450
451
452
453
454
455
456
457
      $defaults['campaign_id'] = $this->_pledgeValues['campaign_id'];
    }

    $this->_defaults = $defaults;
    return $defaults;
  }

  /**
458
   * Build the form object.
totten's avatar
totten committed
459
460
   */
  public function buildQuickForm() {
461

462
    $allPanes = array();
463
    $recurJs = NULL;
464
    //tax rate from financialType
465
    $this->assign('taxRates', json_encode(CRM_Core_PseudoConstant::getTaxRates()));
466
    $this->assign('currencies', json_encode(CRM_Core_OptionGroup::values('currencies_enabled')));
totten's avatar
totten committed
467
468
469

    // build price set form.
    $buildPriceSet = FALSE;
totten's avatar
totten committed
470
    $invoiceSettings = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME, 'contribution_invoice_settings');
471
    $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings);
472
    $this->assign('invoicing', $invoicing);
473

474
475
    // display tax amount on edit contribution page
    if ($invoicing && $this->_action & CRM_Core_Action::UPDATE && isset($this->_values['tax_amount'])) {
476
477
478
      $this->assign('totalTaxAmount', $this->_values['tax_amount']);
    }

totten's avatar
totten committed
479
    if (empty($this->_lineItems) &&
480
      ($this->_priceSetId || !empty($_POST['price_set_id']))
totten's avatar
totten committed
481
482
483
484
485
486
487
488
489
    ) {
      $buildPriceSet = TRUE;
      $getOnlyPriceSetElements = TRUE;
      if (!$this->_priceSetId) {
        $this->_priceSetId = $_POST['price_set_id'];
        $getOnlyPriceSetElements = FALSE;
      }

      $this->set('priceSetId', $this->_priceSetId);
490
      CRM_Price_BAO_PriceSet::buildPriceSet($this);
totten's avatar
totten committed
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506

      // get only price set form elements.
      if ($getOnlyPriceSetElements) {
        return;
      }
    }
    // use to build form during form rule.
    $this->assign('buildPriceSet', $buildPriceSet);

    $defaults = $this->_values;
    $additionalDetailFields = array(
      'note',
      'thankyou_date',
      'invoice_id',
      'non_deductible_amount',
      'fee_amount',
Kurund Jalmi's avatar
Kurund Jalmi committed
507
      'net_amount',
totten's avatar
totten committed
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
    );
    foreach ($additionalDetailFields as $key) {
      if (!empty($defaults[$key])) {
        $defaults['hidden_AdditionalDetail'] = 1;
        break;
      }
    }

    if ($this->_productDAO) {
      if ($this->_productDAO->product_id) {
        $defaults['hidden_Premium'] = 1;
      }
    }

    if ($this->_noteID &&
      isset($this->_values['note'])
    ) {
      $defaults['hidden_AdditionalDetail'] = 1;
    }

    $paneNames = array(
      ts('Additional Details') => 'AdditionalDetail',
    );

    //Add Premium pane only if Premium is exists.
    $dao = new CRM_Contribute_DAO_Product();
    $dao->is_active = 1;

    if ($dao->find(TRUE)) {
      $paneNames[ts('Premium Information')] = 'Premium';
    }

    if ($this->_mode) {
541
      if (CRM_Core_Payment_Form::buildPaymentForm($this, $this->_paymentProcessor, FALSE, TRUE) == TRUE) {
542
        if (!empty($this->_recurPaymentProcessors)) {
543
          $buildRecurBlock = TRUE;
Eileen McNaughton's avatar
Eileen McNaughton committed
544
          if ($this->_ppID) {
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
            // ppID denotes a pledge payment.
            foreach ($this->_paymentProcessors as $processor) {
              if (!empty($processor['is_recur']) && !empty($processor['object']) && $processor['object']->supports('recurContributionsForPledges')) {
                $buildRecurBlock = TRUE;
                break;
              }
              $buildRecurBlock = FALSE;
            }
          }
          if ($buildRecurBlock) {
            CRM_Contribute_Form_Contribution_Main::buildRecur($this);
            $this->setDefaults(array('is_recur' => 0));
            $this->assign('buildRecurBlock', TRUE);
            $recurJs = array('onChange' => "buildRecurBlock( this.value ); return false;");
          }
560
        }
totten's avatar
totten committed
561
562
563
564
      }
    }

    foreach ($paneNames as $name => $type) {
565
      $allPanes[$name] = $this->generatePane($type, $defaults);
totten's avatar
totten committed
566
    }
567

totten's avatar
totten committed
568
569
570
571
    $qfKey = $this->controller->_key;
    $this->assign('qfKey', $qfKey);
    $this->assign('allPanes', $allPanes);

Kurund Jalmi's avatar
Kurund Jalmi committed
572
573
    $this->addFormRule(array('CRM_Contribute_Form_Contribution', 'formRule'), $this);

totten's avatar
totten committed
574
575
576
577
578
579
    if ($this->_formType) {
      $this->assign('formType', $this->_formType);
      return;
    }

    $this->applyFilter('__ALL__', 'trim');
eileen's avatar
eileen committed
580

totten's avatar
totten committed
581
582
583
584
585
586
587
588
589
590
    if ($this->_action & CRM_Core_Action::DELETE) {
      $this->addButtons(array(
          array(
            'type' => 'next',
            'name' => ts('Delete'),
            'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
            'isDefault' => TRUE,
          ),
          array(
            'type' => 'cancel',
591
592
            'name' => ts('Cancel'),
          ),
totten's avatar
totten committed
593
594
595
596
597
598
599
600
601
602
603
        )
      );
      return;
    }

    //need to assign custom data type and subtype to the template
    $this->assign('customDataType', 'Contribution');
    $this->assign('customDataSubType', $this->_contributionType);
    $this->assign('entityID', $this->_id);

    if ($this->_context == 'standalone') {
totten's avatar
totten committed
604
605
      $this->addEntityRef('contact_id', ts('Contact'), array(
          'create' => TRUE,
Web Access's avatar
Web Access committed
606
          'api' => array('extra' => array('email')),
totten's avatar
totten committed
607
        ), TRUE);
totten's avatar
totten committed
608
609
610
611
612
613
614
    }

    $attributes = CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Contribution');

    $financialType = $this->add('select', 'financial_type_id',
      ts('Financial Type'),
      array('' => ts('- select -')) + CRM_Contribute_PseudoConstant::financialType(),
615
616
      TRUE,
      array('onChange' => "CRM.buildCustomData( 'Contribution', this.value );")
totten's avatar
totten committed
617
    );
618
    $paymentInstrument = FALSE;
totten's avatar
totten committed
619
620
    if (!$this->_mode) {
      $paymentInstrument = $this->add('select', 'payment_instrument_id',
621
        ts('Payment Method'),
totten's avatar
totten committed
622
        array('' => ts('- select -')) + CRM_Contribute_PseudoConstant::paymentInstrument(),
623
        TRUE, array('onChange' => "return showHideByValue('payment_instrument_id','4','checkNumber','table-row','select',false);")
totten's avatar
totten committed
624
625
626
      );
    }

627
    $trxnId = $this->add('text', 'trxn_id', ts('Transaction ID'), array('class' => 'twelve') + $attributes['trxn_id']);
totten's avatar
totten committed
628
629
630
631
632
633
634
635
636
637
638
639
640
641

    //add receipt for offline contribution
    $this->addElement('checkbox', 'is_email_receipt', ts('Send Receipt?'));

    $this->add('select', 'from_email_address', ts('Receipt From'), $this->_fromEmails);

    $status = CRM_Contribute_PseudoConstant::contributionStatus();

    // suppressing contribution statuses that are NOT relevant to pledges (CRM-5169)
    $statusName = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
    if ($this->_ppID) {
      foreach (array(
                 'Cancelled',
                 'Failed',
642
                 'In Progress',
totten's avatar
totten committed
643
644
645
646
647
               ) as $suppress) {
        unset($status[CRM_Utils_Array::key($suppress, $statusName)]);
      }
    }
    elseif ((!$this->_ppID && $this->_id) || !$this->_id) {
648
649
650
651
652
653
654
655
656
657
      $suppressFlag = FALSE;
      if ($this->_id) {
        $componentDetails = CRM_Contribute_BAO_Contribution::getComponentDetails($this->_id);
        if (CRM_Utils_Array::value('membership', $componentDetails) || CRM_Utils_Array::value('participant', $componentDetails)) {
          $suppressFlag = TRUE;
        }
      }
      if (!$suppressFlag) {
        foreach (array(
                   'Overdue',
658
                   'In Progress',
659
660
661
662
663
664
                 ) as $suppress) {
          unset($status[CRM_Utils_Array::key($suppress, $statusName)]);
        }
      }
      else {
        unset($status[CRM_Utils_Array::key('Overdue', $statusName)]);
totten's avatar
totten committed
665
666
      }
    }
667

totten's avatar
totten committed
668
669
670
    if ($this->_id) {
      $contributionStatus = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $this->_id, 'contribution_status_id');
      $name = CRM_Utils_Array::value($contributionStatus, $statusName);
yashodha's avatar
yashodha committed
671
      switch ($name) {
totten's avatar
totten committed
672
673
674
        case 'Completed':
        case 'Cancelled':
        case 'Refunded':
675
          unset($status[CRM_Utils_Array::key('In Progress', $statusName)]);
totten's avatar
totten committed
676
677
678
          unset($status[CRM_Utils_Array::key('Pending', $statusName)]);
          unset($status[CRM_Utils_Array::key('Failed', $statusName)]);
          break;
totten's avatar
totten committed
679

totten's avatar
totten committed
680
        case 'Pending':
681
        case 'In Progress':
totten's avatar
totten committed
682
683
          unset($status[CRM_Utils_Array::key('Refunded', $statusName)]);
          break;
totten's avatar
totten committed
684

totten's avatar
totten committed
685
        case 'Failed':
yashodha's avatar
yashodha committed
686
687
688
689
          foreach (array(
                     'Pending',
                     'Refunded',
                     'Completed',
690
                     'In Progress',
691
                     'Cancelled',
yashodha's avatar
yashodha committed
692
                   ) as $suppress) {
totten's avatar
totten committed
693
694
695
696
            unset($status[CRM_Utils_Array::key($suppress, $statusName)]);
          }
          break;
      }
yashodha's avatar
yashodha committed
697
698
    }
    else {
totten's avatar
totten committed
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
      unset($status[CRM_Utils_Array::key('Refunded', $statusName)]);
    }

    $this->add('select', 'contribution_status_id',
      ts('Contribution Status'),
      $status,
      FALSE
    );

    // add various dates
    $this->addDateTime('receive_date', ts('Received'), FALSE, array('formatType' => 'activityDateTime'));

    if ($this->_online) {
      $this->assign('hideCalender', TRUE);
    }
    $checkNumber = $this->add('text', 'check_number', ts('Check Number'), $attributes['check_number']);

    $this->addDateTime('receipt_date', ts('Receipt Date'), FALSE, array('formatType' => 'activityDateTime'));
    $this->addDateTime('cancel_date', ts('Cancelled / Refunded Date'), FALSE, array('formatType' => 'activityDateTime'));

    $this->add('textarea', 'cancel_reason', ts('Cancellation / Refund Reason'), $attributes['cancel_reason']);

    $element = $this->add('select',
      'payment_processor_id',
      ts('Payment Processor'),
      $this->_processors,
      NULL,
      $recurJs
    );

    if ($this->_online) {
      $element->freeze();
    }
732

totten's avatar
totten committed
733
734
735
    $totalAmount = NULL;
    if (empty($this->_lineItems)) {
      $buildPriceSet = FALSE;
736
      $priceSets = CRM_Price_BAO_PriceSet::getAssoc(FALSE, 'CiviContribute');
totten's avatar
totten committed
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
      if (!empty($priceSets) && !$this->_ppID) {
        $buildPriceSet = TRUE;
      }

      // don't allow price set for contribution if it is related to participant, or if it is a pledge payment
      // and if we already have line items for that participant. CRM-5095
      if ($buildPriceSet && $this->_id) {
        $componentDetails = CRM_Contribute_BAO_Contribution::getComponentDetails($this->_id);
        $pledgePaymentId = CRM_Core_DAO::getFieldValue('CRM_Pledge_DAO_PledgePayment',
          $this->_id,
          'id',
          'contribution_id'
        );
        if ($pledgePaymentId) {
          $buildPriceSet = FALSE;
        }
        if ($participantID = CRM_Utils_Array::value('participant', $componentDetails)) {
          $participantLI = CRM_Price_BAO_LineItem::getLineItems($participantID);
          if (!CRM_Utils_System::isNull($participantLI)) {
            $buildPriceSet = FALSE;
          }
        }
      }

      $hasPriceSets = FALSE;
      if ($buildPriceSet) {
        $hasPriceSets = TRUE;
Web Access's avatar
Web Access committed
764
765
766
        // CRM-16451: set financial type of 'Price Set' in back office contribution
        // instead of selecting manually
        $financialTypeIds = CRM_Price_BAO_PriceSet::getAssoc(FALSE, 'CiviContribute', 'financial_type_id');
totten's avatar
totten committed
767
768
        $element = $this->add('select', 'price_set_id', ts('Choose price set'),
          array(
769
            '' => ts('Choose price set'),
totten's avatar
totten committed
770
          ) + $priceSets,
Web Access's avatar
Web Access committed
771
          NULL, array('onchange' => "buildAmount( this.value, " . json_encode($financialTypeIds) . ");")
eileen's avatar
eileen committed
772
        );
totten's avatar
totten committed
773
774
775
776
777
778
779
        if ($this->_online && !($this->_action & CRM_Core_Action::UPDATE)) {
          $element->freeze();
        }
      }
      $this->assign('hasPriceSets', $hasPriceSets);
      $currencyFreeze = FALSE;
      if (!($this->_action & CRM_Core_Action::UPDATE)) {
yashodha's avatar
yashodha committed
780
781
782
        if ($this->_online || $this->_ppID) {
          $attributes['total_amount'] = array_merge($attributes['total_amount'], array(
            'READONLY' => TRUE,
783
            'style' => "background-color:#EBECE4",
yashodha's avatar
yashodha committed
784
785
786
787
788
789
790
791
792
793
794
795
796
          ));
          $optionTypes = array(
            '1' => ts('Adjust Pledge Payment Schedule?'),
            '2' => ts('Adjust Total Pledge Amount?'),
          );
          $this->addRadio('option_type',
            NULL,
            $optionTypes,
            array(), '<br/>'
          );

          $currencyFreeze = TRUE;
        }
totten's avatar
totten committed
797
798
799
800
801
802
803
804
805
806
807
808
      }

      $totalAmount = $this->addMoney('total_amount',
        ts('Total Amount'),
        ($hasPriceSets) ? FALSE : TRUE,
        $attributes['total_amount'],
        TRUE, 'currency', NULL, $currencyFreeze
      );
    }

    $this->add('text', 'source', ts('Source'), CRM_Utils_Array::value('source', $attributes));

Eileen McNaughton's avatar
Eileen McNaughton committed
809
    // CRM-7362 --add campaigns.
totten's avatar
totten committed
810
811
    CRM_Campaign_BAO_Campaign::addCampaign($this, CRM_Utils_Array::value('campaign_id', $this->_values));

yashodha's avatar
yashodha committed
812
813
    CRM_Contribute_Form_SoftCredit::buildQuickForm($this);

totten's avatar
totten committed
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
    $js = NULL;
    if (!$this->_mode) {
      $js = array('onclick' => "return verify( );");
    }

    $mailingInfo = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
      'mailing_backend'
    );
    $this->assign('outBound_option', $mailingInfo['outBound_option']);

    $this->addButtons(array(
        array(
          'type' => 'upload',
          'name' => ts('Save'),
          'js' => $js,
829
          'isDefault' => TRUE,
totten's avatar
totten committed
830
831
832
833
834
        ),
        array(
          'type' => 'upload',
          'name' => ts('Save and New'),
          'js' => $js,
835
          'subName' => 'new',
totten's avatar
totten committed
836
837
838
        ),
        array(
          'type' => 'cancel',
839
          'name' => ts('Cancel'),
totten's avatar
totten committed
840
841
842
843
844
845
846
        ),
      )
    );

    // if status is Cancelled freeze Amount, Payment Instrument, Check #, Financial Type,
    // Net and Fee Amounts are frozen in AdditionalInfo::buildAdditionalDetail
    if ($this->_id && $this->_values['contribution_status_id'] == array_search('Cancelled', $statusName)) {
eileen's avatar
eileen committed
847
      if ($totalAmount) {
totten's avatar
totten committed
848
849
850
851
852
853
854
855
        $totalAmount->freeze();
      }
      $checkNumber->freeze();
      $paymentInstrument->freeze();
      $trxnId->freeze();
      $financialType->freeze();
    }

856
857
858
859
    // if contribution is related to membership or participant freeze Financial Type, Amount
    if ($this->_id && isset($this->_values['tax_amount'])) {
      $componentDetails = CRM_Contribute_BAO_Contribution::getComponentDetails($this->_id);
      if (CRM_Utils_Array::value('membership', $componentDetails) || CRM_Utils_Array::value('participant', $componentDetails)) {
860
        if ($totalAmount) {
totten's avatar
totten committed
861
          $totalAmount->freeze();
862
        }
863
864
865
866
867
        $financialType->freeze();
        $this->assign('freezeFinancialType', TRUE);
      }
    }

totten's avatar
totten committed
868
869
870
871
872
873
    if ($this->_action & CRM_Core_Action::VIEW) {
      $this->freeze();
    }
  }

  /**
874
   * Global form rule.
totten's avatar
totten committed
875
   *
876
877
878
879
   * @param array $fields
   *   The input form values.
   * @param array $files
   *   The uploaded files if any.
Eileen McNaughton's avatar
Eileen McNaughton committed
880
881
   * @param $self
   *
882
883
   * @return bool|array
   *   true if no errors, else array of errors
totten's avatar
totten committed
884
   */
885
  public static function formRule($fields, $files, $self) {
totten's avatar
totten committed
886
    $errors = array();
Eileen McNaughton's avatar
Eileen McNaughton committed
887
    // Check for Credit Card Contribution.
totten's avatar
totten committed
888
889
890
891
    if ($self->_mode) {
      if (empty($fields['payment_processor_id'])) {
        $errors['payment_processor_id'] = ts('Payment Processor is a required field.');
      }
892
893
894
895
      else {
        // validate payment instrument (e.g. credit card number)
        CRM_Core_Payment_Form::validatePaymentInstrument($fields['payment_processor_id'], $fields, $errors, $self);
      }
totten's avatar
totten committed
896
897
    }

Eileen McNaughton's avatar
Eileen McNaughton committed
898
    // Do the amount validations.
899
    if (empty($fields['total_amount']) && empty($self->_lineItems)) {
totten's avatar
totten committed
900
      if ($priceSetId = CRM_Utils_Array::value('price_set_id', $fields)) {
901
        CRM_Price_BAO_PriceField::priceSetValidation($priceSetId, $fields, $errors);
totten's avatar
totten committed
902
903
904
      }
    }

905
    $softErrors = CRM_Contribute_Form_SoftCredit::formRule($fields, $errors, $self);
yashodha's avatar
yashodha committed
906

907
908
    if (!empty($fields['total_amount']) && (!empty($fields['net_amount']) || !empty($fields['fee_amount']))) {
      $sum = CRM_Utils_Rule::cleanMoney($fields['net_amount']) + CRM_Utils_Rule::cleanMoney($fields['fee_amount']);
909
910
911
912
913
914
915
916
917
918
      // For taxable contribution we need to deduct taxable amount from
      // (net amount + fee amount) before comparing it with total amount
      if (!empty($self->_values['tax_amount'])) {
        $componentDetails = CRM_Contribute_BAO_Contribution::getComponentDetails($self->_id);
        if (!(CRM_Utils_Array::value('membership', $componentDetails) ||
            CRM_Utils_Array::value('participant', $componentDetails))
        ) {
          $sum = CRM_Utils_Money::format($sum - $self->_values['tax_amount'], NULL, '%a');
        }
      }
919
      if (CRM_Utils_Rule::cleanMoney($fields['total_amount']) != $sum) {
totten's avatar
totten committed
920
921
922
        $errors['total_amount'] = ts('The sum of fee amount and net amount must be equal to total amount');
      }
    }
923
924
925
926

    //CRM-16285 - Function to handle validation errors on form, for recurring contribution field.
    CRM_Contribute_BAO_ContributionRecur::validateRecurContribution($fields, $files, $self, $errors);

Eileen McNaughton's avatar
Eileen McNaughton committed
927
    // Form rule for status http://wiki.civicrm.org/confluence/display/CRM/CiviAccounts+4.3+Data+Flow
928
929
930
931
    if (($self->_action & CRM_Core_Action::UPDATE)
      && $self->_id
      && $self->_values['contribution_status_id'] != $fields['contribution_status_id']
    ) {
totten's avatar
totten committed
932
933
      CRM_Contribute_BAO_Contribution::checkStatusValidation($self->_values, $fields, $errors);
    }
934
    // CRM-16015, add form-rule to restrict change of financial type if using price field of different financial type
935
936
937
938
    if (($self->_action & CRM_Core_Action::UPDATE)
      && $self->_id
      && $self->_values['financial_type_id'] != $fields['financial_type_id']
    ) {
939
940
      CRM_Contribute_BAO_Contribution::checkFinancialTypeChange(NULL, $self->_id, $errors);
    }
totten's avatar
totten committed
941
    //FIXME FOR NEW DATA FLOW http://wiki.civicrm.org/confluence/display/CRM/CiviAccounts+4.3+Data+Flow
942
    if (!empty($fields['fee_amount']) && !empty($fields['financial_type_id']) && $financialType = CRM_Contribute_BAO_Contribution::validateFinancialType($fields['financial_type_id'])) {
943
      $errors['financial_type_id'] = ts("Financial Account of account relationship of 'Expense Account is' is not configured for Financial Type : ") . $financialType;
totten's avatar
totten committed
944
    }
945

946
947
948
949
950
    // $trxn_id must be unique CRM-13919
    if (!empty($fields['trxn_id'])) {
      $queryParams = array(1 => array($fields['trxn_id'], 'String'));
      $query = 'select count(*) from civicrm_contribution where trxn_id = %1';
      if ($self->_id) {
totten's avatar
totten committed
951
        $queryParams[2] = array((int) $self->_id, 'Integer');
952
953
954
955
956
        $query .= ' and id !=%2';
      }
      $tCnt = CRM_Core_DAO::singleValueQuery($query, $queryParams);
      if ($tCnt) {
        $errors['trxn_id'] = ts('Transaction ID\'s must be unique. Transaction \'%1\' already exists in your database.', array(1 => $fields['trxn_id']));
957
      }
958
    }
yashodha's avatar
yashodha committed
959

yashodha's avatar
yashodha committed
960
    $errors = array_merge($errors, $softErrors);
totten's avatar
totten committed
961
962
963
964
    return $errors;
  }

  /**
965
   * Process the form submission.
totten's avatar
totten committed
966
967
968
969
   */
  public function postProcess() {
    if ($this->_action & CRM_Core_Action::DELETE) {
      CRM_Contribute_BAO_Contribution::deleteContribution($this->_id);
970
      CRM_Core_Session::singleton()->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view',
totten's avatar
totten committed
971
972
973
974
        "reset=1&cid={$this->_contactID}&selectedChild=contribute"
      ));
      return;
    }
colemanw's avatar
colemanw committed
975
    // Get the submitted form values.
totten's avatar
totten committed
976
    $submittedValues = $this->controller->exportValues($this->_name);
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992

    try {
      $contribution = $this->submit($submittedValues, $this->_action, $this->_ppID);
    }
    catch (PaymentProcessorException $e) {
      // Set the contribution mode.
      $urlParams = "action=add&cid={$this->_contactID}";
      if ($this->_mode) {
        $urlParams .= "&mode={$this->_mode}";
      }
      if (!empty($this->_ppID)) {
        $urlParams .= "&context=pledge&ppid={$this->_ppID}";
      }

      CRM_Core_Error::statusBounce($e->getMessage(), $urlParams, ts('Payment Processor Error'));
    }
993
994
995
996
997
998
999
    $session = CRM_Core_Session::singleton();
    $buttonName = $this->controller->getButtonName();
    if ($this->_context == 'standalone') {
      if ($buttonName == $this->getButtonName('upload', 'new')) {
        $session->replaceUserContext(CRM_Utils_System::url('civicrm/contribute/add',
          'reset=1&action=add&context=standalone'
        ));
totten's avatar
totten committed
1000
      }
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
      else {
        $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view',
          "reset=1&cid={$this->_contactID}&selectedChild=contribute"
        ));
      }
    }
    elseif ($this->_context == 'contribution' && $this->_mode && $buttonName == $this->getButtonName('upload', 'new')) {
      $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/contribution',
        "reset=1&action=add&context={$this->_context}&cid={$this->_contactID}&mode={$this->_mode}"
      ));
    }
    elseif ($buttonName == $this->getButtonName('upload', 'new')) {
      $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/contribution',
        "reset=1&action=add&context={$this->_context}&cid={$this->_contactID}"
      ));
totten's avatar
totten committed
1016
1017
    }

1018
1019
1020
    //store contribution ID if not yet set (on create)
    if (empty($this->_id) && !empty($contribution->id)) {
      $this->_id = $contribution->id;
totten's avatar
totten committed
1021
    }
1022
  }
totten's avatar
totten committed
1023

1024
1025
1026
1027
1028
  /**
   * Process credit card payment.
   *
   * @param array $submittedValues
   * @param array $lineItem
Eileen McNaughton's avatar
Eileen McNaughton committed
1029
   *
1030
1031
1032
   * @param int $contactID
   *   Contact ID
   *
Eileen McNaughton's avatar
Eileen McNaughton committed
1033
   * @return bool|\CRM_Contribute_DAO_Contribution
1034
   * @throws \CRM_Core_Exception
1035
   * @throws \Civi\Payment\Exception\PaymentProcessorException
Eileen McNaughton's avatar
Eileen McNaughton committed
1036
   */
1037
  protected function processCreditCard($submittedValues, $lineItem, $contactID) {
Eileen McNaughton's avatar
Eileen McNaughton committed
1038
    $isTest = ($this->_mode == 'test') ? 1 : 0;
1039
    // CRM-12680 set $_lineItem if its not set
1040
1041
1042
    // @todo - I don't believe this would ever BE set. I can't find anywhere in the code.
    // It would be better to pass line item out to functions than $this->_lineItem as
    // we don't know what is being changed where.
1043
1044
    if (empty($this->_lineItem) && !empty($lineItem)) {
      $this->_lineItem = $lineItem;
totten's avatar
totten committed
1045
1046
    }

1047
1048
    $this->_paymentObject = Civi\Payment\System::singleton()->getById($submittedValues['payment_processor_id']);
    $this->_paymentProcessor = $this->_paymentObject->getPaymentProcessor();
1049

1050
1051
1052
1053
1054
1055
1056
1057
1058
    // Set source if not set
    if (empty($submittedValues['source'])) {
      $userID = CRM_Core_Session::singleton()->get('userID');
      $userSortName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $userID,
        'sort_name'
      );
      $submittedValues['source'] = ts('Submit Credit Card Payment by: %1', array(1 => $userSortName));
    }

1059
1060
    $params = $submittedValues;
    $this->_params = array_merge($this->_params, $submittedValues);
1061

1062
1063
1064
    // Mapping requiring documentation.
    $this->_params['payment_processor'] = $submittedValues['payment_processor_id'];

1065
    $now = date('YmdHis');
eileen's avatar
eileen committed
1066

1067
1068
1069
1070
    // we need to retrieve email address
    if ($this->_context == 'standalone' && !empty($submittedValues['is_email_receipt'])) {
      list($this->userDisplayName,
        $this->userEmail
1071
        ) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactID);
1072
      $this->assign('displayName', $this->userDisplayName);
totten's avatar
totten committed
1073
1074
    }

1075
1076
1077
    $this->_contributorEmail = $this->userEmail;
    $this->_contributorContactID = $contactID;
    $this->processBillingAddress();
1078
1079
    if (!empty($params['source'])) {
      unset($params['source']);
totten's avatar
totten committed
1080
    }
1081

1082
1083
    $this->_params['amount'] = $this->_params['total_amount'];
    $this->_params['amount_level'] = 0;
1084
    $this->_params['description'] = ts("Contribution submitted by a staff person using contributor's credit card");
1085
1086
1087
1088
    $this->_params['currencyID'] = CRM_Utils_Array::value('currency',
      $this->_params,
      CRM_Core_Config::singleton()->defaultCurrency
    );
1089

1090
1091
    if (!empty($this->_params['receive_date'])) {
      $this->_params['receive_date'] = CRM_Utils_Date::processDate($this->_params['receive_date'], $this->_params['receive_date_time']);
totten's avatar
totten committed
1092
1093
    }

1094
1095
1096
    $this->_params['pcp_display_in_roll'] = CRM_Utils_Array::value('pcp_display_in_roll', $params);
    $this->_params['pcp_roll_nickname'] = CRM_Utils_Array::value('pcp_roll_nickname', $params);
    $this->_params['pcp_personal_note'] = CRM_Utils_Array::value('pcp_personal_note', $params);
yashodha's avatar
yashodha committed
1097

1098
1099
    //Add common data to formatted params
    CRM_Contribute_Form_AdditionalInfo::postProcessCommon($params, $this->_params, $this);
totten's avatar
totten committed
1100

1101
1102
1103
1104
1105
1106
    if (empty($this->_params['invoice_id'])) {
      $this->_params['invoiceID'] = md5(uniqid(rand(), TRUE));
    }
    else {
      $this->_params['invoiceID'] = $this->_params['invoice_id'];
    }
totten's avatar
totten committed
1107

1108
1109
1110
1111
    // At this point we've created a contact and stored its address etc
    // all the payment processors expect the name and address to be in the
    // so we copy stuff over to first_name etc.
    $paymentParams = $this->_params;
1112
    $paymentParams['contactID'] = $contactID;
1113
    CRM_Core_Payment_Form::mapParams($this->_bltID, $this->_params, $paymentParams, TRUE);
totten's avatar
totten committed
1114

1115
1116
    $financialType = new CRM_Financial_DAO_FinancialType();
    $financialType->id = $params['financial_type_id'];
totten's avatar
totten committed
1117

1118
1119
    // Add some financial type details to the params list
    // if folks need to use it.
1120
    $paymentParams['contributionType_name'] = $this->_params['contributionType_name'] = $financialType->name;
1121
    $paymentParams['contributionPageID'] = NULL;
totten's avatar
totten committed
1122

1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
    if (!empty($this->_params['is_email_receipt'])) {
      $paymentParams['email'] = $this->userEmail;
      $paymentParams['is_email_receipt'] = 1;
    }
    else {
      $paymentParams['is_email_receipt'] = 0;
      $this->_params['is_email_receipt'] = 0;
    }
    if (!empty($this->_params['receive_date'])) {
      $paymentParams['receive_date'] = $this->_params['receive_date'];
    }
totten's avatar
totten committed
1134

1135
    $this->_params['receive_date'] = $now;
totten's avatar
totten committed
1136

1137
1138
1139
1140
1141
1142
1143
1144
    if (!empty($this->_params['is_email_receipt'])) {
      $this->_params['receipt_date'] = $now;
    }
    else {
      $this->_params['receipt_date'] = CRM_Utils_Date::processDate($this->_params['receipt_date'],
        $params['receipt_date_time'], TRUE
      );
    }
totten's avatar
totten committed
1145

1146
    $this->set('params', $this->_params);
1147

1148
    $this->assign('receive_date', $this->_params['receive_date']);
totten's avatar
totten committed
1149

1150
1151
    // Result has all the stuff we need
    // lets archive it to a financial transaction
1152
    if ($financialType->is_deductible) {
1153
1154
1155
      $this->assign('is_deductible', TRUE);
      $this->set('is_deductible', TRUE);
    }
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
    $contributionParams = array(
      'contact_id' => $contactID,
      'line_item' => $lineItem,
      'is_test' => $isTest,
      'campaign_id' => CRM_Utils_Array::value('campaign_id', $this->_params),
      'contribution_page_id' => CRM_Utils_Array::value('contribution_page_id', $this->_params),
      'source' => CRM_Utils_Array::value('source', $paymentParams, CRM_Utils_Array::value('description', $paymentParams)),
      'thankyou_date' => CRM_Utils_Array::value('thankyou_date', $this->_params),
    );

    if (empty($paymentParams['is_pay_later'])) {
      // @todo look up payment_instrument_id on payment processor table.
      $contributionParams['payment_instrument_id'] = 1;
    }
totten's avatar
totten committed
1170

1171
    $contribution = CRM_Contribute_Form_Contribution_Confirm::processFormContribution($this,
1172
1173
      $this->_params,
      NULL,
1174
      $contributionParams,
1175
1176
1177
1178
      $financialType,
      FALSE,
      $this->_bltID
    );
totten's avatar
totten committed
1179

1180
1181
1182
1183
    $paymentParams['contributionID'] = $contribution->id;
    $paymentParams['contributionTypeID'] = $contribution->financial_type_id;
    $paymentParams['contributionPageID'] = $contribution->contribution_page_id;
    $paymentParams['contributionRecurID'] = $contribution->contribution_recur_id;
totten's avatar
totten committed
1184

1185
1186
    if ($paymentParams['amount'] > 0.0) {
      // force a re-get of the payment processor in case the form changed it, CRM-7179
1187
1188
      // NOTE - I expect this is obsolete.
      $payment = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
      try {
        $statuses = CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id');
        $result = $payment->doPayment($paymentParams, 'contribute');
        $this->assign('trxn_id', $result['trxn_id']);
        $contribution->trxn_id = $result['trxn_id'];
        /* Our scenarios here are
         *  1) the payment failed & an Exception should have been thrown
         *  2) the payment succeeded but the payment is not immediate (for example a recurring payment
         *     with a delayed start)
         *  3) the payment succeeded with an immediate payment.
         *
1200
         * The doPayment function ensures that payment_status_id is always set
1201
1202
1203
         * as historically we have had to guess from the context - ie doDirectPayment
         * = error or success, unless it is a recurring contribution in which case it is pending.
         */
1204
        if ($result['payment_status_id'] == array_search('Completed', $statuses)) {
1205
1206
1207
1208
1209
1210
          try {
            civicrm_api3('contribution', 'completetransaction', array(
              'id' => $contribution->id,
              'trxn_id' => $result['trxn_id'],
              'payment_processor_id' => $this->_paymentProcessor['id'],
              'is_transactional' => FALSE,
1211
              'fee_amount' => CRM_Utils_Array::value('fee_amount', $result),
1212
1213
1214
1215