Passed
Push — EXTRACT_CLASSES ( ff35ec...a2ff75 )
by Rafael
48:13
created

ProductFournisseurPrice::getNextNumRef()   B

Complexity

Conditions 9
Paths 26

Size

Total Lines 47
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 29
nc 26
nop 0
dl 0
loc 47
rs 8.0555
c 0
b 0
f 0
1
<?php
2
3
/* Copyright (C) 2017       Laurent Destailleur         <[email protected]>
4
 * Copyright (C) 2021       Alexis LAURIER              <[email protected]>
5
 * Copyright (C) 2024       Frédéric France             <[email protected]>
6
 * Copyright (C) 2024		MDW							<[email protected]>
7
 * Copyright (C) 2024       Rafael San José             <[email protected]>
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 3 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21
 */
22
23
namespace Dolibarr\Code\Product\Classes;
24
25
use Dolibarr\Core\Base\CommonObject;
26
27
/**
28
 * \file        class/productfournisseurprice.class.php
29
 * \ingroup     product
30
 * \brief       This file is a CRUD class file for ProductFournisseurPrice (Create/Read/Update/Delete)
31
 */
32
33
/**
34
 * Class for ProductFournisseurPrice
35
 */
36
class ProductFournisseurPrice extends CommonObject
37
{
38
    /**
39
     * @var string ID to identify managed object.
40
     */
41
    public $element = 'productfournisseurprice';
42
43
    /**
44
     * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management.
45
     */
46
    public $table_element = 'product_fournisseur_price';
47
48
    /**
49
     * @var string String with name of icon for productfournisseurprice. Must be the part after the 'object_' into object_productfournisseurprice.png
50
     */
51
    public $picto = 'productfournisseurprice@buypricehistory';
52
53
54
    const STATUS_DRAFT = 0;
55
    const STATUS_VALIDATED = 1;
56
    const STATUS_CANCELED = 9;
57
58
59
    /**
60
     *  'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter]]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'text:none', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password')
61
     *         Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)"
62
     *  'label' the translation key.
63
     *  'picto' is code of a picto to show before value in forms
64
     *  'enabled' is a condition when the field must be managed (Example: 1 or 'getDolGlobalString("MY_SETUP_PARAM")'
65
     *  'position' is the sort order of field.
66
     *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
67
     *  'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing)
68
     *  'noteditable' says if field is not editable (1 or 0)
69
     *  'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created.
70
     *  'index' if we want an index in database.
71
     *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommended to name the field fk_...).
72
     *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
73
     *  'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8).
74
     *  'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'maxwidth200', 'wordbreak', 'tdoverflowmax200'
75
     *  'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click.
76
     *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
77
     *  'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code.
78
     *  'arrayofkeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel")
79
     *  'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1.
80
     *  'comment' is not used. You can store here any text of your choice. It is not used by application.
81
     *
82
     *  Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
83
     */
84
85
    // BEGIN MODULEBUILDER PROPERTIES
86
    /**
87
     * @var array<string,array{type:string,label:string,enabled:int<0,2>|string,position:int,notnull?:int,visible:int,noteditable?:int,default?:string,index?:int,foreignkey?:string,searchall?:int,isameasure?:int,css?:string,csslist?:string,help?:string,showoncombobox?:int,disabled?:int,arrayofkeyval?:array<int,string>,comment?:string}>  Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string,array{type:...ring>,comment?:string}> at position 16 could not be parsed: Expected '}' at position 16, but found 'int'.
Loading history...
88
     */
89
    public $fields = array(
90
        'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => '1', 'position' => 10, 'notnull' => 1, 'visible' => 0,),
91
        'entity' => array('type' => 'integer', 'label' => 'Entity', 'enabled' => '1', 'position' => 15, 'notnull' => 1, 'visible' => -2, 'default' => '1', 'index' => 1,),
92
        'datec' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => '1', 'position' => 20, 'notnull' => 0, 'visible' => -1,),
93
        'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => '1', 'position' => 25, 'notnull' => 1, 'visible' => -1,),
94
        'fk_product' => array('type' => 'integer:Product:product/class/product.class.php:1', 'label' => 'Fkproduct', 'enabled' => '1', 'position' => 30, 'notnull' => 0, 'visible' => -1,),
95
        'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php', 'label' => 'ThirdParty', 'enabled' => '1', 'position' => 35, 'notnull' => 0, 'visible' => -1,),
96
        'ref_fourn' => array('type' => 'varchar(255)', 'label' => 'Reffourn', 'enabled' => '1', 'position' => 40, 'notnull' => 0, 'visible' => -1,),
97
        'desc_fourn' => array('type' => 'text', 'label' => 'Descfourn', 'enabled' => '1', 'position' => 45, 'notnull' => 0, 'visible' => -1,),
