Total Complexity | 582 |
Total Lines | 3669 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like FactureFournisseur 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 FactureFournisseur, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
58 | class FactureFournisseur extends CommonInvoice |
||
59 | { |
||
60 | /** |
||
61 | * @var string ID to identify managed object |
||
62 | */ |
||
63 | public $element = 'invoice_supplier'; |
||
64 | |||
65 | /** |
||
66 | * @var string Name of table without prefix where object is stored |
||
67 | */ |
||
68 | public $table_element = 'facture_fourn'; |
||
69 | |||
70 | /** |
||
71 | * @var string Name of subtable line |
||
72 | */ |
||
73 | public $table_element_line = 'facture_fourn_det'; |
||
74 | |||
75 | /** |
||
76 | * @var string Name of class line |
||
77 | */ |
||
78 | public $class_element_line = 'SupplierInvoiceLine'; |
||
79 | /** |
||
80 | * @var string Field with ID of parent key if this field has a parent |
||
81 | */ |
||
82 | public $fk_element = 'fk_facture_fourn'; |
||
83 | |||
84 | /** |
||
85 | * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png |
||
86 | */ |
||
87 | public $picto = 'supplier_invoice'; |
||
88 | |||
89 | /** |
||
90 | * 0=Default, 1=View may be restricted to sales representative only if no permission to see all or to company of external user if external user |
||
91 | * @var integer |
||
92 | */ |
||
93 | public $restrictiononfksoc = 1; |
||
94 | |||
95 | /** |
||
96 | * {@inheritdoc} |
||
97 | */ |
||
98 | protected $table_ref_field = 'ref'; |
||
99 | |||
100 | /** |
||
101 | * @var int ID |
||
102 | */ |
||
103 | public $rowid; |
||
104 | |||
105 | /** |
||
106 | * @var string Ref |
||
107 | */ |
||
108 | public $ref; |
||
109 | |||
110 | /** |
||
111 | * @var string Ref supplier |
||
112 | */ |
||
113 | public $ref_supplier; |
||
114 | |||
115 | /** |
||
116 | * @var string Label of invoice |
||
117 | * @deprecated Use $label |
||
118 | */ |
||
119 | public $libelle; |
||
120 | /** |
||
121 | * @var string Label of invoice |
||
122 | */ |
||
123 | public $label; |
||
124 | |||
125 | //Check constants for types |
||
126 | public $type = self::TYPE_STANDARD; |
||
127 | |||
128 | /** |
||
129 | * Supplier invoice status |
||
130 | * @var int |
||
131 | * @deprecated |
||
132 | * @see $status |
||
133 | */ |
||
134 | public $statut; |
||
135 | |||
136 | /** |
||
137 | * Supplier invoice status |
||
138 | * @var int |
||
139 | * @see FactureFournisseur::STATUS_DRAFT, FactureFournisseur::STATUS_VALIDATED, FactureFournisseur::STATUS_PAID, FactureFournisseur::STATUS_ABANDONED |
||
140 | */ |
||
141 | public $status; |
||
142 | |||
143 | /** |
||
144 | * Supplier invoice status |
||
145 | * @var int |
||
146 | * @deprecated |
||
147 | * @see $status |
||
148 | */ |
||
149 | public $fk_statut; |
||
150 | |||
151 | /** |
||
152 | * Set to 1 if the invoice is completely paid, otherwise is 0 |
||
153 | * @var int<0,1> |
||
154 | * @deprecated Use $paid |
||
155 | */ |
||
156 | public $paye; |
||
157 | /** |
||
158 | * Set to 1 if the invoice is completely paid, otherwise is 0 |
||
159 | * @var int<0,1> |
||
160 | */ |
||
161 | public $paid; |
||
162 | |||
163 | /** |
||
164 | * @var int |
||
165 | * @deprecated Use $user_creation_id |
||
166 | */ |
||
167 | public $author; |
||
168 | |||
169 | /** |
||
170 | * Date creation record (datec) |
||
171 | * |
||
172 | * @var integer |
||
173 | */ |
||
174 | public $datec; |
||
175 | |||
176 | /** |
||
177 | * Max payment date (date_echeance) |
||
178 | * |
||
179 | * @var integer |
||
180 | */ |
||
181 | public $date_echeance; |
||
182 | |||
183 | /** |
||
184 | * @var double $amount |
||
185 | * @deprecated See $total_ttc, $total_ht, $total_tva |
||
186 | */ |
||
187 | public $amount = 0; |
||
188 | /** |
||
189 | * @var double $remise |
||
190 | * @deprecated |
||
191 | */ |
||
192 | public $remise = 0; |
||
193 | |||
194 | /** |
||
195 | * @var float tva |
||
196 | * @deprecated Use $total_tva |
||
197 | */ |
||
198 | public $tva; |
||
199 | |||
200 | // Warning: Do not set default value into property definition. it must stay null. |
||
201 | // For example to avoid to have substitution done when object is generic and not yet defined. |
||
202 | /** @var ?string */ |
||
203 | public $localtax1; |
||
204 | /** @var ?string */ |
||
205 | public $localtax2; |
||
206 | /** @var float */ |
||
207 | public $total_ht; |
||
208 | /** @var float */ |
||
209 | public $total_tva; |
||
210 | /** @var float */ |
||
211 | public $total_localtax1; |
||
212 | /** @var float */ |
||
213 | public $total_localtax2; |
||
214 | /** @var float */ |
||
215 | public $total_ttc; |
||
216 | |||
217 | /** |
||
218 | * @deprecated |
||
219 | * @see $note_private, $note_public |
||
220 | * @var string |
||
221 | */ |
||
222 | public $note; |
||
223 | /** @var string */ |
||
224 | public $note_private; |
||
225 | /** @var string */ |
||
226 | public $note_public; |
||
227 | /** @var int */ |
||
228 | public $propalid; |
||
229 | |||
230 | /** |
||
231 | * @var int ID |
||
232 | */ |
||
233 | public $fk_account; // default bank account |
||
234 | |||
235 | /** |
||
236 | * @var int Transport mode id |
||
237 | */ |
||
238 | public $transport_mode_id; |
||
239 | |||
240 | /** |
||
241 | * @var int<0,1> VAT reverse charge can be used on the invoice |
||
242 | */ |
||
243 | public $vat_reverse_charge; |
||
244 | |||
245 | public $extraparams = array(); |
||
246 | |||
247 | /** |
||
248 | * Invoice lines |
||
249 | * @var CommonInvoiceLine[] |
||
250 | */ |
||
251 | public $lines = array(); |
||
252 | |||
253 | /** |
||
254 | * @deprecated |
||
255 | * @var ?Fournisseur |
||
256 | */ |
||
257 | public $fournisseur; |
||
258 | |||
259 | //! id of source invoice if replacement invoice or credit note |
||
260 | /** |
||
261 | * @var int ID |
||
262 | */ |
||
263 | public $fk_facture_source; |
||
264 | |||
265 | /** @var int */ |
||
266 | public $fac_rec; |
||
267 | /** @var int */ |
||
268 | public $fk_fac_rec_source; |
||
269 | |||
270 | public $fields = array( |
||
271 | 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10), |
||
272 | 'ref' => array('type' => 'varchar(255)', 'label' => 'Ref', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'showoncombobox' => 1, 'position' => 15), |
||
273 | 'ref_supplier' => array('type' => 'varchar(255)', 'label' => 'RefSupplier', 'enabled' => 1, 'visible' => -1, 'position' => 20), |
||
274 | 'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => '1', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 25, 'index' => 1), |
||
275 | 'ref_ext' => array('type' => 'varchar(255)', 'label' => 'RefExt', 'enabled' => 1, 'visible' => 0, 'position' => 30), |
||
276 | 'type' => array('type' => 'smallint(6)', 'label' => 'Type', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 35), |
||
277 | 'subtype' => array('type' => 'smallint(6)', 'label' => 'InvoiceSubtype', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 36), |
||
278 | 'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php', 'label' => 'ThirdParty', 'enabled' => 'isModEnabled("societe")', 'visible' => -1, 'notnull' => 1, 'position' => 40), |
||
279 | 'datec' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -1, 'position' => 45), |
||
280 | 'datef' => array('type' => 'date', 'label' => 'Date', 'enabled' => 1, 'visible' => -1, 'position' => 50), |
||
281 | 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 55), |
||
282 | 'libelle' => array('type' => 'varchar(255)', 'label' => 'Label', 'enabled' => 1, 'visible' => -1, 'position' => 60), |
||
283 | 'paye' => array('type' => 'smallint(6)', 'label' => 'Paye', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 65), |
||
284 | 'amount' => array('type' => 'double(24,8)', 'label' => 'Amount', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 70), |
||
285 | 'remise' => array('type' => 'double(24,8)', 'label' => 'Discount', 'enabled' => 1, 'visible' => -1, 'position' => 75), |
||
286 | 'close_code' => array('type' => 'varchar(16)', 'label' => 'CloseCode', 'enabled' => 1, 'visible' => -1, 'position' => 80), |
||
287 | 'close_note' => array('type' => 'varchar(128)', 'label' => 'CloseNote', 'enabled' => 1, 'visible' => -1, 'position' => 85), |
||
288 | 'tva' => array('type' => 'double(24,8)', 'label' => 'Tva', 'enabled' => 1, 'visible' => -1, 'position' => 90), |
||
289 | 'localtax1' => array('type' => 'double(24,8)', 'label' => 'Localtax1', 'enabled' => 1, 'visible' => -1, 'position' => 95), |
||
290 | 'localtax2' => array('type' => 'double(24,8)', 'label' => 'Localtax2', 'enabled' => 1, 'visible' => -1, 'position' => 100), |
||
291 | 'total_ht' => array('type' => 'double(24,8)', 'label' => 'TotalHT', 'enabled' => 1, 'visible' => -1, 'position' => 105), |
||
292 | 'total_tva' => array('type' => 'double(24,8)', 'label' => 'TotalVAT', 'enabled' => 1, 'visible' => -1, 'position' => 110), |
||
293 | 'total_ttc' => array('type' => 'double(24,8)', 'label' => 'TotalTTC', 'enabled' => 1, 'visible' => -1, 'position' => 115), |
||
294 | 'fk_user_author' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserAuthor', 'enabled' => 1, 'visible' => -1, 'position' => 125), |
||
295 | 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 130), |
||
296 | 'fk_user_valid' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserValidation', 'enabled' => 1, 'visible' => -1, 'position' => 135), |
||
297 | 'fk_facture_source' => array('type' => 'integer', 'label' => 'Fk facture source', 'enabled' => 1, 'visible' => -1, 'position' => 140), |
||
298 | 'fk_projet' => array('type' => 'integer:Project:projet/class/project.class.php:1:fk_statut=1', 'label' => 'Project', 'enabled' => "isModEnabled('project')", 'visible' => -1, 'position' => 145), |
||
299 | 'fk_account' => array('type' => 'integer', 'label' => 'Account', 'enabled' => 'isModEnabled("bank")', 'visible' => -1, 'position' => 150), |
||
300 | 'fk_cond_reglement' => array('type' => 'integer', 'label' => 'PaymentTerm', 'enabled' => 1, 'visible' => -1, 'position' => 155), |
||
301 | 'fk_mode_reglement' => array('type' => 'integer', 'label' => 'PaymentMode', 'enabled' => 1, 'visible' => -1, 'position' => 160), |
||
302 | 'date_lim_reglement' => array('type' => 'date', 'label' => 'DateLimReglement', 'enabled' => 1, 'visible' => -1, 'position' => 165), |
||
303 | 'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 170), |
||
304 | 'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 175), |
||
305 | 'model_pdf' => array('type' => 'varchar(255)', 'label' => 'ModelPdf', 'enabled' => 1, 'visible' => 0, 'position' => 180), |
||
306 | 'extraparams' => array('type' => 'varchar(255)', 'label' => 'Extraparams', 'enabled' => 1, 'visible' => -1, 'position' => 190), |
||
307 | 'fk_incoterms' => array('type' => 'integer', 'label' => 'IncotermCode', 'enabled' => 1, 'visible' => -1, 'position' => 195), |
||
308 | 'location_incoterms' => array('type' => 'varchar(255)', 'label' => 'IncotermLocation', 'enabled' => 1, 'visible' => -1, 'position' => 200), |
||
309 | 'fk_multicurrency' => array('type' => 'integer', 'label' => 'MulticurrencyId', 'enabled' => 1, 'visible' => -1, 'position' => 205), |
||
310 | 'multicurrency_code' => array('type' => 'varchar(255)', 'label' => 'MulticurrencyCode', 'enabled' => 1, 'visible' => -1, 'position' => 210), |
||
311 | 'multicurrency_tx' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyRate', 'enabled' => 1, 'visible' => -1, 'position' => 215), |
||
312 | 'multicurrency_total_ht' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyTotalHT', 'enabled' => 1, 'visible' => -1, 'position' => 220), |
||
313 | 'multicurrency_total_tva' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyTotalVAT', 'enabled' => 1, 'visible' => -1, 'position' => 225), |
||
314 | 'multicurrency_total_ttc' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyTotalTTC', 'enabled' => 1, 'visible' => -1, 'position' => 230), |
||
315 | 'date_pointoftax' => array('type' => 'date', 'label' => 'Date pointoftax', 'enabled' => 1, 'visible' => -1, 'position' => 235), |
||
316 | 'date_valid' => array('type' => 'date', 'label' => 'DateValidation', 'enabled' => 1, 'visible' => -1, 'position' => 240), |
||
317 | 'last_main_doc' => array('type' => 'varchar(255)', 'label' => 'Last main doc', 'enabled' => 1, 'visible' => -1, 'position' => 245), |
||
318 | 'fk_statut' => array('type' => 'smallint(6)', 'label' => 'Status', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 500), |
||
319 | 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -2, 'position' => 900), |
||
320 | ); |
||
321 | |||
322 | |||
323 | /** |
||
324 | * Standard invoice |
||
325 | */ |
||
326 | const TYPE_STANDARD = 0; |
||
327 | |||
328 | /** |
||
329 | * Replacement invoice |
||
330 | */ |
||
331 | const TYPE_REPLACEMENT = 1; |
||
332 | |||
333 | /** |
||
334 | * Credit note invoice |
||
335 | */ |
||
336 | const TYPE_CREDIT_NOTE = 2; |
||
337 | |||
338 | /** |
||
339 | * Deposit invoice |
||
340 | */ |
||
341 | const TYPE_DEPOSIT = 3; |
||
342 | |||
343 | /** |
||
344 | * Draft |
||
345 | */ |
||
346 | const STATUS_DRAFT = 0; |
||
347 | |||
348 | /** |
||
349 | * Validated (need to be paid) |
||
350 | */ |
||
351 | const STATUS_VALIDATED = 1; |
||
352 | |||
353 | /** |
||
354 | * Classified paid. |
||
355 | * If paid partially, $this->close_code can be: |
||
356 | * - CLOSECODE_DISCOUNTVAT |
||
357 | * - CLOSECODE_BADCREDIT |
||
358 | * If paid completely, this->close_code will be null |
||
359 | */ |
||
360 | const STATUS_CLOSED = 2; |
||
361 | |||
362 | /** |
||
363 | * Classified abandoned and no payment done. |
||
364 | * $this->close_code can be: |
||
365 | * - CLOSECODE_BADCREDIT |
||
366 | * - CLOSECODE_ABANDONED |
||
367 | * - CLOSECODE_REPLACED |
||
368 | */ |
||
369 | const STATUS_ABANDONED = 3; |
||
370 | |||
371 | const CLOSECODE_DISCOUNTVAT = 'discount_vat'; |
||
372 | const CLOSECODE_BADCREDIT = 'badsupplier'; |
||
373 | const CLOSECODE_ABANDONED = 'abandon'; |
||
374 | const CLOSECODE_REPLACED = 'replaced'; |
||
375 | |||
376 | /** |
||
377 | * Constructor |
||
378 | * |
||
379 | * @param DoliDB $db Database handler |
||
380 | */ |
||
381 | public function __construct($db) |
||
386 | } |
||
387 | |||
388 | /** |
||
389 | * Create supplier invoice into database |
||
390 | * |
||
391 | * @param User $user user object that creates |
||
392 | * @return int Id invoice created if OK, < 0 if KO |
||
393 | */ |
||
394 | public function create($user) |
||
395 | { |
||
396 | global $langs, $conf, $hookmanager; |
||
397 | |||
398 | $error = 0; |
||
399 | $now = dol_now(); |
||
400 | |||
401 | // Clean parameters |
||
402 | if (isset($this->ref_supplier)) { |
||
403 | $this->ref_supplier = trim($this->ref_supplier); |
||
404 | } |
||
405 | if (empty($this->type)) { |
||
406 | $this->type = self::TYPE_STANDARD; |
||
407 | } |
||
408 | if (empty($this->date)) { |
||
409 | $this->date = $now; |
||
410 | } |
||
411 | |||
412 | // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate) |
||
413 | if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) { |
||
414 | list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $this->date); |
||
415 | } else { |
||
416 | $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code); |
||
417 | } |
||
418 | if (empty($this->fk_multicurrency)) { |
||
419 | $this->multicurrency_code = $conf->currency; |
||
420 | $this->fk_multicurrency = 0; |
||
421 | $this->multicurrency_tx = 1; |
||
422 | } |
||
423 | |||
424 | $this->db->begin(); |
||
425 | |||
426 | // Create invoice from a template recurring invoice |
||
427 | if ($this->fac_rec > 0) { |
||
428 | $this->fk_fac_rec_source = $this->fac_rec; |
||
429 | |||
430 | $_facrec = new FactureFournisseurRec($this->db); |
||
431 | $result = $_facrec->fetch($this->fac_rec); |
||
432 | $result = $_facrec->fetchObjectLinked(null, '', null, '', 'OR', 1, 'sourcetype', 0); // This load $_facrec->linkedObjectsIds |
||
433 | |||
434 | // Define some dates |
||
435 | if (!empty($_facrec->frequency)) { |
||
436 | $originaldatewhen = $_facrec->date_when; |
||
437 | $nextdatewhen = dol_time_plus_duree($originaldatewhen, $_facrec->frequency, $_facrec->unit_frequency); |
||
438 | $previousdaynextdatewhen = dol_time_plus_duree($nextdatewhen, -1, 'd'); |
||
439 | $this->socid = $_facrec->socid; |
||
440 | } else { |
||
441 | $originaldatewhen = 0; |
||
442 | $nextdatewhen = 0; |
||
443 | $previousdaynextdatewhen = 0; |
||
444 | } |
||
445 | |||
446 | $this->entity = $_facrec->entity; // Invoice created in same entity than template |
||
447 | |||
448 | // Fields coming from GUI |
||
449 | // @TODO Value of template should be used as default value on the form on the GUI, and we should here always use the value from GUI |
||
450 | // set by posted page with $object->xxx = ... and this section should be removed. |
||
451 | $this->fk_project = GETPOSTINT('projectid') > 0 ? (GETPOSTINT('projectid')) : $_facrec->fk_project; |
||
452 | $this->note_public = GETPOST('note_public', 'restricthtml') ? GETPOST('note_public', 'restricthtml') : $_facrec->note_public; |
||
|
|||
453 | $this->note_private = GETPOST('note_private', 'restricthtml') ? GETPOST('note_private', 'restricthtml') : $_facrec->note_private; |
||
454 | $this->model_pdf = GETPOST('model', 'alpha') ? GETPOST('model', 'alpha') : $_facrec->model_pdf; |
||
455 | $this->cond_reglement_id = GETPOSTINT('cond_reglement_id') > 0 ? (GETPOSTINT('cond_reglement_id')) : $_facrec->cond_reglement_id; |
||
456 | $this->mode_reglement_id = GETPOSTINT('mode_reglement_id') > 0 ? (GETPOSTINT('mode_reglement_id')) : $_facrec->mode_reglement_id; |
||
457 | $this->fk_account = GETPOST('fk_account') > 0 ? ((int) GETPOST('fk_account')) : $_facrec->fk_account; |
||
458 | |||
459 | // Set here to have this defined for substitution into notes, should be recalculated after adding lines to get same result |
||
460 | $this->total_ht = $_facrec->total_ht; |
||
461 | $this->total_ttc = $_facrec->total_ttc; |
||
462 | |||
463 | // Fields always coming from template |
||
464 | $this->fk_incoterms = $_facrec->fk_incoterms; |
||
465 | $this->location_incoterms = $_facrec->location_incoterms; |
||
466 | |||
467 | // Clean parameters |
||
468 | if (! $this->type) { |
||
469 | $this->type = self::TYPE_STANDARD; |
||
470 | } |
||
471 | if (!empty(GETPOST('ref_supplier'))) { |
||
472 | $this->ref_supplier = trim($this->ref_supplier); |
||
473 | } else { |
||
474 | $this->ref_supplier = trim($this->ref_supplier . '_' . ($_facrec->nb_gen_done + 1)); |
||
475 | } |
||
476 | $this->note_public = trim($this->note_public); |
||
477 | $this->note_private = trim($this->note_private); |
||
478 | $this->note_private = dol_concatdesc($this->note_private, $langs->trans("GeneratedFromRecurringInvoice", $_facrec->title)); |
||
479 | |||
480 | $this->array_options = $_facrec->array_options; |
||
481 | |||
482 | if (! $this->mode_reglement_id) { |
||
483 | $this->mode_reglement_id = 0; |
||
484 | } |
||
485 | $this->status = self::STATUS_DRAFT; |
||
486 | $this->statut = self::STATUS_DRAFT; // deprecated |
||
487 | |||
488 | $this->linked_objects = $_facrec->linkedObjectsIds; |
||
489 | // We do not add link to template invoice or next invoice will be linked to all generated invoices |
||
490 | //$this->linked_objects['facturerec'][0] = $this->fac_rec; |
||
491 | |||
492 | $forceduedate = $this->calculate_date_lim_reglement(); |
||
493 | |||
494 | // For recurring invoices, update date and number of last generation of recurring template invoice, before inserting new invoice |
||
495 | if ($_facrec->frequency > 0) { |
||
496 | dol_syslog("This is a recurring invoice so we set date_last_gen and next date_when"); |
||
497 | if (empty($_facrec->date_when)) { |
||
498 | $_facrec->date_when = $now; |
||
499 | } |
||
500 | $next_date = $_facrec->getNextDate(); // Calculate next date |
||
501 | $result = $_facrec->setValueFrom('date_last_gen', $now, '', 0, 'date', '', $user, ''); |
||
502 | //$_facrec->setValueFrom('nb_gen_done', $_facrec->nb_gen_done + 1); // Not required, +1 already included into setNextDate when second param is 1. |
||
503 | $result = $_facrec->setNextDate($next_date, 1); |
||
504 | } |
||
505 | |||
506 | // Define lang of customer |
||
507 | $outputlangs = $langs; |
||
508 | $newlang = ''; |
||
509 | |||
510 | if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && isset($this->thirdparty->default_lang)) { |
||
511 | $newlang = $this->thirdparty->default_lang; // for proposal, order, invoice, ... |
||
512 | } |
||
513 | if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && isset($this->default_lang)) { |
||
514 | $newlang = $this->default_lang; // for thirdparty |
||
515 | } |
||
516 | if (!empty($newlang)) { |
||
517 | $outputlangs = new Translate("", $conf); |
||
518 | $outputlangs->setDefaultLang($newlang); |
||
519 | } // Array of possible substitutions (See also file mailing-send.php that should manage same substitutions) |
||
520 | $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $this); |
||
521 | $substitutionarray['__INVOICE_PREVIOUS_MONTH__'] = dol_print_date(dol_time_plus_duree($this->date, -1, 'm'), '%m'); |
||
522 | $substitutionarray['__INVOICE_MONTH__'] = dol_print_date($this->date, '%m'); |
||
523 | $substitutionarray['__INVOICE_NEXT_MONTH__'] = dol_print_date(dol_time_plus_duree($this->date, 1, 'm'), '%m'); |
||
524 | $substitutionarray['__INVOICE_PREVIOUS_MONTH_TEXT__'] = dol_print_date(dol_time_plus_duree($this->date, -1, 'm'), '%B'); |
||
525 | $substitutionarray['__INVOICE_MONTH_TEXT__'] = dol_print_date($this->date, '%B'); |
||
526 | $substitutionarray['__INVOICE_NEXT_MONTH_TEXT__'] = dol_print_date(dol_time_plus_duree($this->date, 1, 'm'), '%B'); |
||
527 | $substitutionarray['__INVOICE_PREVIOUS_YEAR__'] = dol_print_date(dol_time_plus_duree($this->date, -1, 'y'), '%Y'); |
||
528 | $substitutionarray['__INVOICE_YEAR__'] = dol_print_date($this->date, '%Y'); |
||
529 | $substitutionarray['__INVOICE_NEXT_YEAR__'] = dol_print_date(dol_time_plus_duree($this->date, 1, 'y'), '%Y'); // Only for template invoice |
||
530 | $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_BEFORE_GEN__'] = $originaldatewhen ? dol_print_date($originaldatewhen, 'dayhour') : ''; |
||
531 | $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_AFTER_GEN__'] = $nextdatewhen ? dol_print_date($nextdatewhen, 'dayhour') : ''; |
||
532 | $substitutionarray['__INVOICE_PREVIOUS_DATE_NEXT_INVOICE_AFTER_GEN__'] = $previousdaynextdatewhen ? dol_print_date($previousdaynextdatewhen, 'dayhour') : ''; |
||
533 | $substitutionarray['__INVOICE_COUNTER_CURRENT__'] = $_facrec->nb_gen_done; |
||
534 | $substitutionarray['__INVOICE_COUNTER_MAX__'] = $_facrec->nb_gen_max; |
||
535 | |||
536 | complete_substitutions_array($substitutionarray, $outputlangs); |
||
537 | |||
538 | $this->note_public = make_substitutions($this->note_public, $substitutionarray); |
||
539 | $this->note_private = make_substitutions($this->note_private, $substitutionarray); |
||
540 | } |
||
541 | |||
542 | // Define due date if not already defined |
||
543 | if (!empty($forceduedate)) { |
||
544 | $this->date_echeance = $forceduedate; |
||
545 | } |
||
546 | |||
547 | $sql = "INSERT INTO " . MAIN_DB_PREFIX . "facture_fourn ("; |
||
548 | $sql .= "ref"; |
||
549 | $sql .= ", ref_supplier"; |
||
550 | $sql .= ", ref_ext"; |
||
551 | $sql .= ", entity"; |
||
552 | $sql .= ", type"; |
||
553 | $sql .= ", subtype"; |
||
554 | $sql .= ", libelle"; |
||
555 | $sql .= ", fk_soc"; |
||
556 | $sql .= ", datec"; |
||
557 | $sql .= ", datef"; |
||
558 | $sql .= ", vat_reverse_charge"; |
||
559 | $sql .= ", fk_projet"; |
||
560 | $sql .= ", fk_cond_reglement"; |
||
561 | $sql .= ", fk_mode_reglement"; |
||
562 | $sql .= ", fk_account"; |
||
563 | $sql .= ", note_private"; |
||
564 | $sql .= ", note_public"; |
||
565 | $sql .= ", fk_user_author"; |
||
566 | $sql .= ", date_lim_reglement"; |
||
567 | $sql .= ", fk_incoterms, location_incoterms"; |
||
568 | $sql .= ", fk_multicurrency"; |
||
569 | $sql .= ", multicurrency_code"; |
||
570 | $sql .= ", multicurrency_tx"; |
||
571 | $sql .= ", fk_facture_source"; |
||
572 | $sql .= ", fk_fac_rec_source"; |
||
573 | $sql .= ")"; |
||
574 | $sql .= " VALUES ("; |
||
575 | $sql .= "'(PROV)'"; |
||
576 | $sql .= ", '" . $this->db->escape($this->ref_supplier) . "'"; |
||
577 | $sql .= ", '" . $this->db->escape($this->ref_ext) . "'"; |
||
578 | $sql .= ", " . ((int) $conf->entity); |
||
579 | $sql .= ", '" . $this->db->escape($this->type) . "'"; |
||
580 | $sql .= ", " . ((int) $this->subtype); |
||
581 | $sql .= ", '" . $this->db->escape(isset($this->label) ? $this->label : (isset($this->libelle) ? $this->libelle : '')) . "'"; |
||
582 | $sql .= ", " . ((int) $this->socid); |
||
583 | $sql .= ", '" . $this->db->idate($now) . "'"; |
||
584 | $sql .= ", '" . $this->db->idate($this->date) . "'"; |
||
585 | $sql .= ", " . ($this->vat_reverse_charge != '' ? ((int) $this->db->escape($this->vat_reverse_charge)) : 0); |
||
586 | $sql .= ", " . ($this->fk_project > 0 ? ((int) $this->fk_project) : "null"); |
||
587 | $sql .= ", " . ($this->cond_reglement_id > 0 ? ((int) $this->cond_reglement_id) : "null"); |
||
588 | $sql .= ", " . ($this->mode_reglement_id > 0 ? ((int) $this->mode_reglement_id) : "null"); |
||
589 | $sql .= ", " . ($this->fk_account > 0 ? ((int) $this->fk_account) : 'NULL'); |
||
590 | $sql .= ", '" . $this->db->escape($this->note_private) . "'"; |
||
591 | $sql .= ", '" . $this->db->escape($this->note_public) . "'"; |
||
592 | $sql .= ", " . ((int) $user->id) . ","; |
||
593 | $sql .= $this->date_echeance != '' ? "'" . $this->db->idate($this->date_echeance) . "'" : "null"; |
||
594 | $sql .= ", " . (int) $this->fk_incoterms; |
||
595 | $sql .= ", '" . $this->db->escape($this->location_incoterms) . "'"; |
||
596 | $sql .= ", " . (int) $this->fk_multicurrency; |
||
597 | $sql .= ", '" . $this->db->escape($this->multicurrency_code) . "'"; |
||
598 | $sql .= ", " . (float) $this->multicurrency_tx; |
||
599 | $sql .= ", " . ($this->fk_facture_source ? ((int) $this->fk_facture_source) : "null"); |
||
600 | $sql .= ", " . (isset($this->fk_fac_rec_source) ? $this->fk_fac_rec_source : "NULL"); |
||
601 | $sql .= ")"; |
||
602 | |||
603 | dol_syslog(get_only_class($this) . "::create", LOG_DEBUG); |
||
604 | $resql = $this->db->query($sql); |
||
605 | if ($resql) { |
||
606 | $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . 'facture_fourn'); |
||
607 | |||
608 | // Update ref with new one |
||
609 | $this->ref = '(PROV' . $this->id . ')'; |
||
610 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . "facture_fourn SET ref='" . $this->db->escape($this->ref) . "' WHERE rowid=" . ((int) $this->id); |
||
611 | |||
612 | dol_syslog(get_only_class($this) . "::create", LOG_DEBUG); |
||
613 | $resql = $this->db->query($sql); |
||
614 | if (!$resql) { |
||
615 | $error++; |
||
616 | } |
||
617 | |||
618 | if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) { // To use new linkedObjectsIds instead of old linked_objects |
||
619 | $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds |
||
620 | } |
||
621 | |||
622 | // Add object linked |
||
623 | if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects)) { |
||
624 | foreach ($this->linked_objects as $origin => $tmp_origin_id) { |
||
625 | if (is_array($tmp_origin_id)) { // New behaviour, if linked_object can have several links per type, so is something like array('contract'=>array(id1, id2, ...)) |
||
626 | foreach ($tmp_origin_id as $origin_id) { |
||
627 | $ret = $this->add_object_linked($origin, $origin_id); |
||
628 | if (!$ret) { |
||
629 | dol_print_error($this->db); |
||
630 | $error++; |
||
631 | } |
||
632 | } |
||
633 | } else { // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1)) |
||
634 | $origin_id = $tmp_origin_id; |
||
635 | $ret = $this->add_object_linked($origin, $origin_id); |
||
636 | if (!$ret) { |
||
637 | dol_print_error($this->db); |
||
638 | $error++; |
||
639 | } |
||
640 | } |
||
641 | } |
||
642 | } |
||
643 | |||
644 | if (!$error && empty($this->fac_rec) && count($this->lines) && is_object($this->lines[0])) { // If this->lines is array of InvoiceLines (preferred mode) |
||
645 | dol_syslog("There is " . count($this->lines) . " lines that are invoice lines objects"); |
||
646 | foreach ($this->lines as $i => $val) { |
||
647 | $sql = 'INSERT INTO ' . MAIN_DB_PREFIX . 'facture_fourn_det (fk_facture_fourn, special_code, fk_remise_except)'; |
||
648 | $sql .= " VALUES (" . ((int) $this->id) . ", " . ((int) $this->lines[$i]->special_code) . ", " . ($this->lines[$i]->fk_remise_except > 0 ? ((int) $this->lines[$i]->fk_remise_except) : 'NULL') . ')'; |
||
649 | |||
650 | $resql_insert = $this->db->query($sql); |
||
651 | if ($resql_insert) { |
||
652 | $idligne = $this->db->last_insert_id(MAIN_DB_PREFIX . 'facture_fourn_det'); |
||
653 | |||
654 | $res = $this->updateline( |
||
655 | $idligne, |
||
656 | $this->lines[$i]->desc ? $this->lines[$i]->desc : $this->lines[$i]->description, |
||
657 | $this->lines[$i]->subprice, |
||
658 | $this->lines[$i]->tva_tx . ($this->lines[$i]->vat_src_code ? ' (' . $this->lines[$i]->vat_src_code . ')' : ''), |
||
659 | $this->lines[$i]->localtax1_tx, |
||
660 | $this->lines[$i]->localtax2_tx, |
||
661 | $this->lines[$i]->qty, |
||
662 | $this->lines[$i]->fk_product, |
||
663 | 'HT', |
||
664 | (!empty($this->lines[$i]->info_bits) ? $this->lines[$i]->info_bits : ''), |
||
665 | $this->lines[$i]->product_type, |
||
666 | $this->lines[$i]->remise_percent, |
||
667 | false, |
||
668 | $this->lines[$i]->date_start, |
||
669 | $this->lines[$i]->date_end, |
||
670 | $this->lines[$i]->array_options, |
||
671 | $this->lines[$i]->fk_unit, |
||
672 | $this->lines[$i]->multicurrency_subprice, |
||
673 | $this->lines[$i]->ref_supplier |
||
674 | ); |
||
675 | } else { |
||
676 | $this->error = $this->db->lasterror(); |
||
677 | $this->db->rollback(); |
||
678 | return -5; |
||
679 | } |
||
680 | } |
||
681 | } elseif (!$error && empty($this->fac_rec)) { // If this->lines is an array of invoice line arrays |
||
682 | dol_syslog("There is " . count($this->lines) . " lines that are array lines"); |
||
683 | foreach ($this->lines as $i => $val) { |
||
684 | $line = $this->lines[$i]; |
||
685 | |||
686 | // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array |
||
687 | //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object. |
||
688 | if (!is_object($line)) { |
||
689 | $line = (object) $line; |
||
690 | } |
||
691 | |||
692 | $sql = 'INSERT INTO ' . MAIN_DB_PREFIX . 'facture_fourn_det (fk_facture_fourn, special_code, fk_remise_except)'; |
||
693 | $sql .= " VALUES (" . ((int) $this->id) . ", " . ((int) $this->lines[$i]->special_code) . ", " . ($this->lines[$i]->fk_remise_except > 0 ? ((int) $this->lines[$i]->fk_remise_except) : 'NULL') . ')'; |
||
694 | |||
695 | $resql_insert = $this->db->query($sql); |
||
696 | if ($resql_insert) { |
||
697 | $idligne = $this->db->last_insert_id(MAIN_DB_PREFIX . 'facture_fourn_det'); |
||
698 | |||
699 | $this->updateline( |
||
700 | $idligne, |
||
701 | $line->desc ? $line->desc : $line->description, |
||
702 | $line->subprice, |
||
703 | $line->tva_tx, |
||
704 | $line->localtax1_tx, |
||
705 | $line->localtax2_tx, |
||
706 | $line->qty, |
||
707 | $line->fk_product, |
||
708 | 'HT', |
||
709 | (!empty($line->info_bits) ? $line->info_bits : ''), |
||
710 | $line->product_type, |
||
711 | $line->remise_percent, |
||
712 | 0, |
||
713 | $line->date_start, |
||
714 | $line->date_end, |
||
715 | $line->array_options, |
||
716 | $line->fk_unit, |
||
717 | $line->multicurrency_subprice, |
||
718 | $line->ref_supplier |
||
719 | ); |
||
720 | } else { |
||
721 | $this->error = $this->db->lasterror(); |
||
722 | $this->db->rollback(); |
||
723 | return -5; |
||
724 | } |
||
725 | } |
||
726 | } |
||
727 | |||
728 | /* |
||
729 | * Insert lines of template invoices |
||
730 | */ |
||
731 | if (! $error && $this->fac_rec > 0 && $_facrec instanceof FactureFournisseurRec) { |
||
732 | foreach ($_facrec->lines as $i => $val) { |
||
733 | if ($_facrec->lines[$i]->fk_product) { |
||
734 | $prod = new Product($this->db); |
||
735 | $res = $prod->fetch($_facrec->lines[$i]->fk_product); |
||
736 | } |
||
737 | |||
738 | // For line from template invoice, we use data from template invoice |
||
739 | /* |
||
740 | $tva_tx = get_default_tva($mysoc,$soc,$prod->id); |
||
741 | $tva_npr = get_default_npr($mysoc,$soc,$prod->id); |
||
742 | if (empty($tva_tx)) $tva_npr=0; |
||
743 | $localtax1_tx=get_localtax($tva_tx,1,$soc,$mysoc,$tva_npr); |
||
744 | $localtax2_tx=get_localtax($tva_tx,2,$soc,$mysoc,$tva_npr); |
||
745 | */ |
||
746 | $tva_tx = $_facrec->lines[$i]->tva_tx . ($_facrec->lines[$i]->vat_src_code ? '(' . $_facrec->lines[$i]->vat_src_code . ')' : ''); |
||
747 | $tva_npr = $_facrec->lines[$i]->info_bits; |
||
748 | if (empty($tva_tx)) { |
||
749 | $tva_npr = 0; |
||
750 | } |
||
751 | $localtax1_tx = $_facrec->lines[$i]->localtax1_tx; |
||
752 | $localtax2_tx = $_facrec->lines[$i]->localtax2_tx; |
||
753 | |||
754 | $fk_product_fournisseur_price = empty($_facrec->lines[$i]->fk_product_fournisseur_price) ? null : $_facrec->lines[$i]->fk_product_fournisseur_price; |
||
755 | $buyprice = empty($_facrec->lines[$i]->buyprice) ? 0 : $_facrec->lines[$i]->buyprice; |
||
756 | |||
757 | // If buyprice not defined from template invoice, we try to guess the best value |
||
758 | if (! $buyprice && $_facrec->lines[$i]->fk_product > 0) { |
||
759 | $producttmp = new ProductFournisseur($this->db); |
||
760 | $producttmp->fetch($_facrec->lines[$i]->fk_product); |
||
761 | |||
762 | // If margin module defined on costprice, we try the costprice |
||
763 | // If not defined or if module margin defined and pmp and stock module enabled, we try pmp price |
||
764 | // else we get the best supplier price |
||
765 | if (getDolGlobalString('MARGIN_TYPE') == 'costprice' && !empty($producttmp->cost_price)) { |
||
766 | $buyprice = $producttmp->cost_price; |
||
767 | } elseif (isModEnabled('stock') && (getDolGlobalString('MARGIN_TYPE') == 'costprice' || getDolGlobalString('MARGIN_TYPE') == 'pmp') && !empty($producttmp->pmp)) { |
||
768 | $buyprice = $producttmp->pmp; |
||
769 | } else { |
||
770 | if ($producttmp->find_min_price_product_fournisseur($_facrec->lines[$i]->fk_product) > 0) { |
||
771 | if ($producttmp->product_fourn_price_id > 0) { |
||
772 | $buyprice = price2num($producttmp->fourn_unitprice * (1 - $producttmp->fourn_remise_percent / 100) + $producttmp->fourn_remise, 'MU'); |
||
773 | } |
||
774 | } |
||
775 | } |
||
776 | } |
||
777 | |||
778 | $result_insert = $this->addline( |
||
779 | $_facrec->lines[$i]->desc ? $_facrec->lines[$i]->desc : $_facrec->lines[$i]->description, |
||
780 | $_facrec->lines[$i]->pu_ht, |
||
781 | $tva_tx, |
||
782 | $localtax1_tx, |
||
783 | $localtax2_tx, |
||
784 | $_facrec->lines[$i]->qty, |
||
785 | $_facrec->lines[$i]->fk_product, |
||
786 | $_facrec->lines[$i]->remise_percent, |
||
787 | ($_facrec->lines[$i]->date_start == 1 && $this->date) ? $this->date : '', |
||
788 | ($_facrec->lines[$i]->date_end == 1 && $previousdaynextdatewhen) ? $previousdaynextdatewhen : '', |
||
789 | 0, |
||
790 | $_facrec->lines[$i]->info_bits, |
||
791 | 'HT', |
||
792 | 0, |
||
793 | $_facrec->lines[$i]->rang, |
||
794 | false, |
||
795 | $_facrec->lines[$i]->array_options, |
||
796 | $_facrec->lines[$i]->fk_unit, |
||
797 | 0, |
||
798 | 0, |
||
799 | $_facrec->lines[$i]->ref_supplier, |
||
800 | $_facrec->lines[$i]->special_code, |
||
801 | 0, |
||
802 | 0 |
||
803 | ); |
||
804 | if ($result_insert < 0) { |
||
805 | $error++; |
||
806 | $this->error = $this->db->error(); |
||
807 | break; |
||
808 | } |
||
809 | } |
||
810 | } |
||
811 | |||
812 | |||
813 | // Update total price |
||
814 | $result = $this->update_price(1); |
||
815 | if ($result > 0) { |
||
816 | // Actions on extra fields |
||
817 | if (!$error) { |
||
818 | $result = $this->insertExtraFields(); // This also set $this->error or $this->errors if errors are found |
||
819 | if ($result < 0) { |
||
820 | $error++; |
||
821 | } |
||
822 | } |
||
823 | |||
824 | if (!$error) { |
||
825 | // Call trigger |
||
826 | $result = $this->call_trigger('BILL_SUPPLIER_CREATE', $user); |
||
827 | if ($result < 0) { |
||
828 | $error++; |
||
829 | } |
||
830 | // End call triggers |
||
831 | } |
||
832 | |||
833 | if (!$error) { |
||
834 | $this->db->commit(); |
||
835 | return $this->id; |
||
836 | } else { |
||
837 | $this->db->rollback(); |
||
838 | return -4; |
||
839 | } |
||
840 | } else { |
||
841 | $this->error = $langs->trans('FailedToUpdatePrice'); |
||
842 | $this->db->rollback(); |
||
843 | return -3; |
||
844 | } |
||
845 | } else { |
||
846 | if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') { |
||
847 | $this->error = $langs->trans('ErrorRefAlreadyExists'); |
||
848 | $this->db->rollback(); |
||
849 | return -1; |
||
850 | } else { |
||
851 | $this->error = $this->db->lasterror(); |
||
852 | $this->db->rollback(); |
||
853 | return -2; |
||
854 | } |
||
855 | } |
||
856 | } |
||
857 | |||
858 | /** |
||
859 | * Load object in memory from database |
||
860 | * |
||
861 | * @param int $id Id supplier invoice |
||
862 | * @param string $ref Ref supplier invoice |
||
863 | * @param string $ref_ext External reference of invoice |
||
864 | * @return int Return integer <0 if KO, >0 if OK, 0 if not found |
||
865 | */ |
||
866 | public function fetch($id = 0, $ref = '', $ref_ext = '') |
||
867 | { |
||
868 | if (empty($id) && empty($ref) && empty($ref_ext)) { |
||
869 | return -1; |
||
870 | } |
||
871 | |||
872 | $sql = "SELECT"; |
||
873 | $sql .= " t.rowid,"; |
||
874 | $sql .= " t.ref,"; |
||
875 | $sql .= " t.ref_supplier,"; |
||
876 | $sql .= " t.ref_ext,"; |
||
877 | $sql .= " t.entity,"; |
||
878 | $sql .= " t.type,"; |
||
879 | $sql .= " t.subtype,"; |
||
880 | $sql .= " t.fk_soc,"; |
||
881 | $sql .= " t.datec,"; |
||
882 | $sql .= " t.datef,"; |
||
883 | $sql .= " t.tms,"; |
||
884 | $sql .= " t.libelle as label,"; |
||
885 | $sql .= " t.paye,"; |
||
886 | $sql .= " t.close_code,"; |
||
887 | $sql .= " t.close_note,"; |
||
888 | $sql .= " t.tva,"; |
||
889 | $sql .= " t.localtax1,"; |
||
890 | $sql .= " t.localtax2,"; |
||
891 | $sql .= " t.total_ht,"; |
||
892 | $sql .= " t.total_tva,"; |
||
893 | $sql .= " t.total_ttc,"; |
||
894 | $sql .= " t.fk_statut as status,"; |
||
895 | $sql .= " t.fk_user_author,"; |
||
896 | $sql .= " t.fk_user_valid,"; |
||
897 | $sql .= " t.fk_facture_source,"; |
||
898 | $sql .= " t.vat_reverse_charge,"; |
||
899 | $sql .= " t.fk_fac_rec_source,"; |
||
900 | $sql .= " t.fk_projet as fk_project,"; |
||
901 | $sql .= " t.fk_cond_reglement,"; |
||
902 | $sql .= " t.fk_account,"; |
||
903 | $sql .= " t.fk_mode_reglement,"; |
||
904 | $sql .= " t.date_lim_reglement,"; |
||
905 | $sql .= " t.note_private,"; |
||
906 | $sql .= " t.note_public,"; |
||
907 | $sql .= " t.model_pdf,"; |
||
908 | $sql .= " t.last_main_doc,"; |
||
909 | $sql .= " t.import_key,"; |
||
910 | $sql .= " t.extraparams,"; |
||
911 | $sql .= " cr.code as cond_reglement_code, cr.libelle as cond_reglement_label, cr.libelle_facture as cond_reglement_doc,"; |
||
912 | $sql .= " p.code as mode_reglement_code, p.libelle as mode_reglement_label,"; |
||
913 | $sql .= ' s.nom as socnom, s.rowid as socid,'; |
||
914 | $sql .= ' t.fk_incoterms, t.location_incoterms,'; |
||
915 | $sql .= " i.libelle as label_incoterms,"; |
||
916 | $sql .= ' t.fk_transport_mode,'; |
||
917 | $sql .= ' t.fk_multicurrency, t.multicurrency_code, t.multicurrency_tx, t.multicurrency_total_ht, t.multicurrency_total_tva, t.multicurrency_total_ttc'; |
||
918 | $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_fourn as t'; |
||
919 | $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s ON (t.fk_soc = s.rowid)"; |
||
920 | $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_payment_term as cr ON t.fk_cond_reglement = cr.rowid"; |
||
921 | $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_paiement as p ON t.fk_mode_reglement = p.id"; |
||
922 | $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_incoterms as i ON t.fk_incoterms = i.rowid'; |
||
923 | if ($id) { |
||
924 | $sql .= " WHERE t.rowid = " . ((int) $id); |
||
925 | } else { |
||
926 | $sql .= ' WHERE t.entity IN (' . getEntity('supplier_invoice') . ')'; // Don't use entity if you use rowid |
||
927 | if ($ref) { |
||
928 | $sql .= " AND t.ref = '" . $this->db->escape($ref) . "'"; |
||
929 | } |
||
930 | if ($ref_ext) { |
||
931 | $sql .= " AND t.ref_ext = '" . $this->db->escape($ref_ext) . "'"; |
||
932 | } |
||
933 | } |
||
934 | |||
935 | dol_syslog(get_only_class($this) . "::fetch", LOG_DEBUG); |
||
936 | $resql = $this->db->query($sql); |
||
937 | if ($resql) { |
||
938 | if ($this->db->num_rows($resql)) { |
||
939 | $obj = $this->db->fetch_object($resql); |
||
940 | |||
941 | $this->id = $obj->rowid; |
||
942 | $this->ref = $obj->ref ? $obj->ref : $obj->rowid; // We take rowid if ref is empty for backward compatibility |
||
943 | |||
944 | $this->ref_supplier = $obj->ref_supplier; |
||
945 | $this->ref_ext = $obj->ref_ext; |
||
946 | $this->entity = $obj->entity; |
||
947 | $this->type = empty($obj->type) ? self::TYPE_STANDARD : $obj->type; |
||
948 | $this->subtype = (int) $obj->subtype; |
||
949 | $this->socid = $obj->fk_soc; |
||
950 | $this->datec = $this->db->jdate($obj->datec); |
||
951 | $this->date = $this->db->jdate($obj->datef); |
||
952 | //$this->datep = $this->db->jdate($obj->datef); |
||
953 | $this->tms = $this->db->jdate($obj->tms); |
||
954 | $this->libelle = $obj->label; // deprecated |
||
955 | $this->label = $obj->label; |
||
956 | $this->paye = $obj->paye; |
||
957 | $this->paid = $obj->paye; |
||
958 | $this->close_code = $obj->close_code; |
||
959 | $this->close_note = $obj->close_note; |
||
960 | $this->total_localtax1 = $obj->localtax1; |
||
961 | $this->total_localtax2 = $obj->localtax2; |
||
962 | $this->total_ht = $obj->total_ht; |
||
963 | $this->total_tva = $obj->total_tva; |
||
964 | $this->total_ttc = $obj->total_ttc; |
||
965 | $this->status = $obj->status; |
||
966 | $this->statut = $obj->status; // For backward compatibility |
||
967 | $this->fk_statut = $obj->status; // For backward compatibility |
||
968 | $this->user_creation_id = $obj->fk_user_author; |
||
969 | $this->author = $obj->fk_user_author; // deprecated |
||
970 | $this->user_validation_id = $obj->fk_user_valid; |
||
971 | $this->fk_facture_source = $obj->fk_facture_source; |
||
972 | $this->vat_reverse_charge = empty($obj->vat_reverse_charge) ? 0 : 1; |
||
973 | $this->fk_fac_rec_source = $obj->fk_fac_rec_source; |
||
974 | $this->fk_project = $obj->fk_project; |
||
975 | $this->cond_reglement_id = $obj->fk_cond_reglement; |
||
976 | $this->cond_reglement_code = $obj->cond_reglement_code; |
||
977 | $this->cond_reglement = $obj->cond_reglement_label; // deprecated |
||
978 | $this->cond_reglement_label = $obj->cond_reglement_label; |
||
979 | $this->cond_reglement_doc = $obj->cond_reglement_doc; |
||
980 | $this->fk_account = $obj->fk_account; |
||
981 | $this->mode_reglement_id = $obj->fk_mode_reglement; |
||
982 | $this->mode_reglement_code = $obj->mode_reglement_code; |
||
983 | $this->mode_reglement = $obj->mode_reglement_label; |
||
984 | $this->date_echeance = $this->db->jdate($obj->date_lim_reglement); |
||
985 | $this->note = $obj->note_private; // deprecated |
||
986 | $this->note_private = $obj->note_private; |
||
987 | $this->note_public = $obj->note_public; |
||
988 | $this->model_pdf = $obj->model_pdf; |
||
989 | $this->last_main_doc = $obj->last_main_doc; |
||
990 | $this->import_key = $obj->import_key; |
||
991 | |||
992 | //Incoterms |
||
993 | $this->fk_incoterms = $obj->fk_incoterms; |
||
994 | $this->location_incoterms = $obj->location_incoterms; |
||
995 | $this->label_incoterms = $obj->label_incoterms; |
||
996 | $this->transport_mode_id = $obj->fk_transport_mode; |
||
997 | |||
998 | // Multicurrency |
||
999 | $this->fk_multicurrency = $obj->fk_multicurrency; |
||
1000 | $this->multicurrency_code = $obj->multicurrency_code; |
||
1001 | $this->multicurrency_tx = $obj->multicurrency_tx; |
||
1002 | $this->multicurrency_total_ht = $obj->multicurrency_total_ht; |
||
1003 | $this->multicurrency_total_tva = $obj->multicurrency_total_tva; |
||
1004 | $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc; |
||
1005 | |||
1006 | $this->extraparams = isset($obj->extraparams) ? (array) json_decode($obj->extraparams, true) : array(); |
||
1007 | |||
1008 | $this->socid = $obj->socid; |
||
1009 | |||
1010 | // Retrieve all extrafield |
||
1011 | // fetch optionals attributes and labels |
||
1012 | $this->fetch_optionals(); |
||
1013 | |||
1014 | $result = $this->fetch_lines(); |
||
1015 | if ($result < 0) { |
||
1016 | $this->error = $this->db->lasterror(); |
||
1017 | return -3; |
||
1018 | } |
||
1019 | } else { |
||
1020 | $this->error = 'Bill with id ' . $id . ' not found'; |
||
1021 | dol_syslog(get_only_class($this) . '::fetch ' . $this->error); |
||
1022 | return 0; |
||
1023 | } |
||
1024 | |||
1025 | $this->db->free($resql); |
||
1026 | return 1; |
||
1027 | } else { |
||
1028 | $this->error = "Error " . $this->db->lasterror(); |
||
1029 | return -1; |
||
1030 | } |
||
1031 | } |
||
1032 | |||
1033 | |||
1034 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps |
||
1035 | /** |
||
1036 | * Load this->lines |
||
1037 | * |
||
1038 | * @return int 1 si ok, < 0 si erreur |
||
1039 | */ |
||
1040 | public function fetch_lines() |
||
1041 | { |
||
1042 | // phpcs:enable |
||
1043 | $this->lines = array(); |
||
1044 | |||
1045 | $sql = 'SELECT f.rowid, f.ref as ref_supplier, f.description as line_desc, f.date_start, f.date_end, f.pu_ht, f.pu_ttc, f.qty, f.remise_percent, f.vat_src_code, f.tva_tx'; |
||
1046 | $sql .= ', f.localtax1_tx, f.localtax2_tx, f.localtax1_type, f.localtax2_type, f.total_localtax1, f.total_localtax2, f.fk_facture_fourn, f.fk_remise_except'; |
||
1047 | $sql .= ', f.total_ht, f.tva as total_tva, f.total_ttc, f.fk_product, f.product_type, f.info_bits, f.rang, f.special_code, f.fk_parent_line, f.fk_unit'; |
||
1048 | $sql .= ', p.rowid as product_id, p.ref as product_ref, p.label as label, p.barcode as product_barcode, p.description as product_desc'; |
||
1049 | $sql .= ', f.fk_code_ventilation, f.fk_multicurrency, f.multicurrency_code, f.multicurrency_subprice, f.multicurrency_total_ht, f.multicurrency_total_tva, f.multicurrency_total_ttc'; |
||
1050 | $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_fourn_det as f'; |
||
1051 | $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'product as p ON f.fk_product = p.rowid'; |
||
1052 | $sql .= ' WHERE fk_facture_fourn=' . ((int) $this->id); |
||
1053 | $sql .= ' ORDER BY f.rang, f.rowid'; |
||
1054 | |||
1055 | dol_syslog(get_only_class($this) . "::fetch_lines", LOG_DEBUG); |
||
1056 | |||
1057 | $resql_rows = $this->db->query($sql); |
||
1058 | if ($resql_rows) { |
||
1059 | $num_rows = $this->db->num_rows($resql_rows); |
||
1060 | if ($num_rows) { |
||
1061 | $i = 0; |
||
1062 | while ($i < $num_rows) { |
||
1063 | $obj = $this->db->fetch_object($resql_rows); |
||
1064 | |||
1065 | $line = new SupplierInvoiceLine($this->db); |
||
1066 | |||
1067 | $line->id = $obj->rowid; |
||
1068 | $line->rowid = $obj->rowid; |
||
1069 | $line->description = $obj->line_desc; |
||
1070 | $line->desc = $obj->line_desc; |
||
1071 | $line->date_start = $obj->date_start; |
||
1072 | $line->date_end = $obj->date_end; |
||
1073 | $line->product_ref = $obj->product_ref; |
||
1074 | $line->ref = $obj->product_ref; |
||
1075 | $line->ref_supplier = $obj->ref_supplier; |
||
1076 | $line->libelle = $obj->label; |
||
1077 | $line->label = $obj->label; |
||
1078 | $line->product_barcode = $obj->product_barcode; |
||
1079 | $line->product_desc = $obj->product_desc; |
||
1080 | $line->subprice = $obj->pu_ht; |
||
1081 | $line->pu_ht = $obj->pu_ht; |
||
1082 | $line->pu_ttc = $obj->pu_ttc; |
||
1083 | $line->vat_src_code = $obj->vat_src_code; |
||
1084 | $line->tva_tx = $obj->tva_tx; |
||
1085 | $line->localtax1_tx = $obj->localtax1_tx; |
||
1086 | $line->localtax2_tx = $obj->localtax2_tx; |
||
1087 | $line->localtax1_type = $obj->localtax1_type; |
||
1088 | $line->localtax2_type = $obj->localtax2_type; |
||
1089 | $line->qty = $obj->qty; |
||
1090 | $line->remise_percent = $obj->remise_percent; |
||
1091 | $line->fk_remise_except = $obj->fk_remise_except; |
||
1092 | //$line->tva = $obj->total_tva; // deprecated |
||
1093 | $line->total_ht = $obj->total_ht; |
||
1094 | $line->total_ttc = $obj->total_ttc; |
||
1095 | $line->total_tva = $obj->total_tva; |
||
1096 | $line->total_localtax1 = $obj->total_localtax1; |
||
1097 | $line->total_localtax2 = $obj->total_localtax2; |
||
1098 | $line->fk_facture_fourn = $obj->fk_facture_fourn; |
||
1099 | $line->fk_product = $obj->fk_product; |
||
1100 | $line->product_type = $obj->product_type; |
||
1101 | $line->product_label = $obj->label; |
||
1102 | $line->info_bits = $obj->info_bits; |
||
1103 | $line->fk_parent_line = $obj->fk_parent_line; |
||
1104 | $line->special_code = $obj->special_code; |
||
1105 | $line->rang = $obj->rang; |
||
1106 | $line->fk_unit = $obj->fk_unit; |
||
1107 | |||
1108 | // Accountancy |
||
1109 | $line->fk_accounting_account = $obj->fk_code_ventilation; |
||
1110 | |||
1111 | // Multicurrency |
||
1112 | $line->fk_multicurrency = $obj->fk_multicurrency; |
||
1113 | $line->multicurrency_code = $obj->multicurrency_code; |
||
1114 | $line->multicurrency_subprice = $obj->multicurrency_subprice; |
||
1115 | $line->multicurrency_total_ht = $obj->multicurrency_total_ht; |
||
1116 | $line->multicurrency_total_tva = $obj->multicurrency_total_tva; |
||
1117 | $line->multicurrency_total_ttc = $obj->multicurrency_total_ttc; |
||
1118 | |||
1119 | // Extra fields |
||
1120 | $line->fetch_optionals(); |
||
1121 | |||
1122 | $this->lines[$i] = $line; |
||
1123 | |||
1124 | $i++; |
||
1125 | } |
||
1126 | } |
||
1127 | $this->db->free($resql_rows); |
||
1128 | return 1; |
||
1129 | } else { |
||
1130 | $this->error = $this->db->error(); |
||
1131 | dol_syslog(get_only_class($this) . "::fetch_lines - No lines:{$this->error} Error:{$this->error}", LOG_DEBUG); |
||
1132 | return -3; |
||
1133 | } |
||
1134 | } |
||
1135 | |||
1136 | |||
1137 | /** |
||
1138 | * Update database |
||
1139 | * |
||
1140 | * @param User $user User that modify |
||
1141 | * @param int $notrigger 0=launch triggers after, 1=disable triggers |
||
1142 | * @return int Return integer <0 if KO, >0 if OK |
||
1143 | */ |
||
1144 | public function update($user = null, $notrigger = 0) |
||
1145 | { |
||
1146 | global $langs; |
||
1147 | $error = 0; |
||
1148 | |||
1149 | // Clean parameters |
||
1150 | if (empty($this->type)) { |
||
1151 | $this->type = self::TYPE_STANDARD; |
||
1152 | } |
||
1153 | if (isset($this->ref)) { |
||
1154 | $this->ref = trim($this->ref); |
||
1155 | } |
||
1156 | if (isset($this->ref_supplier)) { |
||
1157 | $this->ref_supplier = trim($this->ref_supplier); |
||
1158 | } |
||
1159 | if (isset($this->ref_ext)) { |
||
1160 | $this->ref_ext = trim($this->ref_ext); |
||
1161 | } |
||
1162 | if (isset($this->entity)) { |
||
1163 | $this->entity = (int) $this->entity; |
||
1164 | } |
||
1165 | if (isset($this->type)) { |
||
1166 | $this->type = (int) $this->type; |
||
1167 | } |
||
1168 | if (isset($this->subtype)) { |
||
1169 | $this->subtype = (int) $this->subtype; |
||
1170 | } |
||
1171 | if (isset($this->socid)) { |
||
1172 | $this->socid = (int) $this->socid; |
||
1173 | } |
||
1174 | if (isset($this->label)) { |
||
1175 | $this->label = trim($this->label); |
||
1176 | } |
||
1177 | if (isset($this->paid)) { |
||
1178 | $this->paid = (int) (bool) $this->paye; |
||
1179 | $this->paye = $this->paid; |
||
1180 | } elseif (isset($this->paye)) { |
||
1181 | $this->paid = (int) (bool) $this->paye; |
||
1182 | $this->paye = $this->paid; |
||
1183 | } |
||
1184 | if (isset($this->close_code)) { |
||
1185 | $this->close_code = trim($this->close_code); |
||
1186 | } |
||
1187 | if (isset($this->close_note)) { |
||
1188 | $this->close_note = trim($this->close_note); |
||
1189 | } |
||
1190 | if (empty($this->total_ht)) { |
||
1191 | $this->total_ht = 0; |
||
1192 | } |
||
1193 | if (empty($this->total_tva)) { |
||
1194 | $this->total_tva = 0; |
||
1195 | } |
||
1196 | if (isset($this->total_ttc)) { |
||
1197 | $this->total_ttc = (float) $this->total_ttc; |
||
1198 | } |
||
1199 | if (isset($this->status)) { |
||
1200 | $this->status = (int) $this->status; |
||
1201 | $this->statut = $this->status; |
||
1202 | } elseif (isset($this->statut)) { |
||
1203 | $this->status = (int) $this->statut; |
||
1204 | $this->statut = $this->status; |
||
1205 | } |
||
1206 | if (isset($this->author)) { // TODO: user_creation_id? |
||
1207 | $this->author = (int) $this->author; |
||
1208 | } |
||
1209 | if (isset($this->fk_user_valid)) { |
||
1210 | $this->fk_user_valid = trim($this->fk_user_valid); |
||
1211 | } |
||
1212 | if (isset($this->fk_facture_source)) { |
||
1213 | $this->fk_facture_source = (int) $this->fk_facture_source; |
||
1214 | } |
||
1215 | if (isset($this->fk_project)) { |
||
1216 | if (empty($this->fk_project)) { |
||
1217 | $this->fk_project = 0; |
||
1218 | } else { |
||
1219 | $this->fk_project = (int) $this->fk_project; |
||
1220 | } |
||
1221 | } |
||
1222 | if (isset($this->cond_reglement_id)) { |
||
1223 | $this->cond_reglement_id = (int) $this->cond_reglement_id; |
||
1224 | } |
||
1225 | if (isset($this->note_private)) { |
||
1226 | $this->note_private = trim($this->note_private); |
||
1227 | $this->note = $this->note_private; |
||
1228 | } |
||
1229 | if (isset($this->note_public)) { |
||
1230 | $this->note_public = trim($this->note_public); |
||
1231 | } |
||
1232 | if (isset($this->model_pdf)) { |
||
1233 | $this->model_pdf = trim($this->model_pdf); |
||
1234 | } |
||
1235 | if (isset($this->import_key)) { |
||
1236 | $this->import_key = trim($this->import_key); |
||
1237 | } |
||
1238 | |||
1239 | |||
1240 | // Check parameters |
||
1241 | // Put here code to add control on parameters values |
||
1242 | |||
1243 | // Update request |
||
1244 | $sql = "UPDATE " . MAIN_DB_PREFIX . "facture_fourn SET"; |
||
1245 | $sql .= " ref=" . (isset($this->ref) ? "'" . $this->db->escape($this->ref) . "'" : "null") . ","; |
||
1246 | $sql .= " ref_supplier=" . (isset($this->ref_supplier) ? "'" . $this->db->escape($this->ref_supplier) . "'" : "null") . ","; |
||
1247 | $sql .= " ref_ext=" . (isset($this->ref_ext) ? "'" . $this->db->escape($this->ref_ext) . "'" : "null") . ","; |
||
1248 | $sql .= " entity=" . (isset($this->entity) ? ((int) $this->entity) : "null") . ","; |
||
1249 | $sql .= " type=" . (isset($this->type) ? ((int) $this->type) : "null") . ","; |
||
1250 | $sql .= " subtype=" . ((int) $this->subtype) . ","; |
||
1251 | $sql .= " fk_soc=" . (isset($this->socid) ? ((int) $this->socid) : "null") . ","; |
||
1252 | $sql .= " datec=" . (dol_strlen($this->datec) != 0 ? "'" . $this->db->idate($this->datec) . "'" : 'null') . ","; |
||
1253 | $sql .= " datef=" . (dol_strlen($this->date) != 0 ? "'" . $this->db->idate($this->date) . "'" : 'null') . ","; |
||
1254 | if (dol_strlen($this->tms) != 0) { |
||
1255 | $sql .= " tms=" . (dol_strlen($this->tms) != 0 ? "'" . $this->db->idate($this->tms) . "'" : 'null') . ","; |
||
1256 | } |
||
1257 | $sql .= " libelle=" . (isset($this->label) ? "'" . $this->db->escape($this->label) . "'" : "null") . ","; |
||
1258 | $sql .= " paye=" . (isset($this->paid) ? ((int) $this->paid) : "0") . ","; |
||
1259 | $sql .= " close_code=" . (isset($this->close_code) ? "'" . $this->db->escape($this->close_code) . "'" : "null") . ","; |
||
1260 | $sql .= " close_note=" . (isset($this->close_note) ? "'" . $this->db->escape($this->close_note) . "'" : "null") . ","; |
||
1261 | $sql .= " localtax1=" . (isset($this->total_localtax1) ? ((float) $this->total_localtax1) : "null") . ","; |
||
1262 | $sql .= " localtax2=" . (isset($this->total_localtax2) ? ((float) $this->total_localtax2) : "null") . ","; |
||
1263 | $sql .= " total_ht=" . (isset($this->total_ht) ? ((float) $this->total_ht) : "null") . ","; |
||
1264 | $sql .= " total_tva=" . (isset($this->total_tva) ? ((float) $this->total_tva) : "null") . ","; |
||
1265 | $sql .= " total_ttc=" . (isset($this->total_ttc) ? ((float) $this->total_ttc) : "null") . ","; |
||
1266 | $sql .= " fk_statut=" . (isset($this->status) ? ((int) $this->status) : (isset($this->statut) ? ((int) $this->statut) : "null")) . ","; |
||
1267 | $sql .= " fk_user_author=" . (isset($this->author) ? ((int) $this->author) : "null") . ","; |
||
1268 | $sql .= " fk_user_valid=" . (isset($this->fk_user_valid) ? ((int) $this->fk_user_valid) : "null") . ","; |
||
1269 | $sql .= " fk_facture_source=" . ($this->fk_facture_source ? ((int) $this->fk_facture_source) : "null") . ","; |
||
1270 | $sql .= " vat_reverse_charge = " . ($this->vat_reverse_charge != '' ? ((int) $this->db->escape($this->vat_reverse_charge)) : 0) . ","; |
||
1271 | $sql .= " fk_projet=" . (!empty($this->fk_project) ? ((int) $this->fk_project) : "null") . ","; |
||
1272 | $sql .= " fk_cond_reglement=" . (isset($this->cond_reglement_id) ? ((int) $this->cond_reglement_id) : "null") . ","; |
||
1273 | $sql .= " date_lim_reglement=" . (dol_strlen($this->date_echeance) != 0 ? "'" . $this->db->idate($this->date_echeance) . "'" : 'null') . ","; |
||
1274 | $sql .= " note_private=" . (isset($this->note_private) ? "'" . $this->db->escape($this->note_private) . "'" : "null") . ","; |
||
1275 | $sql .= " note_public=" . (isset($this->note_public) ? "'" . $this->db->escape($this->note_public) . "'" : "null") . ","; |
||
1276 | $sql .= " model_pdf=" . (isset($this->model_pdf) ? "'" . $this->db->escape($this->model_pdf) . "'" : "null") . ","; |
||
1277 | $sql .= " import_key=" . (isset($this->import_key) ? "'" . $this->db->escape($this->import_key) . "'" : "null"); |
||
1278 | $sql .= " WHERE rowid=" . ((int) $this->id); |
||
1279 | |||
1280 | $this->db->begin(); |
||
1281 | |||
1282 | dol_syslog(get_only_class($this) . "::update", LOG_DEBUG); |
||
1283 | $resql = $this->db->query($sql); |
||
1284 | |||
1285 | if (!$resql) { |
||
1286 | $error++; |
||
1287 | |||
1288 | if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') { |
||
1289 | $this->errors[] = $langs->trans('ErrorRefAlreadyExists'); |
||
1290 | } else { |
||
1291 | $this->errors[] = "Error " . $this->db->lasterror(); |
||
1292 | } |
||
1293 | } |
||
1294 | |||
1295 | if (!$error) { |
||
1296 | $result = $this->insertExtraFields(); |
||
1297 | if ($result < 0) { |
||
1298 | $error++; |
||
1299 | } |
||
1300 | } |
||
1301 | |||
1302 | if (!$error) { |
||
1303 | if (!$notrigger) { |
||
1304 | // Call trigger |
||
1305 | $result = $this->call_trigger('BILL_SUPPLIER_MODIFY', $user); |
||
1306 | if ($result < 0) { |
||
1307 | $error++; |
||
1308 | } |
||
1309 | // End call triggers |
||
1310 | } |
||
1311 | } |
||
1312 | |||
1313 | // Commit or rollback |
||
1314 | if ($error) { |
||
1315 | foreach ($this->errors as $errmsg) { |
||
1316 | dol_syslog(get_only_class($this) . "::update " . $errmsg, LOG_ERR); |
||
1317 | $this->error .= ($this->error ? ', ' . $errmsg : $errmsg); |
||
1318 | } |
||
1319 | $this->db->rollback(); |
||
1320 | return -1 * $error; |
||
1321 | } else { |
||
1322 | $this->db->commit(); |
||
1323 | return 1; |
||
1324 | } |
||
1325 | } |
||
1326 | |||
1327 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps |
||
1328 | /** |
||
1329 | * Add a discount line into an invoice (as an invoice line) using an existing absolute discount (Consume the discount) |
||
1330 | * |
||
1331 | * @param int $idremise Id of absolute discount |
||
1332 | * @return int >0 if OK, <0 if KO |
||
1333 | */ |
||
1334 | public function insert_discount($idremise) |
||
1335 | { |
||
1336 | // phpcs:enable |
||
1337 | global $conf, $langs; |
||
1338 | |||
1339 | include_once DOL_DOCUMENT_ROOT . '/core/lib/price.lib.php'; |
||
1340 | include_once DOL_DOCUMENT_ROOT . '/core/class/discount.class.php'; |
||
1341 | |||
1342 | $this->db->begin(); |
||
1343 | |||
1344 | $remise = new DiscountAbsolute($this->db); |
||
1345 | $result = $remise->fetch($idremise); |
||
1346 | |||
1347 | if ($result > 0) { |
||
1348 | if ($remise->fk_invoice_supplier) { // Protection against multiple submission |
||
1349 | $this->error = $langs->trans("ErrorDiscountAlreadyUsed"); |
||
1350 | $this->db->rollback(); |
||
1351 | return -5; |
||
1352 | } |
||
1353 | |||
1354 | $facligne = new SupplierInvoiceLine($this->db); |
||
1355 | $facligne->fk_facture_fourn = $this->id; |
||
1356 | $facligne->fk_remise_except = $remise->id; |
||
1357 | $facligne->desc = $remise->description; // Description ligne |
||
1358 | $facligne->vat_src_code = $remise->vat_src_code; |
||
1359 | $facligne->tva_tx = $remise->tva_tx; |
||
1360 | $facligne->subprice = -$remise->amount_ht; |
||
1361 | $facligne->fk_product = 0; // Id produit predefini |
||
1362 | $facligne->product_type = 0; |
||
1363 | $facligne->qty = 1; |
||
1364 | $facligne->remise_percent = 0; |
||
1365 | $facligne->rang = -1; |
||
1366 | $facligne->info_bits = 2; |
||
1367 | |||
1368 | if (getDolGlobalString('MAIN_ADD_LINE_AT_POSITION')) { |
||
1369 | $facligne->rang = 1; |
||
1370 | $linecount = count($this->lines); |
||
1371 | for ($ii = 1; $ii <= $linecount; $ii++) { |
||
1372 | $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii + 1); |
||
1373 | } |
||
1374 | } |
||
1375 | |||
1376 | // Get buy/cost price of invoice that is source of discount |
||
1377 | if ($remise->fk_invoice_supplier_source > 0) { |
||
1378 | $srcinvoice = new FactureFournisseur($this->db); |
||
1379 | $srcinvoice->fetch($remise->fk_invoice_supplier_source); |
||
1380 | $totalcostpriceofinvoice = 0; |
||
1381 | include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmargin.class.php'; // TODO Move this into commonobject |
||
1382 | $formmargin = new FormMargin($this->db); |
||
1383 | $arraytmp = $formmargin->getMarginInfosArray($srcinvoice, false); |
||
1384 | $facligne->pa_ht = $arraytmp['pa_total']; |
||
1385 | } |
||
1386 | |||
1387 | $facligne->total_ht = -$remise->amount_ht; |
||
1388 | $facligne->total_tva = -$remise->amount_tva; |
||
1389 | $facligne->total_ttc = -$remise->amount_ttc; |
||
1390 | |||
1391 | $facligne->multicurrency_subprice = -$remise->multicurrency_subprice; |
||
1392 | $facligne->multicurrency_total_ht = -$remise->multicurrency_total_ht; |
||
1393 | $facligne->multicurrency_total_tva = -$remise->multicurrency_total_tva; |
||
1394 | $facligne->multicurrency_total_ttc = -$remise->multicurrency_total_ttc; |
||
1395 | |||
1396 | $lineid = $facligne->insert(); |
||
1397 | if ($lineid > 0) { |
||
1398 | $result = $this->update_price(1); |
||
1399 | if ($result > 0) { |
||
1400 | // Create link between discount and invoice line |
||
1401 | $result = $remise->link_to_invoice($lineid, 0); |
||
1402 | if ($result < 0) { |
||
1403 | $this->error = $remise->error; |
||
1404 | $this->db->rollback(); |
||
1405 | return -4; |
||
1406 | } |
||
1407 | |||
1408 | $this->db->commit(); |
||
1409 | return 1; |
||
1410 | } else { |
||
1411 | $this->error = $facligne->error; |
||
1412 | $this->db->rollback(); |
||
1413 | return -1; |
||
1414 | } |
||
1415 | } else { |
||
1416 | $this->error = $facligne->error; |
||
1417 | $this->db->rollback(); |
||
1418 | return -2; |
||
1419 | } |
||
1420 | } else { |
||
1421 | $this->db->rollback(); |
||
1422 | return -3; |
||
1423 | } |
||
1424 | } |
||
1425 | |||
1426 | |||
1427 | /** |
||
1428 | * Delete invoice from database |
||
1429 | * |
||
1430 | * @param User $user User object |
||
1431 | * @param int $notrigger 1=Does not execute triggers, 0= execute triggers |
||
1432 | * @return int Return integer <0 if KO, >0 if OK |
||
1433 | */ |
||
1434 | public function delete(User $user, $notrigger = 0) |
||
1435 | { |
||
1436 | global $conf; |
||
1437 | |||
1438 | $rowid = $this->id; |
||
1439 | |||
1440 | dol_syslog("FactureFournisseur::delete rowid=" . $rowid, LOG_DEBUG); |
||
1441 | |||
1442 | // TODO Test if there is at least on payment. If yes, refuse to delete. |
||
1443 | |||
1444 | $error = 0; |
||
1445 | $this->db->begin(); |
||
1446 | |||
1447 | if (!$error && !$notrigger) { |
||
1448 | // Call trigger |
||
1449 | $result = $this->call_trigger('BILL_SUPPLIER_DELETE', $user); |
||
1450 | if ($result < 0) { |
||
1451 | $this->db->rollback(); |
||
1452 | return -1; |
||
1453 | } |
||
1454 | // Fin appel triggers |
||
1455 | } |
||
1456 | |||
1457 | if (!$error) { |
||
1458 | // If invoice was converted into a discount not yet consumed, we remove discount |
||
1459 | $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . 'societe_remise_except'; |
||
1460 | $sql .= ' WHERE fk_invoice_supplier_source = ' . ((int) $rowid); |
||
1461 | $sql .= ' AND fk_invoice_supplier_line IS NULL'; |
||
1462 | $resql = $this->db->query($sql); |
||
1463 | |||
1464 | // If invoice has consumned discounts |
||
1465 | $this->fetch_lines(); |
||
1466 | $list_rowid_det = array(); |
||
1467 | foreach ($this->lines as $key => $invoiceline) { |
||
1468 | $list_rowid_det[] = $invoiceline->id; |
||
1469 | } |
||
1470 | |||
1471 | // Consumned discounts are freed |
||
1472 | if (count($list_rowid_det)) { |
||
1473 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'societe_remise_except'; |
||
1474 | $sql .= ' SET fk_invoice_supplier = NULL, fk_invoice_supplier_line = NULL'; |
||
1475 | $sql .= ' WHERE fk_invoice_supplier_line IN (' . $this->db->sanitize(implode(',', $list_rowid_det)) . ')'; |
||
1476 | |||
1477 | dol_syslog(get_only_class($this) . "::delete", LOG_DEBUG); |
||
1478 | if (!$this->db->query($sql)) { |
||
1479 | $error++; |
||
1480 | } |
||
1481 | } |
||
1482 | } |
||
1483 | |||
1484 | if (!$error) { |
||
1485 | $main = MAIN_DB_PREFIX . 'facture_fourn_det'; |
||
1486 | $ef = $main . "_extrafields"; |
||
1487 | $sqlef = "DELETE FROM $ef WHERE fk_object IN (SELECT rowid FROM " . $main . " WHERE fk_facture_fourn = " . ((int) $rowid) . ")"; |
||
1488 | $resqlef = $this->db->query($sqlef); |
||
1489 | $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . 'facture_fourn_det WHERE fk_facture_fourn = ' . ((int) $rowid); |
||
1490 | dol_syslog(get_only_class($this) . "::delete", LOG_DEBUG); |
||
1491 | $resql = $this->db->query($sql); |
||
1492 | if ($resqlef && $resql) { |
||
1493 | $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . 'facture_fourn WHERE rowid = ' . ((int) $rowid); |
||
1494 | dol_syslog(get_only_class($this) . "::delete", LOG_DEBUG); |
||
1495 | $resql2 = $this->db->query($sql); |
||
1496 | if (!$resql2) { |
||
1497 | $error++; |
||
1498 | } |
||
1499 | } else { |
||
1500 | $error++; |
||
1501 | } |
||
1502 | } |
||
1503 | |||
1504 | if (!$error) { |
||
1505 | // Delete linked object |
||
1506 | $res = $this->deleteObjectLinked(); |
||
1507 | if ($res < 0) { |
||
1508 | $error++; |
||
1509 | } |
||
1510 | } |
||
1511 | |||
1512 | if (!$error) { |
||
1513 | // Delete record into ECM index (Note that delete is also done when deleting files with the dol_delete_dir_recursive |
||
1514 | $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive |
||
1515 | $this->deleteEcmFiles(1); // Deleting files physically is done later with the dol_delete_dir_recursive |
||
1516 | |||
1517 | // We remove directory |
||
1518 | if ($conf->fournisseur->facture->dir_output) { |
||
1519 | include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; |
||
1520 | |||
1521 | $ref = dol_sanitizeFileName($this->ref); |
||
1522 | $dir = $conf->fournisseur->facture->dir_output . '/' . get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier') . $ref; |
||
1523 | $file = $dir . "/" . $ref . ".pdf"; |
||
1524 | if (file_exists($file)) { |
||
1525 | if (!dol_delete_file($file, 0, 0, 0, $this)) { // For triggers |
||
1526 | $this->error = 'ErrorFailToDeleteFile'; |
||
1527 | $error++; |
||
1528 | } |
||
1529 | } |
||
1530 | if (file_exists($dir)) { |
||
1531 | $res = @dol_delete_dir_recursive($dir); |
||
1532 | |||
1533 | if (!$res) { |
||
1534 | $this->error = 'ErrorFailToDeleteDir'; |
||
1535 | $error++; |
||
1536 | } |
||
1537 | } |
||
1538 | } |
||
1539 | } |
||
1540 | |||
1541 | // Remove extrafields |
||
1542 | if (!$error) { |
||
1543 | $result = $this->deleteExtraFields(); |
||
1544 | if ($result < 0) { |
||
1545 | $error++; |
||
1546 | dol_syslog(get_only_class($this) . "::delete error -4 " . $this->error, LOG_ERR); |
||
1547 | } |
||
1548 | } |
||
1549 | |||
1550 | if (!$error) { |
||
1551 | dol_syslog(get_only_class($this) . "::delete $this->id by $user->id", LOG_DEBUG); |
||
1552 | $this->db->commit(); |
||
1553 | return 1; |
||
1554 | } else { |
||
1555 | $this->error = $this->db->lasterror(); |
||
1556 | $this->db->rollback(); |
||
1557 | return -$error; |
||
1558 | } |
||
1559 | } |
||
1560 | |||
1561 | |||
1562 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps |
||
1563 | /** |
||
1564 | * Tag invoice as a paid invoice |
||
1565 | * |
||
1566 | * @deprecated |
||
1567 | * @see setPaid() |
||
1568 | * @param User $user Object user |
||
1569 | * @param string $close_code Code indicates whether the class has paid in full while payment is incomplete. Not implemented yet. |
||
1570 | * @param string $close_note Comment informs if the class has been paid while payment is incomplete. Not implemented yet. |
||
1571 | * @return int Return integer <0 si ko, >0 si ok |
||
1572 | */ |
||
1573 | public function set_paid($user, $close_code = '', $close_note = '') |
||
1574 | { |
||
1575 | // phpcs:enable |
||
1576 | dol_syslog(get_only_class($this) . "::set_paid is deprecated, use setPaid instead", LOG_NOTICE); |
||
1577 | return $this->setPaid($user, $close_code, $close_note); |
||
1578 | } |
||
1579 | |||
1580 | /** |
||
1581 | * Tag invoice as a paid invoice |
||
1582 | * |
||
1583 | * @param User $user Object user |
||
1584 | * @param string $close_code Code indicates whether the class has paid in full while payment is incomplete. Not implemented yet. |
||
1585 | * @param string $close_note Comment informs if the class has been paid while payment is incomplete. Not implemented yet. |
||
1586 | * @return int<-1,1> Return integer <0 si ko, >0 si ok |
||
1587 | */ |
||
1588 | public function setPaid($user, $close_code = '', $close_note = '') |
||
1589 | { |
||
1590 | $error = 0; |
||
1591 | |||
1592 | if ($this->paid != 1) { |
||
1593 | $this->db->begin(); |
||
1594 | |||
1595 | $now = dol_now(); |
||
1596 | |||
1597 | dol_syslog("FactureFournisseur::setPaid", LOG_DEBUG); |
||
1598 | |||
1599 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture_fourn SET'; |
||
1600 | $sql .= ' fk_statut = ' . self::STATUS_CLOSED; |
||
1601 | if (!$close_code) { |
||
1602 | $sql .= ', paye=1'; |
||
1603 | } |
||
1604 | if ($close_code) { |
||
1605 | $sql .= ", close_code='" . $this->db->escape($close_code) . "'"; |
||
1606 | } |
||
1607 | if ($close_note) { |
||
1608 | $sql .= ", close_note='" . $this->db->escape($close_note) . "'"; |
||
1609 | } |
||
1610 | $sql .= ', fk_user_closing = ' . ((int) $user->id); |
||
1611 | $sql .= ", date_closing = '" . $this->db->idate($now) . "'"; |
||
1612 | $sql .= ' WHERE rowid = ' . ((int) $this->id); |
||
1613 | |||
1614 | $resql = $this->db->query($sql); |
||
1615 | if ($resql) { |
||
1616 | // Call trigger |
||
1617 | $result = $this->call_trigger('BILL_SUPPLIER_PAYED', $user); |
||
1618 | if ($result < 0) { |
||
1619 | $error++; |
||
1620 | } |
||
1621 | // End call triggers |
||
1622 | } else { |
||
1623 | $error++; |
||
1624 | $this->error = $this->db->error(); |
||
1625 | dol_print_error($this->db); |
||
1626 | } |
||
1627 | |||
1628 | if (!$error) { |
||
1629 | $this->db->commit(); |
||
1630 | return 1; |
||
1631 | } else { |
||
1632 | $this->db->rollback(); |
||
1633 | return -1; |
||
1634 | } |
||
1635 | } else { |
||
1636 | return 0; |
||
1637 | } |
||
1638 | } |
||
1639 | |||
1640 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps |
||
1641 | /** |
||
1642 | * Tag the invoice as not fully paid + trigger call BILL_UNPAYED |
||
1643 | * Function used when a direct debit payment is refused, |
||
1644 | * or when the invoice was canceled and reopened. |
||
1645 | * |
||
1646 | * @deprecated |
||
1647 | * @see setUnpaid() |
||
1648 | * @param User $user Object user that change status |
||
1649 | * @return int Return integer <0 si ok, >0 si ok |
||
1650 | */ |
||
1651 | public function set_unpaid($user) |
||
1652 | { |
||
1653 | // phpcs:enable |
||
1654 | dol_syslog(get_only_class($this) . "::set_unpaid is deprecated, use setUnpaid instead", LOG_NOTICE); |
||
1655 | return $this->setUnpaid($user); |
||
1656 | } |
||
1657 | |||
1658 | /** |
||
1659 | * Tag the invoice as not fully paid + trigger call BILL_UNPAYED |
||
1660 | * Function used when a direct debit payment is refused, |
||
1661 | * or when the invoice was canceled and reopened. |
||
1662 | * |
||
1663 | * @param User $user Object user that change status |
||
1664 | * @return int Return integer <0 si ok, >0 si ok |
||
1665 | */ |
||
1666 | public function setUnpaid($user) |
||
1667 | { |
||
1668 | $error = 0; |
||
1669 | |||
1670 | $this->db->begin(); |
||
1671 | |||
1672 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture_fourn'; |
||
1673 | $sql .= ' SET paye=0, fk_statut=' . self::STATUS_VALIDATED . ', close_code=null, close_note=null,'; |
||
1674 | $sql .= ' date_closing=null,'; |
||
1675 | $sql .= ' fk_user_closing=null'; |
||
1676 | $sql .= ' WHERE rowid = ' . ((int) $this->id); |
||
1677 | |||
1678 | dol_syslog(get_only_class($this) . "::set_unpaid", LOG_DEBUG); |
||
1679 | $resql = $this->db->query($sql); |
||
1680 | if ($resql) { |
||
1681 | // Call trigger |
||
1682 | $result = $this->call_trigger('BILL_SUPPLIER_UNPAYED', $user); |
||
1683 | if ($result < 0) { |
||
1684 | $error++; |
||
1685 | } |
||
1686 | // End call triggers |
||
1687 | } else { |
||
1688 | $error++; |
||
1689 | $this->error = $this->db->error(); |
||
1690 | dol_print_error($this->db); |
||
1691 | } |
||
1692 | |||
1693 | if (!$error) { |
||
1694 | $this->db->commit(); |
||
1695 | return 1; |
||
1696 | } else { |
||
1697 | $this->db->rollback(); |
||
1698 | return -1; |
||
1699 | } |
||
1700 | } |
||
1701 | |||
1702 | /** |
||
1703 | * Tag invoice as canceled, with no payment on it (example for replacement invoice or payment never received) + call trigger BILL_CANCEL |
||
1704 | * Warning, if option to decrease stock on invoice was set, this function does not change stock (it might be a cancel because |
||
1705 | * of no payment even if merchandises were sent). |
||
1706 | * |
||
1707 | * @param User $user Object user making change |
||
1708 | * @param string $close_code Code of closing invoice (CLOSECODE_REPLACED, CLOSECODE_...) |
||
1709 | * @param string $close_note Comment |
||
1710 | * @return int Return integer <0 if KO, >0 if OK |
||
1711 | */ |
||
1712 | public function setCanceled($user, $close_code = '', $close_note = '') |
||
1713 | { |
||
1714 | dol_syslog(get_only_class($this) . "::setCanceled rowid=" . ((int)$this->id), LOG_DEBUG); |
||
1715 | |||
1716 | $this->db->begin(); |
||
1717 | |||
1718 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture_fourn SET'; |
||
1719 | $sql .= ' fk_statut=' . self::STATUS_ABANDONED; |
||
1720 | if ($close_code) { |
||
1721 | $sql .= ", close_code='" . $this->db->escape($close_code) . "'"; |
||
1722 | } |
||
1723 | if ($close_note) { |
||
1724 | $sql .= ", close_note='" . $this->db->escape($close_note) . "'"; |
||
1725 | } |
||
1726 | $sql .= " WHERE rowid = " . ((int) $this->id); |
||
1727 | |||
1728 | $resql = $this->db->query($sql); |
||
1729 | if ($resql) { |
||
1730 | // Bound discounts are deducted from the invoice |
||
1731 | // as they have not been used since the invoice is abandoned. |
||
1732 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'societe_remise_except'; |
||
1733 | $sql .= ' SET fk_invoice_supplier = NULL'; |
||
1734 | $sql .= ' WHERE fk_invoice_supplier = ' . ((int) $this->id); |
||
1735 | |||
1736 | $resql = $this->db->query($sql); |
||
1737 | if ($resql) { |
||
1738 | // Call trigger |
||
1739 | $result = $this->call_trigger('BILL_SUPPLIER_CANCEL', $user); |
||
1740 | if ($result < 0) { |
||
1741 | $this->db->rollback(); |
||
1742 | return -1; |
||
1743 | } |
||
1744 | // End call triggers |
||
1745 | |||
1746 | $this->db->commit(); |
||
1747 | return 1; |
||
1748 | } else { |
||
1749 | $this->error = $this->db->error() . " sql=" . $sql; |
||
1750 | $this->db->rollback(); |
||
1751 | return -1; |
||
1752 | } |
||
1753 | } else { |
||
1754 | $this->error = $this->db->error() . " sql=" . $sql; |
||
1755 | $this->db->rollback(); |
||
1756 | return -2; |
||
1757 | } |
||
1758 | } |
||
1759 | |||
1760 | /** |
||
1761 | * Tag invoice as validated + call trigger BILL_VALIDATE |
||
1762 | * |
||
1763 | * @param User $user Object user that validate |
||
1764 | * @param string $force_number Reference to force on invoice |
||
1765 | * @param int $idwarehouse Id of warehouse for stock change |
||
1766 | * @param int $notrigger 1=Does not execute triggers, 0= execute triggers |
||
1767 | * @return int Return integer <0 if KO, =0 if nothing to do, >0 if OK |
||
1768 | */ |
||
1769 | public function validate($user, $force_number = '', $idwarehouse = 0, $notrigger = 0) |
||
1770 | { |
||
1771 | global $mysoc, $conf, $langs; |
||
1772 | |||
1773 | require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php'; |
||
1774 | |||
1775 | $now = dol_now(); |
||
1776 | |||
1777 | $error = 0; |
||
1778 | dol_syslog(get_only_class($this) . '::validate user=' . $user->id . ', force_number=' . $force_number . ', idwarehouse=' . $idwarehouse); |
||
1779 | |||
1780 | // Force to have object complete for checks |
||
1781 | $this->fetch_thirdparty(); |
||
1782 | $this->fetch_lines(); |
||
1783 | |||
1784 | // Check parameters |
||
1785 | if ($this->status > self::STATUS_DRAFT) { // This is to avoid to validate twice (avoid errors on logs and stock management) |
||
1786 | dol_syslog(get_only_class($this) . "::validate no draft status", LOG_WARNING); |
||
1787 | return 0; |
||
1788 | } |
||
1789 | if (preg_match('/^' . preg_quote($langs->trans("CopyOf") . ' ') . '/', $this->ref_supplier)) { |
||
1790 | $langs->load("errors"); |
||
1791 | $this->error = $langs->trans("ErrorFieldFormat", $langs->transnoentities("RefSupplier")) . '. ' . $langs->trans('RemoveString', $langs->transnoentitiesnoconv("CopyOf")); |
||
1792 | return -1; |
||
1793 | } |
||
1794 | if (count($this->lines) <= 0) { |
||
1795 | $langs->load("errors"); |
||
1796 | $this->error = $langs->trans("ErrorObjectMustHaveLinesToBeValidated", $this->ref); |
||
1797 | return -1; |
||
1798 | } |
||
1799 | |||
1800 | // Check for mandatory fields in thirdparty (defined into setup) |
||
1801 | if (!empty($this->thirdparty) && is_object($this->thirdparty)) { |
||
1802 | $array_to_check = array('IDPROF1', 'IDPROF2', 'IDPROF3', 'IDPROF4', 'IDPROF5', 'IDPROF6', 'EMAIL', 'ACCOUNTANCY_CODE_SUPPLIER'); |
||
1803 | foreach ($array_to_check as $key) { |
||
1804 | $keymin = strtolower($key); |
||
1805 | if ($keymin == 'accountancy_code_supplier') { |
||
1806 | $keymin = 'code_compta_fournisseur'; |
||
1807 | } |
||
1808 | if (!property_exists($this->thirdparty, $keymin)) { |
||
1809 | continue; |
||
1810 | } |
||
1811 | $vallabel = $this->thirdparty->$keymin; |
||
1812 | |||
1813 | $i = (int) preg_replace('/[^0-9]/', '', $key); |
||
1814 | if ($i > 0) { |
||
1815 | if ($this->thirdparty->isACompany()) { |
||
1816 | // Check for mandatory prof id (but only if country is other than ours) |
||
1817 | if ($mysoc->country_id > 0 && $this->thirdparty->country_id == $mysoc->country_id) { |
||
1818 | $idprof_mandatory = 'SOCIETE_' . $key . '_INVOICE_MANDATORY'; |
||
1819 | if (!$vallabel && getDolGlobalString($idprof_mandatory)) { |
||
1820 | $langs->load("errors"); |
||
1821 | $this->error = $langs->trans('ErrorProdIdIsMandatory', $langs->transcountry('ProfId' . $i, $this->thirdparty->country_code)) . ' (' . $langs->trans("ForbiddenBySetupRules") . ') [' . $langs->trans('Company') . ' : ' . $this->thirdparty->name . ']'; |
||
1822 | dol_syslog(__METHOD__ . ' ' . $this->error, LOG_ERR); |
||
1823 | return -1; |
||
1824 | } |
||
1825 | } |
||
1826 | } |
||
1827 | } else { |
||
1828 | if ($key == 'EMAIL') { |
||
1829 | // Check for mandatory |
||
1830 | if (getDolGlobalString('SOCIETE_EMAIL_INVOICE_MANDATORY') && !isValidEmail($this->thirdparty->email)) { |
||
1831 | $langs->load("errors"); |
||
1832 | $this->error = $langs->trans("ErrorBadEMail", $this->thirdparty->email) . ' (' . $langs->trans("ForbiddenBySetupRules") . ') [' . $langs->trans('Company') . ' : ' . $this->thirdparty->name . ']'; |
||
1833 | dol_syslog(__METHOD__ . ' ' . $this->error, LOG_ERR); |
||
1834 | return -1; |
||
1835 | } |
||
1836 | } elseif ($key == 'ACCOUNTANCY_CODE_SUPPLIER') { |
||
1837 | // Check for mandatory |
||
1838 | if (getDolGlobalString('SOCIETE_ACCOUNTANCY_CODE_SUPPLIER_INVOICE_MANDATORY') && empty($this->thirdparty->code_compta_fournisseur)) { |
||
1839 | $langs->load("errors"); |
||
1840 | $this->error = $langs->trans("ErrorAccountancyCodeSupplierIsMandatory", $this->thirdparty->name) . ' (' . $langs->trans("ForbiddenBySetupRules") . ')'; |
||
1841 | dol_syslog(__METHOD__ . ' ' . $this->error, LOG_ERR); |
||
1842 | return -1; |
||
1843 | } |
||
1844 | } |
||
1845 | } |
||
1846 | } |
||
1847 | } |
||
1848 | |||
1849 | $this->db->begin(); |
||
1850 | |||
1851 | // Define new ref |
||
1852 | if ($force_number) { |
||
1853 | $num = $force_number; |
||
1854 | } elseif (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref)) { // empty should not happened, but when it occurs, the test save life |
||
1855 | $num = $this->getNextNumRef($this->thirdparty); |
||
1856 | } else { |
||
1857 | $num = $this->ref; |
||
1858 | } |
||
1859 | $this->newref = dol_sanitizeFileName($num); |
||
1860 | |||
1861 | $sql = "UPDATE " . MAIN_DB_PREFIX . "facture_fourn"; |
||
1862 | $sql .= " SET ref='" . $this->db->escape($num) . "', fk_statut = 1, fk_user_valid = " . ((int) $user->id) . ", date_valid = '" . $this->db->idate($now) . "'"; |
||
1863 | $sql .= " WHERE rowid = " . ((int) $this->id); |
||
1864 | |||
1865 | dol_syslog(get_only_class($this) . "::validate", LOG_DEBUG); |
||
1866 | $resql = $this->db->query($sql); |
||
1867 | if ($resql) { |
||
1868 | // Si on incrémente le produit principal et ses composants à la validation de facture fournisseur |
||
1869 | if (!$error && isModEnabled('stock') && getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_BILL')) { |
||
1870 | $langs->load("agenda"); |
||
1871 | |||
1872 | $cpt = count($this->lines); |
||
1873 | for ($i = 0; $i < $cpt; $i++) { |
||
1874 | if ($this->lines[$i]->fk_product > 0) { |
||
1875 | $mouvP = new MouvementStock($this->db); |
||
1876 | $mouvP->origin = &$this; |
||
1877 | $mouvP->setOrigin($this->element, $this->id); |
||
1878 | // We increase stock for product |
||
1879 | $up_ht_disc = $this->lines[$i]->subprice; |
||
1880 | if (!empty($this->lines[$i]->remise_percent) && !getDolGlobalString('STOCK_EXCLUDE_DISCOUNT_FOR_PMP')) { |
||
1881 | $up_ht_disc = price2num($up_ht_disc * (100 - $this->lines[$i]->remise_percent) / 100, 'MU'); |
||
1882 | } |
||
1883 | if ($this->type == FactureFournisseur::TYPE_CREDIT_NOTE) { |
||
1884 | $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num)); |
||
1885 | } else { |
||
1886 | $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("InvoiceValidatedInDolibarr", $num)); |
||
1887 | } |
||
1888 | if ($result < 0) { |
||
1889 | $this->error = $mouvP->error; |
||
1890 | if (count($mouvP->errors)) { |
||
1891 | $this->errors = $mouvP->errors; |
||
1892 | } |
||
1893 | return -2; |
||
1894 | } |
||
1895 | } |
||
1896 | } |
||
1897 | } |
||
1898 | |||
1899 | // Triggers call |
||
1900 | if (!$error && empty($notrigger)) { |
||
1901 | // Call trigger |
||
1902 | $result = $this->call_trigger('BILL_SUPPLIER_VALIDATE', $user); |
||
1903 | if ($result < 0) { |
||
1904 | $error++; |
||
1905 | } |
||
1906 | // End call triggers |
||
1907 | } |
||
1908 | |||
1909 | if (!$error) { |
||
1910 | $this->oldref = $this->ref; |
||
1911 | |||
1912 | // Rename directory if dir was a temporary ref |
||
1913 | if (preg_match('/^[\(]?PROV/i', $this->ref)) { |
||
1914 | // Now we rename also files into index |
||
1915 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . "ecm_files set filename = CONCAT('" . $this->db->escape($this->newref) . "', SUBSTR(filename, " . (strlen($this->ref) + 1) . ")), filepath = 'fournisseur/facture/" . get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier') . $this->db->escape($this->newref) . "'"; |
||
1916 | $sql .= " WHERE filename LIKE '" . $this->db->escape($this->ref) . "%' AND filepath = 'fournisseur/facture/" . get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier') . $this->db->escape($this->ref) . "' and entity = " . $conf->entity; |
||
1917 | $resql = $this->db->query($sql); |
||
1918 | if (!$resql) { |
||
1919 | $error++; |
||
1920 | $this->error = $this->db->lasterror(); |
||
1921 | } |
||
1922 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . "ecm_files set filepath = 'fournisseur/facture/" . get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier') . $this->db->escape($this->newref) . "'"; |
||
1923 | $sql .= " WHERE filepath = 'fournisseur/facture/" . get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier') . $this->db->escape($this->ref) . "' and entity = " . $conf->entity; |
||
1924 | $resql = $this->db->query($sql); |
||
1925 | if (!$resql) { |
||
1926 | $error++; |
||
1927 | $this->error = $this->db->lasterror(); |
||
1928 | } |
||
1929 | |||
1930 | // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments |
||
1931 | $oldref = dol_sanitizeFileName($this->ref); |
||
1932 | $dirsource = $conf->fournisseur->facture->dir_output . '/' . get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier') . $oldref; |
||
1933 | $dirdest = $conf->fournisseur->facture->dir_output . '/' . get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier') . $this->newref; |
||
1934 | if (!$error && file_exists($dirsource)) { |
||
1935 | dol_syslog(get_only_class($this) . "::validate rename dir " . $dirsource . " into " . $dirdest); |
||
1936 | |||
1937 | if (@rename($dirsource, $dirdest)) { |
||
1938 | dol_syslog("Rename ok"); |
||
1939 | // Rename docs starting with $oldref with $this->newref |
||
1940 | $listoffiles = dol_dir_list($conf->fournisseur->facture->dir_output . '/' . get_exdir($this->id, 2, 0, 0, $this, 'invoice_supplier') . $this->newref, 'files', 1, '^' . preg_quote($oldref, '/')); |
||
1941 | foreach ($listoffiles as $fileentry) { |
||
1942 | $dirsource = $fileentry['name']; |
||
1943 | $dirdest = preg_replace('/^' . preg_quote($oldref, '/') . '/', $this->newref, $dirsource); |
||
1944 | $dirsource = $fileentry['path'] . '/' . $dirsource; |
||
1945 | $dirdest = $fileentry['path'] . '/' . $dirdest; |
||
1946 | @rename($dirsource, $dirdest); |
||
1947 | } |
||
1948 | } |
||
1949 | } |
||
1950 | } |
||
1951 | } |
||
1952 | |||
1953 | // Set new ref and define current statut |
||
1954 | if (!$error) { |
||
1955 | $this->ref = $this->newref; |
||
1956 | $this->statut = self::STATUS_VALIDATED; |
||
1957 | $this->status = self::STATUS_VALIDATED; |
||
1958 | //$this->date_validation=$now; this is stored into log table |
||
1959 | } |
||
1960 | |||
1961 | if (!$error) { |
||
1962 | $this->db->commit(); |
||
1963 | return 1; |
||
1964 | } else { |
||
1965 | $this->db->rollback(); |
||
1966 | return -1; |
||
1967 | } |
||
1968 | } else { |
||
1969 | $this->error = $this->db->error(); |
||
1970 | $this->db->rollback(); |
||
1971 | return -1; |
||
1972 | } |
||
1973 | } |
||
1974 | |||
1975 | /** |
||
1976 | * Set draft status |
||
1977 | * |
||
1978 | * @param User $user Object user that modify |
||
1979 | * @param int $idwarehouse Id warehouse to use for stock change. |
||
1980 | * @param int $notrigger 1=Does not execute triggers, 0= execute triggers |
||
1981 | * @return int Return integer <0 if KO, >0 if OK |
||
1982 | */ |
||
1983 | public function setDraft($user, $idwarehouse = -1, $notrigger = 0) |
||
1984 | { |
||
1985 | // phpcs:enable |
||
1986 | global $conf, $langs; |
||
1987 | |||
1988 | $error = 0; |
||
1989 | |||
1990 | if ($this->status == self::STATUS_DRAFT) { |
||
1991 | dol_syslog(__METHOD__ . " already draft status", LOG_WARNING); |
||
1992 | return 0; |
||
1993 | } |
||
1994 | |||
1995 | dol_syslog(__METHOD__, LOG_DEBUG); |
||
1996 | |||
1997 | $this->db->begin(); |
||
1998 | |||
1999 | $sql = "UPDATE " . MAIN_DB_PREFIX . "facture_fourn"; |
||
2000 | $sql .= " SET fk_statut = " . self::STATUS_DRAFT; |
||
2001 | $sql .= " WHERE rowid = " . ((int) $this->id); |
||
2002 | |||
2003 | $result = $this->db->query($sql); |
||
2004 | if ($result) { |
||
2005 | if (!$error) { |
||
2006 | $this->oldcopy = clone $this; |
||
2007 | } |
||
2008 | |||
2009 | // Si on incremente le produit principal et ses composants a la validation de facture fournisseur, on decremente |
||
2010 | if ($result >= 0 && isModEnabled('stock') && getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_BILL')) { |
||
2011 | $langs->load("agenda"); |
||
2012 | |||
2013 | $cpt = count($this->lines); |
||
2014 | for ($i = 0; $i < $cpt; $i++) { |
||
2015 | if ($this->lines[$i]->fk_product > 0) { |
||
2016 | $mouvP = new MouvementStock($this->db); |
||
2017 | $mouvP->origin = &$this; |
||
2018 | $mouvP->setOrigin($this->element, $this->id); |
||
2019 | // We increase stock for product |
||
2020 | if ($this->type == FactureFournisseur::TYPE_CREDIT_NOTE) { |
||
2021 | $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref)); |
||
2022 | } else { |
||
2023 | $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr", $this->ref)); |
||
2024 | } |
||
2025 | } |
||
2026 | } |
||
2027 | } |
||
2028 | // Triggers call |
||
2029 | if (!$error && empty($notrigger)) { |
||
2030 | // Call trigger |
||
2031 | $result = $this->call_trigger('BILL_SUPPLIER_UNVALIDATE', $user); |
||
2032 | if ($result < 0) { |
||
2033 | $error++; |
||
2034 | } |
||
2035 | // End call triggers |
||
2036 | } |
||
2037 | if ($error == 0) { |
||
2038 | $this->db->commit(); |
||
2039 | return 1; |
||
2040 | } else { |
||
2041 | $this->db->rollback(); |
||
2042 | return -1; |
||
2043 | } |
||
2044 | } else { |
||
2045 | $this->error = $this->db->error(); |
||
2046 | $this->db->rollback(); |
||
2047 | return -1; |
||
2048 | } |
||
2049 | } |
||
2050 | |||
2051 | |||
2052 | /** |
||
2053 | * Adds an invoice line (associated with no predefined product/service) |
||
2054 | * The parameters are already supposed to be correct and with final values when calling |
||
2055 | * this method. Also, for the VAT rate, it must already have been defined by the caller by |
||
2056 | * by the get_default_tva method(vendor_company, buying company, idprod) and the desc must |
||
2057 | * already have the right value (the caller has to manage the multilanguage). |
||
2058 | * |
||
2059 | * @param string $desc Description of the line |
||
2060 | * @param double $pu Unit price (HT or TTC according to price_base_type, > 0 even for credit note) |
||
2061 | * @param double $txtva Force Vat rate to use, -1 for auto. |
||
2062 | * @param double $txlocaltax1 LocalTax1 Rate |
||
2063 | * @param double $txlocaltax2 LocalTax2 Rate |
||
2064 | * @param double $qty Quantity |
||
2065 | * @param int $fk_product Product/Service ID predefined |
||
2066 | * @param double $remise_percent Percentage discount of the line |
||
2067 | * @param int $date_start Service start date |
||
2068 | * @param int $date_end Service expiry date |
||
2069 | * @param int $fk_code_ventilation Accounting breakdown code |
||
2070 | * @param int $info_bits Line type bits |
||
2071 | * @param string $price_base_type HT or TTC |
||
2072 | * @param int $type Type of line (0=product, 1=service) |
||
2073 | * @param int $rang Position of line |
||
2074 | * @param int $notrigger Disable triggers |
||
2075 | * @param array $array_options extrafields array |
||
2076 | * @param int|null $fk_unit Code of the unit to use. Null to use the default one |
||
2077 | * @param int $origin_id id origin document |
||
2078 | * @param double $pu_devise Amount in currency |
||
2079 | * @param string $ref_supplier Supplier ref |
||
2080 | * @param int $special_code Special code |
||
2081 | * @param int $fk_parent_line Parent line id |
||
2082 | * @param int $fk_remise_except Id discount used |
||
2083 | * @return int >0 if OK, <0 if KO |
||
2084 | */ |
||
2085 | public function addline($desc, $pu, $txtva, $txlocaltax1, $txlocaltax2, $qty, $fk_product = 0, $remise_percent = 0, $date_start = 0, $date_end = 0, $fk_code_ventilation = 0, $info_bits = 0, $price_base_type = 'HT', $type = 0, $rang = -1, $notrigger = 0, $array_options = [], $fk_unit = null, $origin_id = 0, $pu_devise = 0, $ref_supplier = '', $special_code = 0, $fk_parent_line = 0, $fk_remise_except = 0) |
||
2086 | { |
||
2087 | global $langs, $mysoc; |
||
2088 | |||
2089 | dol_syslog(get_only_class($this) . "::addline $desc,$pu,$qty,$txtva,$fk_product,$remise_percent,$date_start,$date_end,$fk_code_ventilation,$info_bits,$price_base_type,$type,$fk_unit,fk_remise_except=$fk_remise_except", LOG_DEBUG); |
||
2090 | include_once DOL_DOCUMENT_ROOT . '/core/lib/price.lib.php'; |
||
2091 | |||
2092 | if ($this->status == self::STATUS_DRAFT) { |
||
2093 | // Clean parameters |
||
2094 | if (empty($remise_percent)) { |
||
2095 | $remise_percent = 0; |
||
2096 | } |
||
2097 | if (empty($qty)) { |
||
2098 | $qty = 0; |
||
2099 | } |
||
2100 | if (empty($info_bits)) { |
||
2101 | $info_bits = 0; |
||
2102 | } |
||
2103 | if (empty($rang)) { |
||
2104 | $rang = 0; |
||
2105 | } |
||
2106 | if (empty($fk_code_ventilation)) { |
||
2107 | $fk_code_ventilation = 0; |
||
2108 | } |
||
2109 | if (empty($txtva)) { |
||
2110 | $txtva = 0; |
||
2111 | } |
||
2112 | if (empty($txlocaltax1)) { |
||
2113 | $txlocaltax1 = 0; |
||
2114 | } |
||
2115 | if (empty($txlocaltax2)) { |
||
2116 | $txlocaltax2 = 0; |
||
2117 | } |
||
2118 | |||
2119 | $remise_percent = price2num($remise_percent); |
||
2120 | $qty = price2num($qty); |
||
2121 | $pu = price2num($pu); |
||
2122 | if (!preg_match('/\((.*)\)/', (string) $txtva)) { |
||
2123 | $txtva = price2num($txtva); // $txtva can have format '5,1' or '5.1' or '5.1(XXX)', we must clean only if '5,1' |
||
2124 | } |
||
2125 | $txlocaltax1 = price2num($txlocaltax1); |
||
2126 | $txlocaltax2 = price2num($txlocaltax2); |
||
2127 | |||
2128 | if ($date_start && $date_end && $date_start > $date_end) { |
||
2129 | $langs->load("errors"); |
||
2130 | $this->error = $langs->trans('ErrorStartDateGreaterEnd'); |
||
2131 | return -1; |
||
2132 | } |
||
2133 | |||
2134 | $this->db->begin(); |
||
2135 | |||
2136 | if ($fk_product > 0) { |
||
2137 | if (getDolGlobalString('SUPPLIER_INVOICE_WITH_PREDEFINED_PRICES_ONLY')) { |
||
2138 | // Check quantity is enough |
||
2139 | dol_syslog(get_only_class($this) . "::addline we check supplier prices fk_product=" . $fk_product . " qty=" . $qty . " ref_supplier=" . $ref_supplier); |
||
2140 | $prod = new ProductFournisseur($this->db); |
||
2141 | if ($prod->fetch($fk_product) > 0) { |
||
2142 | $product_type = $prod->type; |
||
2143 | $label = $prod->label; |
||
2144 | $fk_prod_fourn_price = 0; |
||
2145 | |||
2146 | // We use 'none' instead of $ref_supplier, because $ref_supplier may not exists anymore. So we will take the first supplier price ok. |
||
2147 | // If we want a dedicated supplier price, we must provide $fk_prod_fourn_price. |
||
2148 | $result = $prod->get_buyprice($fk_prod_fourn_price, $qty, $fk_product, 'none', ($this->fk_soc ? $this->fk_soc : $this->socid)); // Search on couple $fk_prod_fourn_price/$qty first, then on triplet $qty/$fk_product/$ref_supplier/$this->fk_soc |
||
2149 | if ($result > 0) { |
||
2150 | if (empty($pu)) { |
||
2151 | $pu = $prod->fourn_pu; // Unit price supplier price set by get_buyprice |
||
2152 | } |
||
2153 | $ref_supplier = $prod->ref_supplier; // Ref supplier price set by get_buyprice |
||
2154 | // is remise percent not keyed but present for the product we add it |
||
2155 | if ($remise_percent == 0 && $prod->remise_percent != 0) { |
||
2156 | $remise_percent = $prod->remise_percent; |
||
2157 | } |
||
2158 | } |
||
2159 | if ($result == 0) { // If result == 0, we failed to found the supplier reference price |
||
2160 | $langs->load("errors"); |
||
2161 | $this->error = "Ref " . $prod->ref . " " . $langs->trans("ErrorQtyTooLowForThisSupplier"); |
||
2162 | $this->db->rollback(); |
||
2163 | dol_syslog(get_only_class($this) . "::addline we did not found supplier price, so we can't guess unit price"); |
||
2164 | //$pu = $prod->fourn_pu; // We do not overwrite unit price |
||
2165 | //$ref = $prod->ref_fourn; // We do not overwrite ref supplier price |
||
2166 | return -1; |
||
2167 | } |
||
2168 | if ($result == -1) { |
||
2169 | $langs->load("errors"); |
||
2170 | $this->error = "Ref " . $prod->ref . " " . $langs->trans("ErrorQtyTooLowForThisSupplier"); |
||
2171 | $this->db->rollback(); |
||
2172 | dol_syslog(get_only_class($this) . "::addline result=" . $result . " - " . $this->error, LOG_DEBUG); |
||
2173 | return -1; |
||
2174 | } |
||
2175 | if ($result < -1) { |
||
2176 | $this->error = $prod->error; |
||
2177 | $this->db->rollback(); |
||
2178 | dol_syslog(get_only_class($this) . "::addline result=" . $result . " - " . $this->error, LOG_ERR); |
||
2179 | return -1; |
||
2180 | } |
||
2181 | } else { |
||
2182 | $this->error = $prod->error; |
||
2183 | $this->db->rollback(); |
||
2184 | return -1; |
||
2185 | } |
||
2186 | } |
||
2187 | } else { |
||
2188 | $product_type = $type; |
||
2189 | } |
||
2190 | |||
2191 | if (isModEnabled("multicurrency") && $pu_devise > 0) { |
||
2192 | $pu = 0; |
||
2193 | } |
||
2194 | |||
2195 | $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $mysoc, $this->thirdparty); |
||
2196 | |||
2197 | // Clean vat code |
||
2198 | $reg = array(); |
||
2199 | $vat_src_code = ''; |
||
2200 | if (preg_match('/\((.*)\)/', $txtva, $reg)) { |
||
2201 | $vat_src_code = $reg[1]; |
||
2202 | $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate. |
||
2203 | } |
||
2204 | |||
2205 | // Calcul du total TTC et de la TVA pour la ligne a partir de |
||
2206 | // qty, pu, remise_percent et txtva |
||
2207 | // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker |
||
2208 | // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva. |
||
2209 | |||
2210 | $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $this->thirdparty, $localtaxes_type, 100, $this->multicurrency_tx, $pu_devise); |
||
2211 | $total_ht = $tabprice[0]; |
||
2212 | $total_tva = $tabprice[1]; |
||
2213 | $total_ttc = $tabprice[2]; |
||
2214 | $total_localtax1 = $tabprice[9]; |
||
2215 | $total_localtax2 = $tabprice[10]; |
||
2216 | $pu_ht = $tabprice[3]; |
||
2217 | |||
2218 | // MultiCurrency |
||
2219 | $multicurrency_total_ht = $tabprice[16]; |
||
2220 | $multicurrency_total_tva = $tabprice[17]; |
||
2221 | $multicurrency_total_ttc = $tabprice[18]; |
||
2222 | $pu_ht_devise = $tabprice[19]; |
||
2223 | |||
2224 | // Check parameters |
||
2225 | if ($type < 0) { |
||
2226 | return -1; |
||
2227 | } |
||
2228 | |||
2229 | if ($rang < 0) { |
||
2230 | $rangmax = $this->line_max(); |
||
2231 | $rang = $rangmax + 1; |
||
2232 | } |
||
2233 | |||
2234 | // Insert line |
||
2235 | $supplierinvoiceline = new SupplierInvoiceLine($this->db); |
||
2236 | |||
2237 | $supplierinvoiceline->context = $this->context; |
||
2238 | |||
2239 | $supplierinvoiceline->fk_facture_fourn = $this->id; |
||
2240 | //$supplierinvoiceline->label=$label; // deprecated |
||
2241 | $supplierinvoiceline->desc = $desc; |
||
2242 | $supplierinvoiceline->ref_supplier = $ref_supplier; |
||
2243 | |||
2244 | $supplierinvoiceline->qty = ($this->type == self::TYPE_CREDIT_NOTE ? abs((float) $qty) : $qty); // For credit note, quantity is always positive and unit price negative |
||
2245 | $supplierinvoiceline->subprice = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht) : $pu_ht); // For credit note, unit price always negative, always positive otherwise |
||
2246 | |||
2247 | $supplierinvoiceline->vat_src_code = $vat_src_code; |
||
2248 | $supplierinvoiceline->tva_tx = $txtva; |
||
2249 | $supplierinvoiceline->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0); |
||
2250 | $supplierinvoiceline->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0); |
||
2251 | $supplierinvoiceline->localtax1_type = empty($localtaxes_type[0]) ? 0 : $localtaxes_type[0]; |
||
2252 | $supplierinvoiceline->localtax2_type = empty($localtaxes_type[2]) ? 0 : $localtaxes_type[2]; |
||
2253 | |||
2254 | $supplierinvoiceline->total_ht = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($total_ht) : $total_ht); // For credit note and if qty is negative, total is negative |
||
2255 | $supplierinvoiceline->total_tva = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($total_tva) : $total_tva); // For credit note and if qty is negative, total is negative |
||
2256 | $supplierinvoiceline->total_localtax1 = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($total_localtax1) : $total_localtax1); // For credit note and if qty is negative, total is negative |
||
2257 | $supplierinvoiceline->total_localtax2 = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($total_localtax2) : $total_localtax2); // For credit note and if qty is negative, total is negative |
||
2258 | $supplierinvoiceline->total_ttc = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($total_ttc) : $total_ttc); // For credit note and if qty is negative, total is negative |
||
2259 | |||
2260 | $supplierinvoiceline->fk_product = $fk_product; |
||
2261 | $supplierinvoiceline->product_type = $type; |
||
2262 | $supplierinvoiceline->remise_percent = $remise_percent; |
||
2263 | $supplierinvoiceline->date_start = $date_start; |
||
2264 | $supplierinvoiceline->date_end = $date_end; |
||
2265 | $supplierinvoiceline->fk_code_ventilation = $fk_code_ventilation; |
||
2266 | $supplierinvoiceline->rang = $rang; |
||
2267 | $supplierinvoiceline->info_bits = $info_bits; |
||
2268 | $supplierinvoiceline->fk_remise_except = $fk_remise_except; |
||
2269 | |||
2270 | |||
2271 | $supplierinvoiceline->special_code = (int) $special_code; |
||
2272 | $supplierinvoiceline->fk_parent_line = $fk_parent_line; |
||
2273 | $supplierinvoiceline->origin = $this->origin; |
||
2274 | $supplierinvoiceline->origin_id = $origin_id; |
||
2275 | $supplierinvoiceline->fk_unit = $fk_unit; |
||
2276 | |||
2277 | // Multicurrency |
||
2278 | $supplierinvoiceline->fk_multicurrency = $this->fk_multicurrency; |
||
2279 | $supplierinvoiceline->multicurrency_code = $this->multicurrency_code; |
||
2280 | $supplierinvoiceline->multicurrency_subprice = ($this->type == self::TYPE_CREDIT_NOTE ? -abs($pu_ht_devise) : $pu_ht_devise); // For credit note, unit price always negative, always positive otherwise |
||
2281 | |||
2282 | $supplierinvoiceline->multicurrency_total_ht = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($multicurrency_total_ht) : $multicurrency_total_ht); // For credit note and if qty is negative, total is negative |
||
2283 | $supplierinvoiceline->multicurrency_total_tva = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($multicurrency_total_tva) : $multicurrency_total_tva); // For credit note and if qty is negative, total is negative |
||
2284 | $supplierinvoiceline->multicurrency_total_ttc = (($this->type == self::TYPE_CREDIT_NOTE || $qty < 0) ? -abs($multicurrency_total_ttc) : $multicurrency_total_ttc); // For credit note and if qty is negative, total is negative |
||
2285 | |||
2286 | if (is_array($array_options) && count($array_options) > 0) { |
||
2287 | $supplierinvoiceline->array_options = $array_options; |
||
2288 | } |
||
2289 | |||
2290 | $result = $supplierinvoiceline->insert($notrigger); |
||
2291 | if ($result > 0) { |
||
2292 | // Reorder if child line |
||
2293 | if (!empty($fk_parent_line)) { |
||
2294 | $this->line_order(true, 'DESC'); |
||
2295 | } elseif ($rang > 0 && $rang <= count($this->lines)) { // Update all rank of all other lines |
||
2296 | $linecount = count($this->lines); |
||
2297 | for ($ii = $rang; $ii <= $linecount; $ii++) { |
||
2298 | $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii + 1); |
||
2299 | } |
||
2300 | } |
||
2301 | |||
2302 | // Mise a jour information denormalisees au niveau de la facture meme |
||
2303 | $result = $this->update_price(1, 'auto', 0, $this->thirdparty); // The addline method is designed to add line from user input so total calculation with update_price must be done using 'auto' mode. |
||
2304 | if ($result > 0) { |
||
2305 | $this->db->commit(); |
||
2306 | return $supplierinvoiceline->id; |
||
2307 | } else { |
||
2308 | $this->error = $this->db->error(); |
||
2309 | $this->db->rollback(); |
||
2310 | return -1; |
||
2311 | } |
||
2312 | } else { |
||
2313 | $this->error = $supplierinvoiceline->error; |
||
2314 | $this->errors = $supplierinvoiceline->errors; |
||
2315 | $this->db->rollback(); |
||
2316 | return -2; |
||
2317 | } |
||
2318 | } else { |
||
2319 | return 0; |
||
2320 | } |
||
2321 | } |
||
2322 | |||
2323 | /** |
||
2324 | * Update a line detail into database |
||
2325 | * |
||
2326 | * @param int $id Id of line invoice |
||
2327 | * @param string $desc Description of line |
||
2328 | * @param double $pu Prix unitaire (HT ou TTC selon price_base_type) |
||
2329 | * @param double $vatrate VAT Rate (Can be '8.5', '8.5 (ABC)') |
||
2330 | * @param double $txlocaltax1 LocalTax1 Rate |
||
2331 | * @param double $txlocaltax2 LocalTax2 Rate |
||
2332 | * @param double $qty Quantity |
||
2333 | * @param int $idproduct Id produit |
||
2334 | * @param string $price_base_type HT or TTC |
||
2335 | * @param int $info_bits Miscellaneous information of line |
||
2336 | * @param int $type Type of line (0=product, 1=service) |
||
2337 | * @param double $remise_percent Percentage discount of the line |
||
2338 | * @param int $notrigger Disable triggers |
||
2339 | * @param int|string $date_start Date start of service |
||
2340 | * @param int|string $date_end Date end of service |
||
2341 | * @param array $array_options extrafields array |
||
2342 | * @param int|null $fk_unit Code of the unit to use. Null to use the default one |
||
2343 | * @param double $pu_devise Amount in currency |
||
2344 | * @param string $ref_supplier Supplier ref |
||
2345 | * @param int $rang Line rank |
||
2346 | * @return int<-1,1> Return integer <0 if KO, >0 if OK |
||
2347 | */ |
||
2348 | public function updateline($id, $desc, $pu, $vatrate, $txlocaltax1 = 0, $txlocaltax2 = 0, $qty = 1, $idproduct = 0, $price_base_type = 'HT', $info_bits = 0, $type = 0, $remise_percent = 0, $notrigger = 0, $date_start = '', $date_end = '', $array_options = [], $fk_unit = null, $pu_devise = 0, $ref_supplier = '', $rang = 0) |
||
2497 | } |
||
2498 | |||
2499 | /** |
||
2500 | * Delete a detail line from database |
||
2501 | * |
||
2502 | * @param int $rowid Id of line to delete |
||
2503 | * @param int $notrigger 1=Does not execute triggers, 0= execute triggers |
||
2504 | * @return int Return integer <0 if KO, >0 if OK |
||
2505 | */ |
||
2506 | public function deleteLine($rowid, $notrigger = 0) |
||
2507 | { |
||
2508 | if (!$rowid) { |
||
2509 | $rowid = $this->id; |
||
2510 | } |
||
2511 | |||
2512 | $this->db->begin(); |
||
2513 | |||
2514 | // Free the discount linked to a line of invoice |
||
2515 | $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'societe_remise_except'; |
||
2516 | $sql .= ' SET fk_invoice_supplier_line = NULL'; |
||
2517 | $sql .= ' WHERE fk_invoice_supplier_line = ' . ((int) $rowid); |
||
2518 | |||
2519 | dol_syslog(get_only_class($this) . "::deleteline", LOG_DEBUG); |
||
2520 | $result = $this->db->query($sql); |
||
2521 | if (!$result) { |
||
2522 | $this->error = $this->db->error(); |
||
2523 | $this->db->rollback(); |
||
2524 | return -2; |
||
2525 | } |
||
2526 | |||
2527 | $line = new SupplierInvoiceLine($this->db); |
||
2528 | |||
2529 | if ($line->fetch($rowid) < 1) { |
||
2530 | return -1; |
||
2531 | } |
||
2532 | |||
2533 | $res = $line->delete($notrigger); |
||
2534 | |||
2535 | if ($res < 1) { |
||
2536 | $this->errors[] = $line->error; |
||
2537 | $this->db->rollback(); |
||
2538 | return -3; |
||
2539 | } else { |
||
2540 | $res = $this->update_price(1); |
||
2541 | |||
2542 | if ($res > 0) { |
||
2543 | $this->db->commit(); |
||
2544 | return 1; |
||
2545 | } else { |
||
2546 | $this->db->rollback(); |
||
2547 | $this->error = $this->db->lasterror(); |
||
2548 | return -4; |
||
2549 | } |
||
2550 | } |
||
2551 | } |
||
2552 | |||
2553 | |||
2554 | /** |
||
2555 | * Loads the info order information into the invoice object |
||
2556 | * |
||
2557 | * @param int $id Id of the invoice to load |
||
2558 | * @return void |
||
2559 | */ |
||
2560 | public function info($id) |
||
2561 | { |
||
2562 | $sql = 'SELECT c.rowid, datec, tms as datem, '; |
||
2563 | $sql .= ' fk_user_author, fk_user_modif, fk_user_valid'; |
||
2564 | $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_fourn as c'; |
||
2565 | $sql .= ' WHERE c.rowid = ' . ((int) $id); |
||
2566 | |||
2567 | $result = $this->db->query($sql); |
||
2568 | if ($result) { |
||
2569 | if ($this->db->num_rows($result)) { |
||
2570 | $obj = $this->db->fetch_object($result); |
||
2571 | |||
2572 | $this->id = $obj->rowid; |
||
2573 | |||
2574 | $this->user_creation_id = $obj->fk_user_author; |
||
2575 | $this->user_validation_id = $obj->fk_user_valid; |
||
2576 | $this->user_modification_id = $obj->fk_user_modif; |
||
2577 | $this->date_creation = $this->db->jdate($obj->datec); |
||
2578 | $this->date_modification = $this->db->jdate($obj->datem); |
||
2579 | //$this->date_validation = $obj->datev; // This field is not available. Should be store into log table and using this function should be replaced with showing content of log (like for supplier orders) |
||
2580 | } |
||
2581 | $this->db->free($result); |
||
2582 | } else { |
||
2583 | dol_print_error($this->db); |
||
2584 | } |
||
2585 | } |
||
2586 | |||
2587 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps |
||
2588 | /** |
||
2589 | * Return list of replaceable invoices |
||
2590 | * Status valid or abandoned for other reason + not paid + no payment + not already replaced |
||
2591 | * |
||
2592 | * @param int $socid Thirdparty id |
||
2593 | * @return array|int Table of invoices ('id'=>id, 'ref'=>ref, 'status'=>status, 'paymentornot'=>0/1) |
||
2594 | * <0 if error |
||
2595 | */ |
||
2596 | public function list_replacable_supplier_invoices($socid = 0) |
||
2597 | { |
||
2598 | // phpcs:enable |
||
2599 | global $conf; |
||
2600 | |||
2601 | $return = array(); |
||
2602 | |||
2603 | $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut,"; |
||
2604 | $sql .= " ff.rowid as rowidnext"; |
||
2605 | $sql .= " FROM " . MAIN_DB_PREFIX . "facture_fourn as f"; |
||
2606 | $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn"; |
||
2607 | $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "facture_fourn as ff ON f.rowid = ff.fk_facture_source"; |
||
2608 | $sql .= " WHERE (f.fk_statut = " . self::STATUS_VALIDATED . " OR (f.fk_statut = " . self::STATUS_ABANDONED . " AND f.close_code = '" . self::CLOSECODE_ABANDONED . "'))"; |
||
2609 | $sql .= " AND f.entity = " . $conf->entity; |
||
2610 | $sql .= " AND f.paye = 0"; // Pas classee payee completement |
||
2611 | $sql .= " AND pf.fk_paiementfourn IS NULL"; // Aucun paiement deja fait |
||
2612 | $sql .= " AND ff.fk_statut IS NULL"; // Renvoi vrai si pas facture de replacement |
||
2613 | if ($socid > 0) { |
||
2614 | $sql .= " AND f.fk_soc = " . ((int) $socid); |
||
2615 | } |
||
2616 | $sql .= " ORDER BY f.ref"; |
||
2617 | |||
2618 | dol_syslog(get_only_class($this) . "::list_replacable_supplier_invoices", LOG_DEBUG); |
||
2619 | $resql = $this->db->query($sql); |
||
2620 | if ($resql) { |
||
2621 | while ($obj = $this->db->fetch_object($resql)) { |
||
2622 | $return[$obj->rowid] = array( |
||
2623 | 'id' => $obj->rowid, |
||
2624 | 'ref' => $obj->ref, |
||
2625 | 'status' => $obj->fk_statut |
||
2626 | ); |
||
2627 | } |
||
2628 | //print_r($return); |
||
2629 | return $return; |
||
2630 | } else { |
||
2631 | $this->error = $this->db->error(); |
||
2632 | return -1; |
||
2633 | } |
||
2634 | } |
||
2635 | |||
2636 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps |
||
2637 | /** |
||
2638 | * Return list of qualifying invoices for correction by credit note |
||
2639 | * Invoices that respect the following rules are returned: |
||
2640 | * (validated + payment in progress) or classified (paid in full or paid in part) + not already replaced + not already having |
||
2641 | * |
||
2642 | * @param int $socid Thirdparty id |
||
2643 | * @return array|int Table of invoices ($id => array('ref'=>,'paymentornot'=>,'status'=>,'paye'=>) |
||
2644 | * <0 if error |
||
2645 | */ |
||
2646 | public function list_qualified_avoir_supplier_invoices($socid = 0) |
||
2647 | { |
||
2648 | // phpcs:enable |
||
2649 | global $conf; |
||
2650 | |||
2651 | $return = array(); |
||
2652 | |||
2653 | $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut, f.type, f.subtype, f.paye, pf.fk_paiementfourn"; |
||
2654 | $sql .= " FROM " . MAIN_DB_PREFIX . "facture_fourn as f"; |
||
2655 | $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn"; |
||
2656 | $sql .= " WHERE f.entity = " . $conf->entity; |
||
2657 | $sql .= " AND f.fk_statut in (" . self::STATUS_VALIDATED . "," . self::STATUS_CLOSED . ")"; |
||
2658 | $sql .= " AND NOT EXISTS (SELECT rowid from " . MAIN_DB_PREFIX . "facture_fourn as ff WHERE f.rowid = ff.fk_facture_source"; |
||
2659 | $sql .= " AND ff.type=" . self::TYPE_REPLACEMENT . ")"; |
||
2660 | $sql .= " AND f.type != " . self::TYPE_CREDIT_NOTE; // Type non 2 si facture non avoir |
||
2661 | if ($socid > 0) { |
||
2662 | $sql .= " AND f.fk_soc = " . ((int) $socid); |
||
2663 | } |
||
2664 | $sql .= " ORDER BY f.ref"; |
||
2665 | |||
2666 | dol_syslog(get_only_class($this) . "::list_qualified_avoir_supplier_invoices", LOG_DEBUG); |
||
2667 | $resql = $this->db->query($sql); |
||
2668 | if ($resql) { |
||
2669 | while ($obj = $this->db->fetch_object($resql)) { |
||
2670 | $qualified = 0; |
||
2671 | if ($obj->fk_statut == self::STATUS_VALIDATED) { |
||
2672 | $qualified = 1; |
||
2673 | } |
||
2674 | if ($obj->fk_statut == self::STATUS_CLOSED) { |
||
2675 | $qualified = 1; |
||
2676 | } |
||
2677 | if ($qualified) { |
||
2678 | $paymentornot = ($obj->fk_paiementfourn ? 1 : 0); |
||
2679 | $return[$obj->rowid] = array('ref' => $obj->ref, 'status' => $obj->fk_statut, 'type' => $obj->type, 'paye' => $obj->paye, 'paymentornot' => $paymentornot); |
||
2680 | } |
||
2681 | } |
||
2682 | |||
2683 | return $return; |
||
2684 | } else { |
||
2685 | $this->error = $this->db->error(); |
||
2686 | return -1; |
||
2687 | } |
||
2688 | } |
||
2689 | |||
2690 | // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps |
||
2691 | /** |
||
2692 | * Load indicators for dashboard (this->nbtodo and this->nbtodolate) |
||
2693 | * |
||
2694 | * @param User $user Object user |
||
2695 | * @return WorkboardResponse|int Return integer <0 if KO, WorkboardResponse if OK |
||
2696 | */ |
||
2697 | public function load_board($user) |
||
2698 | { |
||
2699 | // phpcs:enable |
||
2700 | global $conf, $langs; |
||
2701 | |||
2702 | $sql = 'SELECT ff.rowid, ff.date_lim_reglement as datefin, ff.fk_statut as status, ff.total_ht, ff.total_ttc'; |
||
2703 | $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_fourn as ff'; |
||
2704 | if (!$user->hasRight("societe", "client", "voir") && !$user->socid) { |
||
2705 | $sql .= " JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON ff.fk_soc = sc.fk_soc AND sc.fk_user = " . ((int) $user->id); |
||
2706 | } |
||
2707 | $sql .= ' WHERE ff.paye = 0'; |
||
2708 | $sql .= " AND ff.fk_statut IN (" . self::STATUS_VALIDATED . ")"; |
||
2709 | $sql .= " AND ff.entity = " . $conf->entity; |
||
2710 | if ($user->socid) { |
||
2711 | $sql .= ' AND ff.fk_soc = ' . ((int) $user->socid); |
||
2712 | } |
||
2713 | |||
2714 | $resql = $this->db->query($sql); |
||
2715 | if ($resql) { |
||
2716 | $langs->load("bills"); |
||
2717 | $now = dol_now(); |
||
2718 | |||
2719 | $response = new WorkboardResponse(); |
||
2720 | $response->warning_delay = $conf->facture->fournisseur->warning_delay / 60 / 60 / 24; |
||
2721 | $response->label = $langs->trans("SupplierBillsToPay"); |
||
2722 | $response->labelShort = $langs->trans("StatusToPay"); |
||
2723 | |||
2724 | $response->url = constant('BASE_URL') . '/fourn/facture/list.php?search_status=1&mainmenu=billing&leftmenu=suppliers_bills'; |
||
2725 | $response->img = img_object($langs->trans("Bills"), "bill"); |
||
2726 | |||
2727 | $facturestatic = new FactureFournisseur($this->db); |
||
2728 | |||
2729 | while ($obj = $this->db->fetch_object($resql)) { |
||
2730 | $facturestatic->date_echeance = $this->db->jdate($obj->datefin); |
||
2731 | $facturestatic->statut = $obj->status; // For backward compatibility |
||
2732 | $facturestatic->status = $obj->status; |
||
2733 | |||
2734 | $response->nbtodo++; |
||
2735 | $response->total += $obj->total_ht; |
||
2736 | |||
2737 | if ($facturestatic->hasDelay()) { |
||
2738 | $response->nbtodolate++; |
||
2739 | $response->url_late = constant('BASE_URL') . '/fourn/facture/list.php?search_option=late&mainmenu=billing&leftmenu=suppliers_bills'; |
||
2740 | } |
||
2741 | } |
||
2742 | |||
2743 | $this->db->free($resql); |
||
2744 | return $response; |
||
2745 | } else { |
||
2746 | dol_print_error($this->db); |
||
2747 | $this->error = $this->db->error(); |
||
2748 | return -1; |
||
2749 | } |
||
2750 | } |
||
2751 | |||
2752 | /** |
||
2753 | * getTooltipContentArray |
||
2754 | * |
||
2755 | * @param array{moretitle?:string} $params ex option, infologin |
||
2756 | * @since v18 |
||
2757 | * @return array{picto:string,ref?:string,refsupplier?:string,label?:string,date?:string,date_echeance?:string,amountht?:string,total_ht?:string,totaltva?:string,amountlt1?:string,amountlt2?:string,amountrevenustamp?:string,totalttc?:string} |
||
2758 | */ |
||
2759 | public function getTooltipContentArray($params) |
||
2760 | { |
||
2761 | global $conf, $langs, $mysoc; |
||
2762 | |||
2763 | $langs->load('bills'); |
||
2764 | |||
2765 | $datas = []; |
||
2766 | $moretitle = $params['moretitle'] ?? ''; |
||
2767 | |||
2768 | $picto = $this->picto; |
||
2769 | if ($this->type == self::TYPE_REPLACEMENT) { |
||
2770 | $picto .= 'r'; // Replacement invoice |
||
2771 | } |
||
2772 | if ($this->type == self::TYPE_CREDIT_NOTE) { |
||
2773 | $picto .= 'a'; // Credit note |
||
2774 | } |
||
2775 | if ($this->type == self::TYPE_DEPOSIT) { |
||
2776 | $picto .= 'd'; // Deposit invoice |
||
2777 | } |
||
2778 | |||
2779 | $datas['picto'] = img_picto('', $picto) . ' <u class="paddingrightonly">' . $langs->trans("SupplierInvoice") . '</u>'; |
||
2780 | if ($this->type == self::TYPE_REPLACEMENT) { |
||
2781 | $datas['picto'] .= '<u class="paddingrightonly">' . $langs->transnoentitiesnoconv("InvoiceReplace") . '</u>'; |
||
2782 | } elseif ($this->type == self::TYPE_CREDIT_NOTE) { |
||
2783 | $datas['picto'] .= '<u class="paddingrightonly">' . $langs->transnoentitiesnoconv("CreditNote") . '</u>'; |
||
2784 | } elseif ($this->type == self::TYPE_DEPOSIT) { |
||
2785 | $datas['picto'] .= '<u class="paddingrightonly">' . $langs->transnoentitiesnoconv("Deposit") . '</u>'; |
||
2786 | } |
||
2787 | if (isset($this->status)) { |
||
2788 | $alreadypaid = -1; |
||
2789 | if (isset($this->totalpaid)) { |
||
2790 | $alreadypaid = $this->totalpaid; |
||
2791 | } |
||
2792 | |||
2793 | $datas['picto'] .= ' ' . $this->getLibStatut(5, $alreadypaid); |
||
2794 | } |
||
2795 | if ($moretitle) { |
||
2796 | $datas['picto'] .= ' - ' . $moretitle; |
||
2797 | } |
||
2798 | if (!empty($this->ref)) { |
||
2799 | $datas['ref'] = '<br><b>' . $langs->trans('Ref') . ':</b> ' . $this->ref; |
||
2800 | } |
||
2801 | if (!empty($this->ref_supplier)) { |
||
2802 | $datas['refsupplier'] = '<br><b>' . $langs->trans('RefSupplier') . ':</b> ' . $this->ref_supplier; |
||
2803 | } |
||
2804 | if (!empty($this->label)) { |
||
2805 | $datas['label'] = '<br><b>' . $langs->trans('Label') . ':</b> ' . $this->label; |
||
2806 | } |
||
2807 | if (!empty($this->date)) { |
||
2808 | $datas['date'] = '<br><b>' . $langs->trans('Date') . ':</b> ' . dol_print_date($this->date, 'day'); |
||
2809 | } |
||
2810 | if (!empty($this->date_echeance)) { |
||
2811 | $datas['date_echeance'] = '<br><b>' . $langs->trans('DateDue') . ':</b> ' . dol_print_date($this->date_echeance, 'day'); |
||
2812 | } |
||
2813 | if (!empty($this->total_ht)) { |
||
2814 | $datas['amountht'] = '<br><b>' . $langs->trans('AmountHT') . ':</b> ' . price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency); |
||
2815 | } |
||
2816 | if (!empty($this->total_tva)) { |
||
2817 | $datas['totaltva'] = '<br><b>' . $langs->trans('AmountVAT') . ':</b> ' . price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency); |
||
2818 | } |
||
2819 | if (!empty($this->total_localtax1) && $this->total_localtax1 != 0) { |
||
2820 | // We keep test != 0 because $this->total_localtax1 can be '0.00000000' |
||
2821 | $datas['amountlt1'] = '<br><b>' . $langs->transcountry('AmountLT1', $mysoc->country_code) . ':</b> ' . price($this->total_localtax1, 0, $langs, 0, -1, -1, $conf->currency); |
||
2822 | } |
||
2823 | if (!empty($this->total_localtax2) && $this->total_localtax2 != 0) { |
||
2824 | $datas['amountlt2'] = '<br><b>' . $langs->transcountry('AmountLT2', $mysoc->country_code) . ':</b> ' . price($this->total_localtax2, 0, $langs, 0, -1, -1, $conf->currency); |
||
2825 | } |
||
2826 | if (!empty($this->revenuestamp)) { |
||
2827 | $datas['amountrevenustamp'] = '<br><b>' . $langs->trans('RevenueStamp') . ':</b> ' . price($this->revenuestamp, 0, $langs, 0, -1, -1, $conf->currency); |
||
2828 | } |
||
2829 | if (!empty($this->total_ttc)) { |
||
2830 | $datas['totalttc'] = '<br><b>' . $langs->trans('AmountTTC') . ':</b> ' . price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency); |
||
2831 | } |
||
2832 | return $datas; |
||
2833 | } |
||
2834 | |||
2835 | /** |
||
2836 | * Return clicable name (with picto eventually) |
||
2837 | * |
||
2838 | * @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto |
||
2839 | * @param string $option Where point the link |
||
2840 | * @param int $max Max length of shown ref |
||
2841 | * @param int $short 1=Return just URL |
||
2842 | * @param string $moretitle Add more text to title tooltip |
||
2843 | * @param int $notooltip 1=Disable tooltip |
||
2844 | * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking |
||
2845 | * @param int $addlinktonotes Add link to show notes |
||
2846 | * @return string String with URL |
||
2847 | */ |
||
2848 | public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0) |
||
2849 | { |
||
2850 | global $langs, $conf, $user, $hookmanager; |
||
2851 | |||
2852 | $result = ''; |
||
2853 | |||
2854 | if ($option == 'withdraw') { |
||
2855 | $url = constant('BASE_URL') . '/compta/facture/prelevement.php?facid=' . $this->id . '&type=bank-transfer'; |
||
2856 | } elseif ($option == 'document') { |
||
2857 | $url = constant('BASE_URL') . '/fourn/facture/document.php?facid=' . $this->id; |
||
2858 | } else { |
||
2859 | $url = constant('BASE_URL') . '/fourn/facture/card.php?facid=' . $this->id; |
||
2860 | } |
||
2861 | |||
2862 | if ($short) { |
||
2863 | return $url; |
||
2864 | } |
||
2865 | |||
2866 | if ($option !== 'nolink') { |
||
2867 | // Add param to save lastsearch_values or not |
||
2868 | $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); |
||
2869 | if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) { |
||
2870 | $add_save_lastsearch_values = 1; |
||
2871 | } |
||
2872 | if ($add_save_lastsearch_values) { |
||
2873 | $url .= '&save_lastsearch_values=1'; |
||
2874 | } |
||
2875 | } |
||
2876 | |||
2877 | $picto = $this->picto; |
||
2878 | if ($this->type == self::TYPE_REPLACEMENT) { |
||
2879 | $picto .= 'r'; // Replacement invoice |
||
2880 | } |
||
2881 | if ($this->type == self::TYPE_CREDIT_NOTE) { |
||
2882 | $picto .= 'a'; // Credit note |
||
2883 | } |
||
2884 | if ($this->type == self::TYPE_DEPOSIT) { |
||
2885 | $picto .= 'd'; // Deposit invoice |
||
2886 | } |
||
2887 | |||
2888 | $params = [ |
||
2889 | 'id' => $this->id, |
||
2890 | 'objecttype' => $this->element, |
||
2891 | 'option' => $option, |
||
2892 | 'moretitle' => $moretitle, |
||
2893 | ]; |
||
2894 | $classfortooltip = 'classfortooltip'; |
||
2895 | $dataparams = ''; |
||
2896 | if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { |
||
2897 | $classfortooltip = 'classforajaxtooltip'; |
||
2898 | $dataparams = ' data-params="' . dol_escape_htmltag(json_encode($params)) . '"'; |
||
2899 | $label = ''; |
||
2900 | } else { |
||
2901 | $label = implode($this->getTooltipContentArray($params)); |
||
2902 | } |
||
2903 | |||
2904 | $ref = $this->ref; |
||
2905 | if (empty($ref)) { |
||
2906 | $ref = $this->id; |
||
2907 | } |
||
2908 | |||
2909 | $linkclose = ''; |
||
2910 | if (empty($notooltip)) { |
||
2911 | if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) { |
||
2912 | $label = $langs->trans("ShowSupplierInvoice"); |
||
2913 | $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"'; |
||
2914 | } |
||
2915 | $linkclose .= ($label ? ' title="' . dol_escape_htmltag($label, 1) . '"' : ' title="tocomplete"'); |
||
2916 | $linkclose .= $dataparams . ' class="' . $classfortooltip . '"'; |
||
2917 | } |
||
2918 | |||
2919 | $linkstart = '<a href="' . $url . '"'; |
||
2920 | $linkstart .= $linkclose . '>'; |
||
2921 | $linkend = '</a>'; |
||
2922 | |||
2923 | $result .= $linkstart; |
||
2924 | if ($withpicto) { |
||
2925 | $result .= img_object(($notooltip ? '' : $label), ($picto ? $picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . '"'), 0, 0, $notooltip ? 0 : 1); |
||
2926 | } |
||
2927 | if ($withpicto != 2) { |
||
2928 | $result .= ($max ? dol_trunc($ref, $max) : $ref); |
||
2929 | } |
||
2930 | $result .= $linkend; |
||
2931 | |||
2932 | if ($addlinktonotes) { |
||
2933 | $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private); |
||
2934 | if ($txttoshow) { |
||
2935 | $notetoshow = $langs->trans("ViewPrivateNote") . ':<br>' . dol_string_nohtmltag($txttoshow, 1); |
||
2936 | $result .= ' <span class="note inline-block">'; |
||
2937 | $result .= '<a href="' . constant('BASE_URL') . '/fourn/facture/note.php?id=' . $this->id . '" class="classfortooltip" title="' . dol_escape_htmltag($notetoshow) . '">'; |
||
2938 | $result .= img_picto('', 'note'); |
||
2939 | $result .= '</a>'; |
||
2940 | $result .= '</span>'; |
||
2941 | } |
||
2942 | } |
||
2943 | global $action; |
||
2944 | $hookmanager->initHooks(array($this->element . 'dao')); |
||
2945 | $parameters = array('id' => $this->id, 'getnomurl' => &$result); |
||
2946 | $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks |
||
2947 | if ($reshook > 0) { |
||
2948 | $result = $hookmanager->resPrint; |
||
2949 | } else { |
||
2950 | $result .= $hookmanager->resPrint; |
||
2951 | } |
||
2952 | return $result; |
||
2953 | } |
||
2954 | |||
2955 | /** |
||
2956 | * Return next reference of supplier invoice not already used (or last reference) |
||
2957 | * according to numbering module defined into constant INVOICE_SUPPLIER_ADDON_NUMBER |
||
2958 | * |
||
2959 | * @param Societe $soc Thirdparty object |
||
2960 | * @param string $mode 'next' for next value or 'last' for last value |
||
2961 | * @return string|-1 Returns free reference or last reference, or '' or -1 if error |
||
2962 | */ |
||
2963 | public function getNextNumRef($soc, $mode = 'next') |
||
2964 | { |
||
2965 | global $db, $langs, $conf; |
||
2966 | $langs->load("orders"); |
||
2967 | |||
2968 | // Clean parameters (if not defined or using deprecated value) |
||
2969 | if (!getDolGlobalString('INVOICE_SUPPLIER_ADDON_NUMBER')) { |
||
2970 | $conf->global->INVOICE_SUPPLIER_ADDON_NUMBER = 'mod_facture_fournisseur_cactus'; |
||
2971 | } |
||
2972 | |||
2973 | $mybool = false; |
||
2974 | |||
2975 | $file = getDolGlobalString('INVOICE_SUPPLIER_ADDON_NUMBER') . ".php"; |
||
2976 | $classname = getDolGlobalString('INVOICE_SUPPLIER_ADDON_NUMBER'); |
||
2977 | |||
2978 | // Include file with class |
||
2979 | $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); |
||
2980 | |||
2981 | foreach ($dirmodels as $reldir) { |
||
2982 | $dir = dol_buildpath($reldir . "core/modules/supplier_invoice/"); |
||
2983 | |||
2984 | // Load file with numbering class (if found) |
||
2985 | $mybool = ((bool) @include_once $dir . $file) || $mybool; |
||
2986 | } |
||
2987 | |||
2988 | if (!$mybool) { |
||
2989 | dol_print_error(null, "Failed to include file " . $file); |
||
2990 | return ''; |
||
2991 | } |
||
2992 | |||
2993 | $obj = new $classname(); |
||
2994 | '@phan-var-force ModeleNumRefSuppliersInvoices $obj'; |
||
2995 | $numref = ""; |
||
2996 | $numref = $obj->getNextValue($soc, $this, $mode); |
||
2997 | |||
2998 | if ($numref != "") { |
||
2999 | return $numref; |
||
3000 | } else { |
||
3001 | $this->error = $obj->error; |
||
3002 | return -1; |
||
3003 | } |
||
3004 | } |
||
3005 | |||
3006 | |||
3007 | /** |
||
3008 | * Initialise an instance with random values. |
||
3009 | * Used to build previews or test instances. |
||
3010 | * id must be 0 if object instance is a specimen. |
||
3011 | * |
||
3012 | * @param string $option ''=Create a specimen invoice with lines, 'nolines'=No lines |
||
3013 | * @return int |
||
3014 | */ |
||
3015 | public function initAsSpecimen($option = '') |
||
3016 | { |
||
3017 | global $langs, $conf; |
||
3018 | |||
3019 | $now = dol_now(); |
||
3020 | |||
3021 | // Load array of products prodids |
||
3022 | $num_prods = 0; |
||
3023 | $prodids = array(); |
||
3024 | |||
3025 | $sql = "SELECT rowid"; |
||
3026 | $sql .= " FROM " . MAIN_DB_PREFIX . "product"; |
||
3027 | $sql .= " WHERE entity IN (" . getEntity('product') . ")"; |
||
3028 | $sql .= $this->db->plimit(100); |
||
3029 | |||
3030 | $resql = $this->db->query($sql); |
||
3031 | if ($resql) { |
||
3032 | $num_prods = $this->db->num_rows($resql); |
||
3033 | $i = 0; |
||
3034 | while ($i < $num_prods) { |
||
3035 | $i++; |
||
3036 | $row = $this->db->fetch_row($resql); |
||
3037 | $prodids[$i] = $row[0]; |
||
3038 | } |
||
3039 | } |
||
3040 | |||
3041 | // Initialise parameters |
||
3042 | $this->id = 0; |
||
3043 | $this->ref = 'SPECIMEN'; |
||
3044 | $this->ref_supplier = 'SUPPLIER_REF_SPECIMEN'; |
||
3045 | $this->specimen = 1; |
||
3046 | $this->socid = 1; |
||
3047 | $this->date = $now; |
||
3048 | $this->date_lim_reglement = $this->date + 3600 * 24 * 30; |
||
3049 | $this->cond_reglement_code = 'RECEP'; |
||
3050 | $this->mode_reglement_code = 'CHQ'; |
||
3051 | |||
3052 | $this->note_public = 'This is a comment (public)'; |
||
3053 | $this->note_private = 'This is a comment (private)'; |
||
3054 | |||
3055 | $this->multicurrency_tx = 1; |
||
3056 | $this->multicurrency_code = $conf->currency; |
||
3057 | |||
3058 | $xnbp = 0; |
||
3059 | if (empty($option) || $option != 'nolines') { |
||
3060 | // Lines |
||
3061 | $nbp = 5; |
||
3062 | while ($xnbp < $nbp) { |
||
3063 | $line = new SupplierInvoiceLine($this->db); |
||
3064 | $line->desc = $langs->trans("Description") . " " . $xnbp; |
||
3065 | $line->qty = 1; |
||
3066 | $line->subprice = 100; |
||
3067 | $line->pu_ht = $line->subprice; // the canelle template use pu_ht and not subprice |
||
3068 | $line->price = 100; |
||
3069 | $line->tva_tx = 19.6; |
||
3070 | $line->localtax1_tx = 0; |
||
3071 | $line->localtax2_tx = 0; |
||
3072 | if ($xnbp == 2) { |
||
3073 | $line->total_ht = 50; |
||
3074 | $line->total_ttc = 59.8; |
||
3075 | $line->total_tva = 9.8; |
||
3076 | $line->remise_percent = 50; |
||
3077 | } else { |
||
3078 | $line->total_ht = 100; |
||
3079 | $line->total_ttc = 119.6; |
||
3080 | $line->total_tva = 19.6; |
||
3081 | $line->remise_percent = 0; |
||
3082 | } |
||
3083 | |||
3084 | if ($num_prods > 0) { |
||
3085 | $prodid = mt_rand(1, $num_prods); |
||
3086 | $line->fk_product = $prodids[$prodid]; |
||
3087 | } |
||
3088 | $line->product_type = 0; |
||
3089 | |||
3090 | $this->lines[$xnbp] = $line; |
||
3091 | |||
3092 | $this->total_ht += $line->total_ht; |
||
3093 | $this->total_tva += $line->total_tva; |
||
3094 | $this->total_ttc += $line->total_ttc; |
||
3095 | |||
3096 | $xnbp++; |
||
3097 | } |
||
3098 | } |
||
3099 | |||
3100 | $this->total_ht = $xnbp * 100; |
||
3101 | $this->total_tva = $xnbp * 19.6; |
||
3102 | $this->total_ttc = $xnbp * 119.6; |
||
3103 | |||
3104 | return 1; |
||
3105 | } |
||
3106 | |||
3107 | /** |
||
3108 | * Load indicators for dashboard (this->nbtodo and this->nbtodolate) |
||
3109 | * |
||
3110 | * @return int Return integer <0 if KO, >0 if OK |
||
3111 | */ |
||
3112 | public function loadStateBoard() |
||
3113 | { |
||
3114 | global $conf, $user; |
||
3115 | |||
3116 | $this->nb = array(); |
||
3117 | |||
3118 | $clause = "WHERE"; |
||
3119 | |||
3120 | $sql = "SELECT count(f.rowid) as nb"; |
||
3121 | $sql .= " FROM " . MAIN_DB_PREFIX . "facture_fourn as f"; |
||
3122 | $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s ON f.fk_soc = s.rowid"; |
||
3123 | if (!$user->hasRight("societe", "client", "voir") && !$user->socid) { |
||
3124 | $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON s.rowid = sc.fk_soc"; |
||
3125 | $sql .= " WHERE sc.fk_user = " . ((int) $user->id); |
||
3126 | $clause = "AND"; |
||
3127 | } |
||
3128 | $sql .= " " . $clause . " f.entity = " . $conf->entity; |
||
3129 | |||
3130 | $resql = $this->db->query($sql); |
||
3131 | if ($resql) { |
||
3132 | while ($obj = $this->db->fetch_object($resql)) { |
||
3133 | $this->nb["supplier_invoices"] = $obj->nb; |
||
3134 | } |
||
3135 | $this->db->free($resql); |
||
3136 | return 1; |
||
3137 | } else { |
||
3138 | dol_print_error($this->db); |
||
3139 | $this->error = $this->db->error(); |
||
3140 | return -1; |
||
3141 | } |
||
3142 | } |
||
3143 | |||
3144 | /** |
||
3145 | * Load an object from its id and create a new one in database |
||
3146 | * |
||
3147 | * @param User $user User that clone |
||
3148 | * @param int $fromid Id of object to clone |
||
3149 | * @param int $invertdetail Reverse sign of amounts for lines |
||
3150 | * @return int New id of clone |
||
3151 | */ |
||
3152 | public function createFromClone(User $user, $fromid, $invertdetail = 0) |
||
3218 | } |
||
3219 | } |
||
3220 | |||
3221 | /** |
||
3222 | * Create a document onto disk according to template model. |
||
3223 | * |
||
3224 | * @param string $modele Force template to use ('' to not force) |
||
3225 | * @param Translate $outputlangs Object lang a utiliser pour traduction |
||
3226 | * @param int $hidedetails Hide details of lines |
||
3227 | * @param int $hidedesc Hide description |
||
3228 | * @param int $hideref Hide ref |
||
3229 | * @param ?array<string,mixed> $moreparams Array to provide more information |
||
3230 | * @return int<-1,1> Return integer <0 if KO, 0 if nothing done, >0 if OK |
||
3231 | */ |
||
3232 | public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null) |
||
3233 | { |
||
3234 | global $langs; |
||
3235 | |||
3236 | $langs->load("suppliers"); |
||
3237 | $outputlangs->load("products"); |
||
3238 | |||
3239 | // Set the model on the model name to use |
||
3240 | if (empty($modele)) { |
||
3241 | if (getDolGlobalString('INVOICE_SUPPLIER_ADDON_PDF')) { |
||
3242 | $modele = getDolGlobalString('INVOICE_SUPPLIER_ADDON_PDF'); |
||
3243 | } else { |
||
3244 | $modele = ''; // No default value. For supplier invoice, we allow to disable all PDF generation |
||
3245 | } |
||
3246 | } |
||
3247 | |||
3248 | if (empty($modele)) { |
||
3249 | return 0; |
||
3250 | } else { |
||
3251 | $modelpath = "core/modules/supplier_invoice/doc/"; |
||
3252 | |||
3253 | return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); |
||
3254 | } |
||
3255 | } |
||
3256 | |||
3257 | /** |
||
3258 | * Returns the rights used for this class |
||
3259 | * @return int |
||
3260 | */ |
||
3261 | public function getRights() |
||
3262 | { |
||
3263 | global $user; |
||
3264 | |||
3265 | return $user->hasRight("fournisseur", "facture"); |
||
3266 | } |
||
3267 | |||
3268 | /** |
||
3269 | * Function used to replace a thirdparty id with another one. |
||
3270 | * |
||
3271 | * @param DoliDB $dbs Database handler, because function is static we name it $dbs not $db to avoid breaking coding test |
||
3272 | * @param int $origin_id Old thirdparty id |
||
3273 | * @param int $dest_id New thirdparty id |
||
3274 | * @return bool |
||
3275 | */ |
||
3276 | public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id) |
||
3283 | } |
||
3284 | |||
3285 | /** |
||
3286 | * Function used to replace a product id with another one. |
||
3287 | * |
||
3288 | * @param DoliDB $db Database handler |
||
3289 | * @param int $origin_id Old product id |
||
3290 | * @param int $dest_id New product id |
||
3291 | * @return bool |
||
3292 | */ |
||
3293 | public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) |
||
3294 | { |
||
3295 | $tables = array( |
||
3296 | 'facture_fourn_det' |
||
3297 | ); |
||
3298 | |||
3299 | return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); |
||
3300 | } |
||
3301 | |||
3302 | /** |
||
3303 | * Is the payment of the supplier invoice having a delay? |
||
3304 | * |
||
3305 | * @return bool |
||
3306 | */ |
||
3307 | public function hasDelay() |
||
3320 | } |
||
3321 | |||
3322 | /** |
||
3323 | * Is credit note used |
||
3324 | * |
||
3325 | * @return bool |
||
3326 | */ |
||
3327 | public function isCreditNoteUsed() |
||
3328 | { |
||
3329 | $isUsed = false; |
||
3330 | |||
3331 | $sql = "SELECT fk_invoice_supplier FROM " . MAIN_DB_PREFIX . "societe_remise_except WHERE fk_invoice_supplier_source = " . ((int) $this->id); |
||
3332 | $resql = $this->db->query($sql); |
||
3333 | if (!empty($resql)) { |
||
3334 | $obj = $this->db->fetch_object($resql); |
||
3335 | if (!empty($obj->fk_invoice_supplier)) { |
||
3336 | $isUsed = true; |
||
3337 | } |
||
3338 | } |
||
3339 | |||
3340 | return $isUsed; |
||
3341 | } |
||
3342 | /** |
||
3343 | * Return clicable link of object (with eventually picto) |
||
3344 | * |
||
3345 | * @param string $option Where point the link (0=> main card, 1,2 => shipment, 'nolink'=>No link) |
||
3346 | * @param ?array{selected?:int<0,1>} $arraydata Array of data |
||
3347 | * @return string HTML Code for Kanban thumb. |
||
3348 | */ |
||
3349 | public function getKanbanView($option = '', $arraydata = null) |
||
3395 | } |
||
3396 | |||
3397 | /** |
||
3398 | * Change the option VAT reverse charge |
||
3399 | * |
||
3400 | * @param int $vatreversecharge 0 = Off, 1 = On |
||
3401 | * @return int 1 if OK, 0 if KO |
||
3402 | */ |
||
3403 | public function setVATReverseCharge($vatreversecharge) |
||
3423 | } |
||
3424 | } |
||
3425 | |||
3426 | /** |
||
3427 | * Send reminders by emails for supplier invoices validated that are due. |
||
3428 | * CAN BE A CRON TASK |
||
3429 | * |
||
3430 | * @param int $nbdays Delay before due date (or after if delay is negative) |
||
3431 | * @param string $paymentmode '' or 'all' by default (no filter), or 'LIQ', 'CHQ', CB', ... |
||
3432 | * @param int|string $template Name (or id) of email template (Must be a template of type 'invoice_supplier_send') |
||
3433 | * @param string $datetouse 'duedate' (default) or 'invoicedate' |
||
3434 | * @param string $forcerecipient Force email of recipient (for example to send the email to an accountant supervisor instead of the customer) |
||
3435 | * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) |
||
3436 | */ |
||
3437 | public function sendEmailsRemindersOnSupplierInvoiceDueDate($nbdays = 0, $paymentmode = 'all', $template = '', $datetouse = 'duedate', $forcerecipient = '') |
||
3727 | } |
||
3728 | } |
||
3729 | } |
||
3730 |
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.