Completed
Branch develop (2c126c)
by Laurent
24:08
created

Proposals::putLine()   C

Complexity

Conditions 25
Paths 6

Size

Total Lines 55
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 25
eloc 41
nc 6
nop 3
dl 0
loc 55
rs 6.4952
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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
/* Copyright (C) 2015   Jean-François Ferry     <[email protected]>
3
 * Copyright (C) 2016   Laurent Destailleur     <[email protected]>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
 */
18
19
use Luracast\Restler\RestException;
20
21
require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
22
23
24
/**
25
 * API class for orders
26
 *
27
 * @access protected
28
 * @class  DolibarrApiAccess {@requires user,external}
29
 */
30
class Proposals extends DolibarrApi
31
{
32
33
    /**
34
     * @var array   $FIELDS     Mandatory fields, checked when create and update object
35
     */
36
    static $FIELDS = array(
37
        'socid'
38
    );
39
40
    /**
41
     * @var propal $propal {@type propal}
42
     */
43
    public $propal;
44
45
    /**
46
     * Constructor
47
     */
48
    function __construct()
49
    {
50
		global $db, $conf;
51
		$this->db = $db;
52
        $this->propal = new Propal($this->db);
53
    }
54
55
    /**
56
     * Get properties of a commercial proposal object
57
     *
58
     * Return an array with commercial proposal informations
59
     *
60
     * @param       int         $id         ID of commercial proposal
61
     * @return 	array|mixed data without useless information
62
	 *
63
     * @throws 	RestException
64
     */
65
    function get($id)
66
    {
67
		if(! DolibarrApiAccess::$user->rights->propal->lire) {
68
			throw new RestException(401);
69
		}
70
71
        $result = $this->propal->fetch($id);
72
        if( ! $result ) {
73
            throw new RestException(404, 'Commercial Proposal not found');
74
        }
75
76
		if( ! DolibarrApi::_checkAccessToResource('propal',$this->propal->id)) {
77
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
78
		}
79
80
        $this->propal->fetchObjectLinked();
81
		return $this->_cleanObjectDatas($this->propal);
82
    }
83
84
    /**
85
     * List commercial proposals
86
     *
87
     * Get a list of commercial proposals
88
     *
89
     * @param string	$sortfield	        Sort field
90
     * @param string	$sortorder	        Sort order
91
     * @param int		$limit		        Limit for list
92
     * @param int		$page		        Page number
93
     * @param string   	$thirdparty_ids	    Thirdparty ids to filter commercial proposal of. Example: '1' or '1,2,3'          {@pattern /^[0-9,]*$/i}
94
     * @param string    $sqlfilters         Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.datec:<:'20160101')"
95
     * @return  array                       Array of order objects
96
     */
97
    function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 0, $page = 0, $thirdparty_ids = '', $sqlfilters = '') {
98
        global $db, $conf;
99
100
        $obj_ret = array();
101
102
        // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
103
        $socids = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $thirdparty_ids;
104
105
        // If the internal user must only see his customers, force searching by him
106
        $search_sale = 0;
107
        if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) $search_sale = DolibarrApiAccess::$user->id;
108
109
        $sql = "SELECT t.rowid";
110
        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects)
111
        $sql.= " FROM ".MAIN_DB_PREFIX."propal as t";
112
113
        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale
114
115
        $sql.= ' WHERE t.entity IN ('.getEntity('propal').')';
116
        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql.= " AND t.fk_soc = sc.fk_soc";
117
        if ($socids) $sql.= " AND t.fk_soc IN (".$socids.")";
118
        if ($search_sale > 0) $sql.= " AND t.rowid = sc.fk_soc";		// Join for the needed table to filter by sale
119
        // Insert sale filter
120
        if ($search_sale > 0)
121
        {
122
            $sql .= " AND sc.fk_user = ".$search_sale;
123
        }
124
        // Add sql filters
125
        if ($sqlfilters)
126
        {
127
            if (! DolibarrApi::_checkFilters($sqlfilters))
128
            {
129
                throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters);
130
            }
131
	        $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
132
            $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
133
        }
134
135
        $sql.= $db->order($sortfield, $sortorder);
136
        if ($limit)	{
137
            if ($page < 0)
138
            {
139
                $page = 0;
140
            }
141
            $offset = $limit * $page;
142
143
            $sql.= $db->plimit($limit + 1, $offset);
144
        }
145
146
        $result = $db->query($sql);
147
148
        if ($result)
