CreditmemoService.php 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Sales\Model\Service;
  7. /**
  8. * Class CreditmemoService
  9. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  10. */
  11. class CreditmemoService implements \Magento\Sales\Api\CreditmemoManagementInterface
  12. {
  13. /**
  14. * @var \Magento\Sales\Api\CreditmemoRepositoryInterface
  15. */
  16. protected $creditmemoRepository;
  17. /**
  18. * @var \Magento\Sales\Api\CreditmemoCommentRepositoryInterface
  19. */
  20. protected $commentRepository;
  21. /**
  22. * @var \Magento\Framework\Api\SearchCriteriaBuilder
  23. */
  24. protected $searchCriteriaBuilder;
  25. /**
  26. * @var \Magento\Framework\Api\FilterBuilder
  27. */
  28. protected $filterBuilder;
  29. /**
  30. * @var \Magento\Sales\Model\Order\CreditmemoNotifier
  31. */
  32. protected $creditmemoNotifier;
  33. /**
  34. * @var \Magento\Framework\Pricing\PriceCurrencyInterface
  35. */
  36. protected $priceCurrency;
  37. /**
  38. * @var \Magento\Framework\Event\ManagerInterface
  39. */
  40. protected $eventManager;
  41. /**
  42. * @var \Magento\Framework\App\ResourceConnection
  43. */
  44. private $resource;
  45. /**
  46. * @var \Magento\Sales\Model\Order\RefundAdapterInterface
  47. */
  48. private $refundAdapter;
  49. /**
  50. * @var \Magento\Sales\Api\OrderRepositoryInterface
  51. */
  52. private $orderRepository;
  53. /**
  54. * @var \Magento\Sales\Api\InvoiceRepositoryInterface
  55. */
  56. private $invoiceRepository;
  57. /**
  58. * @param \Magento\Sales\Api\CreditmemoRepositoryInterface $creditmemoRepository
  59. * @param \Magento\Sales\Api\CreditmemoCommentRepositoryInterface $creditmemoCommentRepository
  60. * @param \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
  61. * @param \Magento\Framework\Api\FilterBuilder $filterBuilder
  62. * @param \Magento\Sales\Model\Order\CreditmemoNotifier $creditmemoNotifier
  63. * @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
  64. * @param \Magento\Framework\Event\ManagerInterface $eventManager
  65. */
  66. public function __construct(
  67. \Magento\Sales\Api\CreditmemoRepositoryInterface $creditmemoRepository,
  68. \Magento\Sales\Api\CreditmemoCommentRepositoryInterface $creditmemoCommentRepository,
  69. \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder,
  70. \Magento\Framework\Api\FilterBuilder $filterBuilder,
  71. \Magento\Sales\Model\Order\CreditmemoNotifier $creditmemoNotifier,
  72. \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency,
  73. \Magento\Framework\Event\ManagerInterface $eventManager
  74. ) {
  75. $this->creditmemoRepository = $creditmemoRepository;
  76. $this->commentRepository = $creditmemoCommentRepository;
  77. $this->searchCriteriaBuilder = $searchCriteriaBuilder;
  78. $this->filterBuilder = $filterBuilder;
  79. $this->creditmemoNotifier = $creditmemoNotifier;
  80. $this->priceCurrency = $priceCurrency;
  81. $this->eventManager = $eventManager;
  82. }
  83. /**
  84. * Cancel an existing creditmemo
  85. *
  86. * @param int $id Credit Memo Id
  87. * @return void
  88. * @throws \Magento\Framework\Exception\LocalizedException
  89. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  90. */
  91. public function cancel($id)
  92. {
  93. throw new \Magento\Framework\Exception\LocalizedException(__('You can not cancel Credit Memo'));
  94. }
  95. /**
  96. * Returns list of comments attached to creditmemo
  97. *
  98. * @param int $id
  99. * @return \Magento\Sales\Api\Data\CreditmemoCommentSearchResultInterface
  100. */
  101. public function getCommentsList($id)
  102. {
  103. $this->searchCriteriaBuilder->addFilters(
  104. [$this->filterBuilder->setField('parent_id')->setValue($id)->setConditionType('eq')->create()]
  105. );
  106. $searchCriteria = $this->searchCriteriaBuilder->create();
  107. return $this->commentRepository->getList($searchCriteria);
  108. }
  109. /**
  110. * Notify user
  111. *
  112. * @param int $id
  113. * @return bool
  114. */
  115. public function notify($id)
  116. {
  117. $creditmemo = $this->creditmemoRepository->get($id);
  118. return $this->creditmemoNotifier->notify($creditmemo);
  119. }
  120. /**
  121. * Prepare creditmemo to refund and save it.
  122. *
  123. * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo
  124. * @param bool $offlineRequested
  125. * @return \Magento\Sales\Api\Data\CreditmemoInterface
  126. * @throws \Magento\Framework\Exception\LocalizedException
  127. */
  128. public function refund(
  129. \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo,
  130. $offlineRequested = false
  131. ) {
  132. $this->validateForRefund($creditmemo);
  133. $creditmemo->setState(\Magento\Sales\Model\Order\Creditmemo::STATE_REFUNDED);
  134. $connection = $this->getResource()->getConnection('sales');
  135. $connection->beginTransaction();
  136. try {
  137. $invoice = $creditmemo->getInvoice();
  138. if ($invoice && !$offlineRequested) {
  139. $invoice->setIsUsedForRefund(true);
  140. $invoice->setBaseTotalRefunded(
  141. $invoice->getBaseTotalRefunded() + $creditmemo->getBaseGrandTotal()
  142. );
  143. $creditmemo->setInvoiceId($invoice->getId());
  144. $this->getInvoiceRepository()->save($creditmemo->getInvoice());
  145. }
  146. $order = $this->getRefundAdapter()->refund(
  147. $creditmemo,
  148. $creditmemo->getOrder(),
  149. !$offlineRequested
  150. );
  151. $this->creditmemoRepository->save($creditmemo);
  152. $this->getOrderRepository()->save($order);
  153. $connection->commit();
  154. } catch (\Exception $e) {
  155. $connection->rollBack();
  156. throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()));
  157. }
  158. return $creditmemo;
  159. }
  160. /**
  161. * Validates if credit memo is available for refund.
  162. *
  163. * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo
  164. * @return bool
  165. * @throws \Magento\Framework\Exception\LocalizedException
  166. */
  167. protected function validateForRefund(\Magento\Sales\Api\Data\CreditmemoInterface $creditmemo)
  168. {
  169. if ($creditmemo->getId() && $creditmemo->getState() != \Magento\Sales\Model\Order\Creditmemo::STATE_OPEN) {
  170. throw new \Magento\Framework\Exception\LocalizedException(
  171. __('We cannot register an existing credit memo.')
  172. );
  173. }
  174. $baseOrderRefund = $this->priceCurrency->round(
  175. $creditmemo->getOrder()->getBaseTotalRefunded() + $creditmemo->getBaseGrandTotal()
  176. );
  177. if ($baseOrderRefund > $this->priceCurrency->round($creditmemo->getOrder()->getBaseTotalPaid())) {
  178. $baseAvailableRefund = $creditmemo->getOrder()->getBaseTotalPaid()
  179. - $creditmemo->getOrder()->getBaseTotalRefunded();
  180. throw new \Magento\Framework\Exception\LocalizedException(
  181. __(
  182. 'The most money available to refund is %1.',
  183. $creditmemo->getOrder()->formatPriceTxt($baseAvailableRefund)
  184. )
  185. );
  186. }
  187. return true;
  188. }
  189. /**
  190. * Initializes RefundAdapterInterface dependency.
  191. *
  192. * @return \Magento\Sales\Model\Order\RefundAdapterInterface
  193. * @deprecated 100.1.3
  194. */
  195. private function getRefundAdapter()
  196. {
  197. if ($this->refundAdapter === null) {
  198. $this->refundAdapter = \Magento\Framework\App\ObjectManager::getInstance()
  199. ->get(\Magento\Sales\Model\Order\RefundAdapterInterface::class);
  200. }
  201. return $this->refundAdapter;
  202. }
  203. /**
  204. * Initializes ResourceConnection dependency.
  205. *
  206. * @return \Magento\Framework\App\ResourceConnection|mixed
  207. * @deprecated 100.1.3
  208. */
  209. private function getResource()
  210. {
  211. if ($this->resource === null) {
  212. $this->resource = \Magento\Framework\App\ObjectManager::getInstance()
  213. ->get(\Magento\Framework\App\ResourceConnection::class);
  214. }
  215. return $this->resource;
  216. }
  217. /**
  218. * Initializes OrderRepositoryInterface dependency.
  219. *
  220. * @return \Magento\Sales\Api\OrderRepositoryInterface
  221. * @deprecated 100.1.3
  222. */
  223. private function getOrderRepository()
  224. {
  225. if ($this->orderRepository === null) {
  226. $this->orderRepository = \Magento\Framework\App\ObjectManager::getInstance()
  227. ->get(\Magento\Sales\Api\OrderRepositoryInterface::class);
  228. }
  229. return $this->orderRepository;
  230. }
  231. /**
  232. * Initializes InvoiceRepositoryInterface dependency.
  233. *
  234. * @return \Magento\Sales\Api\InvoiceRepositoryInterface
  235. * @deprecated 100.1.3
  236. */
  237. private function getInvoiceRepository()
  238. {
  239. if ($this->invoiceRepository === null) {
  240. $this->invoiceRepository = \Magento\Framework\App\ObjectManager::getInstance()
  241. ->get(\Magento\Sales\Api\InvoiceRepositoryInterface::class);
  242. }
  243. return $this->invoiceRepository;
  244. }
  245. }