/** * Submit a payment using Advanced Integration Method * * @param array $params assoc array of input parameters for this transaction * @return array the result in a nice formatted array (or an error object) * @public */ function doDirectPayment(&$params) { // Invoke hook_civicrm_paymentProcessor // In Dummy's case, there is no translation of parameters into // the back-end's canonical set of parameters. But if a processor // does this, it needs to invoke this hook after it has done translation, // but before it actually starts talking to its proprietary back-end. $cookedParams = $params; // no translation in Dummy processor CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $cookedParams); //end of hook invokation if ($this->_mode == 'test') { $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE 'test\\_%'"; $p = array(); $trxn_id = strval(CRM_Core_Dao::singleValueQuery($query, $p)); $trxn_id = str_replace('test_', '', $trxn_id); $trxn_id = intval($trxn_id) + 1; $params['trxn_id'] = sprintf('test_%08d', $trxn_id); } else { $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE 'live_%'"; $p = array(); $trxn_id = strval(CRM_Core_Dao::singleValueQuery($query, $p)); $trxn_id = str_replace('live_', '', $trxn_id); $trxn_id = intval($trxn_id) + 1; $params['trxn_id'] = sprintf('live_%08d', $trxn_id); } $params['gross_amount'] = $params['amount']; return $params; }
function doDirectPayment(&$params) { $logon = $this->_paymentProcessor['user_name']; $password = $this->_paymentProcessor['password']; $url_site = $this->_paymentProcessor['url_site']; // create pjpgCustInfo object $pjpgCustInfo = new pjpgCustInfo(); $pjpgCustInfo->setEmail($params['email']); $billing = array("logon" => $logon, "password" => $password, "url_site" => $url_site, "first_name" => $params['first_name'], "last_name" => $params['last_name'], "address" => $params['street_address'], "city" => $params['city'], "province" => $params['state_province'], "postal_code" => $params['postal_code'], "country" => $params['country']); $pjpgCustInfo->setBilling($billing); // create pjpgTransaction object $my_orderid = $params['invoiceID']; $expiry_string = sprintf('%04d%02d', $params['year'], $params['month']); $txnArray = array('type' => 'purchase', 'order_id' => $my_orderid, 'amount' => sprintf('%01.2f', $params['amount']), 'pan' => $params['credit_card_number'], 'expdate' => $expiry_string, 'crypt_type' => '7', 'cust_id' => $params['contact_id']); // Allow further manipulation of params via custom hooks CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $txnArray); $pjpgTxn = new pjpgTransaction($txnArray); // set customer info (level 3 data) for the transaction $pjpgTxn->setCustInfo($pjpgCustInfo); // empty installments convert to 999 because PayJunction do not allow open end donation if ($params['installments'] == "") { $params['installments'] = "999"; } // create recurring object if ($params['is_recur'] == true && $params['installments'] > 1) { // schedule start date as today $params['dc_schedule_start'] = date("Y-m-d"); // format: YYYY-MM-DD // Recur Variables $dc_schedule_create = $params['is_recur']; $recurUnit = $params['frequency_unit']; $recurInterval = $params['frequency_interval']; $dc_schedule_start = $params['dc_schedule_start']; $startDate = date("Y/m/d", $next); // next payment in moneris required format $numRecurs = $params['installments']; $recurArray = array('dc_schedule_create' => $dc_schedule_create, 'recur_unit' => $recurUnit, 'start_date' => $startDate, 'num_recurs' => $numRecurs, 'start_now' => 'false', 'period' => $recurInterval, 'dc_schedule_start' => $dc_schedule_start, 'amount' => sprintf('%01.2f', $params['amount'])); $pjpgRecur = new pjpgRecur($recurArray); $pjpgTxn->setRecur($pjpgRecur); } // create a pjpgRequest object passing the transaction object $pjpgRequest = new pjpgRequest($pjpgTxn); $pjpgHttpPost = new pjpgHttpsPost($pjpgRequest); // get an pjpgResponse object $pjpgResponse = $pjpgHttpPost->getPJpgResponse(); if (self::isError($pjpgResponse)) { return self::error($pjpgResponse); } /* Check for application errors */ $result =& self::checkResult($pjpgResponse); if (is_a($result, 'CRM_Core_Error')) { return $result; } // Success $params['trxn_result_code'] = $pjpgResponse['dc_response_code']; $params['trxn_id'] = $pjpgResponse['dc_transaction_id']; $params['gross_amount'] = $params['amount']; return $params; }
/** * Submit a payment using Advanced Integration Method. * * @param array $params * Assoc array of input parameters for this transaction. * * @return array * the result in a nice formatted array (or an error object) */ public function doDirectPayment(&$params) { // Invoke hook_civicrm_paymentProcessor // In Dummy's case, there is no translation of parameters into // the back-end's canonical set of parameters. But if a processor // does this, it needs to invoke this hook after it has done translation, // but before it actually starts talking to its proprietary back-end. if (!empty($params['is_recur'])) { $throwAnENoticeIfNotSetAsTheseAreRequired = $params['frequency_interval'] . $params['frequency_unit']; } // no translation in Dummy processor $cookedParams = $params; CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $cookedParams); // This means we can test failing transactions by setting a past year in expiry. A full expiry check would // be more complete. if (!empty($params['credit_card_exp_date']['Y']) && date('Y') > CRM_Core_Payment_Form::getCreditCardExpirationYear($params)) { $error = new CRM_Core_Error(ts('transaction failed')); return $error; } //end of hook invocation if (!empty($this->_doDirectPaymentResult)) { $result = $this->_doDirectPaymentResult; $result['trxn_id'] = array_shift($this->_doDirectPaymentResult['trxn_id']); return $result; } if ($this->_mode == 'test') { $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE 'test\\_%'"; $p = array(); $trxn_id = strval(CRM_Core_Dao::singleValueQuery($query, $p)); $trxn_id = str_replace('test_', '', $trxn_id); $trxn_id = intval($trxn_id) + 1; $params['trxn_id'] = 'test_' . $trxn_id . '_' . uniqid(); } else { $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE 'live_%'"; $p = array(); $trxn_id = strval(CRM_Core_Dao::singleValueQuery($query, $p)); $trxn_id = str_replace('live_', '', $trxn_id); $trxn_id = intval($trxn_id) + 1; $params['trxn_id'] = 'live_' . $trxn_id . '_' . uniqid(); } $params['gross_amount'] = $params['amount']; // Add a fee_amount so we can make sure fees are handled properly in underlying classes. $params['fee_amount'] = 1.5; $params['net_amount'] = $params['gross_amount'] - $params['fee_amount']; return $params; }
/** * Submit a payment using Advanced Integration Method. * * @param array $params * Assoc array of input parameters for this transaction. * * @return array * the result in a nice formatted array (or an error object) */ public function doDirectPayment(&$params) { // Invoke hook_civicrm_paymentProcessor // In Dummy's case, there is no translation of parameters into // the back-end's canonical set of parameters. But if a processor // does this, it needs to invoke this hook after it has done translation, // but before it actually starts talking to its proprietary back-end. // no translation in Dummy processor $cookedParams = $params; CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $cookedParams); //end of hook invocation if (!empty($this->_doDirectPaymentResult)) { $result = $this->_doDirectPaymentResult; $result['trxn_id'] = array_shift($this->_doDirectPaymentResult['trxn_id']); return $result; } if ($this->_mode == 'test') { $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE 'test\\_%'"; $p = array(); $trxn_id = strval(CRM_Core_Dao::singleValueQuery($query, $p)); $trxn_id = str_replace('test_', '', $trxn_id); $trxn_id = intval($trxn_id) + 1; $params['trxn_id'] = sprintf('test_%08d', $trxn_id); } else { $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE 'live_%'"; $p = array(); $trxn_id = strval(CRM_Core_Dao::singleValueQuery($query, $p)); $trxn_id = str_replace('live_', '', $trxn_id); $trxn_id = intval($trxn_id) + 1; $params['trxn_id'] = sprintf('live_%08d', $trxn_id); } $params['gross_amount'] = $params['amount']; // Add a fee_amount so we can make sure fees are handled properly in underlying classes. $params['fee_amount'] = 1.5; $params['net_amount'] = $params['gross_amount'] - $params['fee_amount']; return $params; }
/** * Main transaction function * * @param array $params name value pair of contribution data * * @return void * @access public * */ function doTransferCheckout(&$params, $component) { $component = strtolower($component); $config = CRM_Core_Config::singleton(); if ($component != 'contribute' && $component != 'event') { CRM_Core_Error::fatal(ts('Component is invalid')); } $url = $config->userFrameworkResourceURL . "extern/pxIPN.php"; if ($component == 'event') { $cancelURL = CRM_Utils_System::url('civicrm/event/register', "_qf_Confirm_display=true&qfKey={$params['qfKey']}", false, null, false); } else { if ($component == 'contribute') { $cancelURL = CRM_Utils_System::url('civicrm/contribute/transact', "_qf_Confirm_display=true&qfKey={$params['qfKey']}", false, null, false); } } /* * Build the private data string to pass to DPS, which they will give back to us with the * * transaction result. We are building this as a comma-separated list so as to avoid long URLs. * * Parameters passed: a=contactID, b=contributionID,c=contributionTypeID,d=invoiceID,e=membershipID,f=participantID,g=eventID */ $privateData = "a={$params['contactID']},b={$params['contributionID']},c={$params['contributionTypeID']},d={$params['invoiceID']}"; if ($component == 'event') { $privateData .= ",f={$params['participantID']},g={$params['eventID']}"; $merchantRef = "event registration"; } elseif ($component == 'contribute') { $merchantRef = "Charitable Contribution"; $membershipID = CRM_Utils_Array::value('membershipID', $params); if ($membershipID) { $privateData .= ",e={$membershipID}"; } } // Allow further manipulation of params via custom hooks CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $privateData); /* * determine whether method is pxaccess or pxpay by whether signature (mac key) is defined */ if (empty($this->_paymentProcessor['signature'])) { /* * Processor is pxpay * * This contains the XML/Curl functions we'll need to generate the XML request */ require_once 'CRM/Core/Payment/PaymentExpressUtils.php'; // Build a valid XML string to pass to DPS $generateRequest = _valueXml(array('PxPayUserId' => $this->_paymentProcessor['user_name'], 'PxPayKey' => $this->_paymentProcessor['password'], 'AmountInput' => str_replace(",", "", number_format($params['amount'], 2)), 'CurrencyInput' => $params['currencyID'], 'MerchantReference' => $merchantRef, 'TxnData1' => $params['qfKey'], 'TxnData2' => $privateData, 'TxnData3' => $component, 'TxnType' => 'Purchase', 'TxnId' => '', 'UrlFail' => $url, 'UrlSuccess' => $url)); $generateRequest = _valueXml('GenerateRequest', $generateRequest); // Get the special validated URL back from DPS by sending them the XML we've generated $curl = _initCURL($generateRequest, $this->_paymentProcessor['url_site']); $success = false; if ($response = curl_exec($curl)) { curl_close($curl); $valid = _xmlAttribute($response, 'valid'); if (1 == $valid) { // the request was validated, so we'll get the URL and redirect to it $uri = _xmlElement($response, 'URI'); CRM_Utils_System::redirect($uri); } else { // redisplay confirmation page CRM_Utils_System::redirect($cancelURL); } } else { // calling DPS failed CRM_Core_Error::fatal(ts('Unable to establish connection to the payment gateway.')); } } else { $processortype = "pxaccess"; require_once 'PaymentExpress/pxaccess.inc.php'; $PxAccess_Url = $this->_paymentProcessor['url_site']; // URL $PxAccess_Userid = $this->_paymentProcessor['user_name']; // User ID $PxAccess_Key = $this->_paymentProcessor['password']; // Your DES Key from DPS $Mac_Key = $this->_paymentProcessor['signature']; // Your MAC key from DPS $pxaccess = new PxAccess($PxAccess_Url, $PxAccess_Userid, $PxAccess_Key, $Mac_Key); $request = new PxPayRequest(); $request->setAmountInput(number_format($params['amount'], 2)); $request->setTxnData1($params['qfKey']); $request->setTxnData2($privateData); $request->setTxnData3($component); $request->setTxnType("Purchase"); $request->setInputCurrency($params['currencyID']); $request->setMerchantReference($merchantRef); $request->setUrlFail($url); $request->setUrlSuccess($url); $request_string = $pxaccess->makeRequest($request); CRM_Utils_System::redirect($request_string); } }
function doDirectPayment(&$params) { // $result = ''; // foreach($params as $key => $value) { // $result .= "<strong>$key</strong>: $value<br />"; // } // return self::error($result); // make sure i've been called correctly ... if (!$this->_profile) { return self::error('Unexpected error, missing profile'); } if (!in_array($params['currencyID'], explode(',', self::CURRENCIES))) { return self::error('Invalid currency selection, must be one of ' . self::CURRENCIES); } $isRecur = $params['is_recur'] && $params['installments'] > 1; // AgentCode = $this->_paymentProcessor['signature']; // Password = $this->_paymentProcessor['password' ]; // beginning of modified sample code from IATS php api include IATS supplied api library if ($isRecur) { include_once 'Services/IATS/iats_reoccur.php'; $iatslink1 = new iatslinkReoccur(); } else { include_once 'Services/IATS/iatslink.php'; $iatslink1 = new iatslink(); } $iatslink1->setTestMode($this->_profile['mode'] == 'live'); $iatslink1->setWebServer($this->_profile['webserver']); // return self::error($this->_profile['webserver']); $iatslink1->setInvoiceNumber($params['invoiceID']); // Put your invoice here // $iatslink1->setCardType("VISA"); // If CardType is not set, iatslink will find the cardType // CardType not set because IATS uses different names! // $iatslink1->setCardType($params['credit_card_type']); $iatslink1->setCardNumber($params['credit_card_number']); $expiry_string = sprintf('%02d/%02d', $params['month'], $params['year'] % 100); $iatslink1->setCardExpiry($expiry_string); $amount = sprintf('%01.2f', $params['amount']); $iatslink1->setDollarAmount($amount); //sell //$iatslink1->setDollarAmount(-1.15); //refund $AgentCode = $this->_paymentProcessor['signature']; $Password = $this->_paymentProcessor['password']; $iatslink1->setAgentCode($AgentCode); $iatslink1->setPassword($Password); // send IATS my invoiceID to match things up later $iatslink1->setInvoiceNumber($params['invoiceID']); // Set billing fields $iatslink1->setFirstName($parames['billing_first_name']); $iatslink1->setLastName($params['billing_last_name']); $iatslink1->setStreetAddress($params['street_address']); $iatslink1->setCity($params['city']); $iatslink1->setState($params['state_province']); $iatslink1->setZipCode($params['postal_code']); // and now go! ... uses curl to post and retrieve values // after various data integrity tests if (!$isRecur) { // simple version // cvv2 only seems to get set for this! $iatslink1->setCVV2($params['cvv2']); // Allow further manipulation of the arguments via custom hooks, // before initiating processCreditCard() CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $iatslink1); $iatslink1->processCreditCard(); } else { // extra fields for recurring donations // implicit - test?: 1 == $params['frequency_interval']; $scheduleType = NULL; $paymentsRecur = $params['installments'] - 1; $startTime = time(); // to be converted to date format later $date = getdate($startTime); switch ($params['frequency_unit']) { case 'week': $scheduleType = 'WEEKLY'; $scheduleDate = $date['wday'] + 1; $endTime = $startTime + $paymentsRecur * 7 * 24 * 60 * 60; break; case 'month': $scheduleType = 'MONTHLY'; $scheduleDate = $date['mday']; $date['mon'] += $paymentsRecur; while ($date['mon'] > 12) { $date['mon'] -= 12; $date['year'] += 1; } $endTime = mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']); break; default: die('Invalid frequency unit!'); break; } $endDate = date('Y-m-d', $endTime); $startDate = date('Y-m-d', $startTime); $iatslink1->setReoccuringStatus("ON"); $iatslink1->setBeginDate($startDate); $iatslink1->setEndDate($endDate); $iatslink1->setScheduleType($scheduleType); $iatslink1->setScheduleDate($scheduleDate); // Allow further manipulation of the arguments via custom hooks, // before initiating the curl process CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $iatslink1); // this next line is the reoccc equiv of processCreditCard $iatslink1->createReoccCustomer(); } if ($iatslink1->getStatus() == 1) { // this just means we got some kind of answer, not necessarily approved $result = $iatslink1->getAuthorizationResult(); //return self::error($result); $result = explode(':', $result, 2); $trxn_result = trim($result[0]); $trxn_id = trim($result[1]); if ($trxn_result == 'OK') { $params['trxn_id'] = $trxn_id . ':' . time(); $params['gross_amount'] = $amount; return $params; } else { return self::error($trxn_id); } } else { return self::error($iatslink1->getError()); } }
/** * Sets appropriate parameters for checking out to google * * @param array $params name value pair of contribution datat * * @return void * @access public * */ function doTransferCheckout(&$params, $component) { $component = strtolower($component); $url = rtrim($this->_paymentProcessor['url_site'], '/') . '/cws/v2/Merchant/' . $this->_paymentProcessor['user_name'] . '/checkout'; //Create a new shopping cart object $merchant_id = $this->_paymentProcessor['user_name']; // Merchant ID $merchant_key = $this->_paymentProcessor['password']; // Merchant Key $server_type = $this->_mode == 'test' ? 'sandbox' : ''; $cart = new GoogleCart($merchant_id, $merchant_key, $server_type); $item1 = new GoogleItem($params['item_name'], '', 1, $params['amount'], $params['currencyID']); $cart->AddItem($item1); if ($component == "event") { $privateData = "contactID={$params['contactID']},contributionID={$params['contributionID']},contributionTypeID={$params['contributionTypeID']},eventID={$params['eventID']},participantID={$params['participantID']},invoiceID={$params['invoiceID']}"; } elseif ($component == "contribute") { $privateData = "contactID={$params['contactID']},contributionID={$params['contributionID']},contributionTypeID={$params['contributionTypeID']},invoiceID={$params['invoiceID']}"; $membershipID = CRM_Utils_Array::value('membershipID', $params); if ($membershipID) { $privateData .= ",membershipID={$membershipID}"; } $relatedContactID = CRM_Utils_Array::value('related_contact', $params); if ($relatedContactID) { $privateData .= ",relatedContactID={$relatedContactID}"; $onBehalfDupeAlert = CRM_Utils_Array::value('onbehalf_dupe_alert', $params); if ($onBehalfDupeAlert) { $privateData .= ",onBehalfDupeAlert={$onBehalfDupeAlert}"; } } } // Allow further manipulation of the arguments via custom hooks .. CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $privateData); $cart->SetMerchantPrivateData($privateData); if ($component == "event") { $returnURL = CRM_Utils_System::url('civicrm/event/register', "_qf_ThankYou_display=1&qfKey={$params['qfKey']}", true, null, false); } elseif ($component == "contribute") { $returnURL = CRM_Utils_System::url('civicrm/contribute/transact', "_qf_ThankYou_display=1&qfKey={$params['qfKey']}", true, null, false); } $cart->SetContinueShoppingUrl($returnURL); $cartVal = base64_encode($cart->GetXML()); $signatureVal = base64_encode($cart->CalcHmacSha1($cart->GetXML())); $googleParams = array('cart' => $cartVal, 'signature' => $signatureVal); require_once 'HTTP/Request.php'; $params = array('method' => HTTP_REQUEST_METHOD_POST, 'allowRedirects' => false); $request =& new HTTP_Request($url, $params); foreach ($googleParams as $key => $value) { $request->addPostData($key, $value); } $result = $request->sendRequest(); if (PEAR::isError($result)) { CRM_Core_Error::fatal($result->getMessage()); } if ($request->getResponseCode() != 302) { CRM_Core_Error::fatal(ts('Invalid response code received from Google Checkout: %1', array(1 => $request->getResponseCode()))); } CRM_Utils_System::redirect($request->getResponseHeader('location')); exit; }
/** * This function collects all the information from a web/api form and invokes * the relevant payment processor specific functions to perform the transaction * * @param array $params * Assoc array of input parameters for this transaction. * * @return array * the result in an nice formatted array (or an error object) * @abstract */ public function doDirectPayment(&$params) { if (!defined('CURLOPT_SSLCERT')) { CRM_Core_Error::fatal(ts('PayFlowPro requires curl with SSL support')); } /* * define variables for connecting with the gateway */ // Are you using the Payflow Fraud Protection Service? // Default is YES, change to NO or blank if not. //This has not been investigated as part of writing this payment processor $fraud = 'NO'; //if you have not set up a separate user account the vendor name is used as the username if (!$this->_paymentProcessor['subject']) { $user = $this->_paymentProcessor['user_name']; } else { $user = $this->_paymentProcessor['subject']; } // ideally this id would be passed through into this class as // part of the paymentProcessor //object with the other variables. It seems inefficient to re-query to get it. //$params['processor_id'] = CRM_Core_DAO::getFieldValue( // 'CRM_Contribute_DAO_ContributionP //age',$params['contributionPageID'], 'payment_processor_id' ); /* *Create the array of variables to be sent to the processor from the $params array * passed into this function * */ $payflow_query_array = array('USER' => $user, 'VENDOR' => $this->_paymentProcessor['user_name'], 'PARTNER' => $this->_paymentProcessor['signature'], 'PWD' => $this->_paymentProcessor['password'], 'TENDER' => 'C', 'TRXTYPE' => 'S', 'ACCT' => urlencode($params['credit_card_number']), 'CVV2' => $params['cvv2'], 'EXPDATE' => urlencode(sprintf('%02d', (int) $params['month']) . substr($params['year'], 2, 2)), 'ACCTTYPE' => urlencode($params['credit_card_type']), 'AMT' => urlencode($params['amount']), 'CURRENCY' => urlencode($params['currency']), 'FIRSTNAME' => $params['billing_first_name'], 'LASTNAME' => $params['billing_last_name'], 'STREET' => $params['street_address'], 'CITY' => urlencode($params['city']), 'STATE' => urlencode($params['state_province']), 'ZIP' => urlencode($params['postal_code']), 'COUNTRY' => urlencode($params['country']), 'EMAIL' => $params['email'], 'CUSTIP' => urlencode($params['ip_address']), 'COMMENT1' => urlencode($params['contributionType_accounting_code']), 'COMMENT2' => $mode, 'INVNUM' => urlencode($params['invoiceID']), 'ORDERDESC' => urlencode($params['description']), 'VERBOSITY' => 'MEDIUM', 'BILLTOCOUNTRY' => urlencode($params['country'])); if ($params['installments'] == 1) { $params['is_recur'] == FALSE; } if ($params['is_recur'] == TRUE) { $payflow_query_array['TRXTYPE'] = 'R'; $payflow_query_array['OPTIONALTRX'] = 'S'; $payflow_query_array['OPTIONALTRXAMT'] = $params['amount']; //Amount of the initial Transaction. Required $payflow_query_array['ACTION'] = 'A'; //A for add recurring (M-modify,C-cancel,R-reactivate,I-inquiry,P-payment $payflow_query_array['PROFILENAME'] = urlencode('RegularContribution'); //A for add recurring (M-modify,C-cancel,R-reactivate,I-inquiry,P-payment if ($params['installments'] > 0) { $payflow_query_array['TERM'] = $params['installments'] - 1; //ie. in addition to the one happening with this transaction } // $payflow_query_array['COMPANYNAME'] // $payflow_query_array['DESC'] = not set yet Optional // description of the goods or //services being purchased. //This parameter applies only for ACH_CCD accounts. // The // $payflow_query_array['MAXFAILPAYMENTS'] = 0; // number of payment periods (as s //pecified by PAYPERIOD) for which the transaction is allowed //to fail before PayPal cancels a profile. the default // value of 0 (zero) specifies no //limit. Retry //attempts occur until the term is complete. // $payflow_query_array['RETRYNUMDAYS'] = (not set as can't assume business rule switch ($params['frequency_unit']) { case '1 week': $params['next_sched_contribution_date'] = mktime(0, 0, 0, date("m"), date("d") + 7, date("Y")); $params['end_date'] = mktime(0, 0, 0, date("m"), date("d") + 7 * $payflow_query_array['TERM'], date("Y")); $payflow_query_array['START'] = date('mdY', $params['next_sched_contribution_date']); $payflow_query_array['PAYPERIOD'] = "WEEK"; $params['frequency_unit'] = "week"; $params['frequency_interval'] = 1; break; case '2 weeks': $params['next_sched_contribution_date'] = mktime(0, 0, 0, date("m"), date("d") + 14, date("Y")); $params['end_date'] = mktime(0, 0, 0, date("m"), date("d") + 14 * $payflow_query_array['TERM'], date("Y ")); $payflow_query_array['START'] = date('mdY', $params['next_sched_contribution_date']); $payflow_query_array['PAYPERIOD'] = "BIWK"; $params['frequency_unit'] = "week"; $params['frequency_interval'] = 2; break; case '4 weeks': $params['next_sched_contribution_date'] = mktime(0, 0, 0, date("m"), date("d") + 28, date("Y")); $params['end_date'] = mktime(0, 0, 0, date("m"), date("d") + 28 * $payflow_query_array['TERM'], date("Y")); $payflow_query_array['START'] = date('mdY', $params['next_sched_contribution_date']); $payflow_query_array['PAYPERIOD'] = "FRWK"; $params['frequency_unit'] = "week"; $params['frequency_interval'] = 4; break; case '1 month': $params['next_sched_contribution_date'] = mktime(0, 0, 0, date("m") + 1, date("d"), date("Y")); $params['end_date'] = mktime(0, 0, 0, date("m") + 1 * $payflow_query_array['TERM'], date("d"), date("Y")); $payflow_query_array['START'] = date('mdY', $params['next_sched_contribution_date']); $payflow_query_array['PAYPERIOD'] = "MONT"; $params['frequency_unit'] = "month"; $params['frequency_interval'] = 1; break; case '3 months': $params['next_sched_contribution_date'] = mktime(0, 0, 0, date("m") + 3, date("d"), date("Y")); $params['end_date'] = mktime(0, 0, 0, date("m") + 3 * $payflow_query_array['TERM'], date("d"), date("Y")); $payflow_query_array['START'] = date('mdY', $params['next_sched_contribution_date']); $payflow_query_array['PAYPERIOD'] = "QTER"; $params['frequency_unit'] = "month"; $params['frequency_interval'] = 3; break; case '6 months': $params['next_sched_contribution_date'] = mktime(0, 0, 0, date("m") + 6, date("d"), date("Y")); $params['end_date'] = mktime(0, 0, 0, date("m") + 6 * $payflow_query_array['TERM'], date("d"), date("Y")); $payflow_query_array['START'] = date('mdY', $params['next_sched_contribution_date']); $payflow_query_array['PAYPERIOD'] = "SMYR"; $params['frequency_unit'] = "month"; $params['frequency_interval'] = 6; break; case '1 year': $params['next_sched_contribution_date'] = mktime(0, 0, 0, date("m"), date("d"), date("Y") + 1); $params['end_date'] = mktime(0, 0, 0, date("m"), date("d"), date("Y") + 1 * $payflow_query_array['TEM']); $payflow_query_array['START'] = date('mdY', $params['next_sched_contribution_date']); $payflow_query_array['PAYPERIOD'] = "YEAR"; $params['frequency_unit'] = "year"; $params['frequency_interval'] = 1; break; } } CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $payflow_query_array); $payflow_query = $this->convert_to_nvp($payflow_query_array); /* * Check to see if we have a duplicate before we send */ if ($this->checkDupe($params['invoiceID'], CRM_Utils_Array::value('contributionID', $params))) { return self::errorExit(9003, 'It appears that this transaction is a duplicate. Have you already submitted the form once? If so there may have been a connection problem. Check your email for a receipt. If you do not receive a receipt within 2 hours you can try your transaction again. If you continue to have problems please contact the site administrator.'); } // ie. url at payment processor to submit to. $submiturl = $this->_paymentProcessor['url_site']; $responseData = self::submit_transaction($submiturl, $payflow_query); /* * Payment successfully sent to gateway - process the response now */ $result = strstr($responseData, "RESULT"); $nvpArray = array(); while (strlen($result)) { // name $keypos = strpos($result, '='); $keyval = substr($result, 0, $keypos); // value $valuepos = strpos($result, '&') ? strpos($result, '&') : strlen($result); $valval = substr($result, $keypos + 1, $valuepos - $keypos - 1); // decoding the respose $nvpArray[$keyval] = $valval; $result = substr($result, $valuepos + 1, strlen($result)); } // get the result code to validate. $result_code = $nvpArray['RESULT']; /*debug echo "<p>Params array</p><br>"; print_r($params); echo "<p></p><br>"; echo "<p>Values to Payment Processor</p><br>"; print_r($payflow_query_array); echo "<p></p><br>"; echo "<p>Results from Payment Processor</p><br>"; print_r($nvpArray); echo "<p></p><br>"; */ switch ($result_code) { case 0: /******************************************************* * Success ! * This is a successful transaction. PayFlow Pro does return further information * about transactions to help you identify fraud including whether they pass * the cvv check, the avs check. This is stored in * CiviCRM as part of the transact * but not further processing is done. Business rules would need to be defined *******************************************************/ $params['trxn_id'] = $nvpArray['PNREF'] . $nvpArray['TRXPNREF']; //'trxn_id' is varchar(255) field. returned value is length 12 $params['trxn_result_code'] = $nvpArray['AUTHCODE'] . "-Cvv2:" . $nvpArray['CVV2MATCH'] . "-avs:" . $nvpArray['AVSADDR']; if ($params['is_recur'] == TRUE) { $params['recur_trxn_id'] = $nvpArray['PROFILEID']; //'trxn_id' is varchar(255) field. returned value is length 12 } return $params; case 1: return self::errorExit(9008, "There is a payment processor configuration problem. This is usually due to invalid account information or ip restrictions on the account. You can verify ip restriction by logging // into Manager. See Service Settings >> Allowed IP Addresses. "); case 12: // Hard decline from bank. return self::errorExit(9009, "Your transaction was declined "); case 13: // Voice authorization required. return self::errorExit(9010, "Your Transaction is pending. Contact Customer Service to complete your order."); case 23: // Issue with credit card number or expiration date. return self::errorExit(9011, "Invalid credit card information. Please re-enter."); case 26: return self::errorExit(9012, "You have not configured your payment processor with the correct credentials. Make sure you have provided both the <vendor> and the <user> variables "); default: return self::errorExit(9013, "Error - from payment processor: [" . $result_code . " " . $nvpArray['RESPMSG'] . "] "); } return self::errorExit(9014, "Check the code - all transactions should have been headed off before they got here. Something slipped through the net"); }
/** * Get request to send to eWay. * * @param $params * Form parameters - this could be altered by hook so is a reference * * @return GatewayRequest * @throws \CRM_Core_Exception */ protected function getEwayRequest(&$params) { $eWAYRequest = new GatewayRequest(); if ($eWAYRequest == NULL || !$eWAYRequest instanceof GatewayRequest) { throw new CRM_Core_Exception("Error: Unable to create eWAY Request object."); } $fullAddress = $params['street_address'] . ", " . $params['city'] . ", " . $params['state_province'] . "."; //---------------------------------------------------------------------------------------------------- // We use CiviCRM's params 'invoiceID' as the unique transaction token to feed to eWAY // Trouble is that eWAY only accepts 16 chars for the token, while CiviCRM's invoiceID is an 32. // As its made from a "$invoiceID = md5(uniqid(rand(), true));" then using the first 16 chars // should be alright //---------------------------------------------------------------------------------------------------- $uniqueTrxnNum = substr($params['invoiceID'], 0, 16); //---------------------------------------------------------------------------------------------------- // OPTIONAL: If TEST Card Number force an Override of URL and CustomerID. // During testing CiviCRM once used the LIVE URL. // This code can be uncommented to override the LIVE URL that if CiviCRM does that again. //---------------------------------------------------------------------------------------------------- // if ( ( $gateway_URL == "https://www.eway.com.au/gateway_cvn/xmlpayment.asp") // && ($params['credit_card_number'] == "4444333322221111" )) { // $ewayCustomerID = "87654321"; // $gateway_URL = "https://www.eway.com.au/gateway_cvn/xmltest/testpage.asp"; // } // 8 Chars - ewayCustomerID - Required $eWAYRequest->EwayCustomerID($this->_paymentProcessor['subject']); // 12 Chars - ewayTotalAmount (in cents) - Required $eWAYRequest->InvoiceAmount($this->getAmountInCents($params)); // 50 Chars - ewayCustomerFirstName $eWAYRequest->PurchaserFirstName($params['first_name']); // 50 Chars - ewayCustomerLastName $eWAYRequest->PurchaserLastName($params['last_name']); // 50 Chars - ewayCustomerEmail $eWAYRequest->PurchaserEmailAddress(CRM_Utils_Array::value('email', $params)); // 255 Chars - ewayCustomerAddress $eWAYRequest->PurchaserAddress($fullAddress); // 6 Chars - ewayCustomerPostcode $eWAYRequest->PurchaserPostalCode($params['postal_code']); // 1000 Chars - ewayCustomerInvoiceDescription $eWAYRequest->InvoiceDescription($params['description']); // 50 Chars - ewayCustomerInvoiceRef $eWAYRequest->InvoiceReference($params['invoiceID']); // 50 Chars - ewayCardHoldersName - Required $eWAYRequest->CardHolderName($this->getCreditCardName($params)); // 20 Chars - ewayCardNumber - Required $eWAYRequest->CardNumber($params['credit_card_number']); $eWAYRequest->CardExpiryMonth($this->getCreditCardExpiryMonth($params)); // 2 Chars - ewayCardExpiryYear - Required. $eWAYRequest->CardExpiryYear($this->getCreditCardExpiryYear($params)); // 4 Chars - ewayCVN - Required if CVN Gateway used $eWAYRequest->CVN($params['cvv2']); // 16 Chars - ewayTrxnNumber $eWAYRequest->TransactionNumber($uniqueTrxnNum); // 255 Chars - ewayOption1 $eWAYRequest->EwayOption1(''); // 255 Chars - ewayOption2 $eWAYRequest->EwayOption2(''); // 255 Chars - ewayOption3 $eWAYRequest->EwayOption3(''); $eWAYRequest->CustomerBillingCountry($params['country']); $eWAYRequest->CustomerIPAddress($params['ip_address']); // Allow further manipulation of the arguments via custom hooks .. CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $eWAYRequest); // Check for a duplicate after the hook has been called. if ($this->checkDupe($params['invoiceID'], CRM_Utils_Array::value('contributionID', $params))) { throw new CRM_Core_Exception('It appears that this transaction is a duplicate. Have you already submitted the form once? If so there may have been a connection problem. Check your email for a receipts. If you do not receive a receipt within 2 hours you can try your transaction again. If you continue to have problems please contact the site administrator.'); } return $eWAYRequest; }
function doDirectPayment(&$params) { //make sure i've been called correctly ... if (!$this->_profile) { return self::error('Unexpected error, missing profile'); } if ($params['currencyID'] != 'CAD') { return self::error('Invalid currency selection, must be $CAD'); } /* unused params: cvv not yet implemented, payment action ingored (should test for 'Sale' value?) [cvv2] => 000 [ip_address] => 192.168.0.103 [payment_action] => Sale [contact_type] => Individual [geo_coord_id] => 1 */ //this code based on Moneris example code # //create an mpgCustInfo object $mpgCustInfo = new mpgCustInfo(); //call set methods of the mpgCustinfo object $mpgCustInfo->setEmail($params['email']); //get text representations of province/country to send to moneris for billing info $billing = array('first_name' => $params['first_name'], 'last_name' => $params['last_name'], 'address' => $params['street_address'], 'city' => $params['city'], 'province' => $params['state_province'], 'postal_code' => $params['postal_code'], 'country' => $params['country']); $mpgCustInfo->setBilling($billing); $my_orderid = $params['invoiceID']; // set orderid as invoiceID to help match things up with Moneris later $expiry_string = sprintf('%04d%02d', $params['year'], $params['month']); $txnArray = array('type' => 'purchase', 'order_id' => $my_orderid, 'amount' => sprintf('%01.2f', $params['amount']), 'pan' => $params['credit_card_number'], 'expdate' => substr($expiry_string, 2, 4), 'crypt_type' => '7', 'cust_id' => $params['contact_id']); // Allow further manipulation of params via custom hooks CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $txnArray); //create a transaction object passing the hash created above $mpgTxn = new mpgTransaction($txnArray); //use the setCustInfo method of mpgTransaction object to //set the customer info (level 3 data) for this transaction $mpgTxn->setCustInfo($mpgCustInfo); // add a recurring payment if requested if ($params['is_recur'] && $params['installments'] > 1) { //Recur Variables $recurUnit = $params['frequency_unit']; $recurInterval = $params['frequency_interval']; $next = time(); $day = 60 * 60 * 24; switch ($recurUnit) { case 'day': $next += $recurInterval * $day; break; case 'week': $next += $recurInterval * $day * 7; break; case 'month': $date = getdate(); $date['mon'] += $recurInterval; while ($date['mon'] > 12) { $date['mon'] -= 12; $date['year'] += 1; } $next = mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']); break; case 'year': $date = getdate(); $date['year'] += 1; $next = mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']); break; default: die('Unexpected error!'); } $startDate = date("Y/m/d", $next); // next payment in moneris required format $numRecurs = $params['installments'] - 1; //$startNow = 'true'; -- setting start now to false will mean the main transaction doesn't happen! $recurAmount = sprintf('%01.2f', $params['amount']); //Create an array with the recur variables $recurArray = array('recur_unit' => $recurUnit, 'start_date' => $startDate, 'num_recurs' => $numRecurs, 'start_now' => 'true', 'period' => $recurInterval, 'recur_amount' => $recurAmount); $mpgRecur = new mpgRecur($recurArray); // set the Recur Object to mpgRecur $mpgTxn->setRecur($mpgRecur); } //create a mpgRequest object passing the transaction object $mpgRequest = new mpgRequest($mpgTxn); // create mpgHttpsPost object which does an https post ## // [extra parameter added to library by AD] $isProduction = $this->_profile['mode'] == 'live'; $mpgHttpPost = new mpgHttpsPost($this->_profile['storeid'], $this->_profile['apitoken'], $mpgRequest, $isProduction); // get an mpgResponse object $mpgResponse = $mpgHttpPost->getMpgResponse(); $params['trxn_result_code'] = $mpgResponse->getResponseCode(); if (self::isError($mpgResponse)) { if ($params['trxn_result_code']) { return self::error($mpgResponse); } else { return self::error('No reply from server - check your settings &/or try again'); } } /* Check for application errors */ $result =& self::checkResult($mpgResponse); if (is_a($result, 'CRM_Core_Error')) { return $result; } /* Success */ $params['trxn_result_code'] = (int) $mpgResponse->getResponseCode(); // todo: above assignment seems to be ignored, not getting stored in the civicrm_financial_trxn table $params['trxn_id'] = $mpgResponse->getTxnNumber(); $params['gross_amount'] = $mpgResponse->getTransAmount(); return $params; }
/** * Main transaction function * * @param array $params name value pair of contribution data * * @return void * @access public * */ function doTransferCheckout(&$params, $component) { $component = strtolower($component); if ($component == 'event') { $baseURL = 'civicrm/event/register'; $cancelURL = urlencode(CRM_Utils_System::url($baseURL, array('reset' => 1, 'cc' => 'fail', 'participantId' => $orderID[4]), TRUE, NULL, FALSE)); } elseif ($component == 'contribute') { $baseURL = 'civicrm/contribute/transact'; $cancelURL = urlencode(CRM_Utils_System::url($baseURL, array('_qf_Main_display' => 1, 'qfKey' => $params['qfKey'], 'cancel' => 1), TRUE, NULL, FALSE)); } $returnOKURL = urlencode(CRM_Utils_System::url($baseURL, array('_qf_ThankYou_display' => 1, 'qfKey' => $params['qfKey']), TRUE, NULL, FALSE)); $returnUrl = urlencode(CRM_Utils_System::url($baseURL, array('_qf_Confirm_display' => 'true', 'qfKey' => $params['qfKey']), TRUE, NULL, FALSE)); if ($component == 'event') { $merchantRef = $params['contactID'] . "-" . $params['description']; //, 27, 20), 0, 24); } elseif ($component == 'contribute') { $merchantRef = $params['contactID'] . "-" . $params['contributionID']; // . " " . substr($params['description'], 20, 20), 0, 24); } $emailFields = array('email', 'email-Primary', 'email-5'); $email = ''; foreach ($emailFields as $emailField) { if (!empty($params[$emailField])) { $email = $params[$emailField]; } } $lang = $this->getLanguage(); $paymentParams = array('url_retour' => $returnURL, 'submit_to' => $this->_paymentProcessor['url_site'], 'url_retour_ok' => $returnOKURL, 'url_retour_err' => $cancelURL, 'sealed_params' => array('TPE' => $this->_paymentProcessor['user_name'], 'date' => date("d/m/Y:H:i:s"), 'montant' => str_replace(",", "", number_format($params['amount'], 2)) . $params['currencyID'], 'reference' => $params['contributionID'], 'texte-libre' => $this->urlEncodeField($merchantRef, 24), 'version' => '3.0', 'lgue' => $lang, 'societe' => $this->_paymentProcessor['signature'], 'mail' => $email)); // Allow further manipulation of params via custom hooks CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $paymentParams); $paymentParams['MAC'] = $this->encodeMac($paymentParams['sealed_params']); $paymentParams = array_merge($paymentParams, $paymentParams['sealed_params']); unset($paymentParams['sealed_params']); $query_string = ''; foreach ($paymentParams as $name => $value) { $query_string .= $name . '=' . $value . '&'; } // Remove extra & $query_string = rtrim($query_string, '&'); // Redirect the user to the payment url. CRM_Utils_System::redirect($this->_paymentProcessor['url_site'] . '?' . $query_string); // looks like we dodged the bullet on POST being required. may as well keep this & the page // in case they tighten up later // CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/cmcic', $paymentParams)); }
function doTransferCheckout(&$params, $component) { $paymentProcessorType = CRM_Core_PseudoConstant::paymentProcessorType(false, null, 'name'); $paymentProcessorTypeId = CRM_Utils_Array::key('Gocardless', $paymentProcessorType); $domainID = CRM_Core_Config::domainID(); $sql = " SELECT user_name "; $sql .= " , password "; $sql .= " , signature "; $sql .= " , subject "; $sql .= " FROM civicrm_payment_processor "; $sql .= " WHERE payment_processor_type_id = %1 "; $sql .= " AND is_test= %2 "; $sql .= " AND domain_id = %3 "; $isTest = 0; if ($this->_mode == 'test') { $isTest = 1; } $sql_params = array(1 => array($paymentProcessorTypeId, 'Integer'), 2 => array($isTest, 'Int'), 3 => array($domainID, 'Int')); $dao = CRM_Core_DAO::executeQuery($sql, $sql_params); if ($dao->fetch()) { $app_id = $dao->user_name; $app_secret = $dao->password; $merchant_id = $dao->signature; $access_token = $dao->subject; } $account_details = array('app_id' => $app_id, 'app_secret' => $app_secret, 'merchant_id' => $merchant_id, 'access_token' => $access_token); // Fail nicely if no account details set if (!$account_details['app_id'] && !$account_details['app_secret']) { echo '<p>First sign up to <a href="http://gocardless.com">GoCardless</a> and copy your sandbox API credentials from the \'Developer\' tab into the top of this script.</p>'; exit; } // Set $environment to 'production' if live. Default is 'sandbox' if ($this->_mode == 'live') { GoCardless::$environment = 'production'; } // Initialize GoCardless GoCardless::set_account_details($account_details); $goCardLessParams = array(); $goCardLessParams['amount'] = $params['amount']; $goCardLessParams['interval_length'] = $params['frequency_interval']; $goCardLessParams['interval_unit'] = $params['frequency_unit']; if (!empty($params['preferred_collection_day'])) { $preferredCollectionDay = $params['preferred_collection_day']; $collectionDate = UK_Direct_Debit_Form_Main::firstCollectionDate($preferredCollectionDay, null); // ISO8601 format. $goCardLessParams['start_at'] = $collectionDate->format('c'); } $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']}" . "&cid={$params['contactID']}", true, null, false); $goCardLessParams['redirect_uri'] = $returnURL; $goCardLessParams['user'] = array('email' => isset($params['email-5']) ? $params['email-5'] : NULL, 'first_name' => isset($params['first_name']) ? $params['first_name'] : NULL, 'last_name' => isset($params['last_name']) ? $params['last_name'] : NULL, 'billing_address1' => isset($params['street_address']) ? $params['street_address'] : NULL, 'billing_town' => isset($params['city']) ? $params['city'] : NULL, 'billing_postcode' => isset($params['postal_code']) ? $params['postal_code'] : NULL, 'country_code' => 'GB'); // Allow further manipulation of the arguments via custom hooks .. CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $goCardLessParams); $subscription_url = GoCardless::new_subscription_url($goCardLessParams); CRM_Utils_System::redirect($subscription_url); }
/** * Get options for credit card. * * Not yet implemented * - token * * @param array $params * @param string $component * * @return array */ private function getCreditCardOptions($params, $component) { // Contribution page in 4.4 passes amount - not sure which passes total_amount if any. if (isset($params['total_amount'])) { $amount = (double) CRM_Utils_Rule::cleanMoney($params['total_amount']); } else { $amount = (double) CRM_Utils_Rule::cleanMoney($params['amount']); } $creditCardOptions = array('amount' => $amount, 'currency' => strtoupper(!empty($params['currencyID']) ? $params['currencyID'] : $params['currency']), 'description' => $this->getPaymentDescription($params), 'transactionId' => $this->transaction_id, 'clientIp' => CRM_Utils_System::ipAddress(), 'returnUrl' => $this->getNotifyUrl(TRUE), 'cancelUrl' => $this->getCancelUrl($params['qfKey'], CRM_Utils_Array::value('participantID', $params)), 'notifyUrl' => $this->getNotifyUrl(), 'card' => $this->getCreditCardObjectParams($params)); CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $creditCardOptions); $creditCardOptions['card'] = array_merge($creditCardOptions['card'], $this->getSensitiveCreditCardObjectOptions($params)); return $creditCardOptions; }
/** * This function collects all the information and * "simulates" a payment processor by creating an incomplete mandate, * that will later be connected with the results of the rest of the * payment process * * @param array $params assoc array of input parameters for this transaction * * @return array the result in an nice formatted array (or an error object) */ function doDirectPayment(&$params) { $original_parameters = $params; // prepare the creation of an incomplete mandate $params['creditor_id'] = $this->_creditorId; $params['contact_id'] = $this->getVar('_contactID'); $params['source'] = $params['description']; $params['iban'] = $params['bank_account_number']; $params['bic'] = $params['bank_identification_number']; $params['creation_date'] = date('YmdHis'); $params['status'] = 'PARTIAL'; if (empty($params['is_recur'])) { $params['type'] = 'OOFF'; $params['entity_table'] = 'civicrm_contribution'; } else { $params['type'] = 'RCUR'; $params['entity_table'] = 'civicrm_contribution_recur'; } // we don't have the associated entity id yet // so we set MAX_INT as a dummy value // remark: setting this to 0/NULL does not work // due to complications with the api $params['entity_id'] = pow(2, 32) - 1; // Allow further manipulation of the arguments via custom hooks .. CRM_Utils_Hook::alterPaymentProcessorParams($this, $original_parameters, $params); // create the mandate $params['version'] = 3; $mandate = civicrm_api('SepaMandate', 'create', $params); if (!empty($mandate['is_error'])) { return CRM_Core_Error::createError(ts("Couldn't create SEPA mandate. Error was: ") . $mandate['error_message']); } $params['trxn_id'] = $mandate['values'][$mandate['id']]['reference']; $params['sepa_start_date'] = empty($params['start_date']) ? date('YmdHis') : date('YmdHis', strtotime($params['start_date'])); // update the contribution, if existing (RCUR case) if (!empty($params['contributionID'])) { $contribution = civicrm_api3('Contribution', 'getsingle', array('id' => $params['contributionID'])); civicrm_api3('Contribution', 'create', array('id' => $params['contributionID'], 'contact_id' => $contribution['contact_id'], 'receive_date' => $params['sepa_start_date'], 'trxn_id' => $params['trxn_id'])); } if (!empty($params['contributionRecurID'])) { civicrm_api3('ContributionRecur', 'create', array('id' => $params['contributionRecurID'], 'start_date' => $params['sepa_start_date'], 'cycle_day' => $params['cycle_day'], 'trxn_id' => $params['trxn_id'])); } return $params; }
/** * Submit a payment using Advanced Integration Method. * * @param array $params * Assoc array of input parameters for this transaction. * * @return array * the result in a nice formatted array (or an error object) */ public function doDirectPayment(&$params) { if (!defined('CURLOPT_SSLCERT')) { return self::error(9001, 'Authorize.Net requires curl with SSL support'); } /* * recurpayment function does not compile an array & then process it - * - the tpl does the transformation so adding call to hook here * & giving it a change to act on the params array */ $newParams = $params; if (!empty($params['is_recur']) && !empty($params['contributionRecurID'])) { CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $newParams); } foreach ($newParams as $field => $value) { $this->_setParam($field, $value); } if (!empty($params['is_recur']) && !empty($params['contributionRecurID'])) { $result = $this->doRecurPayment(); if (is_a($result, 'CRM_Core_Error')) { return $result; } return $params; } $postFields = array(); $authorizeNetFields = $this->_getAuthorizeNetFields(); // Set up our call for hook_civicrm_paymentProcessor, // since we now have our parameters as assigned for the AIM back end. CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $authorizeNetFields); foreach ($authorizeNetFields as $field => $value) { // CRM-7419, since double quote is used as enclosure while doing csv parsing $value = $field == 'x_description' ? str_replace('"', "'", $value) : $value; $postFields[] = $field . '=' . urlencode($value); } // Authorize.Net will not refuse duplicates, so we should check if the user already submitted this transaction if ($this->checkDupe($authorizeNetFields['x_invoice_num'], CRM_Utils_Array::value('contributionID', $params))) { return self::error(9004, 'It appears that this transaction is a duplicate. Have you already submitted the form once? If so there may have been a connection problem. Check your email for a receipt from Authorize.net. If you do not receive a receipt within 2 hours you can try your transaction again. If you continue to have problems please contact the site administrator.'); } $submit = curl_init($this->_paymentProcessor['url_site']); if (!$submit) { return self::error(9002, 'Could not initiate connection to payment gateway'); } curl_setopt($submit, CURLOPT_POST, TRUE); curl_setopt($submit, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($submit, CURLOPT_POSTFIELDS, implode('&', $postFields)); curl_setopt($submit, CURLOPT_SSL_VERIFYPEER, CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'verifySSL')); $response = curl_exec($submit); if (!$response) { return self::error(curl_errno($submit), curl_error($submit)); } curl_close($submit); $response_fields = $this->explode_csv($response); // check gateway MD5 response if (!$this->checkMD5($response_fields[37], $response_fields[6], $response_fields[9])) { return self::error(9003, 'MD5 Verification failed'); } // check for application errors // TODO: // AVS, CVV2, CAVV, and other verification results if ($response_fields[0] != self::AUTH_APPROVED) { $errormsg = $response_fields[2] . ' ' . $response_fields[3]; return self::error($response_fields[1], $errormsg); } // Success // test mode always returns trxn_id = 0 // also live mode in CiviCRM with test mode set in // Authorize.Net return $response_fields[6] = 0 // hence treat that also as test mode transaction // fix for CRM-2566 if ($this->_mode == 'test' || $response_fields[6] == 0) { $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id RLIKE 'test[0-9]+'"; $p = array(); $trxn_id = strval(CRM_Core_DAO::singleValueQuery($query, $p)); $trxn_id = str_replace('test', '', $trxn_id); $trxn_id = intval($trxn_id) + 1; $params['trxn_id'] = sprintf('test%08d', $trxn_id); } else { $params['trxn_id'] = $response_fields[6]; } $params['gross_amount'] = $response_fields[9]; // TODO: include authorization code? return $params; }
/** * Sends request and receive response from eWAY payment process. * * @param array $params * * @return array|object * @throws \Exception */ public function doDirectPayment(&$params) { if (CRM_Utils_Array::value('is_recur', $params) == TRUE) { CRM_Core_Error::fatal(ts('eWAY - recurring payments not implemented')); } if (!defined('CURLOPT_SSLCERT')) { CRM_Core_Error::fatal(ts('eWAY - Gateway requires curl with SSL support')); } // eWAY Client ID $ewayCustomerID = $this->_paymentProcessor['user_name']; // eWAY Gateway URL $gateway_URL = $this->_paymentProcessor['url_site']; //------------------------------------ // create eWAY gateway objects //------------------------------------ $eWAYRequest = new GatewayRequest(); if ($eWAYRequest == NULL || !$eWAYRequest instanceof GatewayRequest) { return self::errorExit(9001, "Error: Unable to create eWAY Request object."); } $eWAYResponse = new GatewayResponse(); if ($eWAYResponse == NULL || !$eWAYResponse instanceof GatewayResponse) { return self::errorExit(9002, "Error: Unable to create eWAY Response object."); } /* //------------------------------------------------------------- // NOTE: eWAY Doesn't use the following at the moment: //------------------------------------------------------------- $creditCardType = $params['credit_card_type']; $currentcyID = $params['currencyID']; $country = $params['country']; */ //------------------------------------------------------------- // Prepare some composite data from _paymentProcessor fields //------------------------------------------------------------- $fullAddress = $params['street_address'] . ", " . $params['city'] . ", " . $params['state_province'] . "."; $expireYear = substr($params['year'], 2, 2); $expireMonth = sprintf('%02d', (int) $params['month']); // CiviCRM V1.9 - Picks up reasonable description //$description = $params['amount_level']; // CiviCRM V2.0 - Picks up description $description = $params['description']; $txtOptions = ""; $amountInCents = round((double) $params['amount'] * 100); $credit_card_name = $params['first_name'] . " "; if (strlen($params['middle_name']) > 0) { $credit_card_name .= $params['middle_name'] . " "; } $credit_card_name .= $params['last_name']; //---------------------------------------------------------------------------------------------------- // We use CiviCRM's param's 'invoiceID' as the unique transaction token to feed to eWAY // Trouble is that eWAY only accepts 16 chars for the token, while CiviCRM's invoiceID is an 32. // As its made from a "$invoiceID = md5(uniqid(rand(), true));" then using the fierst 16 chars // should be alright //---------------------------------------------------------------------------------------------------- $uniqueTrnxNum = substr($params['invoiceID'], 0, 16); //---------------------------------------------------------------------------------------------------- // OPTIONAL: If TEST Card Number force an Override of URL and CutomerID. // During testing CiviCRM once used the LIVE URL. // This code can be uncommented to override the LIVE URL that if CiviCRM does that again. //---------------------------------------------------------------------------------------------------- // if ( ( $gateway_URL == "https://www.eway.com.au/gateway_cvn/xmlpayment.asp") // && ( $params['credit_card_number'] == "4444333322221111" ) ) { // $ewayCustomerID = "87654321"; // $gateway_URL = "https://www.eway.com.au/gateway_cvn/xmltest/testpage.asp"; // } //---------------------------------------------------------------------------------------------------- // Now set the payment details - see http://www.eway.com.au/Support/Developer/PaymentsRealTime.aspx //---------------------------------------------------------------------------------------------------- // 8 Chars - ewayCustomerID - Required $eWAYRequest->EwayCustomerID($ewayCustomerID); // 12 Chars - ewayTotalAmount (in cents) - Required $eWAYRequest->InvoiceAmount($amountInCents); // 50 Chars - ewayCustomerFirstName $eWAYRequest->PurchaserFirstName($params['first_name']); // 50 Chars - ewayCustomerLastName $eWAYRequest->PurchaserLastName($params['last_name']); // 50 Chars - ewayCustomerEmail $eWAYRequest->PurchaserEmailAddress($params['email']); // 255 Chars - ewayCustomerAddress $eWAYRequest->PurchaserAddress($fullAddress); // 6 Chars - ewayCustomerPostcode $eWAYRequest->PurchaserPostalCode($params['postal_code']); // 1000 Chars - ewayCustomerInvoiceDescription $eWAYRequest->InvoiceDescription($description); // 50 Chars - ewayCustomerInvoiceRef $eWAYRequest->InvoiceReference($params['invoiceID']); // 50 Chars - ewayCardHoldersName - Required $eWAYRequest->CardHolderName($credit_card_name); // 20 Chars - ewayCardNumber - Required $eWAYRequest->CardNumber($params['credit_card_number']); // 2 Chars - ewayCardExpiryMonth - Required $eWAYRequest->CardExpiryMonth($expireMonth); // 2 Chars - ewayCardExpiryYear - Required $eWAYRequest->CardExpiryYear($expireYear); // 4 Chars - ewayCVN - Required if CVN Gateway used $eWAYRequest->CVN($params['cvv2']); // 16 Chars - ewayTrxnNumber $eWAYRequest->TransactionNumber($uniqueTrnxNum); // 255 Chars - ewayOption1 $eWAYRequest->EwayOption1($txtOptions); // 255 Chars - ewayOption2 $eWAYRequest->EwayOption2($txtOptions); // 255 Chars - ewayOption3 $eWAYRequest->EwayOption3($txtOptions); $eWAYRequest->CustomerIPAddress($params['ip_address']); $eWAYRequest->CustomerBillingCountry($params['country']); // Allow further manipulation of the arguments via custom hooks .. CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $eWAYRequest); //---------------------------------------------------------------------------------------------------- // Check to see if we have a duplicate before we send //---------------------------------------------------------------------------------------------------- if ($this->checkDupe($params['invoiceID'], CRM_Utils_Array::value('contributionID', $params))) { return self::errorExit(9003, 'It appears that this transaction is a duplicate. Have you already submitted the form once? If so there may have been a connection problem. Check your email for a receipt from eWAY. If you do not receive a receipt within 2 hours you can try your transaction again. If you continue to have problems please contact the site administrator.'); } //---------------------------------------------------------------------------------------------------- // Convert to XML and send the payment information //---------------------------------------------------------------------------------------------------- $requestxml = $eWAYRequest->ToXML(); $submit = curl_init($gateway_URL); if (!$submit) { return self::errorExit(9004, 'Could not initiate connection to payment gateway'); } curl_setopt($submit, CURLOPT_POST, TRUE); // return the result on success, FALSE on failure curl_setopt($submit, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($submit, CURLOPT_POSTFIELDS, $requestxml); curl_setopt($submit, CURLOPT_TIMEOUT, 36000); // if open_basedir or safe_mode are enabled in PHP settings CURLOPT_FOLLOWLOCATION won't work so don't apply it // it's not really required CRM-5841 if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) { // ensures any Location headers are followed curl_setopt($submit, CURLOPT_FOLLOWLOCATION, 1); } // Send the data out over the wire //-------------------------------- $responseData = curl_exec($submit); //---------------------------------------------------------------------------------------------------- // See if we had a curl error - if so tell 'em and bail out // // NOTE: curl_error does not return a logical value (see its documentation), but // a string, which is empty when there was no error. //---------------------------------------------------------------------------------------------------- if (curl_errno($submit) > 0 || strlen(curl_error($submit)) > 0) { $errorNum = curl_errno($submit); $errorDesc = curl_error($submit); // Paranoia - in the unlikley event that 'curl' errno fails if ($errorNum == 0) { $errorNum = 9005; } // Paranoia - in the unlikley event that 'curl' error fails if (strlen($errorDesc) == 0) { $errorDesc = "Connection to eWAY payment gateway failed"; } return self::errorExit($errorNum, $errorDesc); } //---------------------------------------------------------------------------------------------------- // If null data returned - tell 'em and bail out // // NOTE: You will not necessarily get a string back, if the request failed for // any reason, the return value will be the boolean false. //---------------------------------------------------------------------------------------------------- if ($responseData === FALSE || strlen($responseData) == 0) { return self::errorExit(9006, "Error: Connection to payment gateway failed - no data returned."); } //---------------------------------------------------------------------------------------------------- // If gateway returned no data - tell 'em and bail out //---------------------------------------------------------------------------------------------------- if (empty($responseData)) { return self::errorExit(9007, "Error: No data returned from payment gateway."); } //---------------------------------------------------------------------------------------------------- // Success so far - close the curl and check the data //---------------------------------------------------------------------------------------------------- curl_close($submit); //---------------------------------------------------------------------------------------------------- // Payment successfully sent to gateway - process the response now //---------------------------------------------------------------------------------------------------- $eWAYResponse->ProcessResponse($responseData); //---------------------------------------------------------------------------------------------------- // See if we got an OK result - if not tell 'em and bail out //---------------------------------------------------------------------------------------------------- if (self::isError($eWAYResponse)) { $eWayTrxnError = $eWAYResponse->Error(); CRM_Core_Error::debug_var('eWay Error', $eWayTrxnError, TRUE, TRUE); if (substr($eWayTrxnError, 0, 6) == "Error:") { return self::errorExit(9008, $eWayTrxnError); } $eWayErrorCode = substr($eWayTrxnError, 0, 2); $eWayErrorDesc = substr($eWayTrxnError, 3); return self::errorExit(9008, "Error: [" . $eWayErrorCode . "] - " . $eWayErrorDesc . "."); } //----------------------------------------------------------------------------------------------------- // Cross-Check - the unique 'TrxnReference' we sent out should match the just received 'TrxnReference' // // PLEASE NOTE: If this occurs (which is highly unlikely) its a serious error as it would mean we have // received an OK status from eWAY, but their Gateway has not returned the correct unique // token - ie something is broken, BUT money has been taken from the client's account, // so we can't very well error-out as CiviCRM will then not process the registration. // There is an error message commented out here but my preferred response to this unlikley // possibility is to email '*****@*****.**' //----------------------------------------------------------------------------------------------------- $eWayTrxnReference_OUT = $eWAYRequest->GetTransactionNumber(); $eWayTrxnReference_IN = $eWAYResponse->InvoiceReference(); if ($eWayTrxnReference_IN != $eWayTrxnReference_OUT) { // return self::errorExit( 9009, "Error: Unique Trxn code was not returned by eWAY Gateway. This is extremely unusual! Please contact the administrator of this site immediately with details of this transaction."); } /* //---------------------------------------------------------------------------------------------------- // Test mode always returns trxn_id = 0 - so we fix that here // // NOTE: This code was taken from the AuthorizeNet payment processor, however it now appears // unnecessary for the eWAY gateway - Left here in case it proves useful //---------------------------------------------------------------------------------------------------- if ( $this->_mode == 'test' ) { $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE 'test%'"; $p = array( ); $trxn_id = strval( CRM_Core_Dao::singleValueQuery( $query, $p ) ); $trxn_id = str_replace( 'test', '', $trxn_id ); $trxn_id = intval($trxn_id) + 1; $params['trxn_id'] = sprintf('test%08d', $trxn_id); } else { $params['trxn_id'] = $eWAYResponse->TransactionNumber(); } */ //============= // Success ! //============= $beaglestatus = $eWAYResponse->BeagleScore(); if (!empty($beaglestatus)) { $beaglestatus = ": " . $beaglestatus; } $params['trxn_result_code'] = $eWAYResponse->Status() . $beaglestatus; $params['gross_amount'] = $eWAYResponse->Amount(); $params['trxn_id'] = $eWAYResponse->TransactionNumber(); return $params; }
/** * Sets appropriate parameters for checking out to Ogone * * @param array $params name value pair of contribution datat * * @return void * @access public * */ function doTransferCheckout($params, $component) { $config = CRM_Core_Config::singleton(); CRM_Core_Error::debug_var('doTransferCheckOut - params', $params); CRM_Core_Error::debug_var('doTransferCheckOut - component', $component); if ($component != 'contribute' && $component != 'event') { CRM_Core_Error::fatal(ts('Component is invalid')); } // Start building our parameters // - Algemene parameters // PSPID // orderID // amount // currency // language // CN // EMAIL // ownerZIP // owneraddress // ownercty // ownertown // ownertelno // - Controle voor betaling // SHASign // - Feedback na betaling // accepturl // declineurl // exceptionurl // cancelurl // // In order to calculate SHA1 hash: // * parameters sorted in alphabetical order, // * parameter names in uppercase // * name=value pairs separated with SHA passphrase (defined in Ogone > Technical info settings) // $OgoneParams['PSPID'] = $this->_paymentProcessor['user_name']; //TODO: from Ogone tech spec // Although our system can accept up to 30 characters, the norm for most acquirers is 10 or 12. // The exact accepted length and data validation format depend on the acquirer/bank. // If the orderID does not comply to the ref2 rules set by the acquirer, we’ll send our PAYID as ref2 to the acquirer instead. // Avoid using spaces or special characters in the orderID. // // We need to encode following values in orderID to allow further processing in OgoneIPN.php // getContext() in OgoneIPN.php // contributionId // eventID // newOrderNotify() in OgoneIPN.php // contactID // contributionId // eventID // participantID // membershipID // invoiceID - SKIP THIS AND MODIFY newOrderNotify() to ignore this. // invoiceID is too long and causes Ogone orderid to exceed its maximum value of 30 chars. // $orderID = array(CRM_Utils_Array::value('contactID', $params), CRM_Utils_Array::value('contributionID', $params), CRM_Utils_Array::value('contributionTypeID', $params), CRM_Utils_Array::value('eventID', $params), CRM_Utils_Array::value('participantID', $params), CRM_Utils_Array::value('membershipID', $params)); $OgoneParams['orderID'] = implode('-', $orderID); $OgoneParams['amount'] = sprintf("%d", (double) $params['amount'] * 100); $OgoneParams['currency'] = 'EUR'; if (isset($params['preferred_language'])) { $OgoneParams['language'] = $params['preferred_language']; } else { $OgoneParams['language'] = 'nl_NL'; } if (isset($params['first_name']) || isset($params['last_name'])) { $OgoneParams['CN'] = $params['first_name'] . ' ' . $params['last_name']; } if (isset($params['email'])) { $OgoneParams['EMAIL'] = $params['email']; } if (isset($params['postal_code-1'])) { $OgoneParams['ownerZIP'] = $params['postal_code-1']; } if (isset($params['street_address-1'])) { $OgoneParams['owneraddress'] = $params['street_address-1']; } if (isset($params['country-1'])) { $OgoneParams['ownercty'] = $params['country-1']; } if (isset($params['city-1'])) { $OgoneParams['ownertown'] = $params['city-1']; } if (isset($params['phone-1'])) { $OgoneParams['ownertelno'] = $params['phone']; } $notifyURL = $config->userFrameworkResourceURL . "extern/OgoneNotify.php"; $notifyURL .= "?qfKey=" . $params['qfKey']; $OgoneParams['accepturl'] = $notifyURL; $OgoneParams['declineurl'] = $notifyURL; $OgoneParams['exceptionurl'] = $notifyURL; $OgoneParams['cancelurl'] = $notifyURL; // ogone was failing with "unknown order/1/s/" due to non ascii7 char. This is an ugly workaround foreach ($OgoneParams as &$str) { $from = 'àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ'; $to = 'aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY'; $keys = array(); $values = array(); preg_match_all('/./u', $from, $keys); preg_match_all('/./u', $to, $values); $mapping = array_combine($keys[0], $values[0]); $str = strtr($str, $mapping); } $shaSign = calculateSHA1($OgoneParams, $this->_paymentProcessor['password']); $OgoneParams['SHASign'] = $shaSign; //CRM_Core_Error::debug_var('doTransferCheckout - OgoneParams', $OgoneParams); // Allow further manipulation of the arguments via custom hooks .. CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $OgoneParams); // Build our query string; $query_string = ''; foreach ($OgoneParams as $name => $value) { $query_string .= $name . '=' . $value . '&'; } // Remove extra & $query_string = rtrim($query_string, '&'); // Redirect the user to the payment url. CRM_Utils_System::redirect($this->_paymentProcessor['url_site'] . '?' . $query_string); exit; }
/** * Builds appropriate parameters for checking out to google and submits the post params. * * @param array $params * Name value pair of contribution data. * @param string $component * Event/contribution. * @param object $cart * Object of google cart. */ public function submitPostParams($params, $component, $cart) { $url = rtrim($this->_paymentProcessor['url_site'], '/') . '/cws/v2/Merchant/' . $this->_paymentProcessor['user_name'] . '/checkout'; if ($component == "event") { $privateData = "contactID={$params['contactID']},contributionID={$params['contributionID']},contributionTypeID={$params['contributionTypeID']},eventID={$params['eventID']},participantID={$params['participantID']},invoiceID={$params['invoiceID']}"; } elseif ($component == "contribute") { $privateData = "contactID={$params['contactID']},contributionID={$params['contributionID']},contributionTypeID={$params['contributionTypeID']},invoiceID={$params['invoiceID']}"; $contributionRecurID = CRM_Utils_Array::value('contributionRecurID', $params); if ($contributionRecurID) { $privateData .= ",contributionRecurID={$contributionRecurID}"; } $membershipID = CRM_Utils_Array::value('membershipID', $params); if ($membershipID) { $privateData .= ",membershipID={$membershipID}"; } $relatedContactID = CRM_Utils_Array::value('related_contact', $params); if ($relatedContactID) { $privateData .= ",relatedContactID={$relatedContactID}"; $onBehalfDupeAlert = CRM_Utils_Array::value('onbehalf_dupe_alert', $params); if ($onBehalfDupeAlert) { $privateData .= ",onBehalfDupeAlert={$onBehalfDupeAlert}"; } } } // Allow further manipulation of the arguments via custom hooks .. CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $privateData); $cart->SetMerchantPrivateData($privateData); if ($component == "event") { $returnURL = CRM_Utils_System::url('civicrm/event/register', "_qf_ThankYou_display=1&qfKey={$params['qfKey']}", TRUE, NULL, FALSE); } elseif ($component == "contribute") { $returnURL = CRM_Utils_System::url('civicrm/contribute/transact', "_qf_ThankYou_display=1&qfKey={$params['qfKey']}", TRUE, NULL, FALSE); } $cart->SetContinueShoppingUrl($returnURL); $cartVal = base64_encode($cart->GetXML()); $signatureVal = base64_encode($cart->CalcHmacSha1($cart->GetXML())); $googleParams = array('cart' => $cartVal, 'signature' => $signatureVal); require_once 'HTTP/Request.php'; $params = array('method' => HTTP_REQUEST_METHOD_POST, 'allowRedirects' => FALSE); $request = new HTTP_Request($url, $params); foreach ($googleParams as $key => $value) { $request->addPostData($key, $value); } $result = $request->sendRequest(); if (PEAR::isError($result)) { CRM_Core_Error::fatal($result->getMessage()); } if ($request->getResponseCode() != 302) { CRM_Core_Error::fatal(ts('Invalid response code received from Google Checkout: %1', array(1 => $request->getResponseCode()))); } CRM_Utils_System::redirect($request->getResponseHeader('location')); CRM_Utils_System::civiExit(); }
function doTransferCheckout(&$params, $component = 'contribute') { $config = CRM_Core_Config::singleton(); if ($component != 'contribute' && $component != 'event') { CRM_Core_Error::fatal(ts('Component is invalid')); } $notifyURL = $config->userFrameworkResourceURL . "extern/ipn.php?reset=1&contactID={$params['contactID']}" . "&contributionID={$params['contributionID']}" . "&module={$component}"; if ($component == 'event') { $notifyURL .= "&eventID={$params['eventID']}&participantID={$params['participantID']}"; } else { $membershipID = CRM_Utils_Array::value('membershipID', $params); if ($membershipID) { $notifyURL .= "&membershipID={$membershipID}"; } $relatedContactID = CRM_Utils_Array::value('related_contact', $params); if ($relatedContactID) { $notifyURL .= "&relatedContactID={$relatedContactID}"; $onBehalfDupeAlert = CRM_Utils_Array::value('onbehalf_dupe_alert', $params); if ($onBehalfDupeAlert) { $notifyURL .= "&onBehalfDupeAlert={$onBehalfDupeAlert}"; } } } $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); $cancelURL = CRM_Utils_System::url($url, "{$cancel}=1&cancel=1&qfKey={$params['qfKey']}", true, null, false); // ensure that the returnURL is absolute. if (substr($returnURL, 0, 4) != 'http') { require_once 'CRM/Utils/System.php'; $fixUrl = CRM_Utils_System::url("civicrm/admin/setting/url", '&reset=1'); CRM_Core_Error::fatal(ts('Sending a relative URL to Click And Pledge is erroneous. Please make your resource URL (in <a href="%1">Administer CiviCRM » Global Settings » Resource URLs</a> ) complete.', array(1 => $fixUrl))); } $ClickAndPledgeParams = array('WID' => $this->_paymentProcessor['user_name'], 'R' => $returnURL, 'D' => $deductAmount, 'B' => $this->_paymentProcessor['signature'], 'T' => $params['amount'], 'RD' => '1', 'C' => '1', 'I' => $params['invoiceID']); // add name and address if available, CRM-3130 $otherVars = array('first_name' => 'first_name', 'last_name' => 'last_name', 'street_address' => 'address1', 'city' => 'city', 'state_province' => 'state', 'postal_code' => 'zip', 'email' => 'email'); foreach (array_keys($params) as $p) { // get the base name without the location type suffixed to it $parts = explode('-', $p); $name = count($parts) > 1 ? $parts[0] : $p; if (isset($otherVars[$name])) { $value = $params[$p]; if ($name == 'state_province') { $stateName = CRM_Core_PseudoConstant::stateProvinceAbbreviation($value); $value = $stateName; } if ($value) { $ClickAndPledgeParams[$otherVars[$name]] = $value; } } } // if recurring donations, add a few more items if (!empty($params['is_recur'])) { if ($params['contributionRecurID']) { $notifyURL .= "&contributionRecurID={$params['contributionRecurID']}&contributionPageID={$params['contributionPageID']}"; $ClickAndPledgeParams['notify_url'] = $notifyURL; } else { CRM_Core_Error::fatal(ts('Recurring contribution, but no database id')); } $ClickAndPledgeParams = array('WID' => $this->_paymentProcessor['user_name'], 'R' => $returnURL, 'B' => $this->_paymentProcessor['signature'], 'T' => $params['amount'], 'RD' => '1', 'C' => '1', 'I' => $params['invoiceID']); } else { $ClickAndPledgeParams += array('cmd' => '_xclick', 'amount' => $params['amount']); } // Allow further manipulation of the arguments via custom hooks .. CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $ClickAndPledgeParams); $uri = ''; foreach ($ClickAndPledgeParams as $key => $value) { if ($value === null) { continue; } $value = urlencode($value); if ($key == 'return' || $key == 'cancel_return' || $key == 'notify_url') { $value = str_replace('%2F', '/', $value); } $uri .= "&{$key}={$value}"; } $uri = substr($uri, 1); $url = $this->_paymentProcessor['url_site']; $sub = empty($params['is_recur']) ? 'xclick' : 'subscriptions'; $clickandpledgeURL = "{$url}?{$uri}"; CRM_Utils_System::redirect($clickandpledgeURL); }
/** * @param array $params * @param string $component * * @throws Exception */ public function doTransferCheckout(&$params, $component = 'contribute') { $config = CRM_Core_Config::singleton(); if ($component != 'contribute' && $component != 'event') { CRM_Core_Error::fatal(ts('Component is invalid')); } $notifyURL = $config->userFrameworkResourceURL . "extern/ipn.php?reset=1&contactID={$params['contactID']}" . "&contributionID={$params['contributionID']}" . "&module={$component}"; if ($component == 'event') { $notifyURL .= "&eventID={$params['eventID']}&participantID={$params['participantID']}"; } else { $membershipID = CRM_Utils_Array::value('membershipID', $params); if ($membershipID) { $notifyURL .= "&membershipID={$membershipID}"; } $relatedContactID = CRM_Utils_Array::value('related_contact', $params); if ($relatedContactID) { $notifyURL .= "&relatedContactID={$relatedContactID}"; $onBehalfDupeAlert = CRM_Utils_Array::value('onbehalf_dupe_alert', $params); if ($onBehalfDupeAlert) { $notifyURL .= "&onBehalfDupeAlert={$onBehalfDupeAlert}"; } } } $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); $cancelUrlString = "{$cancel}=1&cancel=1&qfKey={$params['qfKey']}"; if (!empty($params['is_recur'])) { $cancelUrlString .= "&isRecur=1&recurId={$params['contributionRecurID']}&contribId={$params['contributionID']}"; } $cancelURL = CRM_Utils_System::url($url, $cancelUrlString, TRUE, NULL, FALSE); // ensure that the returnURL is absolute. if (substr($returnURL, 0, 4) != 'http') { $fixUrl = CRM_Utils_System::url("civicrm/admin/setting/url", '&reset=1'); CRM_Core_Error::fatal(ts('Sending a relative URL to PayPalIPN is erroneous. Please make your resource URL (in <a href="%1">Administer » System Settings » Resource URLs</a> ) complete.', array(1 => $fixUrl))); } $paypalParams = array('business' => $this->_paymentProcessor['user_name'], 'notify_url' => $notifyURL, 'item_name' => $params['item_name'], 'quantity' => 1, 'undefined_quantity' => 0, 'cancel_return' => $cancelURL, 'no_note' => 1, 'no_shipping' => 1, 'return' => $returnURL, 'rm' => 2, 'currency_code' => $params['currencyID'], 'invoice' => $params['invoiceID'], 'lc' => substr($config->lcMessages, -2), 'charset' => function_exists('mb_internal_encoding') ? mb_internal_encoding() : 'UTF-8', 'custom' => CRM_Utils_Array::value('accountingCode', $params), 'bn' => 'CiviCRM_SP'); // add name and address if available, CRM-3130 $otherVars = array('first_name' => 'first_name', 'last_name' => 'last_name', 'street_address' => 'address1', 'country' => 'country', 'preferred_language' => 'lc', 'city' => 'city', 'state_province' => 'state', 'postal_code' => 'zip', 'email' => 'email'); foreach (array_keys($params) as $p) { // get the base name without the location type suffixed to it $parts = explode('-', $p); $name = count($parts) > 1 ? $parts[0] : $p; if (isset($otherVars[$name])) { $value = $params[$p]; if ($value) { if ($name == 'state_province') { $stateName = CRM_Core_PseudoConstant::stateProvinceAbbreviation($value); $value = $stateName; } if ($name == 'country') { $countryName = CRM_Core_PseudoConstant::countryIsoCode($value); $value = $countryName; } // ensure value is not an array // CRM-4174 if (!is_array($value)) { $paypalParams[$otherVars[$name]] = $value; } } } } // if recurring donations, add a few more items if (!empty($params['is_recur'])) { if ($params['contributionRecurID']) { $notifyURL .= "&contributionRecurID={$params['contributionRecurID']}&contributionPageID={$params['contributionPageID']}"; $paypalParams['notify_url'] = $notifyURL; } else { CRM_Core_Error::fatal(ts('Recurring contribution, but no database id')); } $paypalParams += array('cmd' => '_xclick-subscriptions', 'a3' => $params['amount'], 'p3' => $params['frequency_interval'], 't3' => ucfirst(substr($params['frequency_unit'], 0, 1)), 'src' => 1, 'sra' => 1, 'srt' => CRM_Utils_Array::value('installments', $params), 'no_note' => 1, 'modify' => 0); } else { $paypalParams += array('cmd' => '_xclick', 'amount' => $params['amount']); } // Allow further manipulation of the arguments via custom hooks .. CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $paypalParams); $uri = ''; foreach ($paypalParams as $key => $value) { if ($value === NULL) { continue; } $value = urlencode($value); if ($key == 'return' || $key == 'cancel_return' || $key == 'notify_url') { $value = str_replace('%2F', '/', $value); } $uri .= "&{$key}={$value}"; } $uri = substr($uri, 1); $url = $this->_paymentProcessor['url_site']; $sub = empty($params['is_recur']) ? 'cgi-bin/webscr' : 'subscriptions'; $paypalURL = "{$url}{$sub}?{$uri}"; CRM_Utils_System::redirect($paypalURL); }
/** * Submit a payment using Advanced Integration Method * * @param array $params assoc array of input parameters for this transaction * @return array the result in a nice formatted array (or an error object) * @public */ function doDirectPayment(&$params) { if (!defined('CURLOPT_SSLCERT')) { return self::error(9001, 'Authorize.Net requires curl with SSL support'); } foreach ($params as $field => $value) { $this->_setParam($field, $value); } if ($params['is_recur'] && $params['installments'] > 1) { return $this->doRecurPayment($params); } $postFields = array(); $authorizeNetFields = $this->_getAuthorizeNetFields(); // Set up our call for hook_civicrm_paymentProcessor, // since we now have our parameters as assigned for the AIM back end. CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $authorizeNetFields); foreach ($authorizeNetFields as $field => $value) { $postFields[] = $field . '=' . urlencode($value); } // Authorize.Net will not refuse duplicates, so we should check if the user already submitted this transaction if ($this->_checkDupe($authorizeNetFields['x_invoice_num'])) { return self::error(9004, 'It appears that this transaction is a duplicate. Have you already submitted the form once? If so there may have been a connection problem. Check your email for a receipt from Authorize.net. If you do not receive a receipt within 2 hours you can try your transaction again. If you continue to have problems please contact the site administrator.'); } $submit = curl_init($this->_paymentProcessor['url_site']); if (!$submit) { return self::error(9002, 'Could not initiate connection to payment gateway'); } curl_setopt($submit, CURLOPT_POST, true); curl_setopt($submit, CURLOPT_RETURNTRANSFER, true); curl_setopt($submit, CURLOPT_POSTFIELDS, implode('&', $postFields)); $response = curl_exec($submit); if (!$response) { return self::error(curl_errno($submit), curl_error($submit)); } curl_close($submit); $response_fields = $this->explode_csv($response); // check gateway MD5 response if (!$this->checkMD5($response_fields[37], $response_fields[6], $response_fields[9])) { return self::error(9003, 'MD5 Verification failed'); } // check for application errors // TODO: // AVS, CVV2, CAVV, and other verification results if ($response_fields[0] != self::AUTH_APPROVED) { $errormsg = $response_fields[2] . ' ' . $response_fields[3]; return self::error($response_fields[1], $errormsg); } // Success // test mode always returns trxn_id = 0 // also live mode in CiviCRM with test mode set in // Authorize.Net return $response_fields[6] = 0 // hence treat that also as test mode transaction // fix for CRM-2566 if ($this->_mode == 'test' || $response_fields[6] == 0) { $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE 'test%'"; $p = array(); $trxn_id = strval(CRM_Core_Dao::singleValueQuery($query, $p)); $trxn_id = str_replace('test', '', $trxn_id); $trxn_id = intval($trxn_id) + 1; $params['trxn_id'] = sprintf('test%08d', $trxn_id); } else { $params['trxn_id'] = $response_fields[6]; } $params['gross_amount'] = $response_fields[9]; // TODO: include authorization code? return $params; }
/** * This function sends request and receives response from * the processor * @param array $params * @return array|object * @throws Exception */ public function doDirectPayment(&$params) { if (isset($params['is_recur']) && $params['is_recur'] == TRUE) { CRM_Core_Error::fatal(ts('Elavon - recurring payments not implemented')); } if (!defined('CURLOPT_SSLCERT')) { CRM_Core_Error::fatal(ts('Elavon / Nova Virtual Merchant Gateway requires curl with SSL support')); } //Create the array of variables to be sent to the processor from the $params array // passed into this function $requestFields = self::mapProcessorFieldstoParams($params); // define variables for connecting with the gateway $requestFields['ssl_merchant_id'] = $this->_paymentProcessor['user_name']; $requestFields['ssl_user_id'] = $this->_paymentProcessor['password']; $requestFields['ssl_pin'] = $this->_paymentProcessor['signature']; $host = $this->_paymentProcessor['url_site']; if ($this->_mode == "test") { $requestFields['ssl_test_mode'] = "TRUE"; } // Allow further manipulation of the arguments via custom hooks .. CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $requestFields); // Check to see if we have a duplicate before we send if ($this->checkDupe($params['invoiceID'], CRM_Utils_Array::value('contributionID', $params))) { return self::errorExit(9003, 'It appears that this transaction is a duplicate. Have you already submitted the form once? If so there may have been a connection problem. Check your email for a receipt. If you do not receive a receipt within 2 hours you can try your transaction again. If you continue to have problems please contact the site administrator.'); } // Convert to XML using function below $xml = self::buildXML($requestFields); // Send to the payment processor using cURL $chHost = $host . '?xmldata=' . $xml; $ch = curl_init($chHost); if (!$ch) { return self::errorExit(9004, 'Could not initiate connection to payment gateway'); } curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, Civi::settings()->get('verifySSL') ? 2 : 0); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, Civi::settings()->get('verifySSL')); // return the result on success, FALSE on failure curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 36000); // set this for debugging -look for output in apache error log //curl_setopt ($ch,CURLOPT_VERBOSE,1 ); // ensures any Location headers are followed if (ini_get('open_basedir') == '' && ini_get('safe_mode') == 'Off') { curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); } // Send the data out over the wire $responseData = curl_exec($ch); // See if we had a curl error - if so tell 'em and bail out // NOTE: curl_error does not return a logical value (see its documentation), but // a string, which is empty when there was no error. if (curl_errno($ch) > 0 || strlen(curl_error($ch)) > 0) { curl_close($ch); $errorNum = curl_errno($ch); $errorDesc = curl_error($ch); // Paranoia - in the unlikley event that 'curl' errno fails if ($errorNum == 0) { $errorNum = 9005; } // Paranoia - in the unlikley event that 'curl' error fails if (strlen($errorDesc) == 0) { $errorDesc = "Connection to payment gateway failed"; } if ($errorNum = 60) { return self::errorExit($errorNum, "Curl error - " . $errorDesc . " Try this link for more information http://curl.haxx.se/docs/sslcerts.html"); } return self::errorExit($errorNum, "Curl error - " . $errorDesc . " your key is located at " . $key . " the url is " . $host . " xml is " . $requestxml . " processor response = " . $processorResponse); } // If null data returned - tell 'em and bail out // NOTE: You will not necessarily get a string back, if the request failed for // any reason, the return value will be the boolean false. if ($responseData === FALSE || strlen($responseData) == 0) { curl_close($ch); return self::errorExit(9006, "Error: Connection to payment gateway failed - no data returned."); } // If gateway returned no data - tell 'em and bail out if (empty($responseData)) { curl_close($ch); return self::errorExit(9007, "Error: No data returned from payment gateway."); } // Success so far - close the curl and check the data curl_close($ch); // Payment successfully sent to gateway - process the response now $processorResponse = self::decodeXMLResponse($responseData); // success in test mode returns response "APPROVED" // test mode always returns trxn_id = 0 // fix for CRM-2566 if ($processorResponse['errorCode']) { return self::errorExit(9010, "Error: [" . $processorResponse['errorCode'] . " " . $processorResponse['errorName'] . " " . $processorResponse['errorMessage'] . "] - from payment processor"); } if ($processorResponse['ssl_result_message'] == "APPROVED") { if ($this->_mode == 'test') { $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE 'test%'"; $p = array(); $trxn_id = strval(CRM_Core_Dao::singleValueQuery($query, $p)); $trxn_id = str_replace('test', '', $trxn_id); $trxn_id = intval($trxn_id) + 1; $params['trxn_id'] = sprintf('test%08d', $trxn_id); return $params; } else { return self::errorExit(9099, "Error: [approval code related to test transaction but mode was " . $this->_mode); } } // transaction failed, print the reason if ($processorResponse['ssl_result_message'] != "APPROVAL") { return self::errorExit(9009, "Error: [" . $processorResponse['ssl_result_message'] . " " . $processorResponse['ssl_result'] . "] - from payment processor"); } else { // Success ! if ($this->_mode != 'test') { // 'trxn_id' is varchar(255) field. returned value is length 37 $params['trxn_id'] = $processorResponse['ssl_txn_id']; } $params['trxn_result_code'] = $processorResponse['ssl_approval_code'] . "-Cvv2:" . $processorResponse['ssl_cvv2_response'] . "-avs:" . $processorResponse['ssl_avs_response']; return $params; } }
/** * CiviCRM Notify / Transfer method payment. * This is fired when you click to make your contribution. * * @param array $params * Name-value pair of contribution data. * @param string $component * contribute or event * * @return void * @access public * */ function doTransferCheckout(&$params, $component) { $config = CRM_Core_Config::singleton(); // Prepare return URLs. switch ($component) { case 'contribute': $dt_params['successUrl'] = $config->userFrameworkBaseURL . 'civicrm/contribute/transact%3F_qf_ThankYou_display=1%26qfKey=' . $params['qfKey']; $dt_params['errorUrl'] = $config->userFrameworkBaseURL . 'civicrm/contribute/transact%3F_qf_Main_display=1%26cancel=1%26qfKey=' . $params['qfKey']; $dt_params['cancelUrl'] = $config->userFrameworkBaseURL . 'civicrm/contribute/transact%3F_qf_Confirm_display=true%26qfKey=' . $params['qfKey']; break; case 'event': $dt_params['successUrl'] = $config->userFrameworkBaseURL . 'civicrm/event/register%3F_qf_ThankYou_display=1%26qfKey=' . $params['qfKey']; $dt_params['errorUrl'] = $config->userFrameworkBaseURL . 'civicrm/event/register%3F_qf_Confirm_display=true%26qfKey=' . $params['qfKey']; $dt_params['cancelUrl'] = $config->userFrameworkBaseURL . 'civicrm/event/register%3F_qf_Confirm_display=true%26qfKey=' . $params['qfKey']; break; } // Prepare manditory parameters. $dt_params['merchantId'] = $this->_paymentProcessor['user_name']; $dt_params['language'] = 'en'; $dt_params['reqtype'] = 'CAA'; $dt_params['refno'] = $params['invoiceID']; $dt_params['qfKey'] = $params['qfKey']; $dt_params['mode'] = $this->_mode; $dt_params['component'] = $component; $dt_params['payment_processor_id'] = $this->_paymentProcessor['id']; $dt_params['contactID'] = $params['contactID']; $dt_params['contributionID'] = $params['contributionID']; $dt_params['contributionTypeID'] = $params['contributionTypeID']; // Conditional parameters based on contribution or event. switch ($component) { case 'contribute': if (isset($params['membershipID'])) { $dt_params['membershipID'] = $params['membershipID']; } break; case 'event': $dt_params['participantID'] = $params['participantID']; $dt_params['eventID'] = $params['eventID']; break; } // Amount required in smallest unit of currency. // @TODO Handle other currencies. switch ($params['currencyID']) { // Example handling of currency rule. Obviously default can handle USD. case 'USD': $dt_params['amount'] = $params['amount'] * 100; break; // Default currencies to Native * 100 = Smallest Unit. // Default currencies to Native * 100 = Smallest Unit. default: $dt_params['amount'] = $params['amount'] * 100; break; } // @TODO Handle switching currency code if any require. (Civi/DT mismatch). $dt_params['currency'] = $params['currencyID']; // Prepare Customer details. // Turn on Name & Address profile to capture more info. if (isset($params['email'])) { $email = $params['email']; } elseif (isset($params['email-5'])) { $email = $params['email-5']; } elseif (isset($params['email-Primary'])) { $email = $params['email-Primary']; } if (isset($email)) { $dt_params['uppCustomerDetails'] = 'yes'; $dt_params['uppCustomerEmail'] = $email; if (!empty($params['first_name'])) { $dt_params['uppCustomerFirstName'] = $params['first_name']; } if (!empty($params['last_name'])) { $dt_params['uppCustomerLastName'] = $params['last_name']; } if (!empty($params['street_address-1'])) { $dt_params['uppCustomerStreet'] = $params['street_address-1']; } if (!empty($params['city-1'])) { $dt_params['uppCustomerCity'] = $params['city-1']; } if (!empty($params['postal_code-1'])) { $dt_params['uppCustomerZipCode'] = $params['postal_code-1']; } } // @TODO Does DT allow for a payment description? This does nothing for now. $payment_description = '# CiviCRM Donation Page # ' . $params['description'] . ' # Invoice ID # ' . $params['invoiceID']; // Create the 'sign' parameter for HMAC Security option. $dt_hmac = pack("H*", $this->_paymentProcessor['password']); $dt_params['sign'] = hash_hmac('md5', $this->_paymentProcessor['user_name'] . $dt_params['amount'] . $dt_params['currency'] . $dt_params['refno'], $dt_hmac); // Allow further manipulation of the arguments via custom hooks. CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $dt_params); // Prepare query string & remove ending '&'. $dt_post_string = ''; foreach ($dt_params as $name => $value) { $dt_post_string .= $name . '=' . $value . '&'; } $dt_post_string = rtrim($dt_post_string, '&'); // Fire away! CRM_Utils_System::redirect($this->_paymentProcessor['url_site'] . '?' . $dt_post_string); }