Debtor::getPaymentMethodKey()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 0
cts 2
cp 0
crap 2
1
<?php
2
/**
3
 * Debtor = debitor
4
 *
5
 * Debitorklassen bruges til b�de tilbud og ordrer. Den bruges fra et modul,
6
 * og s� bygges de andre p� som moduler, der benytter det overordnede modul.
7
 *
8
 * Klassen kan ogs� bruges til at styre fakturaer.
9
 *
10
 * @package Intraface_Debtor
11
 * @author Lars Olesen <[email protected]>
12
 */
13
class Debtor extends Intraface_Standard
14
{
15
    /**
16
     * @var integer
17
     */
18
    protected $id;
19
20
    /**
21
     * @var object
22
     */
23
    public $kernel;
24
25
    /**
26
     * @var object
27
     */
28
    public $contact;
29
30
    /**
31
     * @var contact_person
32
     */
33
    public $contact_person;
34
35
    /**
36
     * @var array
37
     */
38
    public $value = array();
39
40
    /**
41
     * @var object
42
     */
43
    public $error;
44
45
    /**
46
     * @var string
47
     */
48
    protected $type;
49
50
    /**
51
     * @var integer
52
     */
53
    protected $type_key;
54
55
    /**
56
     * @var object
57
     */
58
    protected $db;
59
60
    /**
61
     * @var object
62
     */
63
    protected $dbquery;
64
65
    /**
66
     * @var object
67
     */
68
    public $payment;
69
70
    /**
71
     * @var object currency
72
     */
73
    private $currency;
74
75
    /**
76
     * Constructor
77
     *
78
     * @param object  $kernel The kernel
79
     * @param string  $type   @see $allowed_types
80
     * @param integer $id     Optional debtor id
81
     *
82
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
83
     */
84 68
    public function __construct($kernel, $type, $id = 0)
85
    {
86 68
        $this->kernel = $kernel;
87 68
        $this->type = $type;
88 68
        $this->type_key = array_search($type, self::getDebtorTypes());
0 ignored issues
show
Documentation Bug introduced by
It seems like array_search($type, self::getDebtorTypes()) can also be of type false. However, the property $type_key is declared as type integer. Maybe add an additional type check?

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 the id property of an instance of the Account 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.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
89 68
        if (!isset($this->type_key)) {
90
            throw new Exception('Debtor: Ugyldig type');
91
        }
92
93
        // Her s�tter vi lige type selvom den ikke er loaded, da man nogle
94
        // gange skal bruge type med id = 0 i getList
95 68
        $this->value["type"] = $this->type;
96 68
        $this->value["type_key"] = $this->type_key;
97
98
        // s�tter variable
99 68
        $this->id = (int)$id;
100 68
        $this->db = new DB_Sql;
101 68
        $this->error = new Intraface_Error;
102
103
104 68
        if ($this->id > 0) {
105 11
            $this->load();
106 11
        }
107 68
    }
108
109
    public function destruct()
110
    {
111
        unset($this->kernel);
112
        unset($this->db);
113
        unset($this->error);
114
        unset($this->dbquery);
115
        unset($this->contact); // consider descruct
116
        unset($this->contact_person); // consider descruct
117
        unset($this->item); // consider desctruct
118
    }
119
120 32 View Code Duplication
    function getDBQuery()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
121
    {
122 32
        if ($this->dbquery) {
123 31
            return $this->dbquery;
124
        }
125
126 32
        $this->dbquery = new Intraface_DBQuery($this->kernel, "debtor", "debtor.active = 1 AND debtor.intranet_id = ".$this->kernel->intranet->get("id"));
127 32
        $this->dbquery->setJoin("LEFT", "contact", "debtor.contact_id = contact.id AND contact.intranet_id = ".$this->kernel->intranet->get("id"), '');
128 32
        $this->dbquery->setJoin("LEFT", "address", "address.belong_to_id = contact.id AND address.active = 1 AND address.type = 3", '');
129 32
        $this->dbquery->setJoin("LEFT", "debtor_item", "debtor_item.debtor_id = debtor.id AND debtor_item.active = 1 AND debtor_item.intranet_id = ".$this->kernel->intranet->get("id"), '');
130
131 32
        $this->dbquery->useErrorObject($this->error);
132
133 32
        return $this->dbquery;
134
    }
135
136
    /**
137
     * Creates a debtor
138
     *
139
     * TODO vi b�r vende det her om og finde ud af en standard factory m�de at g�re det p�
140
     * mit forslag: factory($kernel, $type, $id)
141
     *
142
     * @param object  $kernel Kernel
143
     * @param integer $id     Debtor id or debtor identifier_key
144
     * @param type    $tpye   String TODO What is this used for as a last parameter?
0 ignored issues
show
Bug introduced by
There is no parameter named $tpye. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
145
     */
146 2 View Code Duplication
    public static function factory($kernel, $id = 0, $type = "")
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
147
    {
148 2
        if (is_int($id) && $id != 0) {
149
            $types = self::getDebtorTypes();
150
151
            $db = new DB_Sql;
152
            $db->query("SELECT type FROM debtor WHERE intranet_id = ".$kernel->intranet->get('id')." AND id = ".$id);
153
            if ($db->nextRecord()) {
154
                $type = $types[$db->f("type")];
155
            } else {
156
                throw new Exception("Invalid id for debtor in Debtor::factory");
157
            }
158 2
        } elseif (is_string($id) && $id != '') {
159 1
            $types = self::getDebtorTypes();
160
161 1
            $db = new DB_Sql;
162 1
            $db->query("SELECT type, id FROM debtor WHERE intranet_id = ".$kernel->intranet->get('id')." AND identifier_key = \"".$id."\"");
163 1
            if ($db->nextRecord()) {
164 1
                $type = $types[$db->f("type")];
165 1
                $id = $db->f("id");
166 1
            } else {
167
                throw new Exception("Invalid identifier_key for debtor in Debtor::factory");
168
            }
169 1
        }
170
171
        switch ($type) {
172 2
            case "quotation":
173 1
                $kernel->useModule("quotation");
174 1
                $object = new Quotation($kernel, intval($id));
175 1
                return $object;
176
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
177
178 2
            case "order":
179 2
                $kernel->useModule("order");
180 2
                $object = new Order($kernel, intval($id));
181 2
                break;
182
183 1
            case "invoice":
184 1
                $kernel->useModule("invoice");
185 1
                $object = new Invoice($kernel, intval($id));
186 1
                break;
187
188 1
            case "credit_note":
189 1
                $kernel->useModule("invoice");
190 1
                $object = new CreditNote($kernel, intval($id));
191 1
                break;
192
193
            default:
194
                throw new Exception("Ugyldig type: '".$type."'");
195
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
196
        }
197
198 2
        return $object;
199
    }
200
201
    /**
202
     * Loads debtor into an array
203
     *
204
     * @see $this->values;
205
     *
206
     * @return integer
207
     */
208 63
    public function load()
209
    {
210 63
        if ($this->id == 0) {
211
            return 0;
212
        }
213
214 63
        $this->db->query("SELECT id, number, identifier_key, intranet_address_id, contact_id, contact_address_id, contact_person_id, description, payment_method, this_date, due_date, date_stated, voucher_id, date_executed, status, where_from_id, where_from, user_id, round_off, girocode, active, message, internal_note, currency_id, currency_product_price_exchange_rate_id,
215
                DATE_FORMAT(date_stated, '%d-%m-%Y') AS dk_date_stated,
216
                DATE_FORMAT(this_date, '%d-%m-%Y') AS dk_this_date,
217
                DATE_FORMAT(due_date, '%d-%m-%Y') AS dk_due_date,
218
                DATE_FORMAT(date_sent, '%d-%m-%Y') AS dk_date_sent,
219
                DATE_FORMAT(date_executed, '%d-%m-%Y') AS dk_date_executed,
220
                DATE_FORMAT(date_cancelled, '%d-%m-%Y') AS dk_date_cancelled
221 63
            FROM debtor WHERE id = ".$this->id." AND intranet_id = ".$this->kernel->intranet->get("id"));
222
223 63
        if (!$this->db->nextRecord()) {
224
            $this->error->set('Debtoren findes ikke');
225
            return 0;
226
        }
227 63
        $this->value["id"] = $this->db->f("id");
228 63
        $this->value["number"] = $this->db->f("number");
229 63
        $this->value["identifier_key"] = $this->db->f("identifier_key");
230 63
        $this->value["intranet_address_id"] = $this->db->f("intranet_address_id");
231 63
        $this->value["contact_id"] = $this->db->f("contact_id");
232 63
        $this->value["contact_address_id"] = $this->db->f("contact_address_id");
233 63
        $this->value["contact_person_id"] = $this->db->f("contact_person_id");
234 63
        $this->value["description"] = $this->db->f("description");
235 63
        if (empty($this->value["description"])) {
236
            $this->value["description"] = '[Ingen beskrivelse]';
237
        }
238 63
        $this->value["payment_method"] = $this->db->f("payment_method");
239 63
        $payment_methods = $this->getPaymentMethods();
240 63
        $this->value["translated_payment_method"] = $payment_methods[$this->db->f("payment_method")];
241 63
        $this->value["this_date"] = $this->db->f("this_date");
242 63
        $this->value["due_date"] = $this->db->f("due_date");
243 63
        $this->value["date_stated"] = $this->db->f("date_stated");
244 63
        $this->value["is_stated"] = ($this->db->f("date_stated") > '0000-00-00');
245 63
        $this->value["voucher_id"] = $this->db->f("voucher_id");
246 63
        $this->value["dk_date_stated"] = $this->db->f("dk_date_stated");
247 63
        $this->value["dk_this_date"] = $this->db->f("dk_this_date");
248 63
        $this->value["dk_due_date"] = $this->db->f("dk_due_date");
249 63
        $this->value["dk_date_sent"] = $this->db->f("dk_date_sent");
250 63
        $this->value["date_executed"] = $this->db->f("date_executed");
251 63
        $this->value["dk_date_executed"] = $this->db->f("dk_date_executed");
252 63
        $this->value["dk_date_cancelled"] = $this->db->f("dk_date_cancelled");
253 63
        $status_types = $this->getStatusTypes();
254 63
        $this->value["status"] = $status_types[$this->db->f("status")];
255 63
        $this->value["status_id"] = $this->db->f("status");
256 63
        $this->value["currency_id"] = $this->db->f("currency_id");
257 63
        $this->value["currency_product_price_exchange_rate_id"] = $this->db->f("currency_product_price_exchange_rate_id");
258
        // $this->value["is_credited"] = $this->db->f("is_credited");
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
259 63
        $froms = $this->getFromTypes();
260 63
        $this->value["where_from"] = $froms[$this->db->f("where_from")];
261 63
        $this->value["where_from_id"] = $this->db->f("where_from_id");
262 63
        $this->value["user_id"] = $this->db->f("user_id");
263 63
        $this->value["round_off"] = $this->db->f("round_off");
264 63
        $this->value["girocode"] = $this->db->f("girocode");
265 63
        $this->value["message"] = $this->db->f("message");
266 63
        $this->value["internal_note"] = $this->db->f("internal_note");
267 63
        $this->value["active"] = $this->db->f("active");
268
269
        // Bruges til at afg�re, hvor debtor er sendt hent til
270 63
        $db = new DB_Sql;
271 63
        $db->query("SELECT id, type FROM debtor WHERE where_from > 2 AND where_from_id = " . $this->id . " AND active = 1");
272 63
        if ($db->nextRecord()) {
273 2
            if ($db->f('type') > 0) {
274 2
                $types = self::getDebtorTypes();
275 2
                $this->value['where_to'] = $types[$db->f('type')];
276 2
            } else {
277
                $this->value['where_to'] = '';
278
            }
279 2
            $this->value['where_to_id'] = $db->f('id');
280 2
        } else {
281 63
            $this->value['where_to'] = '';
282 63
            $this->value['where_to_id'] = 0;
283
        }
284
285 63 View Code Duplication
        if ($this->get("status") == "executed" || $this->get("status") == "cancelled") {
286 8
            $this->value["locked"] = true;
287 8
        } else {
288 63
            $this->value["locked"] = false;
289
        }
290
291
        // henter kunden
292 63
        require_once 'Intraface/modules/contact/Contact.php';
293 63
        $this->contact = new Contact($this->kernel, $this->db->f("contact_id"), $this->db->f("contact_address_id"));
0 ignored issues
show
Unused Code introduced by
The call to Contact::__construct() has too many arguments starting with $this->db->f('contact_address_id').

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
294 63 View Code Duplication
        if ($this->contact->get("type") == "corporation" && $this->db->f("contact_person_id") != 0) {
295 3
            $this->contact_person = new ContactPerson($this->contact, $this->db->f("contact_person_id"));
0 ignored issues
show
Documentation Bug introduced by
It seems like new \ContactPerson($this...f('contact_person_id')) of type object<ContactPerson> is incompatible with the declared type object<contact_person> of property $contact_person.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
296 3
        }
297
298
        // henter items p� debtoren
299 63
        $item = $this->getItems();
300 63
        $this->value['items'] = $item;
301
302
        // @todo Currency is always loaded, should be done with left join. Oh give me more doctrine!
303 63
        $currency = $this->getCurrency();
304
305 63
        for ($i = 0, $max = count($item), $total = 0, $total_currency = 0; $i<$max; $i++) {
306 15
            $total += $item[$i]["amount"]->getAsIso();
307 15
            if ($currency) {
308 2
                $total_currency += $item[$i]['amount_currency']->getAsIso();
309 2
            }
310 15
        }
311
312
        // no round off of curreny yet!
313 63
        if ($this->get("round_off") == 1 && $this->get("type") == "invoice") {
314
            $decimal = $total - floor($total);
315
            $decimal *= 4;
316
            $decimal = round($decimal)/4;
317
            $total = $decimal + floor($total);
318
        }
319
320 63
        $this->value["total"] = round($total, 2);
321 63
        if ($currency) {
322 6
            $this->value['total_currency'] = round($total_currency, 2);
323 6
        }
324 63
        $this->value['payment_total'] = 0;
325
326 63
        if ($this->value["type"] == "invoice") {
327 31
            foreach ($this->getDebtorAccount()->getList() as $payment) {
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Debtor as the method getDebtorAccount() does only exist in the following sub-classes of Debtor: Invoice. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
328 10
                $this->value['payment_total'] += $payment["amount"];
329 31
            }
330 31
        }
331
332 63
        $this->value['arrears'] = $this->value['total'] - $this->value['payment_total'];
333
334 63
        return true;
335
    }
336
337
    public function validate($input)
338
    {
339
        if (!is_array($input)) {
340
            throw new Exception('Debtor->update(): $input er ikke et array');
341
        }
342
343
        if ($this->get('locked') == true) {
344
            $this->error->set('This is locked and cannot be updated');
345
            return 0;
346
        }
347
    }
348
349
    /**
350
     * update()
351
     *
352
     * @param array   $input
353
     * @param string  $from    Bruges til at fort�lle, hvor debtoren kommer fra, fx webshop eller quotation
354
     * @param integer $from_id Hvis debtoren kommer fra en anden debtor.
355
     */
356 63
    public function update($input, $from = 'manuel', $from_id = 0)
357
    {
358 63
        settype($input['payment_method'], 'integer');
359 63
        settype($input['girocode'], 'string');
360 63
        settype($input['message'], 'string');
361
362 63
        $input = safeToDb($input);
363 63
        $from = safeToDb($from);
364 63
        $from_id = (int)$from_id;
365
366
        // nummeret
367 63
        if (empty($input["number"])) {
368 63
            $input["number"] = $this->getMaxNumber() + 1;
369 63
        }
370
371
        // starte validatoren
372 63
        $validator = new Intraface_Validator($this->error);
373
374 63
        $validator->isNumeric($input["number"], "Nummeret (".$input["number"].")  skal v�re et tal", "greater_than_zero");
375 63
        if (!$this->isNumberFree($input["number"])) {
376
            $this->error->set("Nummeret er allerede benyttet");
377
        }
378
379 63
        $validator->isString($input['description'], 'Fejl i beskrivelse', '', 'allow_empty');
380 63
        $validator->isString($input['girocode'], 'error in girocode', '', 'allow_empty');
381 63
        $validator->isString($input['message'], 'error in message', '', 'allow_empty');
382 63
        $validator->isNumeric($input["contact_id"], "Du skal angive en kunde", "greater_than_zero");
383
384 63
        if ($validator->isDate($input["this_date"], "Ugyldig dato", "allow_no_year")) {
385 63
            $this_date = new Intraface_Date($input["this_date"]);
386 63
            $this_date->convert2db();
387 63
        }
388
389 63
        if ($this->type == "invoice") {
390
          // Hvis det er en faktura skal der indtastes en due_date, ellers er det ligegyldigt!
391 31 View Code Duplication
            if ($validator->isDate($input["due_date"], "Ugyldig leveringsdato", "allow_no_year")) {
392 31
                $due_date = new Intraface_Date($input["due_date"]);
393 31
                $due_date->convert2db();
394 31
                $due_date_db = $due_date->get();
395 31
            }
396 31
        } else {
397 32
            if ($validator->isDate($input["due_date"], "Ugyldig leveringsdato", "allow_no_year,allow_empty")) {
398
                // der skal laves en due-date, som bare bliver dags datoe, hvis ikke der er indtastet nogen.
399 32 View Code Duplication
                if (!empty($input["due_date"])) {
400 32
                    $due_date = new Intraface_Date($input["due_date"]);
401 32
                    $due_date->convert2db();
402 32
                    $due_date_db = $due_date->get();
403 32
                } else {
404
                    $due_date_db = date('Y-m-d');
405
                }
406 32
            }
407
        }
408
409
        // kunde
410 63
        $contact = new Contact($this->kernel, $input["contact_id"]);
411 63 View Code Duplication
        if (is_object($contact->address)) {
412 63
            $contact_address_id = $contact->address->get("address_id");
413 63
        } else {
414
            $this->error->set("Ugyldig kunde");
415
        }
416
417 63
        if ($contact->get("type") == "corporation") {
418 3
            $validator->isNumeric($input["contact_person_id"], "Der er ikke angivet en kontaktperson");
419 3
        } else {
420 60
            $input["contact_person_id"] = 0;
421
        }
422
423
424 63
        if ($this->error->isError()) {
425
            return 0;
426
        }
427
428 63
        $internal_note_sql = '';
429 63
        if (isset($input['internal_note'])) {
430 12
            $internal_note_sql = ", internal_note = '".$input['internal_note']."'";
431 12
        }
432
433 63
        $currency_id = 0;
434 63
        $currency_exchange_rate_id = 0;
435 63
        if (isset($input['currency']) && is_object($input['currency'])) {
436 6
            $currency_id = $input['currency']->getId();
437 6
            $currency_exchange_rate_id = $input['currency']->getProductPriceExchangeRate()->getId();
438 6
        }
439
440 63
        if (isset($input["round_off"]) && intval($input["round_off"])) {
441
            $input["round_off"] = 1;
442
        } else {
443 63
            $input["round_off"] = 0;
444
        }
445
446
      // user_id = ".$this->kernel->user->get('id').", // skal puttes p�, men kun hvis det ikke er fra webshop.
447 63
        $db = new DB_Sql;
448 63
        if ($this->id == 0) {
449 63
            $infinite_check = 0;
450 63
            $random = new Ilib_RandomKeyGenerator();
451
            do {
452 63
                $identifier = $random->generate(30);
453 63
                $db->query('SELECT id FROM debtor WHERE identifier_key = "'.$identifier.'" AND intranet_id = '.$this->kernel->intranet->get('id'));
454 63
                $infinite_check++;
455 63
                if ($infinite_check > 20) {
456
                    throw new Exception('Unable to generate an unique key');
457
                }
458 63
            } while ($db->nextRecord());
459
460 63
            $sql_type = "INSERT INTO ";
461 63
            $sql_after = ", date_created = NOW(), identifier_key = \"".$identifier."\", intranet_id = " . $this->kernel->intranet->get('id');
462 63
        } else {
463
            $sql_type = "UPDATE ";
464
            $sql_after = " WHERE id = " . $this->id . " AND intranet_id = " . $this->kernel->intranet->get('id');
465
        }
466 63
        $sql = $sql_type . "debtor SET contact_id = " . $contact->get('id') . ",
467 63
            contact_address_id = ".$contact_address_id.",
0 ignored issues
show
Bug introduced by
The variable $contact_address_id does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
468 63
            contact_person_id = ".$input['contact_person_id'].",
469 63
            intranet_address_id = ".$this->kernel->intranet->address->get("address_id").",
470
            date_changed = NOW(),
471 63
            due_date = '".$due_date_db."',
0 ignored issues
show
Bug introduced by
The variable $due_date_db does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
472 63
            this_date = '".$this_date->get()."',
0 ignored issues
show
Bug introduced by
The variable $this_date does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
473 63
            type = '".$this->type_key."',
474 63
            number='".$input['number']."',
475 63
            description = '".$input['description']."',
476 63
            message = '".$input['message']."',
477 63
            round_off = ".$input["round_off"].",
478 63
            currency_id = ".$currency_id.",
479 63
            currency_product_price_exchange_rate_id = ".$currency_exchange_rate_id.",
480 63
            payment_method=".$input['payment_method'].",
481 63
            girocode='".$input['girocode']."' " . $internal_note_sql . $sql_after;
482
483
            // attention_to = '". $input['attention_to'] ."',
484
485 63
        $db->query($sql);
486
487 63
        if ($this->id == 0) {
488 63
            $this->id = $db->insertedId();
489 63
            $this->setFrom($from, $from_id);
490 63
        }
491
492 63
        if (is_object($this->kernel->user) and strtolower(get_class($this->kernel->user)) == 'user') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
493
            $db->query("UPDATE debtor SET user_id = ".$this->kernel->user->get('id')." WHERE id = " . $this->id);
494
        }
495
496 63
        $this->load();
497
498 63
        return (int)$this->id;
499
    }
500
501
    /**
502
     * M� kun bruges hvis hele ordren skal slettes
503
     *
504
     * @return boolean
505
     */
506 1
    public function delete()
507
    {
508 1
        if ($this->id > 0 and $this->get("locked") == true) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
509
            $this->error->set('Posten er l�st og kan ikke slettes');
510
            return false;
511
        }
512 1
        $db = new DB_Sql;
513 1
        $db->query("SELECT id FROM debtor WHERE id = " . $this->id . " AND intranet_id = " . $this->kernel->intranet->get('id'). " AND type = '".$this->type_key."' LIMIT 1");
514 1
        if ($db->nextRecord()) {
515 1
            $db->query("UPDATE debtor SET active = 0 WHERE id = " . $this->id . " AND intranet_id = " . $this->kernel->intranet->get('id') . "  AND type = '".$this->type_key."'");
516 1
            return true;
517
        }
518
        return false;
519
    }