98
        'fk_availability' => array('type' => 'integer', 'label' => 'Fkavailability', 'enabled' => '1', 'position' => 50, 'notnull' => 0, 'visible' => -1,),
99
        'price' => array('type' => 'double(24,8)', 'label' => 'Price', 'enabled' => '1', 'position' => 55, 'notnull' => 0, 'visible' => -1,),
100
        'quantity' => array('type' => 'double', 'label' => 'Quantity', 'enabled' => '1', 'position' => 60, 'notnull' => 0, 'visible' => -1,),
101
        'remise_percent' => array('type' => 'double', 'label' => 'Remisepercent', 'enabled' => '1', 'position' => 65, 'notnull' => 1, 'visible' => -1,),
102
        'remise' => array('type' => 'double', 'label' => 'Remise', 'enabled' => '1', 'position' => 70, 'notnull' => 1, 'visible' => -1,),
103
        'unitprice' => array('type' => 'double(24,8)', 'label' => 'Unitprice', 'enabled' => '1', 'position' => 75, 'notnull' => 0, 'visible' => -1,),
104
        'charges' => array('type' => 'double(24,8)', 'label' => 'Charges', 'enabled' => '1', 'position' => 80, 'notnull' => 0, 'visible' => -1,),
105
        'default_vat_code' => array('type' => 'varchar(10)', 'label' => 'Defaultvatcode', 'enabled' => '1', 'position' => 85, 'notnull' => 0, 'visible' => -1,),
106
        'tva_tx' => array('type' => 'double(6,3)', 'label' => 'Tvatx', 'enabled' => '1', 'position' => 90, 'notnull' => 1, 'visible' => -1,),
107
        'info_bits' => array('type' => 'integer', 'label' => 'Infobits', 'enabled' => '1', 'position' => 95, 'notnull' => 1, 'visible' => -1,),
108
        'fk_user' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'Fkuser', 'enabled' => '1', 'position' => 100, 'notnull' => 0, 'visible' => -1,),
109
        'fk_supplier_price_expression' => array('type' => 'integer', 'label' => 'Fksupplierpriceexpression', 'enabled' => '1', 'position' => 105, 'notnull' => 0, 'visible' => -1,),
110
        'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => '1', 'position' => 900, 'notnull' => 0, 'visible' => -2,),
111
        'delivery_time_days' => array('type' => 'integer', 'label' => 'Deliverytimedays', 'enabled' => '1', 'position' => 115, 'notnull' => 0, 'visible' => -1,),
112
        'supplier_reputation' => array('type' => 'varchar(10)', 'label' => 'Supplierreputation', 'enabled' => '1', 'position' => 120, 'notnull' => 0, 'visible' => -1,),
113
        'fk_multicurrency' => array('type' => 'integer', 'label' => 'Fkmulticurrency', 'enabled' => '1', 'position' => 125, 'notnull' => 0, 'visible' => -1,),
114
        'multicurrency_code' => array('type' => 'varchar(255)', 'label' => 'Multicurrencycode', 'enabled' => '1', 'position' => 130, 'notnull' => 0, 'visible' => -1,),
115
        'multicurrency_tx' => array('type' => 'double(24,8)', 'label' => 'Multicurrencytx', 'enabled' => '1', 'position' => 135, 'notnull' => 0, 'visible' => -1,),
116
        'multicurrency_price' => array('type' => 'double(24,8)', 'label' => 'Multicurrencyprice', 'enabled' => '1', 'position' => 140, 'notnull' => 0, 'visible' => -1,),
117
        'multicurrency_unitprice' => array('type' => 'double(24,8)', 'label' => 'Multicurrencyunitprice', 'enabled' => '1', 'position' => 145, 'notnull' => 0, 'visible' => -1,),
118
        'localtax1_tx' => array('type' => 'double(6,3)', 'label' => 'Localtax1tx', 'enabled' => '1', 'position' => 150, 'notnull' => 0, 'visible' => -1,),
119
        'localtax1_type' => array('type' => 'varchar(10)', 'label' => 'Localtax1type', 'enabled' => '1', 'position' => 155, 'notnull' => 1, 'visible' => -1,),
120
        'localtax2_tx' => array('type' => 'double(6,3)', 'label' => 'Localtax2tx', 'enabled' => '1', 'position' => 160, 'notnull' => 0, 'visible' => -1,),
121
        'localtax2_type' => array('type' => 'varchar(10)', 'label' => 'Localtax2type', 'enabled' => '1', 'position' => 165, 'notnull' => 1, 'visible' => -1,),
122
        'barcode' => array('type' => 'varchar(180)', 'label' => 'Barcode', 'enabled' => '1', 'position' => 170, 'notnull' => 0, 'visible' => -1,),
