ReturnsWriter::writeItem()   C
last analyzed

Complexity

Conditions 8
Paths 19

Size

Total Lines 74
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 74
rs 6.2894
cc 8
eloc 37
nc 19
nop 1

How to fix   Long Method   

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
namespace Jh\DataImportMagento\Writer;
3
4
use Ddeboer\DataImport\Exception\WriterException;
5
use Ddeboer\DataImport\Writer\AbstractWriter;
6
use Jh\DataImportMagento\Exception\MagentoSaveException;
7
8
/**
9
 * Class ReturnsWriter
10
 * @package Jh\DataImportMagento\Writer
11
 * @author Aydin Hassan <[email protected]>
12
 */
13
class ReturnsWriter extends AbstractWriter
14
{
15
16
    /**
17
     * @var \Mage_Core_Model_Resource_Transaction
18
     */
19
    protected $transactionResourceModel;
20
21
    /**
22
     * @var \Mage_Sales_Model_Order
23
     */
24
    protected $orderModel;
25
26
    /**
27
     * @var array
28
     */
29
    protected $options = [
30
        'order_id_field'            => 'increment_id',
31
        'send_credit_memo_email'    => true,
32
    ];
33
34
    /**
35
     * @param \Mage_Sales_Model_Order $orderModel
36
     * @param \Mage_Core_Model_Resource_Transaction $transactionResourceModel
37
     */
38
    public function __construct(
39
        \Mage_Sales_Model_Order $orderModel,
40
        \Mage_Core_Model_Resource_Transaction $transactionResourceModel
41
    ) {
42
        $this->orderModel                   = $orderModel;
43
        $this->transactionResourceModel     = $transactionResourceModel;
44
    }
45
46
    /**
47
     * @param array $item
48
     * @return \Ddeboer\DataImport\Writer\WriterInterface|void
49
     * @throws \Ddeboer\DataImport\Exception\WriterException
50
     * @throws \Jh\DataImportMagento\Exception\MagentoSaveException
51
     */
52
    public function writeItem(array $item)
53
    {
54
        if (!isset($item['orderId'])) {
55
            throw new WriterException('order_id must be set');
56
        }
57
58
        $order      = $this->getOrder($item['orderId']);
59
        $service    = $this->getServiceForOrder($order);
60
61
        $quantities         = $this->validateItemsToBeRefunded($order, $item['items']);
62
        $alreadyReturned    = $this->getItemsRefunded($order);
63
        //TODO: Make this configurable - Some Returns will not include the total qty's returned
64
        //TODO: Just the exact qty to return.
65
        $returnQuantities    = $this->getActualRefundCount($alreadyReturned, $quantities);
66
67
        if (!count($returnQuantities)) {
68
            throw new WriterException(
69
                sprintf(
70
                    'Credit Memo cannot be created with no Items to Refund. Order ID: "%s"',
71
                    $item['orderId']
72
                )
73
            );
74
        }
75
76
        try {
77
            /** @var \Mage_Sales_Model_Order_Creditmemo $creditMemo */
78
            $creditMemo = $service->prepareCreditmemo([
79
                'qtys'              => $returnQuantities,
80
                //TODO: Make this configurable - have an option whether to refund shipping or not
81
                //TODO: if yes, then grab the amount from the input data
82
                'shipping_amount'   => 0,
83
            ]);
84
        } catch (\Mage_Core_Exception $e) {
85
            //Probably something to do trying to refund
86
            //quantities which don't add up
87
            throw new MagentoSaveException($e->getMessage());
88
        }
89
90
        //don't actually perform refund.
91
        //TODO: Make this configurable ^
92
        $creditMemo->addData([
93
            'offline_requested' => true,
94
        ]);
95
96
        if (isset($item['comment'])) {
97
            $creditMemo->addComment($item['comment']);
98
        }
99
100
        $creditMemo->register();
101
102
        try {
103
            $transactionSave = clone $this->transactionResourceModel;
104
            $transactionSave
105
                ->addObject($creditMemo)
106
                ->addObject($creditMemo->getOrder())
107
                ->save();
108
109
            //if there is a custom status for the order
110
            //set it - we do it here, because somewhere in the save process
111
            //Magento sets the order to complete.
112
            if (isset($item['orderStatus'])) {
113
                //$order->setStatus(strtolower($item['orderStatus']));
114
                $order->addStatusHistoryComment("Returned", strtolower($item['orderStatus']));
115
                $order->save();
116
            }
117
118
        } catch (\Exception $e) {
119
            throw new MagentoSaveException($e->getMessage());
120
        }
121
122
        if ($this->options['send_credit_memo_email']) {
123
            $creditMemo->sendEmail(true);
124
        }
125
    }
126
127
    /**
128
     * @param int $orderId
129
     * @throws WriterException
130
     * @return \Mage_Sales_Model_Order
131
     */
132
    public function getOrder($orderId)
133
    {
134
        $order = clone $this->orderModel;
135
        $order->load($orderId, $this->options['order_id_field']);
136
137
        if (!$order->getId()) {
138
            throw new WriterException(
139
                sprintf(
140
                    'Cannot find order with id: "%s", using: "%s" as id field',
141
                    $orderId,
142
                    $this->options['order_id_field']
143
                )
144
            );
145
        }
146
147
        return $order;
148
    }
149
150
    /**
151
     * If we have an item which has a qty of 7 to be refunded. What this actually means is we
152
     * have refunded a total amount of 7, but part of that qty could have been refunded at an earlier time.
153
     * So we need to get the total of that item already refunded and minus it from the qty to be refunded.
154
     *
155
     * Imagine we receive an refund with qty of 7 to refund. We have already refunded 4 so we want to refund the
156
     * other 3. SO: QtyToRefund - AlreadyRefunded === ActualQtyToRefund.
157
     *
158
     * @param array $alreadyRefunded
159
     * @param array $toRefund
160
     * @return array
161
     */
162
    public function getActualRefundCount(array $alreadyRefunded, array $toRefund)
163
    {
164
        $actualRefund = [];
165
        foreach ($toRefund as $itemId => $qty) {
166
            if (isset($alreadyRefunded[$itemId])) {
167
                $actualRefund[$itemId] = $qty - $alreadyRefunded[$itemId];
168
            } else {
169
                $actualRefund[$itemId] = $qty;
170
            }
171
172
            if ($actualRefund[$itemId] == 0) {
173
                unset($actualRefund[$itemId]);
174
            }
175
        }
176
        return $actualRefund;
177
    }
178
179
    /**
180
     * @param \Mage_Sales_Model_Order $order
181
     * @return array
182
     */
183
    public function getItemsRefunded(\Mage_Sales_Model_Order $order)
184
    {
185
        $items = [];
186
187
        /** @var \Mage_Sales_Model_Order_Creditmemo $creditMemo */
188
        foreach ($order->getCreditmemosCollection() as $creditMemo) {
189
            /** @var \Mage_Sales_Model_Order_Creditmemo_Item $item */
190
            foreach ($creditMemo->getAllItems() as $item) {
191
                if (!isset($items[$item->getData('order_item_id')])) {
192
                    $items[$item->getData('order_item_id')] = $item->getQty();
193
                } else {
194
                    $items[$item->getData('order_item_id')] += $item->getQty();
195
                }
196
            }
197
        }
198
199
        return $items;
200
    }
201
202
    /**
203
     * @param \Mage_Sales_Model_Order $order
204
     * @param array $items
205
     * @return array
206
     * @throws WriterException
207
     */
208
    public function validateItemsToBeRefunded(\Mage_Sales_Model_Order $order, array $items)
209
    {
210
        $return = [];
211
        foreach ($items as $item) {
212
            $orderItem = $order->getItemsCollection()->getItemByColumnValue('sku', $item['sku']);
213
            if (null === $orderItem) {
214
                throw new WriterException(
215
                    sprintf('Item with SKU: "%s" does not exist in Order: "%s"', $item['sku'], $order->getIncrementId())
216
                );
217
            }
218
219
            $return[$orderItem->getId()] = $item['qty'];
220
        }
221
222
        return $return;
223
    }
224
225
226
    /**
227
     * @param \Mage_Sales_Model_Order $order
228
     * @return \Mage_Sales_Model_Service_Order
229
     */
230
    public function getServiceForOrder(\Mage_Sales_Model_Order $order)
231
    {
232
        return \Mage::getModel('sales/service_order', $order);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression \Mage::getModel('sales/service_order', $order); of type object|false adds false to the return on line 232 which is incompatible with the return type documented by Jh\DataImportMagento\Wri...ter::getServiceForOrder of type Mage_Sales_Model_Service_Order. It seems like you forgot to handle an error condition.
Loading history...
233
    }
234
}
235