520
521
    /**
522
     * Funktionen bruges til at gemme et debitorobjekt som et andet.
523
     * Denne funktion er nyttig, n�r jeg fx skal transformere et tilbud til en ordre. S� smider
524
     * jeg bare et objekt med tilbuddet ind i et nyt objekt jeg skaber med ordre, og s� g�r
525
     * det hele automatisk.
526
     *
527
     * TODO Kunne v�re vakst om den lige gav det nye objekt en beskrivelse.
528
     *
529
     * <code>
530
     * $quot_id = 10;
531
     * $quot = new Debtor($kernel, 'quotation', $quot_id);
532
     * $order = new Debtor($kernel, 'order');
533
     * $order->create($quot);
534
     * </code>
535
     *
536
     * @param $object $debtor_object Debtor object
0 ignored issues
show
Documentation introduced by
The doc-type $object could not be parsed: Unknown type name "$object" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
537
     *
538
     * @return integer
539
     */
540 2
    public function create($debtor_object)
541
    {
542 2
        if (!is_object($debtor_object)) {
543
            throw new Exception('Debtor: create() har brug for et debtor-objekt, jeg kan skabe et nyt debtorobjekt med');
544
        }
545
546 2
        if ($debtor_object->get("type") == "invoice") {
547
            if ($debtor_object->get("status") == "created" || $debtor_object->get("status") == "cancelled") {
548
                $this->error->set('Debtor::Created kan ikke lave kreditnota fra faktura, når fakturaen ikke er sendt eller færdigbehandlet');
549
                return false;
550
            }
551
        } else {
552 2
            if ($debtor_object->get('locked') == true) {
553
                $this->error->set('Objektet er låst, så du kan ikke lave et nyt objekt fra det.');
554
                return false;
555
            }
556
        }
557
558 2
        $values = $debtor_object->get();
559 2
        $values['this_date'] = date('d-m-Y');
560 2
        $values['number'] = ''; // nulstiller nummeret ellers vil den få samme nummer
561 2
        $values['currency'] = $debtor_object->getCurrency();
562
563 2
        switch ($this->type) {
564 2
            case "invoice":
565
                $values['due_date'] = date("d-m-Y", time() + 24 * 60 * 60 * $debtor_object->contact->get("paymentcondition"));
566
                if (empty($values['payment_method']) and $this->kernel->setting->get('intranet', 'bank_account_number')) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
567
                    $values['payment_method'] = 1;
568
                }
569
                break;
570 2
            case "order":
571 2
            default:
572 2
                $values['due_date'] = date('d-m-Y');
573 2
                break;
574 2
        }