123
        'fk_barcode_type' => array('type' => 'integer', 'label' => 'Fkbarcodetype', 'enabled' => '1', 'position' => 175, 'notnull' => 0, 'visible' => -1,),
124
        'packaging' => array('type' => 'varchar(64)', 'label' => 'Packaging', 'enabled' => '1', 'position' => 180, 'notnull' => 0, 'visible' => -1,),
125
    );
126
    public $rowid;
127
    public $entity;
128
    public $datec;
129
    public $fk_product;
130
    public $fk_soc;
131
    public $ref_fourn;
132
    public $desc_fourn;
133
    public $fk_availability;
134
    public $price;
135
    public $quantity;
136
    public $remise_percent;
137
    public $remise;
138
    public $unitprice;
139
    public $charges;
140
    public $default_vat_code;
141
    public $tva_tx;
142
    public $info_bits;
143
    public $fk_user;
144
    public $fk_supplier_price_expression;
145
    public $import_key;
146
    public $delivery_time_days;
147
    public $supplier_reputation;
148
    public $fk_multicurrency;
149
    public $multicurrency_code;
150
    public $multicurrency_tx;
151
    public $multicurrency_price;
152
    public $multicurrency_unitprice;
153
    public $localtax1_tx;
154
    public $localtax1_type;
155
    public $localtax2_tx;
156
    public $localtax2_type;
157
    public $barcode;
158
    public $fk_barcode_type;
159
    public $packaging;
160
    // END MODULEBUILDER PROPERTIES
161
162
    /**
163
     * Constructor
164
     *
165
     * @param DoliDB $db Database handler
166
     */
167
    public function __construct(DoliDB $db)
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Product\Classes\DoliDB was not found. Did you mean DoliDB? If so, make sure to prefix the type with \.
Loading history...
168
    {
169
        global $conf, $langs;
170
171
        $this->db = $db;
172
173
        $this->ismultientitymanaged = 1;
174
        $this->isextrafieldmanaged = 1;
175
176
        if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
177
            $this->fields['rowid']['visible'] = 0;
178
        }
179
        if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
180
            $this->fields['entity']['enabled'] = 0;
181
        }
182
183
        // Unset fields that are disabled
184
        foreach ($this->fields as $key => $val) {
185
            if (isset($val['enabled']) && empty($val['enabled'])) {
186
                unset($this->fields[$key]);
187
            }
188
        }
189
    }
190
191
    /**
192
     * Create object into database
193
     *
194
     * @param  User $user      User that creates
195
     * @param  int  $notrigger 0=launch triggers after, 1=disable triggers
196
     * @return int             Return integer <0 if KO, Id of created object if OK
197
     */
198
    public function create(User $user, $notrigger = 0)
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Product\Classes\User was not found. Did you mean User? If so, make sure to prefix the type with \.
Loading history...
199
    {
200
        return $this->createCommon($user, $notrigger);
201
    }
202
203
    /**
204
     * Clone an object into another one
205
     *
206
     * @param   User    $user       User that creates
207
     * @param   int     $fromid     Id of object to clone
208
     * @return  mixed               New object created, <0 if KO
209
     */
210
    public function createFromClone(User $user, $fromid)
211
    {
212
        global $langs, $extrafields;
213
        $error = 0;
214
215
        dol_syslog(__METHOD__, LOG_DEBUG);
216
217
        $object = new self($this->db);
218
219
        $this->db->begin();
220
221
        // Load source object
222
        $result = $object->fetchCommon($fromid);
223
        if ($result > 0 && !empty($object->table_element_line)) {
224
            $object->fetchLines();
0 ignored issues
show
Bug introduced by
The method fetchLines() does not exist on Dolibarr\Code\Product\Cl...ProductFournisseurPrice. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

224
            $object->/** @scrutinizer ignore-call */ 
225
                     fetchLines();
Loading history...
225
        }
226
227
        // get lines so they will be clone
228
        //foreach($this->lines as $line)
229
        //  $line->fetch_optionals();
230
231
        // Reset some properties
232
        unset($object->id);
233
        unset($object->fk_user_creat);
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$fk_user_creat has been deprecated: Use $user_creation_id ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

233
        unset(/** @scrutinizer ignore-deprecated */ $object->fk_user_creat);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
234
        unset($object->import_key);
235
236
        // Clear fields
237
        if (property_exists($object, 'ref')) {
238
            $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_" . $object->ref : $this->fields['ref']['default'];
239
        }
240
        if (property_exists($object, 'label')) {
241
            $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf") . " " . $object->label : $this->fields['label']['default'];
242
        }
243
        if (property_exists($object, 'status')) {
244
            $object->status = self::STATUS_DRAFT;
245
        }
246
        if (property_exists($object, 'date_creation')) {
247
            $object->date_creation = dol_now();
248
        }
249
        if (property_exists($object, 'date_modification')) {
250
            $object->date_modification = null;
251
        }
252
        // ...
253
        // Clear extrafields that are unique
254
        if (is_array($object->array_options) && count($object->array_options) > 0) {
255
            $extrafields->fetch_name_optionals_label($this->table_element);
256
            foreach ($object->array_options as $key => $option) {
257
                $shortkey = preg_replace('/options_/', '', $key);
258
                if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) {
259
                    //var_dump($key);
260
                    //var_dump($clonedObj->array_options[$key]); exit;
261
                    unset($object->array_options[$key]);
262
                }
263
            }
264
        }
