2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
38 /*********************************************************************************
40 ********************************************************************************/
47 * This class encapsulates the handling of currency conversions and
48 * formatting in the SugarCRM application.
51 class Currency extends SugarBean
67 var $table_name = "currencies";
68 var $object_name = "Currency";
69 var $module_dir = "Currencies";
70 var $new_schema = true;
72 var $disable_num_format = true;
78 global $app_strings, $current_user, $sugar_config, $locale;
79 $this->field_defs['hide'] = array('name'=>'hide', 'source'=>'non-db', 'type'=>'varchar','len'=>25);
80 $this->field_defs['unhide'] = array('name'=>'unhide', 'source'=>'non-db', 'type'=>'varchar','len'=>25);
81 $this->disable_row_level_security =true;
86 * This method accepts a currency amount and converts it to the US Dollar amount
88 * @param $amount The currency amount to convert to US Dollars
89 * @param $precision The rounding precision scale
90 * @return currency value in US Dollars from conversion
92 function convertToDollar($amount, $precision = 6) {
93 return round(($amount / $this->conversion_rate), $precision);
98 * This method accepts a US Dollar amount and returns a currency amount
99 * with the conversion rate applied to it.
101 * @param $amount The currency amount in US Dollars
102 * @param $precision The rounding precision scale
103 * @return currency value from US Dollar conversion
105 function convertFromDollar($amount, $precision = 6){
106 return round(($amount * $this->conversion_rate), $precision);
110 * getDefaultCurrencyName
112 * Returns the default currency name as defined in application
113 * @return String value of default currency name
115 function getDefaultCurrencyName(){
116 global $sugar_config;
117 return $sugar_config['default_currency_name'];
121 * getDefaultCurrencySymbol
123 * Returns the default currency symobol in application
124 * @return String value of default currency symbol(e.g. $)
126 function getDefaultCurrencySymbol(){
127 global $sugar_config;
128 return $sugar_config['default_currency_symbol'];
134 * Returns the default ISO 4217 standard currency code value
135 * @return String value for the ISO 4217 standard code(e.g. EUR)
137 function getDefaultISO4217(){
138 global $sugar_config;
139 return $sugar_config['default_currency_iso4217'];
145 * Returns the id value for given currency symbol in Currencies table
146 * and currency entry for symbol is not set to deleted.
148 * @param $symbol Symbol value
149 * @return String id value for symbol defined in Currencies table, blank String value
152 function retrieveIDBySymbol($symbol) {
153 $query = "SELECT id FROM currencies WHERE symbol='$symbol' AND deleted=0;";
154 $result = $this->db->query($query);
156 $row = $this->db->fetchByAssoc($result);
165 function list_view_parse_additional_sections(&$list_form) {
168 if(isset($isMerge) && $isMerge && $this->id != '-99'){
169 $list_form->assign('PREROW', '<input name="mergecur[]" type="checkbox" value="'.$this->id.'">');
174 function retrieve_id_by_name($name) {
175 $query = "select id from currencies where name='$name' and deleted=0;";
176 $result = $this->db->query($query);
178 $row = $this->db->fetchByAssoc($result);
186 function retrieve($id, $encode = true){
188 $this->name = $this->getDefaultCurrencyName();
189 $this->symbol = $this->getDefaultCurrencySymbol();
191 $this->conversion_rate = 1;
192 $this->iso4217 = $this->getDefaultISO4217();
194 $this->status = 'Active';
195 $this->hide = '<!--';
196 $this->unhide = '-->';
198 parent::retrieve($id, $encode);
200 if(!isset($this->name) || $this->deleted == 1){
201 $this->name = $this->getDefaultCurrencyName();
202 $this->symbol = $this->getDefaultCurrencySymbol();
203 $this->conversion_rate = 1;
204 $this->iso4217 = $this->getDefaultISO4217();
207 $this->status = 'Active';
208 $this->hide = '<!--';
209 $this->unhide = '-->';
215 * Method for returning the currency symbol, must return chr(2) for the € symbol
216 * to display correctly in pdfs
220 * $symbol otherwise chr(2) for euro symbol
222 function getPdfCurrencySymbol() {
223 if($this->symbol == '€' || $this->symbol == '€')
225 return $this->symbol;
227 function get_list_view_data() {
228 $this->conversion_rate = format_number($this->conversion_rate, 10, 10);
229 $data = parent::get_list_view_data();
232 function save($check_notify = FALSE) {
233 sugar_cache_clear('currency_list');
234 return parent::save($check_notify);
236 } // end currency class
239 * currency_format_number
241 * This method is a wrapper designed exclusively for formatting currency values
242 * with the assumption that the method caller wants a currency formatted value
243 * matching his/her user preferences(if set) or the system configuration defaults
244 *(if user preferences are not defined).
246 * @param $amount The amount to be formatted
247 * @param $params Optional parameters(see @format_number)
248 * @return String representation of amount with formatting applied
250 function currency_format_number($amount, $params = array()) {
252 if(isset($params['round']) && is_int($params['round'])){
253 $real_round = $params['round'];
255 $real_round = $locale->getPrecedentPreference('default_currency_significant_digits');
257 if(isset($params['decimals']) && is_int($params['decimals'])){
258 $real_decimals = $params['decimals'];
260 $real_decimals = $locale->getPrecedentPreference('default_currency_significant_digits');
262 $real_round = $real_round == '' ? 0 : $real_round;
263 $real_decimals = $real_decimals == '' ? 0 : $real_decimals;
265 $showCurrencySymbol = $locale->getPrecedentPreference('default_currency_symbol') != '' ? true : false;
266 if($showCurrencySymbol && !isset($params['currency_symbol'])) {
267 $params["currency_symbol"] = true;
269 return format_number($amount, $real_round, $real_decimals, $params);
274 * format_number(deprecated)
276 * This method accepts an amount and formats it given the user's preferences.
277 * Should the values set in the user preferences be invalid then it will
278 * apply the system wide Sugar configuration values. Calls to
279 * getPrecendentPreference() method in Localization.php are made that
282 * Going forward with Sugar 4.5.0e+ implementations, users of this class should
283 * simple call this function with $amount parameter and leave it to the
284 * class to locate and apply the appropriate formatting.
286 * One of the problems is that there is considerable legacy code that is using
287 * this method for non currency formatting. In other words, the format_number
288 * method may be called to just display a number like 1,000 formatted appropriately.
290 * Also, issues about responsibilities arise. Currently the callers of this function
291 * are responsible for passing in the appropriate decimal and number rounding digits
292 * as well as parameters to control displaying the currency symbol or not.
294 * @param $amount The currency amount to apply formatting to
295 * @param $round Integer value for number of places to round to
296 * @param $decimals Integer value for number of decimals to round to
297 * @param $params Array of additional parameter values
300 * The following are passed in as an array of params:
301 * boolean $params['currency_symbol'] - true to display currency symbol
302 * boolean $params['convert'] - true to convert from USD dollar
303 * boolean $params['percentage'] - true to display % sign
304 * boolean $params['symbol_space'] - true to have space between currency symbol and amount
305 * String $params['symbol_override'] - string to over default currency symbol
306 * String $params['type'] - pass in 'pdf' for pdf currency symbol conversion
307 * String $params['currency_id'] - currency_id to retreive, defaults to current user
308 * String $params['human'] - formatting that truncates the first thousands and appends "k"
309 * @return String formatted currency value
310 * @see include/Localization/Localization.php
312 function format_number($amount, $round = null, $decimals = null, $params = array()) {
313 global $app_strings, $current_user, $sugar_config, $locale;
314 static $current_users_currency = null;
315 static $last_override_currency = null;
316 static $override_currency_id = null;
319 $seps = get_number_seperators();
320 $num_grp_sep = $seps[0];
323 // cn: bug 8522 - sig digits not honored in pdfs
324 if(is_null($decimals)) {
325 $decimals = $locale->getPrecision();
327 if(is_null($round)) {
328 $round = $locale->getPrecision();
331 // only create a currency object if we need it
332 if((!empty($params['currency_symbol']) && $params['currency_symbol']) ||
333 (!empty($params['convert']) && $params['convert']) ||
334 (!empty($params['currency_id']))) {
335 // if we have an override currency_id
336 if(!empty($params['currency_id'])) {
337 if($override_currency_id != $params['currency_id']) {
338 $override_currency_id = $params['currency_id'];
339 $currency = new Currency();
340 $currency->retrieve($override_currency_id);
341 $last_override_currency = $currency;
343 $currency = $last_override_currency;
346 } elseif(!isset($current_users_currency)) { // else use current user's
347 $current_users_currency = new Currency();
348 if($current_user->getPreference('currency')) $current_users_currency->retrieve($current_user->getPreference('currency'));
349 else $current_users_currency->retrieve('-99'); // use default if none set
350 $currency = $current_users_currency;
353 if(!empty($params['convert']) && $params['convert']) {
354 $amount = $currency->convertFromDollar($amount, 6);
357 if(!empty($params['currency_symbol']) && $params['currency_symbol']) {
358 if(!empty($params['symbol_override'])) {
359 $symbol = $params['symbol_override'];
361 elseif(!empty($params['type']) && $params['type'] == 'pdf') {
362 $symbol = $currency->getPdfCurrencySymbol();
363 $symbol_space = false;
365 if(empty($currency->symbol))
366 $symbol = $currency->getDefaultCurrencySymbol();
368 $symbol = $currency->symbol;
369 $symbol_space = true;
375 if(isset($params['charset_convert'])) {
376 $symbol = $locale->translateCharset($symbol, 'UTF-8', $locale->getExportCharset());
379 if(empty($params['human'])) {
380 $amount = number_format(round($amount, $round), $decimals, $dec_sep, $num_grp_sep);
381 $amount = format_place_symbol($amount, $symbol,(empty($params['symbol_space']) ? false : true));
383 // If amount is more greater than a thousand(postiive or negative)
384 if(strpos($amount, '.') > 0) {
385 $checkAmount = strlen(substr($amount, 0, strpos($amount, '.')));
388 if($checkAmount >= 1000 || $checkAmount <= -1000) {
389 $amount = round(($amount / 1000), 0);
390 $amount = $amount . 'k';
391 $amount = format_place_symbol($amount, $symbol,(empty($params['symbol_space']) ? false : true));
393 $amount = format_place_symbol($amount, $symbol,(empty($params['symbol_space']) ? false : true));
397 if(!empty($params['percentage']) && $params['percentage']) $amount .= $app_strings['LBL_PERCENTAGE_SYMBOL'];
400 } //end function format_number
404 function format_place_symbol($amount, $symbol, $symbol_space) {
406 if($symbol_space == true) {
407 $amount = $symbol . ' ' . $amount;
409 $amount = $symbol . $amount;
415 function unformat_number($string) {
416 // Just in case someone passes an already unformatted number through.
417 if ( !is_string($string) ) {
421 static $currency = null;
422 if(!isset($currency)) {
423 global $current_user;
424 $currency = new Currency();
425 if(!empty($current_user->id)){
426 if($current_user->getPreference('currency')){
427 $currency->retrieve($current_user->getPreference('currency'));
430 $currency->retrieve('-99'); // use default if none set
433 $currency->retrieve('-99'); // use default if none set
437 $seps = get_number_seperators();
438 // remove num_grp_sep and replace decimal seperater with decimal
439 $string = trim(str_replace(array($seps[0], $seps[1], $currency->symbol), array('', '.', ''), $string));
440 if(preg_match('/^[+-]?\d(\.\d+)?[Ee]([+-]?\d+)?$/', $string)) $string = sprintf("%.0f", $string);//for scientific number format. After round(), we may get this number type.
441 preg_match('/[\-\+]?[0-9\.]*/', $string, $string);
443 $out_number = trim($string[0]);
444 if ( $out_number == '' ) {
447 return (float)$out_number;
451 // deprecated use format_number() above
452 function format_money($amount, $for_display = TRUE) {
453 // This function formats an amount for display.
454 // Later on, this should be converted to use proper thousand and decimal seperators
455 // Currently, it stays closer to the existing format, and just rounds to two decimal points
458 return sprintf("%0.02f",$amount);
460 // If it's an editable field, don't use a thousand seperator.
461 // Or perhaps we will want to, but it doesn't matter right now.
462 return sprintf("%0.02f",$amount);
470 * Returns user/system preference for number grouping separator character(default ",") and the decimal separator
471 *(default "."). Special case: when num_grp_sep is ".", it will return NULL as the num_grp_sep.
472 * @return array Two element array, first item is num_grp_sep, 2nd item is dec_sep
474 function get_number_seperators($reset_sep = false) {
475 global $current_user, $sugar_config;
477 static $dec_sep = null;
478 static $num_grp_sep = null;
481 // This is typically only used during unit-tests
482 $dec_sep = $num_grp_sep = null;
485 if($dec_sep == null) {
486 $dec_sep = $sugar_config['default_decimal_seperator'];
487 if(!empty($current_user->id)){
488 $user_dec_sep = $current_user->getPreference('dec_sep');
489 $dec_sep =(empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
492 if($num_grp_sep == null) {
493 $num_grp_sep = $sugar_config['default_number_grouping_seperator'];
494 if(!empty($current_user->id)){
495 $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
496 $num_grp_sep =(empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
500 return array($num_grp_sep, $dec_sep);
506 * Utility function to print out some information about Currency instance.
508 function toString($echo = true) {
509 $s = "\$m_currency_round=$m_currency_round \n" .
510 "\$m_currency_decimal=$m_currency_decimal \n" .
511 "\$m_currency_symbol=$m_currency_symbol \n" .
512 "\$m_currency_iso=$m_currency_iso \n" .
513 "\$m_currency_name=$m_currency_name \n";
522 function getCurrencyDropDown($focus, $field='currency_id', $value='', $view='DetailView'){
523 $view = ucfirst($view);
524 if($view == 'EditView' || $view == 'MassUpdate' || $view == 'QuickCreate'){
525 if ( isset($_REQUEST[$field]) && !empty($_REQUEST[$field]) ) {
526 $value = $_REQUEST[$field];
527 } elseif ( empty($focus->id) ) {
528 $value = $GLOBALS['current_user']->getPreference('currency');
529 if ( empty($value) ) {
530 // -99 is the system default currency
534 require_once('modules/Currencies/ListCurrency.php');
535 $currency_fields = array();
536 //Bug 18276 - Fix for php 5.1.6
537 $defs=$focus->field_defs;
539 foreach($defs as $name=>$key){
540 if($key['type'] == 'currency'){
541 $currency_fields[]= $name;
544 $currency = new ListCurrency();
545 $selectCurrency = $currency->getSelectOptions($value);
547 $currency->setCurrencyFields($currency_fields);
548 $html = '<select name="'. $field. '" ';
549 if($view != 'MassUpdate')
550 $html .= 'onchange="CurrencyConvertAll();"';
551 $html .= '>'. $selectCurrency . '</select>';
552 if($view != 'MassUpdate')
553 $html .= $currency->getJavascript();
557 $currency = new Currency();
558 $currency->retrieve($value);
559 return $currency->name;
564 function getCurrencyNameDropDown($focus, $field='currency_name', $value='', $view='DetailView')
566 if($view == 'EditView' || $view == 'MassUpdate' || $view == 'QuickCreate'){
567 require_once('modules/Currencies/ListCurrency.php');
568 $currency_fields = array();
569 //Bug 18276 - Fix for php 5.1.6
570 $defs=$focus->field_defs;
572 foreach($defs as $name=>$key){
573 if($key['type'] == 'currency'){
574 $currency_fields[]= $name;
577 $currency = new ListCurrency();
578 $currency->lookupCurrencies();
579 $listitems = array();
580 foreach ( $currency->list as $item )
581 $listitems[$item->name] = $item->name;
582 return '<select name="'.$field.'" id="'.$field.'" />'.
583 get_select_options_with_id($listitems,$value).'</select>';
586 $currency = new Currency();
587 if ( isset($focus->currency_id) ) {
588 $currency_id = $focus->currency_id;
592 $currency->retrieve($currency_id);
593 return $currency->name;
597 function getCurrencySymbolDropDown($focus, $field='currency_name', $value='', $view='DetailView')
599 if($view == 'EditView' || $view == 'MassUpdate' || $view == 'QuickCreate'){
600 require_once('modules/Currencies/ListCurrency.php');
601 $currency_fields = array();
602 //Bug 18276 - Fix for php 5.1.6
603 $defs=$focus->field_defs;
605 foreach($defs as $name=>$key){
606 if($key['type'] == 'currency'){
607 $currency_fields[]= $name;
610 $currency = new ListCurrency();
611 $currency->lookupCurrencies();
612 $listitems = array();
613 foreach ( $currency->list as $item )
614 $listitems[$item->symbol] = $item->symbol;
615 return '<select name="'.$field.'" id="'.$field.'" />'.
616 get_select_options_with_id($listitems,$value).'</select>';
619 $currency = new Currency();
620 if ( isset($focus->currency_id) ) {
621 $currency_id = $focus->currency_id;
625 $currency->retrieve($currency_id);
626 return $currency->name;