jenkins-bot has submitted this change and it was merged.

Change subject: Encapsulated amount validation for better messages
......................................................................


Encapsulated amount validation for better messages

Use the minimum amount message where appropriate for consistency
with client side and better donor experience.

Had to touch a lot of config files - maybe there's SOME use for
the getCoreDataTransformers outside of testing?

Bug: T105618
Change-Id: If9d60491cdc992a38a0ea459f5ece3f38ce08184
---
M README.txt
M adyen_gateway/AmountInMinorUnits.php
M adyen_gateway/config/transformers.yaml
M amazon_gateway/config/transformers.yaml
M astropay_gateway/config/transformers.yaml
M extension.json
A gateway_common/Amount.php
M gateway_common/AmountInCents.php
M gateway_common/DataValidator.php
M gateway_common/DonationData.php
M gateway_common/FiscalNumber.php
M gateway_common/ValidationHelper.php
M gateway_common/gateway.adapter.php
M gateway_forms/Mustache.php
M globalcollect_gateway/config/transformers.yaml
M paypal_gateway/legacy/config/transformers.yaml
M tests/Adapter/Amazon/AmazonTest.php
A tests/AmountTest.php
M tests/DataValidatorTest.php
M worldpay_gateway/config/transformers.yaml
20 files changed, 427 insertions(+), 166 deletions(-)

Approvals:
  XenoRyet: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/README.txt b/README.txt
index adf8784..60dd3f4 100644
--- a/README.txt
+++ b/README.txt
@@ -89,6 +89,9 @@
 Email address donors should contact with any donation-related problems
 $wgDonationInterfaceProblemsEmail = '[email protected]'
 
+Email address donors should contact with donations too big to process online
+$wgDonationInterfaceMajorGiftsEmail = '[email protected]';
+
 The full URL for Javascript-disabled credit card form redirect
 $wgDonationInterfaceNoScriptRedirect = null
 
diff --git a/adyen_gateway/AmountInMinorUnits.php 
b/adyen_gateway/AmountInMinorUnits.php
index cc64a03..fff6ffc 100644
--- a/adyen_gateway/AmountInMinorUnits.php
+++ b/adyen_gateway/AmountInMinorUnits.php
@@ -17,9 +17,9 @@
                }
 
                $amount = $normalized['amount'];
-               if ( DataValidator::is_exponent3_currency( 
$normalized['currency_code'] ) ) {
+               if ( Amount::is_exponent3_currency( 
$normalized['currency_code'] ) ) {
                        $stagedData['amount'] = $amount * 1000;
-               } elseif ( DataValidator::is_fractional_currency( 
$normalized['currency_code'] ) ) {
+               } elseif ( Amount::is_fractional_currency( 
$normalized['currency_code'] ) ) {
                        $stagedData['amount'] = $amount * 100;
                } else {
                        $amount = floor( $amount );
@@ -29,13 +29,13 @@
        }
 
        public function unstage( GatewayType $adapter, $stagedData, 
&$unstagedData ) {
-               if ( DataValidator::is_exponent3_currency( 
$stagedData['currency_code'] ) ) {
+               if ( Amount::is_exponent3_currency( 
$stagedData['currency_code'] ) ) {
                        $unstagedData['amount'] = $stagedData['amount'] / 1000;
-               } elseif ( DataValidator::is_fractional_currency( 
$stagedData['currency_code'] ) ) {
+               } elseif ( Amount::is_fractional_currency( 
$stagedData['currency_code'] ) ) {
                        $unstagedData['amount'] = $stagedData['amount'] / 100;
                } else {
                        $unstagedData['amount'] = $stagedData['amount'];
                }
 
        }
-}
\ No newline at end of file
+}
diff --git a/adyen_gateway/config/transformers.yaml 
b/adyen_gateway/config/transformers.yaml
index d6fb781..1c7f45f 100644
--- a/adyen_gateway/config/transformers.yaml
+++ b/adyen_gateway/config/transformers.yaml
@@ -1,4 +1,5 @@
 # Core
+- Amount
 - DonorEmail
 - StreetAddress
 # Adyen-specific
diff --git a/amazon_gateway/config/transformers.yaml 
b/amazon_gateway/config/transformers.yaml
index 89e70d8..260f807 100644
--- a/amazon_gateway/config/transformers.yaml
+++ b/amazon_gateway/config/transformers.yaml
@@ -1,4 +1,5 @@
 # Skip AmountInCents, we want to pass the real amount x1.