265
266
        // Create clone
267
        $object->context['createfromclone'] = 'createfromclone';
268
        $result = $object->createCommon($user);
269
        if ($result < 0) {
270
            $error++;
271
            $this->error = $object->error;
272
            $this->errors = $object->errors;
273
        }
274
275
        if (!$error) {
276
            // copy internal contacts
277
            if ($this->copy_linked_contact($object, 'internal') < 0) {
278
                $error++;
279
            }
280
        }
281
282
        if (!$error) {
283
            // copy external contacts if same company
284
            if (property_exists($this, 'socid') && $this->socid == $object->socid) {
285
                if ($this->copy_linked_contact($object, 'external') < 0) {
286
                    $error++;
287
                }
288
            }
289
        }
290
291
        unset($object->context['createfromclone']);
292
293
        // End
294
        if (!$error) {
295
            $this->db->commit();
296
            return $object;
297
        } else {
298
            $this->db->rollback();
299
            return -1;
300
        }
301
    }
302
303
    /**
304
     * Load object in memory from the database
305
     *
306
     * @param int    $id   Id object
307
     * @return int         Return integer <0 if KO, 0 if not found, >0 if OK
308
     */
309
    public function fetch($id)
310
    {
311
        return $this->fetchCommon($id);
312
    }
313
314
    /**
315
     * Load list of objects in memory from the database.
316
     *
317
     * @param  string           $sortorder      Sort Order
318
     * @param  string           $sortfield      Sort field
319
     * @param  int              $limit          Limit
320
     * @param  int              $offset         Offset
321
     * @param  string|array     $filter         Filter USF.
322
     * @param  string           $filtermode     Filter mode (AND or OR)
323
     * @return array|int                        int <0 if KO, array of pages if OK
324
     */
325
    public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
326
    {
327
        dol_syslog(__METHOD__, LOG_DEBUG);
328
329
        $records = array();
330
331
        $sql = "SELECT ";
332
        $sql .= $this->getFieldList();
333
        $sql .= " FROM " . $this->db->prefix() . $this->table_element . " as t";
334
        if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
335
            $sql .= " WHERE t.entity IN (" . getEntity($this->element) . ")";
336
        } else {
337
            $sql .= " WHERE 1 = 1";
338
        }
339
340
        // Manage filter
341
        if (is_array($filter)) {
342
            $sqlwhere = array();
343
            if (count($filter) > 0) {
344
                foreach ($filter as $key => $value) {
345
                    if ($key == 't.rowid') {
346
                        $sqlwhere[] = $key . " = " . ((int) $value);
347
                    } elseif (array_key_exists($key, $this->fields) && in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) {
348
                        $sqlwhere[] = $key . " = '" . $this->db->idate($value) . "'";
349
                    } elseif (strpos($value, '%') === false) {
350
                        $sqlwhere[] = $key . ' IN (' . $this->db->sanitize($this->db->escape($value)) . ')';
351
                    } else {
352
                        $sqlwhere[] = $key . " LIKE '%" . $this->db->escape($this->db->escapeforlike($value)) . "%'";
353
                    }
354
                }
355
            }
356
            if (count($sqlwhere) > 0) {
357
                $sql .= ' AND (' . implode(' ' . $this->db->escape($filtermode) . ' ', $sqlwhere) . ')';
358
            }
359
360
            $filter = '';
361
        }
362
363
        // Manage filter
364
        $errormessage = '';
365
        $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
366
        if ($errormessage) {
367
            $this->errors[] = $errormessage;
368
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
369
            return -1;
370
        }
371
372
        if (!empty($sortfield)) {
373
            $sql .= $this->db->order($sortfield, $sortorder);
374
        }
375
        if (!empty($limit)) {
376
            $sql .= $this->db->plimit($limit, $offset);
377
        }
378
379
        $resql = $this->db->query($sql);
