/**
  * 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');
 }
 /**
  * Integration test to verify that the Amazon gateway converts Canadian
  * dollars before redirecting
  *
  * @dataProvider canadaLanguageProvider
  */
 function testCanadianDollarConversion($language)
 {
     $init = $this->getDonorTestData('CA');
     unset($init['order_id']);
     $init['payment_method'] = 'amazon';
     $init['ffname'] = 'amazon';
     $init['language'] = $language;
     $rates = CurrencyRates::getCurrencyRates();
     $cadRate = $rates['CAD'];
     $expectedAmount = floor($init['amount'] / $cadRate);
     TestingAmazonAdapter::$fakeGlobals = array('FallbackCurrency' => 'USD', 'NotifyOnConvert' => true);
     $expectedNotification = wfMessage('donate_interface-fallback-currency-notice', 'USD')->inLanguage($language)->text();
     $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) {
         $that->assertEquals($expectedDisplayAmount, trim($amountString), 'Displaying wrong amount');
     };
     $assertNodes = array('selected-amount' => array('innerhtml' => $convertTest), 'mw-content-text' => array('innerhtmlmatches' => "/.*{$expectedNotification}.*/"));
     $this->verifyFormOutput('AmazonGateway', $init, $assertNodes, false);
 }
 /**
  * Called when a currency code error exists. If a fallback currency
  * conversion is enabled for this adapter, convert intended amount to
  * default currency.
  *
  * @throws DomainException
  */
 protected function fallbackToDefaultCurrency()
 {
     $adapterClass = $this->gateway->getGatewayAdapterClass();
     $defaultCurrency = null;
     if ($this->gateway->getGlobal('FallbackCurrencyByCountry')) {
         $country = $this->getVal('country');
         if ($country !== null) {
             $defaultCurrency = NationalCurrencies::getNationalCurrency($country);
         }
     } else {
         $defaultCurrency = $this->gateway->getGlobal('FallbackCurrency');
     }
     if (!$defaultCurrency) {
         return;
     }
     // Our conversion rates are all relative to USD, so use that as an
     // intermediate currency if converting between two others.
     $oldCurrency = $this->getVal('currency_code');
     if ($oldCurrency === $defaultCurrency) {
         throw new DomainException(__FUNCTION__ . " Unsupported currency {$defaultCurrency} set as fallback for {$adapterClass}.");
     }
     $oldAmount = $this->getVal('amount');
     $usdAmount = 0.0;
     $newAmount = 0;
     $conversionRates = CurrencyRates::getCurrencyRates();
     if ($oldCurrency === 'USD') {
         $usdAmount = $oldAmount;
     } elseif (array_key_exists($oldCurrency, $conversionRates)) {
         $usdAmount = $oldAmount / $conversionRates[$oldCurrency];
     } else {
         // We can't convert from this unknown currency.
         return;
     }
     if ($defaultCurrency === 'USD') {
         $newAmount = floor($usdAmount);
     } elseif (array_key_exists($defaultCurrency, $conversionRates)) {
         $newAmount = floor($usdAmount * $conversionRates[$defaultCurrency]);
     }
     $this->setVal('amount', $newAmount);
     $this->setVal('currency_code', $defaultCurrency);
     $this->logger->info("Unsupported currency {$oldCurrency} forced to {$defaultCurrency}");
     // We have a fallback, so let's revalidate.
     $this->getValidationErrors(true);
     $notify = $this->gateway->getGlobal('NotifyOnConvert');
     // If we're configured to notify, or if there are already other errors,
     // add a notification message.
     if ($notify || !empty($this->validationErrors)) {
         $error['general'] = MessageUtils::getCountrySpecificMessage('donate_interface-fallback-currency-notice', $this->getVal('country'), $this->getVal('language'), array($this->gateway->getGlobal('FallbackCurrency')));
         $this->gateway->addManualError($error);
     }
 }
 /**
  * @see ResourceLoaderModule::getScript()
  */
 public function getScript(ResourceLoaderContext $context)
 {
     return 'mw.config.set( "wgDonationInterfaceCurrencyRates", ' . Xml::encodeJsVar(CurrencyRates::getCurrencyRates()) . ' );';
 }