575
576 2
        if ($new_debtor_id = $this->update($values, $debtor_object->get("type"), $debtor_object->get('id'))) {
577 2
            $items = $debtor_object->getItems();
578
579 2
            foreach ($items as $item) {
580
                $this->loadItem();
581
                $debtor_object->loadItem($item['id']);
582
                $item_values = $debtor_object->item->get();
583
                $item_values["quantity"] = number_format($item_values["quantity"], 2, ",", "");
584
                $this->item->save($item_values);
0 ignored issues
show
Bug introduced by
The property item does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
585 2
            }
586
587 2
            if ($this->type != "credit_note") {
588
                // Hvis det er en credit_note, s� skal fakturanet ikke l�ses, da man ikke ved om kreditnotaen er p� hele fakturaen
589 2
                $debtor_object->setStatus('executed');
590 2
            }
591
592
            // Overf�rsel af onlinebetaling fra ordre til faktura.
593 2
            if ($debtor_object->get('type') == "order" && $this->kernel->intranet->hasModuleAccess('onlinepayment')) {
594
                $onlinepayment_module = $this->kernel->useModule('onlinepayment', true); // true: ignore user permisssion
0 ignored issues
show
Unused Code introduced by
$onlinepayment_module is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
595
                $onlinepayment = OnlinePayment::factory($this->kernel);
596
597
                $onlinepayment->getDBQuery()->setFilter('belong_to', 'order');
598
                $onlinepayment->getDBQuery()->setFilter('belong_to_id', $debtor_object->get('id'));
599
                $payment_list = $onlinepayment->getlist();
600
601
                foreach ($payment_list as $p) {
602
                    $tmp_onlinepayment = OnlinePayment::factory($this->kernel, 'id', $p['id']);
603
                    $tmp_onlinepayment->changeBelongTo('invoice', $new_debtor_id);
604
                }
605
            }
606
607 2
            return $new_debtor_id;
608
        }
