Merge pull request #11900 from eileenmcnaughton/ref
[civicrm-core.git] / CRM / Utils / Money.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
8c9251b3 6 | Copyright CiviCRM LLC (c) 2004-2018 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
8c9251b3 31 * @copyright CiviCRM LLC (c) 2004-2018
6a488035
TO
32 */
33
34/**
35 * Money utilties
36 */
37class CRM_Utils_Money {
38 static $_currencySymbols = NULL;
39
40 /**
fe482240 41 * Format a monetary string.
6a488035
TO
42 *
43 * Format a monetary string basing on the amount provided,
44 * ISO currency code provided and a format string consisting of:
45 *
46 * %a - the formatted amount
47 * %C - the currency ISO code (e.g., 'USD') if provided
48 * %c - the currency symbol (e.g., '$') if available
49 *
77855840
TO
50 * @param float $amount
51 * The monetary amount to display (1234.56).
52 * @param string $currency
53 * The three-letter ISO currency code ('USD').
54 * @param string $format
55 * The desired currency format.
f4aaa82a 56 * @param bool $onlyNumber
77855840
TO
57 * @param string $valueFormat
58 * The desired monetary value display format (e.g. '%!i').
6a488035 59 *
a6c01b45
CW
60 * @return string
61 * formatted monetary string
6a488035 62 *
6a488035 63 */
00be9182 64 public static function format($amount, $currency = NULL, $format = NULL, $onlyNumber = FALSE, $valueFormat = NULL) {
6a488035
TO
65
66 if (CRM_Utils_System::isNull($amount)) {
67 return '';
68 }
69
70 $config = CRM_Core_Config::singleton();
71
72 if (!$format) {
73 $format = $config->moneyformat;
74 }
f4aaa82a 75
ec4da14d
DG
76 if (!$valueFormat) {
77 $valueFormat = $config->moneyvalueformat;
78 }
f4aaa82a 79
6a488035
TO
80 if ($onlyNumber) {
81 // money_format() exists only in certain PHP install (CRM-650)
82 if (is_numeric($amount) and function_exists('money_format')) {
ec4da14d 83 $amount = money_format($valueFormat, $amount);
6a488035
TO
84 }
85 return $amount;
86 }
87
88 if (!self::$_currencySymbols) {
353ffa53
TO
89 self::$_currencySymbols = CRM_Core_PseudoConstant::get('CRM_Contribute_DAO_Contribution', 'currency', array(
90 'keyColumn' => 'name',
7c550ca0 91 'labelColumn' => 'symbol',
353ffa53 92 ));
6a488035
TO
93 }
94
95 if (!$currency) {
96 $currency = $config->defaultCurrency;
97 }
98
6a488035
TO
99 // money_format() exists only in certain PHP install (CRM-650)
100 // setlocale() affects native gettext (CRM-11054, CRM-9976)
101 if (is_numeric($amount) && function_exists('money_format')) {
102 $lc = setlocale(LC_MONETARY, 0);
103 setlocale(LC_MONETARY, 'en_US.utf8', 'en_US', 'en_US.utf8', 'en_US', 'C');
ec4da14d 104 $amount = money_format($valueFormat, $amount);
6a488035
TO
105 setlocale(LC_MONETARY, $lc);
106 }
107
108 $rep = array(
109 ',' => $config->monetaryThousandSeparator,
110 '.' => $config->monetaryDecimalPoint,
111 );
112
113 // If it contains tags, means that HTML was passed and the
114 // amount is already converted properly,
115 // so don't mess with it again.
116 if (strpos($amount, '<') === FALSE) {
117 $amount = strtr($amount, $rep);
118 }
119
120 $replacements = array(
121 '%a' => $amount,
122 '%C' => $currency,
123 '%c' => CRM_Utils_Array::value($currency, self::$_currencySymbols, $currency),
124 );
125 return strtr($format, $replacements);
126 }
96025800 127
31f5f5e4
ML
128 /**
129 * This is a placeholder function for calculating the number of decimal places for a currency.
130 *
131 * Currently code assumes 2 decimal places but some currencies (bitcoin, middle eastern) have
132 * more. By using this function we can signpost the locations where the number of decimal places is
133 * currency specific for future enhancement.
134 *
135 * @param string $currency
136 *
137 * @return int
138 * Number of decimal places.
139 */
140 public static function getCurrencyPrecision($currency = NULL) {
141 return 2;
142 }
143
c10c4749
EL
144 /**
145 * Subtract currencies using integers instead of floats, to preserve precision
146 *
147 * @return float
148 * Result of subtracting $rightOp from $leftOp to the precision of $currency
149 */
150 public static function subtractCurrencies($leftOp, $rightOp, $currency) {
151 if (is_numeric($leftOp) && is_numeric($rightOp)) {
152 $precision = pow(10, self::getCurrencyPrecision($currency));
153 return (($leftOp * $precision) - ($rightOp * $precision)) / $precision;
154 }
155 }
156
6a488035 157}