/** * 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()) . ' );'; }