149
        {
150
            $num = $db->num_rows($result);
151
            $min = min($num, ($limit <= 0 ? $num : $limit));
152
            while ($i < $min)
0 ignored issues
show
Bug introduced by
The variable $i does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
153
            {
154
                $obj = $db->fetch_object($result);
155
                $propal_static = new Propal($db);
156
                if($propal_static->fetch($obj->rowid)) {
157
                    $obj_ret[] = $this->_cleanObjectDatas($propal_static);
158
                }
159
                $i++;
160
            }
161
        }
162
        else {
163
            throw new RestException(503, 'Error when retrieve propal list : '.$db->lasterror());
164
        }
165
        if( ! count($obj_ret)) {
166
            throw new RestException(404, 'No order found');
167
        }
168
		return $obj_ret;
169
    }
170
171
    /**
172
     * Create commercial proposal object
173
     *
174
     * @param   array   $request_data   Request data
175
     * @return  int     ID of propal
176
     */
177
    function post($request_data = NULL)
178
    {
179
      if(! DolibarrApiAccess::$user->rights->propal->creer) {
180
			  throw new RestException(401, "Insuffisant rights");
181
		  }
182
        // Check mandatory fields
183
        $result = $this->_validate($request_data);
1 ignored issue
show
Bug introduced by
It seems like $request_data defined by parameter $request_data on line 177 can also be of type null; however, Proposals::_validate() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
184
185
        foreach($request_data as $field => $value) {
186
            $this->propal->$field = $value;
187
        }
188
        /*if (isset($request_data["lines"])) {
189
          $lines = array();
190
          foreach ($request_data["lines"] as $line) {
191
            array_push($lines, (object) $line);
192
          }
193
          $this->propal->lines = $lines;
194
        }*/
195
        if ($this->propal->create(DolibarrApiAccess::$user) < 0) {
196
            throw new RestException(500, "Error creating order", array_merge(array($this->propal->error), $this->propal->errors));
197
        }
198
199
        return $this->propal->id;
200
    }
201
202
    /**
203
     * Get lines of a commercial proposal
204
     *
205
     * @param int   $id             Id of commercial proposal
206
     *
207
     * @url	GET {id}/lines
208
     *
209
     * @return int
210
     */
211
    function getLines($id) {
212
      if(! DolibarrApiAccess::$user->rights->propal->lire) {
213
		  	throw new RestException(401);
214
		  }
215
216
      $result = $this->propal->fetch($id);
217
      if( ! $result ) {
218
         throw new RestException(404, 'Commercial Proposal not found');
219
      }
220
221
		  if( ! DolibarrApi::_checkAccessToResource('propal',$this->propal->id)) {
222
			  throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
223
      }
224
      $this->propal->getLinesArray();
225
      $result = array();
226
      foreach ($this->propal->lines as $line) {
227
        array_push($result,$this->_cleanObjectDatas($line));
228
      }
229
      return $result;
230
    }
231
232
    /**
233
     * Add a line to given commercial proposal
234
     *
235
     * @param int   $id             Id of commercial proposal to update
236
     * @param array $request_data   Commercial proposal line data
237
     *
238
     * @url	POST {id}/lines
239
     *
240
     * @return int
241
     */
242
    function postLine($id, $request_data = NULL)
243
    {
244
		if(! DolibarrApiAccess::$user->rights->propal->creer) {
245
		  	throw new RestException(401);
246
		}
247
248
	    $result = $this->propal->fetch($id);
249
	    if (! $result) {
250
	       throw new RestException(404, 'Commercial Proposal not found');
251
	    }
252
253
		if (! DolibarrApi::_checkAccessToResource('propal',$this->propal->id))
254
		{
255
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
256
		}
257
258
		$request_data = (object) $request_data;
259
260
      	$updateRes = $this->propal->addline(
261
                        $request_data->desc,
262
                        $request_data->subprice,
263
                        $request_data->qty,
264
                        $request_data->tva_tx,
265
                        $request_data->localtax1_tx,
266
                        $request_data->localtax2_tx,
267
                        $request_data->fk_product,
268
                        $request_data->remise_percent,
269
                        'HT',
270
                        0,
271
                        $request_data->info_bits,
272
                        $request_data->product_type,
273
                        $request_data->rang,
274
                        $request_data->special_code,
275
                        $fk_parent_line,
0 ignored issues
show
Bug introduced by
The variable $fk_parent_line does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
276
                        $request_data->fk_fournprice,
277
                        $request_data->pa_ht,
278
                        $request_data->label,
279
                        $request_data->date_start,
280
                        $request_data->date_end,
281
                        $request_data->array_options,
282
                        $request_data->fk_unit,
283
                        $this->element,
284
                        $request_data->id,
285
                        $request_data->multicurrency_subprice,
286
                        $request_data->fk_remise_except
287
      );
288
289
      if ($updateRes > 0) {
290
        return $this->get($id)->line->rowid;
291
292
      }
293
      return false;
294
    }