609
        return false;
610
    }
611
612
    ////////////////////////////////////////////////////////////////////////////////////////////////////////
613
614
    /**
615
     * S�tter status for debtoren
616
     *
617
     * @return true / false
618
     */
619 15
    public function setStatus($status)
620
    {
621 15 View Code Duplication
        if (is_string($status)) {
622 15
            $status_id = array_search($status, $this->getStatusTypes());
623 15
            if ($status_id === false) {
624
                throw new Exception("Debtor->setStatus(): Ugyldig status (streng)");
625
            }
626 15
        } else {
627
            $status_id = intval($status);
628
            $status_types = $this->getStatusTypes();
629
            if (isset($status_types[$status_id])) {
630
                $status = $status_types[$status];
631
            } else {
632
                throw new Exception("Debtor->setStatus(): Ugyldig status (integer)");
633
            }
634
        }
635
636 15
        if ($status_id == $this->get("status_id")) {
637
            throw new Exception("Du kan ikke sætte status til samme som den er i forvejen");
638
        }
639 15
        if (($this->get("type") != "invoice" && $status_id < $this->get("status_id")) || ($this->get("type") == "invoice" && $this->get("status") != "executed" && $status_id < $this->get("status_id"))) {
640
            // Man kan godt gå fra executed til sent, hvis f.eks. en betalt faktura bliver efterfølgende bliver krediteret
641
            throw new Exception("Du kan ikke sætte status lavere end den er i forvejen");
642
        }
643
644 View Code Duplication
        switch ($status) {
645 15
            case "sent":
646 12
                $sql = "date_sent = NOW()";
647 12
                break;
648
649 8
            case "executed":
650 8
                $sql = "date_executed = NOW()";
651 8
                break;
652
653
            case "cancelled":
654
                $sql = "date_cancelled = NOW()";
655
                break;
656
657
            default:
658
                throw new Exception("Dette kan ikke lade sig gøre! Debtor->setStatus()");
659
        }
660
661 15
        $db = new Db_Sql;
662 15
        $db->query("UPDATE debtor SET status = ".$status_id.", ".$sql."  WHERE id = " . $this->id . " AND intranet_id = " . $this->kernel->intranet->get('id'));
663 15
        $this->load();
664
665 15
        return true;
666
    }
