Passed
Pull Request — dev (#8)
by Rafael
58:47
created

Orders::index()   F

Complexity

Conditions 21
Paths 2017

Size

Total Lines 89
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 21
eloc 56
nc 2017
nop 8
dl 0
loc 89
rs 0
c 0
b 0
f 0

How to fix   Long Method    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) 2015       Jean-François Ferry         <[email protected]>
4
 * Copyright (C) 2016	    Laurent Destailleur		    <[email protected]>
5
 * Copyright (C) 2024       Rafael San José             <[email protected]>
6
 *
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19
 */
20
21
namespace Dolibarr\Code\Commande\Api;
22
23
use Dolibarr\Code\Api\Classes\DolibarrApiAccess;
24
use Dolibarr\Code\Comm\Classes\Propal;
25
use Dolibarr\Code\Commande\Classes\Commande;
26
use Dolibarr\Core\Base\DolibarrApi;
27
use Luracast\Restler\RestException;
28
29
/**
30
 * API class for orders
31
 *
32
 * @access protected
33
 * @class  DolibarrApiAccess {@requires user,external}
34
 */
35
class Orders extends DolibarrApi
36
{
37
    /**
38
     * @var array $FIELDS Mandatory fields, checked when create and update object
39
     */
40
    public static $FIELDS = array(
41
        'socid',
42
        'date'
43
    );
44
45
    /**
46
     * @var Commande $commande {@type Commande}
47
     */
48
    public $commande;
49
50
    /**
51
     * Constructor
52
     */
53
    public function __construct()
54
    {
55
        global $db, $conf;
56
        $this->db = $db;
57
        $this->commande = new Commande($this->db);
58
    }
59
60
    /**
61
     * Get properties of an order object by ref
62
     *
63
     * Return an array with order information
64
     *
65
     * @param string $ref Ref of object
66
     * @param int $contact_list 0: Returned array of contacts/addresses contains all properties, 1: Return array contains just id
67
     * @return  array|mixed data without useless information
68
     *
69
     * @url GET    ref/{ref}
70
     *
71
     * @throws  RestException
72
     */
73
    public function getByRef($ref, $contact_list = 1)
74
    {
75
        return $this->_fetch('', $ref, '', $contact_list);
76
    }
77
78
    /**
79
     * Get properties of an order object
80
     *
81
     * Return an array with order information
82
     *
83
     * @param int $id ID of order
84
     * @param string $ref Ref of object
85
     * @param string $ref_ext External reference of object
86
     * @param int $contact_list 0: Returned array of contacts/addresses contains all properties, 1: Return array contains just id
87
     * @return      Object                      Object with cleaned properties
88
     *
89
     * @throws  RestException
90
     */
91
    private function _fetch($id, $ref = '', $ref_ext = '', $contact_list = 1)
92
    {
93
        if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
94
            throw new RestException(403);
95
        }
96
97
        $result = $this->commande->fetch($id, $ref, $ref_ext);
98
        if (!$result) {
99
            throw new RestException(404, 'Order not found');
100
        }
101
102
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
103
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
104
        }
105
106
        // Add external contacts ids
107
        $tmparray = $this->commande->liste_contact(-1, 'external', $contact_list);
108
        if (is_array($tmparray)) {
109
            $this->commande->contacts_ids = $tmparray;
110
        }
111
        $this->commande->fetchObjectLinked();
112
113
        // Add online_payment_url, cf #20477
114
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/payments.lib.php';
115
        $this->commande->online_payment_url = getOnlinePaymentUrl(0, 'order', $this->commande->ref);
116
117
        return $this->_cleanObjectDatas($this->commande);
118
    }
119
120
    /**
121
     * Clean sensible object datas
122
     *
123
     * @param Object $object Object to clean
124
     * @return  Object                  Object with cleaned properties
125
     */
126
    protected function _cleanObjectDatas($object)
127
    {
128
        // phpcs:enable
129
        $object = parent::_cleanObjectDatas($object);
130
131
        unset($object->note);
132
        unset($object->address);
133
        unset($object->barcode_type);
134
        unset($object->barcode_type_code);
135
        unset($object->barcode_type_label);
136
        unset($object->barcode_type_coder);
137
138
        return $object;
139
    }
