Passed
Pull Request — main (#3)
by Rafael
54:18
created

Proposals::postLines()   B

Complexity

Conditions 9
Paths 17

Size

Total Lines 68
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 50
nc 17
nop 2
dl 0
loc 68
rs 7.5353
c 0
b 0
f 0

How to fix   Long Method   

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:

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