295
296
    /**
297
     * Update a line of given commercial proposal
298
     *
299
     * @param int   $id             Id of commercial proposal to update
300
     * @param int   $lineid         Id of line to update
301
     * @param array $request_data   Commercial proposal line data
302
     *
303
     * @url	PUT {id}/lines/{lineid}
304
     *
305
     * @return object
306
     */
307
    function putLine($id, $lineid, $request_data = NULL)
308
    {
309
    	if(! DolibarrApiAccess::$user->rights->propal->creer) {
310
			throw new RestException(401);
311
		}
312
313
    	$result = $this->propal->fetch($id);
314
    	if($result <= 0) {
315
        	throw new RestException(404, 'Proposal not found');
316
    	}
317
318
		if( ! DolibarrApi::_checkAccessToResource('propal',$this->propal->id)) {
319
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
320
      	}
321
322
      	$request_data = (object) $request_data;
323
324
      	$propalline = new PropaleLigne($this->db);
325
      	$result = $propalline->fetch($lineid);
326
      	if ($result <= 0) {
327
      		throw new RestException(404, 'Proposal line not found');
328
      	}
329
330
      	$updateRes = $this->propal->updateline(
331
                        $lineid,
332
                        isset($request_data->subprice)?$request_data->subprice:$propalline->subprice,
333
                        isset($request_data->qty)?$request_data->qty:$propalline->qty,
334
                        isset($request_data->remise_percent)?$request_data->remise_percent:$propalline->remise_percent,
335
                        isset($request_data->tva_tx)?$request_data->tva_tx:$propalline->tva_tx,
336
                        isset($request_data->localtax1_tx)?$request_data->localtax1_tx:$propalline->localtax1_tx,
337
                        isset($request_data->localtax2_tx)?$request_data->localtax2_tx:$propalline->localtax2_tx,
338
                        isset($request_data->desc)?$request_data->desc:$propalline->desc,
339
      					'HT',
340
                        isset($request_data->info_bits)?$request_data->info_bits:$propalline->info_bits,
341
                        isset($request_data->special_code)?$request_data->special_code:$propalline->special_code,
342
                        isset($request_data->fk_parent_line)?$request_data->fk_parent_line:$propalline->fk_parent_line,
343
      					0,
344
      					isset($request_data->fk_fournprice)?$request_data->fk_fournprice:$propalline->fk_fournprice,
345
      					isset($request_data->pa_ht)?$request_data->pa_ht:$propalline->pa_ht,
346
      					isset($request_data->label)?$request_data->label:$propalline->label,
347
				      	isset($request_data->product_type)?$request_data->product_type:$propalline->product_type,
348
      					isset($request_data->date_start)?$request_data->date_start:$propalline->date_start,
349
                        isset($request_data->date_end)?$request_data->date_end:$propalline->date_end,
350
                        isset($request_data->array_options)?$request_data->array_options:$propalline->array_options,
351
                        isset($request_data->fk_unit)?$request_data->fk_unit:$propalline->fk_unit,
352
      					isset($request_data->multicurrency_subprice)?$request_data->multicurrency_subprice:$propalline->subprice
353
      );
354
355
      if ($updateRes > 0) {
356
        $result = $this->get($id);
357
        unset($result->line);
358
        return $this->_cleanObjectDatas($result);
359
      }
360
      return false;
361
    }
362
363
    /**
364
     * Delete a line of given commercial proposal
365
     *
366
     *
367
     * @param int   $id             Id of commercial proposal to update
368
     * @param int   $lineid         Id of line to delete
369
     *
370
     * @url	DELETE {id}/lines/{lineid}
371
     *
372
     * @return int
373
     */
374
    function delLine($id, $lineid) {
375
      if(! DolibarrApiAccess::$user->rights->propal->creer) {
376
		  	throw new RestException(401);
377
		  }
378
379
      $result = $this->propal->fetch($id);
380
      if( ! $result ) {
381
         throw new RestException(404, 'Proposal not found');
382
      }
383
384
		  if( ! DolibarrApi::_checkAccessToResource('propal',$this->propal->id)) {
385
			  throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
386
      }
387
			$request_data = (object) $request_data;
0 ignored issues
show
Bug introduced by
The variable $request_data seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
388
      $updateRes = $this->propal->deleteline($lineid);
389
      if ($updateRes == 1) {
390
        return $this->get($id);
391
      }
392
      return false;
393
    }