140
141
    /**
142
     * Get properties of an order object by ref_ext
143
     *
144
     * Return an array with order information
145
     *
146
     * @param string $ref_ext External reference of object
147
     * @param int $contact_list 0: Returned array of contacts/addresses contains all properties, 1: Return array contains just id
148
     * @return  array|mixed data without useless information
149
     *
150
     * @url GET    ref_ext/{ref_ext}
151
     *
152
     * @throws  RestException
153
     */
154
    public function getByRefExt($ref_ext, $contact_list = 1)
155
    {
156
        return $this->_fetch('', '', $ref_ext, $contact_list);
157
    }
158
159
    /**
160
     * List orders
161
     *
162
     * Get a list of orders
163
     *
164
     * @param string $sortfield Sort field
165
     * @param string $sortorder Sort order
166
     * @param int $limit Limit for list
167
     * @param int $page Page number
168
     * @param string $thirdparty_ids Thirdparty ids to filter orders of (example '1' or '1,2,3') {@pattern /^[0-9,]*$/i}
169
     * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
170
     * @param string $sqlfilterlines Other criteria to filter answers separated by a comma. Syntax example "(tl.fk_product:=:'17') and (tl.price:<:'250')"
171
     * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names
172
     * @return  array                               Array of order objects
173
     *
174
     * @throws RestException 404 Not found
175
     * @throws RestException 503 Error
176
     */
177
    public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $sqlfilters = '', $sqlfilterlines = '', $properties = '')
178
    {
179
        if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
180
            throw new RestException(403);
181
        }
182
183
        $obj_ret = array();
184
185
        // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
186
        $socids = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : $thirdparty_ids;
187
188
        // If the internal user must only see his customers, force searching by him
189
        $search_sale = 0;
190
        if (!DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socids) {
191
            $search_sale = DolibarrApiAccess::$user->id;
192
        }
193
194
        $sql = "SELECT t.rowid";
195
        $sql .= " FROM " . MAIN_DB_PREFIX . "commande AS t";
196
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "commande_extrafields AS ef ON (ef.fk_object = t.rowid)"; // Modification VMR Global Solutions to include extrafields as search parameters in the API GET call, so we will be able to filter on extrafields
197
        $sql .= ' WHERE t.entity IN (' . getEntity('commande') . ')';
198
        if ($socids) {
199
            $sql .= " AND t.fk_soc IN (" . $this->db->sanitize($socids) . ")";
200
        }
201
        // Search on sale representative
202
        if ($search_sale && $search_sale != '-1') {
203
            if ($search_sale == -2) {
204
                $sql .= " AND NOT EXISTS (SELECT sc.fk_soc FROM " . MAIN_DB_PREFIX . "societe_commerciaux as sc WHERE sc.fk_soc = t.fk_soc)";
205
            } elseif ($search_sale > 0) {
206
                $sql .= " AND EXISTS (SELECT sc.fk_soc FROM " . MAIN_DB_PREFIX . "societe_commerciaux as sc WHERE sc.fk_soc = t.fk_soc AND sc.fk_user = " . ((int)$search_sale) . ")";
207
            }
208
        }
209
        // Add sql filters
210
        if ($sqlfilters) {
211
            $errormessage = '';
212
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
213
            if ($errormessage) {
214
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
215
            }
216
        }
217
        // Add sql filters for lines
218
        if ($sqlfilterlines) {
219
            $errormessage = '';
220
            $sql .= " AND EXISTS (SELECT tl.rowid FROM " . MAIN_DB_PREFIX . "commandedet AS tl WHERE tl.fk_commande = t.rowid";
221
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilterlines, $errormessage);
222
            $sql .= ")";
223
            if ($errormessage) {
224
                throw new RestException(400, 'Error when validating parameter sqlfilterlines -> ' . $errormessage);
225
            }
226
        }
227
        $sql .= $this->db->order($sortfield, $sortorder);
228
        if ($limit) {
229
            if ($page < 0) {
230
                $page = 0;
231
            }
232
            $offset = $limit * $page;
233
234
            $sql .= $this->db->plimit($limit + 1, $offset);
235
        }
236
237
        dol_syslog("API Rest request");
238
        $result = $this->db->query($sql);
239
240
        if ($result) {
241
            $num = $this->db->num_rows($result);
242
            $min = min($num, ($limit <= 0 ? $num : $limit));
243
            $i = 0;
244
            while ($i < $min) {
245
                $obj = $this->db->fetch_object($result);
246
                $commande_static = new Commande($this->db);
247
                if ($commande_static->fetch($obj->rowid)) {
248
                    // Add external contacts ids
249
                    $tmparray = $commande_static->liste_contact(-1, 'external', 1);
250
                    if (is_array($tmparray)) {
251
                        $commande_static->contacts_ids = $tmparray;
252
                    }
253
                    // Add online_payment_url, cf #20477
254
                    require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/payments.lib.php';
255
                    $commande_static->online_payment_url = getOnlinePaymentUrl(0, 'order', $commande_static->ref);
256
257
                    $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($commande_static), $properties);
258
                }
259
                $i++;
260
            }
