]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/Currencies/Currency.php
Release 6.5.0
[Github/sugarcrm.git] / modules / Currencies / Currency.php
1 <?php
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-2012 SugarCRM Inc.
6  * 
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.
13  * 
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
17  * details.
18  * 
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
22  * 02110-1301 USA.
23  * 
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.
26  * 
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.
30  * 
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  ********************************************************************************/
37
38 /*********************************************************************************
39
40  ********************************************************************************/
41
42
43
44
45 /**
46  * Currency.php
47  * This class encapsulates the handling of currency conversions and
48  * formatting in the SugarCRM application.
49  *
50  */
51 class Currency extends SugarBean
52 {
53         // Stored fields
54         var $id;
55         var $iso4217;
56         var $name;
57         var $status;
58         var $conversion_rate;
59         var $deleted;
60         var $date_entered;
61         var $date_modified;
62         var $symbol;
63         var $hide = '';
64         var $unhide = '';
65         var $field_name_map;
66
67         var $table_name = "currencies";
68         var $object_name = "Currency";
69         var $module_dir = "Currencies";
70         var $new_schema = true;
71
72         var $disable_num_format = true;
73
74
75     function Currency()
76         {
77                 parent::SugarBean();
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;
82         }
83
84     /**
85      * convertToDollar
86      * This method accepts a currency amount and converts it to the US Dollar amount
87      *
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
91      */
92         function convertToDollar($amount, $precision = 6) {
93                 return round(($amount / $this->conversion_rate), $precision);
94         }
95
96     /**
97      * convertFromCollar
98      * This method accepts a US Dollar amount and returns a currency amount
99      * with the conversion rate applied to it.
100      *
101      * @param $amount The currency amount in US Dollars
102      * @param $precision The rounding precision scale
103      * @return currency value from US Dollar conversion
104      */
105         function convertFromDollar($amount, $precision = 6){
106                 return round(($amount * $this->conversion_rate), $precision);
107         }
108
109     /**
110      * getDefaultCurrencyName
111      *
112      * Returns the default currency name as defined in application
113      * @return String value of default currency name
114      */
115         function getDefaultCurrencyName(){
116                 global $sugar_config;
117                 return $sugar_config['default_currency_name'];
118         }
119
120     /**
121      * getDefaultCurrencySymbol
122      *
123      * Returns the default currency symobol in application
124      * @return String value of default currency symbol(e.g. $)
125      */
126         function getDefaultCurrencySymbol(){
127                 global $sugar_config;
128                 return $sugar_config['default_currency_symbol'];
129         }
130
131     /**
132      * getDefaultISO4217
133      *
134      * Returns the default ISO 4217 standard currency code value
135      * @return String value for the ISO 4217 standard code(e.g. EUR)
136      */
137         function getDefaultISO4217(){
138                 global $sugar_config;
139                 return $sugar_config['default_currency_iso4217'];
140         }
141
142     /**
143      * retrieveIDBySmbol
144      *
145      * Returns the id value for given currency symbol in Currencies table
146      * and currency entry for symbol is not set to deleted.
147      *
148      * @param $symbol Symbol value
149      * @return String id value for symbol defined in Currencies table, blank String value
150      *         if none found
151      */
152         function retrieveIDBySymbol($symbol) {
153                 $query = "SELECT id FROM currencies WHERE symbol='$symbol' AND deleted=0;";
154                 $result = $this->db->query($query);
155                 if($result){
156                   $row = $this->db->fetchByAssoc($result);
157                   if($row){
158                      return $row['id'];
159                   }
160                 }
161
162                 return '';
163          }
164
165          function list_view_parse_additional_sections(&$list_form) {
166                 global $isMerge;
167
168                 if(isset($isMerge) && $isMerge && $this->id != '-99'){
169                 $list_form->assign('PREROW', '<input name="mergecur[]" type="checkbox" value="'.$this->id.'">');
170                 }
171                 return $list_form;
172         }
173
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);
177                 if($result){
178                 $row = $this->db->fetchByAssoc($result);
179                 if($row){
180                         return $row['id'];
181                 }
182                 }
183                 return '';
184         }
185         
186     function retrieve($id, $encode = true, $deleted = true){
187         if($id == '-99'){
188                 $this->name =   $this->getDefaultCurrencyName();
189                 $this->symbol = $this->getDefaultCurrencySymbol();
190                 $this->id = '-99';
191                 $this->conversion_rate = 1;
192                 $this->iso4217 = $this->getDefaultISO4217();
193                 $this->deleted = 0;
194                 $this->status = 'Active';
195                 $this->hide = '<!--';
196                 $this->unhide = '-->';
197         }else{
198                 parent::retrieve($id, $encode, $deleted);
199         }
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();
205                 $this->id = '-99';
206                 $this->deleted = 0;
207                 $this->status = 'Active';
208                 $this->hide = '<!--';
209                 $this->unhide = '-->';
210         }
211         return $this;
212      }
213
214     /**
215      * Method for returning the currency symbol, must return chr(2) for the â‚¬ symbol
216      * to display correctly in pdfs
217      * Parameters:
218      *  none
219      * Returns:
220      *  $symbol otherwise chr(2) for euro symbol
221      */
222      function getPdfCurrencySymbol() {
223         if($this->symbol == '&#8364;' || $this->symbol == '€')
224                 return chr(2);
225         return $this->symbol;
226      }
227         function get_list_view_data() {
228                 $this->conversion_rate = format_number($this->conversion_rate, 10, 10);
229                 $data = parent::get_list_view_data();
230                 return $data;
231         }
232     function save($check_notify = FALSE) {
233         sugar_cache_clear('currency_list');
234         return parent::save($check_notify);
235     }
236 } // end currency class
237
238 /**
239  * currency_format_number
240  *
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).
245  *
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
249  */
250 function currency_format_number($amount, $params = array()) {
251     global $locale;
252     if(isset($params['round']) && is_int($params['round'])){
253             $real_round = $params['round'];
254     }else{
255         $real_round = $locale->getPrecedentPreference('default_currency_significant_digits');
256     }
257         if(isset($params['decimals']) && is_int($params['decimals'])){
258         $real_decimals = $params['decimals'];
259         }else{
260             $real_decimals = $locale->getPrecedentPreference('default_currency_significant_digits');
261         }
262         $real_round = $real_round == '' ? 0 : $real_round;
263         $real_decimals = $real_decimals == '' ? 0 : $real_decimals;
264
265         $showCurrencySymbol = $locale->getPrecedentPreference('default_currency_symbol') != '' ? true : false;
266         if($showCurrencySymbol && !isset($params['currency_symbol'])) {
267            $params["currency_symbol"] = true;
268         }
269         return format_number($amount, $real_round, $real_decimals, $params);
270
271 }
272
273 /**
274  * format_number(deprecated)
275  *
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
280  * handle this logic.
281  *
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.
285  *
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.
289  *
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.
293  *
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
298  *
299  *
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
311  */
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;
317         static $currency;
318
319         $seps = get_number_seperators();
320         $num_grp_sep = $seps[0];
321         $dec_sep = $seps[1];
322
323         // cn: bug 8522 - sig digits not honored in pdfs
324         if(is_null($decimals)) {
325                 $decimals = $locale->getPrecision();
326         }
327         if(is_null($round)) {
328                 $round = $locale->getPrecision();
329         }
330
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;
342                                 } else {
343                                         $currency = $last_override_currency;
344                                 }
345
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;
351                         }
352         }
353         if(!empty($params['convert']) && $params['convert']) {
354                 $amount = $currency->convertFromDollar($amount, 6);
355         }
356
357         if(!empty($params['currency_symbol']) && $params['currency_symbol']) {
358                 if(!empty($params['symbol_override'])) {
359                         $symbol = $params['symbol_override'];
360                 }
361                 elseif(!empty($params['type']) && $params['type'] == 'pdf') {
362                         $symbol = $currency->getPdfCurrencySymbol();
363                         $symbol_space = false;
364                 } else {
365                         if(empty($currency->symbol))
366                                 $symbol = $currency->getDefaultCurrencySymbol();
367                         else
368                                 $symbol = $currency->symbol;
369                         $symbol_space = true;
370                 }
371         } else {
372                 $symbol = '';
373         }
374
375         if(isset($params['charset_convert'])) {
376                 $symbol = $locale->translateCharset($symbol, 'UTF-8', $locale->getExportCharset());
377         }
378
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));
382         } else {
383                 // If amount is more greater than a thousand(positive or negative)
384             if(strpos($amount, '.') > 0) {
385                $checkAmount = strlen(substr($amount, 0, strpos($amount, '.')));
386             }
387
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));
392                 } else {
393                         $amount = format_place_symbol($amount, $symbol,(empty($params['symbol_space']) ? false : true));
394                 }
395         }
396
397         if(!empty($params['percentage']) && $params['percentage']) $amount .= $app_strings['LBL_PERCENTAGE_SYMBOL'];
398         return $amount;
399
400 } //end function format_number
401
402
403
404 function format_place_symbol($amount, $symbol, $symbol_space) {
405         if($symbol != '') {
406                 if($symbol_space == true) {
407                         $amount = $symbol . '&nbsp;' . $amount;
408                 } else {
409                         $amount = $symbol . $amount;
410                 }
411         }
412         return $amount;
413 }
414
415 function unformat_number($string) {
416     // Just in case someone passes an already unformatted number through.
417     if ( !is_string($string) ) {
418         return $string;
419     }
420
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'));
428                         }
429                         else{
430                                 $currency->retrieve('-99'); // use default if none set
431         }
432                 }else{
433                         $currency->retrieve('-99'); // use default if none set
434                 }
435         }
436
437         $seps = get_number_seperators();
438         // remove num_grp_sep and replace decimal separator 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);
442
443     $out_number = trim($string[0]);
444     if ( $out_number == '' ) {
445         return '';
446     } else {
447         return (float)$out_number;
448     }
449 }
450
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
456         if(isset($amount)) {
457                 if($for_display) {
458                         return sprintf("%0.02f",$amount);
459                 } else {
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);
463                 }
464         } else {
465                 return;
466         }
467 }
468
469 /**
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
473  */
474 function get_number_seperators($reset_sep = false)
475 {
476         global $current_user, $sugar_config;
477
478         static $dec_sep = null;
479         static $num_grp_sep = null;
480
481     // This is typically only used during unit-tests
482     // TODO: refactor this. unit tests should not have static dependencies
483         if ($reset_sep)
484         {
485         $dec_sep = $num_grp_sep = null;
486     }
487
488         if ($dec_sep == null)
489         {
490                 $dec_sep = $sugar_config['default_decimal_seperator'];
491                 if (!empty($current_user->id))
492                 {
493                         $user_dec_sep = $current_user->getPreference('dec_sep');
494                         $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
495                 }
496         }
497
498         if ($num_grp_sep == null)
499         {
500                 $num_grp_sep = $sugar_config['default_number_grouping_seperator'];
501                 if (!empty($current_user->id))
502                 {
503                         $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
504                         $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
505                 }
506         }
507
508         return array($num_grp_sep, $dec_sep);
509 }
510
511 /**
512  * toString
513  *
514  * Utility function to print out some information about Currency instance.
515  */
516 function toString($echo = true) {
517         $s = "\$m_currency_round=$m_currency_round \n" .
518          "\$m_currency_decimal=$m_currency_decimal \n" .
519          "\$m_currency_symbol=$m_currency_symbol \n" .
520          "\$m_currency_iso=$m_currency_iso \n" .
521          "\$m_currency_name=$m_currency_name \n";
522
523     if($echo) {
524        echo $s;
525     }
526
527     return $s;
528 }
529
530 function getCurrencyDropDown($focus, $field='currency_id', $value='', $view='DetailView'){
531     $view = ucfirst($view);
532         if($view == 'EditView' || $view == 'MassUpdate' || $view == 'QuickCreate'){
533         if ( isset($_REQUEST[$field]) && !empty($_REQUEST[$field]) ) {
534             $value = $_REQUEST[$field];
535             } elseif ( empty($focus->id) ) {
536             $value = $GLOBALS['current_user']->getPreference('currency');
537             if ( empty($value) ) {
538                 // -99 is the system default currency
539                 $value = -99;
540             }
541         }
542                 require_once('modules/Currencies/ListCurrency.php');
543                 $currency_fields = array();
544                 //Bug 18276 - Fix for php 5.1.6
545                 $defs=$focus->field_defs;
546                 //
547                 foreach($defs as $name=>$key){
548                         if($key['type'] == 'currency'){
549                                 $currency_fields[]= $name;
550                         }
551                 }
552                 $currency = new ListCurrency();
553         $selectCurrency = $currency->getSelectOptions($value);
554
555                 $currency->setCurrencyFields($currency_fields);
556                 $html = '<select name="'. $field. '" id="' . $field  . '_select" ';
557                 if($view != 'MassUpdate')
558                         $html .= 'onchange="CurrencyConvertAll(this.form);"';
559                 $html .= '>'. $selectCurrency . '</select>';
560                 if($view != 'MassUpdate')
561                         $html .= $currency->getJavascript();
562                 return $html;
563         }else{
564
565                 $currency = new Currency();
566                 $currency->retrieve($value);
567                 return $currency->name;
568         }
569
570 }
571
572 function getCurrencyNameDropDown($focus, $field='currency_name', $value='', $view='DetailView')
573 {
574     if($view == 'EditView' || $view == 'MassUpdate' || $view == 'QuickCreate'){
575                 require_once('modules/Currencies/ListCurrency.php');
576                 $currency_fields = array();
577                 //Bug 18276 - Fix for php 5.1.6
578                 $defs=$focus->field_defs;
579                 //
580                 foreach($defs as $name=>$key){
581                         if($key['type'] == 'currency'){
582                                 $currency_fields[]= $name;
583                         }
584                 }
585                 $currency = new ListCurrency();
586         $currency->lookupCurrencies();
587         $listitems = array();
588         foreach ( $currency->list as $item )
589             $listitems[$item->name] = $item->name;
590         return '<select name="'.$field.'" id="'.$field.'" />'.
591             get_select_options_with_id($listitems,$value).'</select>';
592         }else{
593
594                 $currency = new Currency();
595         if ( isset($focus->currency_id) ) {
596             $currency_id = $focus->currency_id;
597         } else {
598             $currency_id = -99;
599         }
600                 $currency->retrieve($currency_id);
601                 return $currency->name;
602         }
603 }
604
605 function getCurrencySymbolDropDown($focus, $field='currency_name', $value='', $view='DetailView')
606 {
607     if($view == 'EditView' || $view == 'MassUpdate' || $view == 'QuickCreate'){
608                 require_once('modules/Currencies/ListCurrency.php');
609                 $currency_fields = array();
610                 //Bug 18276 - Fix for php 5.1.6
611                 $defs=$focus->field_defs;
612                 //
613                 foreach($defs as $name=>$key){
614                         if($key['type'] == 'currency'){
615                                 $currency_fields[]= $name;
616                         }
617                 }
618                 $currency = new ListCurrency();
619         $currency->lookupCurrencies();
620         $listitems = array();
621         foreach ( $currency->list as $item )
622             $listitems[$item->symbol] = $item->symbol;
623         return '<select name="'.$field.'" id="'.$field.'" />'.
624             get_select_options_with_id($listitems,$value).'</select>';
625         }else{
626
627                 $currency = new Currency();
628         if ( isset($focus->currency_id) ) {
629             $currency_id = $focus->currency_id;
630         } else {
631             $currency_id = -99;
632         }
633                 $currency->retrieve($currency_id);
634                 return $currency->name;
635         }
636 }
637
638 ?>