Katie Horn has submitted this change and it was merged.
Change subject: PaymentMethod utility class
......................................................................
PaymentMethod utility class
The immediate gain is that utm_source payment method will be
constrained to sane values. The payment method component will be
the name of the payment submethod "group", with an "r" prepended
for recurring donations.
There are also two long-term goals which are supported by this patch:
* Selecting the gateway by desired payment method
* Unique and meaningful designation for each payment method
Change-Id: I34602faa9d8cca99132aa3b8067247e0f0a58b9e
---
M DonationInterface.php
M adyen_gateway/adyen.adapter.php
M amazon_gateway/amazon.adapter.php
M gateway_common/DonationData.php
A gateway_common/PaymentMethod.php
M gateway_common/gateway.adapter.php
M globalcollect_gateway/globalcollect.adapter.php
M payflowpro_gateway/payflowpro.adapter.php
M paypal_gateway/paypal.adapter.php
9 files changed, 234 insertions(+), 70 deletions(-)
Approvals:
Katie Horn: Verified; Looks good to me, approved
jenkins-bot: Verified
diff --git a/DonationInterface.php b/DonationInterface.php
index 6ddbff8..94ee9c6 100644
--- a/DonationInterface.php
+++ b/DonationInterface.php
@@ -102,6 +102,7 @@
$wgAutoloadClasses['GatewayAdapter'] = $donationinterface_dir .
'gateway_common/gateway.adapter.php';
$wgAutoloadClasses['GatewayForm'] = $donationinterface_dir .
'gateway_common/GatewayForm.php';
$wgAutoloadClasses['DataValidator'] = $donationinterface_dir .
'gateway_common/DataValidator.php';
+$wgAutoloadClasses['PaymentMethod'] = $donationinterface_dir .
'gateway_common/PaymentMethod.php';
//load all possible form classes
$wgAutoloadClasses['Gateway_Form'] = $donationinterface_dir .
'gateway_forms/Form.php';
diff --git a/adyen_gateway/adyen.adapter.php b/adyen_gateway/adyen.adapter.php
index 8a17eca..73b7c77 100644
--- a/adyen_gateway/adyen.adapter.php
+++ b/adyen_gateway/adyen.adapter.php
@@ -146,7 +146,14 @@
'iframe' => TRUE,
);
}
-
+
+ public function definePaymentMethods() {
+ $this->payment_methods = array(
+ 'cc' => array(),
+ );
+ PaymentMethod::registerMethods( $this->payment_methods );
+ }
+
protected function getAllowedPaymentMethods() {
return array(
'card',
diff --git a/amazon_gateway/amazon.adapter.php
b/amazon_gateway/amazon.adapter.php
index 31ec0f0..2231c61 100644
--- a/amazon_gateway/amazon.adapter.php
+++ b/amazon_gateway/amazon.adapter.php
@@ -163,6 +163,13 @@
);
}
+ public function definePaymentMethods() {
+ $this->payment_methods = array(
+ 'amazon' => array(),
+ );
+ PaymentMethod::registerMethods( $this->payment_methods );
+ }
+
protected function buildRequestParams() {
// Look up the request structure for our current transaction
type in the transactions array
$structure = $this->getTransactionRequestStructure();
diff --git a/gateway_common/DonationData.php b/gateway_common/DonationData.php
index 3d4314a..718b852 100644
--- a/gateway_common/DonationData.php
+++ b/gateway_common/DonationData.php
@@ -386,11 +386,11 @@
*/
protected function normalize() {
if ( !empty( $this->normalized ) ) {
- $this->setIPAddresses();
- $this->setUtmSource();
$this->setNormalizedOrderIDs();
- $this->setNormalizedAmount();
+ $this->setIPAddresses();
$this->setNormalizedRecurring();
+ $this->setUtmSource();
+ $this->setNormalizedAmount();
$this->setGateway();
$this->setLanguage();
$this->setCountry(); //must do this AFTER
setIPAddress...
@@ -660,11 +660,11 @@
* Takes all possible names for recurring and normalizes them into the
'recurring' field.
*/
protected function setNormalizedRecurring() {
- if( $this->isSomething( 'recurring_paypal' ) && $this->getVal(
'recurring_paypal' ) == '1' ){
+ if( $this->isSomething( 'recurring_paypal' ) && $this->getVal(
'recurring_paypal' ) === '1' ){
$this->setVal( 'recurring', true );
$this->expunge('recurring_paypal');
}
- if( $this->isSomething( 'recurring' ) && $this->getVal(
'recurring' ) == '1'){
+ if( $this->isSomething( 'recurring' ) && $this->getVal(
'recurring' ) === '1' ){
$this->setVal( 'recurring', true );
}
else{
@@ -1070,46 +1070,42 @@
/**
* normalize helper function.
*
- * Checks to see if the utm_source is set properly for the credit card
- * form including any cc form variants (identified by utm_source_id).
If
- * anything cc form related is out of place for the utm_source, this
- * will fix it.
- *
- * the utm_source is structured as:
banner.landing_page.payment_instrument
+ * the utm_source is structured as:
banner.landing_page.payment_method_family
*/
protected function setUtmSource() {
$utm_source = $this->getVal( 'utm_source' );
$utm_source_id = $this->getVal( 'utm_source_id' );
- //TODO: Seriously, you need to move this.
- if ( $this->isSomething('payment_method') ){
- $payment_method = $this->getVal( 'payment_method' );
- } else {
- $payment_method = 'cc';
- }
-
- // this is how the payment method portion of the utm_source
should be defined
- $correct_payment_method_source = ( $utm_source_id ) ?
$payment_method . $utm_source_id . '.' . $payment_method : $payment_method;
+ $payment_method_family = PaymentMethod::getUtmSourceName(
+ $this->getVal( 'payment_method' ),
+ $this->getVal( 'recurring' )
+ );
- // check to see if the utm_source is already correct - if so,
return
- if ( !is_null( $utm_source ) && preg_match( '/' . str_replace(
".", "\.", $correct_payment_method_source ) . '$/', $utm_source ) ) {
- return; //nothing to do.
- }
+ $this->log( $this->getLogMessagePrefix() . "Setting utm_source
payment method to {$payment_method_family}", LOG_INFO );
// split the utm_source into its parts for easier manipulation
$source_parts = explode( ".", $utm_source );
- // if there are no sourceparts element, then the banner portion
of the string needs to be set.
- // since we don't know what it is, set it to an empty string
- if ( !count( $source_parts ) )
+ // If we don't have the banner or any utm_source, set it to the
empty string.
+ if ( empty( $source_parts[0] ) ) {
$source_parts[0] = '';
+ }
- // if the utm_source_id is set, set the landing page portion of
the string to cc#
- $source_parts[1] = ( $utm_source_id ) ? $payment_method .
$utm_source_id : ( isset( $source_parts[1] ) ? $source_parts[1] : '' );
+ // If the utm_source_id is set, include that in the landing page
+ // portion of the string.
+ if ( $utm_source_id ) {
+ $source_parts[1] = $payment_method_family .
$utm_source_id;
+ } else {
+ if ( empty( $source_parts[1] ) ) {
+ $source_parts[1] = '';
+ }
+ }
- // the payment instrument portion should always be 'cc' if this
method is being accessed
- $source_parts[2] = $payment_method;
+ $source_parts[2] = $payment_method_family;
+ if ( empty( $source_parts[2] ) ) {
+ $source_parts[2] = '';
+ }
// reconstruct, and set the value.
$utm_source = implode( ".", $source_parts );
diff --git a/gateway_common/PaymentMethod.php b/gateway_common/PaymentMethod.php
new file mode 100644
index 0000000..0ddf018
--- /dev/null
+++ b/gateway_common/PaymentMethod.php
@@ -0,0 +1,161 @@
+<?php
+
+/**
+ * Describes payment methods.
+ *
+ * This currently bridges old and new code, by allowing payment methods
+ * to be referenced by legacy (method, submethod) strings, or by a new,
+ * unique name for each method. Examples of how these will compare:
+ *
+ * Compound (old) Unique (new) Family (new)
+ * ew, ew_yandex ew_yandex ew
+ * cc, visa cc_visa cc
+ * paypal, paypal paypal paypal
+ *
+ * We are deprecating the "submethod" distinction, dealing with methods
+ * should be simplified by referring to a single PaymentMethod object.
+ * The concept of a "family" becomes more important, this roughly maps
+ * to the donor's intended payment experience, and is the field we use
+ * for most reporting.
+ */
+class PaymentMethod {
+ static protected $specs = array();
+
+ /**
+ * @param array $methods_meta map of name => method specification
+ */
+ static public function registerMethods( $methods_meta ) {
+ // TODO: The registration needs to be reworked. One of the more
+ // important issues is that several processors implement
similar-enough
+ // methods (eg, "cc"), and they should each maintain separate
metadata.
+
+ foreach ( $methods_meta as $name => $meta ) {
+ if ( !array_key_exists( $name, self::$specs ) ) {
+ self::$specs[$name] = array();
+ }
+ self::$specs[$name] = $meta + self::$specs[$name];
+ }
+ }
+
+ /**
+ * @param string $method
+ *
+ * @return array|null method specification data
+ */
+ static protected function getMethodMeta( $method ) {
+ if ( array_key_exists( $method, self::$specs ) ) {
+ return self::$specs[$method];
+ }
+ return null;
+ }
+
+ /**
+ * Convert a unique payment method name into the method/submethod form
+ *
+ * @param string $id unique method identifier
+ * @return list( $payment_method, $payment_submethod )
+ */
+ static public function getCompoundMethod( $id ) {
+ if ( !PaymentMethod::isCompletelySpecified( $id ) ) {
+ $payment_method = $id;
+ $payment_submethod = null;
+ } elseif ( strpos( "_", $id ) !== false ) {
+ // Use the first segment as the method, and the
remainder as submethod
+ $segments = explode( "_", $id );
+ $payment_method = array_shift( $segments );
+
+ // If the remainder is a valid method, use it as the
submethod.
+ // Otherwise, we want something like (dd, dd_fr), so
reuse the whole id.
+ $remainder = implode( "_", $segments );
+ if ( PaymentMethod::getMethodMeta( $remainder ) ) {
+ $payment_submethod = $remainder;
+ } else {
+ $payment_submethod = $id;
+ }
+ } else {
+ $payment_method = $id;
+ $payment_submethod = $id;
+ }
+ return array( $payment_method, $payment_submethod );
+ }
+
+ /**
+ * Process an old-style payment method/submethod name into the unique
form
+ *
+ * For now, this just eliminates duplicated method-submethods.
+ *
+ * @param string $bareMethod old-style payment method
+ * @param string $subMethod old-style payment submethod
+ *
+ * @return string unique method id
+ */
+ static public function parseCompoundMethod( $bareMethod, $subMethod ) {
+ $parts = explode( '_', $subMethod );
+ array_unshift( $parts, $bareMethod );
+
+ if ( $parts[0] === $parts[1] ) {
+ array_shift( $parts );
+ }
+
+ return implode( '_', $parts );
+ }
+
+ /**
+ * @return true if this payment method is complete enough to begin a
transaction
+ */
+ static public function isCompletelySpecified( $id ) {
+ //TODO
+ if ( $id === 'cc' ) return false;
+ return true;
+ }
+
+ /**
+ * @return true if the $method descends from a more general $ancestor
method, or if they are equal.
+ */
+ static public function isInstanceOf( $method, $ancestor ) {
+ do {
+ if ( $method === $ancestor ) {
+ return true;
+ }
+ } while ( $method = PaymentMethod::getParent( $method ) );
+
+ return false;
+ }
+
+ /**
+ * @return the most general ancestor of a given payment $method
+ */
+ static public function getFamily( $method ) {
+ while ( $parent = PaymentMethod::getParent( $method ) ) {
+ $method = $parent;
+ }
+ return $method;
+ }
+
+ /**
+ * @param string $method
+ *
+ * @return string|null parent method name
+ */
+ static protected function getParent( $method ) {
+ $meta = PaymentMethod::getMethodMeta( $method );
+ if ( $meta and array_key_exists( 'group', $meta ) ) {
+ return $meta['group'];
+ }
+ return null;
+ }
+
+ /**
+ * @param string $method
+ * @param boolean $recurring
+ *
+ * @return normalized utm_source payment method component
+ */
+ static public function getUtmSourceName( $method, $recurring ) {
+ $source = PaymentMethod::getFamily( $method );
+ if ( $recurring ) {
+ $source = "r" . $source;
+ }
+ return $source;
+ }
+}
diff --git a/gateway_common/gateway.adapter.php
b/gateway_common/gateway.adapter.php
index dd0e7cc..069d2e1 100644
--- a/gateway_common/gateway.adapter.php
+++ b/gateway_common/gateway.adapter.php
@@ -99,6 +99,13 @@
*/
function defineReturnValueMap();
+ /**
+ * Sets up the $payment_methods array.
+ * Keys = unique name for this method
+ * Values = metadata about the method
+ */
+ function definePaymentMethods();
+
static function getCurrencies();
}
@@ -282,6 +289,7 @@
$this->findAccount();
$this->defineAccountInfo();
$this->defineTransactions();
+ $this->definePaymentMethods();
$this->defineErrorMap();
$this->defineVarMap();
$this->defineDataConstraints();
@@ -661,7 +669,6 @@
if ( array_key_exists( $gateway_field_name, $this->accountInfo
) ) {
return $this->accountInfo[$gateway_field_name];
}
-
//If there's a value in the post data (name-translated by the
var_map), use that.
if ( array_key_exists( $gateway_field_name, $this->var_map ) ) {
@@ -1218,7 +1225,7 @@
* @return string
*/
public function getPaymentMethod() {
-
+ //FIXME: this should return the final calculated method
return $this->getData_Unstaged_Escaped('payment_method');
}
@@ -1230,13 +1237,6 @@
* @return array Returns the available payment methods for the
specific adapter
*/
public function getPaymentMethods() {
-
- // Define the payment methods if they have not been set yet.
- if ( empty( $this->payment_methods ) ) {
-
- $this->definePaymentMethods();
- }
-
return $this->payment_methods;
}
@@ -1261,13 +1261,6 @@
* @return array Returns the available payment submethods for
the specific adapter
*/
public function getPaymentSubmethods() {
-
- // Define the payment methods if they have not been set yet.
- if ( empty( $this->payment_submethods ) ) {
-
- $this->definePaymentSubmethods();
- }
-
return $this->payment_submethods;
}
diff --git a/globalcollect_gateway/globalcollect.adapter.php
b/globalcollect_gateway/globalcollect.adapter.php
index 2814e8f..f561f7e 100644
--- a/globalcollect_gateway/globalcollect.adapter.php
+++ b/globalcollect_gateway/globalcollect.adapter.php
@@ -402,11 +402,6 @@
* - GET_ORDERSTATUS
*/
public function defineTransactions() {
-
- // Define the transaction types and groups
- $this->definePaymentMethods();
- $this->definePaymentSubmethods();
-
$this->transactions = array( );
$this->transactions['DO_BANKVALIDATION'] = array(
@@ -616,14 +611,13 @@
*
* The credit card group has a catchall for unspecified payment types.
*/
- protected function definePaymentMethods() {
+ public function definePaymentMethods() {
$this->payment_methods = array();
// Bank Transfers
$this->payment_methods['bt'] = array(
'label' => 'Bank transfer',
- 'types' => array( 'bt', ),
'validation' => array( 'creditCard' => false, ),
'short_circuit_at' => 'first_iop',
);
@@ -631,13 +625,11 @@
// Credit Cards
$this->payment_methods['cc'] = array(
'label' => 'Credit Cards',
- 'types' => array( '', 'visa', 'mc', 'amex', 'discover',
'maestro', 'solo', 'laser', 'jcb', 'cb', ),
);
// Direct Debit
$this->payment_methods['dd'] = array(
'label' => 'Direct Debit',
- 'types' => array( 'dd_at', 'dd_be', 'dd_ch', 'dd_de',
'dd_es','dd_fr', 'dd_gb', 'dd_it', 'dd_nl', ),
'validation' => array( 'creditCard' => false, ),
'short_circuit_at' => 'first_iop',
);
@@ -645,7 +637,6 @@
// eWallets
$this->payment_methods['ew'] = array(
'label' => 'eWallets',
- 'types' => array( 'ew_cashu', 'ew_moneybookers',
'ew_paypal', 'ew_webmoney', 'ew_yandex' ),
'validation' => array( 'address' => false, 'creditCard'
=> false, ),
'short_circuit_at' => 'first_iop',
'additional_success_status' => array( 20 ),
@@ -654,7 +645,6 @@
// Bank Transfers
$this->payment_methods['obt'] = array(
'label' => 'Online bank transfer',
- 'types' => array( 'bpay', ),
'validation' => array( 'creditCard' => false, ),
'short_circuit_at' => 'first_iop',
);
@@ -662,7 +652,6 @@
// Real Time Bank Transfers
$this->payment_methods['rtbt'] = array(
'label' => 'Real time bank transfer',
- 'types' => array( 'rtbt_ideal', 'rtbt_eps',
'rtbt_sofortuberweisung', 'rtbt_nordea_sweden', 'rtbt_enets', ),
'short_circuit_at' => 'first_iop',
'additional_success_status' => array( 20 ),
);
@@ -670,19 +659,13 @@
// Cash payments
$this->payment_methods['cash'] = array(
'label' => 'Cash payments',
- 'types' => array( 'cash_boleto', ),
'short_circuit_at' => 'first_iop',
'additional_success_status' => array( 55 ), //PENDING
AT CUSTOMER - denotes they need to go to the bank, but we've done all we can.
);
- }
+ // *** Define payment submethods ***
+ //TODO: deprecate submethod, everything is a first-class method.
- /**
- * Define payment submethods
- *
- */
- protected function definePaymentSubmethods() {
-
$this->payment_submethods = array();
/*
@@ -709,7 +692,6 @@
$this->payment_submethods['bt'] = array(
'paymentproductid' => 11,
'label' => 'Bank Transfer',
- 'group' => 'bt',
'validation' => array(),
'keys' => array(),
);
@@ -1034,6 +1016,9 @@
'group' => 'cash',
'keys' => array(),
);
+
+ PaymentMethod::registerMethods( $this->payment_methods );
+ PaymentMethod::registerMethods( $this->payment_submethods );
}
/**
@@ -2092,6 +2077,7 @@
$trythis = $payment_method . '_' . strtolower(
$this->getData_Unstaged_Escaped('country') );
if ( array_key_exists( $trythis,
$this->payment_submethods ) ){
$payment_submethod = $trythis;
+ $this->staged_data['payment_submethod'] =
$payment_submethod;
}
}
@@ -2373,5 +2359,4 @@
return false;
}
}
-
}
diff --git a/payflowpro_gateway/payflowpro.adapter.php
b/payflowpro_gateway/payflowpro.adapter.php
index 86a60a4..0f5548c 100644
--- a/payflowpro_gateway/payflowpro.adapter.php
+++ b/payflowpro_gateway/payflowpro.adapter.php
@@ -113,6 +113,13 @@
);
}
+ function definePaymentMethods() {
+ $this->payment_methods = array(
+ 'cc' => array(),
+ );
+ PaymentMethod::registerMethods( $this->payment_methods );
+ }
+
/**
* Parse the response to get the status. Not sure if this should return
a bool, or something more... telling.
*/
diff --git a/paypal_gateway/paypal.adapter.php
b/paypal_gateway/paypal.adapter.php
index a604bc9..675c13f 100644
--- a/paypal_gateway/paypal.adapter.php
+++ b/paypal_gateway/paypal.adapter.php
@@ -180,6 +180,13 @@
}
}
+ public function definePaymentMethods() {
+ $this->payment_methods = array(
+ 'paypal' => array(),
+ );
+ PaymentMethod::registerMethods( $this->payment_methods );
+ }
+
static function getCurrencies() {
// see
https://www.x.com/developers/paypal/documentation-tools/api/currency-codes
return array(
--
To view, visit https://gerrit.wikimedia.org/r/64348
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I34602faa9d8cca99132aa3b8067247e0f0a58b9e
Gerrit-PatchSet: 10
Gerrit-Project: mediawiki/extensions/DonationInterface
Gerrit-Branch: master
Gerrit-Owner: Adamw <[email protected]>
Gerrit-Reviewer: Adamw <[email protected]>
Gerrit-Reviewer: Katie Horn <[email protected]>
Gerrit-Reviewer: Mwalker <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits