Jump to content
ryan

Module: Currency Conversion Service

Recommended Posts

Currency Conversion for ProcessWire
 
This module is designed for performing currency conversions among ~165 world currencies. It uses OpenExchangeRates.org (or compatible) for data so that currency exchange rates are always up-to-date.
 
It provides various API functions that you can use to convert from one currency to another. This is especially handy for generating rate tables in multiple currencies or giving users of your site the option to see prices in their currency.
Requires ProcessWire 2.4.0 or newer. To use the quick-installer from your modules screen, paste in ServiceCurrencyConversion.
 
Basic Example
$cc = $modules->get('ServiceCurrencyConversion'); 
$dollars = 100; // amount of currency we want to convert
$euros = $cc->convert('USD', 'EUR', $dollars); 
echo "<p>$dollars US Dollars equals $euros Euros</p>";  

For a live example of a currency conversion tool built with this module see the included convert.php file and test it out here.

  • Like 17

Share this post


Link to post
Share on other sites

Ryan, this module is working really well for me on everything but one currency; mexian peso MXN. When parsing it reports this error:

Error: Exception: Can't find target currency. (in /var/www/clients/client2/web37/web/site/modules/ServiceCurrencyConversion/ServiceCurrencyConversion.module line 295)

#0 /var/www/clients/client2/web37/web/site/modules/ServiceCurrencyConversion/ServiceCurrencyConversion.module(310): ServiceCurrencyConversion->convertAdvanced('GBP', 'MXN', 250, 0, -1)
#1 /var/www/clients/client2/web37/web/site/templates/currency.php(16): ServiceCurrencyConversion->convert('GBP', 'MXN', 250)
#2 /var/www/clients/client2/web37/web/wire/core/TemplateFile.php(140): require('/var/www/client...')
#3 [internal function]: TemplateFile->___render()
#4 /var/www/clients/client2/web37/web/wire/core/Wire.php(359): call_user_func_array(Array, Array)
#5 /var/www/clients/client2/web37/web/wire/core/Wire.php(317): Wire->runHooks('render', Array)
#6 /var/www/clients/client2/web37/web/wire/modules/PageRender.module(337): Wire->__call('render', Array)
#7 /var/www/clients/client2/web37/web/wire/modules/PageRender.module(337): TemplateFile->render()
#8 [in

I'm using this to  code:

$cc = $modules->get('ServiceCurrencyConversion');
$dollars  = 250;   // this is what we're going to convert   -- ignore dollar naming convention
$currency = $page->symbol;   // 
$symbol = $cc->getSymbol("$currency");
$euros = $cc->convert('GBP', "$currency", $dollars);  //again, please ignore dodgy naming convention
$simple = $cc->convert('GBP', "$currency", '1');

?>

<div class="container">
	<div class="row">
		<div class="col-md-6">
		<?php echo "<h2> £1 = $symbol$simple .</h2>"; ?>
		</div>

	        <div class="col-md-6">
                <?php echo "<h3>That means £$dollars is going to buy you {$symbol}{$euros} .</3>"; ?>
                </div>



	</div>
</div>

please ignore my dodgy variable names.

Any idea why it has a problem with MXN please?

Share this post


Link to post
Share on other sites

Hmmmm, looks like I'll have to hard code the value with a warning.

I'll have a closer look at the other example. Cheers Adrian.

Share this post


Link to post
Share on other sites

And in this:

http://openexchangerates.org/api/latest.json?app_id=xxxxx (with your API key).

What happens if you edit the module file:

https://github.com/ryancramerdesign/ServiceCurrencyConversion/blob/master/ServiceCurrencyConversion.module#L293

to include a log of $rates and $toCurrency

public function convertAdvanced($fromCurrency, $toCurrency, $amount, $markup = 0.0, $decimals = -1) {
    error_log(print_r($rates,true));
    error_log("ToCURR:".$toCurrency);
    $rates = $this->getConvertedRatesTable($fromCurrency, $amount, $markup, $decimals); 
    if(!isset($rates[$toCurrency])) throw new WireException("Can't find target currency."); 
    return $rates[$toCurrency]; 
}

Share this post


Link to post
Share on other sites

Unfortunately that didn't seem to make any difference. I commented out the original function and added your adapted one in like so:

/**	public function convertAdvanced($fromCurrency, $toCurrency, $amount, $markup = 0.0, $decimals = -1) {
*		$rates = $this->getConvertedRatesTable($fromCurrency, $amount, $markup, $decimals); 
*		if(!isset($rates[$toCurrency])) throw new WireException("Can't find target currency."); 
*		return $rates[$toCurrency]; 
*	}
*/	
	
	public function convertAdvanced($fromCurrency, $toCurrency, $amount, $markup = 0.0, $decimals = -1) {
    error_log(print_r($rates,true));
    error_log("ToCURR:".$toCurrency);
    $rates = $this->getConvertedRatesTable($fromCurrency, $amount, $markup, $decimals); 
    if(!isset($rates[$toCurrency])) throw new WireException("Can't find target currency."); 
    return $rates[$toCurrency]; 
}

but still received the following for MXN:

Error: Exception: Can't find target currency. (in /var/www/clients/client2/web37/web/site/modules/ServiceCurrencyConversion/ServiceCurrencyConversion.module line 304)

#0 /var/www/clients/client2/web37/web/site/modules/ServiceCurrencyConversion/ServiceCurrencyConversion.module(319): ServiceCurrencyConversion->convertAdvanced('GBP', 'MXN', 250, 0, -1)
#1 /var/www/clients/client2/web37/web/site/templates/currency.php(16): ServiceCurrencyConversion->convert('GBP', 'MXN', 250)
#2 /var/www/clients/client2/web37/web/wire/core/TemplateFile.php(140): require('/var/www/client...')
#3 [internal function]: TemplateFile->___render()
#4 /var/www/clients/client2/web37/web/wire/core/Wire.php(359): call_user_func_array(Array, Array)
#5 /var/www/clients/client2/web37/web/wire/core/Wire.php(317): Wire->runHooks('render', Array)
#6 /var/www/clients/client2/web37/web/wire/modules/PageRender.module(337): Wire->__call('render', Array)
#7 /var/www/clients/client2/web37/web/wire/modules/PageRender.module(337): TemplateFile->render()
#8 [in

Share this post


Link to post
Share on other sites

Sorry, I wasn't expecting it to fix anything :)  I just wanted to see what was in the error log to see if the $rates array contains MXN and to check what the value of $toCurrently is.

Do you know where to find your php error log?

Share this post


Link to post
Share on other sites

After having a fair bit of hunting around... no

I'm using apache2 php5 on debian.

/var/log seems to hold most of them but nothing obvious

Share this post


Link to post
Share on other sites

Ok, sorry, try replacing error_log on both lines with:

$log->error 

which will put the results into /site/assets/logs/error.txt

Share this post


Link to post
Share on other sites

Sorry I put that error log call before $rates was defined. Try moving those new lines after:

$rates = $this->getConvertedRatesTable($fromCurrency, $amount, $markup, $decimals); 

I'll also try installing the module here and see if I can replicate the error.

Share this post


Link to post
Share on other sites

Thank you. I need some sleep now so I'll have to recommence tomorrow.

Cheers

Share this post


Link to post
Share on other sites

OK, I have a quick fix for you. Replace the attached file. It was a problem with the parsing of currencies with two codes.

The Mexican Peso was:

MXN MXV Mexican Peso Mexican Unidad de Inversion (UDI) $

But if you change it to:

MXN Mexican Peso Mexican Unidad de Inversion (UDI) $

everything works fine. The reason I attached a replacement is that you need to make sure there are tabs in the correct places within that line.

Seems like there needs to be a change to the parsing logic here to account for currencies with more than one code, because right now, the code that is being sent to the Open Exchange Rates service is "MXN MXV". There are actually several currencies with the same problem.

if(substr_count($line, "\t") < 2) {
   list($code, $name) = explode("\t", $line); 
   $symbol = '';
} else {
   list($code, $name, $symbol) = explode("\t", $line); 
}

I am not sure what the extra code is about anyway, so maybe Ryan will Chime in. He will either need to remove the extra code from the txt file, or parse it out before sending to the service.

Github issue submitted: https://github.com/ryancramerdesign/ServiceCurrencyConversion/issues/1

currencies.txt

  • Like 4

Share this post


Link to post
Share on other sites

OK, I have a quick fix for you. Replace the attached file. It was a problem with the parsing of currencies with two codes.

The Mexican Peso was:

MXN MXV Mexican Peso Mexican Unidad de Inversion (UDI) $

But if you change it to:

MXN Mexican Peso Mexican Unidad de Inversion (UDI) $

everything works fine. The reason I attached a replacement is that you need to make sure there are tabs in the correct places within that line.

Seems like there needs to be a change to the parsing logic here to account for currencies with more than one code, because right now, the code that is being sent to the Open Exchange Rates service is "MXN MXV". There are actually several currencies with the same problem.

if(substr_count($line, "\t") < 2) {
   list($code, $name) = explode("\t", $line); 
   $symbol = '';
} else {
   list($code, $name, $symbol) = explode("\t", $line); 
}

I am not sure what the extra code is about anyway, so maybe Ryan will Chime in. He will either need to remove the extra code from the txt file, or parse it out before sending to the service.

Github issue submitted: https://github.com/ryancramerdesign/ServiceCurrencyConversion/issues/1

Adrian - superb!

I guess the problem with having a separate currency symbol on a different line could cause problems when you use the module round the other way and rather than asking for a conversion with symbols you can pass it country names to return symbols I think.. meaning it may bring back two.

but for me.. solver it perfectly.

Cheers

  • Like 1

Share this post


Link to post
Share on other sites

Can this be tweaked to dynamically change an amount on a PW site?

Say I had a product listed for sale at $60 (USD)

I'd like to have a US and a UK flag.

Clicking US or UK flag would convert the $60 to £80 (or whatever).

Share this post


Link to post
Share on other sites

If somebody needs this too. I wrote a Module Fieldtype InputfieldSelect suitable to ServiceCurrencyConversion.
It stores the 3-letter code and returns a multiple array value of all corresponding exchange rates.

    	array(
    	'code' => EUR // selected value
    	'name' => 'Euros', 
	'symbol' => '€', 
	'x' => [USD exhcange rate], 
	'updated' => 2015-01-14-14:45, 
	'AED' => array(
		'name' => 'UAE Dirham', 
		'symbol' => '', 
		'x' => [EUR exchange rate], // source = selected value
		'amount' => [your amount in UAE Dirham]
		), 
	'[currency code]' => array(
		...and so on...
		),
		.. and so on...
	);

There is a small issue in the currencies.txt file. Module cannot handle double entries like:

UYU UYI    Peso Uruguayo Uruguay Peso en Unidades Indexadas    $U

this should be changed to

UYU    Peso Uruguayo    $U
UYI    Uruguay Peso en Unidades Indexadas    

Other solution is to make the module able to handle this.

Here comes the FieldtypeSelectCurrency. Have fun :)


FieldtypeSelectCurrency.module

Share this post


Link to post
Share on other sites

@adrian
sorry I didn't read all posts of the topic. I fixed the issue in a german translation.

There is also a currency missing.
ZMK    Zambian Kwacha is not in use anymore. It was replaced by ZMW in 2013 (1000:1).
Possible to keep ZMK but ZMW should be added.
 

Share this post


Link to post
Share on other sites

I want to use this lovely little converter to search a given textarea field for all mentions of currency amounts, convert each of those to another currency, and then show both. In other words, taking:

Quote

"...the rate is €40 for 40 minutes, €70 for 80 minutes..."

and turning that into:

Quote

"...the rate is €40 ($48) for 40 minutes, €70 ($83) for 80 minutes..." 

(The usd amount, obviously, would be filled in by the converter.)

After dozens of code variations and attempted angles of attack, I feel like I am close with this—but it is not quite working.

$cc = $modules->get('ServiceCurrencyConversion');
$text = $page->body;
$regex='/\x{20AC}\d+(\.\d{2})?/u';
$text = preg_replace($regex, '$0 ($' . $cc->convert("EUR", "USD", str_replace('€;', '', $regex)) . ')', $text);
echo $text;

It does no actual converting. I end up with just the euro amount repeating itself in parentheses:

Quote

"...the rate is €40 (€40) for 40 minutes, €70 (€70) for 80 minutes..." 

I figured the cc_convert only works on numerical amounts, so I need to strip the currency symbol before I can perform the conversion, but am having a devil of a time doing so. (And, yes, I have tried all sorts of Unicode, UTF, and HTM Entity encodings in place of that '€' to no avail.) 

For the record, I am, shall we say, not very handy with regex (it took my a day and half to arrive at that working $regex variable).

(As a cherry in top, I'd also like to round output amount, which I haven't yet even tried to work into the code.)

Any advice?

Share this post


Link to post
Share on other sites
11 hours ago, Reid Bramblett said:

For the record, I am, shall we say, not very handy with regex

My regex is rather weak also, but I think this will work...

$cc = $modules->get('ServiceCurrencyConversion');
$text = $page->body;
$regex = '/\x{20AC}([0-9]+\.?[0-9]+)/u';
$text = preg_replace_callback(
    $regex,
    function($matches) use ($cc) {
        $dollars = number_format($cc->convert('EUR', 'USD', $matches[1]), 0);
        return "{$matches[0]} (\${$dollars})";
    },
    $text
);
echo $text;

Would makes sense to put this into a simple Textformatter module and use it that way. See TextformatterNewlineBR for a basic example to start from.

  • Like 1

Share this post


Link to post
Share on other sites

Thanks, Robin. Works a treat.

I had tried fiddling with the number_format as well, but didn't really understand it.

I did, however, go back and tweak the regex statement so that it would catch single-digit amounts, too, as well as amounts with or without a two-place decimal amount (the "cents"). 

Share this post


Link to post
Share on other sites

I'm using this piece of code from the convert.php demo page  

  $cc = $modules->get('ServiceCurrencyConversion'); 
    $names = $cc->getNames(); // names of currencies, indexed by 3-digit codes
    $amount = '';
    $options = '';
    foreach($names as $code => $name) {
        $options .= "<option value='$code'>$code: $name</option>";
    }
    $optionsTo = $options; 



    echo "<select name='to' onchange='this.form.submit()'>";
        echo "<option>Select currency</option>";
        echo $optionsTo;
    echo "</select><input type='submit' name='submit' value='Convert' /></p>";

I'm getting all possible currencies as a dropdown.
How do I limit the choices of the options to my selection of relevant currencies (e.g. EUR, USD, GBP)?

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...