380
        if ($resql) {
381
            $num = $this->db->num_rows($resql);
382
            $i = 0;
383
            while ($i < ($limit ? min($limit, $num) : $num)) {
384
                $obj = $this->db->fetch_object($resql);
385
386
                $record = new self($this->db);
387
                $record->setVarsFromFetchObj($obj);
388
389
                $records[$record->id] = $record;
390
391
                $i++;
392
            }
393
            $this->db->free($resql);
394
395
            return $records;
396
        } else {
397
            $this->errors[] = 'Error ' . $this->db->lasterror();
398
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
399
400
            return -1;
401
        }
402
    }
403
404
    /**
405
     * Update object into database
406
     *
407
     * @param  User $user      User that modifies
408
     * @param  int  $notrigger 0=launch triggers after, 1=disable triggers
409
     * @return int             Return integer <0 if KO, >0 if OK
410
     */
411
    public function update(User $user, $notrigger = 0)
412
    {
413
        return $this->updateCommon($user, $notrigger);
414
    }
415
416
    /**
417
     * Delete object in database
418
     *
419
     * @param User $user        User that deletes
420
     * @param int   $notrigger  0=launch triggers after, 1=disable triggers
421
     * @return int              Return integer <0 if KO, >0 if OK
422
     */
423
    public function delete(User $user, $notrigger = 0)
424
    {
425
        return $this->deleteCommon($user, $notrigger);
426
    }
427
428
    /**
429
     *  Validate object
430
     *
431
     *  @param      User    $user           User making status change
432
     *  @param      int     $notrigger      1=Does not execute triggers, 0= execute triggers
433
     *  @return     int                     Return integer <=0 if OK, 0=Nothing done, >0 if KO
434
     */
435
    public function validate($user, $notrigger = 0)
436
    {
437
        global $conf, $langs;
438
439
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
440
441
        $error = 0;
442
443
        // Protection
444
        if ($this->status == self::STATUS_VALIDATED) {
445
            dol_syslog(get_class($this) . "::validate action abandoned: already validated", LOG_WARNING);
446
            return 0;
447
        }
448
449
        $now = dol_now();
450
451
        $this->db->begin();
452
453
        // Define new ref
454
        if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
455
            $num = $this->getNextNumRef();
456
        } else {
457
            $num = $this->ref;
458
        }
459
        $this->newref = $num;
460
461
        if (!empty($num)) {
462
            // Validate
463
            $sql = "UPDATE " . $this->db->prefix() . $this->table_element;
464
            $sql .= " SET ref = '" . $this->db->escape($num) . "',";
465
            $sql .= " status = " . self::STATUS_VALIDATED;
466
            if (!empty($this->fields['date_validation'])) {
467
                $sql .= ", date_validation = '" . $this->db->idate($now) . "'";
468
            }
469
            if (!empty($this->fields['fk_user_valid'])) {
470
                $sql .= ", fk_user_valid = " . $user->id;
471
            }
472
            $sql .= " WHERE rowid = " . ((int) $this->id);
473
474
            dol_syslog(get_class($this) . "::validate()", LOG_DEBUG);
475
            $resql = $this->db->query($sql);
476
            if (!$resql) {
477
                dol_print_error($this->db);
478
                $this->error = $this->db->lasterror();
479
                $error++;
480
            }
481
482
            if (!$error && !$notrigger) {
483
                // Call trigger
484
                $result = $this->call_trigger('PRODUCTFOURNISSEURPRICE_VALIDATE', $user);
485
                if ($result < 0) {
486
                    $error++;
487
                }
488
                // End call triggers
489
            }
490
        }
