Passed
Pull Request — dev (#6)
by Rafael
79:24 queued 24:08
created

Paiement::addPaymentToBank()   F

Complexity

Conditions 35
Paths > 20000

Size

Total Lines 182
Code Lines 120

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 35
eloc 120
nc 30004
nop 9
dl 0
loc 182
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/* Copyright (C) 2002-2004  Rodolphe Quiedeville    <[email protected]>
4
 * Copyright (C) 2004-2010  Laurent Destailleur     <[email protected]>
5
 * Copyright (C) 2005       Marc Barilley / Ocebo   <[email protected]>
6
 * Copyright (C) 2012       Cédric Salvador       <[email protected]>
7
 * Copyright (C) 2014       Raphaël Doursenaud    <[email protected]>
8
 * Copyright (C) 2014       Marcos García 		 <[email protected]>
9
 * Copyright (C) 2015       Juanjo Menent		 <[email protected]>
10
 * Copyright (C) 2018       Ferran Marcet		 <[email protected]>
11
 * Copyright (C) 2018       Thibault FOUCART		<[email protected]>
12
 * Copyright (C) 2018-2024  Frédéric France         <[email protected]>
13
 * Copyright (C) 2020       Andreu Bisquerra Gaya 	<[email protected]>
14
 * Copyright (C) 2021       OpenDsi					<[email protected]>
15
 * Copyright (C) 2023       Joachim Kueter			<[email protected]>
16
 * Copyright (C) 2023       Sylvain Legrand			<[email protected]>
17
 * Copyright (C) 2024		MDW							<[email protected]>
18
 * Copyright (C) 2024       Rafael San José             <[email protected]>
19
 *
20
 * This program is free software; you can redistribute it and/or modify
21
 * it under the terms of the GNU General Public License as published by
22
 * the Free Software Foundation; either version 3 of the License, or
23
 * (at your option) any later version.
24
 *
25
 * This program is distributed in the hope that it will be useful,
26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28
 * GNU General Public License for more details.
29
 *
30
 * You should have received a copy of the GNU General Public License
31
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
32
 */
33
34
namespace Dolibarr\Code\Compta\Classes;
35
36
/**
37
 *  \file       htdocs/compta/paiement/class/paiement.class.php
38
 *  \ingroup    invoice
39
 *  \brief      File of class to manage payments of customers invoices
40
 */
41
42
use Dolibarr\Core\Base\CommonObject;
43
use Dolibarr\Code\MultiCurrency\Classes\MultiCurrency;
44
45
/**
46
 *  Class to manage payments of customer invoices
47
 */
48
class Paiement extends CommonObject
49
{
50
    /**
51
     * @var string ID to identify managed object
52
     */
53
    public $element = 'payment';
54
55
    /**
56
     * @var string Name of table without prefix where object is stored
57
     */
58
    public $table_element = 'paiement';
59
60
    /**
61
     * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
62
     */
63
    public $picto = 'payment';
64
65
    /**
66
     * @var int                         Invoice ID
67
     */
68
    public $facid;
69
70
    /**
71
     * @var int                         Company ID
72
     */
73
    public $socid;
74
75
    /**
76
     * @var int|string
77
     */
78
    public $datepaye;
79
80
    /**
81
     * @var int|string                  same than $datepaye
82
     */
83
    public $date;
84
85
    /**
86
     * @deprecated
87
     * @see $amount, $amounts
88
     */
89
    public $total;
90
91
    /**
92
     * @deprecated
93
     * @see $amount, $amounts
94
     */
95
    public $montant;
96
97
    /**
98
     * @var float                           Total amount of payment (in the main currency)
99
     */
100
    public $amount;
101
102
    /**
103
     * @var float                           Total amount of payment (in the currency of the bank account)
104
     */
105
    public $multicurrency_amount;
106
107
    /**
108
     * @var float[] array: invoice ID => amount for that invoice (in the main currency)
109
     */
110
    public $amounts = array();
111
112
    /**
113
     * @var float[] array: invoice ID => amount for that invoice (in the invoice's currency)
114
     */
115
    public $multicurrency_amounts = array();
116
117
    /**
118
     * @var float[] Multicurrency rate (array: invoice ID => currency rate ("taux" in French) for that invoice)
119
     */
120
    public $multicurrency_tx = array();
121
122
    /**
123
     * @var string[] Multicurrency code (array: invoice ID => currency code for that invoice)
124
     */
125
    public $multicurrency_code = array();
126
127
    /**
128
     * @var float                           Excess received in TakePOS cash payment
129
     */
130
    public $pos_change = 0.0;
131
132
    public $author;
133
134
    /**
135
     * @var int                             ID of mode of payment. Is saved into fields fk_paiement on llx_paiement = id of llx_c_paiement. Can get value from code using ...
136
     */
137
    public $paiementid;
138
139
    /**
140
     * @var string                          Code of mode of payment.
141
     */
142
    public $paiementcode;
143
144
    /**
145
     * @var string                          Type of payment label
146
     */
147
    public $type_label;
148
149
    /**
150
     * @var string                          Type of payment code (seems duplicate with $paiementcode);
151
     */
152
    public $type_code;
153
154
    /**
155
     * @var string
156
     * @deprecated
157
     * @see $num_payment
158
     */
159
    public $num_paiement;
160
161
    /**
162
     * @var string      Payment reference
163
     *                  (Cheque or bank transfer reference. Can be "ABC123")
164
     */
165
    public $num_payment;
166
167
    /**
168
     * @var string Id of external payment mode
169
     */
170
    public $ext_payment_id;
171
172
    /**
173
     * @var string Id of prelevement
174
     */
175
    public $id_prelevement;
176
177
    /**
178
     * @var string num_prelevement
179
     */
180
    public $num_prelevement;
181
182
    /**
183
     * @var string Name of external payment mode
184
     */
185
    public $ext_payment_site;
186
187
    /**
188
     * @var int bank account id of payment
189
     * @deprecated
190
     * @see $fk_account
191
     */
192
    public $bank_account;
193
194
    /**
195
     * @var int bank account id of payment
196
     */
197
    public $fk_account;
198
199
    /**
200
     * @var int id of payment line in bank account
201
     */
202
    public $bank_line;
203
204
    // fk_paiement dans llx_paiement est l'id du type de paiement (7 pour CHQ, ...)
205
    // fk_paiement dans llx_paiement_facture est le rowid du paiement
206
    /**
207
     * @var int payment id
208
     */
209
    public $fk_paiement; // Type of payment
210
211
    /**
212
     * @var string payment external reference
213
     */
214
    public $ref_ext;
215
216
217
    /**
218
     *  Constructor
219
     *
220
     *  @param      DoliDB      $db      Database handler
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Compta\Classes\DoliDB was not found. Did you mean DoliDB? If so, make sure to prefix the type with \.
Loading history...
221
     */
222
    public function __construct($db)
223
    {
224
        $this->db = $db;
225
    }
226
227
    /**
228
     *    Load payment from database
229
     *
230
     *    @param    int     $id         Id of payment to get
231
     *    @param    string  $ref        Ref of payment to get (currently ref = id but this may change in future)
232
     *    @param    int     $fk_bank    Id of bank line associated to payment
233
     *    @return   int                 Return integer <0 if KO, 0 if not found, >0 if OK
234
     */
235
    public function fetch($id, $ref = '', $fk_bank = 0)
236
    {
237
        $sql = 'SELECT p.rowid, p.ref, p.ref_ext, p.datep as dp, p.amount, p.statut, p.ext_payment_id, p.ext_payment_site, p.fk_bank, p.multicurrency_amount,';
238
        $sql .= ' c.code as type_code, c.libelle as type_label,';
239
        $sql .= ' p.num_paiement as num_payment, p.note,';
240
        $sql .= ' b.fk_account';
241
        $sql .= ' FROM ' . MAIN_DB_PREFIX . 'paiement as p LEFT JOIN ' . MAIN_DB_PREFIX . 'c_paiement as c ON p.fk_paiement = c.id';
242
        $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'bank as b ON p.fk_bank = b.rowid';
243
        $sql .= ' WHERE p.entity IN (' . getEntity('invoice') . ')';
244
        if ($id > 0) {
245
            $sql .= ' AND p.rowid = ' . ((int) $id);
246
        } elseif ($ref) {
247
            $sql .= " AND p.ref = '" . $this->db->escape($ref) . "'";
248
        } elseif ($fk_bank) {
249
            $sql .= ' AND p.fk_bank = ' . ((int) $fk_bank);
250
        }
251
252
        $resql = $this->db->query($sql);
253
        if ($resql) {
254
            if ($this->db->num_rows($resql)) {
255
                $obj = $this->db->fetch_object($resql);
256
257
                $this->id             = $obj->rowid;
258
                $this->ref            = $obj->ref ? $obj->ref : $obj->rowid;
259
                $this->ref_ext        = $obj->ref_ext;
260
                $this->date           = $this->db->jdate($obj->dp);
261
                $this->datepaye       = $this->db->jdate($obj->dp);
262
                $this->num_payment    = $obj->num_payment;
263
                $this->montant        = $obj->amount; // deprecated
264
                $this->amount         = $obj->amount;
265
                $this->multicurrency_amount = $obj->multicurrency_amount;
266
                $this->note           = $obj->note;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$note has been deprecated: Use $note_private instead. ( Ignorable by Annotation )

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

266
                /** @scrutinizer ignore-deprecated */ $this->note           = $obj->note;

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

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

Loading history...
267
                $this->note_private   = $obj->note;
268
                $this->type_label = $obj->type_label;
269
                $this->type_code      = $obj->type_code;
270
                $this->statut         = $obj->statut;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$statut has been deprecated: Use $status instead. ( Ignorable by Annotation )

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

270
                /** @scrutinizer ignore-deprecated */ $this->statut         = $obj->statut;

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

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

Loading history...
271
                $this->ext_payment_id = $obj->ext_payment_id;
272
                $this->ext_payment_site = $obj->ext_payment_site;
273
274
                $this->bank_account   = $obj->fk_account; // deprecated
275
                $this->fk_account     = $obj->fk_account;
276
                $this->bank_line      = $obj->fk_bank;
277
278
                $this->db->free($resql);
279
                return 1;
280
            } else {
281
                $this->db->free($resql);
282
                return 0;
283
            }
284
        } else {
285
            dol_print_error($this->db);
286
            return -1;
287
        }
288
    }
289
290
    /**
291
     *  Create payment of invoices into database.
292
     *  Use this->amounts to have list of invoices for the payment.
293
     *  For payment of a customer invoice, amounts are positive, for payment of credit note, amounts are negative
294
     *
295
     *  @param  User      $user                 Object user
296
     *  @param  int       $closepaidinvoices    1=Also close paid invoices to paid, 0=Do nothing more
297
     *  @param  Societe   $thirdparty           Thirdparty
298
     *  @return int                             id of created payment, < 0 if error
299
     */
300
    public function create($user, $closepaidinvoices = 0, $thirdparty = null)
301
    {
302
        global $conf, $langs;
303
304
        $error = 0;
305
        $way = $this->getWay(); // 'dolibarr' to use amount, 'customer' to use foreign multicurrency amount
306
307
        $now = dol_now();
308
309
        // Clean parameters
310
        $totalamount = 0;
311
        $totalamount_converted = 0;
312
        $atleastonepaymentnotnull = 0;
313
314
        if ($way == 'dolibarr') {   // Payments were entered into the column of main currency
315
            $amounts = &$this->amounts;
316
            $amounts_to_update = &$this->multicurrency_amounts;
317
        } else {                    // Payments were entered into the column of foreign currency
318
            $amounts = &$this->multicurrency_amounts;
319
            $amounts_to_update = &$this->amounts;
320
        }
321
322
        $currencyofpayment = '';
323
        $currencytxofpayment = '';
324
325
        foreach ($amounts as $key => $value) {  // How payment is dispatched
326
            if (empty($value)) {
327
                continue;
328
            }
329
            // $key is id of invoice, $value is amount, $way is a 'dolibarr' if amount is in main currency, 'customer' if in foreign currency
330
            $value_converted = MultiCurrency::getAmountConversionFromInvoiceRate($key, $value, $way);
331
            // Add controls of input validity
332
            if ($value_converted === false) {
333
                // We failed to find the conversion for one invoice
334
                $this->error = $langs->trans('FailedToFoundTheConversionRateForInvoice');
335
                return -1;
336
            }
337
            if (empty($currencyofpayment)) {
338
                $currencyofpayment = isset($this->multicurrency_code[$key]) ? $this->multicurrency_code[$key] : "";
339
            } elseif ($currencyofpayment != $this->multicurrency_code[$key]) {
340
                // If we have invoices with different currencies in the payment, we stop here
341
                $this->error = 'ErrorYouTryToPayInvoicesWithDifferentCurrenciesInSamePayment';
342
                return -1;
343
            }
344
            if (empty($currencytxofpayment)) {
345
                $currencytxofpayment = isset($this->multicurrency_tx[$key]) ? $this->multicurrency_tx[$key] : "";
346
            }
347
348
            $totalamount_converted += $value_converted;
349
            $amounts_to_update[$key] = price2num($value_converted, 'MT');
350
351
            $newvalue = price2num($value, 'MT');
352
            $amounts[$key] = $newvalue;
353
            $totalamount += $newvalue;
354
            if (!empty($newvalue)) {
355
                $atleastonepaymentnotnull++;
356
            }
357
        }
358
359
        if (empty($currencyofpayment)) {    // Should not happen. For the case the multicurrency_code was not saved into invoices
360
            $currencyofpayment = $conf->currency;
361
        }
362
363
        if (!empty($currencyofpayment)) {
364
            // We must check that the currency of invoices is the same than the currency of the bank
365
            $bankaccount = new Account($this->db);
366
            $bankaccount->fetch($this->fk_account);
367
            $bankcurrencycode = empty($bankaccount->currency_code) ? $conf->currency : $bankaccount->currency_code;
368
            if ($currencyofpayment != $bankcurrencycode && $currencyofpayment != $conf->currency && $bankcurrencycode != $conf->currency) {
369
                $langs->load("errors");
370
                $this->error = $langs->trans('ErrorYouTryToPayInvoicesInACurrencyFromBankWithAnotherCurrency', $currencyofpayment, $bankcurrencycode);
371
                return -1;
372
            }
373
        }
374
375
376
        $totalamount = (float) price2num($totalamount);
377
        $totalamount_converted = (float) price2num($totalamount_converted);
378
379
        // Check parameters
380
        if (empty($totalamount) && empty($atleastonepaymentnotnull)) {   // We accept negative amounts for withdraw reject but not empty arrays
381
            $this->errors[] = 'TotalAmountEmpty';
382
            $this->error = $langs->trans('TotalAmountEmpty');
383
            return -1;
384
        }
385
386
        dol_syslog(get_class($this) . "::create insert paiement (closepaidinvoices = " . $closepaidinvoices . ")", LOG_DEBUG);
387
388
        $this->db->begin();
389
390
        $this->ref = $this->getNextNumRef(is_object($thirdparty) ? $thirdparty : '');
391
392
        if (empty($this->ref_ext)) {
393
            $this->ref_ext = '';
394
        }
395
396
        if ($way == 'dolibarr') {
397
            $total = $totalamount;
398
            $mtotal = $totalamount_converted;
399
        } else {
400
            $total = $totalamount_converted;
401
            $mtotal = $totalamount;
402
        }
403
404
        $num_payment = $this->num_payment;
405
        $note = ($this->note_private ? $this->note_private : $this->note);
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$note has been deprecated: Use $note_private instead. ( Ignorable by Annotation )

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

405
        $note = ($this->note_private ? $this->note_private : /** @scrutinizer ignore-deprecated */ $this->note);

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

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

Loading history...
406
407
        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "paiement (entity, ref, ref_ext, datec, datep, amount, multicurrency_amount, fk_paiement, num_paiement, note, ext_payment_id, ext_payment_site, fk_user_creat, pos_change)";
408
        $sql .= " VALUES (" . ((int) $conf->entity) . ", '" . $this->db->escape($this->ref) . "', '" . $this->db->escape($this->ref_ext) . "', '" . $this->db->idate($now) . "', '" . $this->db->idate($this->datepaye) . "', " . ((float) $total) . ", " . ((float) $mtotal) . ", " . ((int) $this->paiementid) . ", ";
409
        $sql .= "'" . $this->db->escape($num_payment) . "', '" . $this->db->escape($note) . "', " . ($this->ext_payment_id ? "'" . $this->db->escape($this->ext_payment_id) . "'" : "null") . ", " . ($this->ext_payment_site ? "'" . $this->db->escape($this->ext_payment_site) . "'" : "null") . ", " . ((int) $user->id) . ", " . ((float) $this->pos_change) . ")";
410
411
        $resql = $this->db->query($sql);
412
        if ($resql) {
413
            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . 'paiement');
414
415
            // Insert links amount / invoices
416
            foreach ($this->amounts as $key => $amount) {
417
                $facid = $key;
418
                if (is_numeric($amount) && $amount != 0) {
419
                    $amount = price2num($amount);
420
                    $sql = "INSERT INTO " . MAIN_DB_PREFIX . "paiement_facture (fk_facture, fk_paiement, amount, multicurrency_amount, multicurrency_code, multicurrency_tx)";
421
                    $sql .= " VALUES (" . ((int) $facid) . ", " . ((int) $this->id) . ", " . ((float) $amount) . ", " . ((float) $this->multicurrency_amounts[$key]) . ", " . ($currencyofpayment ? "'" . $this->db->escape($currencyofpayment) . "'" : 'NULL') . ", " . (!empty($this->multicurrency_tx) ? (float) $currencytxofpayment : 1) . ")";
422
423
                    dol_syslog(get_class($this) . '::create Amount line ' . $key . ' insert paiement_facture', LOG_DEBUG);
424
                    $resql = $this->db->query($sql);
425
                    if ($resql) {
426
                        $invoice = new Facture($this->db);
427
                        $invoice->fetch($facid);
428
429
                        // If we want to closed paid invoices
430
                        if ($closepaidinvoices) {
431
                            $paiement = $invoice->getSommePaiement();
432
                            $creditnotes = $invoice->getSumCreditNotesUsed();
433
                            $deposits = $invoice->getSumDepositsUsed();
434
                            $alreadypayed = price2num($paiement + $creditnotes + $deposits, 'MT');
435
                            $remaintopay = price2num($invoice->total_ttc - $paiement - $creditnotes - $deposits, 'MT');
436
437
                            //var_dump($invoice->total_ttc.' - '.$paiement.' -'.$creditnotes.' - '.$deposits.' - '.$remaintopay);exit;
438
439
                            //Invoice types that are eligible for changing status to paid
440
                            $affected_types = array(
441
                                Facture::TYPE_STANDARD,
442
                                Facture::TYPE_REPLACEMENT,
443
                                Facture::TYPE_CREDIT_NOTE,
444
                                Facture::TYPE_DEPOSIT,
445
                                Facture::TYPE_SITUATION
446
                            );
447
448
                            if (!in_array($invoice->type, $affected_types)) {
449
                                dol_syslog("Invoice " . $facid . " is not a standard, nor replacement invoice, nor credit note, nor deposit invoice, nor situation invoice. We do nothing more.");
450
                            } elseif ($remaintopay) {
451
                                // hook to have an option to automatically close a closable invoice with less payment than the total amount (e.g. agreed cash discount terms)
452
                                global $hookmanager;
453
                                $hookmanager->initHooks(array('paymentdao'));
454
                                $parameters = array('facid' => $facid, 'invoice' => $invoice, 'remaintopay' => $remaintopay);
455
                                $action = 'CLOSEPAIDINVOICE';
456
                                $reshook = $hookmanager->executeHooks('createPayment', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
457
                                if ($reshook < 0) {
458
                                    $this->errors[] = $hookmanager->error;
459
                                    $this->error = $hookmanager->error;
460
                                    $error++;
461
                                } elseif ($reshook == 0) {
462
                                    dol_syslog("Remain to pay for invoice " . $facid . " not null. We do nothing more.");
463
                                }
464
                                // } else if ($mustwait) dol_syslog("There is ".$mustwait." differed payment to process, we do nothing more.");
465
                            } else {
466
                                // If invoice is a down payment, we also convert down payment to discount
467
                                if ($invoice->type == Facture::TYPE_DEPOSIT) {
468
                                    $amount_ht = $amount_tva = $amount_ttc = array();
469
                                    $multicurrency_amount_ht = $multicurrency_amount_tva = $multicurrency_amount_ttc = array();
470
471
                                    // Insert one discount by VAT rate category
472
                                    $discount = new DiscountAbsolute($this->db);
473
                                    $discount->fetch('', $invoice->id);
474
                                    if (empty($discount->id)) { // If the invoice was not yet converted into a discount (this may have been done manually before we come here)
475
                                        $discount->description = '(DEPOSIT)';
476
                                        $discount->fk_soc = $invoice->socid;
477
                                        $discount->socid = $invoice->socid;
478
                                        $discount->fk_facture_source = $invoice->id;
479
480
                                        // Loop on each vat rate
481
                                        $i = 0;
482
                                        foreach ($invoice->lines as $line) {
483
                                            if ($line->total_ht != 0) {    // no need to create discount if amount is null
484
                                                $amount_ht[$line->tva_tx] += $line->total_ht;
485
                                                $amount_tva[$line->tva_tx] += $line->total_tva;
486
                                                $amount_ttc[$line->tva_tx] += $line->total_ttc;
487
                                                $multicurrency_amount_ht[$line->tva_tx] += $line->multicurrency_total_ht;
488
                                                $multicurrency_amount_tva[$line->tva_tx] += $line->multicurrency_total_tva;
489
                                                $multicurrency_amount_ttc[$line->tva_tx] += $line->multicurrency_total_ttc;
490
                                                $i++;
491
                                            }
492
                                        }
493
494
                                        foreach ($amount_ht as $tva_tx => $xxx) {
495
                                            $discount->amount_ht = abs($amount_ht[$tva_tx]);
496
                                            $discount->amount_tva = abs($amount_tva[$tva_tx]);
497
                                            $discount->amount_ttc = abs($amount_ttc[$tva_tx]);
498
                                            $discount->multicurrency_amount_ht = abs($multicurrency_amount_ht[$tva_tx]);
499
                                            $discount->multicurrency_amount_tva = abs($multicurrency_amount_tva[$tva_tx]);
500
                                            $discount->multicurrency_amount_ttc = abs($multicurrency_amount_ttc[$tva_tx]);
501
                                            $discount->tva_tx = abs($tva_tx);
502
503
                                            $result = $discount->create($user);
504
                                            if ($result < 0) {
505
                                                $error++;
506
                                                break;
507
                                            }
508
                                        }
509
                                    }
510
511
                                    if ($error) {
512
                                        $this->error = $discount->error;
513
                                        $this->errors = $discount->errors;
514
                                        $error++;
515
                                    }
516
                                }
517
518
                                // Set invoice to paid
519
                                if (!$error) {
520
                                    $result = $invoice->setPaid($user, '', '');
521
                                    if ($result < 0) {
522
                                        $this->error = $invoice->error;
523
                                        $this->errors = $invoice->errors;
524
                                        $error++;
525
                                    }
526
                                }
527
                            }
528
                        }
529
530
                        // Regenerate documents of invoices
531
                        if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
532
                            dol_syslog(get_class($this) . '::create Regenerate the document after inserting payment for thirdparty default_lang=' . (is_object($invoice->thirdparty) ? $invoice->thirdparty->default_lang : 'null'), LOG_DEBUG);
533
534
                            $newlang = '';
535
                            $outputlangs = $langs;
536
                            if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
537
                                $invoice->fetch_thirdparty();
538
                                $newlang = $invoice->thirdparty->default_lang;
539
                            }
540
                            if (!empty($newlang)) {
541
                                $outputlangs = new Translate("", $conf);
542
                                $outputlangs->setDefaultLang($newlang);
543
                            }
544
545
                            $hidedetails = getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 1 : 0;
546
                            $hidedesc = getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 1 : 0;
547
                            $hideref = getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 1 : 0;
548
549
                            $ret = $invoice->fetch($facid); // Reload to get new records
550
551
                            $result = $invoice->generateDocument($invoice->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
552
553
                            dol_syslog(get_class($this) . '::create Regenerate end result=' . $result, LOG_DEBUG);
554
555
                            if ($result < 0) {
556
                                $this->error = $invoice->error;
557
                                $this->errors = $invoice->errors;
558
                                $error++;
559
                            }
560
                        }
561
                    } else {
562
                        $this->error = $this->db->lasterror();
563
                        $error++;
564
                    }
565
                } else {
566
                    dol_syslog(get_class($this) . '::Create Amount line ' . $key . ' not a number. We discard it.');
567
                }
568
            }
569
570
            dol_syslog(get_class($this) . '::create Now we call the triggers if no error (error = ' . $error . ')', LOG_DEBUG);
571
572
            if (!$error) {    // All payments into $this->amounts were recorded without errors
573
                // Appel des triggers
574
                $result = $this->call_trigger('PAYMENT_CUSTOMER_CREATE', $user);
575
                if ($result < 0) {
576
                    $error++;
577
                }
578
                // Fin appel triggers
579
            }
580
        } else {
581
            $this->error = $this->db->lasterror();
582
            $error++;
583
        }
584
585
        if (!$error) {
586
            $this->amount = $total;
587
            $this->total = $total; // deprecated
588
            $this->multicurrency_amount = $mtotal;
589
            $this->db->commit();
590
            return $this->id;
591
        } else {
592
            $this->db->rollback();
593
            return -1;
594
        }
595
    }
596
597
598
    /**
599
     * Delete a payment and generated links into account
600
     *  - Si le paiement porte sur un ecriture compte qui est rapprochee, on refuse
601
     *  - Si le paiement porte sur au moins une facture a "payee", on refuse
602
     *
603
     * @param   User    $user           User making the deletion
604
     * @param   int     $notrigger      No trigger
605
     * @return  int                     Return integer <0 if KO, >0 if OK
606
     */
607
    public function delete($user, $notrigger = 0)
608
    {
609
        $error = 0;
610
611
        $bank_line_id = $this->bank_line;
612
613
        $this->db->begin();
614
615
        // Verifier si paiement porte pas sur une facture classee
616
        // Si c'est le cas, on refuse la suppression
617
        $billsarray = $this->getBillsArray('f.fk_statut > 1');
618
        if (is_array($billsarray)) {
619
            if (count($billsarray)) {
620
                $this->error = "ErrorDeletePaymentLinkedToAClosedInvoiceNotPossible";
621
                $this->db->rollback();
622
                return -1;
623
            }
624
        } else {
625
            $this->db->rollback();
626
            return -2;
627
        }
628
629
        // Delete bank urls. If payment is on a conciliated line, return error.
630
        if ($bank_line_id > 0) {
631
            $accline = new AccountLine($this->db);
632
633
            $result = $accline->fetch($bank_line_id);
634
            if ($result == 0) {
635
                $accline->id = $accline->rowid = $bank_line_id; // If not found, we set artificially rowid to allow delete of llx_bank_url
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObjectLine::$rowid has been deprecated: Try to use id property as possible (even if field into database is still rowid) ( Ignorable by Annotation )

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

635
                $accline->id = /** @scrutinizer ignore-deprecated */ $accline->rowid = $bank_line_id; // If not found, we set artificially rowid to allow delete of llx_bank_url

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

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

Loading history...
636
            }
637
638
            // Delete bank account url lines linked to payment
639
            $result = $accline->delete_urls($user);
640
            if ($result < 0) {
641
                $this->error = $accline->error;
642
                $this->db->rollback();
643
                return -3;
644
            }
645
646
            // Delete bank account lines linked to payment
647
            $result = $accline->delete($user);
648
            if ($result < 0) {
649
                $this->error = $accline->error;
650
                $this->db->rollback();
651
                return -4;
652
            }
653
        }
654
655
        if (!$notrigger) {
656
            // Call triggers
657
            $result = $this->call_trigger('PAYMENT_CUSTOMER_DELETE', $user);
658
            if ($result < 0) {
659
                $this->db->rollback();
660
                return -1;
661
            }
662
            // End call triggers
663
        }
664
665
        // Delete payment (into paiement_facture and paiement)
666
        $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . 'paiement_facture';
667
        $sql .= ' WHERE fk_paiement = ' . ((int) $this->id);
668
        dol_syslog($sql);
669
        $result = $this->db->query($sql);
670
        if ($result) {
671
            $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . 'paiement';
672
            $sql .= " WHERE rowid = " . ((int) $this->id);
673
            dol_syslog($sql);
674
            $result = $this->db->query($sql);
675
            if (!$result) {
676
                $this->error = $this->db->lasterror();
677
                $this->db->rollback();
678
                return -3;
679
            }
680
681
            $this->db->commit();
682
            return 1;
683
        } else {
684
            $this->error = $this->db->error;
685
            $this->db->rollback();
686
            return -5;
687
        }
688
    }
689
690
691
    /**
692
     *      Add a record into bank for payment + links between this bank record and sources of payment.
693
     *      All payment properties (this->amount, this->amounts, ...) must have been set first like after a call to create().
694
     *
695
     *      @param  User    $user               Object of user making payment
696
     *      @param  string  $mode               'payment', 'payment_supplier'
697
     *      @param  string  $label              Label to use in bank record
698
     *      @param  int     $accountid          Id of bank account to do link with
699
     *      @param  string  $emetteur_nom       Name of transmitter
700
     *      @param  string  $emetteur_banque    Name of bank
701
     *      @param  int     $notrigger          No trigger
702
     *      @param  string  $accountancycode    When we record a free bank entry, we must provide accounting account if accountancy module is on.
703
     *      @param  string  $addbankurl         'direct-debit' or 'credit-transfer': Add another entry into bank_url.
704
     *      @return int                         Return integer <0 if KO, bank_line_id if OK
705
     */
706
    public function addPaymentToBank($user, $mode, $label, $accountid, $emetteur_nom, $emetteur_banque, $notrigger = 0, $accountancycode = '', $addbankurl = '')
707
    {
708
        global $conf, $user;
709
710
        $error = 0;
711
        $bank_line_id = 0;
712
713
        if (isModEnabled("bank")) {
714
            if ($accountid <= 0) {
715
                $this->error = 'Bad value for parameter accountid=' . $accountid;
716
                dol_syslog(get_class($this) . '::addPaymentToBank ' . $this->error, LOG_ERR);
717
                return -1;
718
            }
719
720
            $this->fk_account = $accountid;
721
722
            dol_syslog("addPaymentToBank " . $user->id . ", " . $mode . ", " . $label . ", " . $this->fk_account . ", " . $emetteur_nom . ", " . $emetteur_banque);
723
724
            $acc = new Account($this->db);
725
            $result = $acc->fetch($this->fk_account);
726
            if ($result < 0) {
727
                $this->error = $acc->error;
728
                $this->errors = $acc->errors;
729
                $error++;
730
                return -1;
731
            }
732
733
            $this->db->begin();
734
735
            $totalamount = $this->amount;
736
            $totalamount_main_currency = null;
737
            if (empty($totalamount)) {
738
                $totalamount = $this->total; // For backward compatibility
739
            }
740
741
            // if dolibarr currency != bank currency then we received an amount in customer currency (currently I don't manage the case : my currency is USD, the customer currency is EUR and he paid me in GBP. Seems no sense for me)
742
            if (isModEnabled('multicurrency') && $conf->currency != $acc->currency_code) {
743
                $totalamount = $this->multicurrency_amount;     // We will insert into llx_bank.amount in foreign currency
744
                $totalamount_main_currency = $this->amount;     // We will also save the amount in main currency into column llx_bank.amount_main_currency
745
            }
746
747
            if ($mode == 'payment_supplier') {
748
                $totalamount = -$totalamount;
749
                if (isset($totalamount_main_currency)) {
750
                    $totalamount_main_currency = -$totalamount_main_currency;
751
                }
752
            }
753
754
            // Insert payment into llx_bank
755
            $bank_line_id = $acc->addline(
756
                $this->datepaye,
757
                $this->paiementcode ? $this->paiementcode : $this->paiementid, // Payment mode code ('CB', 'CHQ' or 'VIR' for example). Use payment id if not defined for backward compatibility.
758
                $label,
759
                $totalamount, // Sign must be positive when we receive money (customer payment), negative when you give money (supplier invoice or credit note)
760
                $this->num_payment,
761
                '',
762
                $user,
763
                $emetteur_nom,
764
                $emetteur_banque,
765
                $accountancycode,
766
                null,
767
                '',
768
                $totalamount_main_currency
769
            );
770
771
            // Mise a jour fk_bank dans llx_paiement
772
            // On connait ainsi le paiement qui a genere l'ecriture bancaire
773
            if ($bank_line_id > 0) {
774
                $result = $this->update_fk_bank($bank_line_id);
775
                if ($result <= 0) {
776
                    $error++;
777
                    dol_print_error($this->db);
778
                }
779
780
                // Add link 'payment', 'payment_supplier' in bank_url between payment and bank transaction
781
                if (!$error) {
782
                    $url = '';
783
                    if ($mode == 'payment') {
784
                        $url = constant('BASE_URL') . '/compta/paiement/card.php?id=';
785
                    }
786
                    if ($mode == 'payment_supplier') {
787
                        $url = constant('BASE_URL') . '/fourn/paiement/card.php?id=';
788
                    }
789
                    if ($url) {
790
                        $result = $acc->add_url_line($bank_line_id, $this->id, $url, '(paiement)', $mode);
791
                        if ($result <= 0) {
792
                            $error++;
793
                            dol_print_error($this->db);
794
                        }
795
                    }
796
                }
797
798
                // Add link 'company' in bank_url between invoice and bank transaction (for each invoice concerned by payment)
799
                if (!$error) {
800
                    $linkaddedforthirdparty = array();
801
                    foreach ($this->amounts as $key => $value) {  // We should have invoices always for same third party but we loop in case of.
802
                        if ($mode == 'payment') {
803
                            $fac = new Facture($this->db);
804
                            $fac->fetch($key);
805
                            $fac->fetch_thirdparty();
806
                            if (!in_array($fac->thirdparty->id, $linkaddedforthirdparty)) { // Not yet done for this thirdparty
807
                                $result = $acc->add_url_line(
808
                                    $bank_line_id,
809
                                    $fac->thirdparty->id,
810
                                    constant('BASE_URL') . '/comm/card.php?socid=',
811
                                    $fac->thirdparty->name,
812
                                    'company'
813
                                );
814
                                if ($result <= 0) {
815
                                    dol_syslog(get_class($this) . '::addPaymentToBank ' . $this->db->lasterror());
816
                                }
817
                                $linkaddedforthirdparty[$fac->thirdparty->id] = $fac->thirdparty->id; // Mark as done for this thirdparty
818
                            }
819
                        }
820
                        if ($mode == 'payment_supplier') {
821
                            $fac = new FactureFournisseur($this->db);
822
                            $fac->fetch($key);
823
                            $fac->fetch_thirdparty();
824
                            if (!in_array($fac->thirdparty->id, $linkaddedforthirdparty)) { // Not yet done for this thirdparty
825
                                $result = $acc->add_url_line(
826
                                    $bank_line_id,
827
                                    $fac->thirdparty->id,
828
                                    constant('BASE_URL') . '/fourn/card.php?socid=',
829
                                    $fac->thirdparty->name,
830
                                    'company'
831
                                );
832
                                if ($result <= 0) {
833
                                    dol_syslog(get_class($this) . '::addPaymentToBank ' . $this->db->lasterror());
834
                                }
835
                                $linkaddedforthirdparty[$fac->thirdparty->id] = $fac->thirdparty->id; // Mark as done for this thirdparty
836
                            }
837
                        }
838
                    }
839
                }
840
841
                // Add a link to the Direct Debit ('direct-debit') or Credit transfer ('credit-transfer') file in bank_url
842
                if (!$error && $addbankurl && in_array($addbankurl, array('direct-debit', 'credit-transfer'))) {
843
                    $result = $acc->add_url_line(
844
                        $bank_line_id,
845
                        $this->id_prelevement,
846
                        constant('BASE_URL') . '/compta/prelevement/card.php?id=',
847
                        $this->num_payment,
848
                        $addbankurl
849
                    );
850
                }
851
852
                // Add link to the Direct Debit if invoice refused ('InvoiceRefused') in bank_url
853
                if (!$error && $label == '(InvoiceRefused)') {
854
                    $result = $acc->add_url_line(
855
                        $bank_line_id,
856
                        $this->id_prelevement,
857
                        constant('BASE_URL') . '/compta/prelevement/card.php?id=',
858
                        $this->num_prelevement,
859
                        'withdraw'
860
                    );
861
                }
862
863
                if (!$error && !$notrigger) {
864
                    // Appel des triggers
865
                    $result = $this->call_trigger('PAYMENT_ADD_TO_BANK', $user);
866
                    if ($result < 0) {
867
                        $error++;
868
                    }
869
                    // Fin appel triggers
870
                }
871
            } else {
872
                $this->error = $acc->error;
873
                $this->errors = $acc->errors;
874
                $error++;
875
            }
876
877
            if (!$error) {
878
                $this->db->commit();
879
            } else {
880
                $this->db->rollback();
881
            }
882
        }
883
884
        if (!$error) {
885
            return $bank_line_id;
886
        } else {
887
            return -1;
888
        }
889
    }
890
891
892
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
893
    /**
894
     *      Mise a jour du lien entre le paiement et la ligne generee dans llx_bank
895
     *
896
     *      @param  int     $id_bank    Id compte bancaire
897
     *      @return int                 Return integer <0 if KO, >0 if OK
898
     */
899
    public function update_fk_bank($id_bank)
900
    {
901
		// phpcs:enable
902
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element . ' set fk_bank = ' . ((int) $id_bank);
903
        $sql .= " WHERE rowid = " . ((int) $this->id);
904
905
        dol_syslog(get_class($this) . '::update_fk_bank', LOG_DEBUG);
906
        $result = $this->db->query($sql);
907
        if ($result) {
908
            return 1;
909
        } else {
910
            $this->error = $this->db->lasterror();
911
            dol_syslog(get_class($this) . '::update_fk_bank ' . $this->error);
912
            return -1;
913
        }
914
    }
915
916
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
917
    /**
918
     *  Updates the payment date
919
     *
920
     *  @param  int $date   New date
921
     *  @return int                 Return integer <0 if KO, 0 if OK
922
     */
923
    public function update_date($date)
924
    {
925
		// phpcs:enable
926
        $error = 0;
927
928
        if (!empty($date) && $this->statut != 1) {
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$statut has been deprecated: Use $status instead. ( Ignorable by Annotation )

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

928
        if (!empty($date) && /** @scrutinizer ignore-deprecated */ $this->statut != 1) {

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

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

Loading history...
929
            $this->db->begin();
930
931
            dol_syslog(get_class($this) . "::update_date with date = " . $date, LOG_DEBUG);
932
933
            $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element;
934
            $sql .= " SET datep = '" . $this->db->idate($date) . "'";
935
            $sql .= " WHERE rowid = " . ((int) $this->id);
936
937
            $result = $this->db->query($sql);
938
            if (!$result) {
939
                $error++;
940
                $this->error = 'Error -1 ' . $this->db->error();
941
            }
942
943
            $type = $this->element;
944
945
            $sql = "UPDATE " . MAIN_DB_PREFIX . 'bank';
946
            $sql .= " SET dateo = '" . $this->db->idate($date) . "', datev = '" . $this->db->idate($date) . "'";
947
            $sql .= " WHERE rowid IN (SELECT fk_bank FROM " . MAIN_DB_PREFIX . "bank_url WHERE type = '" . $this->db->escape($type) . "' AND url_id = " . ((int) $this->id) . ")";
948
            $sql .= " AND rappro = 0";
949
950
            $result = $this->db->query($sql);
951
            if (!$result) {
952
                $error++;
953
                $this->error = 'Error -1 ' . $this->db->error();
954
            }
955
956
            if (!$error) {
957
            }
958
959
            if (!$error) {
960
                $this->datepaye = $date;
961
                $this->date = $date;
962
963
                $this->db->commit();
964
                return 0;
965
            } else {
966
                $this->db->rollback();
967
                return -2;
968
            }
969
        }
970
        return -1; //no date given or already validated
971
    }
972
973
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
974
    /**
975
     *  Updates the payment number
976
     *
977
     *  @param  string  $num_payment        New num
978
     *  @return int                         Return integer <0 if KO, 0 if OK
979
     */
980
    public function update_num($num_payment)
981
    {
982
		// phpcs:enable
983
        if (!empty($num_payment) && $this->statut != 1) {
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$statut has been deprecated: Use $status instead. ( Ignorable by Annotation )

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

983
        if (!empty($num_payment) && /** @scrutinizer ignore-deprecated */ $this->statut != 1) {

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

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

Loading history...
984
            $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element;
985
            $sql .= " SET num_paiement = '" . $this->db->escape($num_payment) . "'";
986
            $sql .= " WHERE rowid = " . ((int) $this->id);
987
988
            dol_syslog(get_class($this) . "::update_num", LOG_DEBUG);
989
            $result = $this->db->query($sql);
990
            if ($result) {
991
                $this->num_payment = $this->db->escape($num_payment);
992
                return 0;
993
            } else {
994
                $this->error = 'Error -1 ' . $this->db->error();
995
                return -2;
996
            }
997
        }
998
        return -1; //no num given or already validated
999
    }
1000
1001
    /**
1002
     * Validate payment
1003
     *
1004
     * @param   User|null   $user       User making validation
1005
     * @return  int                     Return integer <0 if KO, >0 if OK
1006
     * @deprecated
1007
     */
1008
    public function valide(User $user = null)
1009
    {
1010
        return $this->validate($user);
1011
    }
1012
1013
    /**
1014
     * Validate payment
1015
     *
1016
     * @param   User|null   $user       User making validation
1017
     * @return  int                     Return integer <0 if KO, >0 if OK
1018
     */
1019
    public function validate(User $user = null)
1020
    {
1021
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element . ' SET statut = 1 WHERE rowid = ' . ((int) $this->id);
1022
1023
        dol_syslog(get_class($this) . '::valide', LOG_DEBUG);
1024
        $result = $this->db->query($sql);
1025
        if ($result) {
1026
            return 1;
1027
        } else {
1028
            $this->error = $this->db->lasterror();
1029
            dol_syslog(get_class($this) . '::valide ' . $this->error);
1030
            return -1;
1031
        }
1032
    }
1033
1034
    /**
1035
     * Reject payment
1036
     *
1037
     * @param   User|null   $user       User making reject
1038
     * @return  int                     Return integer <0 if KO, >0 if OK
1039
     */
1040
    public function reject(User $user = null)
1041
    {
1042
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element . ' SET statut = 2 WHERE rowid = ' . ((int) $this->id);
1043
1044
        dol_syslog(get_class($this) . '::reject', LOG_DEBUG);
1045
        $result = $this->db->query($sql);
1046
        if ($result) {
1047
            return 1;
1048
        } else {
1049
            $this->error = $this->db->lasterror();
1050
            dol_syslog(get_class($this) . '::reject ' . $this->error);
1051
            return -1;
1052
        }
1053
    }
1054
1055
    /**
1056
     * Information sur l'objet
1057
     *
1058
     * @param   int     $id      id du paiement don't il faut afficher les infos
1059
     * @return  void
1060
     */
1061
    public function info($id)
1062
    {
1063
        $sql = 'SELECT p.rowid, p.datec, p.fk_user_creat, p.fk_user_modif, p.tms';
1064
        $sql .= ' FROM ' . MAIN_DB_PREFIX . 'paiement as p';
1065
        $sql .= ' WHERE p.rowid = ' . ((int) $id);
1066
1067
        dol_syslog(get_class($this) . '::info', LOG_DEBUG);
1068
        $result = $this->db->query($sql);
1069
1070
        if ($result) {
1071
            if ($this->db->num_rows($result)) {
1072
                $obj = $this->db->fetch_object($result);
1073
1074
                $this->id = $obj->rowid;
1075
1076
                $this->user_creation_id = $obj->fk_user_creat;
1077
                $this->user_modification_id = $obj->fk_user_modif;
1078
                $this->date_creation     = $this->db->jdate($obj->datec);
1079
                $this->date_modification = $this->db->jdate($obj->tms);
1080
            }
1081
            $this->db->free($result);
1082
        } else {
1083
            dol_print_error($this->db);
1084
        }
1085
    }
1086
1087
    /**
1088
     *  Return list of invoices the payment is related to.
1089
     *
1090
     *  @param  string      $filter         Filter
1091
     *  @return int|array                   Return integer <0 if KO or array of invoice id
1092
     *  @see getAmountsArray()
1093
     */
1094
    public function getBillsArray($filter = '')
1095
    {
1096
        $sql = 'SELECT pf.fk_facture';
1097
        $sql .= ' FROM ' . MAIN_DB_PREFIX . 'paiement_facture as pf, ' . MAIN_DB_PREFIX . 'facture as f'; // We keep link on invoice to allow use of some filters on invoice
1098
        $sql .= ' WHERE pf.fk_facture = f.rowid AND pf.fk_paiement = ' . ((int) $this->id);
1099
        if ($filter) {
1100
            $sql .= ' AND ' . $filter;
1101
        }
1102
        $resql = $this->db->query($sql);
1103
        if ($resql) {
1104
            $i = 0;
1105
            $num = $this->db->num_rows($resql);
1106
            $billsarray = array();
1107
1108
            while ($i < $num) {
1109
                $obj = $this->db->fetch_object($resql);
1110
                $billsarray[$i] = $obj->fk_facture;
1111
                $i++;
1112
            }
1113
1114
            return $billsarray;
1115
        } else {
1116
            $this->error = $this->db->error();
1117
            dol_syslog(get_class($this) . '::getBillsArray Error ' . $this->error . ' -', LOG_DEBUG);
1118
            return -1;
1119
        }
1120
    }
1121
1122
    /**
1123
     *  Return list of amounts of payments.
1124
     *
1125
     *  @return int|array                   Array of amount of payments
1126
     *  @see getBillsArray()
1127
     */
1128
    public function getAmountsArray()
1129
    {
1130
        $sql = 'SELECT pf.fk_facture, pf.amount';
1131
        $sql .= ' FROM ' . MAIN_DB_PREFIX . 'paiement_facture as pf';
1132
        $sql .= ' WHERE pf.fk_paiement = ' . ((int) $this->id);
1133
        $resql = $this->db->query($sql);
1134
        if ($resql) {
1135
            $i = 0;
1136
            $num = $this->db->num_rows($resql);
1137
            $amounts = array();
1138
1139
            while ($i < $num) {
1140
                $obj = $this->db->fetch_object($resql);
1141
                $amounts[$obj->fk_facture] = $obj->amount;
1142
                $i++;
1143
            }
1144
1145
            return $amounts;
1146
        } else {
1147
            $this->error = $this->db->error();
1148
            dol_syslog(get_class($this) . '::getAmountsArray Error ' . $this->error . ' -', LOG_DEBUG);
1149
            return -1;
1150
        }
1151
    }
1152
1153
    /**
1154
     *      Return next reference of customer invoice not already used (or last reference)
1155
     *      according to numbering module defined into constant FACTURE_ADDON
1156
     *
1157
     *      @param     Societe      $soc        object company
1158
     *      @param     string       $mode       'next' for next value or 'last' for last value
1159
     *      @return    string                   free ref or last ref
1160
     */
1161
    public function getNextNumRef($soc, $mode = 'next')
1162
    {
1163
        global $conf, $db, $langs;
1164
        $langs->load("bills");
1165
1166
        // Clean parameters (if not defined or using deprecated value)
1167
        if (!getDolGlobalString('PAYMENT_ADDON')) {
1168
            $conf->global->PAYMENT_ADDON = 'mod_payment_cicada';
1169
        } elseif (getDolGlobalString('PAYMENT_ADDON') == 'ant') {
1170
            $conf->global->PAYMENT_ADDON = 'mod_payment_ant';
1171
        } elseif (getDolGlobalString('PAYMENT_ADDON') == 'cicada') {
1172
            $conf->global->PAYMENT_ADDON = 'mod_payment_cicada';
1173
        }
1174
1175
        if (getDolGlobalString('PAYMENT_ADDON')) {
1176
            $mybool = false;
1177
1178
            $file = getDolGlobalString('PAYMENT_ADDON') . ".php";
1179
            $classname = getDolGlobalString('PAYMENT_ADDON');
1180
1181
            // Include file with class
1182
            $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1183
1184
            foreach ($dirmodels as $reldir) {
1185
                $dir = dol_buildpath($reldir . "core/modules/payment/");
1186
1187
                // Load file with numbering class (if found)
1188
                if (is_file($dir . $file) && is_readable($dir . $file)) {
1189
                    $mybool = (include_once $dir . $file) || $mybool;
1190
                }
1191
            }
1192
1193
            // For compatibility
1194
            if (!$mybool) {
1195
                $file = getDolGlobalString('PAYMENT_ADDON') . ".php";
1196
                $classname = "mod_payment_" . getDolGlobalString('PAYMENT_ADDON');
1197
                $classname = preg_replace('/\-.*$/', '', $classname);
1198
                // Include file with class
1199
                foreach ($conf->file->dol_document_root as $dirroot) {
1200
                    $dir = $dirroot . "/core/modules/payment/";
1201
1202
                    // Load file with numbering class (if found)
1203
                    if (is_file($dir . $file) && is_readable($dir . $file)) {
1204
                        $mybool = (include_once $dir . $file) || $mybool;
1205
                    }
1206
                }
1207
            }
1208
1209
            if (!$mybool) {
1210
                dol_print_error(null, "Failed to include file " . $file);
1211
                return '';
1212
            }
1213
1214
            $obj = new $classname();
1215
            $numref = "";
1216
            $numref = $obj->getNextValue($soc, $this);
1217
1218
            /**
1219
             * $numref can be empty in case we ask for the last value because if there is no invoice created with the
1220
             * set up mask.
1221
             */
1222
            if ($mode != 'last' && !$numref) {
1223
                dol_print_error($db, "Payment::getNextNumRef " . $obj->error);
1224
                return "";
1225
            }
1226
1227
            return $numref;
1228
        } else {
1229
            $langs->load("errors");
1230
            print $langs->trans("Error") . " " . $langs->trans("ErrorModuleSetupNotComplete", $langs->transnoentitiesnoconv("Invoice"));
1231
            return "";
1232
        }
1233
    }
1234
1235
    /**
1236
     *  get the right way of payment
1237
     *
1238
     *  @return     string  'dolibarr' if standard comportment or paid in main currency, 'customer' if payment received from multicurrency inputs
1239
     */
1240
    public function getWay()
1241
    {
1242
        global $conf;
1243
1244
        $way = 'dolibarr';
1245
        if (isModEnabled('multicurrency')) {
1246
            foreach ($this->multicurrency_amounts as $value) {
1247
                if (!empty($value)) { // one value found then payment is in invoice currency
1248
                    $way = 'customer';
1249
                    break;
1250
                }
1251
            }
1252
        }
1253
1254
        return $way;
1255
    }
1256
1257
    /**
1258
     *  Initialise an instance with random values.
1259
     *  Used to build previews or test instances.
1260
     *  id must be 0 if object instance is a specimen.
1261
     *
1262
     *  @param  string      $option     ''=Create a specimen invoice with lines, 'nolines'=No lines
1263
     *  @return int
1264
     */
1265
    public function initAsSpecimen($option = '')
1266
    {
1267
        global $user, $langs, $conf;
1268
1269
        $now = dol_now();
1270
        $arraynow = dol_getdate($now);
1271
        $nownotime = dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']);
1272
1273
        // Initialize parameters
1274
        $this->id = 0;
1275
        $this->ref = 'SPECIMEN';
1276
        $this->specimen = 1;
1277
        $this->facid = 1;
1278
        $this->datepaye = $nownotime;
1279
1280
        return 1;
1281
    }
1282
1283
1284
    /**
1285
     *  Return clicable name (with picto eventually)
1286
     *
1287
     *  @param  int     $withpicto      0=No picto, 1=Include picto into link, 2=Only picto
1288
     *  @param  string  $option         Sur quoi pointe le lien
1289
     *  @param  string  $mode           'withlistofinvoices'=Include list of invoices into tooltip
1290
     *  @param  int     $notooltip      1=Disable tooltip
1291
     *  @param  string  $morecss        Add more CSS
1292
     *  @return string                  Chaine avec URL
1293
     */
1294
    public function getNomUrl($withpicto = 0, $option = '', $mode = 'withlistofinvoices', $notooltip = 0, $morecss = '')
1295
    {
1296
        global $conf, $langs, $hookmanager;
1297
1298
        if (!empty($conf->dol_no_mouse_hover)) {
1299
            $notooltip = 1; // Force disable tooltips
1300
        }
1301
1302
        $result = '';
1303
1304
        $label = img_picto('', $this->picto) . ' <u>' . $langs->trans("Payment") . '</u><br>';
1305
        $label .= '<strong>' . $langs->trans("Ref") . ':</strong> ' . $this->ref;
1306
        $dateofpayment = ($this->datepaye ? $this->datepaye : $this->date);
1307
        if ($dateofpayment) {
1308
            $label .= '<br><strong>' . $langs->trans("Date") . ':</strong> ';
1309
            $tmparray = dol_getdate($dateofpayment);
1310
            if ($tmparray['seconds'] == 0 && $tmparray['minutes'] == 0 && ($tmparray['hours'] == 0 || $tmparray['hours'] == 12)) {  // We set hours to 0:00 or 12:00 because we don't know it
1311
                $label .= dol_print_date($dateofpayment, 'day');
1312
            } else {    // Hours was set to real date of payment (special case for POS for example)
1313
                $label .= dol_print_date($dateofpayment, 'dayhour', 'tzuser');
1314
            }
1315
        }
1316
        if ($this->amount) {
1317
            $label .= '<br><strong>' . $langs->trans("Amount") . ':</strong> ' . price($this->amount, 0, $langs, 1, -1, -1, $conf->currency);
1318
        }
1319
        if ($mode == 'withlistofinvoices') {
1320
            $arraybill = $this->getBillsArray();
1321
            if (is_array($arraybill) && count($arraybill) > 0) {
1322
                $facturestatic = new Facture($this->db);
1323
                foreach ($arraybill as $billid) {
1324
                    $facturestatic->fetch($billid);
1325
                    $label .= '<br> ' . $facturestatic->getNomUrl(1, '', 0, 0, '', 1) . ' ' . $facturestatic->getLibStatut(2, 1);
1326
                }
1327
            }
1328
        }
1329
1330
        $linkclose = '';
1331
        if (empty($notooltip)) {
1332
            if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1333
                $label = $langs->trans("Payment");
1334
                $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
1335
            }
1336
            $linkclose .= ' title="' . dol_escape_htmltag($label, 1) . '"';
1337
            $linkclose .= ' class="classfortooltip' . ($morecss ? ' ' . $morecss : '') . '"';
1338
        } else {
1339
            $linkclose = ($morecss ? ' class="' . $morecss . '"' : '');
1340
        }
1341
1342
        $url = constant('BASE_URL') . '/compta/paiement/card.php?id=' . $this->id;
1343
1344
        $linkstart = '<a href="' . $url . '"';
1345
        $linkstart .= $linkclose . '>';
1346
        $linkend = '</a>';
1347
1348
        $result .= $linkstart;
1349
        if ($withpicto) {
1350
            $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . 'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
1351
        }
1352
        if ($withpicto && $withpicto != 2) {
1353
            $result .= ($this->ref ? $this->ref : $this->id);
1354
        }
1355
        $result .= $linkend;
1356
        global $action;
1357
        $hookmanager->initHooks(array($this->element . 'dao'));
1358
        $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1359
        $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1360
        if ($reshook > 0) {
1361
            $result = $hookmanager->resPrint;
1362
        } else {
1363
            $result .= $hookmanager->resPrint;
1364
        }
1365
        return $result;
1366
    }
1367
1368
    /**
1369
     *  Return the label of the status
1370
     *
1371
     *  @param  int     $mode          0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
1372
     *  @return string                 Label of status
1373
     */
1374
    public function getLibStatut($mode = 0)
1375
    {
1376
        return $this->LibStatut($this->statut, $mode);
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$statut has been deprecated: Use $status instead. ( Ignorable by Annotation )

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

1376
        return $this->LibStatut(/** @scrutinizer ignore-deprecated */ $this->statut, $mode);

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

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

Loading history...
1377
    }
1378
1379
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1380
    /**
1381
     *  Return the label of a given status
1382
     *
1383
     *  @param  int     $status        Id status
1384
     *  @param  int     $mode          0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
1385
     *  @return string                 Label of status
1386
     */
1387
    public function LibStatut($status, $mode = 0)
1388
    {
1389
		// phpcs:enable
1390
        global $langs; // TODO Renvoyer le libelle anglais et faire traduction a affichage
1391
1392
        $langs->load('compta');
1393
        /*if ($mode == 0)
1394
         {
1395
         if ($status == 0) return $langs->trans('ToValidate');
1396
         if ($status == 1) return $langs->trans('Validated');
1397
         }
1398
         if ($mode == 1)
1399
         {
1400
         if ($status == 0) return $langs->trans('ToValidate');
1401
         if ($status == 1) return $langs->trans('Validated');
1402
         }
1403
         if ($mode == 2)
1404
         {
1405
         if ($status == 0) return img_picto($langs->trans('ToValidate'),'statut1').' '.$langs->trans('ToValidate');
1406
         if ($status == 1) return img_picto($langs->trans('Validated'),'statut4').' '.$langs->trans('Validated');
1407
         }
1408
         if ($mode == 3)
1409
         {
1410
         if ($status == 0) return img_picto($langs->trans('ToValidate'),'statut1');
1411
         if ($status == 1) return img_picto($langs->trans('Validated'),'statut4');
1412
         }
1413
         if ($mode == 4)
1414
         {
1415
         if ($status == 0) return img_picto($langs->trans('ToValidate'),'statut1').' '.$langs->trans('ToValidate');
1416
         if ($status == 1) return img_picto($langs->trans('Validated'),'statut4').' '.$langs->trans('Validated');
1417
         }
1418
         if ($mode == 5)
1419
         {
1420
         if ($status == 0) return $langs->trans('ToValidate').' '.img_picto($langs->trans('ToValidate'),'statut1');
1421
         if ($status == 1) return $langs->trans('Validated').' '.img_picto($langs->trans('Validated'),'statut4');
1422
         }
1423
         if ($mode == 6)
1424
         {
1425
         if ($status == 0) return $langs->trans('ToValidate').' '.img_picto($langs->trans('ToValidate'),'statut1');
1426
         if ($status == 1) return $langs->trans('Validated').' '.img_picto($langs->trans('Validated'),'statut4');
1427
         }*/
1428
        return '';
1429
    }
1430
1431
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1432
    /**
1433
     *  Load the third party of object, from id into this->thirdparty.
1434
     *  For payments, take the thirdparty linked to the first invoice found. This is enough because payments are done on invoices of the same thirdparty.
1435
     *
1436
     *  @param      int     $force_thirdparty_id    Force thirdparty id
1437
     *  @return     int                             Return integer <0 if KO, >0 if OK
1438
     */
1439
    public function fetch_thirdparty($force_thirdparty_id = 0)
1440
    {
1441
		// phpcs:enable
1442
1443
        if (empty($force_thirdparty_id)) {
1444
            $billsarray = $this->getBillsArray(); // From payment, the fk_soc isn't available, we should load the first supplier invoice to get him
1445
            if (!empty($billsarray)) {
1446
                $invoice = new Facture($this->db);
1447
                if ($invoice->fetch($billsarray[0]) > 0) {
1448
                    $force_thirdparty_id = $invoice->socid;
1449
                }
1450
            }
1451
        }
1452
1453
        return parent::fetch_thirdparty($force_thirdparty_id);
1454
    }
1455
1456
1457
    /**
1458
     *  Return if payment is reconciled
1459
     *
1460
     *  @return     boolean     True if payment is reconciled
1461
     */
1462
    public function isReconciled()
1463
    {
1464
        $accountline = new AccountLine($this->db);
1465
        $accountline->fetch($this->bank_line);
1466
        return $accountline->rappro ? true : false;
1467
    }
1468
}
1469