Completed
Push — master ( d208aa...25518b )
by Lars
12:37
created

CreditNote::state()   D

Complexity

Conditions 14
Paths 222

Size

Total Lines 120
Code Lines 79

Duplication

Lines 48
Ratio 40 %

Code Coverage

Tests 67
CRAP Score 16.1127

Importance

Changes 0
Metric Value
cc 14
eloc 79
nc 222
nop 4
dl 48
loc 120
ccs 67
cts 86
cp 0.7791
crap 16.1127
rs 4.2429
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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:

1
<?php
2
/**
3
 * Invoice
4
 *
5
 * @package Intraface_Invoice
6
 * @author Sune Jensen <[email protected]>
7
 * @author Lars Olesen <[email protected]>
8
 */
9
require_once 'Intraface/modules/debtor/Debtor.php';
10
11
class CreditNote extends Debtor
12
{
13 39
    function __construct($kernel, $id = 0)
14
    {
15 39
        parent::__construct($kernel, 'credit_note', $id);
16 39
    }
17
18 6
    function setStatus($status)
19
    {
20 6
        $return = parent::setStatus($status);
21 6
        if ($status == "sent") {
22
            // Er den sendt, bliver den ogs� l�st
23 5
            return parent::setStatus("executed");
24
        } else {
25 1
            return $return;
26
        }
27
    }
28
29
    function delete()
30
    {
31
        if ($this->get("where_from") == "invoice" && $this->get("where_from_id") != 0) {
32
            $invoice = parent::factory($this->kernel, (int)$this->get("where_from_id"));
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (factory() instead of delete()). Are you sure this is correct? If so, you might want to change this to $this->factory().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
33
        }
34
        parent::delete();
35
        if (isset($invoice)) {
36
            $invoice->updateStatus();
0 ignored issues
show
Bug introduced by
The method updateStatus does only exist in Invoice, but not in CreditNote and Order and Quotation.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
37
        }
38
    }
39
40 4
    function readyForState($year, $check_products = 'check_products')
41
    {
42 4
        if (!is_object($year)) {
43
            throw new Exception('First parameter to readyForState needs to be a Year object!');
44
            return false;
0 ignored issues
show
Unused Code introduced by
return false; 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...
45
        }
46
47 4 View Code Duplication
        if (!in_array($check_products, array('check_products', 'skip_check_products'))) {
48
            throw new Exception('Second paramenter in creditnote->readyForState should be either "check_products" or "skip_check_products"');
49
            return false;
0 ignored issues
show
Unused Code introduced by
return false; 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...
50
        }
51
52 4
        if (!$year->readyForState($this->get('this_date'))) {
53
            $this->error->set('Regnskab�ret er ikke klar til bogf�ring');
54
            return false;
55
        }
56
57
58 4
        if ($this->type != 'credit_note') {
59
            $this->error->set('Du kan kun bogf�re kreditnotaer');
60
            return false;
61
        }
62
63 4
        if ($this->isStated()) {
64 2
            $this->error->set('Kreditnotaen er allerede bogf�rt');
65 2
            return false;
66
        }
67
68 4 View Code Duplication
        if ($this->get('status') != 'sent' && $this->get('status') != 'executed') {
69 1
            $this->error->set('Kreditnotaen skal v�re sendt eller afsluttet for at den kan bogf�res');
70 1
            return false;
71
        }
72
73 4
        $return = true;
74
75 4 View Code Duplication
        if ($check_products == 'check_products') {
76 3
            $this->loadItem();
77 3
            $items = $this->item->getList();
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...
78 3
            for ($i = 0, $max = count($items); $i < $max; $i++) {
79 3
                $product = new Product($this->kernel, $items[$i]['product_id']);
80 3
                if ($product->get('state_account_id') == 0) {
81
                    $this->error->set('Produktet ' . $product->get('name') . ' ved ikke hvor den skal bogf�res');
82
                } else {
83 3
                    require_once 'Intraface/modules/accounting/Account.php';
84 3
                    $account = Account::factory($year, $product->get('state_account_id'));
0 ignored issues
show
Deprecated Code introduced by
The method Account::factory() has been deprecated.

This method has been deprecated.

Loading history...
85 3
                    if ($account->get('id') == 0 || $account->get('type') != 'operating') {
86
                        $this->error->set('Ugyldig konto for bogf�ring af produktet ' . $product->get('name'));
87
                        $return = false;
88
                    }
89
                }
90 3
            }
91 3
        }
92
93 4
        return $return;
94
    }
95
96 2
    function state($year, $voucher_number, $voucher_date, $translation)
97
    {
98 2
        if (!is_object($year)) {
99
            throw new Exception('First parameter to state needs to be a Year object!');
100
            return false;
0 ignored issues
show
Unused Code introduced by
return false; 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...
101
        }
102
103 2
        if (!is_object($translation)) {
104
            throw new Exception('4th parameter to state needs to be a translation object!');
105
            return false;
0 ignored issues
show
Unused Code introduced by
return false; 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...
106
        }
107
108 2
        $text = $translation->get('credit note');
109
110 2
        $validator = new Intraface_Validator($this->error);
111 2
        if ($validator->isDate($voucher_date, "Ugyldig dato")) {
112 2
            $this_date = new Intraface_Date($voucher_date);
113 2
            $this_date->convert2db();
114 2
        }
115
116 2
        if ($this->error->isError()) {
117
            return false;
118
        }
119
120 2
        if (!$this->readyForState($year)) {
121
            $this->error->set('Kreditnotaen er ikke klar til bogf�ring');
122
            return false;
123
        }
124
125
        // hente alle produkterne p� debtor
126 2
        $this->loadItem();
127 2
        $items = $this->item->getList();
128
129 2
        require_once 'Intraface/modules/accounting/Voucher.php';
130 2
        require_once 'Intraface/modules/accounting/Account.php';
131 2
        $voucher = Voucher::factory($year, $voucher_number);
0 ignored issues
show
Deprecated Code introduced by
The method Voucher::factory() has been deprecated.

This method has been deprecated.

Loading history...
132 2
        $voucher->save(array(
133 2
            'voucher_number' => $voucher_number,
134 2
            'date' => $voucher_date,
135 2
            'text' => 'Kreditnota #' . $this->get('number')
136 2
        ));
137
138
139 2
        $total_with_vat = 0;
140 2 View Code Duplication
        foreach ($items as $item) {
141
            // produkterne
142
            // bem�rk at denne g�r ud fra at alt skal overf�res til debtorkontoen som standard
143 2
            $product = new Product($this->kernel, $item['product_id']);
144 2
            $debet_account = Account::factory($year, $product->get('state_account_id'));
0 ignored issues
show
Deprecated Code introduced by
The method Account::factory() has been deprecated.

This method has been deprecated.

Loading history...
145 2
            $debet_account_number = $debet_account->get('number');
146 2
            $credit_account = new Account($year, $year->getSetting('debtor_account_id'));
147 2
            $credit_account_number = $credit_account->get('number');
148 2
            $voucher = Voucher::factory($year, $voucher_number);
0 ignored issues
show
Deprecated Code introduced by
The method Voucher::factory() has been deprecated.

This method has been deprecated.

Loading history...
149
150 2
            $amount = $item['quantity'] * $item['price']->getAsIso(2);
151
152
            // hvis bel�bet er mindre end nul, skal konti byttes om og bel�bet skal g�res positivt
153 2
            if ($amount < 0) {
154
                $debet_account_number = $credit_account->get('number');
155
                $credit_account_number = $debet_account->get('number');
156
                $amount = abs($amount);
157
            }
158
159
            $input_values = array(
160 2
                'voucher_number' => $voucher_number,
161 2
                'reference' => $this->get('number'),
162 2
                'date' => $voucher_date,
163 2
                'amount' => number_format($amount, 2, ",", "."),
164 2
                'debet_account_number' => $debet_account_number,
165 2
                'credit_account_number' => $credit_account_number,
166 2
                'vat_off' => 1,
167 2
                'text' => $text.' #' . $this->get('number') . ' - ' . $item['name']
168 2
            );
169 2
            if ($debet_account->get('vat') == 'out') {
170 1
                $total_with_vat += $item["quantity"] * $item["price"]->getAsIso(2);
171 1
            }
172
173 2
            if (!$voucher->saveInDaybook($input_values, true)) {
174
                $voucher->error->view();
175
            }
176 2
        }
177
178
        // samlet moms p� fakturaen
179 2
        if ($total_with_vat != 0) {
180 1
            $voucher = Voucher::factory($year, $voucher_number);
0 ignored issues
show
Deprecated Code introduced by
The method Voucher::factory() has been deprecated.

This method has been deprecated.

Loading history...
181 1
            $debet_account = new Account($year, $year->getSetting('vat_out_account_id'));
182 1
            $credit_account = new Account($year, $year->getSetting('debtor_account_id'));
183
            $input_values = array(
184 1
                    'voucher_number' => $voucher_number,
185 1
                    'reference' => $this->get('number'),
186 1
                    'date' => $voucher_date,
187 1
                    'amount' => number_format($total_with_vat * $this->kernel->setting->get('intranet', 'vatpercent') / 100, 2, ",", "."), // opm�rksom p� at vat bliver rigtig defineret
188 1
                    'debet_account_number' => $debet_account->get('number'),
189 1
                    'credit_account_number' => $credit_account->get('number'),
190 1
                    'vat_off' => 1,
191 1
                    'text' => $text.' #' . $this->get('number') . ' - ' . $debet_account->get('name')
192 1
            );
193 1
            if (!$voucher->saveInDaybook($input_values, true)) {
194
                $this->error->merge($voucher->error->getMessage());
195
            }
196 1
        }
197
198 2
        require_once 'Intraface/modules/accounting/VoucherFile.php';
199 2
        $voucher_file = new VoucherFile($voucher);
200 2 View Code Duplication
        if (!$voucher_file->save(array('description' => $text.' #' . $this->get('number'), 'belong_to'=>'credit_note','belong_to_id'=>$this->get('id')))) {
201
            $this->error->merge($voucher_file->error->getMessage());
202
            $this->error->set('Filen blev ikke overflyttet');
203
        }
204
205 2 View Code Duplication
        if ($this->error->isError()) {
206
            $this->error->set('Der er opst�et en fejl under bogf�ringen af kreditnotaen. Det kan betyde at dele af den er bogf�rt, men ikke det hele. Du bedes manuelt tjekke bilaget');
207
            // I am not quite sure if the credit note should be set as stated, but it can give trouble to state it again, if some of it was stated...
208
            $this->setStated($voucher->get('id'), $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...
209
            return false;
210
        }
211
212 2
        $this->setStated($voucher->get('id'), $this_date->get());
213 2
        $this->load();
214 2
        return true;
215
    }
216
}
217