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

Orders::getContacts()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 4
nop 2
dl 0
loc 18
rs 9.9666
c 0
b 0
f 0
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