394
395
    /**
396
     * Update commercial proposal general fields (won't touch lines of commercial proposal)
397
     *
398
     * @param int   $id             Id of commercial proposal to update
399
     * @param array $request_data   Datas
400
     *
401
     * @return int
402
     */
403
    function put($id, $request_data = NULL) {
404
      if(! DolibarrApiAccess::$user->rights->propal->creer) {
405
		  	throw new RestException(401);
406
		  }
407
408
        $result = $this->propal->fetch($id);
409
        if( ! $result ) {
410
            throw new RestException(404, 'Proposal not found');
411
        }
412
413
		if( ! DolibarrApi::_checkAccessToResource('propal',$this->propal->id)) {
414
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
415
		}
416
        foreach($request_data as $field => $value) {
417
            if ($field == 'id') continue;
418
            $this->propal->$field = $value;
419
        }
420
421
        if($this->propal->update($id, DolibarrApiAccess::$user,1,'','','update'))
0 ignored issues
show
Bug introduced by
The method update() does not exist on Propal. Did you maybe mean updateline()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
422
            return $this->get($id);
423
424
        return false;
425
    }
426
427
    /**
428
     * Delete commercial proposal
429
     *
430
     * @param   int     $id         Commercial proposal ID
431
     *
432
     * @return  array
433
     */
434
    function delete($id)
435
    {
436
        if(! DolibarrApiAccess::$user->rights->propal->supprimer) {
437
			throw new RestException(401);
438
		}
439
        $result = $this->propal->fetch($id);
440
        if( ! $result ) {
441
            throw new RestException(404, 'Commercial Proposal not found');
442
        }
443
444
		if( ! DolibarrApi::_checkAccessToResource('propal',$this->propal->id)) {
445
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
446
		}
447
448
        if( ! $this->propal->delete(DolibarrApiAccess::$user)) {
449
            throw new RestException(500, 'Error when delete Commercial Proposal : '.$this->propal->error);
450
        }
451
452
        return array(
453
            'success' => array(
454
                'code' => 200,
455
                'message' => 'Commercial Proposal deleted'
456
            )
457
        );
458
459
    }
460
461
    /**
462
     * Validate a commercial proposal
463
     *
464
     * @param   int     $id             Commercial proposal ID
465
     * @param   int     $notrigger      Use {}
466
     *
467
     * @url POST    {id}/validate
468
     *
469
     * @return  array
470
     * FIXME An error 403 is returned if the request has an empty body.
471
     * Error message: "Forbidden: Content type `text/plain` is not supported."
472
     * Workaround: send this in the body
473
     * {
474
     * "notrigger": 0
475
     * }
476
     */
477
    function validate($id, $notrigger=0)
478
    {
479
        if(! DolibarrApiAccess::$user->rights->propal->creer) {
480
			throw new RestException(401);
481
		}
482
        $result = $this->propal->fetch($id);
483
        if( ! $result ) {
484
            throw new RestException(404, 'Commercial Proposal not found');
485
        }
486
487
		if( ! DolibarrApi::_checkAccessToResource('propal',$this->propal->id)) {
488
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
489
		}
490
491
        $result = $this->propal->valid(DolibarrApiAccess::$user, $notrigger);
492
        if ($result == 0) {
493
            throw new RestException(500, 'Error nothing done. May be object is already validated');
494
        }
495
        if ($result < 0) {
496
            throw new RestException(500, 'Error when validating Commercial Proposal: '.$this->propal->error);
497
        }
498
499
        return array(
500
            'success' => array(
501
                'code' => 200,
502
                'message' => 'Commercial Proposal validated (Ref='.$this->propal->ref.')'
503
            )
504
        );
505
    }
506
507
    /**
508
     * Validate fields before create or update object
509
     *
510
     * @param   array           $data   Array with data to verify
511
     * @return  array
512
     * @throws  RestException
513
     */
514
    function _validate($data)
515
    {
516
        $propal = array();
517
        foreach (Proposals::$FIELDS as $field) {
518
            if (!isset($data[$field]))
519
                throw new RestException(400, "$field field missing");
520
            $propal[$field] = $data[$field];
521
522
        }
523
        return $propal;
524
    }
525
526
    /**
527
     * Clean sensible object datas
528
     *
529
     * @param   object  $object    Object to clean
530
     * @return    array    Array of cleaned object properties
531
     */
532
    function _cleanObjectDatas($object) {
533
534
    	$object = parent::_cleanObjectDatas($object);
535
536
    	unset($object->name);
537
    	unset($object->lastname);
538
    	unset($object->firstname);
539
    	unset($object->civility_id);
540
    	unset($object->address);
541
542
    	return $object;
543
    }
544
}
545