| Total Complexity | 320 | 
| Total Lines | 2817 | 
| Duplicated Lines | 0 % | 
| Changes | 0 | ||
Complex classes like ExpenseReport often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use ExpenseReport, and based on these observations, apply Extract Interface, too.
| 1 | <?php | ||
| 41 | class ExpenseReport extends CommonObject | ||
| 42 | { | ||
| 43 | /** | ||
| 44 | * @var string ID to identify managed object | ||
| 45 | */ | ||
| 46 | public $element = 'expensereport'; | ||
| 47 | |||
| 48 | /** | ||
| 49 | * @var string Name of table without prefix where object is stored | ||
| 50 | */ | ||
| 51 | public $table_element = 'expensereport'; | ||
| 52 | |||
| 53 | /** | ||
| 54 | * @var string table element line name | ||
| 55 | */ | ||
| 56 | public $table_element_line = 'expensereport_det'; | ||
| 57 | |||
| 58 | /** | ||
| 59 | * @var string Fieldname with ID of parent key if this field has a parent | ||
| 60 | */ | ||
| 61 | public $fk_element = 'fk_expensereport'; | ||
| 62 | |||
| 63 | /** | ||
| 64 | * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png | ||
| 65 | */ | ||
| 66 | public $picto = 'trip'; | ||
| 67 | |||
| 68 | /** | ||
| 69 | * @var ExpenseReportLine[] array of expensereport lines | ||
| 70 | */ | ||
| 71 | public $lines = array(); | ||
| 72 | |||
| 73 | /** | ||
| 74 | * @var ExpenseReportLine expensereport lines | ||
| 75 | */ | ||
| 76 | public $line; | ||
| 77 | |||
| 78 | /** | ||
| 79 | * @var int|string | ||
| 80 | */ | ||
| 81 | public $date_debut; | ||
| 82 | |||
| 83 | /** | ||
| 84 | * @var int|string | ||
| 85 | */ | ||
| 86 | public $date_fin; | ||
| 87 | |||
| 88 | /** | ||
| 89 | * @var int|string | ||
| 90 | */ | ||
| 91 | public $date_approbation; | ||
| 92 | |||
| 93 | /** | ||
| 94 | * @var int ID | ||
| 95 | */ | ||
| 96 | public $fk_user; | ||
| 97 | |||
| 98 | /** | ||
| 99 | * @var int ID | ||
| 100 | */ | ||
| 101 | public $user_approve_id; | ||
| 102 | |||
| 103 | /** | ||
| 104 | * 0=draft, 2=validated (attente approb), 4=canceled, 5=approved, 6=paid, 99=denied | ||
| 105 | * | ||
| 106 | * @var int Status | ||
| 107 | */ | ||
| 108 | public $status; | ||
| 109 | |||
| 110 | /** | ||
| 111 | * 0=draft, 2=validated (attente approb), 4=canceled, 5=approved, 6=paid, 99=denied | ||
| 112 | * | ||
| 113 | * @var int Status | ||
| 114 | * @deprecated | ||
| 115 | */ | ||
| 116 | public $fk_statut; | ||
| 117 | |||
| 118 | /** | ||
| 119 | * @var int ID | ||
| 120 | */ | ||
| 121 | public $fk_c_paiement; | ||
| 122 | |||
| 123 | /** | ||
| 124 | * @var int ID | ||
| 125 | */ | ||
| 126 | public $modepaymentid; | ||
| 127 | |||
| 128 | public $paid; | ||
| 129 | |||
| 130 | // Paiement | ||
| 131 | /** | ||
| 132 | * @var string Firstname Lastname | ||
| 133 | */ | ||
| 134 | public $user_paid_infos; | ||
| 135 | |||
| 136 | /** | ||
| 137 | * @var string Firstname Lastname | ||
| 138 | */ | ||
| 139 | public $user_author_infos; | ||
| 140 | |||
| 141 | /** | ||
| 142 | * @var string Firstname Lastname | ||
| 143 | */ | ||
| 144 | public $user_validator_infos; | ||
| 145 | |||
| 146 | public $rule_warning_message; | ||
| 147 | |||
| 148 | // ACTIONS | ||
| 149 | |||
| 150 | // Create | ||
| 151 | /** | ||
| 152 | * @var int|string | ||
| 153 | */ | ||
| 154 | public $date_create; | ||
| 155 | |||
| 156 | /** | ||
| 157 | * @var int ID of user creator | ||
| 158 | */ | ||
| 159 | public $fk_user_creat; | ||
| 160 | |||
| 161 | /** | ||
| 162 | * @var int ID of user who reclaim expense report | ||
| 163 | */ | ||
| 164 | public $fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for. | ||
| 165 | |||
| 166 | // Update | ||
| 167 | /** | ||
| 168 | * @var int|string | ||
| 169 | */ | ||
| 170 | public $date_modif; | ||
| 171 | |||
| 172 | /** | ||
| 173 | * @var int ID | ||
| 174 | */ | ||
| 175 | public $fk_user_modif; | ||
| 176 | |||
| 177 | // Refus | ||
| 178 | /** | ||
| 179 | * @var int|string | ||
| 180 | */ | ||
| 181 | public $date_refuse; | ||
| 182 | |||
| 183 | /** | ||
| 184 | * @var string | ||
| 185 | */ | ||
| 186 | public $detail_refuse; | ||
| 187 | |||
| 188 | /** | ||
| 189 | * @var int ID | ||
| 190 | */ | ||
| 191 | public $fk_user_refuse; | ||
| 192 | |||
| 193 | // Annulation | ||
| 194 | /** | ||
| 195 | * @var int|string | ||
| 196 | */ | ||
| 197 | public $date_cancel; | ||
| 198 | |||
| 199 | /** | ||
| 200 | * @var string | ||
| 201 | */ | ||
| 202 | public $detail_cancel; | ||
| 203 | |||
| 204 | /** | ||
| 205 | * @var int ID of user who cancel expense report | ||
| 206 | */ | ||
| 207 | public $fk_user_cancel; | ||
| 208 | |||
| 209 | /** | ||
| 210 | * @var int User that is defined to approve | ||
| 211 | */ | ||
| 212 | public $fk_user_validator; | ||
| 213 | |||
| 214 | /** | ||
| 215 | * Validation date | ||
| 216 | * @var int | ||
| 217 | * @deprecated | ||
| 218 | * @see $date_valid | ||
| 219 | */ | ||
| 220 | public $datevalid; | ||
| 221 | |||
| 222 | /** | ||
| 223 | * Validation date | ||
| 224 | * @var int | ||
| 225 | */ | ||
| 226 | public $date_valid; | ||
| 227 | |||
| 228 | /** | ||
| 229 | * @var int ID of User making validation | ||
| 230 | */ | ||
| 231 | public $fk_user_valid; | ||
| 232 | |||
| 233 | /** | ||
| 234 | * @var string Firstname Lastname | ||
| 235 | */ | ||
| 236 | public $user_valid_infos; | ||
| 237 | |||
| 238 | // Approve | ||
| 239 | /** | ||
| 240 | * @var int|string | ||
| 241 | */ | ||
| 242 | public $date_approve; | ||
| 243 | |||
| 244 | /** | ||
| 245 | * @var int ID User that has approved | ||
| 246 | */ | ||
| 247 | public $fk_user_approve; | ||
| 248 | |||
| 249 | public $localtax1; // for backward compatibility (real field should be total_localtax1 defined into CommonObject) | ||
| 250 | public $localtax2; // for backward compatibility (real field should be total_localtax2 defined into CommonObject) | ||
| 251 | |||
| 252 | /** | ||
| 253 | * Draft status | ||
| 254 | */ | ||
| 255 | const STATUS_DRAFT = 0; | ||
| 256 | |||
| 257 | /** | ||
| 258 | * Validated (need to be paid) | ||
| 259 | */ | ||
| 260 | const STATUS_VALIDATED = 2; | ||
| 261 | |||
| 262 | /** | ||
| 263 | * Classified canceled | ||
| 264 | */ | ||
| 265 | const STATUS_CANCELED = 4; | ||
| 266 | |||
| 267 | /** | ||
| 268 | * Classified approved | ||
| 269 | */ | ||
| 270 | const STATUS_APPROVED = 5; | ||
| 271 | |||
| 272 | /** | ||
| 273 | * Classified paid. | ||
| 274 | */ | ||
| 275 | const STATUS_CLOSED = 6; | ||
| 276 | |||
| 277 | /** | ||
| 278 | * Classified refused | ||
| 279 | */ | ||
| 280 | const STATUS_REFUSED = 99; | ||
| 281 | |||
| 282 | public $fields = array( | ||
| 283 |         'rowid' => array('type' => 'integer', 'label' => 'ID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10), | ||
| 284 |         'ref' => array('type' => 'varchar(50)', 'label' => 'Ref', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'showoncombobox' => 1, 'position' => 15), | ||
| 285 |         'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => '1', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 20), | ||
| 286 |         'ref_number_int' => array('type' => 'integer', 'label' => 'Ref number int', 'enabled' => 1, 'visible' => -1, 'position' => 25), | ||
| 287 |         'ref_ext' => array('type' => 'integer', 'label' => 'Ref ext', 'enabled' => 1, 'visible' => -1, 'position' => 30), | ||
| 288 |         'total_ht' => array('type' => 'double(24,8)', 'label' => 'Total ht', 'enabled' => 1, 'visible' => -1, 'position' => 35), | ||
| 289 |         'total_tva' => array('type' => 'double(24,8)', 'label' => 'Total tva', 'enabled' => 1, 'visible' => -1, 'position' => 40), | ||
| 290 |         'localtax1' => array('type' => 'double(24,8)', 'label' => 'Localtax1', 'enabled' => 1, 'visible' => -1, 'position' => 45), | ||
| 291 |         'localtax2' => array('type' => 'double(24,8)', 'label' => 'Localtax2', 'enabled' => 1, 'visible' => -1, 'position' => 50), | ||
| 292 |         'total_ttc' => array('type' => 'double(24,8)', 'label' => 'Total ttc', 'enabled' => 1, 'visible' => -1, 'position' => 55), | ||
| 293 |         'date_debut' => array('type' => 'date', 'label' => 'Date debut', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 60), | ||
| 294 |         'date_fin' => array('type' => 'date', 'label' => 'Date fin', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 65), | ||
| 295 |         'date_valid' => array('type' => 'datetime', 'label' => 'Date valid', 'enabled' => 1, 'visible' => -1, 'position' => 75), | ||
| 296 |         'date_approve' => array('type' => 'datetime', 'label' => 'Date approve', 'enabled' => 1, 'visible' => -1, 'position' => 80), | ||
| 297 |         'date_refuse' => array('type' => 'datetime', 'label' => 'Date refuse', 'enabled' => 1, 'visible' => -1, 'position' => 85), | ||
| 298 |         'date_cancel' => array('type' => 'datetime', 'label' => 'Date cancel', 'enabled' => 1, 'visible' => -1, 'position' => 90), | ||
| 299 |         'fk_user_author' => array('type' => 'integer', 'label' => 'Fk user author', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 100), | ||
| 300 |         'fk_user_modif' => array('type' => 'integer', 'label' => 'Fk user modif', 'enabled' => 1, 'visible' => -1, 'position' => 105), | ||
| 301 |         'fk_user_valid' => array('type' => 'integer', 'label' => 'Fk user valid', 'enabled' => 1, 'visible' => -1, 'position' => 110), | ||
| 302 |         'fk_user_validator' => array('type' => 'integer', 'label' => 'Fk user validator', 'enabled' => 1, 'visible' => -1, 'position' => 115), | ||
| 303 |         'fk_user_approve' => array('type' => 'integer', 'label' => 'Fk user approve', 'enabled' => 1, 'visible' => -1, 'position' => 120), | ||
| 304 |         'fk_user_refuse' => array('type' => 'integer', 'label' => 'Fk user refuse', 'enabled' => 1, 'visible' => -1, 'position' => 125), | ||
| 305 |         'fk_user_cancel' => array('type' => 'integer', 'label' => 'Fk user cancel', 'enabled' => 1, 'visible' => -1, 'position' => 130), | ||
| 306 |         'fk_c_paiement' => array('type' => 'integer', 'label' => 'Fk c paiement', 'enabled' => 1, 'visible' => -1, 'position' => 140), | ||
| 307 |         'paid' => array('type' => 'integer', 'label' => 'Paid', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 145), | ||
| 308 |         'note_public' => array('type' => 'html', 'label' => 'Note public', 'enabled' => 1, 'visible' => 0, 'position' => 150), | ||
| 309 |         'note_private' => array('type' => 'html', 'label' => 'Note private', 'enabled' => 1, 'visible' => 0, 'position' => 155), | ||
| 310 |         'detail_refuse' => array('type' => 'varchar(255)', 'label' => 'Detail refuse', 'enabled' => 1, 'visible' => -1, 'position' => 160), | ||
| 311 |         'detail_cancel' => array('type' => 'varchar(255)', 'label' => 'Detail cancel', 'enabled' => 1, 'visible' => -1, 'position' => 165), | ||
| 312 |         'integration_compta' => array('type' => 'integer', 'label' => 'Integration compta', 'enabled' => 1, 'visible' => -1, 'position' => 170), | ||
| 313 |         'fk_bank_account' => array('type' => 'integer', 'label' => 'Fk bank account', 'enabled' => 1, 'visible' => -1, 'position' => 175), | ||
| 314 |         'fk_multicurrency' => array('type' => 'integer', 'label' => 'Fk multicurrency', 'enabled' => 1, 'visible' => -1, 'position' => 185), | ||
| 315 |         'multicurrency_code' => array('type' => 'varchar(255)', 'label' => 'Multicurrency code', 'enabled' => 1, 'visible' => -1, 'position' => 190), | ||
| 316 |         'multicurrency_tx' => array('type' => 'double(24,8)', 'label' => 'Multicurrency tx', 'enabled' => 1, 'visible' => -1, 'position' => 195), | ||
| 317 |         'multicurrency_total_ht' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total ht', 'enabled' => 1, 'visible' => -1, 'position' => 200), | ||
| 318 |         'multicurrency_total_tva' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total tva', 'enabled' => 1, 'visible' => -1, 'position' => 205), | ||
| 319 |         'multicurrency_total_ttc' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total ttc', 'enabled' => 1, 'visible' => -1, 'position' => 210), | ||
| 320 |         'extraparams' => array('type' => 'varchar(255)', 'label' => 'Extraparams', 'enabled' => 1, 'visible' => -1, 'position' => 220), | ||
| 321 |         'date_create' => array('type' => 'datetime', 'label' => 'Date create', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 300), | ||
| 322 |         'tms' => array('type' => 'timestamp', 'label' => 'Tms', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 305), | ||
| 323 |         'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -1, 'position' => 1000), | ||
| 324 |         'model_pdf' => array('type' => 'varchar(255)', 'label' => 'Model pdf', 'enabled' => 1, 'visible' => 0, 'position' => 1010), | ||
| 325 |         'fk_statut' => array('type' => 'integer', 'label' => 'Fk statut', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 500), | ||
| 326 | ); | ||
| 327 | |||
| 328 | /** | ||
| 329 | * Constructor | ||
| 330 | * | ||
| 331 | * @param DoliDB $db Handler access base de donnees | ||
|  | |||
| 332 | */ | ||
| 333 | public function __construct($db) | ||
| 348 | } | ||
| 349 | |||
| 350 | /** | ||
| 351 | * Create object in database | ||
| 352 | * | ||
| 353 | * @param User $user User that create | ||
| 354 | * @param int $notrigger Disable triggers | ||
| 355 | * @return int Return integer <0 if KO, >0 if OK | ||
| 356 | */ | ||
| 357 | public function create($user, $notrigger = 0) | ||
| 358 |     { | ||
| 359 | global $conf, $langs; | ||
| 360 | |||
| 361 | $now = dol_now(); | ||
| 362 | |||
| 363 | $error = 0; | ||
| 364 | |||
| 365 | // Check parameters | ||
| 366 |         if (empty($this->date_debut) || empty($this->date_fin)) { | ||
| 367 |             $this->error = $langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Date')); | ||
| 368 | return -1; | ||
| 369 | } | ||
| 370 | |||
| 371 | $fuserid = $this->fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for. | ||
| 372 |         if (empty($fuserid)) { | ||
| 373 | $fuserid = $user->id; | ||
| 374 | } | ||
| 375 | |||
| 376 | $this->db->begin(); | ||
| 377 | |||
| 378 |         $sql = "INSERT INTO " . MAIN_DB_PREFIX . $this->table_element . " ("; | ||
| 379 | $sql .= "ref"; | ||
| 380 | $sql .= ",total_ht"; | ||
| 381 | $sql .= ",total_ttc"; | ||
| 382 | $sql .= ",total_tva"; | ||
| 383 | $sql .= ",date_debut"; | ||
| 384 | $sql .= ",date_fin"; | ||
| 385 | $sql .= ",date_create"; | ||
| 386 | $sql .= ",fk_user_creat"; | ||
| 387 | $sql .= ",fk_user_author"; | ||
| 388 | $sql .= ",fk_user_validator"; | ||
| 389 | $sql .= ",fk_user_approve"; | ||
| 390 | $sql .= ",fk_user_modif"; | ||
| 391 | $sql .= ",fk_statut"; | ||
| 392 | $sql .= ",fk_c_paiement"; | ||
| 393 | $sql .= ",paid"; | ||
| 394 | $sql .= ",note_public"; | ||
| 395 | $sql .= ",note_private"; | ||
| 396 | $sql .= ",entity"; | ||
| 397 |         $sql .= ") VALUES("; | ||
| 398 | $sql .= "'(PROV)'"; | ||
| 399 | $sql .= ", " . price2num($this->total_ht, 'MT'); | ||
| 400 | $sql .= ", " . price2num($this->total_ttc, 'MT'); | ||
| 401 | $sql .= ", " . price2num($this->total_tva, 'MT'); | ||
| 402 | $sql .= ", '" . $this->db->idate($this->date_debut) . "'"; | ||
| 403 | $sql .= ", '" . $this->db->idate($this->date_fin) . "'"; | ||
| 404 | $sql .= ", '" . $this->db->idate($now) . "'"; | ||
| 405 | $sql .= ", " . ((int) $user->id); | ||
| 406 | $sql .= ", " . ((int) $fuserid); | ||
| 407 | $sql .= ", " . ($this->fk_user_validator > 0 ? ((int) $this->fk_user_validator) : "null"); | ||
| 408 | $sql .= ", " . ($this->fk_user_approve > 0 ? ((int) $this->fk_user_approve) : "null"); | ||
| 409 | $sql .= ", " . ($this->fk_user_modif > 0 ? ((int) $this->fk_user_modif) : "null"); | ||
| 410 | $sql .= ", " . ($this->fk_statut > 1 ? ((int) $this->fk_statut) : 0); | ||
| 411 | $sql .= ", " . ($this->modepaymentid ? ((int) $this->modepaymentid) : "null"); | ||
| 412 | $sql .= ", 0"; | ||
| 413 | $sql .= ", " . ($this->note_public ? "'" . $this->db->escape($this->note_public) . "'" : "null"); | ||
| 414 | $sql .= ", " . ($this->note_private ? "'" . $this->db->escape($this->note_private) . "'" : "null"); | ||
| 415 | $sql .= ", " . ((int) $conf->entity); | ||
| 416 | $sql .= ")"; | ||
| 417 | |||
| 418 | $result = $this->db->query($sql); | ||
| 419 |         if ($result) { | ||
| 420 | $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element); | ||
| 421 | $this->ref = '(PROV' . $this->id . ')'; | ||
| 422 | |||
| 423 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element . " SET ref='" . $this->db->escape($this->ref) . "' WHERE rowid=" . ((int) $this->id); | ||
| 424 | $resql = $this->db->query($sql); | ||
| 425 |             if (!$resql) { | ||
| 426 | $this->error = $this->db->lasterror(); | ||
| 427 | $error++; | ||
| 428 | } | ||
| 429 | |||
| 430 |             if (!$error) { | ||
| 431 |                 if (is_array($this->lines) && count($this->lines) > 0) { | ||
| 432 |                     foreach ($this->lines as $line) { | ||
| 433 | // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array | ||
| 434 | //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object. | ||
| 435 |                         if (!is_object($line)) { | ||
| 436 | $line = (object) $line; | ||
| 437 | $newndfline = new ExpenseReportLine($this->db); | ||
| 438 | $newndfline->fk_expensereport = $line->fk_expensereport; | ||
| 439 | $newndfline->fk_c_type_fees = $line->fk_c_type_fees; | ||
| 440 | $newndfline->fk_project = $line->fk_project; | ||
| 441 | $newndfline->vatrate = $line->vatrate; | ||
| 442 | $newndfline->vat_src_code = $line->vat_src_code; | ||
| 443 | $newndfline->localtax1_tx = $line->localtax1_tx; | ||
| 444 | $newndfline->localtax2_tx = $line->localtax2_tx; | ||
| 445 | $newndfline->localtax1_type = $line->localtax1_type; | ||
| 446 | $newndfline->localtax2_type = $line->localtax2_type; | ||
| 447 | $newndfline->comments = $line->comments; | ||
| 448 | $newndfline->qty = $line->qty; | ||
| 449 | $newndfline->value_unit = $line->value_unit; | ||
| 450 | $newndfline->total_ht = $line->total_ht; | ||
| 451 | $newndfline->total_ttc = $line->total_ttc; | ||
| 452 | $newndfline->total_tva = $line->total_tva; | ||
| 453 | $newndfline->total_localtax1 = $line->total_localtax1; | ||
| 454 | $newndfline->total_localtax2 = $line->total_localtax2; | ||
| 455 | $newndfline->date = $line->date; | ||
| 456 | $newndfline->rule_warning_message = $line->rule_warning_message; | ||
| 457 | $newndfline->fk_c_exp_tax_cat = $line->fk_c_exp_tax_cat; | ||
| 458 | $newndfline->fk_ecm_files = $line->fk_ecm_files; | ||
| 459 |                         } else { | ||
| 460 | $newndfline = $line; | ||
| 461 | } | ||
| 462 | //$newndfline=new ExpenseReportLine($this->db); | ||
| 463 | $newndfline->fk_expensereport = $this->id; | ||
| 464 | $result = $newndfline->insert(); | ||
| 465 |                         if ($result < 0) { | ||
| 466 | $this->error = $newndfline->error; | ||
| 467 | $this->errors = $newndfline->errors; | ||
| 468 | $error++; | ||
| 469 | break; | ||
| 470 | } | ||
| 471 | } | ||
| 472 | } | ||
| 473 | } | ||
| 474 | |||
| 475 |             if (!$error) { | ||
| 476 | $result = $this->insertExtraFields(); | ||
| 477 |                 if ($result < 0) { | ||
| 478 | $error++; | ||
| 479 | } | ||
| 480 | } | ||
| 481 | |||
| 482 |             if (!$error) { | ||
| 483 | $result = $this->update_price(1); | ||
| 484 |                 if ($result > 0) { | ||
| 485 |                     if (!$notrigger) { | ||
| 486 | // Call trigger | ||
| 487 |                         $result = $this->call_trigger('EXPENSE_REPORT_CREATE', $user); | ||
| 488 | |||
| 489 |                         if ($result < 0) { | ||
| 490 | $error++; | ||
| 491 | } | ||
| 492 | // End call triggers | ||
| 493 | } | ||
| 494 | |||
| 495 |                     if (empty($error)) { | ||
| 496 | $this->db->commit(); | ||
| 497 | return $this->id; | ||
| 498 |                     } else { | ||
| 499 | $this->db->rollback(); | ||
| 500 | return -4; | ||
| 501 | } | ||
| 502 |                 } else { | ||
| 503 | $this->db->rollback(); | ||
| 504 | return -3; | ||
| 505 | } | ||
| 506 |             } else { | ||
| 507 | dol_syslog(get_only_class($this) . "::create error " . $this->error, LOG_ERR); | ||
| 508 | $this->db->rollback(); | ||
| 509 | return -2; | ||
| 510 | } | ||
| 511 |         } else { | ||
| 512 | $this->error = $this->db->lasterror() . " sql=" . $sql; | ||
| 513 | $this->db->rollback(); | ||
| 514 | return -1; | ||
| 515 | } | ||
| 516 | } | ||
| 517 | |||
| 518 | /** | ||
| 519 | * Load an object from its id and create a new one in database | ||
| 520 | * | ||
| 521 | * @param User $user User making the clone | ||
| 522 | * @param int $fk_user_author Id of new user | ||
| 523 | * @return int New id of clone | ||
| 524 | */ | ||
| 525 | public function createFromClone(User $user, $fk_user_author) | ||
| 526 |     { | ||
| 527 | global $hookmanager; | ||
| 528 | |||
| 529 | $error = 0; | ||
| 530 | |||
| 531 |         if (empty($fk_user_author)) { | ||
| 532 | $fk_user_author = $user->id; | ||
| 533 | } | ||
| 534 | |||
| 535 | $this->db->begin(); | ||
| 536 | |||
| 537 | // get extrafields so they will be clone | ||
| 538 | //foreach($this->lines as $line) | ||
| 539 | //$line->fetch_optionals(); | ||
| 540 | |||
| 541 | // Load source object | ||
| 542 | $objFrom = clone $this; | ||
| 543 | |||
| 544 | $this->id = 0; | ||
| 545 | $this->ref = ''; | ||
| 546 | $this->status = 0; | ||
| 547 | $this->fk_statut = 0; // deprecated | ||
| 548 | |||
| 549 | // Clear fields | ||
| 550 | $this->fk_user_creat = $user->id; | ||
| 551 | $this->fk_user_author = $fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for. | ||
| 552 | $this->fk_user_valid = 0; | ||
| 553 | $this->date_create = ''; | ||
| 554 | $this->date_creation = ''; | ||
| 555 | $this->date_validation = ''; | ||
| 556 | |||
| 557 | // Remove link on lines to a joined file | ||
| 558 |         if (is_array($this->lines) && count($this->lines) > 0) { | ||
| 559 |             foreach ($this->lines as $key => $line) { | ||
| 560 | $this->lines[$key]->fk_ecm_files = 0; | ||
| 561 | } | ||
| 562 | } | ||
| 563 | |||
| 564 | // Create clone | ||
| 565 | $this->context['createfromclone'] = 'createfromclone'; | ||
| 566 | $result = $this->create($user); | ||
| 567 |         if ($result < 0) { | ||
| 568 | $error++; | ||
| 569 | } | ||
| 570 | |||
| 571 |         if (!$error) { | ||
| 572 | // Hook of thirdparty module | ||
| 573 |             if (is_object($hookmanager)) { | ||
| 574 |                 $parameters = array('objFrom' => $objFrom); | ||
| 575 | $action = ''; | ||
| 576 |                 $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks | ||
| 577 |                 if ($reshook < 0) { | ||
| 578 | $this->setErrorsFromObject($hookmanager); | ||
| 579 | $error++; | ||
| 580 | } | ||
| 581 | } | ||
| 582 | } | ||
| 583 | |||
| 584 | unset($this->context['createfromclone']); | ||
| 585 | |||
| 586 | // End | ||
| 587 |         if (!$error) { | ||
| 588 | $this->db->commit(); | ||
| 589 | return $this->id; | ||
| 590 |         } else { | ||
| 591 | $this->db->rollback(); | ||
| 592 | return -1; | ||
| 593 | } | ||
| 594 | } | ||
| 595 | |||
| 596 | |||
| 597 | /** | ||
| 598 | * update | ||
| 599 | * | ||
| 600 | * @param User $user User making change | ||
| 601 | * @param int $notrigger Disable triggers | ||
| 602 | * @param User $userofexpensereport New user we want to have the expense report on. | ||
| 603 | * @return int Return integer <0 if KO, >0 if OK | ||
| 604 | */ | ||
| 605 | public function update($user, $notrigger = 0, $userofexpensereport = null) | ||
| 606 |     { | ||
| 607 | global $langs; | ||
| 608 | |||
| 609 | $error = 0; | ||
| 610 | $this->db->begin(); | ||
| 611 | |||
| 612 | $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element . " SET"; | ||
| 613 | $sql .= " total_ht = " . $this->total_ht; | ||
| 614 | $sql .= " , total_ttc = " . $this->total_ttc; | ||
| 615 | $sql .= " , total_tva = " . $this->total_tva; | ||
| 616 | $sql .= " , date_debut = '" . $this->db->idate($this->date_debut) . "'"; | ||
| 617 | $sql .= " , date_fin = '" . $this->db->idate($this->date_fin) . "'"; | ||
| 618 |         if ($userofexpensereport && is_object($userofexpensereport)) { | ||
| 619 | $sql .= " , fk_user_author = " . ($userofexpensereport->id > 0 ? $userofexpensereport->id : "null"); // Note fk_user_author is not the 'author' but the guy the expense report is for. | ||
| 620 | } | ||
| 621 | $sql .= " , fk_user_validator = " . ($this->fk_user_validator > 0 ? $this->fk_user_validator : "null"); | ||
| 622 | $sql .= " , fk_user_valid = " . ($this->fk_user_valid > 0 ? $this->fk_user_valid : "null"); | ||
| 623 | $sql .= " , fk_user_approve = " . ($this->fk_user_approve > 0 ? $this->fk_user_approve : "null"); | ||
| 624 | $sql .= " , fk_user_modif = " . $user->id; | ||
| 625 | $sql .= " , fk_statut = " . ($this->fk_statut >= 0 ? $this->fk_statut : '0'); | ||
| 626 | $sql .= " , fk_c_paiement = " . ($this->fk_c_paiement > 0 ? $this->fk_c_paiement : "null"); | ||
| 627 | $sql .= " , note_public = " . (!empty($this->note_public) ? "'" . $this->db->escape($this->note_public) . "'" : "''"); | ||
| 628 | $sql .= " , note_private = " . (!empty($this->note_private) ? "'" . $this->db->escape($this->note_private) . "'" : "''"); | ||
| 629 | $sql .= " , detail_refuse = " . (!empty($this->detail_refuse) ? "'" . $this->db->escape($this->detail_refuse) . "'" : "''"); | ||
| 630 | $sql .= " WHERE rowid = " . ((int) $this->id); | ||
| 631 | |||
| 632 | dol_syslog(get_only_class($this) . "::update", LOG_DEBUG); | ||
| 633 | $result = $this->db->query($sql); | ||
| 634 |         if ($result) { | ||
| 635 |             if (!$notrigger) { | ||
| 636 | // Call trigger | ||
| 637 |                 $result = $this->call_trigger('EXPENSE_REPORT_MODIFY', $user); | ||
| 638 | |||
| 639 |                 if ($result < 0) { | ||
| 640 | $error++; | ||
| 641 | } | ||
| 642 | // End call triggers | ||
| 643 | } | ||
| 644 | |||
| 645 |             if (empty($error)) { | ||
| 646 | $this->db->commit(); | ||
| 647 | return 1; | ||
| 648 |             } else { | ||
| 649 | $this->db->rollback(); | ||
| 650 | $this->error = $this->db->error(); | ||
| 651 | return -2; | ||
| 652 | } | ||
| 653 |         } else { | ||
| 654 | $this->db->rollback(); | ||
| 655 | $this->error = $this->db->error(); | ||
| 656 | return -1; | ||
| 657 | } | ||
| 658 | } | ||
| 659 | |||
| 660 | /** | ||
| 661 | * Load an object from database | ||
| 662 | * | ||
| 663 |      *  @param  int     $id     Id                      {@min 1} | ||
| 664 |      *  @param  string  $ref    Ref                     {@name ref} | ||
| 665 | * @return int Return integer <0 if KO, >0 if OK | ||
| 666 | */ | ||
| 667 | public function fetch($id, $ref = '') | ||
| 668 |     { | ||
| 669 | $sql = "SELECT d.rowid, d.entity, d.ref, d.note_public, d.note_private,"; // DEFAULT | ||
| 670 | $sql .= " d.detail_refuse, d.detail_cancel, d.fk_user_refuse, d.fk_user_cancel,"; // ACTIONS | ||
| 671 | $sql .= " d.date_refuse, d.date_cancel,"; // ACTIONS | ||
| 672 | $sql .= " d.total_ht, d.total_ttc, d.total_tva,"; | ||
| 673 | $sql .= " d.localtax1 as total_localtax1, d.localtax2 as total_localtax2,"; | ||
| 674 | $sql .= " d.date_debut, d.date_fin, d.date_create, d.tms as date_modif, d.date_valid, d.date_approve,"; // DATES (datetime) | ||
| 675 | $sql .= " d.fk_user_creat, d.fk_user_author, d.fk_user_modif, d.fk_user_validator,"; | ||
| 676 | $sql .= " d.fk_user_valid, d.fk_user_approve,"; | ||
| 677 | $sql .= " d.fk_statut as status, d.fk_c_paiement, d.paid"; | ||
| 678 | $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element . " as d"; | ||
| 679 |         if ($ref) { | ||
| 680 | $sql .= " WHERE d.ref = '" . $this->db->escape($ref) . "'"; | ||
| 681 |         } else { | ||
| 682 | $sql .= " WHERE d.rowid = " . ((int) $id); | ||
| 683 | } | ||
| 684 | //$sql.= $restrict; | ||
| 685 | |||
| 686 | dol_syslog(get_only_class($this) . "::fetch", LOG_DEBUG); | ||
| 687 | $resql = $this->db->query($sql); | ||
| 688 |         if ($resql) { | ||
| 689 | $obj = $this->db->fetch_object($resql); | ||
| 690 |             if ($obj) { | ||
| 691 | $this->id = $obj->rowid; | ||
| 692 | $this->ref = $obj->ref; | ||
| 693 | |||
| 694 | $this->entity = $obj->entity; | ||
| 695 | |||
| 696 | $this->total_ht = $obj->total_ht; | ||
| 697 | $this->total_tva = $obj->total_tva; | ||
| 698 | $this->total_ttc = $obj->total_ttc; | ||
| 699 | $this->localtax1 = $obj->total_localtax1; // For backward compatibility | ||
| 700 | $this->localtax2 = $obj->total_localtax2; // For backward compatibility | ||
| 701 | $this->total_localtax1 = $obj->total_localtax1; | ||
| 702 | $this->total_localtax2 = $obj->total_localtax2; | ||
| 703 | |||
| 704 | $this->note_public = $obj->note_public; | ||
| 705 | $this->note_private = $obj->note_private; | ||
| 706 | $this->detail_refuse = $obj->detail_refuse; | ||
| 707 | $this->detail_cancel = $obj->detail_cancel; | ||
| 708 | |||
| 709 | $this->date_debut = $this->db->jdate($obj->date_debut); | ||
| 710 | $this->date_fin = $this->db->jdate($obj->date_fin); | ||
| 711 | $this->date_valid = $this->db->jdate($obj->date_valid); | ||
| 712 | $this->date_approve = $this->db->jdate($obj->date_approve); | ||
| 713 | $this->date_create = $this->db->jdate($obj->date_create); | ||
| 714 | $this->date_modif = $this->db->jdate($obj->date_modif); | ||
| 715 | $this->date_refuse = $this->db->jdate($obj->date_refuse); | ||
| 716 | $this->date_cancel = $this->db->jdate($obj->date_cancel); | ||
| 717 | |||
| 718 | $this->fk_user_creat = $obj->fk_user_creat; | ||
| 719 | $this->fk_user_author = $obj->fk_user_author; // Note fk_user_author is not the 'author' but the guy the expense report is for. | ||
| 720 | $this->fk_user_modif = $obj->fk_user_modif; | ||
| 721 | $this->fk_user_validator = $obj->fk_user_validator; | ||
| 722 | $this->fk_user_valid = $obj->fk_user_valid; | ||
| 723 | $this->fk_user_refuse = $obj->fk_user_refuse; | ||
| 724 | $this->fk_user_cancel = $obj->fk_user_cancel; | ||
| 725 | $this->fk_user_approve = $obj->fk_user_approve; | ||
| 726 | |||
| 727 | $user_author = new User($this->db); | ||
| 728 |                 if ($this->fk_user_author > 0) { | ||
| 729 | $user_author->fetch($this->fk_user_author); | ||
| 730 | } | ||
| 731 | |||
| 732 | $this->user_author_infos = dolGetFirstLastname($user_author->firstname, $user_author->lastname); | ||
| 733 | |||
| 734 | $user_approver = new User($this->db); | ||
| 735 |                 if ($this->fk_user_approve > 0) { | ||
| 736 | $user_approver->fetch($this->fk_user_approve); | ||
| 737 |                 } elseif ($this->fk_user_validator > 0) { | ||
| 738 | $user_approver->fetch($this->fk_user_validator); // For backward compatibility | ||
| 739 | } | ||
| 740 | $this->user_validator_infos = dolGetFirstLastname($user_approver->firstname, $user_approver->lastname); | ||
| 741 | |||
| 742 | $this->fk_statut = $obj->status; // deprecated | ||
| 743 | $this->status = $obj->status; | ||
| 744 | $this->fk_c_paiement = $obj->fk_c_paiement; | ||
| 745 | $this->paid = $obj->paid; | ||
| 746 | |||
| 747 |                 if ($this->status == self::STATUS_APPROVED || $this->status == self::STATUS_CLOSED) { | ||
| 748 | $user_valid = new User($this->db); | ||
| 749 |                     if ($this->fk_user_valid > 0) { | ||
| 750 | $user_valid->fetch($this->fk_user_valid); | ||
| 751 | } | ||
| 752 | $this->user_valid_infos = dolGetFirstLastname($user_valid->firstname, $user_valid->lastname); | ||
| 753 | } | ||
| 754 | |||
| 755 | $this->fetch_optionals(); | ||
| 756 | |||
| 757 | $result = $this->fetch_lines(); | ||
| 758 | |||
| 759 | return $result; | ||
| 760 |             } else { | ||
| 761 | return 0; | ||
| 762 | } | ||
| 763 |         } else { | ||
| 764 | $this->error = $this->db->lasterror(); | ||
| 765 | return -1; | ||
| 766 | } | ||
| 767 | } | ||
| 768 | |||
| 769 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps | ||
| 770 | /** | ||
| 771 | * Classify the expense report as paid | ||
| 772 | * | ||
| 773 | * @deprecated | ||
| 774 | * @see setPaid() | ||
| 775 | * @param int $id Id of expense report | ||
| 776 | * @param user $fuser User making change | ||
| 777 | * @param int $notrigger Disable triggers | ||
| 778 | * @return int Return integer <0 if KO, >0 if OK | ||
| 779 | */ | ||
| 780 | public function set_paid($id, $fuser, $notrigger = 0) | ||
| 781 |     { | ||
| 782 | // phpcs:enable | ||
| 783 | dol_syslog(get_only_class($this) . "::set_paid is deprecated, use setPaid instead", LOG_NOTICE); | ||
| 784 | return $this->setPaid($id, $fuser, $notrigger); | ||
| 785 | } | ||
| 786 | |||
| 787 | /** | ||
| 788 | * Classify the expense report as paid | ||
| 789 | * | ||
| 790 | * @param int $id Id of expense report | ||
| 791 | * @param user $fuser User making change | ||
| 792 | * @param int $notrigger Disable triggers | ||
| 793 | * @return int Return integer <0 if KO, >0 if OK | ||
| 794 | */ | ||
| 795 | public function setPaid($id, $fuser, $notrigger = 0) | ||
| 796 |     { | ||
| 797 | $error = 0; | ||
| 798 | $this->db->begin(); | ||
| 799 | |||
| 800 | $sql = "UPDATE " . MAIN_DB_PREFIX . "expensereport"; | ||
| 801 | $sql .= " SET fk_statut = " . self::STATUS_CLOSED . ", paid=1"; | ||
| 802 | $sql .= " WHERE rowid = " . ((int) $id) . " AND fk_statut = " . self::STATUS_APPROVED; | ||
| 803 | |||
| 804 | dol_syslog(get_only_class($this) . "::setPaid", LOG_DEBUG); | ||
| 805 | $resql = $this->db->query($sql); | ||
| 806 |         if ($resql) { | ||
| 807 |             if ($this->db->affected_rows($resql)) { | ||
| 808 |                 if (!$notrigger) { | ||
| 809 | // Call trigger | ||
| 810 |                     $result = $this->call_trigger('EXPENSE_REPORT_PAID', $fuser); | ||
| 811 | |||
| 812 |                     if ($result < 0) { | ||
| 813 | $error++; | ||
| 814 | } | ||
| 815 | // End call triggers | ||
| 816 | } | ||
| 817 | |||
| 818 |                 if (empty($error)) { | ||
| 819 | $this->db->commit(); | ||
| 820 | return 1; | ||
| 821 |                 } else { | ||
| 822 | $this->db->rollback(); | ||
| 823 | $this->error = $this->db->error(); | ||
| 824 | return -2; | ||
| 825 | } | ||
| 826 |             } else { | ||
| 827 | $this->db->commit(); | ||
| 828 | return 0; | ||
| 829 | } | ||
| 830 |         } else { | ||
| 831 | $this->db->rollback(); | ||
| 832 | dol_print_error($this->db); | ||
| 833 | return -1; | ||
| 834 | } | ||
| 835 | } | ||
| 836 | |||
| 837 | /** | ||
| 838 | * Returns the label status | ||
| 839 | * | ||
| 840 | * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto | ||
| 841 | * @return string Label | ||
| 842 | */ | ||
| 843 | public function getLibStatut($mode = 0) | ||
| 844 |     { | ||
| 845 | return $this->LibStatut($this->status, $mode); | ||
| 846 | } | ||
| 847 | |||
| 848 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps | ||
| 849 | /** | ||
| 850 | * Returns the label of a status | ||
| 851 | * | ||
| 852 | * @param int $status ID status | ||
| 853 | * @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 | ||
| 854 | * @return string Label | ||
| 855 | */ | ||
| 856 | public function LibStatut($status, $mode = 0) | ||
| 857 |     { | ||
| 858 | // phpcs:enable | ||
| 859 | global $langs; | ||
| 860 | |||
| 861 | $labelStatus = $langs->transnoentitiesnoconv($this->labelStatus[$status]); | ||
| 862 | $labelStatusShort = $langs->transnoentitiesnoconv($this->labelStatusShort[$status]); | ||
| 863 | |||
| 864 | $statuslogo = array(0 => 'status0', 2 => 'status1', 4 => 'status6', 5 => 'status4', 6 => 'status6', 99 => 'status5'); | ||
| 865 | |||
| 866 | $statusType = $statuslogo[$status]; | ||
| 867 | |||
| 868 | return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode); | ||
| 869 | } | ||
| 870 | |||
| 871 | |||
| 872 | /** | ||
| 873 | * Load information on object | ||
| 874 | * | ||
| 875 | * @param int $id Id of object | ||
| 876 | * @return void | ||
| 877 | */ | ||
| 878 | public function info($id) | ||
| 879 |     { | ||
| 880 | global $conf; | ||
| 881 | |||
| 882 | $sql = "SELECT f.rowid,"; | ||
| 883 | $sql .= " f.date_create as datec,"; | ||
| 884 | $sql .= " f.tms as date_modification,"; | ||
| 885 | $sql .= " f.date_valid as datev,"; | ||
| 886 | $sql .= " f.date_approve as datea,"; | ||
| 887 | $sql .= " f.fk_user_creat as fk_user_creation,"; | ||
| 888 | $sql .= " f.fk_user_author as fk_user_author,"; | ||
| 889 | $sql .= " f.fk_user_modif as fk_user_modification,"; | ||
| 890 | $sql .= " f.fk_user_valid,"; | ||
| 891 | $sql .= " f.fk_user_approve"; | ||
| 892 | $sql .= " FROM " . MAIN_DB_PREFIX . "expensereport as f"; | ||
| 893 | $sql .= " WHERE f.rowid = " . ((int) $id); | ||
| 894 | $sql .= " AND f.entity = " . $conf->entity; | ||
| 895 | |||
| 896 | |||
| 897 | |||
| 898 | $resql = $this->db->query($sql); | ||
| 899 |         if ($resql) { | ||
| 900 |             if ($this->db->num_rows($resql)) { | ||
| 901 | $obj = $this->db->fetch_object($resql); | ||
| 902 | |||
| 903 | $this->id = $obj->rowid; | ||
| 904 | |||
| 905 | $this->date_creation = $this->db->jdate($obj->datec); | ||
| 906 | $this->date_modification = $this->db->jdate($obj->date_modification); | ||
| 907 | $this->date_validation = $this->db->jdate($obj->datev); | ||
| 908 | $this->date_approbation = $this->db->jdate($obj->datea); | ||
| 909 | |||
| 910 | $this->user_creation_id = $obj->fk_user_author; | ||
| 911 | $this->user_creation_id = $obj->fk_user_creation; | ||
| 912 | $this->user_validation_id = $obj->fk_user_valid; | ||
| 913 | $this->user_modification_id = $obj->fk_user_modification; | ||
| 914 | $this->user_approve_id = $obj->fk_user_approve; | ||
| 915 | } | ||
| 916 | $this->db->free($resql); | ||
| 917 |         } else { | ||
| 918 | dol_print_error($this->db); | ||
| 919 | } | ||
| 920 | } | ||
| 921 | |||
| 922 | |||
| 923 | |||
| 924 | /** | ||
| 925 | * Initialise an instance with random values. | ||
| 926 | * Used to build previews or test instances. | ||
| 927 | * id must be 0 if object instance is a specimen. | ||
| 928 | * | ||
| 929 | * @return int | ||
| 930 | */ | ||
| 931 | public function initAsSpecimen() | ||
| 932 |     { | ||
| 933 | global $user, $langs; | ||
| 934 | |||
| 935 | $now = dol_now(); | ||
| 936 | |||
| 937 | // Initialise parameters | ||
| 938 | $this->id = 0; | ||
| 939 | $this->ref = 'SPECIMEN'; | ||
| 940 | $this->specimen = 1; | ||
| 941 | $this->entity = 1; | ||
| 942 | $this->date_create = $now; | ||
| 943 | $this->date_debut = $now; | ||
| 944 | $this->date_fin = $now; | ||
| 945 | $this->date_valid = $now; | ||
| 946 | $this->date_approve = $now; | ||
| 947 | |||
| 948 | $type_fees_id = 2; // TF_TRIP | ||
| 949 | |||
| 950 | $this->status = 5; | ||
| 951 | |||
| 952 | $this->fk_user_author = $user->id; | ||
| 953 | $this->fk_user_validator = $user->id; | ||
| 954 | $this->fk_user_valid = $user->id; | ||
| 955 | $this->fk_user_approve = $user->id; | ||
| 956 | |||
| 957 | $this->note_private = 'Private note'; | ||
| 958 | $this->note_public = 'SPECIMEN'; | ||
| 959 | $nbp = 5; | ||
| 960 | $xnbp = 0; | ||
| 961 |         while ($xnbp < $nbp) { | ||
| 962 | $line = new ExpenseReportLine($this->db); | ||
| 963 |             $line->comments = $langs->trans("Comment") . " " . $xnbp; | ||
| 964 | $line->date = ($now - 3600 * (1 + $xnbp)); | ||
| 965 | $line->total_ht = 100; | ||
| 966 | $line->total_tva = 20; | ||
| 967 | $line->total_ttc = 120; | ||
| 968 | $line->qty = 1; | ||
| 969 | $line->vatrate = 20; | ||
| 970 | $line->value_unit = 120; | ||
| 971 | $line->fk_expensereport = 0; | ||
| 972 | $line->type_fees_code = 'TRA'; | ||
| 973 | $line->fk_c_type_fees = $type_fees_id; | ||
| 974 | |||
| 975 | $line->projet_ref = 'ABC'; | ||
| 976 | |||
| 977 | $this->lines[$xnbp] = $line; | ||
| 978 | $xnbp++; | ||
| 979 | |||
| 980 | $this->total_ht += $line->total_ht; | ||
| 981 | $this->total_tva += $line->total_tva; | ||
| 982 | $this->total_ttc += $line->total_ttc; | ||
| 983 | } | ||
| 984 | |||
| 985 | return 1; | ||
| 986 | } | ||
| 987 | |||
| 988 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps | ||
| 989 | /** | ||
| 990 | * fetch_line_by_project | ||
| 991 | * | ||
| 992 | * @param int $projectid Project id | ||
| 993 | * @param User $user User | ||
| 994 | * @return int Return integer <0 if KO, >0 if OK | ||
| 995 | */ | ||
| 996 | public function fetch_line_by_project($projectid, $user) | ||
| 997 |     { | ||
| 998 | // phpcs:enable | ||
| 999 | global $langs; | ||
| 1000 | |||
| 1001 |         $langs->load('trips'); | ||
| 1002 | |||
| 1003 |         if ($user->hasRight('expensereport', 'lire')) { | ||
| 1004 | $sql = "SELECT de.fk_expensereport, de.date, de.comments, de.total_ht, de.total_ttc"; | ||
| 1005 | $sql .= " FROM " . MAIN_DB_PREFIX . "expensereport_det as de"; | ||
| 1006 | $sql .= " WHERE de.fk_projet = " . ((int) $projectid); | ||
| 1007 | |||
| 1008 | dol_syslog(get_only_class($this) . "::fetch", LOG_DEBUG); | ||
| 1009 | $result = $this->db->query($sql); | ||
| 1010 |             if ($result) { | ||
| 1011 | $num = $this->db->num_rows($result); | ||
| 1012 | $i = 0; | ||
| 1013 | $total_HT = 0; | ||
| 1014 | $total_TTC = 0; | ||
| 1015 | |||
| 1016 |                 while ($i < $num) { | ||
| 1017 | $objp = $this->db->fetch_object($result); | ||
| 1018 | |||
| 1019 | $sql2 = "SELECT d.rowid, d.fk_user_author, d.ref, d.fk_statut as status"; | ||
| 1020 | $sql2 .= " FROM " . MAIN_DB_PREFIX . "expensereport as d"; | ||
| 1021 | $sql2 .= " WHERE d.rowid = " . ((int) $objp->fk_expensereport); | ||
| 1022 | |||
| 1023 | $result2 = $this->db->query($sql2); | ||
| 1024 | $obj = $this->db->fetch_object($result2); | ||
| 1025 | |||
| 1026 | $objp->fk_user_author = $obj->fk_user_author; | ||
| 1027 | $objp->ref = $obj->ref; | ||
| 1028 | $objp->fk_c_expensereport_status = $obj->status; | ||
| 1029 | $objp->rowid = $obj->rowid; | ||
| 1030 | |||
| 1031 | $total_HT += $objp->total_ht; | ||
| 1032 | $total_TTC += $objp->total_ttc; | ||
| 1033 | $author = new User($this->db); | ||
| 1034 | $author->fetch($objp->fk_user_author); | ||
| 1035 | |||
| 1036 | print '<tr>'; | ||
| 1037 |                     print '<td><a href="' . constant('BASE_URL') . '/expensereport/card.php?id=' . $objp->rowid . '">' . $objp->ref_num . '</a></td>'; | ||
| 1038 | print '<td class="center">' . dol_print_date($objp->date, 'day') . '</td>'; | ||
| 1039 | print '<td>' . $author->getNomUrl(1) . '</td>'; | ||
| 1040 | print '<td>' . $objp->comments . '</td>'; | ||
| 1041 | print '<td class="right">' . price($objp->total_ht) . '</td>'; | ||
| 1042 | print '<td class="right">' . price($objp->total_ttc) . '</td>'; | ||
| 1043 | print '<td class="right">'; | ||
| 1044 | |||
| 1045 |                     switch ($objp->fk_c_expensereport_status) { | ||
| 1046 | case 4: | ||
| 1047 |                             print img_picto($langs->trans('StatusOrderCanceled'), 'statut5'); | ||
| 1048 | break; | ||
| 1049 | case 1: | ||
| 1050 |                             print $langs->trans('Draft') . ' ' . img_picto($langs->trans('Draft'), 'statut0'); | ||
| 1051 | break; | ||
| 1052 | case 2: | ||
| 1053 |                             print $langs->trans('TripForValid') . ' ' . img_picto($langs->trans('TripForValid'), 'statut3'); | ||
| 1054 | break; | ||
| 1055 | case 5: | ||
| 1056 |                             print $langs->trans('TripForPaid') . ' ' . img_picto($langs->trans('TripForPaid'), 'statut3'); | ||
| 1057 | break; | ||
| 1058 | case 6: | ||
| 1059 |                             print $langs->trans('TripPaid') . ' ' . img_picto($langs->trans('TripPaid'), 'statut4'); | ||
| 1060 | break; | ||
| 1061 | } | ||
| 1062 | /* | ||
| 1063 |                      if ($status==4) return img_picto($langs->trans('StatusOrderCanceled'),'statut5'); | ||
| 1064 |                     if ($status==1) return img_picto($langs->trans('StatusOrderDraft'),'statut0'); | ||
| 1065 |                     if ($status==2) return img_picto($langs->trans('StatusOrderValidated'),'statut1'); | ||
| 1066 |                     if ($status==2) return img_picto($langs->trans('StatusOrderOnProcess'),'statut3'); | ||
| 1067 |                     if ($status==5) return img_picto($langs->trans('StatusOrderToBill'),'statut4'); | ||
| 1068 |                     if ($status==6) return img_picto($langs->trans('StatusOrderOnProcess'),'statut6'); | ||
| 1069 | */ | ||
| 1070 | print '</td>'; | ||
| 1071 | print '</tr>'; | ||
| 1072 | |||
| 1073 | $i++; | ||
| 1074 | } | ||
| 1075 | |||
| 1076 |                 print '<tr class="liste_total"><td colspan="4">' . $langs->trans("Number") . ': ' . $i . '</td>'; | ||
| 1077 |                 print '<td class="right" width="100">' . $langs->trans("TotalHT") . ' : ' . price($total_HT) . '</td>'; | ||
| 1078 |                 print '<td class="right" width="100">' . $langs->trans("TotalTTC") . ' : ' . price($total_TTC) . '</td>'; | ||
| 1079 | print '<td> </td>'; | ||
| 1080 | print '</tr>'; | ||
| 1081 |             } else { | ||
| 1082 | $this->error = $this->db->lasterror(); | ||
| 1083 | return -1; | ||
| 1084 | } | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | return 0; | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps | ||
| 1091 | /** | ||
| 1092 | * fetch_lines | ||
| 1093 | * | ||
| 1094 | * @return int Return integer <0 if OK, >0 if KO | ||
| 1095 | */ | ||
| 1096 | public function fetch_lines() | ||
| 1097 |     { | ||
| 1098 | // phpcs:enable | ||
| 1099 | $this->lines = array(); | ||
| 1100 | |||
| 1101 | $sql = ' SELECT de.rowid, de.comments, de.qty, de.value_unit, de.date, de.rang,'; | ||
| 1102 | $sql .= " de." . $this->fk_element . ", de.fk_c_type_fees, de.fk_c_exp_tax_cat, de.fk_projet as fk_project,"; | ||
| 1103 | $sql .= ' de.tva_tx, de.vat_src_code,'; | ||
| 1104 | $sql .= ' de.localtax1_tx, de.localtax2_tx, de.localtax1_type, de.localtax2_type,'; | ||
| 1105 | $sql .= ' de.fk_ecm_files,'; | ||
| 1106 | $sql .= ' de.total_ht, de.total_tva, de.total_ttc,'; | ||
| 1107 | $sql .= ' de.total_localtax1, de.total_localtax2, de.rule_warning_message,'; | ||
| 1108 | $sql .= ' ctf.code as code_type_fees, ctf.label as label_type_fees, ctf.accountancy_code as accountancy_code_type_fees,'; | ||
| 1109 | $sql .= ' p.ref as ref_projet, p.title as title_projet'; | ||
| 1110 | $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element_line . ' as de'; | ||
| 1111 | $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_type_fees as ctf ON de.fk_c_type_fees = ctf.id'; | ||
| 1112 | $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'projet as p ON de.fk_projet = p.rowid'; | ||
| 1113 | $sql .= " WHERE de." . $this->fk_element . " = " . ((int) $this->id); | ||
| 1114 |         if (getDolGlobalString('EXPENSEREPORT_LINES_SORTED_BY_ROWID')) { | ||
| 1115 | $sql .= ' ORDER BY de.rang ASC, de.rowid ASC'; | ||
| 1116 |         } else { | ||
| 1117 | $sql .= ' ORDER BY de.rang ASC, de.date ASC'; | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | $resql = $this->db->query($sql); | ||
| 1121 |         if ($resql) { | ||
| 1122 | $num = $this->db->num_rows($resql); | ||
| 1123 | $i = 0; | ||
| 1124 |             while ($i < $num) { | ||
| 1125 | $objp = $this->db->fetch_object($resql); | ||
| 1126 | |||
| 1127 | $deplig = new ExpenseReportLine($this->db); | ||
| 1128 | |||
| 1129 | $deplig->rowid = $objp->rowid; | ||
| 1130 | $deplig->id = $objp->rowid; | ||
| 1131 | $deplig->comments = $objp->comments; | ||
| 1132 | $deplig->qty = $objp->qty; | ||
| 1133 | $deplig->value_unit = $objp->value_unit; | ||
| 1134 | $deplig->date = $objp->date; | ||
| 1135 | $deplig->dates = $this->db->jdate($objp->date); | ||
| 1136 | |||
| 1137 | $deplig->fk_expensereport = $objp->fk_expensereport; | ||
| 1138 | $deplig->fk_c_type_fees = $objp->fk_c_type_fees; | ||
| 1139 | $deplig->fk_c_exp_tax_cat = $objp->fk_c_exp_tax_cat; | ||
| 1140 | $deplig->fk_projet = $objp->fk_project; // deprecated | ||
| 1141 | $deplig->fk_project = $objp->fk_project; | ||
| 1142 | $deplig->fk_ecm_files = $objp->fk_ecm_files; | ||
| 1143 | |||
| 1144 | $deplig->total_ht = $objp->total_ht; | ||
| 1145 | $deplig->total_tva = $objp->total_tva; | ||
| 1146 | $deplig->total_ttc = $objp->total_ttc; | ||
| 1147 | $deplig->total_localtax1 = $objp->total_localtax1; | ||
| 1148 | $deplig->total_localtax2 = $objp->total_localtax2; | ||
| 1149 | |||
| 1150 | $deplig->type_fees_code = empty($objp->code_type_fees) ? 'TF_OTHER' : $objp->code_type_fees; | ||
| 1151 | $deplig->type_fees_libelle = $objp->label_type_fees; | ||
| 1152 | $deplig->type_fees_accountancy_code = $objp->accountancy_code_type_fees; | ||
| 1153 | |||
| 1154 | $deplig->tva_tx = $objp->tva_tx; | ||
| 1155 | $deplig->vatrate = $objp->tva_tx; | ||
| 1156 | $deplig->vat_src_code = $objp->vat_src_code; | ||
| 1157 | $deplig->localtax1_tx = $objp->localtax1_tx; | ||
| 1158 | $deplig->localtax2_tx = $objp->localtax2_tx; | ||
| 1159 | $deplig->localtax1_type = $objp->localtax1_type; | ||
| 1160 | $deplig->localtax2_type = $objp->localtax2_type; | ||
| 1161 | |||
| 1162 | $deplig->projet_ref = $objp->ref_projet; | ||
| 1163 | $deplig->projet_title = $objp->title_projet; | ||
| 1164 | |||
| 1165 | $deplig->rule_warning_message = $objp->rule_warning_message; | ||
| 1166 | |||
| 1167 | $deplig->rang = $objp->rang; | ||
| 1168 | |||
| 1169 | $this->lines[$i] = $deplig; | ||
| 1170 | |||
| 1171 | $i++; | ||
| 1172 | } | ||
| 1173 | $this->db->free($resql); | ||
| 1174 | return 1; | ||
| 1175 |         } else { | ||
| 1176 | $this->error = $this->db->lasterror(); | ||
| 1177 | dol_syslog(get_only_class($this) . "::fetch_lines: Error " . $this->error, LOG_ERR); | ||
| 1178 | return -3; | ||
| 1179 | } | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | |||
| 1183 | /** | ||
| 1184 | * Delete object in database | ||
| 1185 | * | ||
| 1186 | * @param User|null $user User that delete | ||
| 1187 | * @param int $notrigger 0=launch triggers after, 1=disable triggers | ||
| 1188 | * @return int Return integer <0 if KO, >0 if OK | ||
| 1189 | */ | ||
| 1190 | public function delete(User $user = null, $notrigger = 0) | ||
| 1191 |     { | ||
| 1192 | global $conf; | ||
| 1193 |         require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php'; | ||
| 1194 | |||
| 1195 | $error = 0; | ||
| 1196 | |||
| 1197 | $this->db->begin(); | ||
| 1198 | |||
| 1199 |         if (!$notrigger) { | ||
| 1200 | // Call trigger | ||
| 1201 |             $result = $this->call_trigger('EXPENSE_REPORT_DELETE', $user); | ||
| 1202 |             if ($result < 0) { | ||
| 1203 | $error++; | ||
| 1204 | } | ||
| 1205 | // End call triggers | ||
| 1206 | } | ||
| 1207 | |||
| 1208 | // Delete extrafields of lines and lines | ||
| 1209 |         if (!$error && !empty($this->table_element_line)) { | ||
| 1210 | $tabletodelete = $this->table_element_line; | ||
| 1211 | //$sqlef = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete."_extrafields WHERE fk_object IN (SELECT rowid FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".((int) $this->id).")"; | ||
| 1212 | $sql = "DELETE FROM " . MAIN_DB_PREFIX . $tabletodelete . " WHERE " . $this->fk_element . " = " . ((int) $this->id); | ||
| 1213 |             if (!$this->db->query($sql)) { | ||
| 1214 | $error++; | ||
| 1215 | $this->error = $this->db->lasterror(); | ||
| 1216 | $this->errors[] = $this->error; | ||
| 1217 | dol_syslog(get_only_class($this) . "::delete error " . $this->error, LOG_ERR); | ||
| 1218 | } | ||
| 1219 | } | ||
| 1220 | |||
| 1221 |         if (!$error) { | ||
| 1222 | // Delete linked object | ||
| 1223 | $res = $this->deleteObjectLinked(); | ||
| 1224 |             if ($res < 0) { | ||
| 1225 | $error++; | ||
| 1226 | } | ||
| 1227 | } | ||
| 1228 | |||
| 1229 |         if (!$error) { | ||
| 1230 | // Delete linked contacts | ||
| 1231 | $res = $this->delete_linked_contact(); | ||
| 1232 |             if ($res < 0) { | ||
| 1233 | $error++; | ||
| 1234 | } | ||
| 1235 | } | ||
| 1236 | |||
| 1237 | // Removed extrafields of object | ||
| 1238 |         if (!$error) { | ||
| 1239 | $result = $this->deleteExtraFields(); | ||
| 1240 |             if ($result < 0) { | ||
| 1241 | $error++; | ||
| 1242 | dol_syslog(get_only_class($this) . "::delete error " . $this->error, LOG_ERR); | ||
| 1243 | } | ||
| 1244 | } | ||
| 1245 | |||
| 1246 | // Delete main record | ||
| 1247 |         if (!$error) { | ||
| 1248 | $sql = "DELETE FROM " . MAIN_DB_PREFIX . $this->table_element . " WHERE rowid = " . ((int) $this->id); | ||
| 1249 | $res = $this->db->query($sql); | ||
| 1250 |             if (!$res) { | ||
| 1251 | $error++; | ||
| 1252 | $this->error = $this->db->lasterror(); | ||
| 1253 | $this->errors[] = $this->error; | ||
| 1254 | dol_syslog(get_only_class($this) . "::delete error " . $this->error, LOG_ERR); | ||
| 1255 | } | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | // Delete record into ECM index and physically | ||
| 1259 |         if (!$error) { | ||
| 1260 | $res = $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive | ||
| 1261 | $res = $this->deleteEcmFiles(1); // Deleting files physically is done later with the dol_delete_dir_recursive | ||
| 1262 |             if (!$res) { | ||
| 1263 | $error++; | ||
| 1264 | } | ||
| 1265 | } | ||
| 1266 | |||
| 1267 |         if (!$error) { | ||
| 1268 | // We remove directory | ||
| 1269 | $ref = dol_sanitizeFileName($this->ref); | ||
| 1270 |             if ($conf->expensereport->multidir_output[$this->entity] && !empty($this->ref)) { | ||
| 1271 | $dir = $conf->expensereport->multidir_output[$this->entity] . "/" . $ref; | ||
| 1272 | $file = $dir . "/" . $ref . ".pdf"; | ||
| 1273 |                 if (file_exists($file)) { | ||
| 1274 | dol_delete_preview($this); | ||
| 1275 | |||
| 1276 |                     if (!dol_delete_file($file, 0, 0, 0, $this)) { | ||
| 1277 | $this->error = 'ErrorFailToDeleteFile'; | ||
| 1278 | $this->errors[] = $this->error; | ||
| 1279 | $this->db->rollback(); | ||
| 1280 | return 0; | ||
| 1281 | } | ||
| 1282 | } | ||
| 1283 |                 if (file_exists($dir)) { | ||
| 1284 | $res = @dol_delete_dir_recursive($dir); | ||
| 1285 |                     if (!$res) { | ||
| 1286 | $this->error = 'ErrorFailToDeleteDir'; | ||
| 1287 | $this->errors[] = $this->error; | ||
| 1288 | $this->db->rollback(); | ||
| 1289 | return 0; | ||
| 1290 | } | ||
| 1291 | } | ||
| 1292 | } | ||
| 1293 | } | ||
| 1294 | |||
| 1295 |         if (!$error) { | ||
| 1296 | dol_syslog(get_only_class($this) . "::delete " . $this->id . " by " . $user->id, LOG_DEBUG); | ||
| 1297 | $this->db->commit(); | ||
| 1298 | return 1; | ||
| 1299 |         } else { | ||
| 1300 | $this->db->rollback(); | ||
| 1301 | return -1; | ||
| 1302 | } | ||
| 1303 | } | ||
| 1304 | |||
| 1305 | /** | ||
| 1306 | * Set to status validate | ||
| 1307 | * | ||
| 1308 | * @param User $fuser User | ||
| 1309 | * @param int $notrigger Disable triggers | ||
| 1310 | * @return int Return integer <0 if KO, 0 if nothing done, >0 if OK | ||
| 1311 | */ | ||
| 1312 | public function setValidate($fuser, $notrigger = 0) | ||
| 1313 |     { | ||
| 1314 | global $conf, $langs, $user; | ||
| 1315 | |||
| 1316 | $error = 0; | ||
| 1317 | $now = dol_now(); | ||
| 1318 | |||
| 1319 | // Protection | ||
| 1320 |         if ($this->status == self::STATUS_VALIDATED) { | ||
| 1321 | dol_syslog(get_only_class($this) . "::valid action abandoned: already validated", LOG_WARNING); | ||
| 1322 | return 0; | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | $this->date_valid = $now; // Required for the getNextNum later. | ||
| 1326 | |||
| 1327 | // Define new ref | ||
| 1328 |         if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life | ||
| 1329 | $num = $this->getNextNumRef(); | ||
| 1330 |         } else { | ||
| 1331 | $num = $this->ref; | ||
| 1332 | } | ||
| 1333 |         if (empty($num) || $num < 0) { | ||
| 1334 | return -1; | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | $this->newref = dol_sanitizeFileName($num); | ||
| 1338 | |||
| 1339 | $this->db->begin(); | ||
| 1340 | |||
| 1341 | // Validate | ||
| 1342 | $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element; | ||
| 1343 | $sql .= " SET ref = '" . $this->db->escape($num) . "',"; | ||
| 1344 | $sql .= " fk_statut = " . self::STATUS_VALIDATED . ","; | ||
| 1345 | $sql .= " date_valid = '" . $this->db->idate($this->date_valid) . "',"; | ||
| 1346 | $sql .= " fk_user_valid = " . ((int) $user->id); | ||
| 1347 | $sql .= " WHERE rowid = " . ((int) $this->id); | ||
| 1348 | |||
| 1349 | $resql = $this->db->query($sql); | ||
| 1350 |         if ($resql) { | ||
| 1351 |             if (!$error && !$notrigger) { | ||
| 1352 | // Call trigger | ||
| 1353 |                 $result = $this->call_trigger('EXPENSE_REPORT_VALIDATE', $fuser); | ||
| 1354 |                 if ($result < 0) { | ||
| 1355 | $error++; | ||
| 1356 | } | ||
| 1357 | // End call triggers | ||
| 1358 | } | ||
| 1359 | |||
| 1360 |             if (!$error) { | ||
| 1361 | $this->oldref = $this->ref; | ||
| 1362 | |||
| 1363 | // Rename directory if dir was a temporary ref | ||
| 1364 |                 if (preg_match('/^[\(]?PROV/i', $this->ref)) { | ||
| 1365 |                     require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php'; | ||
| 1366 | |||
| 1367 | // Now we rename also files into index | ||
| 1368 |                     $sql = 'UPDATE ' . MAIN_DB_PREFIX . "ecm_files set filename = CONCAT('" . $this->db->escape($this->newref) . "', SUBSTR(filename, " . (strlen($this->ref) + 1) . ")), filepath = 'expensereport/" . $this->db->escape($this->newref) . "'"; | ||
| 1369 | $sql .= " WHERE filename LIKE '" . $this->db->escape($this->ref) . "%' AND filepath = 'expensereport/" . $this->db->escape($this->ref) . "' AND entity = " . ((int) $this->entity); | ||
| 1370 | $resql = $this->db->query($sql); | ||
| 1371 |                     if (!$resql) { | ||
| 1372 | $error++; | ||
| 1373 | $this->error = $this->db->lasterror(); | ||
| 1374 | } | ||
| 1375 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . "ecm_files set filepath = 'expensereport/" . $this->db->escape($this->newref) . "'"; | ||
| 1376 | $sql .= " WHERE filepath = 'expensereport/" . $this->db->escape($this->ref) . "' and entity = " . $conf->entity; | ||
| 1377 | $resql = $this->db->query($sql); | ||
| 1378 |                     if (!$resql) { | ||
| 1379 | $error++; | ||
| 1380 | $this->error = $this->db->lasterror(); | ||
| 1381 | } | ||
| 1382 | |||
| 1383 | // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments | ||
| 1384 | $oldref = dol_sanitizeFileName($this->ref); | ||
| 1385 | $newref = dol_sanitizeFileName($num); | ||
| 1386 | $dirsource = $conf->expensereport->multidir_output[$this->entity] . '/' . $oldref; | ||
| 1387 | $dirdest = $conf->expensereport->multidir_output[$this->entity] . '/' . $newref; | ||
| 1388 |                     if (!$error && file_exists($dirsource)) { | ||
| 1389 | dol_syslog(get_only_class($this) . "::setValidate() rename dir " . $dirsource . " into " . $dirdest); | ||
| 1390 | |||
| 1391 |                         if (@rename($dirsource, $dirdest)) { | ||
| 1392 |                             dol_syslog("Rename ok"); | ||
| 1393 | // Rename docs starting with $oldref with $newref | ||
| 1394 | $listoffiles = dol_dir_list($dirdest, 'files', 1, '^' . preg_quote($oldref, '/')); | ||
| 1395 |                             foreach ($listoffiles as $fileentry) { | ||
| 1396 | $dirsource = $fileentry['name']; | ||
| 1397 |                                 $dirdest = preg_replace('/^' . preg_quote($oldref, '/') . '/', $newref, $dirsource); | ||
| 1398 | $dirsource = $fileentry['path'] . '/' . $dirsource; | ||
| 1399 | $dirdest = $fileentry['path'] . '/' . $dirdest; | ||
| 1400 | @rename($dirsource, $dirdest); | ||
| 1401 | } | ||
| 1402 | } | ||
| 1403 | } | ||
| 1404 | } | ||
| 1405 | } | ||
| 1406 | |||
| 1407 | // Set new ref and current status | ||
| 1408 |             if (!$error) { | ||
| 1409 | $this->ref = $num; | ||
| 1410 | $this->status = self::STATUS_VALIDATED; | ||
| 1411 | } | ||
| 1412 | |||
| 1413 |             if (empty($error)) { | ||
| 1414 | $this->db->commit(); | ||
| 1415 | return 1; | ||
| 1416 |             } else { | ||
| 1417 | $this->db->rollback(); | ||
| 1418 | $this->error = $this->db->error(); | ||
| 1419 | return -2; | ||
| 1420 | } | ||
| 1421 |         } else { | ||
| 1422 | $this->db->rollback(); | ||
| 1423 | $this->error = $this->db->lasterror(); | ||
| 1424 | return -1; | ||
| 1425 | } | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps | ||
| 1429 | /** | ||
| 1430 | * set_save_from_refuse | ||
| 1431 | * | ||
| 1432 | * @param User $fuser User | ||
| 1433 | * @return int Return integer <0 if KO, >0 if OK | ||
| 1434 | */ | ||
| 1435 | public function set_save_from_refuse($fuser) | ||
| 1436 |     { | ||
| 1437 | // phpcs:enable | ||
| 1438 | // Sélection de la date de début de la NDF | ||
| 1439 | $sql = 'SELECT date_debut'; | ||
| 1440 | $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element; | ||
| 1441 | $sql .= " WHERE rowid = " . ((int) $this->id); | ||
| 1442 | |||
| 1443 | $result = $this->db->query($sql); | ||
| 1444 | |||
| 1445 | $objp = $this->db->fetch_object($result); | ||
| 1446 | |||
| 1447 | $this->date_debut = $this->db->jdate($objp->date_debut); | ||
| 1448 | |||
| 1449 |         if ($this->status != self::STATUS_VALIDATED) { | ||
| 1450 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element; | ||
| 1451 | $sql .= " SET fk_statut = " . self::STATUS_VALIDATED; | ||
| 1452 | $sql .= " WHERE rowid = " . ((int) $this->id); | ||
| 1453 | |||
| 1454 | dol_syslog(get_only_class($this) . "::set_save_from_refuse", LOG_DEBUG); | ||
| 1455 | |||
| 1456 |             if ($this->db->query($sql)) { | ||
| 1457 | return 1; | ||
| 1458 |             } else { | ||
| 1459 | $this->error = $this->db->lasterror(); | ||
| 1460 | return -1; | ||
| 1461 | } | ||
| 1462 |         } else { | ||
| 1463 | dol_syslog(get_only_class($this) . "::set_save_from_refuse expensereport already with save status", LOG_WARNING); | ||
| 1464 | } | ||
| 1465 | |||
| 1466 | return 0; | ||
| 1467 | } | ||
| 1468 | |||
| 1469 | /** | ||
| 1470 | * Set status to approved | ||
| 1471 | * | ||
| 1472 | * @param User $fuser User | ||
| 1473 | * @param int $notrigger Disable triggers | ||
| 1474 | * @return int Return integer <0 if KO, 0 if nothing done, >0 if OK | ||
| 1475 | */ | ||
| 1476 | public function setApproved($fuser, $notrigger = 0) | ||
| 1477 |     { | ||
| 1478 | $now = dol_now(); | ||
| 1479 | $error = 0; | ||
| 1480 | |||
| 1481 | // date approval | ||
| 1482 | $this->date_approve = $now; | ||
| 1483 |         if ($this->status != self::STATUS_APPROVED) { | ||
| 1484 | $this->db->begin(); | ||
| 1485 | |||
| 1486 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element; | ||
| 1487 | $sql .= " SET ref = '" . $this->db->escape($this->ref) . "', fk_statut = " . self::STATUS_APPROVED . ", fk_user_approve = " . ((int) $fuser->id) . ","; | ||
| 1488 | $sql .= " date_approve='" . $this->db->idate($this->date_approve) . "'"; | ||
| 1489 | $sql .= " WHERE rowid = " . ((int) $this->id); | ||
| 1490 |             if ($this->db->query($sql)) { | ||
| 1491 |                 if (!$notrigger) { | ||
| 1492 | // Call trigger | ||
| 1493 |                     $result = $this->call_trigger('EXPENSE_REPORT_APPROVE', $fuser); | ||
| 1494 | |||
| 1495 |                     if ($result < 0) { | ||
| 1496 | $error++; | ||
| 1497 | } | ||
| 1498 | // End call triggers | ||
| 1499 | } | ||
| 1500 | |||
| 1501 |                 if (empty($error)) { | ||
| 1502 | $this->db->commit(); | ||
| 1503 | return 1; | ||
| 1504 |                 } else { | ||
| 1505 | $this->db->rollback(); | ||
| 1506 | $this->error = $this->db->error(); | ||
| 1507 | return -2; | ||
| 1508 | } | ||
| 1509 |             } else { | ||
| 1510 | $this->db->rollback(); | ||
| 1511 | $this->error = $this->db->lasterror(); | ||
| 1512 | return -1; | ||
| 1513 | } | ||
| 1514 |         } else { | ||
| 1515 | dol_syslog(get_only_class($this) . "::setApproved expensereport already with approve status", LOG_WARNING); | ||
| 1516 | } | ||
| 1517 | |||
| 1518 | return 0; | ||
| 1519 | } | ||
| 1520 | |||
| 1521 | /** | ||
| 1522 | * setDeny | ||
| 1523 | * | ||
| 1524 | * @param User $fuser User | ||
| 1525 | * @param string $details Details | ||
| 1526 | * @param int $notrigger Disable triggers | ||
| 1527 | * @return int | ||
| 1528 | */ | ||
| 1529 | public function setDeny($fuser, $details, $notrigger = 0) | ||
| 1530 |     { | ||
| 1531 | $now = dol_now(); | ||
| 1532 | $error = 0; | ||
| 1533 | |||
| 1534 | // date de refus | ||
| 1535 |         if ($this->status != self::STATUS_REFUSED) { | ||
| 1536 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element; | ||
| 1537 | $sql .= " SET ref = '" . $this->db->escape($this->ref) . "', fk_statut = " . self::STATUS_REFUSED . ", fk_user_refuse = " . ((int) $fuser->id) . ","; | ||
| 1538 | $sql .= " date_refuse='" . $this->db->idate($now) . "',"; | ||
| 1539 | $sql .= " detail_refuse='" . $this->db->escape($details) . "',"; | ||
| 1540 | $sql .= " fk_user_approve = NULL"; | ||
| 1541 | $sql .= " WHERE rowid = " . ((int) $this->id); | ||
| 1542 |             if ($this->db->query($sql)) { | ||
| 1543 | $this->fk_statut = 99; // deprecated | ||
| 1544 | $this->status = 99; | ||
| 1545 | $this->fk_user_refuse = $fuser->id; | ||
| 1546 | $this->detail_refuse = $details; | ||
| 1547 | $this->date_refuse = $now; | ||
| 1548 | |||
| 1549 |                 if (!$notrigger) { | ||
| 1550 | // Call trigger | ||
| 1551 |                     $result = $this->call_trigger('EXPENSE_REPORT_DENY', $fuser); | ||
| 1552 | |||
| 1553 |                     if ($result < 0) { | ||
| 1554 | $error++; | ||
| 1555 | } | ||
| 1556 | // End call triggers | ||
| 1557 | } | ||
| 1558 | |||
| 1559 |                 if (empty($error)) { | ||
| 1560 | $this->db->commit(); | ||
| 1561 | return 1; | ||
| 1562 |                 } else { | ||
| 1563 | $this->db->rollback(); | ||
| 1564 | $this->error = $this->db->error(); | ||
| 1565 | return -2; | ||
| 1566 | } | ||
| 1567 |             } else { | ||
| 1568 | $this->db->rollback(); | ||
| 1569 | $this->error = $this->db->lasterror(); | ||
| 1570 | return -1; | ||
| 1571 | } | ||
| 1572 |         } else { | ||
| 1573 | dol_syslog(get_only_class($this) . "::setDeny expensereport already with refuse status", LOG_WARNING); | ||
| 1574 | } | ||
| 1575 | |||
| 1576 | return 0; | ||
| 1577 | } | ||
| 1578 | |||
| 1579 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps | ||
| 1580 | /** | ||
| 1581 | * set_unpaid | ||
| 1582 | * | ||
| 1583 | * @deprecated | ||
| 1584 | * @see setUnpaid() | ||
| 1585 | * @param User $fuser User | ||
| 1586 | * @param int $notrigger Disable triggers | ||
| 1587 | * @return int Return integer <0 if KO, >0 if OK | ||
| 1588 | */ | ||
| 1589 | public function set_unpaid($fuser, $notrigger = 0) | ||
| 1590 |     { | ||
| 1591 | // phpcs:enable | ||
| 1592 | dol_syslog(get_only_class($this) . "::set_unpaid is deprecated, use setUnpaid instead", LOG_NOTICE); | ||
| 1593 | return $this->setUnpaid($fuser, $notrigger); | ||
| 1594 | } | ||
| 1595 | |||
| 1596 | /** | ||
| 1597 | * set_unpaid | ||
| 1598 | * | ||
| 1599 | * @param User $fuser User | ||
| 1600 | * @param int $notrigger Disable triggers | ||
| 1601 | * @return int Return integer <0 if KO, >0 if OK | ||
| 1602 | */ | ||
| 1603 | public function setUnpaid($fuser, $notrigger = 0) | ||
| 1604 |     { | ||
| 1605 | $error = 0; | ||
| 1606 | |||
| 1607 |         if ($this->paid) { | ||
| 1608 | $this->db->begin(); | ||
| 1609 | |||
| 1610 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element; | ||
| 1611 | $sql .= " SET paid = 0, fk_statut = " . self::STATUS_APPROVED; | ||
| 1612 | $sql .= " WHERE rowid = " . ((int) $this->id); | ||
| 1613 | |||
| 1614 | dol_syslog(get_only_class($this) . "::set_unpaid", LOG_DEBUG); | ||
| 1615 | |||
| 1616 |             if ($this->db->query($sql)) { | ||
| 1617 |                 if (!$notrigger) { | ||
| 1618 | // Call trigger | ||
| 1619 |                     $result = $this->call_trigger('EXPENSE_REPORT_UNPAID', $fuser); | ||
| 1620 | |||
| 1621 |                     if ($result < 0) { | ||
| 1622 | $error++; | ||
| 1623 | } | ||
| 1624 | // End call triggers | ||
| 1625 | } | ||
| 1626 | |||
| 1627 |                 if (empty($error)) { | ||
| 1628 | $this->db->commit(); | ||
| 1629 | return 1; | ||
| 1630 |                 } else { | ||
| 1631 | $this->db->rollback(); | ||
| 1632 | $this->error = $this->db->error(); | ||
| 1633 | return -2; | ||
| 1634 | } | ||
| 1635 |             } else { | ||
| 1636 | $this->db->rollback(); | ||
| 1637 | $this->error = $this->db->error(); | ||
| 1638 | return -1; | ||
| 1639 | } | ||
| 1640 |         } else { | ||
| 1641 | dol_syslog(get_only_class($this) . "::set_unpaid expensereport already with unpaid status", LOG_WARNING); | ||
| 1642 | } | ||
| 1643 | |||
| 1644 | return 0; | ||
| 1645 | } | ||
| 1646 | |||
| 1647 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps | ||
| 1648 | /** | ||
| 1649 | * set_cancel | ||
| 1650 | * | ||
| 1651 | * @param User $fuser User | ||
| 1652 | * @param string $detail Detail | ||
| 1653 | * @param int $notrigger Disable triggers | ||
| 1654 | * @return int Return integer <0 if KO, >0 if OK | ||
| 1655 | */ | ||
| 1656 | public function set_cancel($fuser, $detail, $notrigger = 0) | ||
| 1657 |     { | ||
| 1658 | // phpcs:enable | ||
| 1659 | $error = 0; | ||
| 1660 | $this->date_cancel = $this->db->idate(dol_now()); | ||
| 1661 |         if ($this->status != self::STATUS_CANCELED) { | ||
| 1662 | $this->db->begin(); | ||
| 1663 | |||
| 1664 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element; | ||
| 1665 | $sql .= " SET fk_statut = " . self::STATUS_CANCELED . ", fk_user_cancel = " . ((int) $fuser->id); | ||
| 1666 | $sql .= ", date_cancel='" . $this->db->idate($this->date_cancel) . "'"; | ||
| 1667 | $sql .= ", detail_cancel='" . $this->db->escape($detail) . "'"; | ||
| 1668 | $sql .= " WHERE rowid = " . ((int) $this->id); | ||
| 1669 | |||
| 1670 | dol_syslog(get_only_class($this) . "::set_cancel", LOG_DEBUG); | ||
| 1671 | |||
| 1672 |             if ($this->db->query($sql)) { | ||
| 1673 |                 if (!$notrigger) { | ||
| 1674 | // Call trigger | ||
| 1675 |                     $result = $this->call_trigger('EXPENSE_REPORT_CANCEL', $fuser); | ||
| 1676 | |||
| 1677 |                     if ($result < 0) { | ||
| 1678 | $error++; | ||
| 1679 | } | ||
| 1680 | // End call triggers | ||
| 1681 | } | ||
| 1682 | |||
| 1683 |                 if (empty($error)) { | ||
| 1684 | $this->db->commit(); | ||
| 1685 | return 1; | ||
| 1686 |                 } else { | ||
| 1687 | $this->db->rollback(); | ||
| 1688 | $this->error = $this->db->error(); | ||
| 1689 | return -2; | ||
| 1690 | } | ||
| 1691 |             } else { | ||
| 1692 | $this->db->rollback(); | ||
| 1693 | $this->error = $this->db->error(); | ||
| 1694 | return -1; | ||
| 1695 | } | ||
| 1696 |         } else { | ||
| 1697 | dol_syslog(get_only_class($this) . "::set_cancel expensereport already with cancel status", LOG_WARNING); | ||
| 1698 | } | ||
| 1699 | return 0; | ||
| 1700 | } | ||
| 1701 | |||
| 1702 | /** | ||
| 1703 | * Return next reference of expense report not already used | ||
| 1704 | * | ||
| 1705 | * @return string|int<-2,-1> free ref, or <0 if error | ||
| 1706 | */ | ||
| 1707 | public function getNextNumRef() | ||
| 1708 |     { | ||
| 1709 | global $langs, $conf; | ||
| 1710 |         $langs->load("trips"); | ||
| 1711 | |||
| 1712 |         if (getDolGlobalString('EXPENSEREPORT_ADDON')) { | ||
| 1713 | $mybool = false; | ||
| 1714 | |||
| 1715 |             $file = getDolGlobalString('EXPENSEREPORT_ADDON') . ".php"; | ||
| 1716 |             $classname = getDolGlobalString('EXPENSEREPORT_ADDON'); | ||
| 1717 | |||
| 1718 | // Include file with class | ||
| 1719 |             $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); | ||
| 1720 |             foreach ($dirmodels as $reldir) { | ||
| 1721 | $dir = dol_buildpath($reldir . "core/modules/expensereport/"); | ||
| 1722 | |||
| 1723 | // Load file with numbering class (if found) | ||
| 1724 | $mybool = ((bool) @include_once $dir . $file) || $mybool; | ||
| 1725 | } | ||
| 1726 | |||
| 1727 |             if (!$mybool) { | ||
| 1728 | dol_print_error(null, "Failed to include file " . $file); | ||
| 1729 | return ''; | ||
| 1730 | } | ||
| 1731 | |||
| 1732 | $obj = new $classname(); | ||
| 1733 | $numref = $obj->getNextValue($this); | ||
| 1734 | |||
| 1735 |             if ($numref != "") { | ||
| 1736 | return $numref; | ||
| 1737 |             } else { | ||
| 1738 | $this->error = $obj->error; | ||
| 1739 | $this->errors = $obj->errors; | ||
| 1740 | //dol_print_error($this->db,get_only_class($this)."::getNextNumRef ".$obj->error); | ||
| 1741 | return -1; | ||
| 1742 | } | ||
| 1743 |         } else { | ||
| 1744 | $this->error = "Error_EXPENSEREPORT_ADDON_NotDefined"; | ||
| 1745 | return -2; | ||
| 1746 | } | ||
| 1747 | } | ||
| 1748 | |||
| 1749 | /** | ||
| 1750 | * getTooltipContentArray | ||
| 1751 | * | ||
| 1752 | * @param array $params ex option, infologin | ||
| 1753 | * @since v18 | ||
| 1754 |      * @return array{picto:string,ref?:string,total_ht?:string,total_tva?:string,total_ttc?:string} | ||
| 1755 | */ | ||
| 1756 | public function getTooltipContentArray($params) | ||
| 1757 |     { | ||
| 1758 | global $conf, $langs; | ||
| 1759 | |||
| 1760 |         $langs->load('trips'); | ||
| 1761 | |||
| 1762 | $nofetch = !empty($params['nofetch']); | ||
| 1763 | $moretitle = $params['moretitle'] ?? ''; | ||
| 1764 | |||
| 1765 | $datas = array(); | ||
| 1766 |         $datas['picto'] = img_picto('', $this->picto) . ' <u class="paddingrightonly">' . $langs->trans("ExpenseReport") . '</u>'; | ||
| 1767 |         if (isset($this->status)) { | ||
| 1768 | $datas['picto'] .= ' ' . $this->getLibStatut(5); | ||
| 1769 | } | ||
| 1770 |         if ($moretitle) { | ||
| 1771 | $datas['picto'] .= ' - ' . $moretitle; | ||
| 1772 | } | ||
| 1773 |         if (!empty($this->ref)) { | ||
| 1774 |             $datas['ref'] = '<br><b>' . $langs->trans('Ref') . ':</b> ' . $this->ref; | ||
| 1775 | } | ||
| 1776 |         if (!empty($this->total_ht)) { | ||
| 1777 |             $datas['total_ht'] = '<br><b>' . $langs->trans('AmountHT') . ':</b> ' . price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency); | ||
| 1778 | } | ||
| 1779 |         if (!empty($this->total_tva)) { | ||
| 1780 |             $datas['total_tva'] = '<br><b>' . $langs->trans('VAT') . ':</b> ' . price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency); | ||
| 1781 | } | ||
| 1782 |         if (!empty($this->total_ttc)) { | ||
| 1783 |             $datas['total_ttc'] = '<br><b>' . $langs->trans('AmountTTC') . ':</b> ' . price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency); | ||
| 1784 | } | ||
| 1785 | |||
| 1786 | return $datas; | ||
| 1787 | } | ||
| 1788 | |||
| 1789 | /** | ||
| 1790 | * Return clicable name (with picto eventually) | ||
| 1791 | * | ||
| 1792 | * @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto | ||
| 1793 |      *  @param      string  $option                     Where point the link ('', 'document', ..) | ||
| 1794 | * @param int $max Max length of shown ref | ||
| 1795 | * @param int $short 1=Return just URL | ||
| 1796 | * @param string $moretitle Add more text to title tooltip | ||
| 1797 | * @param int $notooltip 1=Disable tooltip | ||
| 1798 | * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking | ||
| 1799 | * @return string String with URL | ||
| 1800 | */ | ||
| 1801 | public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1) | ||
| 1802 |     { | ||
| 1803 | global $langs, $hookmanager; | ||
| 1804 | |||
| 1805 | $result = ''; | ||
| 1806 | |||
| 1807 |         $url = constant('BASE_URL') . '/expensereport/card.php?id=' . $this->id; | ||
| 1808 | |||
| 1809 |         if ($short) { | ||
| 1810 | return $url; | ||
| 1811 | } | ||
| 1812 | |||
| 1813 | $params = [ | ||
| 1814 | 'id' => $this->id, | ||
| 1815 | 'objecttype' => $this->element, | ||
| 1816 | 'option' => $option, | ||
| 1817 | 'moretitle' => $moretitle, | ||
| 1818 | 'nofetch' => 1, | ||
| 1819 | ]; | ||
| 1820 | $classfortooltip = 'classfortooltip'; | ||
| 1821 | $dataparams = ''; | ||
| 1822 |         if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { | ||
| 1823 | $classfortooltip = 'classforajaxtooltip'; | ||
| 1824 | $dataparams = ' data-params="' . dol_escape_htmltag(json_encode($params)) . '"'; | ||
| 1825 | $label = ''; | ||
| 1826 |         } else { | ||
| 1827 | $label = implode($this->getTooltipContentArray($params)); | ||
| 1828 | } | ||
| 1829 | |||
| 1830 |         if ($option != 'nolink') { | ||
| 1831 | // Add param to save lastsearch_values or not | ||
| 1832 | $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); | ||
| 1833 |             if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) { | ||
| 1834 | $add_save_lastsearch_values = 1; | ||
| 1835 | } | ||
| 1836 |             if ($add_save_lastsearch_values) { | ||
| 1837 | $url .= '&save_lastsearch_values=1'; | ||
| 1838 | } | ||
| 1839 | } | ||
| 1840 | |||
| 1841 | $ref = $this->ref; | ||
| 1842 |         if (empty($ref)) { | ||
| 1843 | $ref = $this->id; | ||
| 1844 | } | ||
| 1845 | |||
| 1846 | $linkclose = ''; | ||
| 1847 |         if (empty($notooltip)) { | ||
| 1848 |             if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) { | ||
| 1849 |                 $label = $langs->trans("ShowExpenseReport"); | ||
| 1850 | $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"'; | ||
| 1851 | } | ||
| 1852 | $linkclose .= ($label ? ' title="' . dol_escape_htmltag($label, 1) . '"' : ' title="tocomplete"'); | ||
| 1853 | $linkclose .= $dataparams . ' class="' . $classfortooltip . '"'; | ||
| 1854 | } | ||
| 1855 | |||
| 1856 | $linkstart = '<a href="' . $url . '"'; | ||
| 1857 | $linkstart .= $linkclose . '>'; | ||
| 1858 | $linkend = '</a>'; | ||
| 1859 | |||
| 1860 | $result .= $linkstart; | ||
| 1861 |         if ($withpicto) { | ||
| 1862 | $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . '"'), 0, 0, $notooltip ? 0 : 1); | ||
| 1863 | } | ||
| 1864 |         if ($withpicto != 2) { | ||
| 1865 | $result .= ($max ? dol_trunc($ref, $max) : $ref); | ||
| 1866 | } | ||
| 1867 | $result .= $linkend; | ||
| 1868 | |||
| 1869 | global $action; | ||
| 1870 | $hookmanager->initHooks(array($this->element . 'dao')); | ||
| 1871 |         $parameters = array('id' => $this->id, 'getnomurl' => &$result); | ||
| 1872 |         $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks | ||
| 1873 |         if ($reshook > 0) { | ||
| 1874 | $result = $hookmanager->resPrint; | ||
| 1875 |         } else { | ||
| 1876 | $result .= $hookmanager->resPrint; | ||
| 1877 | } | ||
| 1878 | return $result; | ||
| 1879 | } | ||
| 1880 | |||
| 1881 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps | ||
| 1882 | /** | ||
| 1883 | * Update total of an expense report when you add a line. | ||
| 1884 | * | ||
| 1885 | * @param string $ligne_total_ht Amount without taxes | ||
| 1886 | * @param string $ligne_total_tva Amount of all taxes | ||
| 1887 | * @return int | ||
| 1888 | */ | ||
| 1889 | public function update_totaux_add($ligne_total_ht, $ligne_total_tva) | ||
| 1908 | } | ||
| 1909 | } | ||
| 1910 | |||
| 1911 | /** | ||
| 1912 | * Add expense report line | ||
| 1913 | * | ||
| 1914 | * @param float $qty Qty | ||
| 1915 | * @param double $up Unit price (price with tax) | ||
| 1916 | * @param int $fk_c_type_fees Type payment | ||
| 1917 | * @param int<-1,0>|string $vatrate Vat rate (Can be '10' or '10 (ABC)') | ||
| 1918 | * @param string $date Date | ||
| 1919 | * @param string $comments Description | ||
| 1920 | * @param int $fk_project Project id | ||
| 1921 | * @param int $fk_c_exp_tax_cat Car category id | ||
| 1922 | * @param int $type Type line | ||
| 1923 | * @param int $fk_ecm_files Id of ECM file to link to this expensereport line | ||
| 1924 | * @return int Return integer <0 if KO, >0 if OK | ||
| 1925 | */ | ||
| 1926 | public function addline($qty = 0, $up = 0, $fk_c_type_fees = 0, $vatrate = 0, $date = '', $comments = '', $fk_project = 0, $fk_c_exp_tax_cat = 0, $type = 0, $fk_ecm_files = 0) | ||
| 1927 |     { | ||
| 1928 | global $langs, $mysoc; | ||
| 1929 | |||
| 1930 | dol_syslog(get_only_class($this) . "::addline qty=$qty, up=$up, fk_c_type_fees=$fk_c_type_fees, vatrate=$vatrate, date=$date, fk_project=$fk_project, type=$type, comments=$comments", LOG_DEBUG); | ||
| 1931 | |||
| 1932 |         if ($this->status == self::STATUS_DRAFT) { | ||
| 1933 |             if (empty($qty)) { | ||
| 1934 | $qty = 0; | ||
| 1935 | } | ||
| 1936 |             if (empty($fk_c_type_fees) || $fk_c_type_fees < 0) { | ||
| 1937 | $fk_c_type_fees = 0; | ||
| 1938 | } | ||
| 1939 |             if (empty($fk_c_exp_tax_cat) || $fk_c_exp_tax_cat < 0) { | ||
| 1940 | $fk_c_exp_tax_cat = 0; | ||
| 1941 | } | ||
| 1942 |             if (empty($vatrate) || $vatrate < 0) { | ||
| 1943 | $vatrate = 0; | ||
| 1944 | } | ||
| 1945 |             if (empty($date)) { | ||
| 1946 | $date = ''; | ||
| 1947 | } | ||
| 1948 |             if (empty($fk_project)) { | ||
| 1949 | $fk_project = 0; | ||
| 1950 | } | ||
| 1951 | |||
| 1952 | $qty = (float) price2num($qty); | ||
| 1953 |             if (!preg_match('/\s*\((.*)\)/', $vatrate)) { | ||
| 1954 | $vatrate = price2num($vatrate); // $txtva can have format '5.0 (XXX)' or '5' | ||
| 1955 | } | ||
| 1956 | $up = price2num($up); | ||
| 1957 | |||
| 1958 | $this->db->begin(); | ||
| 1959 | |||
| 1960 | $this->line = new ExpenseReportLine($this->db); | ||
| 1961 | |||
| 1962 | // We don't know seller and buyer for expense reports | ||
| 1963 | $seller = $mysoc; // We use same than current company (expense report are often done in same country) | ||
| 1964 | $seller->tva_assuj = 1; // Most seller uses vat | ||
| 1965 | $buyer = new Societe($this->db); | ||
| 1966 | |||
| 1967 | $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $buyer, $seller); | ||
| 1968 | |||
| 1969 | $vat_src_code = ''; | ||
| 1970 | $reg = array(); | ||
| 1971 |             if (preg_match('/\s*\((.*)\)/', $vatrate, $reg)) { | ||
| 1972 | $vat_src_code = $reg[1]; | ||
| 1973 |                 $vatrate = preg_replace('/\s*\(.*\)/', '', $vatrate); // Remove code into vatrate. | ||
| 1974 | } | ||
| 1975 |             $vatrate = preg_replace('/\*/', '', $vatrate); | ||
| 1976 | |||
| 1977 | $tmp = calcul_price_total($qty, $up, 0, $vatrate, -1, -1, 0, 'TTC', 0, $type, $seller, $localtaxes_type); | ||
| 1978 | |||
| 1979 | $this->line->value_unit = $up; | ||
| 1980 | |||
| 1981 | $this->line->vat_src_code = $vat_src_code; | ||
| 1982 | $this->line->vatrate = price2num($vatrate); | ||
| 1983 | $this->line->localtax1_tx = $localtaxes_type[1]; | ||
| 1984 | $this->line->localtax2_tx = $localtaxes_type[3]; | ||
| 1985 | $this->line->localtax1_type = $localtaxes_type[0]; | ||
| 1986 | $this->line->localtax2_type = $localtaxes_type[2]; | ||
| 1987 | |||
| 1988 | $this->line->total_ttc = $tmp[2]; | ||
| 1989 | $this->line->total_ht = $tmp[0]; | ||
| 1990 | $this->line->total_tva = $tmp[1]; | ||
| 1991 | $this->line->total_localtax1 = $tmp[9]; | ||
| 1992 | $this->line->total_localtax2 = $tmp[10]; | ||
| 1993 | |||
| 1994 | $this->line->fk_expensereport = $this->id; | ||
| 1995 | $this->line->qty = $qty; | ||
| 1996 | $this->line->date = $date; | ||
| 1997 | $this->line->fk_c_type_fees = $fk_c_type_fees; | ||
| 1998 | $this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat; | ||
| 1999 | $this->line->comments = $comments; | ||
| 2000 | $this->line->fk_projet = $fk_project; // deprecated | ||
| 2001 | $this->line->fk_project = $fk_project; | ||
| 2002 | |||
| 2003 | $this->line->fk_ecm_files = $fk_ecm_files; | ||
| 2004 | |||
| 2005 | $this->applyOffset(); | ||
| 2006 | $this->checkRules($type, $seller); | ||
| 2007 | |||
| 2008 | $result = $this->line->insert(0, true); | ||
| 2009 |             if ($result > 0) { | ||
| 2010 | $result = $this->update_price(1); // This method is designed to add line from user input so total calculation must be done using 'auto' mode. | ||
| 2011 |                 if ($result > 0) { | ||
| 2012 | $this->db->commit(); | ||
| 2013 | return $this->line->id; | ||
| 2014 |                 } else { | ||
| 2015 | $this->db->rollback(); | ||
| 2016 | return -1; | ||
| 2017 | } | ||
| 2018 |             } else { | ||
| 2019 | $this->error = $this->line->error; | ||
| 2020 | dol_syslog(get_only_class($this) . "::addline error=" . $this->error, LOG_ERR); | ||
| 2021 | $this->db->rollback(); | ||
| 2022 | return -2; | ||
| 2023 | } | ||
| 2024 |         } else { | ||
| 2025 | dol_syslog(get_only_class($this) . "::addline status of expense report must be Draft to allow use of ->addline()", LOG_ERR); | ||
| 2026 | $this->error = 'ErrorExpenseNotDraft'; | ||
| 2027 | return -3; | ||
| 2028 | } | ||
| 2029 | } | ||
| 2030 | |||
| 2031 | /** | ||
| 2032 | * Check constraint of rules and update price if needed | ||
| 2033 | * | ||
| 2034 | * @param int $type Type of line | ||
| 2035 | * @param string $seller Seller, but actually he is unknown | ||
| 2036 | * @return boolean true or false | ||
| 2037 | */ | ||
| 2038 | public function checkRules($type = 0, $seller = '') | ||
| 2039 |     { | ||
| 2040 | global $conf, $db, $langs, $mysoc; | ||
| 2041 | |||
| 2042 |         $langs->load('trips'); | ||
| 2043 | |||
| 2044 | // We don't know seller and buyer for expense reports | ||
| 2045 |         if (!is_object($seller)) { | ||
| 2046 | $seller = $mysoc; // We use same than current company (expense report are often done in same country) | ||
| 2047 | $seller->tva_assuj = 1; // Most seller uses vat | ||
| 2048 | } | ||
| 2049 | |||
| 2050 | $expensereportrule = new ExpenseReportRule($db); | ||
| 2051 | $rulestocheck = $expensereportrule->getAllRule($this->line->fk_c_type_fees, $this->line->date, $this->fk_user_author); | ||
| 2052 | |||
| 2053 | $violation = 0; | ||
| 2054 | $rule_warning_message_tab = array(); | ||
| 2055 | |||
| 2056 | $current_total_ttc = $this->line->total_ttc; | ||
| 2057 | $new_current_total_ttc = $this->line->total_ttc; | ||
| 2058 | |||
| 2059 | // check if one is violated | ||
| 2060 |         foreach ($rulestocheck as $rule) { | ||
| 2061 |             if (in_array($rule->code_expense_rules_type, array('EX_DAY', 'EX_MON', 'EX_YEA'))) { | ||
| 2062 | $amount_to_test = $this->line->getExpAmount($rule, $this->fk_user_author, $rule->code_expense_rules_type); | ||
| 2063 |             } else { | ||
| 2064 | $amount_to_test = $current_total_ttc; // EX_EXP | ||
| 2065 | } | ||
| 2066 | |||
| 2067 | $amount_to_test = $amount_to_test - $current_total_ttc + $new_current_total_ttc; // if amount as been modified by a previous rule | ||
| 2068 | |||
| 2069 |             if ($amount_to_test > $rule->amount) { | ||
| 2070 | $violation++; | ||
| 2071 | |||
| 2072 |                 if ($rule->restrictive) { | ||
| 2073 | $this->error = 'ExpenseReportConstraintViolationError'; | ||
| 2074 | $this->errors[] = $this->error; | ||
| 2075 | |||
| 2076 | $new_current_total_ttc -= $amount_to_test - $rule->amount; // ex, entered 16€, limit 12€, subtracts 4€; | ||
| 2077 |                     $rule_warning_message_tab[] = $langs->trans('ExpenseReportConstraintViolationError', $rule->id, price($amount_to_test, 0, $langs, 1, -1, -1, $conf->currency), price($rule->amount, 0, $langs, 1, -1, -1, $conf->currency)); | ||
| 2078 |                 } else { | ||
| 2079 | $this->error = 'ExpenseReportConstraintViolationWarning'; | ||
| 2080 | $this->errors[] = $this->error; | ||
| 2081 | |||
| 2082 |                     $rule_warning_message_tab[] = $langs->trans('ExpenseReportConstraintViolationWarning', $rule->id, price($amount_to_test, 0, $langs, 1, -1, -1, $conf->currency), price($rule->amount, 0, $langs, 1, -1, -1, $conf->currency)); | ||
| 2083 | } | ||
| 2084 | |||
| 2085 | // No break, we should test if another rule is violated | ||
| 2086 | } | ||
| 2087 | } | ||
| 2088 | |||
| 2089 |         $this->line->rule_warning_message = implode('\n', $rule_warning_message_tab); | ||
| 2090 | |||
| 2091 |         if ($violation > 0) { | ||
| 2092 | $tmp = calcul_price_total($this->line->qty, $new_current_total_ttc / $this->line->qty, 0, $this->line->vatrate, 0, 0, 0, 'TTC', 0, $type, $seller); | ||
| 2093 | |||
| 2094 | $this->line->value_unit = $tmp[5]; | ||
| 2095 | $this->line->total_ttc = $tmp[2]; | ||
| 2096 | $this->line->total_ht = $tmp[0]; | ||
| 2097 | $this->line->total_tva = $tmp[1]; | ||
| 2098 | $this->line->total_localtax1 = $tmp[9]; | ||
| 2099 | $this->line->total_localtax2 = $tmp[10]; | ||
| 2100 | |||
| 2101 | return false; | ||
| 2102 |         } else { | ||
| 2103 | return true; | ||
| 2104 | } | ||
| 2105 | } | ||
| 2106 | |||
| 2107 | /** | ||
| 2108 | * Method to apply the offset if needed | ||
| 2109 | * | ||
| 2110 | * @param int $type Type of line | ||
| 2111 | * @param string $seller Seller, but actually he is unknown | ||
| 2112 | * @return boolean True=applied, False=not applied | ||
| 2113 | */ | ||
| 2114 | public function applyOffset($type = 0, $seller = '') | ||
| 2115 |     { | ||
| 2116 | global $mysoc; | ||
| 2117 | |||
| 2118 |         if (!getDolGlobalString('MAIN_USE_EXPENSE_IK')) { | ||
| 2119 | return false; | ||
| 2120 | } | ||
| 2121 | |||
| 2122 | $userauthor = new User($this->db); | ||
| 2123 |         if ($userauthor->fetch($this->fk_user_author) <= 0) { | ||
| 2124 | $this->error = 'ErrorCantFetchUser'; | ||
| 2125 | $this->errors[] = 'ErrorCantFetchUser'; | ||
| 2126 | return false; | ||
| 2127 | } | ||
| 2128 | |||
| 2129 | // We don't know seller and buyer for expense reports | ||
| 2130 |         if (!is_object($seller)) { | ||
| 2131 | $seller = $mysoc; // We use same than current company (expense report are often done in same country) | ||
| 2132 | $seller->tva_assuj = 1; // Most seller uses vat | ||
| 2133 | } | ||
| 2134 | |||
| 2135 | $expenseik = new ExpenseReportIk($this->db); | ||
| 2136 | $range = $expenseik->getRangeByUser($userauthor, $this->line->fk_c_exp_tax_cat); | ||
| 2137 | |||
| 2138 |         if (empty($range)) { | ||
| 2139 | $this->error = 'ErrorNoRangeAvailable'; | ||
| 2140 | $this->errors[] = 'ErrorNoRangeAvailable'; | ||
| 2141 | return false; | ||
| 2142 | } | ||
| 2143 | |||
| 2144 |         if (getDolGlobalString('MAIN_EXPENSE_APPLY_ENTIRE_OFFSET')) { | ||
| 2145 | $ikoffset = $range->ikoffset; | ||
| 2146 |         } else { | ||
| 2147 | $ikoffset = $range->ikoffset / 12; // The amount of offset is a global value for the year | ||
| 2148 | } | ||
| 2149 | |||
| 2150 | // Test if ikoffset has been applied for the current month | ||
| 2151 |         if (!$this->offsetAlreadyGiven()) { | ||
| 2152 | $new_up = $range->coef + ($ikoffset / $this->line->qty); | ||
| 2153 | $tmp = calcul_price_total($this->line->qty, $new_up, 0, $this->line->vatrate, 0, 0, 0, 'TTC', 0, $type, $seller); | ||
| 2154 | |||
| 2155 | $this->line->value_unit = $tmp[5]; | ||
| 2156 | $this->line->total_ttc = $tmp[2]; | ||
| 2157 | $this->line->total_ht = $tmp[0]; | ||
| 2158 | $this->line->total_tva = $tmp[1]; | ||
| 2159 | $this->line->total_localtax1 = $tmp[9]; | ||
| 2160 | $this->line->total_localtax2 = $tmp[10]; | ||
| 2161 | |||
| 2162 | return true; | ||
| 2163 | } | ||
| 2164 | |||
| 2165 | return false; | ||
| 2166 | } | ||
| 2167 | |||
| 2168 | /** | ||
| 2169 | * If the sql find any rows then the ikoffset is already given (ikoffset is applied at the first expense report line) | ||
| 2170 | * | ||
| 2171 | * @return bool | ||
| 2172 | */ | ||
| 2173 | public function offsetAlreadyGiven() | ||
| 2174 |     { | ||
| 2175 | $sql = 'SELECT e.rowid FROM ' . MAIN_DB_PREFIX . 'expensereport e'; | ||
| 2176 | $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "expensereport_det d ON (e.rowid = d.fk_expensereport)"; | ||
| 2177 | $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "c_type_fees f ON (d.fk_c_type_fees = f.id AND f.code = 'EX_KME')"; | ||
| 2178 | $sql .= " WHERE e.fk_user_author = " . (int) $this->fk_user_author; | ||
| 2179 | $sql .= " AND YEAR(d.date) = '" . dol_print_date($this->line->date, '%Y') . "' AND MONTH(d.date) = '" . dol_print_date($this->line->date, '%m') . "'"; | ||
| 2180 |         if (!empty($this->line->id)) { | ||
| 2181 | $sql .= ' AND d.rowid <> ' . ((int) $this->line->id); | ||
| 2182 | } | ||
| 2183 | |||
| 2184 | dol_syslog(get_only_class($this) . "::offsetAlreadyGiven"); | ||
| 2185 | $resql = $this->db->query($sql); | ||
| 2186 |         if ($resql) { | ||
| 2187 | $num = $this->db->num_rows($resql); | ||
| 2188 |             if ($num > 0) { | ||
| 2189 | return true; | ||
| 2190 | } | ||
| 2191 |         } else { | ||
| 2192 | dol_print_error($this->db); | ||
| 2193 | } | ||
| 2194 | |||
| 2195 | return false; | ||
| 2196 | } | ||
| 2197 | |||
| 2198 | /** | ||
| 2199 | * Update an expense report line. | ||
| 2200 | * | ||
| 2201 | * @param int $rowid Line to edit | ||
| 2202 | * @param int $type_fees_id Type payment | ||
| 2203 | * @param int $projet_id Project id | ||
| 2204 | * @param double $vatrate Vat rate. Can be '8.5' or '8.5* (8.5NPROM...)' | ||
| 2205 | * @param string $comments Description | ||
| 2206 | * @param float $qty Qty | ||
| 2207 | * @param double $value_unit Unit price (with taxes) | ||
| 2208 | * @param int $date Date | ||
| 2209 | * @param int $expensereport_id Expense report id | ||
| 2210 | * @param int $fk_c_exp_tax_cat Id of category of car | ||
| 2211 | * @param int $fk_ecm_files Id of ECM file to link to this expensereport line | ||
| 2212 | * @param int $notrigger 1=No trigger | ||
| 2213 | * @return int Return integer <0 if KO, >0 if OK | ||
| 2214 | */ | ||
| 2215 | public function updateline($rowid, $type_fees_id, $projet_id, $vatrate, $comments, $qty, $value_unit, $date, $expensereport_id, $fk_c_exp_tax_cat = 0, $fk_ecm_files = 0, $notrigger = 0) | ||
| 2216 |     { | ||
| 2217 | global $user, $mysoc; | ||
| 2218 | |||
| 2219 |         if ($this->status == self::STATUS_DRAFT || $this->status == self::STATUS_REFUSED) { | ||
| 2220 | $this->db->begin(); | ||
| 2221 | |||
| 2222 | $error = 0; | ||
| 2223 | $type = 0; // TODO What if type is service ? | ||
| 2224 | |||
| 2225 | // We don't know seller and buyer for expense reports | ||
| 2226 | $seller = $mysoc; // We use same than current company (expense report are often done in same country) | ||
| 2227 | $seller->tva_assuj = 1; // Most seller uses vat | ||
| 2228 | $seller->localtax1_assuj = $mysoc->localtax1_assuj; // We don't know, we reuse the state of company | ||
| 2229 | $seller->localtax2_assuj = $mysoc->localtax1_assuj; // We don't know, we reuse the state of company | ||
| 2230 | $buyer = new Societe($this->db); | ||
| 2231 | |||
| 2232 | $localtaxes_type = getLocalTaxesFromRate($vatrate, 0, $buyer, $seller); | ||
| 2233 | |||
| 2234 | // Clean vat code | ||
| 2235 | $reg = array(); | ||
| 2236 | $vat_src_code = ''; | ||
| 2237 |             if (preg_match('/\((.*)\)/', (string) $vatrate, $reg)) { | ||
| 2238 | $vat_src_code = $reg[1]; | ||
| 2239 |                 $vatrate = preg_replace('/\s*\(.*\)/', '', (string) $vatrate); // Remove code into vatrate. | ||
| 2240 | } | ||
| 2241 |             $vatrate = preg_replace('/\*/', '', $vatrate); | ||
| 2242 | |||
| 2243 | $tmp = calcul_price_total($qty, $value_unit, 0, $vatrate, -1, -1, 0, 'TTC', 0, $type, $seller, $localtaxes_type); | ||
| 2244 | //var_dump($vatrate);var_dump($localtaxes_type);var_dump($tmp);exit; | ||
| 2245 | // calcul total of line | ||
| 2246 | //$total_ttc = price2num($qty*$value_unit, 'MT'); | ||
| 2247 | |||
| 2248 | $tx_tva = 1 + (float) $vatrate / 100; | ||
| 2249 | |||
| 2250 | $this->line = new ExpenseReportLine($this->db); | ||
| 2251 | $this->line->comments = $comments; | ||
| 2252 | $this->line->qty = $qty; | ||
| 2253 | $this->line->value_unit = $value_unit; | ||
| 2254 | $this->line->date = $date; | ||
| 2255 | |||
| 2256 | $this->line->fk_expensereport = $expensereport_id; | ||
| 2257 | $this->line->fk_c_type_fees = $type_fees_id; | ||
| 2258 | $this->line->fk_c_exp_tax_cat = $fk_c_exp_tax_cat; | ||
| 2259 | $this->line->fk_projet = $projet_id; // deprecated | ||
| 2260 | $this->line->fk_project = $projet_id; | ||
| 2261 | |||
| 2262 | $this->line->vat_src_code = $vat_src_code; | ||
| 2263 | $this->line->vatrate = price2num($vatrate); | ||
| 2264 | $this->line->localtax1_tx = $localtaxes_type[1]; | ||
| 2265 | $this->line->localtax2_tx = $localtaxes_type[3]; | ||
| 2266 | $this->line->localtax1_type = $localtaxes_type[0]; | ||
| 2267 | $this->line->localtax2_type = $localtaxes_type[2]; | ||
| 2268 | |||
| 2269 | $this->line->total_ttc = $tmp[2]; | ||
| 2270 | $this->line->total_ht = $tmp[0]; | ||
| 2271 | $this->line->total_tva = $tmp[1]; | ||
| 2272 | $this->line->total_localtax1 = $tmp[9]; | ||
| 2273 | $this->line->total_localtax2 = $tmp[10]; | ||
| 2274 | |||
| 2275 | $this->line->fk_ecm_files = $fk_ecm_files; | ||
| 2276 | |||
| 2277 | $this->line->id = ((int) $rowid); | ||
| 2278 | |||
| 2279 | // Select des infos sur le type fees | ||
| 2280 | $sql = "SELECT c.code as code_type_fees, c.label as label_type_fees"; | ||
| 2281 | $sql .= " FROM " . MAIN_DB_PREFIX . "c_type_fees as c"; | ||
| 2282 | $sql .= " WHERE c.id = " . ((int) $type_fees_id); | ||
| 2283 | $resql = $this->db->query($sql); | ||
| 2284 |             if ($resql) { | ||
| 2285 | $objp_fees = $this->db->fetch_object($resql); | ||
| 2286 | $this->line->type_fees_code = $objp_fees->code_type_fees; | ||
| 2287 | $this->line->type_fees_libelle = $objp_fees->label_type_fees; | ||
| 2288 | $this->db->free($resql); | ||
| 2289 | } | ||
| 2290 | |||
| 2291 | // Select des information du projet | ||
| 2292 | $sql = "SELECT p.ref as ref_projet, p.title as title_projet"; | ||
| 2293 | $sql .= " FROM " . MAIN_DB_PREFIX . "projet as p"; | ||
| 2294 | $sql .= " WHERE p.rowid = " . ((int) $projet_id); | ||
| 2295 | $resql = $this->db->query($sql); | ||
| 2296 |             if ($resql) { | ||
| 2297 | $objp_projet = $this->db->fetch_object($resql); | ||
| 2298 | $this->line->projet_ref = $objp_projet->ref_projet; | ||
| 2299 | $this->line->projet_title = $objp_projet->title_projet; | ||
| 2300 | $this->db->free($resql); | ||
| 2301 | } | ||
| 2302 | |||
| 2303 | $this->applyOffset(); | ||
| 2304 | $this->checkRules(); | ||
| 2305 | |||
| 2306 | $result = $this->line->update($user); | ||
| 2307 |             if ($result < 0) { | ||
| 2308 | $error++; | ||
| 2309 | } | ||
| 2310 | |||
| 2311 |             if (!$error && !$notrigger) { | ||
| 2312 | // Call triggers | ||
| 2313 |                 $result = $this->call_trigger('EXPENSE_REPORT_DET_MODIFY', $user); | ||
| 2314 |                 if ($result < 0) { | ||
| 2315 | $error++; | ||
| 2316 | } | ||
| 2317 | // End call triggers | ||
| 2318 | } | ||
| 2319 | |||
| 2320 |             if (!$error) { | ||
| 2321 | $this->db->commit(); | ||
| 2322 | return 1; | ||
| 2323 |             } else { | ||
| 2324 | $this->error = $this->line->error; | ||
| 2325 | $this->errors = $this->line->errors; | ||
| 2326 | $this->db->rollback(); | ||
| 2327 | return -2; | ||
| 2328 | } | ||
| 2329 | } | ||
| 2330 | |||
| 2331 | return 0; | ||
| 2332 | } | ||
| 2333 | |||
| 2334 | /** | ||
| 2335 | * deleteline | ||
| 2336 | * | ||
| 2337 | * @param int $rowid Row id | ||
| 2338 | * @param User|string $fuser User | ||
| 2339 | * @param int<0,1> $notrigger 1=No trigger | ||
| 2340 | * @return int<-1,1> Return integer <0 if KO, >0 if OK | ||
| 2341 | */ | ||
| 2342 | public function deleteLine($rowid, $fuser = '', $notrigger = 0) | ||
| 2343 |     { | ||
| 2344 | $error = 0; | ||
| 2345 | |||
| 2346 | $this->db->begin(); | ||
| 2347 | |||
| 2348 |         if (!$notrigger) { | ||
| 2349 | // Call triggers | ||
| 2350 |             $result = $this->call_trigger('EXPENSE_REPORT_DET_DELETE', $fuser); | ||
| 2351 |             if ($result < 0) { | ||
| 2352 | $error++; | ||
| 2353 | } | ||
| 2354 | // End call triggers | ||
| 2355 | } | ||
| 2356 | |||
| 2357 | $sql = ' DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element_line; | ||
| 2358 | $sql .= ' WHERE rowid = ' . ((int) $rowid); | ||
| 2359 | |||
| 2360 | dol_syslog(get_only_class($this) . "::deleteline sql=" . $sql); | ||
| 2361 | $result = $this->db->query($sql); | ||
| 2362 | |||
| 2363 |         if (!$result || $error > 0) { | ||
| 2364 | $this->error = $this->db->error(); | ||
| 2365 | dol_syslog(get_only_class($this) . "::deleteline Error " . $this->error, LOG_ERR); | ||
| 2366 | $this->db->rollback(); | ||
| 2367 | return -1; | ||
| 2368 | } | ||
| 2369 | |||
| 2370 | $this->update_price(1); | ||
| 2371 | |||
| 2372 | $this->db->commit(); | ||
| 2373 | |||
| 2374 | return 1; | ||
| 2375 | } | ||
| 2376 | |||
| 2377 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps | ||
| 2378 | /** | ||
| 2379 | * periode_existe | ||
| 2380 | * | ||
| 2381 | * @param User $fuser User | ||
| 2382 | * @param integer $date_debut Start date | ||
| 2383 | * @param integer $date_fin End date | ||
| 2384 | * @return int Return integer <0 if KO, >0 if OK | ||
| 2385 | */ | ||
| 2386 | public function periode_existe($fuser, $date_debut, $date_fin) | ||
| 2427 | } | ||
| 2428 | } | ||
| 2429 | |||
| 2430 | |||
| 2431 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps | ||
| 2432 | /** | ||
| 2433 | * Return list of people with permission to validate expense reports. | ||
| 2434 | * Search for permission "approve expense report" | ||
| 2435 | * | ||
| 2436 | * @return array|int Array of user ids, <0 if KO | ||
| 2437 | */ | ||
| 2438 | public function fetch_users_approver_expensereport() | ||
| 2439 |     { | ||
| 2440 | // phpcs:enable | ||
| 2441 | $users_validator = array(); | ||
| 2442 | |||
| 2443 | $sql = "SELECT DISTINCT ur.fk_user"; | ||
| 2444 | $sql .= " FROM " . MAIN_DB_PREFIX . "user_rights as ur, " . MAIN_DB_PREFIX . "rights_def as rd"; | ||
| 2445 | $sql .= " WHERE ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve'; | ||
| 2446 | $sql .= " UNION"; | ||
| 2447 | $sql .= " SELECT DISTINCT ugu.fk_user"; | ||
| 2448 | $sql .= " FROM " . MAIN_DB_PREFIX . "usergroup_user as ugu, " . MAIN_DB_PREFIX . "usergroup_rights as ur, " . MAIN_DB_PREFIX . "rights_def as rd"; | ||
| 2449 | $sql .= " WHERE ugu.fk_usergroup = ur.fk_usergroup AND ur.fk_id = rd.id and rd.module = 'expensereport' AND rd.perms = 'approve'"; // Permission 'Approve'; | ||
| 2450 | //print $sql; | ||
| 2451 | |||
| 2452 | dol_syslog(get_only_class($this) . "::fetch_users_approver_expensereport sql=" . $sql); | ||
| 2453 | $result = $this->db->query($sql); | ||
| 2454 |         if ($result) { | ||
| 2455 | $num_rows = $this->db->num_rows($result); | ||
| 2456 | $i = 0; | ||
| 2457 |             while ($i < $num_rows) { | ||
| 2458 | $objp = $this->db->fetch_object($result); | ||
| 2459 | array_push($users_validator, $objp->fk_user); | ||
| 2460 | $i++; | ||
| 2461 | } | ||
| 2462 | return $users_validator; | ||
| 2463 |         } else { | ||
| 2464 | $this->error = $this->db->lasterror(); | ||
| 2465 | dol_syslog(get_only_class($this) . "::fetch_users_approver_expensereport Error " . $this->error, LOG_ERR); | ||
| 2466 | return -1; | ||
| 2467 | } | ||
| 2468 | } | ||
| 2469 | |||
| 2470 | /** | ||
| 2471 | * Create a document onto disk according to template module. | ||
| 2472 | * | ||
| 2473 |      *  @param      string      $modele         Force le mnodele a utiliser ('' to not force) | ||
| 2474 | * @param Translate $outputlangs object lang a utiliser pour traduction | ||
| 2475 | * @param int $hidedetails Hide details of lines | ||
| 2476 | * @param int $hidedesc Hide description | ||
| 2477 | * @param int $hideref Hide ref | ||
| 2478 | * @param ?array $moreparams Array to provide more information | ||
| 2479 | * @return int 0 if KO, 1 if OK | ||
| 2480 | */ | ||
| 2481 | public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null) | ||
| 2482 |     { | ||
| 2483 |         $outputlangs->load("trips"); | ||
| 2484 | |||
| 2485 |         if (!dol_strlen($modele)) { | ||
| 2486 |             if (!empty($this->model_pdf)) { | ||
| 2487 | $modele = $this->model_pdf; | ||
| 2488 |             } elseif (getDolGlobalString('EXPENSEREPORT_ADDON_PDF')) { | ||
| 2489 |                 $modele = getDolGlobalString('EXPENSEREPORT_ADDON_PDF'); | ||
| 2490 | } | ||
| 2491 | } | ||
| 2492 | |||
| 2493 |         if (!empty($modele)) { | ||
| 2494 | $modelpath = "core/modules/expensereport/doc/"; | ||
| 2495 | |||
| 2496 | return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); | ||
| 2497 |         } else { | ||
| 2498 | return 0; | ||
| 2499 | } | ||
| 2500 | } | ||
| 2501 | |||
| 2502 | /** | ||
| 2503 | * List of types | ||
| 2504 | * | ||
| 2505 | * @param int $active Active or not | ||
| 2506 | * @return array | ||
| 2507 | */ | ||
| 2508 | public function listOfTypes($active = 1) | ||
| 2509 |     { | ||
| 2510 | global $langs; | ||
| 2511 | $ret = array(); | ||
| 2512 | $sql = "SELECT id, code, label"; | ||
| 2513 | $sql .= " FROM " . MAIN_DB_PREFIX . "c_type_fees"; | ||
| 2514 | $sql .= " WHERE active = " . ((int) $active); | ||
| 2515 | dol_syslog(get_only_class($this) . "::listOfTypes", LOG_DEBUG); | ||
| 2516 | $result = $this->db->query($sql); | ||
| 2517 |         if ($result) { | ||
| 2518 | $num = $this->db->num_rows($result); | ||
| 2519 | $i = 0; | ||
| 2520 |             while ($i < $num) { | ||
| 2521 | $obj = $this->db->fetch_object($result); | ||
| 2522 | $ret[$obj->code] = (($langs->transnoentitiesnoconv($obj->code) != $obj->code) ? $langs->transnoentitiesnoconv($obj->code) : $obj->label); | ||
| 2523 | $i++; | ||
| 2524 | } | ||
| 2525 |         } else { | ||
| 2526 | dol_print_error($this->db); | ||
| 2527 | } | ||
| 2528 | return $ret; | ||
| 2529 | } | ||
| 2530 | |||
| 2531 | /** | ||
| 2532 | * Load the indicators this->nb for the state board | ||
| 2533 | * | ||
| 2534 | * @return int Return integer <0 if KO, >0 if OK | ||
| 2535 | */ | ||
| 2536 | public function loadStateBoard() | ||
| 2537 |     { | ||
| 2538 | global $user; | ||
| 2539 | |||
| 2540 | $this->nb = array(); | ||
| 2541 | |||
| 2542 | $sql = "SELECT count(ex.rowid) as nb"; | ||
| 2543 | $sql .= " FROM " . MAIN_DB_PREFIX . "expensereport as ex"; | ||
| 2544 | $sql .= " WHERE ex.fk_statut > 0"; | ||
| 2545 |         $sql .= " AND ex.entity IN (" . getEntity('expensereport') . ")"; | ||
| 2546 |         if (!$user->hasRight('expensereport', 'readall')) { | ||
| 2547 | $userchildids = $user->getAllChildIds(1); | ||
| 2548 |             $sql .= " AND (ex.fk_user_author IN (" . $this->db->sanitize(implode(',', $userchildids)) . ")"; | ||
| 2549 |             $sql .= " OR ex.fk_user_validator IN (" . $this->db->sanitize(implode(',', $userchildids)) . "))"; | ||
| 2550 | } | ||
| 2551 | |||
| 2552 | $resql = $this->db->query($sql); | ||
| 2553 |         if ($resql) { | ||
| 2554 |             while ($obj = $this->db->fetch_object($resql)) { | ||
| 2555 | $this->nb["expensereports"] = $obj->nb; | ||
| 2556 | } | ||
| 2557 | $this->db->free($resql); | ||
| 2558 | return 1; | ||
| 2559 |         } else { | ||
| 2560 | dol_print_error($this->db); | ||
| 2561 | $this->error = $this->db->error(); | ||
| 2562 | return -1; | ||
| 2563 | } | ||
| 2564 | } | ||
| 2565 | |||
| 2566 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps | ||
| 2567 | /** | ||
| 2568 | * Load indicators for dashboard (this->nbtodo and this->nbtodolate) | ||
| 2569 | * | ||
| 2570 | * @param User $user Object user | ||
| 2571 | * @param string $option 'topay' or 'toapprove' | ||
| 2572 | * @return WorkboardResponse|int Return integer <0 if KO, WorkboardResponse if OK | ||
| 2573 | */ | ||
| 2574 | public function load_board($user, $option = 'topay') | ||
| 2575 |     { | ||
| 2576 | // phpcs:enable | ||
| 2577 | global $conf, $langs; | ||
| 2578 | |||
| 2579 |         if ($user->socid) { | ||
| 2580 | return -1; // protection pour eviter appel par utilisateur externe | ||
| 2581 | } | ||
| 2582 | |||
| 2583 | $now = dol_now(); | ||
| 2584 | |||
| 2585 | $sql = "SELECT ex.rowid, ex.date_valid"; | ||
| 2586 | $sql .= " FROM " . MAIN_DB_PREFIX . "expensereport as ex"; | ||
| 2587 |         if ($option == 'toapprove') { | ||
| 2588 | $sql .= " WHERE ex.fk_statut = " . self::STATUS_VALIDATED; | ||
| 2589 |         } else { | ||
| 2590 | $sql .= " WHERE ex.fk_statut = " . self::STATUS_APPROVED; | ||
| 2591 | } | ||
| 2592 |         $sql .= " AND ex.entity IN (" . getEntity('expensereport') . ")"; | ||
| 2593 |         if (!$user->hasRight('expensereport', 'readall')) { | ||
| 2594 | $userchildids = $user->getAllChildIds(1); | ||
| 2595 |             $sql .= " AND (ex.fk_user_author IN (" . $this->db->sanitize(implode(',', $userchildids)) . ")"; | ||
| 2596 |             $sql .= " OR ex.fk_user_validator IN (" . $this->db->sanitize(implode(',', $userchildids)) . "))"; | ||
| 2597 | } | ||
| 2598 | |||
| 2599 | $resql = $this->db->query($sql); | ||
| 2600 |         if ($resql) { | ||
| 2601 |             $langs->load("trips"); | ||
| 2602 | |||
| 2603 | $response = new WorkboardResponse(); | ||
| 2604 |             if ($option == 'toapprove') { | ||
| 2605 | $response->warning_delay = $conf->expensereport->approve->warning_delay / 60 / 60 / 24; | ||
| 2606 |                 $response->label = $langs->trans("ExpenseReportsToApprove"); | ||
| 2607 |                 $response->labelShort = $langs->trans("ToApprove"); | ||
| 2608 |                 $response->url = constant('BASE_URL') . '/expensereport/list.php?mainmenu=hrm&statut=' . self::STATUS_VALIDATED; | ||
| 2609 |             } else { | ||
| 2610 | $response->warning_delay = $conf->expensereport->payment->warning_delay / 60 / 60 / 24; | ||
| 2611 |                 $response->label = $langs->trans("ExpenseReportsToPay"); | ||
| 2612 |                 $response->labelShort = $langs->trans("StatusToPay"); | ||
| 2613 |                 $response->url = constant('BASE_URL') . '/expensereport/list.php?mainmenu=hrm&statut=' . self::STATUS_APPROVED; | ||
| 2614 | } | ||
| 2615 |             $response->img = img_object('', "trip"); | ||
| 2616 | |||
| 2617 |             while ($obj = $this->db->fetch_object($resql)) { | ||
| 2618 | $response->nbtodo++; | ||
| 2619 | |||
| 2620 |                 if ($option == 'toapprove') { | ||
| 2621 |                     if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->approve->warning_delay)) { | ||
| 2622 | $response->nbtodolate++; | ||
| 2623 | } | ||
| 2624 |                 } else { | ||
| 2625 |                     if ($this->db->jdate($obj->date_valid) < ($now - $conf->expensereport->payment->warning_delay)) { | ||
| 2626 | $response->nbtodolate++; | ||
| 2627 | } | ||
| 2628 | } | ||
| 2629 | } | ||
| 2630 | |||
| 2631 | return $response; | ||
| 2632 |         } else { | ||
| 2633 | dol_print_error($this->db); | ||
| 2634 | $this->error = $this->db->error(); | ||
| 2635 | return -1; | ||
| 2636 | } | ||
| 2637 | } | ||
| 2638 | |||
| 2639 | /** | ||
| 2640 | * Return if an expense report is late or not | ||
| 2641 | * | ||
| 2642 | * @param string $option 'topay' or 'toapprove' | ||
| 2643 | * @return boolean True if late, False if not late | ||
| 2644 | */ | ||
| 2645 | public function hasDelay($option) | ||
| 2646 |     { | ||
| 2647 | global $conf; | ||
| 2648 | |||
| 2649 | // Only valid expenses reports | ||
| 2650 |         if ($option == 'toapprove' && $this->status != 2) { | ||
| 2651 | return false; | ||
| 2652 | } | ||
| 2653 |         if ($option == 'topay' && $this->status != 5) { | ||
| 2654 | return false; | ||
| 2655 | } | ||
| 2656 | |||
| 2657 | $now = dol_now(); | ||
| 2658 |         if ($option == 'toapprove') { | ||
| 2659 | return (!empty($this->datevalid) ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->approve->warning_delay); | ||
| 2660 |         } else { | ||
| 2661 | return (!empty($this->datevalid) ? $this->datevalid : $this->date_valid) < ($now - $conf->expensereport->payment->warning_delay); | ||
| 2662 | } | ||
| 2663 | } | ||
| 2664 | |||
| 2665 | /** | ||
| 2666 | * Return if object was dispatched into bookkeeping | ||
| 2667 | * | ||
| 2668 | * @return int Return integer <0 if KO, 0=no, 1=yes | ||
| 2669 | */ | ||
| 2670 | public function getVentilExportCompta() | ||
| 2692 | } | ||
| 2693 | |||
| 2694 | /** | ||
| 2695 | * Return amount of payments already done | ||
| 2696 | * | ||
| 2697 | * @return int Amount of payment already done, <0 if KO | ||
| 2698 | */ | ||
| 2699 | public function getSumPayments() | ||
| 2700 |     { | ||
| 2701 | $table = 'payment_expensereport'; | ||
| 2702 | $field = 'fk_expensereport'; | ||
| 2703 | |||
| 2704 | $sql = 'SELECT sum(amount) as amount'; | ||
| 2705 | $sql .= ' FROM ' . MAIN_DB_PREFIX . $table; | ||
| 2706 | $sql .= " WHERE " . $field . " = " . ((int) $this->id); | ||
| 2707 | |||
| 2708 | dol_syslog(get_only_class($this) . "::getSumPayments", LOG_DEBUG); | ||
| 2709 | $resql = $this->db->query($sql); | ||
| 2710 |         if ($resql) { | ||
| 2711 | $obj = $this->db->fetch_object($resql); | ||
| 2712 | $this->db->free($resql); | ||
| 2713 | return (empty($obj->amount) ? 0 : $obj->amount); | ||
| 2714 |         } else { | ||
| 2715 | $this->error = $this->db->lasterror(); | ||
| 2716 | return -1; | ||
| 2717 | } | ||
| 2718 | } | ||
| 2719 | |||
| 2720 | /** | ||
| 2721 | * \brief Compute the cost of the kilometers expense based on the number of kilometers and the vehicle category | ||
| 2722 | * | ||
| 2723 | * @param int $fk_cat Category of the vehicle used | ||
| 2724 | * @param float $qty Number of kilometers | ||
| 2725 | * @param float $tva VAT rate | ||
| 2726 | * @return int Return integer <0 if KO, total ttc if OK | ||
| 2727 | */ | ||
| 2728 | public function computeTotalKm($fk_cat, $qty, $tva) | ||
| 2729 |     { | ||
| 2730 | global $langs, $db, $conf; | ||
| 2731 | |||
| 2732 | $cumulYearQty = 0; | ||
| 2733 | $ranges = array(); | ||
| 2734 | $coef = 0; | ||
| 2735 | |||
| 2736 | |||
| 2737 |         if ($fk_cat < 0) { | ||
| 2738 |             $this->error = $langs->trans('ErrorBadParameterCat'); | ||
| 2739 | return -1; | ||
| 2740 | } | ||
| 2741 | |||
| 2742 |         if ($qty <= 0) { | ||
| 2743 |             $this->error = $langs->trans('ErrorBadParameterQty'); | ||
| 2744 | return -1; | ||
| 2745 | } | ||
| 2746 | |||
| 2747 | $currentUser = new User($db); | ||
| 2748 | $currentUser->fetch($this->fk_user); | ||
| 2749 |         $currentUser->getrights('expensereport'); | ||
| 2750 | //Clean | ||
| 2751 | $qty = (float) price2num($qty); | ||
| 2752 | |||
| 2753 | $sql = " SELECT r.range_ik, t.ikoffset, t.coef"; | ||
| 2754 | $sql .= " FROM " . MAIN_DB_PREFIX . "expensereport_ik t"; | ||
| 2755 | $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_exp_tax_range r ON r.rowid = t.fk_range"; | ||
| 2756 | $sql .= " WHERE t.fk_c_exp_tax_cat = " . (int) $fk_cat; | ||
| 2757 | $sql .= " ORDER BY r.range_ik ASC"; | ||
| 2758 | |||
| 2759 |         dol_syslog("expenseReport::computeTotalkm sql=" . $sql, LOG_DEBUG); | ||
| 2760 | |||
| 2761 | $result = $this->db->query($sql); | ||
| 2762 | |||
| 2763 |         if ($result) { | ||
| 2764 |             if ($conf->global->EXPENSEREPORT_CALCULATE_MILEAGE_EXPENSE_COEFFICIENT_ON_CURRENT_YEAR) { | ||
| 2765 | $arrayDate = dol_getdate(dol_now()); | ||
| 2766 | $sql = " SELECT count(n.qty) as cumul FROM " . MAIN_DB_PREFIX . "expensereport_det n"; | ||
| 2767 | $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "expensereport e ON e.rowid = n.fk_expensereport"; | ||
| 2768 | $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_type_fees tf ON tf.id = n.fk_c_type_fees"; | ||
| 2769 | $sql .= " WHERE e.fk_user_author = " . (int) $this->fk_user_author; | ||
| 2770 | $sql .= " AND YEAR(n.date) = " . (int) $arrayDate['year']; | ||
| 2771 | $sql .= " AND tf.code = 'EX_KME' "; | ||
| 2772 | $sql .= " AND e.fk_statut = " . (int) ExpenseReport::STATUS_VALIDATED; | ||
| 2773 | |||
| 2774 | $resql = $this->db->query($sql); | ||
| 2775 | |||
| 2776 |                 if ($resql) { | ||
| 2777 | $obj = $this->db->fetch_object($resql); | ||
| 2778 | $cumulYearQty = $obj->cumul; | ||
| 2779 | } | ||
| 2780 | |||
| 2781 | $qty += (float) $cumulYearQty; | ||
| 2782 | } | ||
| 2783 | |||
| 2784 | $num = $this->db->num_rows($result); | ||
| 2785 | |||
| 2786 |             if ($num) { | ||
| 2787 |                 for ($i = 0; $i < $num; $i++) { | ||
| 2788 | $obj = $this->db->fetch_object($result); | ||
| 2789 | |||
| 2790 | $ranges[$i] = $obj; | ||
| 2791 | } | ||
| 2792 | |||
| 2793 | |||
| 2794 |                 for ($i = 0; $i < $num; $i++) { | ||
| 2795 |                     if ($i < ($num - 1)) { | ||
| 2796 |                         if ($qty > $ranges[$i]->range_ik && $qty < $ranges[$i + 1]->range_ik) { | ||
| 2797 | $coef = $ranges[$i]->coef; | ||
| 2798 | $offset = $ranges[$i]->ikoffset; | ||
| 2799 | } | ||
| 2800 |                     } else { | ||
| 2801 |                         if ($qty > $ranges[$i]->range_ik) { | ||
| 2802 | $coef = $ranges[$i]->coef; | ||
| 2803 | $offset = $ranges[$i]->ikoffset; | ||
| 2804 | } | ||
| 2805 | } | ||
| 2806 | } | ||
| 2807 | $total_ht = $coef; | ||
| 2808 | return $total_ht; | ||
| 2809 |             } else { | ||
| 2810 |                 $this->error = $langs->trans('TaxUndefinedForThisCategory'); | ||
| 2811 | return 0; | ||
| 2812 | } | ||
| 2813 |         } else { | ||
| 2814 | $this->error = $this->db->error() . " sql=" . $sql; | ||
| 2815 | |||
| 2816 | return -1; | ||
| 2817 | } | ||
| 2818 | } | ||
| 2819 | |||
| 2820 | /** | ||
| 2821 | * Return clickable link of object (with optional picto) | ||
| 2822 | * | ||
| 2823 | * @param string $option Where point the link (0=> main card, 1,2 => shipment, 'nolink'=>No link) | ||
| 2824 | * @param array $arraydata Array of data | ||
| 2825 | * @return string HTML Code for Kanban thumb. | ||
| 2826 | */ | ||
| 2827 | public function getKanbanView($option = '', $arraydata = null) | ||
| 2858 | } | ||
| 2859 | } | ||
| 2860 |