Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
CreditmemoFactory.php
Go to the documentation of this file.
1 <?php
7 
10 
15 {
21  protected $convertor;
22 
26  protected $taxConfig;
27 
32  protected $unserialize;
33 
37  private $serializer;
38 
46  public function __construct(
47  \Magento\Sales\Model\Convert\OrderFactory $convertOrderFactory,
49  \Magento\Framework\Serialize\Serializer\Json $serializer = null
50  ) {
51  $this->convertor = $convertOrderFactory->create();
52  $this->taxConfig = $taxConfig;
53  $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
54  \Magento\Framework\Serialize\Serializer\Json::class
55  );
56  }
57 
65  public function createByOrder(\Magento\Sales\Model\Order $order, array $data = [])
66  {
67  $totalQty = 0;
68  $creditmemo = $this->convertor->toCreditmemo($order);
69  $qtyList = isset($data['qtys']) ? $data['qtys'] : [];
70 
71  foreach ($order->getAllItems() as $orderItem) {
72  if (!$this->canRefundItem($orderItem, $qtyList)) {
73  continue;
74  }
75 
76  $item = $this->convertor->itemToCreditmemoItem($orderItem);
77  $qty = $this->getQtyToRefund($orderItem, $qtyList);
78  $totalQty += $qty;
79  $item->setQty($qty);
80  $creditmemo->addItem($item);
81  }
82  $creditmemo->setTotalQty($totalQty);
83 
84  $this->initData($creditmemo, $data);
85 
86  $creditmemo->collectTotals();
87  return $creditmemo;
88  }
89 
97  public function createByInvoice(\Magento\Sales\Model\Order\Invoice $invoice, array $data = [])
98  {
99  $order = $invoice->getOrder();
100  $totalQty = 0;
101  $qtyList = isset($data['qtys']) ? $data['qtys'] : [];
102  $creditmemo = $this->convertor->toCreditmemo($order);
103  $creditmemo->setInvoice($invoice);
104 
105  $invoiceRefundLimitsQtyList = $this->getInvoiceRefundLimitsQtyList($invoice);
106 
107  foreach ($invoice->getAllItems() as $invoiceItem) {
109  $orderItem = $invoiceItem->getOrderItem();
110 
111  if (!$this->canRefundItem($orderItem, $qtyList, $invoiceRefundLimitsQtyList)) {
112  continue;
113  }
114 
115  $qty = min(
116  $this->getQtyToRefund($orderItem, $qtyList, $invoiceRefundLimitsQtyList),
117  $invoiceItem->getQty()
118  );
119  $totalQty += $qty;
120  $item = $this->convertor->itemToCreditmemoItem($orderItem);
121  $item->setQty($qty);
122  $creditmemo->addItem($item);
123  }
124  $creditmemo->setTotalQty($totalQty);
125 
126  $this->initData($creditmemo, $data);
127  if (!isset($data['shipping_amount'])) {
128  $baseAllowedAmount = $this->getShippingAmount($invoice);
129  $creditmemo->setBaseShippingAmount($baseAllowedAmount);
130  }
131 
132  $creditmemo->collectTotals();
133  return $creditmemo;
134  }
135 
145  protected function canRefundItem($item, $qtys = [], $invoiceQtysRefundLimits = [])
146  {
147  if ($item->isDummy()) {
148  if ($item->getHasChildren()) {
149  foreach ($item->getChildrenItems() as $child) {
150  if (empty($qtys)) {
151  if ($this->canRefundNoDummyItem($child, $invoiceQtysRefundLimits)) {
152  return true;
153  }
154  } else {
155  if (isset($qtys[$child->getId()]) && $qtys[$child->getId()] > 0) {
156  return true;
157  }
158  }
159  }
160  return false;
161  } elseif ($item->getParentItem()) {
162  $parent = $item->getParentItem();
163  if (empty($qtys)) {
164  return $this->canRefundNoDummyItem($parent, $invoiceQtysRefundLimits);
165  } else {
166  return isset($qtys[$parent->getId()]) && $qtys[$parent->getId()] > 0;
167  }
168  }
169  } else {
170  return $this->canRefundNoDummyItem($item, $invoiceQtysRefundLimits);
171  }
172  }
173 
181  protected function canRefundNoDummyItem($item, $invoiceQtysRefundLimits = [])
182  {
183  if ($item->getQtyToRefund() < 0) {
184  return false;
185  }
186  if (isset($invoiceQtysRefundLimits[$item->getId()])) {
187  return $invoiceQtysRefundLimits[$item->getId()] > 0;
188  }
189  return true;
190  }
191 
199  protected function initData($creditmemo, $data)
200  {
201  if (isset($data['shipping_amount'])) {
202  $creditmemo->setBaseShippingAmount((double)$data['shipping_amount']);
203  }
204  if (isset($data['adjustment_positive'])) {
205  $creditmemo->setAdjustmentPositive($data['adjustment_positive']);
206  }
207  if (isset($data['adjustment_negative'])) {
208  $creditmemo->setAdjustmentNegative($data['adjustment_negative']);
209  }
210  }
211 
217  private function calculateProductOptions(Item $orderItem, int $parentQty): int
218  {
219  $qty = $parentQty;
220  $productOptions = $orderItem->getProductOptions();
221  if (isset($productOptions['bundle_selection_attributes'])) {
222  $bundleSelectionAttributes = $this->serializer->unserialize(
223  $productOptions['bundle_selection_attributes']
224  );
225  if ($bundleSelectionAttributes) {
226  $qty = $bundleSelectionAttributes['qty'] * $parentQty;
227  }
228  }
229  return $qty;
230  }
231 
238  private function getInvoiceRefundedQtyList(Invoice $invoice): array
239  {
240  $invoiceRefundedQtyList = [];
241  foreach ($invoice->getOrder()->getCreditmemosCollection() as $creditmemo) {
242  if ($creditmemo->getState() !== Creditmemo::STATE_CANCELED &&
243  $creditmemo->getInvoiceId() === $invoice->getId()
244  ) {
245  foreach ($creditmemo->getAllItems() as $creditmemoItem) {
246  $orderItemId = $creditmemoItem->getOrderItem()->getId();
247  if (isset($invoiceRefundedQtyList[$orderItemId])) {
248  $invoiceRefundedQtyList[$orderItemId] += $creditmemoItem->getQty();
249  } else {
250  $invoiceRefundedQtyList[$orderItemId] = $creditmemoItem->getQty();
251  }
252  }
253  }
254  }
255 
256  return $invoiceRefundedQtyList;
257  }
258 
265  private function getInvoiceRefundLimitsQtyList(Invoice $invoice): array
266  {
267  $invoiceRefundLimitsQtyList = [];
268  $invoiceRefundedQtyList = $this->getInvoiceRefundedQtyList($invoice);
269 
270  foreach ($invoice->getAllItems() as $invoiceItem) {
271  $qtyCanBeRefunded = $invoiceItem->getQty();
272  $orderItemId = $invoiceItem->getOrderItem()->getId();
273  if (isset($invoiceRefundedQtyList[$orderItemId])) {
274  $qtyCanBeRefunded = $qtyCanBeRefunded - $invoiceRefundedQtyList[$orderItemId];
275  }
276  $invoiceRefundLimitsQtyList[$orderItemId] = $qtyCanBeRefunded;
277  }
278 
279  return $invoiceRefundLimitsQtyList;
280  }
281 
290  private function getQtyToRefund(Item $orderItem, array $qtyList, array $refundLimits = []): float
291  {
292  $qty = 0;
293  if ($orderItem->isDummy()) {
294  if (isset($qtyList[$orderItem->getParentItemId()])) {
295  $parentQty = $qtyList[$orderItem->getParentItemId()];
296  } elseif ($orderItem->getProductType() === BundlePrice::PRODUCT_TYPE) {
297  $parentQty = $orderItem->getQtyInvoiced();
298  } else {
299  $parentQty = $orderItem->getParentItem() ? $orderItem->getParentItem()->getQtyToRefund() : 1;
300  }
301  $qty = $this->calculateProductOptions($orderItem, $parentQty);
302  } else {
303  if (isset($qtyList[$orderItem->getId()])) {
304  $qty = $qtyList[$orderItem->getId()];
305  } elseif (!count($qtyList)) {
306  $qty = $orderItem->getQtyToRefund();
307  } else {
308  return (float)$qty;
309  }
310 
311  if (isset($refundLimits[$orderItem->getId()])) {
312  $qty = min($qty, $refundLimits[$orderItem->getId()]);
313  }
314  }
315 
316  return (float)$qty;
317  }
318 
325  private function getShippingAmount(Invoice $invoice): float
326  {
327  $order = $invoice->getOrder();
328  $isShippingInclTax = $this->taxConfig->displaySalesShippingInclTax($order->getStoreId());
329  if ($isShippingInclTax) {
330  $amount = $order->getBaseShippingInclTax() -
331  $order->getBaseShippingRefunded() -
332  $order->getBaseShippingTaxRefunded();
333  } else {
334  $amount = $order->getBaseShippingAmount() - $order->getBaseShippingRefunded();
335  $amount = min($amount, $invoice->getBaseShippingAmount());
336  }
337 
338  return (float)$amount;
339  }
340 }
$invoiceItem
createByOrder(\Magento\Sales\Model\Order $order, array $data=[])
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
$orderItem
Definition: order.php:30
$order
Definition: order.php:55
$amount
Definition: order.php:14
canRefundItem($item, $qtys=[], $invoiceQtysRefundLimits=[])
canRefundNoDummyItem($item, $invoiceQtysRefundLimits=[])
$invoice
__construct(\Magento\Sales\Model\Convert\OrderFactory $convertOrderFactory, \Magento\Tax\Model\Config $taxConfig, \Magento\Framework\Serialize\Serializer\Json $serializer=null)