X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=CRM%2FCore%2FPayment.php;h=c52693c8e8539a996224609d09aaaeba096ba1b3;hb=21dfd5f567e7996ad92cf2a7d0fbe6f5fc205a5c;hp=9d143ea7ba3b64de517973b6f87c232825fbb896;hpb=9c41996008a0cb938cd30d8996cdec462c6a61a7;p=civicrm-core.git
diff --git a/CRM/Core/Payment.php b/CRM/Core/Payment.php
index 9d143ea7ba..c52693c8e8 100644
--- a/CRM/Core/Payment.php
+++ b/CRM/Core/Payment.php
@@ -1,7 +1,7 @@
getMapper();
if ($ext->isExtensionKey($paymentProcessor['class_name'])) {
$paymentClass = $ext->keyToClass($paymentProcessor['class_name'], 'payment');
- require_once ($ext->classToPath($paymentClass));
+ require_once $ext->classToPath($paymentClass);
}
else {
$paymentClass = 'CRM_Core_' . $paymentProcessor['class_name'];
- require_once (str_replace('_', DIRECTORY_SEPARATOR, $paymentClass) . '.php');
+ if (empty($paymentClass)) {
+ throw new CRM_Core_Exception('no class provided');
+ }
+ require_once str_replace('_', DIRECTORY_SEPARATOR, $paymentClass) . '.php';
}
//load the object.
@@ -120,15 +129,15 @@ abstract class CRM_Core_Payment {
}
//load the payment form for required processor.
- if ($paymentForm !== NULL) {
- self::$_singleton[$cacheKey]->setForm($paymentForm);
- }
+ //if ($paymentForm !== NULL) {
+ //self::$_singleton[$cacheKey]->setForm($paymentForm);
+ //}
return self::$_singleton[$cacheKey];
}
/**
- * @param $params
+ * @param array $params
*
* @return mixed
*/
@@ -145,13 +154,67 @@ abstract class CRM_Core_Payment {
$log->alert($message, $_REQUEST);
}
+ /**
+ * Check if capability is supported
+ * @param string $capability
+ * E.g BackOffice, LiveMode, FutureRecurStartDate.
+ *
+ * @return bool
+ */
+ public function supports($capability) {
+ $function = 'supports' . ucfirst($capability);
+ if (method_exists($this, $function)) {
+ return $this->$function();
+ }
+ return FALSE;
+ }
+
+ /**
+ * Are back office payments supported - e.g paypal standard won't permit you to enter a credit card associated with someone else's login
+ * The intention is to support off-site (other than paypal) & direct debit but that is not all working yet so to reach a 'stable' point we disable
+ * @return bool
+ */
+ protected function supportsBackOffice() {
+ if ($this->_paymentProcessor['billing_mode'] == 4 || $this->_paymentProcessor['payment_type'] != 1) {
+ return FALSE;
+ }
+ else {
+ return TRUE;
+ }
+ }
+
+ /**
+ * Are live payments supported - e.g dummy doesn't support this
+ * @return bool
+ */
+ protected function supportsLiveMode() {
+ return TRUE;
+ }
+
+ /**
+ * Are test payments supported
+ * @return bool
+ */
+ protected function supportsTestMode() {
+ return TRUE;
+ }
+
+ /**
+ * Should the first payment date be configurable when setting up back office recurring payments
+ * We set this to false for historical consistency but in fact most new processors use tokens for recurring and can support this
+ * @return bool
+ */
+ protected function supportsFutureRecurStartDate() {
+ return FALSE;
+ }
+
/**
* Setter for the payment form that wants to use the processor
*
* @param CRM_Core_Form $paymentForm
*
*/
- function setForm(&$paymentForm) {
+ public function setForm(&$paymentForm) {
$this->_paymentForm = $paymentForm;
}
@@ -160,23 +223,218 @@ abstract class CRM_Core_Payment {
*
* @return CRM_Core_Form A form object
*/
- function getForm() {
+ public function getForm() {
return $this->_paymentForm;
}
/**
* Getter for accessing member vars
*
+ * @param string $name
+ *
+ * @return null
*/
- function getVar($name) {
+ public function getVar($name) {
return isset($this->$name) ? $this->$name : NULL;
}
+ /**
+ * Get name for the payment information type
+ *
+ * @return string
+ */
+ public function getPaymentTypeName() {
+ return $this->_paymentProcessor['payment_type'] == 1 ? 'credit_card' : 'direct_debit';
+ }
+
+ /**
+ * Get label for the payment information type
+ *
+ * @return string
+ */
+ public function getPaymentTypeLabel() {
+ return $this->_paymentProcessor['payment_type'] == 1 ? 'Credit Card' : 'Direct Debit';
+ }
+
+ /**
+ * Get array of fields that should be displayed on the payment form
+ * @todo make payment type an option value & use it in the function name - currently on debit & credit card work
+ * @return array
+ * @throws CiviCRM_API3_Exception
+ */
+ public function getPaymentFormFields() {
+ if ($this->_paymentProcessor['billing_mode'] == 4) {
+ return array();
+ }
+ return $this->_paymentProcessor['payment_type'] == 1 ? $this->getCreditCardFormFields() : $this->getDirectDebitFormFields();
+ }
+
+ /**
+ * Get array of fields that should be displayed on the payment form for credit cards
+ *
+ * @return array
+ */
+ protected function getCreditCardFormFields() {
+ return array(
+ 'credit_card_type',
+ 'credit_card_number',
+ 'cvv2',
+ 'credit_card_exp_date',
+ );
+ }
+
+ /**
+ * Get array of fields that should be displayed on the payment form for direct debits
+ *
+ * @return array
+ */
+ protected function getDirectDebitFormFields() {
+ return array(
+ 'account_holder',
+ 'bank_account_number',
+ 'bank_identification_number',
+ 'bank_name',
+ );
+ }
+
+ /**
+ * Return an array of all the details about the fields potentially required for payment fields
+ * Only those determined by getPaymentFormFields will actually be assigned to the form
+ *
+ * @return array field metadata
+ */
+ public function getPaymentFormFieldsMetadata() {
+ //@todo convert credit card type into an option value
+ $creditCardType = array('' => ts('- select -')) + CRM_Contribute_PseudoConstant::creditCard();
+ return array(
+ 'credit_card_number' => array(
+ 'htmlType' => 'text',
+ 'name' => 'credit_card_number',
+ 'title' => ts('Card Number'),
+ 'cc_field' => TRUE,
+ 'attributes' => array(
+ 'size' => 20,
+ 'maxlength' => 20,
+ 'autocomplete' => 'off',
+ ),
+ 'is_required' => TRUE,
+ ),
+ 'cvv2' => array(
+ 'htmlType' => 'text',
+ 'name' => 'cvv2',
+ 'title' => ts('Security Code'),
+ 'cc_field' => TRUE,
+ 'attributes' => array(
+ 'size' => 5,
+ 'maxlength' => 10,
+ 'autocomplete' => 'off',
+ ),
+ 'is_required' => CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME,
+ 'cvv_backoffice_required',
+ NULL,
+ 1
+ ),
+ 'rules' => array(
+ array(
+ 'rule_message' => ts('Please enter a valid value for your card security code. This is usually the last 3-4 digits on the card\'s signature panel.'),
+ 'rule_name' => 'integer',
+ 'rule_parameters' => NULL,
+ )),
+ ),
+ 'credit_card_exp_date' => array(
+ 'htmlType' => 'date',
+ 'name' => 'credit_card_exp_date',
+ 'title' => ts('Expiration Date'),
+ 'cc_field' => TRUE,
+ 'attributes' => CRM_Core_SelectValues::date('creditCard'),
+ 'is_required' => TRUE,
+ 'rules' => array(
+ array(
+ 'rule_message' => ts('Card expiration date cannot be a past date.'),
+ 'rule_name' => 'currentDate',
+ 'rule_parameters' => TRUE,
+ )),
+ ),
+ 'credit_card_type' => array(
+ 'htmlType' => 'select',
+ 'name' => 'credit_card_type',
+ 'title' => ts('Card Type'),
+ 'cc_field' => TRUE,
+ 'attributes' => $creditCardType,
+ 'is_required' => FALSE,
+ ),
+ 'account_holder' => array(
+ 'htmlType' => 'text',
+ 'name' => 'account_holder',
+ 'title' => ts('Account Holder'),
+ 'cc_field' => TRUE,
+ 'attributes' => array(
+ 'size' => 20,
+ 'maxlength' => 34,
+ 'autocomplete' => 'on',
+ ),
+ 'is_required' => TRUE,
+ ),
+ //e.g. IBAN can have maxlength of 34 digits
+ 'bank_account_number' => array(
+ 'htmlType' => 'text',
+ 'name' => 'bank_account_number',
+ 'title' => ts('Bank Account Number'),
+ 'cc_field' => TRUE,
+ 'attributes' => array(
+ 'size' => 20,
+ 'maxlength' => 34,
+ 'autocomplete' => 'off',
+ ),
+ 'rules' => array(
+ array(
+ 'rule_message' => ts('Please enter a valid Bank Identification Number (value must not contain punctuation characters).'),
+ 'rule_name' => 'nopunctuation',
+ 'rule_parameters' => NULL,
+ )),
+ 'is_required' => TRUE,
+ ),
+ //e.g. SWIFT-BIC can have maxlength of 11 digits
+ 'bank_identification_number' => array(
+ 'htmlType' => 'text',
+ 'name' => 'bank_identification_number',
+ 'title' => ts('Bank Identification Number'),
+ 'cc_field' => TRUE,
+ 'attributes' => array(
+ 'size' => 20,
+ 'maxlength' => 11,
+ 'autocomplete' => 'off',
+ ),
+ 'is_required' => TRUE,
+ 'rules' => array(
+ array(
+ 'rule_message' => ts('Please enter a valid Bank Identification Number (value must not contain punctuation characters).'),
+ 'rule_name' => 'nopunctuation',
+ 'rule_parameters' => NULL,
+ )),
+ ),
+ 'bank_name' => array(
+ 'htmlType' => 'text',
+ 'name' => 'bank_name',
+ 'title' => ts('Bank Name'),
+ 'cc_field' => TRUE,
+ 'attributes' => array(
+ 'size' => 20,
+ 'maxlength' => 64,
+ 'autocomplete' => 'off',
+ ),
+ 'is_required' => TRUE,
+
+ ),
+ );
+ }
+
/**
* 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
+ * @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
@@ -184,12 +442,33 @@ abstract class CRM_Core_Payment {
abstract function doDirectPayment(&$params);
/**
- * This function checks to see if we have the right config values
+ * Process payment - this function wraps around both doTransferPayment and doDirectPayment
+ * it ensures an exception is thrown & moves some of this logic out of the form layer and makes the forms more agnostic
+ *
+ * @param array $params
*
- * @internal param string $mode the mode we are operating in (live or test)
+ * @param $component
+ *
+ * @throws CRM_Core_Exception
+ */
+ public function doPayment(&$params, $component) {
+ if ($this->_paymentProcessor['billing_mode'] == 4) {
+ $result = $this->doTransferCheckout($params, $component);
+ }
+ else {
+ $result = $this->doDirectPayment($params, $component);
+ }
+ if (is_a($result, 'CRM_Core_Error')) {
+ throw new CRM_Core_Exception(CRM_Core_Error::getMessages($result));
+ }
+ //CRM-15767 - Submit Credit Card Contribution not being saved
+ return $result;
+ }
+
+ /**
+ * This function checks to see if we have the right config values
*
* @return string the error message if any
- * @public
*/
abstract function checkConfig();
@@ -198,7 +477,7 @@ abstract class CRM_Core_Payment {
*
* @return bool
*/
- static function paypalRedirect(&$paymentProcessor) {
+ public static function paypalRedirect(&$paymentProcessor) {
if (!$paymentProcessor) {
return FALSE;
}
@@ -216,9 +495,8 @@ abstract class CRM_Core_Payment {
/**
* Page callback for civicrm/payment/ipn
- * @public
*/
- static function handleIPN() {
+ public static function handleIPN() {
self::handlePaymentMethod(
'PaymentNotification',
array(
@@ -235,11 +513,10 @@ abstract class CRM_Core_Payment {
* processor & ideally the processor will be validating the results
* Load requested payment processor and call that processor's handle<$method> method
*
- * @public
* @param $method
* @param array $params
*/
- static function handlePaymentMethod($method, $params = array()) {
+ public static function handlePaymentMethod($method, $params = array()) {
if (!isset($params['processor_id']) && !isset($params['processor_name'])) {
CRM_Core_Error::fatal("Either 'processor_id' or 'processor_name' param is required for payment callback");
}
@@ -319,10 +596,12 @@ abstract class CRM_Core_Payment {
$extension_instance_found = TRUE;
}
- if (!$extension_instance_found) CRM_Core_Error::fatal(
- "No extension instances of the '{$params['processor_name']}' payment processor were found.
" .
- "$method method is unsupported in legacy payment processors."
- );
+ if (!$extension_instance_found) {
+ CRM_Core_Error::fatal(
+ "No extension instances of the '{$params['processor_name']}' payment processor were found.
" .
+ "$method method is unsupported in legacy payment processors."
+ );
+ }
// Exit here on web requests, allowing just the plain text response to be echoed
if ($method == 'handlePaymentNotification') {
@@ -331,38 +610,40 @@ abstract class CRM_Core_Payment {
}
/**
- * Function to check whether a method is present ( & supported ) by the payment processor object.
+ * Check whether a method is present ( & supported ) by the payment processor object.
*
- * @param string $method method to check for.
+ * @param string $method
+ * Method to check for.
*
* @return boolean
- * @public
*/
- function isSupported($method = 'cancelSubscription') {
+ public function isSupported($method = 'cancelSubscription') {
return method_exists(CRM_Utils_System::getClassName($this), $method);
}
/**
- * @param null $entityID
+ * @param int $entityID
* @param null $entity
* @param string $action
*
* @return string
*/
- function subscriptionURL($entityID = NULL, $entity = NULL, $action = 'cancel') {
+ public function subscriptionURL($entityID = NULL, $entity = NULL, $action = 'cancel') {
// Set URL
switch ($action) {
- case 'cancel' :
+ case 'cancel':
$url = 'civicrm/contribute/unsubscribe';
break;
- case 'billing' :
+
+ case 'billing':
//in notify mode don't return the update billing url
if (!$this->isSupported('updateSubscriptionBillingInfo')) {
return NULL;
}
$url = 'civicrm/contribute/updatebilling';
break;
- case 'update' :
+
+ case 'update':
$url = 'civicrm/contribute/updaterecur';
break;
}
@@ -376,17 +657,17 @@ abstract class CRM_Core_Payment {
// Find related Contact
if ($entityID) {
switch ($entity) {
- case 'membership' :
+ case 'membership':
$contactID = CRM_Core_DAO::getFieldValue("CRM_Member_DAO_Membership", $entityID, "contact_id");
$entityArg = 'mid';
break;
- case 'contribution' :
+ case 'contribution':
$contactID = CRM_Core_DAO::getFieldValue("CRM_Contribute_DAO_Contribution", $entityID, "contact_id");
$entityArg = 'coid';
break;
- case 'recur' :
+ case 'recur':
$sql = "
SELECT con.contact_id
FROM civicrm_contribution_recur rec