Passed
Push — EXTRACT_CLASSES ( 231cec...0382f2 )
by Rafael
65:54 queued 05:18
created

Setup::getListOfTowns()   B

Complexity

Conditions 10
Paths 76

Size

Total Lines 47
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 28
nc 76
nop 8
dl 0
loc 47
rs 7.6666
c 0
b 0
f 0

How to fix   Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/* Copyright (C) 2016       Xebax Christy               <[email protected]>
4
 * Copyright (C) 2016	    Laurent Destailleur		    <[email protected]>
5
 * Copyright (C) 2017	    Regis Houssin	            <[email protected]>
6
 * Copyright (C) 2017	    Neil Orley	                <[email protected]>
7
 * Copyright (C) 2018-2021  Frédéric France             <[email protected]>
8
 * Copyright (C) 2018-2022  Thibault FOUCART            <[email protected]>
9
 * Copyright (C) 2024       Jon Bendtsen                <[email protected]>
10
 * Copyright (C) 2024       Rafael San José             <[email protected]>
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 3 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
24
 */
25
26
namespace Dolibarr\Code\Api\Api;
27
28
use Luracast\Restler\RestException;
29
30
require_once constant('DOL_DOCUMENT_ROOT') . '/main.inc.php';
31
require_once constant('DOL_DOCUMENT_ROOT') . '/api/class/api.class.php';
32
require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/cstate.class.php';
33
require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/cregion.class.php';
34
require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/ccountry.class.php';
35
require_once constant('DOL_DOCUMENT_ROOT') . '/hrm/class/establishment.class.php';
36
37
/**
38
 * API class for dictionaries
39
 *
40
 * @access protected
41
 * @class DolibarrApiAccess {@requires user,external}
42
 */