261
        } else {
262
            throw new RestException(503, 'Error when retrieve commande list : ' . $this->db->lasterror());
263
        }
264
265
        return $obj_ret;
266
    }
267
268
    /**
269
     * Create a sale order
270
     *
271
     * Example: { "socid": 2, "date": 1595196000, "type": 0, "lines": [{ "fk_product": 2, "qty": 1 }] }
272
     *
273
     * @param array $request_data Request data
274
     * @return  int     ID of order
275
     */
276
    public function post($request_data = null)
277
    {
278
        if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
279
            throw new RestException(403, "Insuffisant rights");
280
        }
281
        // Check mandatory fields
282
        $result = $this->_validate($request_data);
283
284
        foreach ($request_data as $field => $value) {
285
            if ($field === 'caller') {
286
                // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller
287
                $this->commande->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
288
                continue;
289
            }
290
291
            $this->commande->$field = $this->_checkValForAPI($field, $value, $this->commande);
292
        }
293
        /*if (isset($request_data["lines"])) {
294
          $lines = array();
295
          foreach ($request_data["lines"] as $line) {
296
            array_push($lines, (object) $line);
297
          }
298
          $this->commande->lines = $lines;
299
        }*/
300
301
        if ($this->commande->create(DolibarrApiAccess::$user) < 0) {
302
            throw new RestException(500, "Error creating order", array_merge(array($this->commande->error), $this->commande->errors));
303
        }
304
305
        return ((int)$this->commande->id);
306
    }
307
308
    /**
309
     * Validate fields before create or update object
310
     *
311
     * @param array $data Array with data to verify
312
     * @return  array
313
     * @throws  RestException
314
     */
315
    private function _validate($data)
316
    {
317
        $commande = array();
318
        foreach (Orders::$FIELDS as $field) {
319
            if (!isset($data[$field])) {
320
                throw new RestException(400, $field . " field missing");
321
            }
322
            $commande[$field] = $data[$field];
323
        }
324
        return $commande;
325
    }
326
327
    /**
328
     * Get lines of an order
329
     *
330
     * @param int $id Id of order
331
     *
332
     * @url GET {id}/lines
333
     *
334
     * @return array
335
     */
336
    public function getLines($id)
337
    {
338
        if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
339
            throw new RestException(403);
340
        }
341
342
        $result = $this->commande->fetch($id);
343
        if (!$result) {
344
            throw new RestException(404, 'Order not found');
345
        }
346
347
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
348
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
349
        }
350
        $this->commande->getLinesArray();
351
        $result = array();
352
        foreach ($this->commande->lines as $line) {
353
            array_push($result, $this->_cleanObjectDatas($line));
354
        }
355
        return $result;
356
    }
357
358
    /**
359
     * Add a line to given order
360
     *
361
     * @param int $id Id of order to update
362
     * @param array $request_data OrderLine data
363
     *
364
     * @url POST {id}/lines
365
     *
366
     * @return int
367
     */
368
    public function postLine($id, $request_data = null)
369
    {
370
        if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
371
            throw new RestException(403);
372
        }
373
374
        $result = $this->commande->fetch($id);
375
        if (!$result) {
376
            throw new RestException(404, 'Order not found');
377
        }
378
379
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
380
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
381
        }
382
383
        $request_data = (object)$request_data;
384
385
        $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
386
        $request_data->label = sanitizeVal($request_data->label);
387
388
        $updateRes = $this->commande->addline(
389
            $request_data->desc,
390
            $request_data->subprice,
391
            $request_data->qty,
392
            $request_data->tva_tx,
393
            $request_data->localtax1_tx,
394
            $request_data->localtax2_tx,
395
            $request_data->fk_product,
396
            $request_data->remise_percent,
397
            $request_data->info_bits,
398
            $request_data->fk_remise_except,
399
            $request_data->price_base_type ? $request_data->price_base_type : 'HT',
400
            $request_data->subprice,
401
            $request_data->date_start,
402
            $request_data->date_end,
403
            $request_data->product_type,
404
            $request_data->rang,
405
            $request_data->special_code,
406
            $request_data->fk_parent_line,
407
            $request_data->fk_fournprice,
408
            $request_data->pa_ht,
409
            $request_data->label,
410
            $request_data->array_options,
411
            $request_data->fk_unit,
412
            $request_data->origin,
413
            $request_data->origin_id,
414
            $request_data->multicurrency_subprice,
415
            $request_data->ref_ext
416
        );
417
418
        if ($updateRes > 0) {
419
            return $updateRes;
420
        } else {
421
            throw new RestException(400, $this->commande->error);
422
        }
423
    }
424
425
    /**
426
     * Update a line to given order
427
     *
428
     * @param int $id Id of order to update
429
     * @param int $lineid Id of line to update
430
     * @param array $request_data OrderLine data
431
     * @return  Object|false          Object with cleaned properties
432
     *
433
     * @url PUT {id}/lines/{lineid}
434
     */
435
    public function putLine($id, $lineid, $request_data = null)
436
    {
437
        if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
438
            throw new RestException(403);
439
        }
440
441
        $result = $this->commande->fetch($id);
442
        if (!$result) {
443
            throw new RestException(404, 'Order not found');
444
        }
445
446
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
447
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
448
        }
449
450
        $request_data = (object)$request_data;
451
452
        $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
453
        $request_data->label = sanitizeVal($request_data->label);
454
455
        $updateRes = $this->commande->updateline(
456
            $lineid,
457
            $request_data->desc,
458
            $request_data->subprice,
459
            $request_data->qty,
460
            $request_data->remise_percent,
461
            $request_data->tva_tx,
462
            $request_data->localtax1_tx,
463
            $request_data->localtax2_tx,
464
            $request_data->price_base_type ? $request_data->price_base_type : 'HT',
465
            $request_data->info_bits,
466
            $request_data->date_start,
467
            $request_data->date_end,
468
            $request_data->product_type,
469
            $request_data->fk_parent_line,
470
            0,
471
            $request_data->fk_fournprice,
472
            $request_data->pa_ht,
473
            $request_data->label,
474
            $request_data->special_code,
475
            $request_data->array_options,
476
            $request_data->fk_unit,
477
            $request_data->multicurrency_subprice,
478
            0,
479
            $request_data->ref_ext,
480
            $request_data->rang
481
        );
482
483
        if ($updateRes > 0) {
484
            $result = $this->get($id);
485
            unset($result->line);
486
            return $this->_cleanObjectDatas($result);
487
        }
488
        return false;
489
    }
490
491
    /**
492
     * Get properties of an order object by id
493
     *
494
     * Return an array with order information
495
     *
496
     * @param int $id ID of order
497
     * @param int $contact_list 0: Returned array of contacts/addresses contains all properties, 1: Return array contains just id
498
     * @return  array|mixed data without useless information
499
     *
500
     * @throws  RestException
501
     */
502
    public function get($id, $contact_list = 1)
503
    {
504
        return $this->_fetch($id, '', '', $contact_list);
505
    }
506
507
    /**
508
     * Delete a line of a given order
509
     *
510
     * @param int $id Id of order to update
511
     * @param int $lineid Id of line to delete
512
     * @return  array                  Object with cleaned properties
513
     *
514
     * @url DELETE {id}/lines/{lineid}
515
     *
516
     * @throws RestException 401
517
     * @throws RestException 404
518
     */
519
    public function deleteLine($id, $lineid)
520
    {
521
        if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
522
            throw new RestException(403);
523
        }
524
525
        $result = $this->commande->fetch($id);
526
        if (!$result) {
527
            throw new RestException(404, 'Order not found');
528
        }
529
530
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
531
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
532
        }
533
534
        $updateRes = $this->commande->deleteLine(DolibarrApiAccess::$user, $lineid, $id);
535
        if ($updateRes > 0) {
536
            return $this->get($id);
537
        } else {
538
            throw new RestException(405, $this->commande->error);
539
        }
540
    }
541
542
    /**
543
     * Get contacts of given order
544
     *
545
     * Return an array with contact information
546
     *
547
     * @param int $id ID of order
548
     * @param string $type Type of the contact (BILLING, SHIPPING, CUSTOMER)
549
     * @return  array              Object with cleaned properties
550
     *
551
     * @url GET {id}/contacts
552
     *
553
     * @throws  RestException
554
     */
555
    public function getContacts($id, $type = '')