667
668
    /**
669
     * S�tter hvorfra debtoren er indtastet. B�r kun bruges, hvis ikke det stammer fra modulet selv,
670
     *  fx fra en webshop, eller hvor de bliver skabt fra et andet sted, fx en ordre skabt fra et tilbud-
671
     *
672
     * @param string  $from    Where from
673
     * @param integer $from_id From id
674
     *
675
     * @return true / false
676
     */
677 63
    private function setFrom($from = 'manuel', $from_id = 0)
678
    {
679 63
        $from = array_search($from, $this->getFromTypes());
680 63
        if ($from === false) {
681
            throw new Exception('Debtor->setFrom(): Ugyldig from');
682
        }
683 63
        $from_id = (int)$from_id;
684
685 63
        if ($this->error->isError()) {
686
            return false;
687
        }
688 63
        $db = new Db_Sql;
689 63
        $db->query("UPDATE debtor SET where_from = ".(int)$from.", where_from_id = " . $from_id . " WHERE id = " . $this->id);
690 63
        return true;
691
    }
692
693
    /**
694
     * setNewContact();
695
     * Bruges til at skifte kunden p� en debtor, er fx nyttig ved webshopordrene, hvis
696
     * kunden allerede findes i systemet.
697
     * M�ske den burde indholde en kontrol af at kunden overhovedet findes og tilh�re dette intranet /Sune (21/3 2005)
698
     *
699
     * @param $contact_id int
700
     *
701
     * @return boolean
702
     */
703 1
    public function setNewContact($contact_id)
704
    {
705 1
        if ($this->id == 0) {
706
            return false;
707
        }
708 1
        $contact_id = (int)$contact_id;
709 1
        $db = new DB_Sql;
710 1
        $db->query("UPDATE debtor SET contact_id = " . $contact_id . " WHERE id = " . $this->id . " AND intranet_id = " . $this->kernel->intranet->get("id") . " AND type='".$this->type_key."'");
711
712 1
        return true;
713
    }
714
715
    function getFromShopId()
716
    {
717
        if ($this->value['where_from'] == 'webshop') {
718
            return $this->value['where_from_id'];
719
        }
720
        throw new Exception('Not from a shop');
721
    }
722
723
    //////////////////////////////////////////////////////////////////////////////////////////////////////
724
725
    /**
726
     * Bruges til at lave en menu p� kontakten eller produktet
727
     *
728
     * @param string  $type    contact eller product
729
     * @param integer $type_id id p� contact eller product.
730
     *
731
     * @return integer
732
     */
733 2
    public function any($type, $type_id, $variation_id = 0)
734
    {
735
        switch ($type) {
736 2
            case 'contact':
737
                $sql = "SELECT id
738
                FROM debtor
739 1
                    WHERE intranet_id = " . $this->kernel->intranet->get("id") . "
740 1
                        AND contact_id = ".(int)$type_id."
741 1
              AND type='".$this->type_key."'
742 1
              AND active = 1";
743 1
                break;
744 1
            case 'product':
745
                $sql = "SELECT DISTINCT(debtor.id)
746
                    FROM debtor
747
                    INNER JOIN debtor_item ON debtor_item.debtor_id = debtor.id
748 1
                    WHERE debtor.intranet_id = ".$this->kernel->intranet->get("id")."
749 1
                        AND debtor.type=".$this->type_key."
750
                        AND debtor.active = 1
751 1
                        AND debtor_item.intranet_id = ".$this->kernel->intranet->get("id")."
752
                        AND debtor_item.active = 1
753 1
                        AND debtor_item.product_id = ".(int)$type_id."
754 1
                        AND debtor_item.product_variation_id = ".(int)$variation_id;
755 1
                break;
756
            default:
757
                throw new Exception("Ugyldg type i Debtor->any");
758
        }
759
760 2
        $db = new DB_Sql;
761 2
        $db->query($sql);
762 2
        return $db->numRows();
763
    }
764
765
    /**
766
     * Funktion til at finde ud af, om der er oprettet nogen poster af den aktuelle bruger
767
     *
768
     * @return integer
769
     */
