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