491
492
        if (!$error) {
493
            $this->oldref = $this->ref;
494
495
            // Rename directory if dir was a temporary ref
496
            if (preg_match('/^[\(]?PROV/i', $this->ref)) {
497
                // Now we rename also files into index
498
                $sql = 'UPDATE ' . $this->db->prefix() . "ecm_files set filename = CONCAT('" . $this->db->escape($this->newref) . "', SUBSTR(filename, " . (strlen($this->ref) + 1) . ")), filepath = 'productfournisseurprice/" . $this->db->escape($this->newref) . "'";
499
                $sql .= " WHERE filename LIKE '" . $this->db->escape($this->ref) . "%' AND filepath = 'productfournisseurprice/" . $this->db->escape($this->ref) . "' and entity = " . $conf->entity;
500
                $resql = $this->db->query($sql);
501
                if (!$resql) {
502
                    $error++;
503
                    $this->error = $this->db->lasterror();
504
                }
505
                $sql = 'UPDATE ' . MAIN_DB_PREFIX . "ecm_files set filepath = 'productfournisseurprice/" . $this->db->escape($this->newref) . "'";
506
                $sql .= " WHERE filepath = 'productfournisseurprice/" . $this->db->escape($this->ref) . "' and entity = " . $conf->entity;
507
                $resql = $this->db->query($sql);
508
                if (!$resql) {
509
                    $error++;
510
                    $this->error = $this->db->lasterror();
511
                }
512
513
                // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
514
                $oldref = dol_sanitizeFileName($this->ref);
515
                $newref = dol_sanitizeFileName($num);
516
                $dirsource = $conf->buypricehistory->dir_output . '/productfournisseurprice/' . $oldref;
517
                $dirdest = $conf->buypricehistory->dir_output . '/productfournisseurprice/' . $newref;
518
                if (!$error && file_exists($dirsource)) {
519
                    dol_syslog(get_class($this) . "::validate() rename dir " . $dirsource . " into " . $dirdest);
520
521
                    if (@rename($dirsource, $dirdest)) {
522
                        dol_syslog("Rename ok");
523
                        // Rename docs starting with $oldref with $newref
524
                        $listoffiles = dol_dir_list($conf->buypricehistory->dir_output . '/productfournisseurprice/' . $newref, 'files', 1, '^' . preg_quote($oldref, '/'));
525
                        foreach ($listoffiles as $fileentry) {
526
                            $dirsource = $fileentry['name'];
527
                            $dirdest = preg_replace('/^' . preg_quote($oldref, '/') . '/', $newref, $dirsource);
528
                            $dirsource = $fileentry['path'] . '/' . $dirsource;
529
                            $dirdest = $fileentry['path'] . '/' . $dirdest;
530
                            @rename($dirsource, $dirdest);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for rename(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

530
                            /** @scrutinizer ignore-unhandled */ @rename($dirsource, $dirdest);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
531
                        }
532
                    }
533
                }
534
            }
535
        }
536
537
        // Set new ref and current status
538
        if (!$error) {
539
            $this->ref = $num;
540
            $this->status = self::STATUS_VALIDATED;
541
        }
542
543
        if (!$error) {
544
            $this->db->commit();
545
            return 1;
546
        } else {
547
            $this->db->rollback();
548
            return -1;
549
        }
550
    }
551
552
553
    /**
554
     *  Set draft status
555
     *
556
     *  @param  User    $user           Object user that modify
557
     *  @param  int     $notrigger      1=Does not execute triggers, 0=Execute triggers
558
     *  @return int                     Return integer <0 if KO, >0 if OK
559
     */
560
    public function setDraft($user, $notrigger = 0)
561
    {
562
        // Protection
563
        if ($this->status <= self::STATUS_DRAFT) {
564
            return 0;
565
        }
566
567
        return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'PRODUCTFOURNISSEURPRICE_UNVALIDATE');
568
    }
569
570
    /**
571
     *  Set cancel status
572
     *
573
     *  @param  User    $user           Object user that modify
574
     *  @param  int     $notrigger      1=Does not execute triggers, 0=Execute triggers
575
     *  @return int                     Return integer <0 if KO, 0=Nothing done, >0 if OK
576
     */
577
    public function cancel($user, $notrigger = 0)
578
    {
579
        // Protection
580
        if ($this->status != self::STATUS_VALIDATED) {
581
            return 0;
582
        }
583
584
        return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'PRODUCTFOURNISSEURPRICE_CANCEL');
585
    }
586
587
    /**
588
     *  Set back to validated status
589
     *
590
     *  @param  User    $user           Object user that modify
591
     *  @param  int     $notrigger      1=Does not execute triggers, 0=Execute triggers
592
     *  @return int                     Return integer <0 if KO, 0=Nothing done, >0 if OK
593
     */
594
    public function reopen($user, $notrigger = 0)
595
    {
596
        // Protection
597
        if ($this->status != self::STATUS_CANCELED) {
598
            return 0;
599
        }
600
601
        return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'PRODUCTFOURNISSEURPRICE_REOPEN');
602
    }
603
604
    /**
605
     *  Return a link to the object card (with optionally the picto)
606
     *
607
     *  @param  int     $withpicto                  Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
608
     *  @param  string  $option                     On what the link point to ('nolink', ...)
609
     *  @param  int     $notooltip                  1=Disable tooltip
610
     *  @param  string  $morecss                    Add more css on link
611
     *  @param  int     $save_lastsearch_value      -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
612
     *  @return string                              String with URL
613
     */
614
    public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