770
    public function isFilledIn()
771
    {
772
        $db = new DB_Sql;
773
        $db->query("SELECT id FROM debtor WHERE type = " . $this->type_key . " AND intranet_id = " . $this->kernel->intranet->get('id'));
774
        return $db->numRows();
775
    }
776
777
    /**
778
     * Gets a list with debtors
779
     *
780
     * @return array
781
     */
782 31 View Code Duplication
    public function getList()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
783
    {
784 31
        $db = new DB_Sql;
0 ignored issues
show
Unused Code introduced by
$db is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
785
786 31
        $this->dbquery = $this->getDBQuery();
787
788 31
        $this->dbquery->setCondition("debtor.type = ".$this->get("type_key"));
789
790 31
        if ($this->dbquery->checkFilter("contact_id")) {
791
            $this->dbquery->setCondition("debtor.contact_id = ".intval($this->dbquery->getFilter("contact_id")));
792
        }
793
794 31
        if ($this->dbquery->checkFilter("text")) {
795
            $this->dbquery->setCondition("(debtor.description LIKE \"%".$this->dbquery->getFilter("text")."%\" OR debtor.girocode = \"".$this->dbquery->getFilter("text")."\" OR debtor.number = \"".$this->dbquery->getFilter("text")."\" OR address.name LIKE \"%".$this->dbquery->getFilter("text")."%\")");
796
        }
797
798 31
        if ($this->dbquery->checkFilter("product_id")) {
799
            $this->dbquery->setCondition("debtor_item.product_id = ".$this->dbquery->getFilter('product_id'));
800
            if ($this->dbquery->checkFilter("product_variation_id")) {
801
                $this->dbquery->setCondition("debtor_item.product_variation_id = ".$this->dbquery->getFilter('product_variation_id'));
802
            } else {
803
                $this->dbquery->setCondition("debtor_item.product_variation_id = 0");
804
            }
805
        }
806
807 31
        if ($this->dbquery->checkFilter("date_field")) {
808
            if (in_array($this->dbquery->getFilter("date_field"), array('this_date', 'date_created', 'date_sent', 'date_executed', 'data_cancelled'))) {
809
                $date_field = $this->dbquery->getFilter("date_field");
810
            } else {
811
                $this->error->set("Ugyldigt datointerval felt");
812
            }
813
        } else {
814 31
            $date_field = 'this_date';
815
        }
816
817 31
        if ($this->dbquery->checkFilter("from_date")) {
818
            $date = new Intraface_Date($this->dbquery->getFilter("from_date"));
819
            if ($date->convert2db()) {
820
                $this->dbquery->setCondition("debtor.".$date_field." >= \"".$date->get()."\"");
0 ignored issues
show
Bug introduced by
The variable $date_field does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
821
            } else {
822
                $this->error->set("Fra dato er ikke gyldig");
823
            }
824
        }
825
826
        // Poster med fakturadato f�r slutdato.
827 31
        if ($this->dbquery->checkFilter("to_date")) {
828
            $date = new Intraface_Date($this->dbquery->getFilter("to_date"));
829
            if ($date->convert2db()) {
830
                $this->dbquery->setCondition("debtor.".$date_field." <= \"".$date->get()."\"");
831
            } else {
832
                $this->error->set("Til dato er ikke gyldig");
833
            }
834
        }
835
        // alle ikke bogf�rte skal findes
836 31
        if ($this->dbquery->checkFilter("not_stated")) {
837
            $this->dbquery->setCondition("voucher_id = 0");
838
        }
839
840
841 31
        if ($this->dbquery->checkFilter("status")) {
842
            if ($this->dbquery->getFilter("status") == "-1") {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
843
                // Beh�ves ikke, den tager alle.
844
                // $this->dbquery->setCondition("status >= 0");
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
845
            } elseif ($this->dbquery->getFilter("status") == "-2") {
846
                // Not executed = �bne
847
                if ($this->dbquery->checkFilter("to_date")) {
848
                    $date = new Intraface_Date($this->dbquery->getFilter("to_date"));
849
                    if ($date->convert2db()) {
850
                        // Poster der er executed eller cancelled efter dato, og sikring at executed stadig er det, da faktura kan s�ttes tilbage.
851
                        $this->dbquery->setCondition("(debtor.date_executed >= \"".$date->get()."\" AND debtor.status = 2) OR (debtor.date_cancelled >= \"".$date->get()."\") OR debtor.status < 2");
852
                    }
853
                } else {
854
                    // Hvis der ikke er nogen dato s� tager vi alle dem som p� nuv�rende tidspunkt har status under
855
                    $this->dbquery->setCondition("debtor.status < 2");
856
                }
857
            } elseif ($this->dbquery->getFilter("status") == "-3") {
858
                //  Afskrevne. Vi tager f�rst alle sendte og executed.
859
860
                if ($this->get("type") != "invoice") {
861
                    throw new Exception("Afskrevne kan kun benyttes ved faktura");
862
                }
863
864
                $this->dbquery->setJoin("INNER", "invoice_payment", "invoice_payment.payment_for_id = debtor.id", "invoice_payment.intranet_id = ".$this->kernel->intranet->get("id")." AND invoice_payment.payment_for = 1");
865
                $this->dbquery->setCondition("invoice_payment.type = -1");
866
867
                if ($this->dbquery->checkFilter("to_date")) {
868
                    $date = new Intraface_Date($this->dbquery->getFilter("to_date"));
869
                    if ($date->convert2db()) {
870
                        // alle som er sendte p� datoen og som ikke er cancelled
871
                        $this->dbquery->setCondition("debtor.date_sent <= '".$date->get()."' AND debtor.status != 3");
872
                        $this->dbquery->setCondition("invoice_payment.payment_date <= '".$date->get()."'");
873
                    }
874
                } else {
875
                    // Hvis der ikke er nogen dato s� tager vi alle dem som p� nuv�rende tidspunkt har status under
876
                    $this->dbquery->setCondition("status = 1 OR status = 2");
877
                }
878
            } else {
879
                $this->dbquery->setCondition("debtor.status = ".intval($this->dbquery->getFilter("status")));
880
881
                /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
882
                // New date_field handles this instead
883
                switch ($this->dbquery->getFilter("status")) {
884
                    case "0":
885
                        $to_date_field = "date_created";
886
                        break;
887
888
                    case "1":
889
                        $to_date_field = "date_sent";
890
                        break;
891
892
                    case "2":
893
                        $to_date_field = "date_executed";
894
                        break;
895
896
                    case "3":
897
                        $to_date_field = "data_cancelled";
898
                        break;
899
                }
900
901
                if ($this->dbquery->checkFilter("to_date")) {
902
                    $date = new Intraface_Date($this->dbquery->getFilter("to_date"));
903
                    if ($date->convert2db()) {
904
                        // This gives a problem: We have an invoice created 20/4 and is executed 5/5
905
                        // If we make a search: executed 1/4-30/4 the above invoice will not be calculated in with date search below.
906
                        // And if we make a search : executed 1/5-30/5 it will not even be included in that search.
907
                        // Why was this made in that way?
908
                        // $this->dbquery->setCondition("debtor.".$to_date_field." <= \"".$date->get()."\"");
909
                        // So instead we add this normal status search: Changed 12/7 2009 /Sune
910
                        $this->dbquery->setCondition("debtor.status = ".intval($this->dbquery->getFilter("status")));
911
                    }
912
                } else {
913
                    // tager dem som p� nuv�rende tidspunkt har den angivet status
914
                    $this->dbquery->setCondition("debtor.status = ".intval($this->dbquery->getFilter("status")));
915
                }
916
                */
917
            }
918
        }
919
920 31
        switch ($this->dbquery->getFilter("sorting")) {
921 31
            case 1:
922
                $this->dbquery->setSorting("debtor.number ASC");
923
                break;
924 31
            case 2:
925
                $this->dbquery->setSorting("contact.number ASC");
926
                break;
927 31
            case 3:
928
                $this->dbquery->setSorting("address.name ASC");
929
                break;
930 31
            default:
931 31
                $this->dbquery->setSorting("debtor.number DESC");
932 31
        }
933
934 31
        $db = $this->dbquery->getRecordset("DISTINCT(debtor.id)", "", false);
935 31
        $i = 0;
936 31
        $list = array();
937
938 31
        while ($db->nextRecord()) {
939
            $debtor = self::factory($this->kernel, (int)$db->f("id"));
940
            $list[$i] = $debtor->get();
941
942
            // $contact = new Contact($this->kernel, $db->f('contact_id'));
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
943
            if (is_object($debtor->contact->address)) {
944
                $list[$i]['contact'] = $debtor->contact->get();
945
                $list[$i]['contact']['address'] = $debtor->contact->address->get();
946
947
                // f�lgende skal v�k
948
                $list[$i]['contact_id'] = $debtor->contact->get('id');
949
                $list[$i]['name'] = $debtor->contact->address->get('name');
950
                $list[$i]['address'] = $debtor->contact->address->get('address');
951
                $list[$i]['postalcode'] = $debtor->contact->address->get('postcode');
952
                $list[$i]['city'] = $debtor->contact->address->get('city');
953
            }
954
            $debtor->destruct();
955
            unset($debtor);
956
            $i++;
957
        }
958 31
        unset($db);
959 31
        return $list;
960
    }
