Redsys.php 8.83 KB
Newer Older
1
<?php
sluc23's avatar
sluc23 committed
2
3
4
5
6
7
8
9
/**
 * CiviCRM Payment Processor for Redsys (before called Sermepa).
 *
 * Redsys is a company based in Spain. Many banks are using its
 * payment processor for their payment processors.
 */

require_once 'CRM/Core/Payment.php';
rubofvil's avatar
rubofvil committed
10
require_once 'includes/apiRedsys.php';
sluc23's avatar
sluc23 committed
11
12

class CRM_Core_Payment_Redsys extends CRM_Core_Payment {
sluc23's avatar
sluc23 committed
13
14
15
16
17
18
  CONST REDSYS_CURRENCY_EURO = 978;
  CONST REDSYS_LANGUAGE_SPANISH = 1;
  CONST REDSYS_LANGUAGE_BASQUE = 13;
  CONST REDSYS_LANGUAGE_CATALAN = 3;
  CONST REDSYS_LANGUAGE_GALICIAN = 12;
  CONST REDSYS_TRANSACTION_TYPE_OPERATION_STANDARD = 0;
sluc23's avatar
sluc23 committed
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

  /**
  * We only need one instance of this object. So we use the singleton
  * pattern and cache the instance in this variable
  *
  * @var object
  * @static
  */
  static private $_singleton = null;

  /**
  * mode of operation: live or test
  *
  * @var object
  */
34
  protected $_mode = null;
sluc23's avatar
sluc23 committed
35
36

  /**
37
38
39
40
41
   * Processor type label.
   *
   * (Deprecated parameter but used in some messages).
   *
   * @deprecated
sluc23's avatar
sluc23 committed
42
43
44
   *
   * @var string
   */
45
  public $_processorName = null;
sluc23's avatar
sluc23 committed
46
47
48
49
50
51
52
53
54

  /**
  * Constructor
  *
  * @param string $mode the mode of operation: live or test
  *
  * @return void
  */
  function __construct($mode, &$paymentProcessor) {
sluc23's avatar
sluc23 committed
55
56
57
    $this->_mode              = $mode;
    $this->_paymentProcessor  = $paymentProcessor;
    $this->_processorName     = 'Redsys';
sluc23's avatar
sluc23 committed
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  }

  /**
  * Singleton function used to manage this object
  *
  * @param string $mode the mode of operation: live or test
  *
  * @return object
  * @static
  *
  */
  static function &singleton($mode, &$paymentProcessor) {
    $processorName = $paymentProcessor["name"];
    if (self::$_singleton[$processorName] === NULL ) {
      self::$_singleton[$processorName] = new self($mode, $paymentProcessor);
    }
    return self::$_singleton[$processorName];
  }

  /**
  * This function checks to see if we have the right config values
  *
  * @return string the error message if any
  * @public
  */
  function checkConfig() {
    $config = CRM_Core_Config::singleton();
    $error = array();

    if (empty($this->_paymentProcessor["user_name"])) {
      $error[] = ts( "Merchant Code is not set in the Redsys Payment Processor settings." );
    }
    if (empty($this->_paymentProcessor["password"])) {
      $error[] = ts( "Merchant Password is not set in the Redsys Payment Processor settings." );
    }

    if (!empty($error)) {
      return implode("<p>", $error);
    } else {
      return NULL;
    }
  }

  /**
   * This function is not implemented, as long as this payment
   * procesor is notify mode only.
   *
   * @param type $params
   */
  function doDirectPayment( &$params ) {
    CRM_Core_Error::fatal( ts( "This function is not implemented" ) );
  }