556
    {
557
        if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
558
            throw new RestException(403);
559
        }
560
561
        $result = $this->commande->fetch($id);
562
        if (!$result) {
563
            throw new RestException(404, 'Order not found');
564
        }
565
566
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
567
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
568
        }
569
570
        $contacts = $this->commande->liste_contact(-1, 'external', 0, $type);
571
572
        return $this->_cleanObjectDatas($contacts);
573
    }
574
575
    /**
576
     * Add a contact type of given order
577
     *
578
     * @param int $id Id of order to update
579
     * @param int $contactid Id of contact to add
580
     * @param string $type Type of the contact (BILLING, SHIPPING, CUSTOMER)
581
     * @return array
582
     *
583
     * @url POST {id}/contact/{contactid}/{type}
584
     *
585
     * @throws RestException 401
586
     * @throws RestException 404
587
     */
588
    public function postContact($id, $contactid, $type)
589
    {
590
        if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
591
            throw new RestException(403);
592
        }
593
594
        $result = $this->commande->fetch($id);
595
        if (!$result) {
596
            throw new RestException(404, 'Order not found');
597
        }
598
599
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
600
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
601
        }
602
603
        $result = $this->commande->add_contact($contactid, $type, 'external');
604
605
        if ($result < 0) {
606
            throw new RestException(500, 'Error when added the contact');
607
        }
608
609
        if ($result == 0) {
610
            throw new RestException(304, 'contact already added');
611
        }
612
613
        return array(
614
            'success' => array(
615
                'code' => 200,
616
                'message' => 'Contact linked to the order'
617
            )
618
        );
619
    }
620
621
    /**
622
     * Unlink a contact type of given order
623
     *
624
     * @param int $id Id of order to update
625
     * @param int $contactid Id of contact
626
     * @param string $type Type of the contact (BILLING, SHIPPING, CUSTOMER).
627
     *
628
     * @url DELETE {id}/contact/{contactid}/{type}
629
     *
630
     * @return array
631
     *
632
     * @throws RestException 401
633
     * @throws RestException 404
634
     * @throws RestException 500 System error
635
     */
636
    public function deleteContact($id, $contactid, $type)
637
    {
638
        if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
639
            throw new RestException(403);
640
        }
641
642
        $result = $this->commande->fetch($id);
643
        if (!$result) {
644
            throw new RestException(404, 'Order not found');
645
        }
646
647
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
648
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
649
        }
650
651
        $contacts = $this->commande->liste_contact();
652
653
        foreach ($contacts as $contact) {
0 ignored issues
show
Bug introduced by
The expression $contacts of type integer is not traversable.
Loading history...
654
            if ($contact['id'] == $contactid && $contact['code'] == $type) {
655
                $result = $this->commande->delete_contact($contact['rowid']);
656
657
                if (!$result) {
658
                    throw new RestException(500, 'Error when deleted the contact');
659
                }
660
            }
661
        }
662
663
        return array(
664
            'success' => array(
665
                'code' => 200,
666
                'message' => 'Contact unlinked from order'
667
            )
668
        );
669
    }
670
671
    /**
672
     * Update order general fields (won't touch lines of order)
673
     *
674
     * @param int $id Id of order to update
675
     * @param array $request_data Datas
676
     * @return  array                  Object with cleaned properties
677
     * @throws RestException
678
     */
679
    public function put($id, $request_data = null)
680
    {
681
        if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
682
            throw new RestException(403);
683
        }
684
685
        $result = $this->commande->fetch($id);
686
        if (!$result) {
687
            throw new RestException(404, 'Order not found');
688
        }
689
690
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
691
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
692
        }
693
        foreach ($request_data as $field => $value) {
694
            if ($field == 'id') {
695
                continue;
696
            }
697
            if ($field === 'caller') {
698
                // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller
699
                $this->commande->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
700
                continue;
701
            }
702
            if ($field == 'array_options' && is_array($value)) {
703
                foreach ($value as $index => $val) {
704
                    $this->commande->array_options[$index] = $this->_checkValForAPI($field, $val, $this->commande);
705
                }
706
                continue;
707
            }
708
709
            $this->commande->$field = $this->_checkValForAPI($field, $value, $this->commande);
710
        }
711
712
        // Update availability
713
        if (!empty($this->commande->availability_id)) {
714
            if ($this->commande->availability($this->commande->availability_id) < 0) {
715
                throw new RestException(400, 'Error while updating availability');
716
            }
717
        }