961
962
    /**
963
     * Checks whether a product number is available
964
     *
965
     * @return boolean
966
     */
967 63
    private function isNumberFree($number)
968
    {
969 63
        $number = safeToDb($number);
970 63
        $db = new DB_Sql;
971 63
        $sql = "SELECT id FROM debtor WHERE intranet_id = " . $this->kernel->intranet->get('id') . " AND number = '".$number."' AND type = '".$this->type_key."' AND id != " . $this->id." AND active = 1";
972 63
        $db->query($sql);
973 63
        if ($db->numRows() == 0) {
974 63
            return true;
975
        }
976
        return false;
977
    }
978
979
    /**
980
     * Gets the max number
981
     *
982
     * @return integer
983
     */
984 63
    public function getMaxNumber()
985
    {
986 63
        $db = new DB_Sql;
987 63
        $db->query("SELECT MAX(number) AS max_number FROM debtor WHERE intranet_id = ".$this->kernel->intranet->get("id")." AND type=".$this->type_key." AND active = 1");
988 63
        if ($db->nextRecord()) {
989 63
            return $db->f('max_number');
990
        }
991
        return 0;
992
    }
993
994
    ////////////////////////////////////////////////////////////////////////////////////////////////////
995
996
    /**
997
     * Loads the items
998
     *
999
     * @return void
1000
     */
1001 64
    public function loadItem($id = 0)
1002
    {
1003 64
        require_once 'DebtorItem.php';
1004 64
        $this->item = new DebtorItem($this, (int)$id);
1005 64
    }
1006
1007
    /**
1008
     * Gets all items
1009
     *
1010
     * @return array
1011
     */
1012 63
    public function getItems()
1013
    {
1014 63
        $this->loadItem();
1015 63
        return $this->item->getList();
1016
    }
1017
1018
    /**
1019
     * Adds an item
1020
     *
1021
     * @return void
1022
     */
1023
    public function addItem($item)
0 ignored issues
show
Unused Code introduced by
The parameter $item is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1024
    {
1025
        // TODO hide the implementation details of how to add an item. Also to conform with basket.
1026
        throw new Exception('Add item not implemented yet');
1027
    }
1028
1029
    /* FUNKTIONER TIL BOGF�RING ***********************************************************/
1030
1031
    /**
1032
     * Dummy method to checks whether the debtor can be stated
1033
     * This method is overwritten in the extended class.
1034
     *
1035
     * @return boolean
1036
     */
1037
    public function readyForState()
1038
    {
1039
        $this->error->set('Denne type kan ikke bogf�res');
1040
        return false;
1041
    }
1042
1043
    /**
1044
     * Set the debtor as stated
1045
     *
1046
     * @param integer $voucher_id   The voucher id
1047
     * @param string  $voucher_date Which date is it stated
1048
     *
1049
     * @return boolean
1050
     */
1051 4 View Code Duplication
    public function setStated($voucher_id, $voucher_date)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1052
    {
1053
        // FIXME - check on date
1054 4
        $db = new DB_Sql;
1055 4
        $db->query("UPDATE debtor SET date_stated = '" . $voucher_date . "', voucher_id = '".$voucher_id."' WHERE id = " . $this->id . " AND intranet_id = " . $this->kernel->intranet->get('id'));
1056 4
        return true;
1057
    }
1058
1059
    /**
1060
     * Check whether debtor has been stated
1061
     *
1062
     * @return boolean
1063
     */
1064 8
    public function isStated()
1065
    {
1066 8
        if ($this->get("date_stated") > '0000-00-00') {
1067 4
            return true;
1068
        }
1069 8
        return false;
1070
    }
1071
1072
    /////////////////////////////////////////////////////////////////////////////////////////////////////
1073
1074
    /**
1075
     * Gets invoice text
1076
     *
1077
     * @return string
1078
     */
1079
    public function getInvoiceText()
1080
    {
1081
        return $this->kernel->setting->get('intranet', 'debtor.invoice.text');
1082
    }
1083
1084
    /**
1085
     * Gets contact information
1086
     *
1087
     * @return array
1088
     */
1089
    public function getContactInformation()