615
    {
616
        global $conf, $langs, $hookmanager;
617
618
        if (!empty($conf->dol_no_mouse_hover)) {
619
            $notooltip = 1;
620
        } // Force disable tooltips
621
622
        $result = '';
623
624
        $label = img_picto('', $this->picto) . ' <u>' . $langs->trans("ProductFournisseurPrice") . '</u>';
625
        if (isset($this->status)) {
626
            $label .= ' ' . $this->getLibStatut(5);
627
        }
628
        $label .= '<br>';
629
        $label .= '<b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
630
631
        $url = dol_buildpath('/buypricehistory/productfournisseurprice_card.php', 1) . '?id=' . $this->id;
632
633
        if ($option != 'nolink') {
634
            // Add param to save lastsearch_values or not
635
            $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
636
            if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
637
                $add_save_lastsearch_values = 1;
638
            }
639
            if ($add_save_lastsearch_values) {
640
                $url .= '&save_lastsearch_values=1';
641
            }
642
        }
643
644
        $linkclose = '';
645
        if (empty($notooltip)) {
646
            if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
647
                $label = $langs->trans("ShowProductFournisseurPrice");
648
                $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
649
            }
650
            $linkclose .= ' title="' . dol_escape_htmltag($label, 1) . '"';
651
            $linkclose .= ' class="classfortooltip' . ($morecss ? ' ' . $morecss : '') . '"';
652
        } else {
653
            $linkclose = ($morecss ? ' class="' . $morecss . '"' : '');
654
        }
655
656
        $linkstart = '<a href="' . $url . '"';
657
        $linkstart .= $linkclose . '>';
658
        $linkend = '</a>';
659
660
        $result .= $linkstart;
661
662
        if (empty($this->showphoto_on_popup)) {
663
            if ($withpicto) {
664
                $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . 'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
665
            }
666
        } else {
667
            if ($withpicto) {
668
                require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
669
670
                list($class, $module) = explode('@', $this->picto);
671
                $upload_dir = $conf->$module->multidir_output[$conf->entity] . "/$class/" . dol_sanitizeFileName($this->ref);
672
                $filearray = dol_dir_list($upload_dir, "files");
673
                $filename = $filearray[0]['name'];
674
                if (!empty($filename)) {
675
                    $pospoint = strpos($filearray[0]['name'], '.');
676
677
                    $pathtophoto = $class . '/' . $this->ref . '/thumbs/' . substr($filename, 0, $pospoint) . '_mini' . substr($filename, $pospoint);
678
                    if (!getDolGlobalString(strtoupper($module . '_' . $class) . '_FORMATLISTPHOTOSASUSERS')) {
679
                        $result .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref"><img class="photo' . $module . '" alt="No photo" border="0" src="' . constant('BASE_URL') . '/viewimage.php?modulepart=' . $module . '&entity=' . $conf->entity . '&file=' . urlencode($pathtophoto) . '"></div></div>';
680
                    } else {
681
                        $result .= '<div class="floatleft inline-block valignmiddle divphotoref"><img class="photouserphoto userphoto" alt="No photo" border="0" src="' . constant('BASE_URL') . '/viewimage.php?modulepart=' . $module . '&entity=' . $conf->entity . '&file=' . urlencode($pathtophoto) . '"></div>';
682
                    }
683
684
                    $result .= '</div>';
685
                } else {
686
                    $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . 'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
687
                }
688
            }
689
        }
690
691
        if ($withpicto != 2) {
692
            $result .= $this->ref;
693
        }
694
695
        $result .= $linkend;
696
        //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
697
698
        global $action, $hookmanager;
699
        $hookmanager->initHooks(array('productfournisseurpricedao'));
700
        $parameters = array('id' => $this->id, 'getnomurl' => &$result);
701
        $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
702
        if ($reshook > 0) {
703
            $result = $hookmanager->resPrint;
704
        } else {
705
            $result .= $hookmanager->resPrint;
706
        }
707
708
        return $result;
709
    }
710
711
    /**
712
     *  Return the label of the status
713
     *
714
     *  @param  int     $mode          0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
715
     *  @return string                 Label of status
716
     */
717
    public function getLibStatut($mode = 0)
718
    {
719
        return $this->LibStatut($this->status, $mode);
720
    }
721
722
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
723
    /**
724
     *  Return the status
725
     *
726
     *  @param  int     $status        Id status
727
     *  @param  int     $mode          0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
728
     *  @return string                 Label of status
729
     */
730
    public function LibStatut($status, $mode = 0)
731
    {
732
		// phpcs:enable
733
        if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
734
            global $langs;
735
            //$langs->load("buypricehistory@buypricehistory");
736
            $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
737
            $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled');
738
            $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled');
739
            $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
740
            $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled');
741
            $this->labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled');
742
        }
743
744
        $statusType = 'status' . $status;
745
        //if ($status == self::STATUS_VALIDATED) $statusType = 'status1';
746
        if ($status == self::STATUS_CANCELED) {
747
            $statusType = 'status6';
748
        }
749
750
        return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
751
    }
752
753
    /**
754
     *  Load the info information in the object
755
     *
756
     *  @param  int     $id       Id of object
757
     *  @return void
758
     */