718
719
        if ($this->commande->update(DolibarrApiAccess::$user) > 0) {
720
            return $this->get($id);
721
        } else {
722
            throw new RestException(500, $this->commande->error);
723
        }
724
    }
725
726
    /**
727
     * Delete order
728
     *
729
     * @param int $id Order ID
730
     * @return  array
731
     */
732
    public function delete($id)
733
    {
734
        if (!DolibarrApiAccess::$user->hasRight('commande', 'supprimer')) {
735
            throw new RestException(403);
736
        }
737
        $result = $this->commande->fetch($id);
738
        if (!$result) {
739
            throw new RestException(404, 'Order not found');
740
        }
741
742
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
743
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
744
        }
745
746
        if (!$this->commande->delete(DolibarrApiAccess::$user)) {
747
            throw new RestException(500, 'Error when deleting order : ' . $this->commande->error);
748
        }
749
750
        return array(
751
            'success' => array(
752
                'code' => 200,
753
                'message' => 'Order deleted'
754
            )
755
        );
756
    }
757
758
    /**
759
     * Validate an order
760
     *
761
     * If you get a bad value for param notrigger check, provide this in body
762
     * {
763
     *   "idwarehouse": 0,
764
     *   "notrigger": 0
765
     * }
766
     *
767
     * @param int $id Order ID
768
     * @param int $idwarehouse Warehouse ID
769
     * @param int $notrigger 1=Does not execute triggers, 0= execute triggers
770
     * @return  array              Object with cleaned properties
771
     *
772
     * @url POST    {id}/validate
773
     *
774
     * @throws RestException 304
775
     * @throws RestException 401
776
     * @throws RestException 404
777
     * @throws RestException 500 System error
778
     *
779
     */
780
    public function validate($id, $idwarehouse = 0, $notrigger = 0)
781
    {
782
        if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
783
            throw new RestException(403);
784
        }
785
        $result = $this->commande->fetch($id);
786
        if (!$result) {
787
            throw new RestException(404, 'Order not found');
788
        }
789
790
        $result = $this->commande->fetch_thirdparty(); // do not check result, as failure is not fatal (used only for mail notification substitutes)
791
792
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
793
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
794
        }
795
796
        $result = $this->commande->valid(DolibarrApiAccess::$user, $idwarehouse, $notrigger);
797
        if ($result == 0) {
798
            throw new RestException(304, 'Error nothing done. May be object is already validated');
799
        }
800
        if ($result < 0) {
801
            throw new RestException(500, 'Error when validating Order: ' . $this->commande->error);
802
        }
803
        $result = $this->commande->fetch($id);
804
805
        $this->commande->fetchObjectLinked();
806
807
        //fix #20477 : add online_payment_url
808
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/payments.lib.php';
809
        $this->commande->online_payment_url = getOnlinePaymentUrl(0, 'order', $this->commande->ref);
810
811
        return $this->_cleanObjectDatas($this->commande);
812
    }
813
814
    /**
815
     *  Tag the order as validated (opened)
816
     *
817
     *  Function used when order is reopend after being closed.
818
     *
819
     * @param int $id Id of the order
820
     *
821
     * @url     POST {id}/reopen
822
     *
823
     * @return int
824
     *
825
     * @throws RestException 304
826
     * @throws RestException 400
827
     * @throws RestException 401
828
     * @throws RestException 404
829
     * @throws RestException 405
830
     */
831
    public function reopen($id)
832
    {
833
        if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
834
            throw new RestException(403);
835
        }
836
        if (empty($id)) {
837
            throw new RestException(400, 'Order ID is mandatory');
838
        }
839
        $result = $this->commande->fetch($id);
840
        if (!$result) {
841
            throw new RestException(404, 'Order not found');
842
        }
843
844
        $result = $this->commande->set_reopen(DolibarrApiAccess::$user);
845
        if ($result < 0) {
846
            throw new RestException(405, $this->commande->error);
847
        } elseif ($result == 0) {
848
            throw new RestException(304);
849
        }
850
851
        return $result;
852
    }
853
854
    /**
855
     * Classify the order as invoiced. Could be also called setbilled
856
     *
857
     * @param int $id Id of the order
858
     * @return  array                  Object with cleaned properties
859
     *
860
     * @url     POST {id}/setinvoiced
861
     *
862
     * @throws RestException 400
863
     * @throws RestException 401
864
     * @throws RestException 404
865
     * @throws RestException 405
866
     */