+- Amount
 - DonorEmail
 - DonorFullName
 - StreetAddress
diff --git a/astropay_gateway/config/transformers.yaml 
b/astropay_gateway/config/transformers.yaml
index caaa153..bae2a9c 100644
--- a/astropay_gateway/config/transformers.yaml
+++ b/astropay_gateway/config/transformers.yaml
@@ -1,7 +1,9 @@
 # Skip AmountInCents.
+- Amount
 - AstroPayFinancialNumbers
 - AstroPayMethodCodec
 - FiscalNumber
+- DonorEmail
 - DummyFiscalNumber # see class comment
 - DonorFullName
 - StreetAddress
diff --git a/extension.json b/extension.json
index a18b381..df397a1 100644
--- a/extension.json
+++ b/extension.json
@@ -64,6 +64,7 @@
                "WorldpayGatewayAlias": 
"worldpay_gateway/worldpay_gateway.alias.php"
        },
        "AutoloadClasses": {
+               "Amount": "gateway_common/Amount.php",
                "AmountInCents": "gateway_common/AmountInCents.php",
                "ArrayHelper": "gateway_common/ArrayHelper.php",
                "FiscalNumber": "gateway_common/FiscalNumber.php",
@@ -445,6 +446,7 @@
                "DonationInterfaceFaqURL": 
"https://wikimediafoundation.org/wiki/Special:LandingCheck?basic=true&landing_page=FAQ&language=$language&country=$country";,
                "DonationInterfaceTaxURL": 
"https://wikimediafoundation.org/wiki/Special:LandingCheck?basic=true&landing_page=Tax_Deductibility&language=$language&country=$country";,
                "DonationInterfaceProblemsEmail": 
"[email protected]",
+               "DonationInterfaceMajorGiftsEmail": "[email protected]",
                "DonationInterfaceDefaultEmail": "[email protected]",
                "DonationInterfaceDebugLog": false,
                "DonationInterfaceDisplayDebug": false,
diff --git a/gateway_common/Amount.php b/gateway_common/Amount.php
new file mode 100644
index 0000000..8f3e802
--- /dev/null
+++ b/gateway_common/Amount.php
@@ -0,0 +1,176 @@
+<?php
+
+class Amount implements ValidationHelper {
+
+       public function validate( GatewayType $adapter, $normalized, &$errors ) 
{
+               if (
+                       !isset( $normalized['amount'] ) ||
+                       !isset( $normalized['currency_code'] )
+               ) {
+                       // Not enough info to validate
+                       return;
+               }
+               if ( isset( $errors['currency_code'] ) ) {
+                       // Already displaying an error
+                       return;
+               }
+               $value = $normalized['amount'];
+
+               if ( self::isZeroIsh( $value ) ) {
+                       $errors['amount'] = DataValidator::getErrorMessage(
+                               'amount',
+                               'not_empty',
+                               $normalized['language']
+                       );
+                       return;
+               }
+               $currency = $normalized['currency_code'];
+               $min = self::convert( $adapter->getGlobal( 'PriceFloor' ), 
$currency );
+               $max = self::convert( $adapter->getGlobal( 'PriceCeiling' ), 
$currency );
+               if (
+                       !is_numeric( $value ) ||
+                       $value < 0
+               ) {
+                       $errors['amount'] = WmfFramework::formatMessage(
+                               'donate_interface-error-msg-invalid-amount'
+                       );
+               } else if ( $value > $max ) {
+                       // FIXME: should format the currency values in this 
message
+                       $errors['amount'] = WmfFramework::formatMessage(
+                               'donate_interface-bigamount-error',
+                               $max,
+                               $currency,
+                               $adapter->getGlobal( 'MajorGiftsEmail' )
+                       );
+               } else if ( $value < $min ) {
+                       $locale = $normalized['language'] . '_' . 
$normalized['country'];
+                       $formattedMin = self::format( $min, $currency, $locale 
);
+                       $errors['amount'] = WmfFramework::formatMessage(
+                               'donate_interface-smallamount-error',
+                               $formattedMin
+                       );
+               }
+       }
+
+       /**
+        * Checks if the $value is missing or equivalent to zero.
+        *
+        * @param string $value The value to check for zero-ness
+        * @return boolean True if the $value is missing or zero, otherwise 
false
+        */
+       protected static function isZeroIsh( $value ) {
+               if (
+                       $value === null ||
+                       trim( $value ) === '' ||
+                       ( is_numeric( $value ) && abs( $value ) < 0.01 )
+               ) {
+                       return true;
+               }
+
+               return false;
+       }
+
+       /**
+        * Convert an amount in USD to a particular currency
+        *
+        * This is grossly rudimentary and likely wildly inaccurate.
+        * This mimics the hard-coded values used by the WMF to convert 
currencies
+        * for validation on the front-end on the first step landing pages of 
their
+        * donation process - the idea being that we can get a close 
approximation
+        * of converted currencies to ensure that contributors are not going 
above
+        * or below the price ceiling/floor, even if they are using a non-US 
currency.
+        *
+        * In reality, this probably ought to use some sort of webservice to 
get real-time
+        * conversion rates.
+        *
+        * @param float $amount
+        * @param string $currency
+        * @return float
+        * @throws UnexpectedValueException
+        */
+       public static function convert( $amount, $currency ) {
+               $rates = CurrencyRates::getCurrencyRates();
+               $code = strtoupper( $currency );
+               if ( array_key_exists( $code, $rates ) ) {
+                       return $amount * $rates[$code];
+               }
+               throw new UnexpectedValueException(
+                       'Bad programmer!  Bad currency made it too far through 
the portcullis'
+               );
+       }
+
+       /**
+        * Some currencies, like JPY, don't exist in fractional amounts.
+        * This rounds an amount to the appropriate number of decimal places.
+        * Use the results of this for internal use, and use @see Amount::format
+        * for values displayed to donors.
+        *
+        * @param float $amount
+        * @param string $currencyCode
+        * @return string rounded amount
+        */
+       public static function round( $amount, $currencyCode ) {
+               if ( self::is_fractional_currency( $currencyCode ) ){
+                       return number_format( $amount, 2, '.', '' );
+               } else {
+                       return ( string ) floor( $amount );
+               }
+       }
+
+       /**
+        * If an amount is ever expressed for the fractional currencies defined 
in
+        * this function, they should not have an associated fractional amount
+        * (so: full integers only).
+        *
+        * @param string $currency_code The three-digit currency code.
+        * @return boolean
+        */
+       public static function is_fractional_currency( $currency_code ){
+               // these currencies cannot have cents.
+               $non_fractional_currencies = array(
+                       'CLP', 'DJF', 'IDR', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 
'VND', 'XAF', 'XOF', 'XPF'
+               );
+
+               if ( in_array( strtoupper( $currency_code ), 
$non_fractional_currencies ) ) {
+                       return false;
+               }
+               return true;
+       }
+
+       /**
+        * Checks if ISO 4217 defines the currency's minor units as being 
expressed using
+        * exponent 3 (three decimal places).
+        * @param string $currency_code The three-character currency code.
+        * @return boolean
+        */
+       public static function is_exponent3_currency( $currency_code ){
+
+               $exponent3_currencies = array( 'BHD', 'CLF', 'IQD', 'KWD', 
'LYD', 'MGA', 'MRO', 'OMR', 'TND' );
+
+               if ( in_array( strtoupper( $currency_code ), 
$exponent3_currencies ) ) {
+                       return true;
+               }
+               return false;
+       }
+
+       /**
+        * Format an amount and currency for display to users.
+        *
+        * @param float $amount
+        * @param string $currencyCode
+        * @param string $locale e.g. en_US
+        * @return string
+        */
+       public static function format( $amount, $currencyCode, $locale ) {
+               $amount = self::round( $amount, $currencyCode );
+               if ( class_exists( 'NumberFormatter' ) ) {
+                       $formatter = new NumberFormatter( $locale, 
NumberFormatter::CURRENCY );
+                       return $formatter->formatCurrency(
+                               $amount,
+                               $currencyCode
+                       );
+               } else {
+                       return "$amount $currencyCode";
+               }
+       }
+}
diff --git a/gateway_common/AmountInCents.php b/gateway_common/AmountInCents.php
index 8222dd6..545d7b3 100644
--- a/gateway_common/AmountInCents.php
+++ b/gateway_common/AmountInCents.php
@@ -11,16 +11,17 @@
  */
 class AmountInCents implements StagingHelper, UnstagingHelper {
        public function stage( GatewayType $adapter, $normalized, &$stagedData 
) {
-               if ( empty( $normalized['amount'] ) || empty( 
$normalized['currency_code'] ) ) {
+               if (
+                       empty( $normalized['amount'] ) ||
+                       empty( $normalized['currency_code'] ) ||
+                       !is_numeric( $normalized['amount'] )
+               ) {
                        //can't do anything with amounts at all. Just go home.
                        unset( $stagedData['amount'] );
                        return;
                }
 
-               $amount = $normalized['amount'];
-               if ( !DataValidator::is_fractional_currency( 
$normalized['currency_code'] ) ) {
-                       $amount = floor( $amount );
-               }
+               $amount = Amount::round( $normalized['amount'], 
$normalized['currency_code'] );
 
                $stagedData['amount'] = $amount * 100;
        }
diff --git a/gateway_common/DataValidator.php b/gateway_common/DataValidator.php
index d069ca4..caf6882 100644
--- a/gateway_common/DataValidator.php
+++ b/gateway_common/DataValidator.php
@@ -25,10 +25,6 @@
         */
        public static function getErrorToken( $field ){
                switch ( $field ) {
-                       case 'amountGiven' :
-                       case 'amountOther' :
-                               $error_token = 'amount';
-                               break;
                        case 'email' :
                        case 'amount' :
                        case 'currency_code' :
@@ -138,14 +134,7 @@
                        //getErrorToken is actually for something entirely 
different:
                        //Figuring out where on the form the error should land.
                        $token = self::getErrorToken( $field );
-                       switch ( $token ) {
-                               case 'amount':
-                                       $error_key_calc = 
'donate_interface-error-msg-invalid-amount';
-                                       break;
-                               default:
-                                       $error_key_calc = 
'donate_interface-error-msg-' . $token . '-calc';
-                                       break;
-                       }
+                       $error_key_calc = 'donate_interface-error-msg-' . 
$token . '-calc';
 
                        if ( $type === 'calculated' ){
                                // try for the special "calculated" error 
message.
@@ -204,7 +193,6 @@
                // Define all default validations.
                $validations = array(
                        'not_empty' => array(
-                               'amount' => 'validate_non_zero',
                                'country',
                                'currency_code',
                                'gateway',
@@ -212,9 +200,6 @@
                        'valid_type' => array(
                                '_cache_' => 'validate_boolean',
                                'account_number' => 'validate_numeric',
-                               'amount' => 'validate_numeric',
-                               'amountGiven' => 'validate_numeric',
-                               'amountOther' => 'validate_numeric',
                                'anonymous' => 'validate_boolean',
                                'contribution_tracking_id' => 
'validate_numeric',
                                'currency_code' => 'validate_alphanumeric',
@@ -236,10 +221,6 @@
                                'fname' => 'validate_name',
                                'lname' => 'validate_name',
                                'name' => 'validate_name',
-
-                               // Depends on currency_code and gateway.
-                               'amount' => 'validate_amount',
-
                        ),
                );
 
@@ -295,13 +276,6 @@
                                $result = null;
                                // Handle special cases.
                                switch ( $validation_function ) {
-                                       case 'validate_amount':
-                                               if ( 
self::checkValidationPassed( array( 'currency_code', 'gateway' ), $results ) ){
-                                                       $priceFloor = 
$gateway->getGlobal( 'PriceFloor' );
-                                                       $priceCeiling = 
$gateway->getGlobal( 'PriceCeiling' );
-                                                       $result = 
call_user_func( $callable, $data[$field], $data['currency_code'], $priceFloor, 
$priceCeiling );
-                                               } //otherwise, just don't do 
the validation. The other stuff will be complaining already.
-                                               break;
                                        case 'validate_currency_code':
                                                $result = call_user_func( 
$callable, $data[$field], $gateway->getCurrencies( $data ) );
                                                break;
@@ -357,31 +331,6 @@
        protected static function validate_email( $value ) {
                return WmfFramework::validateEmail( $value )
                        && !DataValidator::cc_number_exists_in_str( $value );
-       }
-
-       /**
-        * validate_amount
-        *
-        * Determines if the $value passed in is a valid amount.
-        * @param string $value The piece of data that is supposed to be an 
amount.
-        * @param string $currency_code The amount was given in this currency.
-        * @param float $priceFloor Minimum valid amount (USD).
-        * @param float $priceCeiling Maximum valid amount (USD).
-        *
-        * @return boolean True if $value is a valid amount, otherwise false.
-        */
-       protected static function validate_amount( $value, $currency_code, 
$priceFloor, $priceCeiling ) {
-               if ( !$value || !$currency_code || !is_numeric( $value ) ) {
-                       return false;
-               }
-
-               if ( !preg_match( '/^\d+(\.(\d+)?)?$/', $value ) ||
-                       ( ( float ) self::convert_to_usd( $currency_code, 
$value ) < ( float ) $priceFloor ||
-                       ( float ) self::convert_to_usd( $currency_code, $value 
) > ( float ) $priceCeiling ) ) {
-                       return false;
-               }
-
-               return true;
        }
 
        protected static function validate_currency_code( $value, 
$acceptedCurrencies ) {
@@ -567,22 +516,6 @@
        }
 
        /**
-        * Checks to make sure that the $value is present in the $data array, 
and not equivalent to zero.
-        * @param string $value The value to check for non-zeroness.
-        * @param array $data The whole data set.
-        * @return boolean True if the $value is not missing or zero, otherwise 
false.
-        */
-       public static function validate_non_zero( $value ) {
-               if ( $value === null || $value === ''
-                       || preg_match( '/^0+(\.0+)?$/', $value )
-               ) {
-                       return false;
-               }
-
-               return true;
-       }
-
-       /**
         * Analyzes a string to see if any credit card numbers are hiding out 
in it
         *
         * @param $str
@@ -671,36 +604,6 @@
                }
                return( ( $sum % 10 ) == 0 );
        }
-
-       /**
-        * Convert an amount for a particular currency to an amount in USD
-        *
-        * This is grosley rudimentary and likely wildly inaccurate.
-        * This mimicks the hard-coded values used by the WMF to convert 
currencies
-        * for validatoin on the front-end on the first step landing pages of 
their
-        * donation process - the idea being that we can get a close 
approximation
-        * of converted currencies to ensure that contributors are not going 
above
-        * or below the price ceiling/floor, even if they are using a non-US 
currency.
-        *
-        * In reality, this probably ought to use some sort of webservice to 
get real-time
-        * conversion rates.
-        *
-        * @param string $currency_code
-        * @param float $amount
-        * @return float
-        * @throws UnexpectedValueException
-        */
-       public static function convert_to_usd( $currency_code, $amount ) {
-               $rates = CurrencyRates::getCurrencyRates();
-               $code = strtoupper( $currency_code );
-               if ( array_key_exists( $code, $rates ) ) {
-                       $usd_amount = $amount / $rates[$code];
-               } else {
-                       throw new UnexpectedValueException( 'Bad programmer!  
Bad currency made it too far through the portcullis' );
-               }
-               return $usd_amount;
-       }
-
 
        /**
         * Calculates and returns the card type for a given credit card number.
@@ -832,39 +735,6 @@
                } else {
                        return false;
                }
-       }
-
-       /**
-        * More of a validation helper function. If an amount is ever expressed 
for
-        * the fractional currencies defined in this function,
-        * they should not have an associated fractional amount (so: full 
integers only).
-        * @param string $currency_code The three-digit currency code.
-        * @return boolean
-        */
-       public static function is_fractional_currency( $currency_code ){
-               // these currencies cannot have cents.
-               $non_fractional_currencies = array( 'CLP', 'DJF', 'IDR', 'JPY', 
'KMF', 'KRW', 'MGA', 'PYG', 'VND', 'XAF', 'XOF', 'XPF' );
-
-               if ( in_array( strtoupper( $currency_code ), 
$non_fractional_currencies ) ) {
-                       return false;
-               }
-               return true;
-       }
-
-       /**
-        * Checks if ISO 4217 defines the currency's minor units as being 
expressed using
-        * exponent 3 (three decimal places).
-        * @param string $currency_code The three-character currency code.
-        * @return boolean
-        */
-       public static function is_exponent3_currency( $currency_code ){
-
-               $exponent3_currencies = array( 'BHD', 'CLF', 'IQD', 'KWD', 
'LYD', 'MGA', 'MRO', 'OMR', 'TND' );
-
-               if ( in_array( strtoupper( $currency_code ), 
$exponent3_currencies ) ) {
-                       return true;
-               }
-               return false;
        }
 
        /**
diff --git a/gateway_common/DonationData.php b/gateway_common/DonationData.php
index dba7860..bcde039 100644
--- a/gateway_common/DonationData.php
+++ b/gateway_common/DonationData.php
@@ -544,11 +544,10 @@
                        return;
                }
 
-               if ( DataValidator::is_fractional_currency( $this->getVal( 
'currency_code' ) ) ) {
-                       $this->setVal( 'amount', number_format( $this->getVal( 
'amount' ), 2, '.', '' ) );
-               } else {
-                       $this->setVal( 'amount', floor( $this->getVal( 'amount' 
) ) );
-               }
+               $this->setVal(
+                       'amount',
+                       Amount::round( $this->getVal( 'amount' ), 
$this->getVal( 'currency_code' ) )
+               );
        }
 
        /**
@@ -985,7 +984,11 @@
                        $transformers = $this->gateway->getDataTransformers();
                        foreach ( $transformers as $transformer ) {
                                if ( $transformer instanceof ValidationHelper ) 
{
-                                       $transformer->validate( 
$this->normalized, $this->validationErrors );
+                                       $transformer->validate(
+                                               $this->gateway,
+                                               $this->normalized,
+                                               $this->validationErrors
+                                       );
                                }
                        }
                }
diff --git a/gateway_common/FiscalNumber.php b/gateway_common/FiscalNumber.php
index 7b8b626..c2d66db 100644
--- a/gateway_common/FiscalNumber.php
+++ b/gateway_common/FiscalNumber.php
@@ -56,10 +56,11 @@
        /**
         * Rudimentary tests of fiscal number format for different countries
         *
+        * @param GatewayType $unused
         * @param array $normalized Normalized donation data
         * @param array $errors Results of validation to this point
         */
-       public function validate( $normalized, &$errors ) {
+       public function validate( GatewayType $unused, $normalized, &$errors ) {
                if (
                        !isset( $normalized['country'] ) ||
                        !isset( $normalized[self::$key] )
diff --git a/gateway_common/ValidationHelper.php 
b/gateway_common/ValidationHelper.php
index 8926315..e2c0c50 100644
--- a/gateway_common/ValidationHelper.php
+++ b/gateway_common/ValidationHelper.php
@@ -4,6 +4,11 @@
        /**
         * Run validation on whatever normalized data we're responsible for,
         * and set errors per field, or under the "general" key.
+        *
+        * @param GatewayType $adapter
+        * @param array $normalized Donation data in normalized form.
+        * @param array $errors Reference to error array
+        * @return void
         */
-       function validate( $normalized, &$errors );
+       function validate( GatewayType $adapter, $normalized, &$errors );
 }
diff --git a/gateway_common/gateway.adapter.php 
b/gateway_common/gateway.adapter.php
index 7847f14..0e3d68d 100644
--- a/gateway_common/gateway.adapter.php
+++ b/gateway_common/gateway.adapter.php
@@ -453,6 +453,7 @@
                        // Always stage email address first, to set default if 
missing
                        new DonorEmail(),
                        new DonorFullName(),
+                       new Amount(),
                        new AmountInCents(),
                        new StreetAddress(),
                );
diff --git a/gateway_forms/Mustache.php b/gateway_forms/Mustache.php
index 9216a11..d6665ea 100644
--- a/gateway_forms/Mustache.php
+++ b/gateway_forms/Mustache.php
@@ -215,16 +215,12 @@
                                'selected' => ( $currency === 
$data['currency_code'] ),
                        );
                }
-               if ( class_exists( 'NumberFormatter' ) ) {
-                       $locale = $data['language'] . '_' . $data['country'];
-                       $formatter = new NumberFormatter( $locale, 
NumberFormatter::CURRENCY );
-                       $data['display_amount'] = $formatter->formatCurrency(
-                               $data['amount'],
-                               $data['currency_code']
-                       );
-               } else {
-                       $data['display_amount'] = "{$data['amount']} 
{$data['currency_code']}";
-               }
+
+               $data['display_amount'] = Amount::format(
+                       $data['amount'],
+                       $data['currency_code'],
+                       $data['language'] . '_' . $data['country']
+               );
        }
 
        /**
diff --git a/globalcollect_gateway/config/transformers.yaml 
b/globalcollect_gateway/config/transformers.yaml
index cea8f45..082adfe 100644
--- a/globalcollect_gateway/config/transformers.yaml
+++ b/globalcollect_gateway/config/transformers.yaml
@@ -1,4 +1,5 @@
 # Core
+- Amount
 - DonorEmail
 - DonorFullName
 - AmountInCents
diff --git a/paypal_gateway/legacy/config/transformers.yaml 
b/paypal_gateway/legacy/config/transformers.yaml
index 0e676ed..3f63205 100644
--- a/paypal_gateway/legacy/config/transformers.yaml
+++ b/paypal_gateway/legacy/config/transformers.yaml
@@ -1,4 +1,5 @@
 # Core
+- Amount
 - DonorEmail
 
 # PayPal
diff --git a/tests/Adapter/Amazon/AmazonTest.php 
b/tests/Adapter/Amazon/AmazonTest.php
index 1bcd5c7..aadbe31 100644
--- a/tests/Adapter/Amazon/AmazonTest.php
+++ b/tests/Adapter/Amazon/AmazonTest.php
@@ -87,13 +87,9 @@
                        'donate_interface-fallback-currency-notice',
                        'USD'
                )->inLanguage( $language )->text();
-               if ( class_exists( 'NumberFormatter' ) ) {
-                       $locale = $init['language'] . '_' . $init['country'];
-                       $formatter = new NumberFormatter( $locale, 
NumberFormatter::CURRENCY );
-                       $expectedDisplayAmount = $formatter->formatCurrency( 
$expectedAmount, 'USD' );
-               } else {
-                       $expectedDisplayAmount = "$expectedAmount USD";
-               }
+
+               $locale = $init['language'] . '_' . $init['country'];
+               $expectedDisplayAmount = Amount::format( $expectedAmount, 
'USD', $locale );
 
                $that = $this; //needed for PHP pre-5.4
                $convertTest = function( $amountString ) use ( 
$expectedDisplayAmount, $that ) {
diff --git a/tests/AmountTest.php b/tests/AmountTest.php
new file mode 100644
index 0000000..1f365ab
--- /dev/null
+++ b/tests/AmountTest.php
@@ -0,0 +1,199 @@
+<?php
+/**
+ * Wikimedia Foundation
+ *
+ * LICENSE
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/**
+ * @group      Fundraising
+ * @group      DonationInterface
+ * @group      Validation
+ */
+class AmountTest  extends DonationInterfaceTestCase {
+
+       /**
+        * @var GatewayType
+        */
+       protected $adapter;
+       /**
+        * @var Amount
+        */
+       protected $validator;
+       /**
+        * @var array
+        */
+       protected $errors;
+       /**
+        * @var array
+        */
+       protected $normalized;
+
+       public function setUp() {
+               parent::setUp();
+               $this->setMwGlobals( array(
+                       'wgDonationInterfacePriceFloor' => 1.50,
+                       'wgDonationInterfacePriceCeiling' => 100,
+                       'wgLanguageCode' => 'en',
+               ) );
+
+               $this->setUpRequest( array(
+                       'country' => 'US',
+                       'uselang' => 'en',
+               ) );
+
+               $this->normalized = array(
+                       'language' => 'en',
+                       'country' => 'US',
+                       'currency_code' => 'USD',
+               );
+
+               $this->errors = array();
+               $this->adapter = new TestingGenericAdapter();
+               $this->validator = new Amount();
+       }
+
+       protected function validate() {
+               $this->validator->validate(
+                       $this->adapter, $this->normalized, $this->errors
+               );
+       }
+
+       public function testValidUsd() {
+               $this->normalized['amount'] = '10.00';
+               $this->validate();
+               $this->assertEmpty( $this->errors, 'Error shown for valid 
amount' );
+       }
+
+       public function testZeroAmount() {
+               $this->normalized['amount'] = '0.00';
+               $this->validate();
+               $this->assertNotEmpty( $this->errors, 'No error for zero 
amount' );
+               $expected = DataValidator::getErrorMessage(
+                       'amount', 'not_empty', 'en'
+               );
+               $this->assertEquals(
+                       $expected,
+                       $this->errors['amount'],
+                       'Wrong error message for zero amount'
+               );
+       }
+
+       public function testWhitespaceAmount() {
+               $this->normalized['amount'] = '    ';
+               $this->validate();
+               $this->assertNotEmpty( $this->errors, 'No error for whitespace 
amount' );
+               $expected = DataValidator::getErrorMessage(
+                       'amount', 'not_empty', 'en'
+               );
+               $this->assertEquals(
+                       $expected,
+                       $this->errors['amount'],
+                       'Wrong error message for whitespace amount'
+               );
+       }
+
+       public function testNonNumericAmount() {
+               $this->normalized['amount'] = 'XYZ123';
+               $this->validate();
+               $this->assertNotEmpty( $this->errors, 'No error for non-numeric 
amount' );
+               $this->assertEquals(
+                       WmfFramework::formatMessage( 
'donate_interface-error-msg-invalid-amount' ),
+                       $this->errors['amount'],
+                       'Wrong error message for non-numeric amount'
+               );
+       }
+
+       public function testNegativeAmount() {
+               $this->normalized['amount'] = '-100.00';
+               $this->validate();
+               $this->assertNotEmpty( $this->errors, 'No error for negative 
amount' );
+               $this->assertEquals(
+                       WmfFramework::formatMessage( 
'donate_interface-error-msg-invalid-amount' ),
+                       $this->errors['amount'],
+                       'Wrong error message for negative amount'
+               );
+       }
+
+       public function testTooMuchUsd() {
+               $this->normalized['amount'] = '101.00';
+               $this->validate();
+               $this->assertNotEmpty( $this->errors, 'No error for excessive 
amount (USD)' );
+               $expected = WmfFramework::formatMessage(
+                       'donate_interface-bigamount-error',
+                       100,
+                       'USD',
+                       $this->adapter->getGlobal( 'MajorGiftsEmail' )
+               );
+               $this->assertEquals(
+                       $expected,
+                       $this->errors['amount'],
+                       'Wrong error message for excessive amount (USD)'
+               );
+       }
+
+       public function testTooLittleUsd() {
+               $this->normalized['amount'] = '1.49';
+               $this->validate();
+               $this->assertNotEmpty( $this->errors, 'No error for diminutive 
amount (USD)' );
+
+               $formattedMin = Amount::format( 1.50, 'USD', 'en_US' );
+               $expected = WmfFramework::formatMessage(
+                       'donate_interface-smallamount-error',
+                       $formattedMin
+               );
+               $this->assertEquals(
+                       $expected,
+                       $this->errors['amount'],
+                       'Wrong error message for diminutive amount (USD)'
+               );
+       }
+
+       // Conversion tests depend on Barbadian monetary policy
+       // BBD is convenient as it's pegged to $0.50
+       public function testTooMuchBbd() {
+               $this->normalized['currency_code'] = 'BBD';
+               $this->normalized['amount'] = '201.00';
+               $this->validate();
+               $this->assertNotEmpty( $this->errors, 'No error for excessive 
amount (BBD)' );
+               $expected = WmfFramework::formatMessage(
+                       'donate_interface-bigamount-error',
+                       200,
+                       'BBD',
+                       $this->adapter->getGlobal( 'MajorGiftsEmail' )
+               );
+               $this->assertEquals(
+                       $expected,
+                       $this->errors['amount'],
+                       'Wrong error message for excessive amount (BBD)'
+               );
+       }
+
+       public function testTooLittleBbd() {
+               $this->normalized['currency_code'] = 'BBD';
+               $this->normalized['amount'] = '2.95';
+               $this->validate();
+               $this->assertNotEmpty( $this->errors, 'No error for diminutive 
amount (BBD)' );
+
+               $formattedMin = Amount::format( 3.00, 'BBD', 'en_US' );
+               $expected = WmfFramework::formatMessage(
+                       'donate_interface-smallamount-error',
+                       $formattedMin
+               );
+               $this->assertEquals(
+                       $expected,
+                       $this->errors['amount'],
+                       'Wrong error message for diminutive amount (BBD)'
+               );
+       }
+}
diff --git a/tests/DataValidatorTest.php b/tests/DataValidatorTest.php
index 2c6c3f7..a158ae6 100644
--- a/tests/DataValidatorTest.php
+++ b/tests/DataValidatorTest.php
@@ -141,6 +141,7 @@
                $validator = new FiscalNumber();
                $errors = array();
                $validator->validate(
+                       new TestingGenericAdapter(),
                        array( 'country' => $country, 'fiscal_number' => 
$value, 'language' => 'en' ),
                        $errors
                );
diff --git a/worldpay_gateway/config/transformers.yaml 
b/worldpay_gateway/config/transformers.yaml
index 7bd55ed..cf439ca 100644
--- a/worldpay_gateway/config/transformers.yaml
+++ b/worldpay_gateway/config/transformers.yaml
@@ -1,4 +1,5 @@
 # Core
+- Amount
 - DonorEmail
 - DonorFullName
 - AmountInCents

-- 
To view, visit https://gerrit.wikimedia.org/r/286261
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: If9d60491cdc992a38a0ea459f5ece3f38ce08184
Gerrit-PatchSet: 13
Gerrit-Project: mediawiki/extensions/DonationInterface
Gerrit-Branch: master
Gerrit-Owner: Ejegg <[email protected]>
Gerrit-Reviewer: AndyRussG <[email protected]>
Gerrit-Reviewer: Awight <[email protected]>
Gerrit-Reviewer: Cdentinger <[email protected]>
Gerrit-Reviewer: Ejegg <[email protected]>
Gerrit-Reviewer: Ssmith <[email protected]>
Gerrit-Reviewer: XenoRyet <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to