  /**
   * This function calls the Redsys servers and sends them information
   * about the payment.
   */
115
  function doTransferCheckout(&$params, $component = 'contribute') {
sluc23's avatar
sluc23 committed
116

117
118
119
120
121
122
    $config = CRM_Core_Config::singleton();

    if ($component != 'contribute' && $component != 'event') {
      CRM_Core_Error::fatal(ts('Component is invalid'));
    }

123
124
125
126
127
128
129
130
131
132
    if( array_key_exists( 'webform_redirect_success', $params ) ) {
      $returnURL = $params['webform_redirect_success'];
      $cancelURL = $params['webform_redirect_cancel'];
    } else {
      $url       = ($component == 'event') ? 'civicrm/event/register' : 'civicrm/contribute/transact';
      $cancel    = ($component == 'event') ? '_qf_Register_display' : '_qf_Main_display';
      $returnURL = CRM_Utils_System::url($url,
        "_qf_ThankYou_display=1&qfKey={$params['qfKey']}",
        TRUE, NULL, FALSE
      );
133
134


135
136
137
138
      $cancelUrlString = "$cancel=1&cancel=1&qfKey={$params['qfKey']}";
      if (CRM_Utils_Array::value('is_recur', $params)) {
        $cancelUrlString .= "&isRecur=1&recurId={$params['contributionRecurID']}&contribId={$params['contributionID']}";
      }
139

140
141
142
143
144
145
      $cancelURL = CRM_Utils_System::url(
        $url,
        $cancelUrlString,
        TRUE, NULL, FALSE
      );
    }
146

sluc23's avatar
sluc23 committed
147
    $merchantUrlParams = "contactID={$params['contactID']}&contributionID={$params['contributionID']}";
148
    if ($component == 'event') {
sluc23's avatar
sluc23 committed
149
      $merchantUrlParams .= "&eventID={$params['eventID']}&participantID={$params['participantID']}";
150
151
152
153
    }
    else {
      $membershipID = CRM_Utils_Array::value('membershipID', $params);
      if ($membershipID) {
sluc23's avatar
sluc23 committed
154
        $merchantUrlParams .= "&membershipID=$membershipID";
155
156
157
      }
      $contributionPageID = CRM_Utils_Array::value('contributionPageID', $params);
      if ($contributionPageID) {
sluc23's avatar
sluc23 committed
158
        $merchantUrlParams .= "&contributionPageID=$contributionPageID";
159
160
161
      }
      $relatedContactID = CRM_Utils_Array::value('related_contact', $params);
      if ($relatedContactID) {
sluc23's avatar
sluc23 committed
162
        $merchantUrlParams .= "&relatedContactID=$relatedContactID";
163
164
165

        $onBehalfDupeAlert = CRM_Utils_Array::value('onbehalf_dupe_alert', $params);
        if ($onBehalfDupeAlert) {
sluc23's avatar
sluc23 committed
166
          $merchantUrlParams .= "&onBehalfDupeAlert=$onBehalfDupeAlert";
167
168
169
        }
      }
    }
170
171
172
173
174

    $merchantUrl = CRM_Utils_System::url('civicrm/payment/ipn',
      'processor_name=Redsys&mode=' . $this->_mode . '&md=' . $component . '&qfKey=' . $params["qfKey"] . '&' . $merchantUrlParams,
      TRUE, NULL, FALSE, TRUE
    );
sluc23's avatar
sluc23 committed
175

sluc23's avatar
sluc23 committed
176
177
178
179
    // Force http if set
    $redsys_settings = CRM_Core_BAO_Setting::getItem("Redsys Settings", 'redsys_settings');
    if($redsys_settings['ipn_http'] == '1')
      $merchantUrl = preg_replace('/^https:/i', 'http:', $merchantUrl);
180

181
182
183
184
185
186
187
    // The payment processor id can be named payment_processor (contribution pages)
    if( array_key_exists( 'payment_processor', $params ) ) {
      $paymentProcessorId = $params['payment_processor'];
    } elseif( array_key_exists( 'payment_processor_id', $params ) ) {
      $paymentProcessorId = $params['payment_processor_id'];
    }

Carlos Capote's avatar
Carlos Capote committed
188
189
190
191
192
193
    // Get the terminal for this payment processor
    if( array_key_exists('merchant_terminal_' . $paymentProcessorId, $redsys_settings) ) {
      if( $redsys_settings['merchant_terminal_' . $paymentProcessorId] ) {
        $merchantTerminal = $redsys_settings['merchant_terminal_' . $paymentProcessorId];
      }
    }
194

Carlos Capote's avatar
Carlos Capote committed
195
196
197
198
199
    // Use the default terminal if the processor doesn't have an assigned one
    if( ! $merchantTerminal ) {
      $merchantTerminal = empty($redsys_settings['merchant_terminal']) ? 1 :
        $redsys_settings['merchant_terminal'];
    }
sluc23's avatar
sluc23 committed
200

sluc23's avatar
sluc23 committed
201
202
203
204
205
206
    $miObj = new RedsysAPI;
    $miObj->setParameter("Ds_Merchant_Amount", $params["amount"] * 100);
    $miObj->setParameter("Ds_Merchant_Order", strval(self::formatAmount($params["contributionID"], 12)));
    $miObj->setParameter("Ds_Merchant_MerchantCode", $this->_paymentProcessor["user_name"]);
    $miObj->setParameter("Ds_Merchant_Currency", self::REDSYS_CURRENCY_EURO);
    $miObj->setParameter("Ds_Merchant_TransactionType", self::REDSYS_TRANSACTION_TYPE_OPERATION_STANDARD);
207
    $miObj->setParameter("Ds_Merchant_Terminal", $merchantTerminal);
sluc23's avatar
sluc23 committed
208
209
210
211
212
213
    $miObj->setParameter("Ds_Merchant_MerchantURL", $merchantUrl);
    $miObj->setParameter("Ds_Merchant_UrlOK", $returnURL);
    $miObj->setParameter("Ds_Merchant_UrlKO", $cancelURL);
    $miObj->setParameter("Ds_Merchant_ProductDescription", $params["contributionType_name"]);
    $miObj->setParameter("Ds_Merchant_Titular", $params["first_name"] . " " . $params["last_name"]   );
    $miObj->setParameter("Ds_Merchant_ConsumerLanguage", self::REDSYS_LANGUAGE_SPANISH);
214

sluc23's avatar
sluc23 committed
215
    $version = "HMAC_SHA256_V1";
sluc23's avatar
sluc23 committed
216
217

    $signature = $miObj->createMerchantSignature($this->_paymentProcessor["password"]);
sluc23's avatar
sluc23 committed
218
219
220
221

    // Print the tpl to redirect and send POST variables to RedSys Getaway
    $template = CRM_Core_Smarty::singleton();
    $tpl = 'CRM/Core/Payment/Redsys.tpl';
sluc23's avatar
sluc23 committed
222

rubofvil's avatar
rubofvil committed
223
224
225
226
    $template->assign('signature', $signature);
    $redsysParamsJSON = $miObj->createMerchantParameters();
    $template->assign('redsysParamsJSON', $redsysParamsJSON);
    $template->assign('version', $version);
sluc23's avatar
sluc23 committed
227
    $template->assign('redsysURL', $this->_paymentProcessor["url_site"]);
sluc23's avatar
sluc23 committed
228
229
230

    print $template->fetch($tpl);

231
    CRM_Utils_System::civiExit();
sluc23's avatar
sluc23 committed
232
233
  }

sluc23's avatar
sluc23 committed
234
  public function handlePaymentNotification() {
sluc23's avatar
sluc23 committed
235
236
    $input = $ids = $objects = array();
    $ipn = new CRM_Core_Payment_RedsysIPN();
sluc23's avatar
sluc23 committed
237

sluc23's avatar
sluc23 committed
238
239
240
    // load vars in $input, &ids
    $ipn->getInput($input, $ids);
    CRM_Core_Error::debug_log_message("Redsys IPN Response: Parameteres received \n input: " . print_r($input, TRUE) . "\n ids: " . print_r($ids, TRUE) );
241

242
    $paymentProcessorID = $this->_paymentProcessor['id'];
sluc23's avatar
sluc23 committed
243
244
    if (!$ipn->validateData($this->_paymentProcessor, $input, $ids, $objects, TRUE, $paymentProcessorID)) {
      CRM_Core_Error::debug_log_message("Redsys Validation failed");
rubofvil's avatar
CleanUp    
rubofvil committed
245
246
247
      return FALSE;
    }

sluc23's avatar
sluc23 committed
248
    return $ipn->single($input, $ids, $objects, FALSE, FALSE);
sluc23's avatar
sluc23 committed
249
250
  }

sluc23's avatar
sluc23 committed
251
  static function formatAmount($amount, $size, $pad = 0){
sluc23's avatar
sluc23 committed
252
253
254
255
    $amount_str = preg_replace('/[\.,]/', '', strval($amount));
    $amount_str = str_pad($amount_str, $size, $pad, STR_PAD_LEFT);
    return $amount_str;
  }
sluc23's avatar
sluc23 committed
256
257

  static function trimAmount($amount, $pad = '0'){
rubofvil's avatar
rubofvil committed
258
    return ltrim(trim($amount), $pad);
sluc23's avatar
sluc23 committed
259
  }
rubofvil's avatar
rubofvil committed
260
}