Completed
Pull Request — master (#67)
by Mario
03:25
created

Invoice   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 188
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 31
lcom 1
cbo 2
dl 0
loc 188
rs 9.8
c 1
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A addInvoicePosition() 0 11 1
B addProductInfo() 0 21 7
B addShippingItem() 0 12 6
B addDiscountItem() 0 20 8
B addProductItem() 0 14 6
A convertItemAmount() 0 9 2
1
<?php
2
3
/**
4
 * PAYONE Magento 2 Connector is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU Lesser General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * PAYONE Magento 2 Connector is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public License
15
 * along with PAYONE Magento 2 Connector. If not, see <http://www.gnu.org/licenses/>.
16
 *
17
 * PHP version 5
18
 *
19
 * @category  Payone
20
 * @package   Payone_Magento2_Plugin
21
 * @author    FATCHIP GmbH <[email protected]>
22
 * @copyright 2003 - 2016 Payone GmbH
23
 * @license   <http://www.gnu.org/licenses/> GNU Lesser General Public License
24
 * @link      http://www.payone.de
25
 */
26
27
namespace Payone\Core\Model\Api;
28
29
use Payone\Core\Model\Api\Request\Base;
30
use Magento\Sales\Model\Order;
31
32
/**
33
 * Collect all invoice parameters
34
 *
35
 * @category  Payone
36
 * @package   Payone_Magento2_Plugin
37
 * @author    FATCHIP GmbH <[email protected]>
38
 * @copyright 2003 - 2016 Payone GmbH
39
 * @license   <http://www.gnu.org/licenses/> GNU Lesser General Public License
40
 * @link      http://www.payone.de
41
 */
42
class Invoice
43
{
44
    /**
45
     * Index of added invoice items
46
     *
47
     * @var integer
48
     */
49
    protected $iIndex = 1;
50
51
    /**
52
     * Invoice amount
53
     *
54
     * @var integer
55
     */
56
    protected $dAmount = 0;
57
58
    /**
59
     * Vat rate for following entities which may not have the vat attached to it
60
     *
61
     * @var double
62
     */
63
    protected $dTax = false;
64
65
    /**
66
     * PAYONE toolkit helper
67
     *
68
     * @var \Payone\Core\Helper\Toolkit
69
     */
70
    protected $toolkitHelper;
71
72
    /**
73
     * Request object
74
     *
75
     * @var Base
76
     */
77
    protected $oRequest;
78
79
    /**
80
     * Constructor
81
     *
82
     * @param \Payone\Core\Helper\Toolkit $toolkitHelper Toolkit helper
83
     */
84
    public function __construct(\Payone\Core\Helper\Toolkit $toolkitHelper)
85
    {
86
        $this->toolkitHelper = $toolkitHelper;
87
    }
88
89
    /**
90
     * Add parameters for a invoice position
91
     *
92
     * @param  string $sId       item identification
93
     * @param  double $dPrice    item price
94
     * @param  string $sItemType item type
95
     * @param  int    $iAmount   item amount
96
     * @param  string $sDesc     item description
97
     * @param  double $dVat      item tax rate
98
     * @return void
99
     */
100
    protected function addInvoicePosition($sId, $dPrice, $sItemType, $iAmount, $sDesc, $dVat)
101
    {
102
        $this->oRequest->addParameter('id['.$this->iIndex.']', $sId); // add invoice item id
103
        $this->oRequest->addParameter('pr['.$this->iIndex.']', $this->toolkitHelper->formatNumber($dPrice) * 100); // expected in smallest unit of currency
104
        $this->oRequest->addParameter('it['.$this->iIndex.']', $sItemType); // add invoice item type
105
        $this->oRequest->addParameter('no['.$this->iIndex.']', $iAmount); // add invoice item amount
106
        $this->oRequest->addParameter('de['.$this->iIndex.']', $sDesc); // add invoice item description
107
        $this->oRequest->addParameter('va['.$this->iIndex.']', $this->toolkitHelper->formatNumber($dVat * 100, 0)); // expected * 100 to also handle vats with decimals
108
        $this->dAmount += $dPrice * $iAmount; // needed for return of the main method
109
        $this->iIndex++; // increase index for next item
110
    }
111
112
    /**
113
     * Add invoicing data to the request and return the summed invoicing amount
114
     *
115
     * @param  Base  $oRequest   Request object
116
     * @param  Order $oOrder     Order object
117
     * @param  array $aPositions Is given with non-complete captures or debits
118
     * @param  bool  $blDebit    Is the call coming from a debit request
119
     * @return integer
120
     */
121
    public function addProductInfo(Base $oRequest, Order $oOrder, $aPositions = false, $blDebit = false)
122
    {
123
        $this->oRequest = $oRequest; // write request to property for manipulation of the object
124
        $sInvoiceAppendix = $this->toolkitHelper->getInvoiceAppendix($oOrder); // get invoice appendix
125
        if (!empty($sInvoiceAppendix)) {// invoice appendix existing?
126
            $this->oRequest->addParameter('invoiceappendix', $sInvoiceAppendix); // add appendix to request
127
        }
128
129
        foreach ($oOrder->getAllItems() as $oItem) { // add invoice items for all order items
130
            if ($oItem->isDummy() === false) { // prevent variant-products of adding 2 items
131
                $this->addProductItem($oItem, $aPositions); // add product invoice params to request
0 ignored issues
show
Bug introduced by
It seems like $aPositions defined by parameter $aPositions on line 121 can also be of type false; however, Payone\Core\Model\Api\Invoice::addProductItem() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
132
            }
133
        }
134
135
        $blFirstCapture = true; // Is first capture?
136
        if ($aPositions === false || $blFirstCapture === true || $blDebit === true) {
137
            $this->addShippingItem($oOrder, $aPositions, $blDebit); // add shipping invoice params to request
0 ignored issues
show
Bug introduced by
It seems like $aPositions defined by parameter $aPositions on line 121 can also be of type false; however, Payone\Core\Model\Api\Invoice::addShippingItem() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
138
            $this->addDiscountItem($oOrder, $aPositions, $blDebit); // add discount invoice params to request
0 ignored issues
show
Bug introduced by
It seems like $aPositions defined by parameter $aPositions on line 121 can also be of type false; however, Payone\Core\Model\Api\Invoice::addDiscountItem() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
139
        }
140
        return $this->dAmount;
141
    }
142
143
    /**
144
     * Add invoicing item for a product
145
     *
146
     * @param  \Magento\Sales\Model\Order\Item $oItem
147
     * @param  array $aPositions
148
     * @return void
149
     */
150
    protected function addProductItem($oItem, $aPositions)
151
    {
152
        if ($aPositions === false || array_key_exists($oItem->getProductId(), $aPositions) !== false) { // full or single-invoice?
153
            $dItemAmount = $oItem->getQtyOrdered(); // get ordered item amount
154
            if ($aPositions !== false && array_key_exists($oItem->getProductId(), $aPositions) !== false) { // product existing in single-invoice?
155
                $dItemAmount = $aPositions[$oItem->getProductId()]['amount']; // use amount from single-invoice
156
            }
157
            $iAmount = $this->convertItemAmount($dItemAmount);
158
            $this->addInvoicePosition($oItem->getSku(), $oItem->getPriceInclTax(), 'goods', $iAmount, $oItem->getName(), $oItem->getTaxPercent()); // add invoice params to request
159
            if ($this->dTax === false) { // is dTax not set yet?
160
                $this->dTax = $oItem->getTaxPercent(); // set the tax for following entities which dont have the vat attached to it
161
            }
162
        }
163
    }
164
165
    /**
166
     * Add invoicing item for shipping
167
     *
168
     * @param  Order $oOrder
169
     * @param  array $aPositions
170
     * @param  bool  $blDebit
171
     * @return void
172
     */
173
    protected function addShippingItem(Order $oOrder, $aPositions, $blDebit)
174
    {
175
        // shipping costs existing or given for partial captures/debits?
176
        if ($oOrder->getBaseShippingInclTax() != 0 && ($aPositions === false || ($blDebit === false || array_key_exists('oxdelcost', $aPositions) !== false))) {
177
            $sDelDesc = __('Surcharge').' '.__('Shipping Costs'); // default description
178
            if ($oOrder->getBaseShippingInclTax() < 0) { // negative shipping cost
179
                $sDelDesc = __('Deduction').' '.__('Shipping Costs'); // change item description to deduction
180
            }
181
            $sShippingSku = $this->toolkitHelper->getConfigParam('sku', 'costs', 'payone_misc'); // get configured shipping SKU
182
            $this->addInvoicePosition($sShippingSku, $oOrder->getBaseShippingInclTax(), 'shipment', 1, $sDelDesc, $this->dTax); // add invoice params to request
183
        }
184
    }
185
186
    /**
187
     * Add invoicing item for discounts
188
     *
189
     * @param  Order $oOrder
190
     * @param  array $aPositions
191
     * @param  bool  $blDebit
192
     * @return void
193
     */
194
    protected function addDiscountItem(Order $oOrder, $aPositions, $blDebit)
195
    {
196
        // discount costs existing or given for partial captures/debis?
197
        if ($oOrder->getBaseDiscountAmount() != 0 && $oOrder->getCouponCode() && ($aPositions === false || ($blDebit === false || array_key_exists('oxvoucherdiscount', $aPositions) !== false))) {
198
            $dDiscount = $this->toolkitHelper->formatNumber($oOrder->getBaseDiscountAmount()); // format discount
199
            if ($aPositions === false) {// full invoice?
200
                // The calculations broken down to single items of Magento2 are unprecise and the Payone API will send an error if
201
                // the calculated positions don't match, so we compensate for rounding-problems here
202
                $dDiff = ($this->dAmount + $oOrder->getBaseDiscountAmount()) - $oOrder->getGrandTotal(); // calc rounding discrepancy
203
                $dDiscount -= $dDiff; // subtract difference from discount
204
            }
205
            $sDiscountSku = $this->toolkitHelper->getConfigParam('sku', 'discount', 'payone_misc'); // get configured discount SKU
206
            $sDesc = (string)__('Discount'); // default description
207
            if ($oOrder->getCouponCode()) {// was a coupon code used?
208
                $sDiscountSku = $this->toolkitHelper->getConfigParam('sku', 'voucher', 'payone_misc'); // get configured voucher SKU
209
                $sDesc = (string)__('Coupon').' - '.$oOrder->getCouponCode(); // add counpon code to description
210
            }
211
            $this->addInvoicePosition($sDiscountSku, $dDiscount, 'voucher', 1, $sDesc, $this->dTax); // add invoice params to request
212
        }
213
    }
214
215
    /**
216
     * @param double $dItemAmount
217
     * @throws \InvalidArgumentException
218
     * @return integer
219
     */
220
    private function convertItemAmount($dItemAmount)
221
    {
222
        if (fmod(floatval($dItemAmount), 1.0) > 0) { // input does not represent an integer
223
            $sErrorMessage = "Unable to use floating point values for item amounts! Parameter was: ";
224
            throw new \InvalidArgumentException($sErrorMessage . strval($dItemAmount), 1);
225
        } else { // return the integer value
226
            return intval($dItemAmount);
227
        }
228
    }
229
}
230