759
    public function info($id)
760
    {
761
        $sql = "SELECT rowid, date_creation as datec, tms as datem,";
762
        $sql .= " fk_user_creat, fk_user_modif";
763
        $sql .= " FROM " . $this->db->prefix() . $this->table_element . " as t";
764
        $sql .= " WHERE t.rowid = " . ((int) $id);
765
        $result = $this->db->query($sql);
766
        if ($result) {
767
            if ($this->db->num_rows($result)) {
768
                $obj = $this->db->fetch_object($result);
769
770
                $this->id = $obj->rowid;
771
772
                $this->user_creation_id = $obj->fk_user_author;
773
                $this->user_validation_id = $obj->fk_user_valid;
774
775
                $this->date_creation     = $this->db->jdate($obj->datec);
776
                $this->date_modification = $this->db->jdate($obj->datem);
777
            }
778
779
            $this->db->free($result);
780
        } else {
781
            dol_print_error($this->db);
782
        }
783
    }
784
785
    /**
786
     * Initialise object with example values
787
     * Id must be 0 if object instance is a specimen
788
     *
789
     * @return int
790
     */
791
    public function initAsSpecimen()
792
    {
793
        return $this->initAsSpecimenCommon();
794
    }
795
796
    /**
797
     *  Returns the reference to the following non used object depending on the active numbering module.
798
     *
799
     *  @return string              Object free reference
800
     */
801
    public function getNextNumRef()
802
    {
803
        global $langs, $conf;
804
        $langs->load("buypricehistory@buypricehistory");
805
806
        if (!getDolGlobalString('BUYPRICEHISTORY_PRODUCTFOURNISSEURPRICE_ADDON')) {
807
            $conf->global->BUYPRICEHISTORY_PRODUCTFOURNISSEURPRICE_ADDON = 'mod_productfournisseurprice_standard';
808
        }
809
810
        if (getDolGlobalString('BUYPRICEHISTORY_PRODUCTFOURNISSEURPRICE_ADDON')) {
811
            $mybool = false;
812
813
            $file = getDolGlobalString('BUYPRICEHISTORY_PRODUCTFOURNISSEURPRICE_ADDON') . ".php";
814
            $classname = getDolGlobalString('BUYPRICEHISTORY_PRODUCTFOURNISSEURPRICE_ADDON');
815
816
            // Include file with class
817
            $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
818
            foreach ($dirmodels as $reldir) {
819
                $dir = dol_buildpath($reldir . "core/modules/buypricehistory/");
820
821
                // Load file with numbering class (if found)
822
                $mybool = ((bool) @include_once $dir . $file) || $mybool;
823
            }
824
825
            if ($mybool === false) {
826
                dol_print_error(null, "Failed to include file " . $file);
827
                return '';
828
            }
829
830
            if (class_exists($classname)) {
831
                $obj = new $classname();
832
                $numref = $obj->getNextValue($this);
833
834
                if ($numref != '' && $numref != '-1') {
835
                    return $numref;
836
                } else {
837
                    $this->error = $obj->error;
838
                    //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
839
                    return "";
840
                }
841
            } else {
842
                print $langs->trans("Error") . " " . $langs->trans("ClassNotFound") . ' ' . $classname;
843
                return "";
844
            }
845
        } else {
846
            print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
847
            return "";
848
        }
849
    }
850
851
    /**
852
     *  Create a document onto disk according to template module.
853
     *
854
     *  @param      string      $modele         Force template to use ('' to not force)
855
     *  @param      Translate   $outputlangs    object lang a utiliser pour traduction
856
     *  @param      int         $hidedetails    Hide details of lines
857
     *  @param      int         $hidedesc       Hide description
858
     *  @param      int         $hideref        Hide ref
859
     *  @param      null|array  $moreparams     Array to provide more information
860
     *  @return     int                         0 if KO, 1 if OK
861
     */
862
    public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
863
    {
864
        global $conf, $langs;
865
866
        $result = 0;
867
        $includedocgeneration = 0;
868
869
        $langs->load("buypricehistory@buypricehistory");
870
871
        if (!dol_strlen($modele)) {
872
            $modele = 'standard_productfournisseurprice';
873
874
            if (!empty($this->model_pdf)) {
875
                $modele = $this->model_pdf;
876
            } elseif (getDolGlobalString('PRODUCTFOURNISSEURPRICE_ADDON_PDF')) {
877
                $modele = getDolGlobalString('PRODUCTFOURNISSEURPRICE_ADDON_PDF');
878
            }
879
        }
880
881
        $modelpath = "core/modules/buypricehistory/doc/";
882
883
        if ($includedocgeneration && !empty($modele)) {
884
            $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
885
        }
886
887
        return $result;
888
    }
889
}
890