dolibarr 23.0.3
functionsnumtoword.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2015 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2015 Víctor Ortiz Pérez <victor@accett.com.mx>
4 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
5 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 * or see https://www.gnu.org/
20 */
21
38function dol_convertToWord($num, $langs, $currency = '', $centimes = false)
39{
40 //$num = str_replace(array(',', ' '), '', trim($num)); This should be useless since $num MUST be a php numeric value
41 if (!$num) {
42 return false;
43 }
44
45 if ($centimes && strlen((string) $num) == 1) {
46 $num *= 10;
47 }
48
49 if (isModEnabled('numberwords')) {
50 $concatWords = $langs->getLabelFromNumber((string) $num, $currency);
51 return $concatWords;
52 } else {
53 $TNum = explode('.', (string) $num);
54
55 $num = abs((int) $TNum[0]);
56 $words = array();
57 $list1 = array(
58 '',
59 $langs->transnoentitiesnoconv('one'),
60 $langs->transnoentitiesnoconv('two'),
61 $langs->transnoentitiesnoconv('three'),
62 $langs->transnoentitiesnoconv('four'),
63 $langs->transnoentitiesnoconv('five'),
64 $langs->transnoentitiesnoconv('six'),
65 $langs->transnoentitiesnoconv('seven'),
66 $langs->transnoentitiesnoconv('eight'),
67 $langs->transnoentitiesnoconv('nine'),
68 $langs->transnoentitiesnoconv('ten'),
69 $langs->transnoentitiesnoconv('eleven'),
70 $langs->transnoentitiesnoconv('twelve'),
71 $langs->transnoentitiesnoconv('thirteen'),
72 $langs->transnoentitiesnoconv('fourteen'),
73 $langs->transnoentitiesnoconv('fifteen'),
74 $langs->transnoentitiesnoconv('sixteen'),
75 $langs->transnoentitiesnoconv('seventeen'),
76 $langs->transnoentitiesnoconv('eighteen'),
77 $langs->transnoentitiesnoconv('nineteen')
78 );
79 $list2 = array(
80 '',
81 $langs->transnoentitiesnoconv('ten'),
82 $langs->transnoentitiesnoconv('twenty'),
83 $langs->transnoentitiesnoconv('thirty'),
84 $langs->transnoentitiesnoconv('forty'),
85 $langs->transnoentitiesnoconv('fifty'),
86 $langs->transnoentitiesnoconv('sixty'),
87 $langs->transnoentitiesnoconv('seventy'),
88 $langs->transnoentitiesnoconv('eighty'),
89 $langs->transnoentitiesnoconv('ninety'),
90 $langs->transnoentitiesnoconv('hundred')
91 );
92 $list3 = array(
93 '',
94 $langs->transnoentitiesnoconv('thousand'),
95 $langs->transnoentitiesnoconv('million'),
96 $langs->transnoentitiesnoconv('billion'),
97 $langs->transnoentitiesnoconv('trillion'),
98 $langs->transnoentitiesnoconv('quadrillion')
99 );
100
101 $num_length = strlen((string) $num);
102 $levels = (int) (($num_length + 2) / 3);
103 $max_length = $levels * 3;
104 $num = substr('00'.$num, -$max_length);
105 $num_levels = str_split($num, 3);
106 $nboflevels = count($num_levels);
107 for ($i = 0; $i < $nboflevels; $i++) {
108 $levels--;
109 $hundreds = (int) ((int) $num_levels[$i] / 100);
110 $hundreds = ($hundreds ? ' '.$list1[$hundreds].' '.$langs->transnoentities('hundred').($hundreds == 1 ? '' : 's').' ' : '');
111 $tens = (int) ((int) $num_levels[$i] % 100);
112 $singles = '';
113 if ($tens < 20) {
114 $tens = ($tens ? ' '.$list1[$tens].' ' : '');
115 } else {
116 $tsd = (int) ($tens / 10); // tens digit (2-9)
117 $usd = (int) ($tens % 10); // units digit (0-9)
118
119 // French-style systems: 70-79 = sixty + (10-19), 90-99 = eighty + (10-19)
120 // Detection: if the translation of "seventy"/"ninety" contains the word for "ten"
121 $tenWord = trim($list1[10]); // e.g. "dix"
122 if ($usd > 0 && ($tsd == 7 || $tsd == 9) && $tenWord !== '' && strpos(trim($list2[$tsd]), $tenWord) !== false) {
123 // Use the base ten word (60 for 70s, 80 for 90s) + teen word (11-19)
124 $baseWord = trim($list2[$tsd - 1]);
125 // Remove trailing 's' (e.g. quatre-vingts → quatre-vingt when used in composition)
126 if (substr($baseWord, -1) === 's') {
127 $baseWord = substr($baseWord, 0, -1);
128 }
129 $tens = ' '.$baseWord.' ';
130 $singles = ' '.$list1[10 + $usd].' ';
131 } else {
132 $tens = ' '.$list2[$tsd].' ';
133 $singles = ' '.$list1[$usd].' ';
134 }
135 }
136 $words[] = $hundreds.$tens.$singles.(($levels && (int) ($num_levels[$i])) ? ' '.$list3[$levels].' ' : '');
137 } //end for loop
138 $commas = count($words);
139 if ($commas > 1) {
140 $commas -= 1;
141 }
142 $concatWords = implode(' ', $words);
143 // Delete multi whitespaces
144 $concatWords = trim(preg_replace('/[ ]+/', ' ', $concatWords));
145
146 if (!empty($currency)) {
147 $concatWords .= ' '.$currency;
148 }
149
150 // If we need to write cents call again this function for cents
151 $decimalpart = empty($TNum[1]) ? '' : preg_replace('/0+$/', '', $TNum[1]);
152
153 if ($decimalpart) {
154 if (!empty($currency)) {
155 $concatWords .= ' '.$langs->transnoentities('and');
156 }
157
158 $concatWords .= ' '.dol_convertToWord((float) $decimalpart, $langs, '', true);
159 if (!empty($currency)) {
160 $concatWords .= ' '.$langs->transnoentities('centimes');
161 }
162 }
163 return $concatWords;
164 }
165}
166
167
178function dolNumberToWord($numero, $langs, $numorcurrency = 'number')
179{
180 // If the number is negative convert to positive and return -1 if it is too long
181 if ($numero < 0) {
182 $numero *= -1;
183 }
184 if ($numero >= 1000000000001) {
185 return -1;
186 }
187
188 // Get 2 decimals to cents, another functions round or truncate
189 $strnumber = number_format($numero, 10);
190 $len = strlen($strnumber);
191 $parte_decimal = '00'; // For static analysis, strnumber should contain '.'
192 for ($i = 0; $i < $len; $i++) {
193 if ($strnumber[$i] == '.') {
194 $parte_decimal = $strnumber[$i + 1].$strnumber[$i + 2];
195 break;
196 }
197 }
198
199 /* Dolibarr 3.6.2 doesn't have $langs->default, why ask $lang like a parameter in case it exists? */
200 if (((is_object($langs) && $langs->getDefaultLang(0) == 'es_MX') || (!is_object($langs) && $langs == 'es_MX')) && $numorcurrency == 'currency') {
201 if ($numero >= 1 && $numero < 2) {
202 return ("UN PESO ".$parte_decimal." / 100 M.N.");
203 } elseif ($numero >= 0 && $numero < 1) {
204 return ("CERO PESOS ".$parte_decimal." / 100 M.N.");
205 } elseif ($numero >= 1000000 && $numero < 1000001) {
206 return ("UN MILL&OacuteN DE PESOS ".$parte_decimal." / 100 M.N.");
207 } elseif ($numero >= 1000000000000 && $numero < 1000000000001) {
208 return ("UN BILL&OacuteN DE PESOS ".$parte_decimal." / 100 M.N.");
209 } else {
210 $entexto = "";
211 $number = $numero;
212 if ($number >= 1000000000) {
213 $CdMMillon = (int) ($numero / 100000000000);
214 $numero -= $CdMMillon * 100000000000;
215 $DdMMillon = (int) ($numero / 10000000000);
216 $numero -= $DdMMillon * 10000000000;
217 $UdMMillon = (int) ($numero / 1000000000);
218 $numero -= $UdMMillon * 1000000000;
219 $entexto .= hundreds2text($CdMMillon, $DdMMillon, $UdMMillon);
220 $entexto .= " MIL ";
221 } else {
222 $CdMMillon = 0;
223 $DdMMillon = 0;
224 $UdMMillon = 0;
225 }
226 if ($number >= 1000000) {
227 $CdMILLON = (int) ($numero / 100000000);
228 $numero -= $CdMILLON * 100000000;
229 $DdMILLON = (int) ($numero / 10000000);
230 $numero -= $DdMILLON * 10000000;
231 $udMILLON = (int) ($numero / 1000000);
232 $numero -= $udMILLON * 1000000;
233 $entexto .= hundreds2text($CdMILLON, $DdMILLON, $udMILLON);
234 if (!$CdMMillon && !$DdMMillon && !$UdMMillon && !$CdMILLON && !$DdMILLON && $udMILLON == 1) {
235 $entexto .= " MILL&OacuteN ";
236 } else {
237 $entexto .= " MILLONES ";
238 }
239 }
240
241 if ($number >= 1000) {
242 $cdm = (int) ($numero / 100000);
243 $numero -= $cdm * 100000;
244 $ddm = (int) ($numero / 10000);
245 $numero -= $ddm * 10000;
246 $udm = (int) ($numero / 1000);
247 $numero -= $udm * 1000;
248 $entexto .= hundreds2text($cdm, $ddm, $udm);
249 if ($cdm || $ddm || $udm) {
250 $entexto .= " MIL ";
251 }
252 } else {
253 $ddm = 0;
254 $cdm = 0;
255 $udm = 0;
256 }
257 $c = (int) ($numero / 100);
258 $numero -= $c * 100;
259 $d = (int) ($numero / 10);
260 $u = (int) $numero - $d * 10;
261 $entexto .= hundreds2text($c, $d, $u);
262 if (!$cdm && !$ddm && !$udm && !$c && !$d && !$u && $number > 1000000) {
263 $entexto .= " DE";
264 }
265 $entexto .= " PESOS ".$parte_decimal." / 100 M.N.";
266 }
267 return $entexto;
268 }
269 return -1;
270}
271
280function hundreds2text($hundreds, $tens, $units)
281{
282 if ($hundreds == 1 && $tens == 0 && $units == 0) {
283 return "CIEN";
284 }
285 $centenas = array("CIENTO", "DOSCIENTOS", "TRESCIENTOS", "CUATROCIENTOS", "QUINIENTOS", "SEISCIENTOS", "SETECIENTOS", "OCHOCIENTOS", "NOVECIENTOS");
286 $decenas = array("", "", "TREINTA ", "CUARENTA ", "CINCUENTA ", "SESENTA ", "SETENTA ", "OCHENTA ", "NOVENTA ");
287 $veintis = array("VEINTE", "VEINTIUN", "VEINTID&OacuteS", "VEINTITR&EacuteS", "VEINTICUATRO", "VEINTICINCO", "VEINTIS&EacuteIS", "VEINTISIETE", "VEINTIOCHO", "VEINTINUEVE");
288 $diecis = array("DIEZ", "ONCE", "DOCE", "TRECE", "CATORCE", "QUINCE", "DIECIS&EacuteIS", "DIECISIETE", "DIECIOCHO", "DIECINUEVE");
289 $unidades = array("UN", "DOS", "TRES", "CUATRO", "CINCO", "SEIS", "SIETE", "OCHO", "NUEVE");
290 $entexto = "";
291 if ($hundreds != 0) {
292 $entexto .= $centenas[$hundreds - 1];
293 }
294 if ($tens > 2) {
295 if ($hundreds != 0) {
296 $entexto .= " ";
297 }
298 $entexto .= $decenas[$tens - 1];
299 if ($units != 0) {
300 $entexto .= " Y ";
301 $entexto .= $unidades[$units - 1];
302 }
303 return $entexto;
304 } elseif ($tens == 2) {
305 if ($hundreds != 0) {
306 $entexto .= " ";
307 }
308 $entexto .= " ".$veintis[$units];
309 return $entexto;
310 } elseif ($tens == 1) {
311 if ($hundreds != 0) {
312 $entexto .= " ";
313 }
314 $entexto .= $diecis[$units];
315 return $entexto;
316 }
317 if ($units != 0) {
318 if ($hundreds != 0 || $tens != 0) {
319 $entexto .= " ";
320 }
321 $entexto .= $unidades[$units - 1];
322 }
323 return $entexto;
324}
$c
Definition line.php:331
isModEnabled($module)
Is Dolibarr module enabled.
dol_convertToWord($num, $langs, $currency='', $centimes=false)
Function to return a number into a text.
hundreds2text($hundreds, $tens, $units)
hundreds2text
dolNumberToWord($numero, $langs, $numorcurrency='number')
Function to return number or amount in text.