867
    public function setinvoiced($id)
868
    {
869
        if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
870
            throw new RestException(403);
871
        }
872
        if (empty($id)) {
873
            throw new RestException(400, 'Order ID is mandatory');
874
        }
875
        $result = $this->commande->fetch($id);
876
        if (!$result) {
877
            throw new RestException(404, 'Order not found');
878
        }
879
880
        $result = $this->commande->classifyBilled(DolibarrApiAccess::$user);
881
        if ($result < 0) {
882
            throw new RestException(400, $this->commande->error);
883
        }
884
885
        $result = $this->commande->fetch($id);
886
        if (!$result) {
887
            throw new RestException(404, 'Order not found');
888
        }
889
890
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
891
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
892
        }
893
894
        $this->commande->fetchObjectLinked();
895
896
        return $this->_cleanObjectDatas($this->commande);
897
    }
898
899
    /**
900
     * Close an order (Classify it as "Delivered")
901
     *
902
     * @param int $id Order ID
903
     * @param int $notrigger Disabled triggers
904
     * @return  array                  Object with cleaned properties
905
     *
906
     * @url POST    {id}/close
907
     */
908
    public function close($id, $notrigger = 0)
909
    {
910
        if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
911
            throw new RestException(403);
912
        }
913
        $result = $this->commande->fetch($id);
914
        if (!$result) {
915
            throw new RestException(404, 'Order not found');
916
        }
917
918
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
919
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
920
        }
921
922
        $result = $this->commande->cloture(DolibarrApiAccess::$user, $notrigger);
923
        if ($result == 0) {
924
            throw new RestException(304, 'Error nothing done. May be object is already closed');
925
        }
926
        if ($result < 0) {
927
            throw new RestException(500, 'Error when closing Order: ' . $this->commande->error);
928
        }
929
930
        $result = $this->commande->fetch($id);
931
        if (!$result) {
932
            throw new RestException(404, 'Order not found');
933
        }
934
935
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
936
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
937
        }
938
939
        $this->commande->fetchObjectLinked();
940
941
        return $this->_cleanObjectDatas($this->commande);
942
    }
943
944
    /**
945
     * Set an order to draft
946
     *
947
     * @param int $id Order ID
948
     * @param int $idwarehouse Warehouse ID to use for stock change (Used only if option STOCK_CALCULATE_ON_VALIDATE_ORDER is on)
949
     * @return  array                  Object with cleaned properties
950
     *
951
     * @url POST    {id}/settodraft
952
     */
953
    public function settodraft($id, $idwarehouse = -1)
954
    {
955
        if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
956
            throw new RestException(403);
957
        }
958
        $result = $this->commande->fetch($id);
959
        if (!$result) {
960
            throw new RestException(404, 'Order not found');
961
        }
962
963
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
964
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
965
        }
966
967
        $result = $this->commande->setDraft(DolibarrApiAccess::$user, $idwarehouse);
968
        if ($result == 0) {
969
            throw new RestException(304, 'Nothing done. May be object is already closed');
970
        }
971
        if ($result < 0) {
972
            throw new RestException(500, 'Error when closing Order: ' . $this->commande->error);
973
        }
974
975
        $result = $this->commande->fetch($id);
976
        if (!$result) {
977
            throw new RestException(404, 'Order not found');
978
        }
979
980
        if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
981
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
982
        }
983
984
        $this->commande->fetchObjectLinked();
985
986
        return $this->_cleanObjectDatas($this->commande);
987
    }
988
989
    /**
990
     * Create an order using an existing proposal.
991
     *
992
     * @param int $proposalid Id of the proposal
993
     * @return  array                  Object with cleaned properties
994
     *
995
     * @url     POST /createfromproposal/{proposalid}
996
     *
997
     * @throws RestException 400
998
     * @throws RestException 401
999
     * @throws RestException 404
1000
     * @throws RestException 405
1001
     */
1002
    public function createOrderFromProposal($proposalid)
1003
    {
1004
        if (!DolibarrApiAccess::$user->hasRight('propal', 'lire')) {
1005
            throw new RestException(403);
1006
        }
1007
        if (!DolibarrApiAccess::$user->hasRight('commande', 'creer')) {
1008
            throw new RestException(403);
1009
        }
1010
        if (empty($proposalid)) {
1011
            throw new RestException(400, 'Proposal ID is mandatory');
1012
        }
1013
1014
        $propal = new Propal($this->db);
1015
        $result = $propal->fetch($proposalid);
1016
        if (!$result) {
1017
            throw new RestException(404, 'Proposal not found');
1018
        }
1019
1020
        $result = $this->commande->createFromProposal($propal, DolibarrApiAccess::$user);
1021
        if ($result < 0) {
1022
            throw new RestException(405, $this->commande->error);
1023
        }
1024
        $this->commande->fetchObjectLinked();
1025
1026
        return $this->_cleanObjectDatas($this->commande);
1027
    }