1090
    {
1091
        $intranet = array();
1092
        switch ($this->kernel->setting->get('intranet', 'debtor.sender')) {
1093
            case 'intranet':
1094
                // void
1095
                break;
1096
            case 'user':
1097
                // @todo needs to be changed in order to work with contactlogin
1098
                // hack hack hack
1099
                if (isset($this->kernel->user) and is_object($this->kernel->user) and method_exists($this->kernel->user, 'getAddress')) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1100
                    $intranet['email'] = $this->kernel->user->getAddress()->get('email');
1101
                    $intranet['contact_person'] = $this->kernel->user->getAddress()->get('name');
1102
                    $intranet['phone'] = $this->kernel->user->getAddress()->get('phone');
1103
                }
1104
                break;
1105 View Code Duplication
            case 'defined':
1106
                $intranet['email'] = $this->kernel->setting->get('intranet', 'debtor.sender.email');
1107
                $intranet['contact_person'] = $this->kernel->setting->get('intranet', 'debtor.sender.name');
1108
                break;
1109
        }
1110
1111
        return $intranet;
1112
    }
1113
1114
    /**
1115
     * Gets the payment information
1116
     *
1117
     * @return array
1118
     */
1119 View Code Duplication
    function getPaymentInformation()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1120
    {
1121
        $info = array('bank_name'    => $this->kernel->setting->get("intranet", "bank_name"),
1122
                      'bank_reg_number' => $this->kernel->setting->get("intranet", "bank_reg_number"),
1123
                      'bank_account_number' => $this->kernel->setting->get("intranet", "bank_account_number"),
1124
                      'giro_account_number' => $this->kernel->setting->get("intranet", "giro_account_number")
1125
        );
1126
1127
        return $info;
1128
    }
1129
1130
    /**
1131
     * Gets the intranet address
1132
     *
1133
     * @return object
1134
     */
1135
    public function getIntranetAddress()
1136
    {
1137
        return new Intraface_Address($this->get("intranet_address_id"));
1138
    }
1139
1140 2
    function getContact()
1141
    {
1142 2
        return new Contact($this->kernel, $this->get("contact_id"), $this->get("contact_address_id"));
0 ignored issues
show
Unused Code introduced by
The call to Contact::__construct() has too many arguments starting with $this->get('contact_address_id').

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
1143
    }
1144
1145
    /**
1146
     * Returns currency if debtor is in another currency.
1147
     *
1148
     * @todo it is wrong that doctrine connection is created here. Should be given to Debtor object.
1149
     * @return mixed object currency when currency set or false.
1150
     *
1151
     */
1152 63 View Code Duplication
    public function getCurrency()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1153
    {
1154
1155 63
        if ($this->get('currency_id') == 0 || $this->get('currency_product_price_exchange_rate_id') == 0) {
1156 57
            return false;
1157
        }
1158
1159 6
        if (!$this->currency) {
1160 6
            $doctrine = Doctrine_Manager::connection(DB_DSN);
1161 6
            $gateway = new Intraface_modules_currency_Currency_Gateway($doctrine);
1162 6
            $this->currency = $gateway->findById($this->get('currency_id'));
1163 6
        }
1164
1165 6
        return $this->currency;
1166
    }
1167
1168
    /**
1169
     * Returns the total amount on Debtor
1170
     *
1171
     * @return object Ilib_Variable_Float with total
1172
     */
1173 3
    public function getTotal()
1174
    {
1175 3
        return new Ilib_Variable_Float($this->value['total']);
1176
    }
1177
1178
    /**
1179
     * Returns the total amount of debtor in the given set currency if is set.
1180
     *
1181
     * @returns object Ilib_Variable_Float with total amount in currency if set, otherwise in system default.
1182
     */
1183 1
    public function getTotalInCurrency()
1184
    {
1185 1
        if ($this->getCurrency()) {
1186 1
            return new Ilib_Variable_Float($this->value['total_currency']);
1187
        } else {
1188
            return $this->getTotal();
1189
        }
1190
    }
1191
1192
1193
    /**
1194
     * Returns arrears on a debtor
1195
     *
1196
     * @return object Ilib_Variable_Float with arrears
1197
     */
1198 2
    public function getArrears()
1199
    {
1200 2
        return new Ilib_Variable_Float($this->value['arrears']);
1201
    }
1202
1203
    /**
1204
     * Returns arrears in currency
1205
     */
1206 1
    public function getArrearsInCurrency()
1207
    {
1208 1
        if (false !== ($currency = $this->getCurrency())) {
1209 1
            return new Ilib_Variable_Float(round($currency->getProductPriceExchangeRate($this->get('currency_product_price_exchange_rate_id'))->convertAmountToCurrency($this->getArrears())->getAsIso(), 2));
1210
        }
1211
1212
        return $this->getArrears();
1213
    }
1214
1215
    /**
1216
     * returns the possible debtor types!
1217
     *
1218
     * @return array types
1219
     */
1220 68
    static function getDebtorTypes()
1221
    {
1222
        return array(
1223 68
            1 => 'quotation',
1224 68
            2 => 'order',
1225 68
            3 => 'invoice',
1226 68
            4 => 'credit_note');
1227
    }
1228
1229
    /**
1230
     * returns the possible places where the debtor comes from
1231
     *
1232
     * @return array with the allowed froms
1233
     */
1234 63
    private function getFromTypes()
1235
    {
1236
        return array(
1237 63
            1 => 'manuel',
1238 63
            2 => 'webshop',
1239 63
            3 => 'quotation',
1240 63
            4 => 'order',
1241
            5 => 'invoice'
1242 63
        );
1243
    }
1244
1245
    /**
1246
     * returns possible status types
1247
     *
1248
     * @return array possible status types
1249
     */
1250 63
    private function getStatusTypes()
1251
    {
1252
        return array(
1253 63
            0 => 'created',
1254 63
            1 => 'sent',
1255 63
            2 => 'executed',
1256
            3 => 'cancelled'
1257 63
        );
1258
    }
1259
1260
    /**
1261
     * returns possible payment methods
1262
     *
1263
     * @return array possible payment methods
1264
     */
1265 63
    private function getPaymentMethods()
1266
    {
1267 63
        $gateway = new Intraface_modules_debtor_PaymentMethod;
1268 63
        return $gateway->getTypes();
1269
    }
1270
1271 5
    function getIdentifier()
1272
    {
1273 5
        return $this->get('identifier_key');
1274
    }
1275
1276
    function getId()
1277
    {
1278
        return $this->id;
1279
    }
1280
1281
    function getPaymentMethodKey()
1282
    {
1283
        return $this->get('payment_method');
1284
    }
1285
1286
    function getWhereToId()
1287
    {
1288
        return $this->get('where_to_id');
1289
    }
1290
1291
    function getWhereFromId()
1292
    {
1293
        return $this->get('where_from_id');
1294
    }
1295
1296
    function getPaymentLink($url)
1297
    {
1298
        return $url . $this->getIdentifier();
1299
    }
1300
}
1301