43
class Setup extends DolibarrApi
44
{
45
    private $translations = null;
46
47
    /**
48
     * Constructor
49
     */
50
    public function __construct()
51
    {
52
        global $db;
53
        $this->db = $db;
54
    }
55
56
    /**
57
     * Get the list of ordering methods.
58
     *
59
     * @param string    $sortfield  Sort field
60
     * @param string    $sortorder  Sort order
61
     * @param int       $limit      Number of items per page
62
     * @param int       $page       Page number {@min 0}
63
     * @param int       $active     Payment type is active or not {@min 0} {@max 1}
64
     * @param string    $sqlfilters SQL criteria to filter with. Syntax example "(t.code:=:'OrderByWWW')"
65
     *
66
     * @url     GET dictionary/ordering_methods
67
     *
68
     * @return array [List of ordering methods]
69
     *
70
     * @throws  RestException   400     Bad value for sqlfilters
71
     * @throws  RestException   403     Access denied
72
     * @throws  RestException   503     Error retrieving list of ordering methods
73
     */
74
    public function getOrderingMethods($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
75
    {
76
        $list = array();
77
78
        if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
79
            throw new RestException(403);
80
        }
81
82
        $sql = "SELECT rowid, code, libelle as label, module";
83
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_input_method as t";
84
        $sql .= " WHERE t.active = " . ((int) $active);
85
        // Add sql filters
86
        if ($sqlfilters) {
87
            $errormessage = '';
88
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
89
            if ($errormessage) {
90
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
91
            }
92
        }
93
94
95
        $sql .= $this->db->order($sortfield, $sortorder);
96
97
        if ($limit) {
98
            if ($page < 0) {
99
                $page = 0;
100
            }
101
            $offset = $limit * $page;
102
103
            $sql .= $this->db->plimit($limit, $offset);
104
        }
105
106
        $result = $this->db->query($sql);
107
108
        if ($result) {
109
            $num = $this->db->num_rows($result);
110
            $min = min($num, ($limit <= 0 ? $num : $limit));
111
            for ($i = 0; $i < $min; $i++) {
112
                $list[] = $this->db->fetch_object($result);
113
            }
114
        } else {
115
            throw new RestException(503, $this->db->lasterror());
116
        }
117
118
        return $list;
119
    }
120
121
    /**
122
     * Get the list of ordering origins.
123
     *
124
     * @param string    $sortfield  Sort field
125
     * @param string    $sortorder  Sort order
126
     * @param int       $limit      Number of items per page
127
     * @param int       $page       Page number {@min 0}
128
     * @param int       $active     Payment type is active or not {@min 0} {@max 1}
129
     * @param string    $sqlfilters SQL criteria to filter with. Syntax example "(t.code:=:'OrderByWWW')"
130
     * @return array [List of ordering reasons]
131
     *
132
     * @url     GET dictionary/ordering_origins
133
     *
134
     * @throws  RestException   400     Bad value for sqlfilters
135
     * @throws  RestException   403     Access denied
136
     * @throws  RestException   503     Error retrieving list of ordering origins
137
     */
138
    public function getOrderingOrigins($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
139
    {
140
        $list = array();
141
142
        if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
143
            throw new RestException(403);
144
        }
145
146
        $sql = "SELECT rowid, code, label, module";
147
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_input_reason as t";
148
        $sql .= " WHERE t.active = " . ((int) $active);
149
        // Add sql filters
150
        if ($sqlfilters) {
151
            $errormessage = '';
152
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
153
            if ($errormessage) {
154
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
155
            }
156
        }
157
158
159
        $sql .= $this->db->order($sortfield, $sortorder);
160
161
        if ($limit) {
162
            if ($page < 0) {
163
                $page = 0;
164
            }
165
            $offset = $limit * $page;
166
167
            $sql .= $this->db->plimit($limit, $offset);
168
        }
169
170
        $result = $this->db->query($sql);
171
172
        if ($result) {
173
            $num = $this->db->num_rows($result);
174
            $min = min($num, ($limit <= 0 ? $num : $limit));
175
            for ($i = 0; $i < $min; $i++) {
176
                $list[] = $this->db->fetch_object($result);
177
            }
178
        } else {
179
            throw new RestException(503, $this->db->lasterror());
180
        }
181
182
        return $list;
183
    }
184
185
    /**
186
     * Get the list of payments types.
187
     *
188
     * @param string    $sortfield  Sort field
189
     * @param string    $sortorder  Sort order
190
     * @param int       $limit      Number of items per page
191
     * @param int       $page       Page number {@min 0}
192
     * @param int       $active     Payment type is active or not {@min 0} {@max 1}
193
     * @param string    $sqlfilters SQL criteria to filter with. Syntax example "(t.code:=:'CHQ')"
194
     *
195
     * @url     GET dictionary/payment_types
196
     *
197
     * @return array [List of payment types]
198
     *
199
     * @throws  RestException   400     Bad value for sqlfilters
200
     * @throws  RestException   403     Access denied
201
     * @throws  RestException   503     Error retrieving list of payment types
202
     */
203
    public function getPaymentTypes($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
204
    {
205
        $list = array();
206
207
        if (!DolibarrApiAccess::$user->hasRight('propal', 'lire') && !DolibarrApiAccess::$user->hasRight('commande', 'lire') && !DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
208
            throw new RestException(403);
209
        }
210
211
        $sql = "SELECT id, code, type, libelle as label, module";
212
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_paiement as t";
213
        $sql .= " WHERE t.entity IN (" . getEntity('c_paiement') . ")";
214
        $sql .= " AND t.active = " . ((int) $active);
215
        // Add sql filters
216
        if ($sqlfilters) {
217
            $errormessage = '';
218
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
219
            if ($errormessage) {
220
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
221
            }
222
        }
223
224
225
        $sql .= $this->db->order($sortfield, $sortorder);
226
227
        if ($limit) {
228
            if ($page < 0) {
229
                $page = 0;
230
            }
231
            $offset = $limit * $page;
232
233
            $sql .= $this->db->plimit($limit, $offset);
234
        }
235
236
        $result = $this->db->query($sql);
237
238
        if ($result) {
239
            $num = $this->db->num_rows($result);
240
            $min = min($num, ($limit <= 0 ? $num : $limit));
241
            for ($i = 0; $i < $min; $i++) {
242
                $list[] = $this->db->fetch_object($result);
243
            }
244
        } else {
245
            throw new RestException(503, $this->db->lasterror());
246
        }
247
248
        return $list;
249
    }
250
    /**
251
     * Get the list of regions.
252
     *
253
     * The returned list is sorted by region ID.
254
     *
255
     * @param string    $sortfield  Sort field
256
     * @param string    $sortorder  Sort order
257
     * @param int       $limit      Number of items per page
258
     * @param int       $page       Page number (starting from zero)
259
     * @param int       $country    To filter on country
260
     * @param string    $filter     To filter the regions by name
261
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
262
     * @return array                List of regions
263
     *
264
     * @url     GET dictionary/regions
265
     *
266
     * @throws  RestException   400     Bad value for sqlfilters
267
     * @throws  RestException   503     Error retrieving list of regions
268
     */
269
    public function getListOfRegions($sortfield = "code_region", $sortorder = 'ASC', $limit = 100, $page = 0, $country = 0, $filter = '', $sqlfilters = '')
270
    {
271
        $list = array();
272
273
        // Note: The filter is not applied in the SQL request because it must
274
        // be applied to the translated names, not to the names in database.
275
        $sql = "SELECT t.rowid FROM " . MAIN_DB_PREFIX . "c_regions as t";
276
        $sql .= " WHERE 1 = 1";
277
        if ($country) {
278
            $sql .= " AND t.fk_pays = " . ((int) $country);
279
        }
280
        // Add sql filters
281
        if ($sqlfilters) {
282
            $errormessage = '';
283
            if (!DolibarrApi::_checkFilters($sqlfilters, $errormessage)) {
284
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
285
            }
286
            $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
287
            $sql .= " AND (" . preg_replace_callback('/' . $regexstring . '/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters) . ")";
288
        }
289
290
        $sql .= $this->db->order($sortfield, $sortorder);
291
292
        if ($limit) {
293
            if ($page < 0) {
294
                $page = 0;
295
            }
296
            $offset = $limit * $page;
297
298
            $sql .= $this->db->plimit($limit, $offset);
299
        }
300
301
        $result = $this->db->query($sql);
302
303
        if ($result) {
304
            $num = $this->db->num_rows($result);
305
            $min = min($num, ($limit <= 0 ? $num : $limit));
306
            for ($i = 0; $i < $min; $i++) {
307
                $obj = $this->db->fetch_object($result);
308
                $region = new Cregion($this->db);
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Api\Api\Cregion was not found. Did you mean Cregion? If so, make sure to prefix the type with \.
Loading history...
309
                if ($region->fetch($obj->rowid) > 0) {
310
                    if (empty($filter) || stripos($region->name, $filter) !== false) {
311
                        $list[] = $this->_cleanObjectDatas($region);
312
                    }
313
                }
314
            }
315
        } else {
316
            throw new RestException(503, 'Error when retrieving list of regions');
317
        }
318
319
        return $list;
320
    }
321
322
    /**
323
     * Get region by ID.
324
     *
325
     * @param   int       $id       ID of region
326
     * @return  Object              Object with cleaned properties
327
     *
328
     * @url     GET dictionary/regions/{id}
329
     *
330
     * @throws  RestException   404     Region not found
331
     * @throws  RestException   503     Error retrieving region
332
     */
333
    public function getRegionByID($id)
334
    {
335
        return $this->_fetchCregion($id, '');
336
    }
337
338
    /**
339
     * Get region by Code.
340
     *
341
     * @param   string    $code     Code of region
342
     * @return  Object              Object with cleaned properties
343
     *
344
     * @url     GET dictionary/regions/byCode/{code}
345
     *
346
     * @throws  RestException   404     Region not found
347
     * @throws  RestException   503     Error when retrieving region
348
     */
349
    public function getRegionByCode($code)
350
    {
351
        return $this->_fetchCregion('', $code);
352
    }
353
354
    /**
355
     * Get the list of states/provinces.
356
     *
357
     * The names of the states will be translated to the given language if
358
     * the $lang parameter is provided. The value of $lang must be a language
359
     * code supported by Dolibarr, for example 'en_US' or 'fr_FR'.
360
     * The returned list is sorted by state ID.
361
     *
362
     * @param string    $sortfield  Sort field
363
     * @param string    $sortorder  Sort order
364
     * @param int       $limit      Number of items per page
365
     * @param int       $page       Page number (starting from zero)
366
     * @param int       $country    To filter on country
367
     * @param string    $filter     To filter the states by name
368
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
369
     * @return array                List of states
370
     *
371
     * @url     GET dictionary/states
372
     *
373
     * @throws  RestException   400     Bad value for sqlfilters
374
     * @throws  RestException   503     Error retrieving list of states
375
     */
376
    public function getListOfStates($sortfield = "code_departement", $sortorder = 'ASC', $limit = 100, $page = 0, $country = 0, $filter = '', $sqlfilters = '')
377
    {
378
        $list = array();
379
380
        // Note: The filter is not applied in the SQL request because it must
381
        // be applied to the translated names, not to the names in database.
382
        $sql = "SELECT t.rowid FROM " . MAIN_DB_PREFIX . "c_departements as t";
383
        if ($country) {
384
            $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_regions as d ON t.fk_region = d.code_region";
385
        }
386
        $sql .= " WHERE 1 = 1";
387
        if ($country) {
388
            $sql .= " AND d.fk_pays = " . ((int) $country);
389
        }
390
        // Add sql filters
391
        if ($sqlfilters) {
392
            $errormessage = '';
393
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
394
            if ($errormessage) {
395
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
396
            }
397
        }
398
399
        $sql .= $this->db->order($sortfield, $sortorder);
400
401
        if ($limit) {
402
            if ($page < 0) {
403
                $page = 0;
404
            }
405
            $offset = $limit * $page;
406
407
            $sql .= $this->db->plimit($limit, $offset);
408
        }
409
410
        $result = $this->db->query($sql);
411
412
        if ($result) {
413
            $num = $this->db->num_rows($result);
414
            $min = min($num, ($limit <= 0 ? $num : $limit));
415
            for ($i = 0; $i < $min; $i++) {
416
                $obj = $this->db->fetch_object($result);
417
                $state = new Cstate($this->db);
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Api\Api\Cstate was not found. Did you mean Cstate? If so, make sure to prefix the type with \.
Loading history...
418
                if ($state->fetch($obj->rowid) > 0) {
419
                    if (empty($filter) || stripos($state->label, $filter) !== false) {
420
                        $list[] = $this->_cleanObjectDatas($state);
421
                    }
422
                }
423
            }
424
        } else {
425
            throw new RestException(503, 'Error when retrieving list of states');
426
        }
427
428
        return $list;
429
    }
430
431
    /**
432
     * Get state by ID.
433
     *
434
     * @param   int       $id           ID of state
435
     * @return  Object                  Object with cleaned properties
436
     *
437
     * @url     GET dictionary/states/{id}
438
     *
439
     * @throws  RestException   404     State not found
440
     * @throws  RestException   503     Error retrieving state
441
     */
442
    public function getStateByID($id)
443
    {
444
        return $this->_fetchCstate($id, '');
445
    }
446
447
    /**
448
     * Get state by Code.
449
     *
450
     * @param   string    $code         Code of state
451
     * @return  Object                  Object with cleaned properties
452
     *
453
     * @url     GET dictionary/states/byCode/{code}
454
     *
455
     * @throws  RestException   404     State not found
456
     * @throws  RestException   503     Error retrieving state
457
     */
458
    public function getStateByCode($code)
459
    {
460
        return $this->_fetchCstate('', $code);
461
    }
462
463
    /**
464
     * Get the list of countries.
465
     *
466
     * The names of the countries will be translated to the given language if
467
     * the $lang parameter is provided. The value of $lang must be a language
468
     * code supported by Dolibarr, for example 'en_US' or 'fr_FR'.
469
     * The returned list is sorted by country ID.
470
     *
471
     * @param string    $sortfield  Sort field
472
     * @param string    $sortorder  Sort order
473
     * @param int       $limit      Number of items per page
474
     * @param int       $page       Page number (starting from zero)
475
     * @param string    $filter     To filter the countries by name
476
     * @param string    $lang       Code of the language the label of the countries must be translated to
477
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
478
     * @return array                List of countries
479
     *
480
     * @url     GET dictionary/countries
481
     *
482
     * @throws  RestException   400     Bad value for sqlfilters
483
     * @throws  RestException   503     Error retrieving list of countries
484
     */
485
    public function getListOfCountries($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $filter = '', $lang = '', $sqlfilters = '')
486
    {
487
        $list = array();
488
489
        // Note: The filter is not applied in the SQL request because it must
490
        // be applied to the translated names, not to the names in database.
491
        $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "c_country as t";
492
        $sql .= " WHERE 1 = 1";
493
        // Add sql filters
494
        if ($sqlfilters) {
495
            $errormessage = '';
496
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
497
            if ($errormessage) {
498
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
499
            }
500
        }
501
502
        $sql .= $this->db->order($sortfield, $sortorder);
503
504
        if ($limit) {
505
            if ($page < 0) {
506
                $page = 0;
507
            }
508
            $offset = $limit * $page;
509
510
            $sql .= $this->db->plimit($limit, $offset);
511
        }
512
513
        $result = $this->db->query($sql);
514
515
        if ($result) {
516
            $num = $this->db->num_rows($result);
517
            $min = min($num, ($limit <= 0 ? $num : $limit));
518
            for ($i = 0; $i < $min; $i++) {
519
                $obj = $this->db->fetch_object($result);
520
                $country = new Ccountry($this->db);
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Api\Api\Ccountry was not found. Did you mean Ccountry? If so, make sure to prefix the type with \.
Loading history...
521
                if ($country->fetch($obj->rowid) > 0) {
522
                    // Translate the name of the country if needed
523
                    // and then apply the filter if there is one.
524
                    $this->translateLabel($country, $lang, 'Country');
525
526
                    if (empty($filter) || stripos($country->label, $filter) !== false) {
527
                        $list[] = $this->_cleanObjectDatas($country);
528
                    }
529
                }
530
            }
531
        } else {
532
            throw new RestException(503, 'Error when retrieving list of countries');
533
        }
534
535
        return $list;
536
    }
537
538
    /**
539
     * Get country by ID.
540
     *
541
     * @param   int       $id           ID of country
542
     * @param   string    $lang         Code of the language the name of the country must be translated to
543
     * @return  Object                  Object with cleaned properties
544
     *
545
     * @url     GET dictionary/countries/{id}
546
     *
547
     * @throws  RestException   404     Country not found
548
     * @throws  RestException   503     Error retrieving country
549
     */
550
    public function getCountryByID($id, $lang = '')
551
    {
552
        return $this->_fetchCcountry($id, '', '', $lang);
553
    }
554
555
    /**
556
     * Get country by Code.
557
     *
558
     * @param   string    $code         Code of country (2 characters)
559
     * @param   string    $lang         Code of the language the name of the country must be translated to
560
     * @return  Object                  Object with cleaned properties
561
     *
562
     * @url     GET dictionary/countries/byCode/{code}
563
     *
564
     * @throws  RestException   404     Country not found
565
     * @throws  RestException   503     Error retrieving country
566
     */
567
    public function getCountryByCode($code, $lang = '')
568
    {
569
        return $this->_fetchCcountry('', $code, '', $lang);
570
    }
571
572
    /**
573
     * Get country by Iso.
574
     *
575
     * @param   string    $iso          ISO of country (3 characters)
576
     * @param   string    $lang         Code of the language the name of the country must be translated to
577
     * @return  Object                  Object with cleaned properties
578
     *
579
     * @url     GET dictionary/countries/byISO/{iso}
580
     *
581
     * @throws  RestException   404     Country not found
582
     * @throws  RestException   503     Error retrieving country
583
     */
584
    public function getCountryByISO($iso, $lang = '')
585
    {
586
        return $this->_fetchCcountry('', '', $iso, $lang);
587
    }
588
589
    /**
590
     * Get region.
591
     *
592
     * @param   int       $id       ID of region
593
     * @param   string    $code     Code of region
594
     * @return  Object              Object with cleaned properties
595
     *
596
     * @throws RestException
597
     */
598
    private function _fetchCregion($id, $code = '')
599
    {
600
        $region = new Cregion($this->db);
601
602
        $result = $region->fetch($id, $code);
603
        if ($result < 0) {
604
            throw new RestException(503, 'Error when retrieving region : ' . $region->error);
605
        } elseif ($result == 0) {
606
            throw new RestException(404, 'Region not found');
607
        }
608
609
        return $this->_cleanObjectDatas($region);
610
    }
611
612
    /**
613
     * Get state.
614
     *
615
     * @param   int       $id           ID of state
616
     * @param   string    $code         Code of state
617
     * @return  Object                  Object with cleaned properties
618
     *
619
     * @throws RestException
620
     */
621
    private function _fetchCstate($id, $code = '')
622
    {
623
        $state = new Cstate($this->db);
624
625
        $result = $state->fetch($id, $code);
626
        if ($result < 0) {
627
            throw new RestException(503, 'Error when retrieving state : ' . $state->error);
628
        } elseif ($result == 0) {
629
            throw new RestException(404, 'State not found');
630
        }
631
632
        return $this->_cleanObjectDatas($state);
633
    }
634
635
    /**
636
     * Get country.
637
     *
638
     * @param   int       $id           ID of country
639
     * @param   string    $code         Code of country (2 characters)
640
     * @param   string    $iso          ISO of country (3 characters)
641
     * @param   string    $lang         Code of the language the name of the country must be translated to
642
     * @return  Object                  Object with cleaned properties
643
     *
644
     * @throws RestException
645
     */
646
    private function _fetchCcountry($id, $code = '', $iso = '', $lang = '')
647
    {
648
        $country = new Ccountry($this->db);
649
650
        $result = $country->fetch($id, $code, $iso);
651
652
        if ($result < 0) {
653
            throw new RestException(503, 'Error when retrieving country : ' . $country->error);
654
        } elseif ($result == 0) {
655
            throw new RestException(404, 'Country not found');
656
        }
657
658
        $this->translateLabel($country, $lang, 'Country');
659
660
        return $this->_cleanObjectDatas($country);
661
    }
662
663
    /**
664
     * Get the list of delivery times.
665
     *
666
     * @param string    $sortfield      Sort field
667
     * @param string    $sortorder      Sort order
668
     * @param int       $limit          Number of items per page
669
     * @param int       $page           Page number {@min 0}
670
     * @param int       $active         Delivery times is active or not {@min 0} {@max 1}
671
     * @param string    $sqlfilters     SQL criteria to filter with.
672
     *
673
     * @url     GET dictionary/availability
674
     *
675
     * @return array [List of availability]
676
     *
677
     * @throws  RestException   400     Bad value for sqlfilters
678
     * @throws  RestException   403     Access denied
679
     * @throws  RestException   503     Error when retrieving list of availabilities
680
     */
681
    public function getAvailability($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
682
    {
683
        $list = array();
684
685
        if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
686
            throw new RestException(403);
687
        }
688
689
        $sql = "SELECT rowid, code, label";
690
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_availability as t";
691
        $sql .= " WHERE t.active = " . ((int) $active);
692
        // Add sql filters
693
        if ($sqlfilters) {
694
            $errormessage = '';
695
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
696
            if ($errormessage) {
697
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
698
            }
699
        }
700
701
702
        $sql .= $this->db->order($sortfield, $sortorder);
703
704
        if ($limit) {
705
            if ($page < 0) {
706
                $page = 0;
707
            }
708
            $offset = $limit * $page;
709
710
            $sql .= $this->db->plimit($limit, $offset);
711
        }
712
713
        $result = $this->db->query($sql);
714
715
        if ($result) {
716
            $num = $this->db->num_rows($result);
717
            $min = min($num, ($limit <= 0 ? $num : $limit));
718
            for ($i = 0; $i < $min; $i++) {
719
                $list[] = $this->db->fetch_object($result);
720
            }
721
        } else {
722
            throw new RestException(503, $this->db->lasterror());
723
        }
724
725
        return $list;
726
    }
727
728
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
729
    /**
730
     * Clean sensible object datas
731
     *
732
     * @param   Object    $object       Object to clean
733
     * @return  Object                  Object with cleaned properties
734
     */
735
    protected function _cleanObjectDatas($object)
736
    {
737
		// phpcs:enable
738
        $object = parent::_cleanObjectDatas($object);
739
740
        unset($object->error);
741
        unset($object->errors);
742
743
        return $object;
744
    }
745
746
    /**
747
     * Translate the name of the object to the given language.
748
     *
749
     * @param object   $object    Object with label to translate
750
     * @param string   $lang      Code of the language the name of the object must be translated to
751
     * @param string   $prefix    Prefix for translation key
752
     * @param array    $dict      Array of dictionary for translation
753
     * @return void
754
     */
755
    private function translateLabel($object, $lang, $prefix = 'Country', $dict = array('dict'))
756
    {
757
        if (!empty($lang)) {
758
            // Load the translations if this is a new language.
759
            if ($this->translations == null || $this->translations->getDefaultLang() !== $lang) {
760
                global $conf;
761
                $this->translations = new Translate('', $conf);
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Api\Api\Translate was not found. Did you mean Translate? If so, make sure to prefix the type with \.
Loading history...
762
                $this->translations->setDefaultLang($lang);
763
                $this->translations->loadLangs($dict);
764
            }
765
            if ($object->code) {
766
                $key = $prefix . $object->code;
767
768
                $translation = $this->translations->trans($key);
769
                if ($translation != $key) {
770
                    $object->label = html_entity_decode($translation);
771
                }
772
            }
773
        }
774
    }
775
776
    /**
777
     * Get the list of events types.
778
     *
779
     * @param string    $sortfield  Sort field
780
     * @param string    $sortorder  Sort order
781
     * @param int       $limit      Number of items per page
782
     * @param int       $page       Page number (starting from zero)
783
     * @param string    $type       To filter on type of event
784
     * @param string    $module     To filter on module events
785
     * @param int       $active     Event's type is active or not {@min 0} {@max 1}
786
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
787
     * @return array                List of events types
788
     *
789
     * @url     GET dictionary/event_types
790
     *
791
     * @throws  RestException   400     Bad value for sqlfilters
792
     * @throws  RestException   503     Error when retrieving list of events types
793
     */
794
    public function getListOfEventTypes($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $type = '', $module = '', $active = 1, $sqlfilters = '')
795
    {
796
        $list = array();
797
798
        $sql = "SELECT id, code, type, libelle as label, module";
799
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_actioncomm as t";
800
        $sql .= " WHERE t.active = " . ((int) $active);
801
        if ($type) {
802
            $sql .= " AND t.type LIKE '%" . $this->db->escape($type) . "%'";
803
        }
804
        if ($module) {
805
            $sql .= " AND t.module LIKE '%" . $this->db->escape($module) . "%'";
806
        }
807
        // Add sql filters
808
        if ($sqlfilters) {
809
            $errormessage = '';
810
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
811
            if ($errormessage) {
812
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
813
            }
814
        }
815
816
817
        $sql .= $this->db->order($sortfield, $sortorder);
818
819
        if ($limit) {
820
            if ($page < 0) {
821
                $page = 0;
822
            }
823
            $offset = $limit * $page;
824
825
            $sql .= $this->db->plimit($limit, $offset);
826
        }
827
828
        $result = $this->db->query($sql);
829
830
        if ($result) {
831
            $num = $this->db->num_rows($result);
832
            $min = min($num, ($limit <= 0 ? $num : $limit));
833
            for ($i = 0; $i < $min; $i++) {
834
                $list[] = $this->db->fetch_object($result);
835
            }
836
        } else {
837
            throw new RestException(503, 'Error when retrieving list of events types : ' . $this->db->lasterror());
838
        }
839
840
        return $list;
841
    }
842
843
844
    /**
845
     * Get the list of Expense Report types.
846
     *
847
     * @param string    $sortfield  Sort field
848
     * @param string    $sortorder  Sort order
849
     * @param int       $limit      Number of items per page
850
     * @param int       $page       Page number (starting from zero)
851
     * @param string    $module     To filter on module
852
     * @param int       $active     Event's type is active or not {@min 0} {@max 1}
853
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
854
     * @return array                List of expense report types
855
     *
856
     * @url     GET dictionary/expensereport_types
857
     *
858
     * @throws  RestException   400     Bad value for sqlfilters
859
     * @throws  RestException   503     Error when retrieving list of expense report types
860
     */
861
    public function getListOfExpenseReportsTypes($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $module = '', $active = 1, $sqlfilters = '')
862
    {
863
        $list = array();
864
865
        $sql = "SELECT id, code, label, accountancy_code, active, module, position";
866
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_type_fees as t";
867
        $sql .= " WHERE t.active = " . ((int) $active);
868
        if ($module) {
869
            $sql .= " AND t.module LIKE '%" . $this->db->escape($module) . "%'";
870
        }
871
        // Add sql filters
872
        if ($sqlfilters) {
873
            $errormessage = '';
874
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
875
            if ($errormessage) {
876
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
877
            }
878
        }
879
880
881
        $sql .= $this->db->order($sortfield, $sortorder);
882
883
        if ($limit) {
884
            if ($page < 0) {
885
                $page = 0;
886
            }
887
            $offset = $limit * $page;
888
889
            $sql .= $this->db->plimit($limit, $offset);
890
        }
891
892
        $result = $this->db->query($sql);
893
894
        if ($result) {
895
            $num = $this->db->num_rows($result);
896
            $min = min($num, ($limit <= 0 ? $num : $limit));
897
            for ($i = 0; $i < $min; $i++) {
898
                $list[] = $this->db->fetch_object($result);
899
            }
900
        } else {
901
            throw new RestException(503, 'Error when retrieving list of expense report types : ' . $this->db->lasterror());
902
        }
903
904
        return $list;
905
    }
906
907
908
    /**
909
     * Get the list of contacts types.
910
     *
911
     * @param string    $sortfield  Sort field
912
     * @param string    $sortorder  Sort order
913
     * @param int       $limit      Number of items per page
914
     * @param int       $page       Page number (starting from zero)
915
     * @param string    $type       To filter on type of contact
916
     * @param string    $module     To filter on module contacts
917
     * @param int       $active     Contact's type is active or not {@min 0} {@max 1}
918
     * @param string    $lang       Code of the language the label of the civility must be translated to
919
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
920
     * @return array      List of Contacts types
921
     *
922
     * @url     GET dictionary/contact_types
923
     *
924
     * @throws  RestException   400     Bad value for sqlfilters
925
     * @throws  RestException   503     Error when retrieving list of contacts types
926
     */
927
    public function getListOfContactTypes($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $type = '', $module = '', $active = 1, $lang = '', $sqlfilters = '')
928
    {
929
        $list = array();
930
931
        $sql = "SELECT rowid, code, element as type, libelle as label, source, module, position";
932
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_type_contact as t";
933
        $sql .= " WHERE t.active = " . ((int) $active);
934
        if ($type) {
935
            $sql .= " AND type LIKE '%" . $this->db->escape($type) . "%'";
936
        }
937
        if ($module) {
938
            $sql .= " AND t.module LIKE '%" . $this->db->escape($module) . "%'";
939
        }
940
        // Add sql filters
941
        if ($sqlfilters) {
942
            $errormessage = '';
943
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
944
            if ($errormessage) {
945
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
946
            }
947
        }
948
949
950
        $sql .= $this->db->order($sortfield, $sortorder);
951
952
        if ($limit) {
953
            if ($page < 0) {
954
                $page = 0;
955
            }
956
            $offset = $limit * $page;
957
958
            $sql .= $this->db->plimit($limit, $offset);
959
        }
960
961
        $result = $this->db->query($sql);
962
963
        if ($result) {
964
            $num = $this->db->num_rows($result);
965
            $min = min($num, ($limit <= 0 ? $num : $limit));
966
            for ($i = 0; $i < $min; $i++) {
967
                $contact_type = $this->db->fetch_object($result);
968
                $this->translateLabel($contact_type, $lang, 'TypeContact_' . $contact_type->type . '_' . $contact_type->source . '_', array("eventorganization", "resource", "projects", "contracts", "bills", "orders", "agenda", "propal", "stocks", "supplier_proposal", "interventions", "sendings", "ticket"));
969
                $list[] = $contact_type;
970
            }
971
        } else {
972
            throw new RestException(503, 'Error when retrieving list of contacts types : ' . $this->db->lasterror());
973
        }
974
975
        return $list;
976
    }
977
978
    /**
979
     * Get the list of civilities.
980
     *
981
     * @param string    $sortfield  Sort field
982
     * @param string    $sortorder  Sort order
983
     * @param int       $limit      Number of items per page
984
     * @param int       $page       Page number (starting from zero)
985
     * @param string    $module     To filter on module events
986
     * @param int       $active     Civility is active or not {@min 0} {@max 1}
987
     * @param string    $lang       Code of the language the label of the civility must be translated to
988
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
989
     * @return array        List of civility types
990
     *
991
     * @url     GET dictionary/civilities
992
     *
993
     * @throws  RestException   400     Bad value for sqlfilters
994
     * @throws  RestException   503     Error when retrieving list of civilities
995
     */
996
    public function getListOfCivilities($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $module = '', $active = 1, $lang = '', $sqlfilters = '')
997
    {
998
        $list = array();
999
1000
        $sql = "SELECT rowid, code, label, module";
1001
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_civility as t";
1002
        $sql .= " WHERE t.active = " . ((int) $active);
1003
        if ($module) {
1004
            $sql .= " AND t.module LIKE '%" . $this->db->escape($module) . "%'";
1005
        }
1006
        // Add sql filters
1007
        if ($sqlfilters) {
1008
            $errormessage = '';
1009
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
1010
            if ($errormessage) {
1011
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
1012
            }
1013
        }
1014
1015
1016
        $sql .= $this->db->order($sortfield, $sortorder);
1017
1018
        if ($limit) {
1019
            if ($page < 0) {
1020
                $page = 0;
1021
            }
1022
            $offset = $limit * $page;
1023
1024
            $sql .= $this->db->plimit($limit, $offset);
1025
        }
1026
1027
        $result = $this->db->query($sql);
1028
1029
        if ($result) {
1030
            $num = $this->db->num_rows($result);
1031
            $min = min($num, ($limit <= 0 ? $num : $limit));
1032
            for ($i = 0; $i < $min; $i++) {
1033
                $civility = $this->db->fetch_object($result);
1034
                $this->translateLabel($civility, $lang, 'Civility', array('dict'));
1035
                $list[] = $civility;
1036
            }
1037
        } else {
1038
            throw new RestException(503, 'Error when retrieving list of civility : ' . $this->db->lasterror());
1039
        }
1040
1041
        return $list;
1042
    }
1043
1044
    /**
1045
     * Get the list of currencies.
1046
     *
1047
     * @param int       $multicurrency  Multicurrency rates (0: no multicurrency, 1: last rate, 2: all rates) {@min 0} {@max 2}
1048
     * @param string    $sortfield  Sort field
1049
     * @param string    $sortorder  Sort order
1050
     * @param int       $limit      Number of items per page
1051
     * @param int       $page       Page number (starting from zero)
1052
     * @param int       $active     Payment term is active or not {@min 0} {@max 1}
1053
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
1054
     * @return array                List of currencies
1055
     *
1056
     * @url     GET dictionary/currencies
1057
     *
1058
     * @throws  RestException   400     Bad value for sqlfilters
1059
     * @throws  RestException   503     Error when retrieving list of currencies
1060
     */
1061
    public function getListOfCurrencies($multicurrency = 0, $sortfield = "code_iso", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
1062
    {
1063
        $list = array();
1064
        $sql = "SELECT t.code_iso, t.label, t.unicode";
1065
        if (!empty($multicurrency)) {
1066
            $sql .= " , cr.date_sync, cr.rate ";
1067
        }
1068
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_currencies as t";
1069
        if (!empty($multicurrency)) {
1070
            $sql .= " JOIN " . MAIN_DB_PREFIX . "multicurrency as m ON m.code=t.code_iso";
1071
            $sql .= " JOIN " . MAIN_DB_PREFIX . "multicurrency_rate as cr ON (m.rowid = cr.fk_multicurrency)";
1072
        }
1073
        $sql .= " WHERE t.active = " . ((int) $active);
1074
        if (!empty($multicurrency)) {
1075
            $sql .= " AND m.entity IN (" . getEntity('multicurrency') . ")";
1076
            if (!empty($multicurrency) && $multicurrency != 2) {
1077
                $sql .= " AND cr.date_sync = (SELECT MAX(cr2.date_sync) FROM " . MAIN_DB_PREFIX . "multicurrency_rate AS cr2 WHERE cr2.fk_multicurrency = m.rowid)";
1078
            }
1079
        }
1080
1081
        // Add sql filters
1082
        if ($sqlfilters) {
1083
            $errormessage = '';
1084
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
1085
            if ($errormessage) {
1086
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
1087
            }
1088
        }
1089
1090
1091
        $sql .= $this->db->order($sortfield, $sortorder);
1092
1093
        if ($limit) {
1094
            if ($page < 0) {
1095
                $page = 0;
1096
            }
1097
            $offset = $limit * $page;
1098
1099
            $sql .= $this->db->plimit($limit, $offset);
1100
        }
1101
1102
        $result = $this->db->query($sql);
1103
1104
        if ($result) {
1105
            $num = $this->db->num_rows($result);
1106
            $min = min($num, ($limit <= 0 ? $num : $limit));
1107
            for ($i = 0; $i < $min; $i++) {
1108
                $list[] = $this->db->fetch_object($result);
1109
            }
1110
        } else {
1111
            throw new RestException(503, 'Error when retrieving list of currency : ' . $this->db->lasterror());
1112
        }
1113
1114
        return $list;
1115
    }
1116
1117
    /**
1118
     * Get the list of extra fields.
1119
     *
1120
     * @param string    $sortfield  Sort field
1121
     * @param string    $sortorder  Sort order
1122
     * @param string    $elementtype       Type of element ('adherent', 'commande', 'thirdparty', 'facture', 'propal', 'product', ...)
1123
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.label:like:'SO-%')"
1124
     * @return array                List of extra fields
1125
     *
1126
     * @url     GET extrafields
1127
     *
1128
     * @throws  RestException   400     Bad value for sqlfilters
1129
     * @throws  RestException   503     Error when retrieving list of extra fields
1130
     */
1131
    public function getListOfExtrafields($sortfield = "t.pos", $sortorder = 'ASC', $elementtype = '', $sqlfilters = '')
1132
    {
1133
        $list = array();
1134
1135
        if (!DolibarrApiAccess::$user->admin) {
1136
            throw new RestException(403, 'Only an admin user can get list of extrafields');
1137
        }
1138
1139
        if ($elementtype == 'thirdparty') {
1140
            $elementtype = 'societe';
1141
        }
1142
        if ($elementtype == 'contact') {
1143
            $elementtype = 'socpeople';
1144
        }
1145
1146
        $sql = "SELECT t.rowid as id, t.name, t.entity, t.elementtype, t.label, t.type, t.size, t.fieldcomputed, t.fielddefault,";
1147
        $sql .= " t.fieldunique, t.fieldrequired, t.perms, t.enabled, t.pos, t.alwayseditable, t.param, t.list, t.printable,";
1148
        $sql .= " t.totalizable, t.langs, t.help, t.css, t.cssview, t.fk_user_author, t.fk_user_modif, t.datec, t.tms";
1149
        $sql .= " FROM " . MAIN_DB_PREFIX . "extrafields as t";
1150
        $sql .= " WHERE t.entity IN (" . getEntity('extrafields') . ")";
1151
        if (!empty($elementtype)) {
1152
            $sql .= " AND t.elementtype = '" . $this->db->escape($elementtype) . "'";
1153
        }
1154
        // Add sql filters
1155
        if ($sqlfilters) {
1156
            $errormessage = '';
1157
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
1158
            if ($errormessage) {
1159
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
1160
            }
1161
        }
1162
1163
        $sql .= $this->db->order($sortfield, $sortorder);
1164
1165
        $resql = $this->db->query($sql);
1166
        if ($resql) {
1167
            if ($this->db->num_rows($resql)) {
1168
                while ($tab = $this->db->fetch_object($resql)) {
1169
                    // New usage
1170
                    $list[$tab->elementtype][$tab->name]['id'] = $tab->id;
1171
                    $list[$tab->elementtype][$tab->name]['type'] = $tab->type;
1172
                    $list[$tab->elementtype][$tab->name]['label'] = $tab->label;
1173
                    $list[$tab->elementtype][$tab->name]['size'] = $tab->size;
1174
                    $list[$tab->elementtype][$tab->name]['elementtype'] = $tab->elementtype;
1175
                    $list[$tab->elementtype][$tab->name]['default'] = $tab->fielddefault;
1176
                    $list[$tab->elementtype][$tab->name]['computed'] = $tab->fieldcomputed;
1177
                    $list[$tab->elementtype][$tab->name]['unique'] = $tab->fieldunique;
1178
                    $list[$tab->elementtype][$tab->name]['required'] = $tab->fieldrequired;
1179
                    $list[$tab->elementtype][$tab->name]['param'] = ($tab->param ? jsonOrUnserialize($tab->param) : '');    // This may be a string encoded with serialise() or json_encode()
1180
                    $list[$tab->elementtype][$tab->name]['pos'] = $tab->pos;
1181
                    $list[$tab->elementtype][$tab->name]['alwayseditable'] = $tab->alwayseditable;
1182
                    $list[$tab->elementtype][$tab->name]['perms'] = $tab->perms;
1183
                    $list[$tab->elementtype][$tab->name]['list'] = $tab->list;
1184
                    $list[$tab->elementtype][$tab->name]['printable'] = $tab->printable;
1185
                    $list[$tab->elementtype][$tab->name]['totalizable'] = $tab->totalizable;
1186
                    $list[$tab->elementtype][$tab->name]['langs'] = $tab->langs;
1187
                    $list[$tab->elementtype][$tab->name]['help'] = $tab->help;
1188
                    $list[$tab->elementtype][$tab->name]['css'] = $tab->css;
1189
                    $list[$tab->elementtype][$tab->name]['cssview'] = $tab->cssview;
1190
                    $list[$tab->elementtype][$tab->name]['csslist'] = $tab->csslist;
1191
                    $list[$tab->elementtype][$tab->name]['fk_user_author'] = $tab->fk_user_author;
1192
                    $list[$tab->elementtype][$tab->name]['fk_user_modif'] = $tab->fk_user_modif;
1193
                    $list[$tab->elementtype][$tab->name]['datec'] = $tab->datec;
1194
                    $list[$tab->elementtype][$tab->name]['tms'] = $tab->tms;
1195
                }
1196
            }
1197
        } else {
1198
            throw new RestException(503, 'Error when retrieving list of extra fields : ' . $this->db->lasterror());
1199
        }
1200
1201
        return $list;
1202
    }
1203
1204
    /**
1205
     * Delete extrafield
1206
     *
1207
     * @param   string     $attrname         extrafield attrname
1208
     * @param   string     $elementtype      extrafield elementtype
1209
     * @return  array
1210
     *
1211
     * @url     DELETE extrafields/{elementtype}/{attrname}
1212
     *
1213
     */
1214
    public function deleteExtrafieldsFromNames($attrname, $elementtype)
1215
    {
1216
        if (!DolibarrApiAccess::$user->admin) {
1217
            throw new RestException(403, 'Only an admin user can delete an extrafield by attrname and elementtype');
1218
        }
1219
1220
        $extrafields = new ExtraFields($this->db);
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Api\Api\ExtraFields was not found. Did you mean ExtraFields? If so, make sure to prefix the type with \.
Loading history...
1221
1222
        $result = $extrafields->fetch_name_optionals_label($elementtype, false, $attrname);
1223
        if (!$result) {
1224
            throw new RestException(404, 'Extrafield not found from attrname and elementtype');
1225
        }
1226
1227
        if (!$extrafields->delete($attrname, $elementtype)) {
1228
            throw new RestException(500, 'Error when delete extrafield : ' . $extrafields->error);
1229
        }
1230
1231
        return array(
1232
            'success' => array(
1233
                'code' => 200,
1234
                'message' => 'Extrafield deleted from attrname and elementtype'
1235
            )
1236
        );
1237
    }
1238
1239
1240
1241
    /** get Extrafield object
1242
     *
1243
     * @param   string  $attrname       extrafield attrname
1244
     * @param   string  $elementtype    extrafield elementtype
1245
     * @return  array                   List of extra fields
1246
     *
1247
     * @url     GET     extrafields/{elementtype}/{attrname}
1248
     *
1249
     * @suppress PhanPluginUnknownArrayMethodParamType  Luracast limitation
1250
     *
1251
     */
1252
    public function getExtrafields($attrname, $elementtype)
1253
    {
1254
        $answer = array();
1255
1256
        if (!DolibarrApiAccess::$user->admin) {
1257
            throw new RestException(403, 'Only an admin user can get list of extrafields');
1258
        }
1259
1260
        if ($elementtype == 'thirdparty') {
1261
            $elementtype = 'societe';
1262
        }
1263
        if ($elementtype == 'contact') {
1264
            $elementtype = 'socpeople';
1265
        }
1266
1267
        $sql = "SELECT t.rowid as id, t.name, t.entity, t.elementtype, t.label, t.type, t.size, t.fieldcomputed, t.fielddefault,";
1268
        $sql .= " t.fieldunique, t.fieldrequired, t.perms, t.enabled, t.pos, t.alwayseditable, t.param, t.list, t.printable,";
1269
        $sql .= " t.totalizable, t.langs, t.help, t.css, t.cssview, t.fk_user_author, t.fk_user_modif, t.datec, t.tms";
1270
        $sql .= " FROM " . MAIN_DB_PREFIX . "extrafields as t";
1271
        $sql .= " WHERE t.entity IN (" . getEntity('extrafields') . ")";
1272
        $sql .= " AND t.elementtype = '" . $this->db->escape($elementtype) . "'";
1273
        $sql .= " AND t.name = '" . $this->db->escape($attrname) . "'";
1274
1275
        $resql = $this->db->query($sql);
1276
        if ($resql) {
1277
            if ($this->db->num_rows($resql)) {
1278
                while ($tab = $this->db->fetch_object($resql)) {
1279
                    // New usage
1280
                    $answer[$tab->elementtype][$tab->name]['id'] = $tab->id;
1281
                    $answer[$tab->elementtype][$tab->name]['type'] = $tab->type;
1282
                    $answer[$tab->elementtype][$tab->name]['label'] = $tab->label;
1283
                    $answer[$tab->elementtype][$tab->name]['size'] = $tab->size;
1284
                    $answer[$tab->elementtype][$tab->name]['elementtype'] = $tab->elementtype;
1285
                    $answer[$tab->elementtype][$tab->name]['default'] = $tab->fielddefault;
1286
                    $answer[$tab->elementtype][$tab->name]['computed'] = $tab->fieldcomputed;
1287
                    $answer[$tab->elementtype][$tab->name]['unique'] = $tab->fieldunique;
1288
                    $answer[$tab->elementtype][$tab->name]['required'] = $tab->fieldrequired;
1289
                    $answer[$tab->elementtype][$tab->name]['param'] = ($tab->param ? jsonOrUnserialize($tab->param) : '');  // This may be a string encoded with serialise() or json_encode()
1290
                    $answer[$tab->elementtype][$tab->name]['pos'] = $tab->pos;
1291
                    $answer[$tab->elementtype][$tab->name]['alwayseditable'] = $tab->alwayseditable;
1292
                    $answer[$tab->elementtype][$tab->name]['perms'] = $tab->perms;
1293
                    $answer[$tab->elementtype][$tab->name]['list'] = $tab->list;
1294
                    $answer[$tab->elementtype][$tab->name]['printable'] = $tab->printable;
1295
                    $answer[$tab->elementtype][$tab->name]['totalizable'] = $tab->totalizable;
1296
                    $answer[$tab->elementtype][$tab->name]['langs'] = $tab->langs;
1297
                    $answer[$tab->elementtype][$tab->name]['help'] = $tab->help;
1298
                    $answer[$tab->elementtype][$tab->name]['css'] = $tab->css;
1299
                    $answer[$tab->elementtype][$tab->name]['cssview'] = $tab->cssview;
1300
                    $answer[$tab->elementtype][$tab->name]['csslist'] = $tab->csslist;
1301
                    $answer[$tab->elementtype][$tab->name]['fk_user_author'] = $tab->fk_user_author;
1302
                    $answer[$tab->elementtype][$tab->name]['fk_user_modif'] = $tab->fk_user_modif;
1303
                    $answer[$tab->elementtype][$tab->name]['datec'] = $tab->datec;
1304
                    $answer[$tab->elementtype][$tab->name]['tms'] = $tab->tms;
1305
                }
1306
            } else {
1307
                throw new RestException(404, 'Extrafield not found from attrname and elementtype');
1308
            }
1309
        } else {
1310
            throw new RestException(503, 'Error when retrieving list of extra fields : ' . $this->db->lasterror());
1311
        }
1312
1313
        return $answer;
1314
    }
1315
1316
    /**
1317
     * Create Extrafield object
1318
     *
1319
     * @param   string  $attrname       extrafield attrname
1320
     * @param   string  $elementtype    extrafield elementtype
1321
     * @param   array   $request_data   Request datas
1322
     * @return  int                     ID of extrafield
1323
     *
1324
     * @url     POST    extrafields/{elementtype}/{attrname}
1325
     *
1326
     * @suppress PhanPluginUnknownArrayMethodParamType  Luracast limitation
1327
     *
1328
     */
1329
    public function postExtrafields($attrname, $elementtype, $request_data = null)
1330
    {
1331
        if (!DolibarrApiAccess::$user->admin) {
1332
            throw new RestException(403, 'Only an admin user can create an extrafield');
1333
        }
1334
1335
        $extrafields = new ExtraFields($this->db);
1336
1337
        $result = $extrafields->fetch_name_optionals_label($elementtype, false, $attrname);
1338
        if ($result) {
1339
            throw new RestException(409, 'Duplicate extrafield already found from attrname and elementtype');
1340
        }
1341
1342
        // Check mandatory fields is not working despise being a modified copy from api_thirdparties.class.php
1343
        // $result = $this->_validateExtrafields($request_data, $extrafields);
1344
1345
        foreach ($request_data as $field => $value) {
1346
            $extrafields->$field = $this->_checkValForAPI($field, $value, $extrafields);
1347
        }
1348
1349
        $entity = DolibarrApiAccess::$user->entity;
1350
        if (empty($entity)) {
1351
            $entity = 1;
1352
        }
1353
1354
        // built in validation
1355
        $enabled = 1; // hardcoded because it seems to always be 1 in every row in the database
1356
1357
        if ($request_data['label']) {
1358
            $label = $request_data['label'];
1359
        } else {
1360
            throw new RestException(400, "label field absent in json at root level");
1361
        }
1362
1363
        $alwayseditable = $request_data['alwayseditable'];
1364
        $default_value = $request_data['default_value'];
1365
        $totalizable = $request_data['totalizable'];
1366
        $printable = $request_data['printable'];
1367
        $required = $request_data['required'];
1368
        $langfile = $request_data['langfile'];
1369
        $computed = $request_data['computed'];
1370
        $unique = $request_data['unique'];
1371
        $param = $request_data['param'];
1372
        $perms = $request_data['perms'];
1373
        $size = $request_data['size'];
1374
        $type = $request_data['type'];
1375
        $list = $request_data['list'];
1376
        $help = $request_data['help'];
1377
        $pos = $request_data['pos'];
1378
        $moreparams = array();
1379
1380
        if (0 > $extrafields->addExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique, $required, $default_value, $param, $alwayseditable, $perms, $list, $help, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams)) {
1381
            throw new RestException(500, 'Error creating extrafield', array_merge(array($extrafields->errno), $extrafields->errors));
1382
        }
1383
1384
        $sql = "SELECT t.rowid as id";
1385
        $sql .= " FROM " . MAIN_DB_PREFIX . "extrafields as t";
1386
        $sql .= " WHERE elementtype = '" . $this->db->escape($elementtype) . "'";
1387
        $sql .= " AND name = '" . $this->db->escape($attrname) . "'";
1388
1389
        $resql = $this->db->query($sql);
1390
        if ($resql) {
1391
            if ($this->db->num_rows($resql)) {
1392
                $tab = $this->db->fetch_object($resql);
1393
                $id = (int) $tab->id;
1394
            } else {
1395
                $id = (int) -1;
1396
            }
1397
        } else {
1398
            $id = (int) -2;
1399
        }
1400
1401
        return $id;
1402
    }
1403
1404
    /**
1405
1406
     * Update Extrafield object
1407
     *
1408
     * @param   string  $attrname       extrafield attrname
1409
     * @param   string  $elementtype    extrafield elementtype
1410
     * @param   array   $request_data   Request datas
1411
     * @return  int                     ID of extrafield
1412
     *
1413
     * @url     PUT     extrafields/{elementtype}/{attrname}
1414
     *
1415
     * @suppress PhanPluginUnknownArrayMethodParamType  Luracast limitation
1416
     *
1417
     */
1418
    public function updateExtrafields($attrname, $elementtype, $request_data = null)
1419
    {
1420
        if (!DolibarrApiAccess::$user->admin) {
1421
            throw new RestException(403, 'Only an admin user can create an extrafield');
1422
        }
1423
1424
        $extrafields = new ExtraFields($this->db);
1425
1426
        $result = $extrafields->fetch_name_optionals_label($elementtype, false, $attrname);
1427
        if (!$result) {
1428
            throw new RestException(404, 'Extrafield not found from attrname and elementtype');
1429
        }
1430
1431
        foreach ($request_data as $field => $value) {
1432
            $extrafields->$field = $this->_checkValForAPI($field, $value, $extrafields);
1433
        }
1434
1435
        $entity = DolibarrApiAccess::$user->entity;
1436
        if (empty($entity)) {
1437
            $entity = 1;
1438
        }
1439
1440
        // built in validation
1441
        $enabled = 1; // hardcoded because it seems to always be 1 in every row in the database
1442
        if ($request_data['label']) {
1443
            $label = $request_data['label'];
1444
        } else {
1445
            throw new RestException(400, "label field absent in json at root level");
1446
        }
1447
1448
        $alwayseditable = $request_data['alwayseditable'];
1449
        $default_value = $request_data['default_value'];
1450
        $totalizable = $request_data['totalizable'];
1451
        $printable = $request_data['printable'];
1452
        $required = $request_data['required'];
1453
        $langfile = $request_data['langfile'];
1454
        $computed = $request_data['computed'];
1455
        $unique = $request_data['unique'];
1456
        $param = $request_data['param'];
1457
        $perms = $request_data['perms'];
1458
        $size = $request_data['size'];
1459
        $type = $request_data['type'];
1460
        $list = $request_data['list'];
1461
        $help = $request_data['help'];
1462
        $pos = $request_data['pos'];
1463
        $moreparams = array();
1464
1465
        dol_syslog(get_class($this) . '::updateExtraField', LOG_DEBUG);
1466
        if (0 > $extrafields->updateExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique, $required, $default_value, $param, $alwayseditable, $perms, $list, $help, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams)) {
1467
            throw new RestException(500, 'Error updating extrafield', array_merge(array($extrafields->errno), $extrafields->errors));
1468
        }
1469
1470
        $sql = "SELECT t.rowid as id";
1471
        $sql .= " FROM " . MAIN_DB_PREFIX . "extrafields as t";
1472
        $sql .= " WHERE elementtype = '" . $this->db->escape($elementtype) . "'";
1473
        $sql .= " AND name = '" . $this->db->escape($attrname) . "'";
1474
1475
        $resql = $this->db->query($sql);
1476
        if ($resql) {
1477
            if ($this->db->num_rows($resql)) {
1478
                $tab = $this->db->fetch_object($resql);
1479
                $id = (int) $tab->id;
1480
            } else {
1481
                $id = (int) -1;
1482
            }
1483
        } else {
1484
            $id = (int) -2;
1485
        }
1486
1487
        return $id;
1488
    }
1489
1490
    /**
1491
     * Get the list of towns.
1492
     *
1493
     * @param string    $sortfield  Sort field
1494
     * @param string    $sortorder  Sort order
1495
     * @param int       $limit      Number of items per page
1496
     * @param int       $page       Page number (starting from zero)
1497
     * @param string    $zipcode    To filter on zipcode
1498
     * @param string    $town       To filter on city name
1499
     * @param int       $active     Town is active or not {@min 0} {@max 1}
1500
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
1501
     * @return array                List of towns
1502
     *
1503
     * @url     GET dictionary/towns
1504
     *
1505
     * @throws  RestException   400     Bad value for sqlfilters
1506
     * @throws  RestException   503     Error when retrieving list of towns
1507
     */
1508
    public function getListOfTowns($sortfield = "zip,town", $sortorder = 'ASC', $limit = 100, $page = 0, $zipcode = '', $town = '', $active = 1, $sqlfilters = '')
1509
    {
1510
        $list = array();
1511
1512
        $sql = "SELECT rowid AS id, zip, town, fk_county, fk_pays AS fk_country";
1513
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_ziptown as t";
1514
        $sql .= " WHERE t.active = " . ((int) $active);
1515
        if ($zipcode) {
1516
            $sql .= " AND t.zip LIKE '%" . $this->db->escape($zipcode) . "%'";
1517
        }
1518
        if ($town) {
1519
            $sql .= " AND t.town LIKE '%" . $this->db->escape($town) . "%'";
1520
        }
1521
        // Add sql filters
1522
        if ($sqlfilters) {
1523
            $errormessage = '';
1524
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
1525
            if ($errormessage) {
1526
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
1527
            }
1528
        }
1529
1530
1531
        $sql .= $this->db->order($sortfield, $sortorder);
1532
1533
        if ($limit) {
1534
            if ($page < 0) {
1535
                $page = 0;
1536
            }
1537
            $offset = $limit * $page;
1538
1539
            $sql .= $this->db->plimit($limit, $offset);
1540
        }
1541
1542
        $result = $this->db->query($sql);
1543
1544
        if ($result) {
1545
            $num = $this->db->num_rows($result);
1546
            $min = min($num, ($limit <= 0 ? $num : $limit));
1547
            for ($i = 0; $i < $min; $i++) {
1548
                $list[] = $this->db->fetch_object($result);
1549
            }
1550
        } else {
1551
            throw new RestException(503, 'Error when retrieving list of towns : ' . $this->db->lasterror());
1552
        }
1553
1554
        return $list;
1555
    }
1556
1557
    /**
1558
     * Get the list of payments terms.
1559
     *
1560
     * @param string    $sortfield  Sort field
1561
     * @param string    $sortorder  Sort order
1562
     * @param int       $limit      Number of items per page
1563
     * @param int       $page       Page number {@min 0}
1564
     * @param int       $active     Payment term is active or not {@min 0} {@max 1}
1565
     * @param string    $sqlfilters SQL criteria to filter. Syntax example "(t.code:=:'CHQ')"
1566
     *
1567
     * @url     GET dictionary/payment_terms
1568
     *
1569
     * @return array List of payment terms
1570
     *
1571
     * @throws  RestException   400     Bad value for sqlfilters
1572
     * @throws  RestException   403     Access denied
1573
     * @throws  RestException   503     Error when retrieving list of payments terms
1574
     */
1575
    public function getPaymentTerms($sortfield = "sortorder", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
1576
    {
1577
        $list = array();
1578
1579
        if (!DolibarrApiAccess::$user->hasRight('propal', 'lire') && !DolibarrApiAccess::$user->hasRight('commande', 'lire') && !DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
1580
            throw new RestException(403);
1581
        }
1582
1583
        $sql = "SELECT rowid as id, code, sortorder, libelle as label, libelle_facture as descr, type_cdr, nbjour, decalage, module";
1584
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_payment_term as t";
1585
        $sql .= " WHERE t.entity IN (" . getEntity('c_payment_term') . ")";
1586
        $sql .= " AND t.active = " . ((int) $active);
1587
        // Add sql filters
1588
        if ($sqlfilters) {
1589
            $errormessage = '';
1590
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
1591
            if ($errormessage) {
1592
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
1593
            }
1594
        }
1595
1596
1597
        $sql .= $this->db->order($sortfield, $sortorder);
1598
1599
        if ($limit) {
1600
            if ($page < 0) {
1601
                $page = 0;
1602
            }
1603
            $offset = $limit * $page;
1604
1605
            $sql .= $this->db->plimit($limit, $offset);
1606
        }
1607
1608
        $result = $this->db->query($sql);
1609
1610
        if ($result) {
1611
            $num = $this->db->num_rows($result);
1612
            $min = min($num, ($limit <= 0 ? $num : $limit));
1613
            for ($i = 0; $i < $min; $i++) {
1614
                $list[] = $this->db->fetch_object($result);
1615
            }
1616
        } else {
1617
            throw new RestException(503, $this->db->lasterror());
1618
        }
1619
1620
        return $list;
1621
    }
1622
1623
    /**
1624
     * Get the list of shipping methods.
1625
     *
1626
     * @param int       $limit      Number of items per page
1627
     * @param int       $page       Page number {@min 0}
1628
     * @param int       $active     Shipping methodsm is active or not {@min 0} {@max 1}
1629
     * @param string    $lang       Code of the language the label of the method must be translated to
1630
     * @param string    $sqlfilters SQL criteria to filter. Syntax example "(t.code:=:'CHQ')"
1631
     *
1632
     * @url     GET dictionary/shipping_methods
1633
     *
1634
     * @return array List of shipping methods
1635
     *
1636
     * @throws  RestException   400     Bad value for sqlfilters
1637
     * @throws  RestException   503     Error when retrieving list of shipping modes
1638
     */
1639
    public function getShippingModes($limit = 100, $page = 0, $active = 1, $lang = '', $sqlfilters = '')
1640
    {
1641
        $list = array();
1642
1643
        $sql = "SELECT rowid as id, code, libelle as label, description, tracking, module";
1644
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_shipment_mode as t";
1645
        $sql .= " WHERE t.entity IN (" . getEntity('c_shipment_mode') . ")";
1646
        $sql .= " AND t.active = " . ((int) $active);
1647
        // Add sql filters
1648
        if ($sqlfilters) {
1649
            $errormessage = '';
1650
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
1651
            if ($errormessage) {
1652
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
1653
            }
1654
        }
1655
1656
1657
        //$sql.= $this->db->order($sortfield, $sortorder);
1658
1659
        if ($limit) {
1660
            if ($page < 0) {
1661
                $page = 0;
1662
            }
1663
            $offset = $limit * $page;
1664
1665
            $sql .= $this->db->plimit($limit, $offset);
1666
        }
1667
1668
        $result = $this->db->query($sql);
1669
1670
        if ($result) {
1671
            $num = $this->db->num_rows($result);
1672
            $min = min($num, ($limit <= 0 ? $num : $limit));
1673
            for ($i = 0; $i < $min; $i++) {
1674
                $method = $this->db->fetch_object($result);
1675
                $this->translateLabel($method, $lang, '', array('dict'));
1676
                $list[] = $method;
1677
            }
1678
        } else {
1679
            throw new RestException(503, $this->db->lasterror());
1680
        }
1681
1682
        return $list;
1683
    }
1684
1685
    /**
1686
     * Get the list of measuring units.
1687
     *
1688
     * @param string    $sortfield  Sort field
1689
     * @param string    $sortorder  Sort order
1690
     * @param int       $limit      Number of items per page
1691
     * @param int       $page       Page number (starting from zero)
1692
     * @param int       $active     Measuring unit is active or not {@min 0} {@max 1}
1693
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
1694
     * @return array                List of measuring unit
1695
     *
1696
     * @url     GET dictionary/units
1697
     *
1698
     * @throws  RestException   400     Bad value for sqlfilters
1699
     * @throws  RestException   503     Error when retrieving list of measuring units
1700
     */
1701
    public function getListOfMeasuringUnits($sortfield = "rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
1702
    {
1703
        $list = array();
1704
1705
        $sql = "SELECT t.rowid, t.code, t.label,t.short_label, t.active, t.scale, t.unit_type";
1706
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_units as t";
1707
        $sql .= " WHERE t.active = " . ((int) $active);
1708
        // Add sql filters
1709
        if ($sqlfilters) {
1710
            $errormessage = '';
1711
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
1712
            if ($errormessage) {
1713
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
1714
            }
1715
        }
1716
1717
1718
        $sql .= $this->db->order($sortfield, $sortorder);
1719
1720
        if ($limit) {
1721
            if ($page < 0) {
1722
                $page = 0;
1723
            }
1724
            $offset = $limit * $page;
1725
1726
            $sql .= $this->db->plimit($limit, $offset);
1727
        }
1728
1729
        $result = $this->db->query($sql);
1730
1731
        if ($result) {
1732
            $num = $this->db->num_rows($result);
1733
            $min = min($num, ($limit <= 0 ? $num : $limit));
1734
            for ($i = 0; $i < $min; $i++) {
1735
                $list[] = $this->db->fetch_object($result);
1736
            }
1737
        } else {
1738
            throw new RestException(503, 'Error when retrieving list of measuring units: ' . $this->db->lasterror());
1739
        }
1740
1741
        return $list;
1742
    }
1743
1744
    /**
1745
     * Get the list of legal form of business.
1746
     *
1747
     * @param string    $sortfield  Sort field
1748
     * @param string    $sortorder  Sort order
1749
     * @param int       $limit      Number of items per page
1750
     * @param int       $page       Page number (starting from zero)
1751
     * @param int       $country    To filter on country
1752
     * @param int       $active     Lega form is active or not {@min 0} {@max 1}
1753
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
1754
     * @return array                List of legal form
1755
     *
1756
     * @url     GET dictionary/legal_form
1757
     *
1758
     * @throws  RestException   400     Bad value for sqlfilters
1759
     * @throws  RestException   503     Error when retrieving list of legal form
1760
     */
1761
    public function getListOfLegalForm($sortfield = "rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $country = 0, $active = 1, $sqlfilters = '')
1762
    {
1763
        $list = array();
1764
1765
        $sql = "SELECT t.rowid, t.code, t.fk_pays, t.libelle, t.isvatexempted, t.active, t.module, t.position";
1766
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_forme_juridique as t";
1767
        $sql .= " WHERE t.active = " . ((int) $active);
1768
        if ($country) {
1769
            $sql .= " AND t.fk_pays = " . ((int) $country);
1770
        }
1771
        // Add sql filters
1772
        if ($sqlfilters) {
1773
            $errormessage = '';
1774
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
1775
            if ($errormessage) {
1776
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
1777
            }
1778
        }
1779
1780
1781
        $sql .= $this->db->order($sortfield, $sortorder);
1782
1783
        if ($limit) {
1784
            if ($page < 0) {
1785
                $page = 0;
1786
            }
1787
            $offset = $limit * $page;
1788
1789
            $sql .= $this->db->plimit($limit, $offset);
1790
        }
1791
1792
        $result = $this->db->query($sql);
1793
1794
        if ($result) {
1795
            $num = $this->db->num_rows($result);
1796
            $min = min($num, ($limit <= 0 ? $num : $limit));
1797
            for ($i = 0; $i < $min; $i++) {
1798
                $list[] = $this->db->fetch_object($result);
1799
            }
1800
        } else {
1801
            throw new RestException(503, 'Error when retrieving list of legal form: ' . $this->db->lasterror());
1802
        }
1803
1804
        return $list;
1805
    }
1806
1807
    /**
1808
     * Get the list of staff.
1809
     *
1810
     * @param string    $sortfield  Sort field
1811
     * @param string    $sortorder  Sort order
1812
     * @param int       $limit      Number of items per page
1813
     * @param int       $page       Page number (starting from zero)
1814
     * @param int       $active     Staff is active or not {@min 0} {@max 1}
1815
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
1816
     * @return array                List of staff
1817
     *
1818
     * @url     GET dictionary/staff
1819
     *
1820
     * @throws  RestException   400     Bad value for sqlfilters
1821
     * @throws  RestException   503     Error when retrieving list of staff
1822
     */
1823
    public function getListOfStaff($sortfield = "id", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
1824
    {
1825
        $list = array();
1826
1827
        $sql = "SELECT t.id, t.code, t.libelle, t.active, t.module";
1828
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_effectif as t";
1829
        $sql .= " WHERE t.active = " . ((int) $active);
1830
        // Add sql filters
1831
        if ($sqlfilters) {
1832
            $errormessage = '';
1833
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
1834
            if ($errormessage) {
1835
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
1836
            }
1837
        }
1838
1839
1840
        $sql .= $this->db->order($sortfield, $sortorder);
1841
1842
        if ($limit) {
1843
            if ($page < 0) {
1844
                $page = 0;
1845
            }
1846
            $offset = $limit * $page;
1847
1848
            $sql .= $this->db->plimit($limit, $offset);
1849
        }
1850
1851
        $result = $this->db->query($sql);
1852
1853
        if ($result) {
1854
            $num = $this->db->num_rows($result);
1855
            $min = min($num, ($limit <= 0 ? $num : $limit));
1856
            for ($i = 0; $i < $min; $i++) {
1857
                $list[] = $this->db->fetch_object($result);
1858
            }
1859
        } else {
1860
            throw new RestException(503, 'Error when retrieving list of staff: ' . $this->db->lasterror());
1861
        }
1862
1863
        return $list;
1864
    }
1865
1866
    /**
1867
     * Get the list of social networks.
1868
     *
1869
     * @param string    $sortfield  Sort field
1870
     * @param string    $sortorder  Sort order
1871
     * @param int       $limit      Number of items per page
1872
     * @param int       $page       Page number (starting from zero)
1873
     * @param int       $active     Social network is active or not {@min 0} {@max 1}
1874
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
1875
     * @return array                List of social networks
1876
     *
1877
     * @url     GET dictionary/socialnetworks
1878
     *
1879
     * @throws  RestException   400     Bad value for sqlfilters
1880
     * @throws  RestException   503     Error when retrieving list of social networks
1881
     */
1882
    public function getListOfsocialNetworks($sortfield = "rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
1883
    {
1884
        global $conf;
1885
1886
        if (!isModEnabled('socialnetworks')) {
1887
            throw new RestException(400, 'API not available: this dictionary is not enabled by setup');
1888
        }
1889
1890
        $list = array();
1891
        //TODO link with multicurrency module
1892
        $sql = "SELECT t.rowid, t.entity, t.code, t.label, t.url, t.icon, t.active";
1893
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_socialnetworks as t";
1894
        $sql .= " WHERE t.entity IN (" . getEntity('c_socialnetworks') . ")";
1895
        $sql .= " AND t.active = " . ((int) $active);
1896
        // Add sql filters
1897
        if ($sqlfilters) {
1898
            $errormessage = '';
1899
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
1900
            if ($errormessage) {
1901
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
1902
            }
1903
        }
1904
1905
1906
        $sql .= $this->db->order($sortfield, $sortorder);
1907
1908
        if ($limit) {
1909
            if ($page < 0) {
1910
                $page = 0;
1911
            }
1912
            $offset = $limit * $page;
1913
1914
            $sql .= $this->db->plimit($limit, $offset);
1915
        }
1916
1917
        $result = $this->db->query($sql);
1918
1919
        if ($result) {
1920
            $num = $this->db->num_rows($result);
1921
            $min = min($num, ($limit <= 0 ? $num : $limit));
1922
            for ($i = 0; $i < $min; $i++) {
1923
                $list[] = $this->db->fetch_object($result);
1924
            }
1925
        } else {
1926
            throw new RestException(503, 'Error when retrieving list of social networks: ' . $this->db->lasterror());
1927
        }
1928
1929
        return $list;
1930
    }
1931
1932
    /**
1933
     * Get the list of tickets categories.
1934
     *
1935
     * @param string    $sortfield  Sort field
1936
     * @param string    $sortorder  Sort order
1937
     * @param int       $limit      Number of items per page
1938
     * @param int       $page       Page number (starting from zero)
1939
     * @param int       $active     Payment term is active or not {@min 0} {@max 1}
1940
     * @param string    $lang       Code of the language the label of the category must be translated to
1941
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
1942
     * @return array                List of ticket categories
1943
     *
1944
     * @url     GET dictionary/ticket_categories
1945
     *
1946
     * @throws  RestException   400     Bad value for sqlfilters
1947
     * @throws  RestException   503     Error when retrieving list of tickets categories
1948
     */
1949
    public function getTicketsCategories($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $lang = '', $sqlfilters = '')
1950
    {
1951
        $list = array();
1952
1953
        $sql = "SELECT rowid, code, pos,  label, use_default, description";
1954
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_ticket_category as t";
1955
        $sql .= " WHERE t.entity IN (" . getEntity('c_ticket_category') . ")";
1956
        $sql .= " AND t.active = " . ((int) $active);
1957
        // Add sql filters
1958
        if ($sqlfilters) {
1959
            $errormessage = '';
1960
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
1961
            if ($errormessage) {
1962
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
1963
            }
1964
        }
1965
1966
1967
        $sql .= $this->db->order($sortfield, $sortorder);
1968
1969
        if ($limit) {
1970
            if ($page < 0) {
1971
                $page = 0;
1972
            }
1973
            $offset = $limit * $page;
1974
1975
            $sql .= $this->db->plimit($limit, $offset);
1976
        }
1977
1978
        $result = $this->db->query($sql);
1979
1980
        if ($result) {
1981
            $num = $this->db->num_rows($result);
1982
            $min = min($num, ($limit <= 0 ? $num : $limit));
1983
            for ($i = 0; $i < $min; $i++) {
1984
                $category = $this->db->fetch_object($result);
1985
                $this->translateLabel($category, $lang, 'TicketCategoryShort', array('ticket'));
1986
                $list[] = $category;
1987
            }
1988
        } else {
1989
            throw new RestException(503, 'Error when retrieving list of ticket categories : ' . $this->db->lasterror());
1990
        }
1991
1992
        return $list;
1993
    }
1994
1995
    /**
1996
     * Get the list of tickets severity.
1997
     *
1998
     * @param string    $sortfield  Sort field
1999
     * @param string    $sortorder  Sort order
2000
     * @param int       $limit      Number of items per page
2001
     * @param int       $page       Page number (starting from zero)
2002
     * @param int       $active     Payment term is active or not {@min 0} {@max 1}
2003
     * @param string    $lang       Code of the language the label of the severity must be translated to
2004
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
2005
     * @return array                List of ticket severities
2006
     *
2007
     * @url     GET dictionary/ticket_severities
2008
     *
2009
     * @throws  RestException   400     Bad value for sqlfilters
2010
     * @throws  RestException   503     Error when retrieving list of tickets severities
2011
     */
2012
    public function getTicketsSeverities($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $lang = '', $sqlfilters = '')
2013
    {
2014
        $list = array();
2015
2016
        $sql = "SELECT rowid, code, pos,  label, use_default, color, description";
2017
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_ticket_severity as t";
2018
        $sql .= " WHERE t.entity IN (" . getEntity('c_ticket_severity') . ")";
2019
        $sql .= " AND t.active = " . ((int) $active);
2020
        // Add sql filters
2021
        if ($sqlfilters) {
2022
            $errormessage = '';
2023
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
2024
            if ($errormessage) {
2025
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
2026
            }
2027
        }
2028
2029
2030
        $sql .= $this->db->order($sortfield, $sortorder);
2031
2032
        if ($limit) {
2033
            if ($page < 0) {
2034
                $page = 0;
2035
            }
2036
            $offset = $limit * $page;
2037
2038
            $sql .= $this->db->plimit($limit, $offset);
2039
        }
2040
2041
        $result = $this->db->query($sql);
2042
2043
        if ($result) {
2044
            $num = $this->db->num_rows($result);
2045
            $min = min($num, ($limit <= 0 ? $num : $limit));
2046
            for ($i = 0; $i < $min; $i++) {
2047
                $severity = $this->db->fetch_object($result);
2048
                $this->translateLabel($severity, $lang, 'TicketSeverityShort', array('ticket'));
2049
                $list[] = $severity;
2050
            }
2051
        } else {
2052
            throw new RestException(503, 'Error when retrieving list of ticket severities : ' . $this->db->lasterror());
2053
        }
2054
2055
        return $list;
2056
    }
2057
2058
    /**
2059
     * Get the list of tickets types.
2060
     *
2061
     * @param string    $sortfield  Sort field
2062
     * @param string    $sortorder  Sort order
2063
     * @param int       $limit      Number of items per page
2064
     * @param int       $page       Page number (starting from zero)
2065
     * @param int       $active     Payment term is active or not {@min 0} {@max 1}
2066
     * @param string    $lang       Code of the language the label of the type must be translated to
2067
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
2068
     * @return array                List of ticket types
2069
     *
2070
     * @url     GET dictionary/ticket_types
2071
     *
2072
     * @throws RestException 400 Bad value for sqlfilters
2073
     * @throws RestException 503 Error when retrieving list of tickets types
2074
     */
2075
    public function getTicketsTypes($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $lang = '', $sqlfilters = '')
2076
    {
2077
        $list = array();
2078
2079
        $sql = "SELECT rowid, code, pos,  label, use_default, description";
2080
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_ticket_type as t";
2081
        $sql .= " WHERE t.entity IN (" . getEntity('c_ticket_type') . ")";
2082
        $sql .= " AND t.active = " . ((int) $active);
2083
2084
        // Add sql filters
2085
        if ($sqlfilters) {
2086
            $errormessage = '';
2087
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
2088
            if ($errormessage) {
2089
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
2090
            }
2091
        }
2092
2093
2094
        $sql .= $this->db->order($sortfield, $sortorder);
2095
2096
        if ($limit) {
2097
            if ($page < 0) {
2098
                $page = 0;
2099
            }
2100
            $offset = $limit * $page;
2101
2102
            $sql .= $this->db->plimit($limit, $offset);
2103
        }
2104
2105
        $result = $this->db->query($sql);
2106
2107
        if ($result) {
2108
            $num = $this->db->num_rows($result);
2109
            $min = min($num, ($limit <= 0 ? $num : $limit));
2110
            for ($i = 0; $i < $min; $i++) {
2111
                $type = $this->db->fetch_object($result);
2112
                $this->translateLabel($type, $lang, 'TicketTypeShort', array('ticket'));
2113
                $list[] = $type;
2114
            }
2115
        } else {
2116
            throw new RestException(503, 'Error when retrieving list of ticket types : ' . $this->db->lasterror());
2117
        }
2118
2119
        return $list;
2120
    }
2121
2122
    /**
2123
     * Get the list of incoterms.
2124
     *
2125
     * @param string    $sortfield  Sort field
2126
     * @param string    $sortorder  Sort order
2127
     * @param int       $limit      Number of items per page
2128
     * @param int       $page       Page number (starting from zero)
2129
     * @param int       $active     Payment term is active or not {@min 0} {@max 1}
2130
     * @param string    $lang       Code of the language the label of the type must be translated to
2131
     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
2132
     * @return array                List of incoterm types
2133
     *
2134
     * @url     GET dictionary/incoterms
2135
     *
2136
     * @throws RestException 503 Error when retrieving list of incoterms types
2137
     */
2138
    public function getListOfIncoterms($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $lang = '', $sqlfilters = '')
2139
    {
2140
        $list = array();
2141
2142
        $sql = "SELECT rowid, code, active";
2143
        $sql .= " FROM " . MAIN_DB_PREFIX . "c_incoterms as t";
2144
        $sql .= " WHERE 1=1";
2145
2146
        // Add sql filters
2147
        if ($sqlfilters) {
2148
            $errormessage = '';
2149
            if (!DolibarrApi::_checkFilters($sqlfilters, $errormessage)) {
2150
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
2151
            }
2152
            $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
2153
            $sql .= " AND (" . preg_replace_callback('/' . $regexstring . '/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters) . ")";
2154
        }
2155
2156
2157
        $sql .= $this->db->order($sortfield, $sortorder);
2158
2159
        if ($limit) {
2160
            if ($page < 0) {
2161
                $page = 0;
2162
            }
2163
            $offset = $limit * $page;
2164
2165
            $sql .= $this->db->plimit($limit, $offset);
2166
        }
2167
2168
        $result = $this->db->query($sql);
2169
2170
        if ($result) {
2171
            $num = $this->db->num_rows($result);
2172
            $min = min($num, ($limit <= 0 ? $num : $limit));
2173
            for ($i = 0; $i < $min; $i++) {
2174
                $type = $this->db->fetch_object($result);
2175
                $list[] = $type;
2176
            }
2177
        } else {
2178
            throw new RestException(503, 'Error when retrieving list of incoterm types : ' . $this->db->lasterror());
2179
        }
2180
2181
        return $list;
2182
    }
2183
2184
    /**
2185
     * Get properties of company
2186
     *
2187
     * @url GET /company
2188
     *
2189
     * @return  array|mixed Mysoc object
2190
     *
2191
     * @throws RestException 403 Forbidden
2192
     */
2193
    public function getCompany()
2194
    {
2195
        global $conf, $mysoc;
2196
2197
        if (
2198
            !DolibarrApiAccess::$user->admin
2199
            && (!getDolGlobalString('API_LOGINS_ALLOWED_FOR_GET_COMPANY') || DolibarrApiAccess::$user->login != $conf->global->API_LOGINS_ALLOWED_FOR_GET_COMPANY)
2200
        ) {
2201
            throw new RestException(403, 'Error API open to admin users only or to the users with logins defined into constant API_LOGINS_ALLOWED_FOR_GET_COMPANY');
2202
        }
2203
2204
        unset($mysoc->pays);
2205
        unset($mysoc->note);
2206
        unset($mysoc->nom);
2207
2208
        unset($mysoc->lines);
2209
2210
        unset($mysoc->effectif);
2211
        unset($mysoc->effectif_id);
2212
        unset($mysoc->forme_juridique_code);
2213
        unset($mysoc->forme_juridique);
2214
        unset($mysoc->mode_reglement_supplier_id);
2215
        unset($mysoc->cond_reglement_supplier_id);
2216
        unset($mysoc->transport_mode_supplier_id);
2217
        unset($mysoc->fk_prospectlevel);
2218
2219
        unset($mysoc->total_ht);
2220
        unset($mysoc->total_tva);
2221
        unset($mysoc->total_localtax1);
2222
        unset($mysoc->total_localtax2);
2223
        unset($mysoc->total_ttc);
2224
2225
        unset($mysoc->lastname);
2226
        unset($mysoc->firstname);
2227
        unset($mysoc->civility_id);
2228
2229
        unset($mysoc->client);
2230
        unset($mysoc->prospect);
2231
        unset($mysoc->fournisseur);
2232
        unset($mysoc->contact_id);
2233
2234
        unset($mysoc->fk_incoterms);
2235
        unset($mysoc->label_incoterms);
2236
        unset($mysoc->location_incoterms);
2237
2238
        return $this->_cleanObjectDatas($mysoc);
2239
    }
2240
2241
    /**
2242
     * Get the list of establishments.
2243
     *
2244
     * @return array                List of establishments
2245
     *
2246
     * @url     GET /establishments
2247
     *
2248
     * @throws RestException 503 Error when retrieving list of establishments
2249
     */
2250
    public function getEstablishments()
2251
    {
2252
        $list = array();
2253
2254
        $limit = 0;
2255
2256
        $sql = "SELECT e.rowid, e.rowid as ref, e.label, e.address, e.zip, e.town, e.status";
2257
        $sql .= " FROM " . MAIN_DB_PREFIX . "establishment as e";
2258
        $sql .= " WHERE e.entity IN (" . getEntity('establishment') . ')';
2259
        // if ($type) $sql .= " AND t.type LIKE '%".$this->db->escape($type)."%'";
2260
        // if ($module)    $sql .= " AND t.module LIKE '%".$this->db->escape($module)."%'";
2261
        // Add sql filters
2262
2263
        $result = $this->db->query($sql);
2264
2265
        if ($result) {
2266
            $num = $this->db->num_rows($result);
2267
            $min = min($num, ($limit <= 0 ? $num : $limit));
2268
            for ($i = 0; $i < $min; $i++) {
2269
                $list[] = $this->db->fetch_object($result);
2270
            }
2271
        } else {
2272
            throw new RestException(503, 'Error when retrieving list of establishments : ' . $this->db->lasterror());
2273
        }
2274
2275
        return $list;
2276
    }
2277
2278
    /**
2279
     * Get establishment by ID.
2280
     *
2281
     * @param   int       $id           ID of establishment
2282
     * @return  Object                  Object with cleaned properties
2283
     *
2284
     * @url     GET establishments/{id}
2285
     *
2286
     * @throws RestException 404 Establishment not found
2287
     * @throws RestException 503 Error when retrieving establishment
2288
     */
2289
    public function getEtablishmentByID($id)
2290
    {
2291
        $establishment = new Establishment($this->db);
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Api\Api\Establishment was not found. Did you mean Establishment? If so, make sure to prefix the type with \.
Loading history...
2292
2293
        $result = $establishment->fetch($id);
2294
        if ($result < 0) {
2295
            throw new RestException(503, 'Error when retrieving establishment : ' . $establishment->error);
2296
        } elseif ($result == 0) {
2297
            throw new RestException(404, 'Establishment not found');
2298
        }
2299
2300
        return $this->_cleanObjectDatas($establishment);
2301
    }
2302
2303
    /**
2304
     * Get value of a setup variables
2305
     *
2306
     * Note that conf variables that stores security key or password hashes can't be loaded with API.
2307
     *
2308
     * @param   string          $constantname   Name of conf variable to get
2309
     * @return  string                          Data without useless information
2310
     *
2311
     * @url     GET conf/{constantname}
2312
     *
2313
     * @throws RestException 400 Error Bad or unknown value for constantname
2314
     * @throws RestException 403 Forbidden
2315
     */
2316
    public function getConf($constantname)
2317
    {
2318
        global $conf;
2319
2320
        if (
2321
            !DolibarrApiAccess::$user->admin
2322
            && (!getDolGlobalString('API_LOGINS_ALLOWED_FOR_CONST_READ') || DolibarrApiAccess::$user->login != getDolGlobalString('API_LOGINS_ALLOWED_FOR_CONST_READ'))
2323
        ) {
2324
            throw new RestException(403, 'Error API open to admin users only or to the users with logins defined into constant API_LOGINS_ALLOWED_FOR_CONST_READ');
2325
        }
2326
2327
        if (!preg_match('/^[a-zA-Z0-9_]+$/', $constantname) || !isset($conf->global->$constantname)) {
2328
            throw new RestException(400, 'Error Bad or unknown value for constantname');
2329
        }
2330
        if (isASecretKey($constantname)) {
2331
            throw new RestException(403, 'Forbidden. This parameter can not be read with APIs');
2332
        }
2333
2334
        return getDolGlobalString($constantname);
2335
    }
2336
2337
    /**
2338
     * Do a test of integrity for files and setup.
2339
     *
2340
     * @param string    $target         Can be 'local' or 'default' or Url of the signatures file to use for the test. Must be reachable by the tested Dolibarr.
2341
     * @return array                    Result of file and setup integrity check
2342
     *
2343
     * @url     GET checkintegrity
2344
     *
2345
     * @throws RestException 403 Forbidden
2346
     * @throws RestException 404 Signature file not found
2347
     * @throws RestException 500 Technical error
2348
     */
2349
    public function getCheckIntegrity($target)
2350
    {
2351
        global $langs, $conf;
2352
2353
        if (
2354
            !DolibarrApiAccess::$user->admin
2355
            && (!getDolGlobalString('API_LOGINS_ALLOWED_FOR_INTEGRITY_CHECK') || DolibarrApiAccess::$user->login != $conf->global->API_LOGINS_ALLOWED_FOR_INTEGRITY_CHECK)
2356
        ) {
2357
            throw new RestException(403, 'Error API open to admin users only or to the users with logins defined into constant API_LOGINS_ALLOWED_FOR_INTEGRITY_CHECK');
2358
        }
2359
2360
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
2361
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/geturl.lib.php';
2362
2363
        $langs->load("admin");
2364
2365
        $outexpectedchecksum = '';
2366
        $outcurrentchecksum = '';
2367
2368
        // Modified or missing files
2369
        $file_list = array('missing' => array(), 'updated' => array());
2370
2371
        // Local file to compare to
2372
        $xmlshortfile = dol_sanitizeFileName('filelist-' . DOL_VERSION . getDolGlobalString('MAIN_FILECHECK_LOCAL_SUFFIX') . '.xml' . getDolGlobalString('MAIN_FILECHECK_LOCAL_EXT'));
2373
2374
        $xmlfile = DOL_DOCUMENT_ROOT . '/install/' . $xmlshortfile;
2375
        if (!preg_match('/\.zip$/i', $xmlfile) && dol_is_file($xmlfile . '.zip')) {
2376
            $xmlfile = $xmlfile . '.zip';
2377
        }
2378
2379
        // Remote file to compare to
2380
        $xmlremote = (($target == 'default' || $target == 'local') ? '' : $target);
2381
        if (empty($xmlremote) && getDolGlobalString('MAIN_FILECHECK_URL')) {
2382
            $xmlremote = getDolGlobalString('MAIN_FILECHECK_URL');
2383
        }
2384
        $param = 'MAIN_FILECHECK_URL_' . DOL_VERSION;
2385
        if (empty($xmlremote) && getDolGlobalString($param)) {
2386
            $xmlremote = getDolGlobalString($param);
2387
        }
2388
        if (empty($xmlremote)) {
2389
            $xmlremote = 'https://www.dolibarr.org/files/stable/signatures/filelist-' . DOL_VERSION . '.xml';
2390
        }
2391
        if ($xmlremote && !preg_match('/^https?:\/\//i', $xmlremote)) {
2392
            $langs->load("errors");
2393
            throw new RestException(500, $langs->trans("ErrorURLMustStartWithHttp", $xmlremote));
2394
        }
2395
        if ($xmlremote && !preg_match('/\.xml$/', $xmlremote)) {
2396
            $langs->load("errors");
2397
            throw new RestException(500, $langs->trans("ErrorURLMustEndWith", $xmlremote, '.xml'));
2398
        }
2399
2400
        if (LIBXML_VERSION < 20900) {
2401
            // Avoid load of external entities (security problem).
2402
            // Required only if LIBXML_VERSION < 20900
2403
            // @phan-suppress-next-line PhanDeprecatedFunctionInternal
2404
            libxml_disable_entity_loader(true);
2405
        }
2406
2407
        if ($target == 'local') {
2408
            if (dol_is_file($xmlfile)) {
2409
                $xml = simplexml_load_file($xmlfile);
2410
            } else {
2411
                throw new RestException(500, $langs->trans('XmlNotFound') . ': /install/' . $xmlshortfile);
2412
            }
2413
        } else {
2414
            $xmlarray = getURLContent($xmlremote, 'GET', '', 1, array(), array('http', 'https'), 0);    // Accept http or https links on external remote server only. Same is used into filecheck.php.
2415
2416
            // Return array('content'=>response,'curl_error_no'=>errno,'curl_error_msg'=>errmsg...)
2417
            if (!$xmlarray['curl_error_no'] && $xmlarray['http_code'] != '400' && $xmlarray['http_code'] != '404') {
2418
                $xmlfile = $xmlarray['content'];
2419
                //print "xmlfilestart".$xmlfile."endxmlfile";
2420
                $xml = simplexml_load_string($xmlfile, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NONET);
2421
            } else {
2422
                $errormsg = $langs->trans('XmlNotFound') . ': ' . $xmlremote . ' - ' . $xmlarray['http_code'] . (($xmlarray['http_code'] == 400 && $xmlarray['content']) ? ' ' . $xmlarray['content'] : '') . ' ' . $xmlarray['curl_error_no'] . ' ' . $xmlarray['curl_error_msg'];
2423
                throw new RestException(500, $errormsg);
2424
            }
2425
        }
2426
2427
        if ($xml) {
2428
            $checksumconcat = array();
2429
            $file_list = array();
2430
            $out = '';
2431
2432
            // Forced constants
2433
            if (is_object($xml->dolibarr_constants[0])) {
2434
                $out .= load_fiche_titre($langs->trans("ForcedConstants"));
2435
2436
                $out .= '<div class="div-table-responsive-no-min">';
2437
                $out .= '<table class="noborder">';
2438
                $out .= '<tr class="liste_titre">';
2439
                $out .= '<td>#</td>';
2440
                $out .= '<td>' . $langs->trans("Constant") . '</td>';
2441
                $out .= '<td class="center">' . $langs->trans("ExpectedValue") . '</td>';
2442
                $out .= '<td class="center">' . $langs->trans("Value") . '</td>';
2443
                $out .= '</tr>' . "\n";
2444
2445
                $i = 0;
2446
                foreach ($xml->dolibarr_constants[0]->constant as $constant) {    // $constant is a simpleXMLElement
2447
                    $constname = $constant['name'];
2448
                    $constvalue = (string) $constant;
2449
                    $constvalue = (empty($constvalue) ? '0' : $constvalue);
2450
                    // Value found
2451
                    $value = '';
2452
                    if ($constname && getDolGlobalString($constname) != '') {
2453
                        $value = getDolGlobalString($constname);
2454
                    }
2455
                    $valueforchecksum = (empty($value) ? '0' : $value);
2456
2457
                    $checksumconcat[] = $valueforchecksum;
2458
2459
                    $i++;
2460
                    $out .= '<tr class="oddeven">';
2461
                    $out .= '<td>' . $i . '</td>' . "\n";
2462
                    $out .= '<td>' . dol_escape_htmltag($constname) . '</td>' . "\n";
2463
                    $out .= '<td class="center">' . dol_escape_htmltag($constvalue) . '</td>' . "\n";
2464
                    $out .= '<td class="center">' . dol_escape_htmltag($valueforchecksum) . '</td>' . "\n";
2465
                    $out .= "</tr>\n";
2466
                }
2467
2468
                if ($i == 0) {
2469
                    $out .= '<tr class="oddeven"><td colspan="4" class="opacitymedium">' . $langs->trans("None") . '</td></tr>';
2470
                }
2471
                $out .= '</table>';
2472
                $out .= '</div>';
2473
2474
                $out .= '<br>';
2475
            }
2476
2477
            // Scan htdocs
2478
            if (is_object($xml->dolibarr_htdocs_dir[0])) {
2479
                $includecustom = (empty($xml->dolibarr_htdocs_dir[0]['includecustom']) ? 0 : $xml->dolibarr_htdocs_dir[0]['includecustom']);
2480
2481
                // Define qualified files (must be same than into generate_filelist_xml.php and in api_setup.class.php)
2482
                $regextoinclude = '\.(php|php3|php4|php5|phtml|phps|phar|inc|css|scss|html|xml|js|json|tpl|jpg|jpeg|png|gif|ico|sql|lang|txt|yml|bak|md|mp3|mp4|wav|mkv|z|gz|zip|rar|tar|less|svg|eot|woff|woff2|ttf|manifest)$';
2483
                $regextoexclude = '(' . ($includecustom ? '' : 'custom|') . 'documents|conf|install|dejavu-fonts-ttf-.*|public\/test|sabre\/sabre\/.*\/tests|Shared\/PCLZip|nusoap\/lib\/Mail|php\/example|php\/test|geoip\/sample.*\.php|ckeditor\/samples|ckeditor\/adapters)$'; // Exclude dirs
2484
                $scanfiles = dol_dir_list(DOL_DOCUMENT_ROOT, 'files', 1, $regextoinclude, $regextoexclude);
2485
2486
                // Fill file_list with files in signature, new files, modified files
2487
                $ret = getFilesUpdated($file_list, $xml->dolibarr_htdocs_dir[0], '', DOL_DOCUMENT_ROOT, $checksumconcat); // Fill array $file_list
2488
                // Complete with list of new files
2489
                foreach ($scanfiles as $keyfile => $valfile) {
2490
                    $tmprelativefilename = preg_replace('/^' . preg_quote(DOL_DOCUMENT_ROOT, '/') . '/', '', $valfile['fullname']);
2491
                    if (!in_array($tmprelativefilename, $file_list['insignature'])) {
2492
                        $md5newfile = @md5_file($valfile['fullname']); // Can fails if we don't have permission to open/read file
2493
                        $file_list['added'][] = array('filename' => $tmprelativefilename, 'md5' => $md5newfile);
2494
                    }
2495
                }
2496
2497
                // Files missing
2498
                $out .= load_fiche_titre($langs->trans("FilesMissing"));
2499
2500
                $out .= '<div class="div-table-responsive-no-min">';
2501
                $out .= '<table class="noborder">';
2502
                $out .= '<tr class="liste_titre">';
2503
                $out .= '<td>#</td>';
2504
                $out .= '<td>' . $langs->trans("Filename") . '</td>';
2505
                $out .= '<td class="center">' . $langs->trans("ExpectedChecksum") . '</td>';
2506
                $out .= '</tr>' . "\n";
2507
                $tmpfilelist = dol_sort_array($file_list['missing'], 'filename');
2508
                if (is_array($tmpfilelist) && count($tmpfilelist)) {
2509
                    $i = 0;
2510
                    foreach ($tmpfilelist as $file) {
2511
                        $i++;
2512
                        $out .= '<tr class="oddeven">';
2513
                        $out .= '<td>' . $i . '</td>' . "\n";
2514
                        $out .= '<td>' . dol_escape_htmltag($file['filename']) . '</td>' . "\n";
2515
                        $out .= '<td class="center">' . $file['expectedmd5'] . '</td>' . "\n";
2516
                        $out .= "</tr>\n";
2517
                    }
2518
                } else {
2519
                    $out .= '<tr class="oddeven"><td colspan="3" class="opacitymedium">' . $langs->trans("None") . '</td></tr>';
2520
                }
2521
                $out .= '</table>';
2522
                $out .= '</div>';
2523
2524
                $out .= '<br>';
2525
2526
                // Files modified
2527
                $out .= load_fiche_titre($langs->trans("FilesModified"));
2528
2529
                $totalsize = 0;
2530
                $out .= '<div class="div-table-responsive-no-min">';
2531
                $out .= '<table class="noborder">';
2532
                $out .= '<tr class="liste_titre">';
2533
                $out .= '<td>#</td>';
2534
                $out .= '<td>' . $langs->trans("Filename") . '</td>';
2535
                $out .= '<td class="center">' . $langs->trans("ExpectedChecksum") . '</td>';
2536
                $out .= '<td class="center">' . $langs->trans("CurrentChecksum") . '</td>';
2537
                $out .= '<td class="right">' . $langs->trans("Size") . '</td>';
2538
                $out .= '<td class="right">' . $langs->trans("DateModification") . '</td>';
2539
                $out .= '</tr>' . "\n";
2540
                $tmpfilelist2 = dol_sort_array($file_list['updated'], 'filename');
2541
                if (is_array($tmpfilelist2) && count($tmpfilelist2)) {
2542
                    $i = 0;
2543
                    foreach ($tmpfilelist2 as $file) {
2544
                        $i++;
2545
                        $out .= '<tr class="oddeven">';
2546
                        $out .= '<td>' . $i . '</td>' . "\n";
2547
                        $out .= '<td>' . dol_escape_htmltag($file['filename']) . '</td>' . "\n";
2548
                        $out .= '<td class="center">' . $file['expectedmd5'] . '</td>' . "\n";
2549
                        $out .= '<td class="center">' . $file['md5'] . '</td>' . "\n";
2550
                        $size = dol_filesize(DOL_DOCUMENT_ROOT . '/' . $file['filename']);
2551
                        $totalsize += $size;
2552
                        $out .= '<td class="right">' . dol_print_size($size) . '</td>' . "\n";
2553
                        $out .= '<td class="right">' . dol_print_date(dol_filemtime(DOL_DOCUMENT_ROOT . '/' . $file['filename']), 'dayhour') . '</td>' . "\n";
2554
                        $out .= "</tr>\n";
2555
                    }
2556
                    $out .= '<tr class="liste_total">';
2557
                    $out .= '<td></td>' . "\n";
2558
                    $out .= '<td>' . $langs->trans("Total") . '</td>' . "\n";
2559
                    $out .= '<td align="center"></td>' . "\n";
2560
                    $out .= '<td align="center"></td>' . "\n";
2561
                    $out .= '<td class="right">' . dol_print_size($totalsize) . '</td>' . "\n";
2562
                    $out .= '<td class="right"></td>' . "\n";
2563
                    $out .= "</tr>\n";
2564
                } else {
2565
                    $out .= '<tr class="oddeven"><td colspan="5" class="opacitymedium">' . $langs->trans("None") . '</td></tr>';
2566
                }
2567
                $out .= '</table>';
2568
                $out .= '</div>';
2569
2570
                $out .= '<br>';
2571
2572
                // Files added
2573
                $out .= load_fiche_titre($langs->trans("FilesAdded"));
2574
2575
                $totalsize = 0;
2576
                $out .= '<div class="div-table-responsive-no-min">';
2577
                $out .= '<table class="noborder">';
2578
                $out .= '<tr class="liste_titre">';
2579
                $out .= '<td>#</td>';
2580
                $out .= '<td>' . $langs->trans("Filename") . '</td>';
2581
                $out .= '<td class="center">' . $langs->trans("ExpectedChecksum") . '</td>';
2582
                $out .= '<td class="center">' . $langs->trans("CurrentChecksum") . '</td>';
2583
                $out .= '<td class="right">' . $langs->trans("Size") . '</td>';
2584
                $out .= '<td class="right">' . $langs->trans("DateModification") . '</td>';
2585
                $out .= '</tr>' . "\n";
2586
                $tmpfilelist3 = dol_sort_array($file_list['added'], 'filename');
2587
                if (is_array($tmpfilelist3) && count($tmpfilelist3)) {
2588
                    $i = 0;
2589
                    foreach ($tmpfilelist3 as $file) {
2590
                        $i++;
2591
                        $out .= '<tr class="oddeven">';
2592
                        $out .= '<td>' . $i . '</td>' . "\n";
2593
                        $out .= '<td>' . dol_escape_htmltag($file['filename']) . '</td>' . "\n";
2594
                        $out .= '<td class="center">' . $file['expectedmd5'] . '</td>' . "\n";
2595
                        $out .= '<td class="center">' . $file['md5'] . '</td>' . "\n";
2596
                        $size = dol_filesize(DOL_DOCUMENT_ROOT . '/' . $file['filename']);
2597
                        $totalsize += $size;
2598
                        $out .= '<td class="right">' . dol_print_size($size) . '</td>' . "\n";
2599
                        $out .= '<td class="right">' . dol_print_date(dol_filemtime(DOL_DOCUMENT_ROOT . '/' . $file['filename']), 'dayhour') . '</td>' . "\n";
2600
                        $out .= "</tr>\n";
2601
                    }
2602
                    $out .= '<tr class="liste_total">';
2603
                    $out .= '<td></td>' . "\n";
2604
                    $out .= '<td>' . $langs->trans("Total") . '</td>' . "\n";
2605
                    $out .= '<td align="center"></td>' . "\n";
2606
                    $out .= '<td align="center"></td>' . "\n";
2607
                    $out .= '<td class="right">' . dol_print_size($totalsize) . '</td>' . "\n";
2608
                    $out .= '<td class="right"></td>' . "\n";
2609
                    $out .= "</tr>\n";
2610
                } else {
2611
                    $out .= '<tr class="oddeven"><td colspan="5" class="opacitymedium">' . $langs->trans("None") . '</td></tr>';
2612
                }
2613
                $out .= '</table>';
2614
                $out .= '</div>';
2615
2616
2617
                // Show warning
2618
                if (empty($tmpfilelist) && empty($tmpfilelist2) && empty($tmpfilelist3)) {
2619
                    //setEventMessages($langs->trans("FileIntegrityIsStrictlyConformedWithReference"), null, 'mesgs');
2620
                } else {
2621
                    //setEventMessages($langs->trans("FileIntegritySomeFilesWereRemovedOrModified"), null, 'warnings');
2622
                }
2623
            } else {
2624
                throw new RestException(500, 'Error: Failed to found dolibarr_htdocs_dir into XML file ' . $xmlfile);
2625
            }
2626
2627
2628
            // Scan scripts
2629
            asort($checksumconcat); // Sort list of checksum
2630
            $checksumget = md5(implode(',', $checksumconcat));
2631
            $checksumtoget = trim((string) $xml->dolibarr_htdocs_dir_checksum);
2632
2633
            $outexpectedchecksum = ($checksumtoget ? $checksumtoget : $langs->trans("Unknown"));
2634
            if ($checksumget == $checksumtoget) {
2635
                if (count($file_list['added'])) {
2636
                    $resultcode = 'warning';
2637
                    $resultcomment = 'FileIntegrityIsOkButFilesWereAdded';
2638
                    //$outcurrentchecksum =  $checksumget.' - <span class="'.$resultcode.'">'.$langs->trans("FileIntegrityIsOkButFilesWereAdded").'</span>';
2639
                    $outcurrentchecksum = $checksumget;
2640
                } else {
2641
                    $resultcode = 'ok';
2642
                    $resultcomment = 'Success';
2643
                    //$outcurrentchecksum = '<span class="'.$resultcode.'">'.$checksumget.'</span>';
2644
                    $outcurrentchecksum = $checksumget;
2645
                }
2646
            } else {
2647
                $resultcode = 'error';
2648
                $resultcomment = 'Error';
2649
                //$outcurrentchecksum = '<span class="'.$resultcode.'">'.$checksumget.'</span>';
2650
                $outcurrentchecksum = $checksumget;
2651
            }
2652
        } else {
2653
            throw new RestException(404, 'No signature file known');
2654
        }
2655
2656
        return array('resultcode' => $resultcode, 'resultcomment' => $resultcomment, 'expectedchecksum' => $outexpectedchecksum, 'currentchecksum' => $outcurrentchecksum, 'out' => $out);
2657
    }
2658
2659
2660
    /**
2661
     * Get list of enabled modules
2662
     *
2663
     * @url GET /modules
2664
     *
2665
     * @return  array|mixed Data without useless information
2666
     *
2667
     * @throws RestException 403 Forbidden
2668
     */
2669
    public function getModules()
2670
    {
2671
        global $conf;
2672
2673
        if (
2674
            !DolibarrApiAccess::$user->admin
2675
            && (!getDolGlobalString('API_LOGINS_ALLOWED_FOR_GET_MODULES') || DolibarrApiAccess::$user->login != $conf->global->API_LOGINS_ALLOWED_FOR_GET_MODULES)
2676
        ) {
2677
            throw new RestException(403, 'Error API open to admin users only or to the users with logins defined into constant API_LOGINS_ALLOWED_FOR_GET_MODULES');
2678
        }
2679
2680
        sort($conf->modules);
2681
2682
        return $this->_cleanObjectDatas($conf->modules);
2683
    }
2684
}
2685