1028
1029
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
1030
1031
    /**
1032
     * Get the shipments of an order
1033
     *
1034
     * @param int $id Id of the order
1035
     *
1036
     * @url     GET {id}/shipment
1037
     *
1038
     * @return array
1039
     *
1040
     * @throws RestException 401
1041
     * @throws RestException 404
1042
     * @throws RestException 500 System error
1043
     */
1044
    public function getOrderShipments($id)
1045
    {
1046
        if (!DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
1047
            throw new RestException(403);
1048
        }
1049
        $obj_ret = array();
1050
        $sql = "SELECT e.rowid";
1051
        $sql .= " FROM " . MAIN_DB_PREFIX . "expedition as e";
1052
        $sql .= " JOIN " . MAIN_DB_PREFIX . "expeditiondet as edet";
1053
        $sql .= " ON e.rowid = edet.fk_expedition";
1054
        $sql .= " JOIN " . MAIN_DB_PREFIX . "commandedet as cdet";
1055
        $sql .= " ON edet.fk_elementdet = cdet.rowid";
1056
        $sql .= " JOIN " . MAIN_DB_PREFIX . "commande as c";
1057
        $sql .= " ON cdet.fk_commande = c.rowid";
1058
        $sql .= " WHERE c.rowid = " . ((int)$id);
1059
        $sql .= " GROUP BY e.rowid";
1060
        $sql .= $this->db->order("e.rowid", "ASC");
1061
1062
        dol_syslog("API Rest request");
1063
        $result = $this->db->query($sql);
1064
1065
        if ($result) {
1066
            $num = $this->db->num_rows($result);
1067
            if ($num <= 0) {
1068
                throw new RestException(404, 'Shipments not found ');
1069
            }
1070
            $i = 0;
1071
            while ($i < $num) {
1072
                $obj = $this->db->fetch_object($result);
1073
                $shipment_static = new Expedition($this->db);
1074
                if ($shipment_static->fetch($obj->rowid)) {
1075
                    $obj_ret[] = $this->_cleanObjectDatas($shipment_static);
1076
                }
1077
                $i++;
1078
            }
1079
        } else {
1080
            throw new RestException(500, 'Error when retrieve shipment list : ' . $this->db->lasterror());
1081
        }
1082
        return $obj_ret;
1083
    }
1084
1085
    /**
1086
     * Create the shipment of an order
1087
     *
1088
     * @param int $id Id of the order
1089
     * @param int $warehouse_id Id of a warehouse
1090
     *
1091
     * @url     POST {id}/shipment/{warehouse_id}
1092
     *
1093
     * @return int
1094
     *
1095
     * @throws RestException 401
1096
     * @throws RestException 404
1097
     * @throws RestException 500 System error
1098
     */
1099
    public function createOrderShipment($id, $warehouse_id)
1100
    {
1101
        if (!DolibarrApiAccess::$user->hasRight('expedition', 'creer')) {
1102
            throw new RestException(403);
1103
        }
1104
        if ($warehouse_id <= 0) {
1105
            throw new RestException(404, 'Warehouse not found');
1106
        }
1107
        $result = $this->commande->fetch($id);
1108
        if (!$result) {
1109
            throw new RestException(404, 'Order not found');
1110
        }
1111
        $shipment = new Expedition($this->db);
1112
        $shipment->socid = $this->commande->socid;
1113
        $shipment->origin_id = $this->commande->id;
1114
        $result = $shipment->create(DolibarrApiAccess::$user);
1115
        if ($result <= 0) {
1116
            throw new RestException(500, 'Error on creating expedition :' . $this->db->lasterror());
1117
        }
1118
        foreach ($this->commande->lines as $line) {
1119
            $result = $shipment->create_line($warehouse_id, $line->id, $line->qty);
1120
            if ($result <= 0) {
1121
                throw new RestException(500, 'Error on creating expedition lines:' . $this->db->lasterror());
1122
            }
1123
        }
1124
        return $shipment->id;
1125
    }
1126
}
1127