OrderSavedAfterObserver.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <?php
  2. /**
  3. * @copyright Vertex. All rights reserved. https://www.vertexinc.com/
  4. * @author Mediotype https://www.mediotype.com/
  5. */
  6. namespace Vertex\Tax\Observer;
  7. use Magento\Framework\Event\Observer;
  8. use Magento\Framework\Event\ObserverInterface;
  9. use Magento\Framework\Exception\NoSuchEntityException;
  10. use Magento\Framework\Message\ManagerInterface;
  11. use Magento\Store\Model\ScopeInterface;
  12. use Vertex\Data\LineItemInterface;
  13. use Vertex\Services\Invoice\ResponseInterface;
  14. use Vertex\Tax\Model\Api\Data\InvoiceRequestBuilder;
  15. use Vertex\Tax\Model\Config;
  16. use Vertex\Tax\Model\ConfigurationValidator;
  17. use Vertex\Tax\Model\CountryGuard;
  18. use Vertex\Tax\Model\Data\OrderInvoiceStatus;
  19. use Vertex\Tax\Model\Data\OrderInvoiceStatusFactory;
  20. use Vertex\Tax\Model\ExceptionLogger;
  21. use Vertex\Tax\Model\Repository\OrderInvoiceStatusRepository;
  22. use Vertex\Tax\Model\TaxInvoice;
  23. use Vertex\Tax\Model\VertexTaxAttributeManager;
  24. /**
  25. * Observes when an Order is saved to determine if we need to commit data to the Vertex Tax Log
  26. */
  27. class OrderSavedAfterObserver implements ObserverInterface
  28. {
  29. /** @var VertexTaxAttributeManager */
  30. private $attributeManager;
  31. /** @var Config */
  32. private $config;
  33. /** @var ConfigurationValidator */
  34. private $configValidator;
  35. /** @var CountryGuard */
  36. private $countryGuard;
  37. /** @var OrderInvoiceStatusFactory */
  38. private $factory;
  39. /** @var GiftwrapExtensionLoader */
  40. private $giftwrapExtensionLoader;
  41. /** @var InvoiceRequestBuilder */
  42. private $invoiceRequestBuilder;
  43. /** @var ExceptionLogger */
  44. private $logger;
  45. /** @var ManagerInterface */
  46. private $messageManager;
  47. /** @var OrderInvoiceStatusRepository */
  48. private $repository;
  49. /** @var ShippingAssignmentExtensionLoader */
  50. private $shipmentExtensionLoader;
  51. /** @var bool */
  52. private $showSuccessMessage;
  53. /** @var TaxInvoice */
  54. private $taxInvoice;
  55. /**
  56. * @param Config $config
  57. * @param CountryGuard $countryGuard
  58. * @param TaxInvoice $taxInvoice
  59. * @param ManagerInterface $messageManager
  60. * @param OrderInvoiceStatusRepository $repository
  61. * @param OrderInvoiceStatusFactory $factory
  62. * @param ExceptionLogger $logger
  63. * @param ConfigurationValidator $configValidator
  64. * @param InvoiceRequestBuilder $invoiceRequestBuilder
  65. * @param GiftwrapExtensionLoader $giftwrapExtensionLoader
  66. * @param ShippingAssignmentExtensionLoader $shipmentExtensionLoader
  67. * @param VertexTaxAttributeManager $attributeManager
  68. * @param bool $showSuccessMessage
  69. */
  70. public function __construct(
  71. Config $config,
  72. CountryGuard $countryGuard,
  73. TaxInvoice $taxInvoice,
  74. ManagerInterface $messageManager,
  75. OrderInvoiceStatusRepository $repository,
  76. OrderInvoiceStatusFactory $factory,
  77. ExceptionLogger $logger,
  78. ConfigurationValidator $configValidator,
  79. InvoiceRequestBuilder $invoiceRequestBuilder,
  80. GiftwrapExtensionLoader $giftwrapExtensionLoader,
  81. ShippingAssignmentExtensionLoader $shipmentExtensionLoader,
  82. VertexTaxAttributeManager $attributeManager,
  83. $showSuccessMessage = false
  84. ) {
  85. $this->config = $config;
  86. $this->countryGuard = $countryGuard;
  87. $this->taxInvoice = $taxInvoice;
  88. $this->messageManager = $messageManager;
  89. $this->repository = $repository;
  90. $this->factory = $factory;
  91. $this->logger = $logger;
  92. $this->configValidator = $configValidator;
  93. $this->invoiceRequestBuilder = $invoiceRequestBuilder;
  94. $this->giftwrapExtensionLoader = $giftwrapExtensionLoader;
  95. $this->shipmentExtensionLoader = $shipmentExtensionLoader;
  96. $this->attributeManager = $attributeManager;
  97. $this->showSuccessMessage = $showSuccessMessage;
  98. }
  99. /**
  100. * Commit an Invoice to the Vertex Tax Log
  101. *
  102. * When an order is saved, request by order status is enabled, and the Order's status is the one configured, we
  103. * will commit it's data to the Vertex Tax Log
  104. *
  105. * @param Observer $observer
  106. * @return void
  107. */
  108. public function execute(Observer $observer)
  109. {
  110. /** @var \Magento\Sales\Model\Order $order */
  111. $order = $observer->getEvent()->getOrder();
  112. if (!$this->config->isVertexActive($order->getStoreId())
  113. || $this->hasInvoice($order->getId())
  114. || !$this->config->isTaxCalculationEnabled($order->getStoreId())
  115. ) {
  116. return;
  117. }
  118. /** @var boolean $requestByOrder */
  119. $requestByOrder = $this->requestByOrderStatus($order->getStatus(), $order->getStore());
  120. /** @var boolean $canService */
  121. $canService = $this->countryGuard->isOrderServiceableByVertex($order);
  122. /** @var boolean $configValid */
  123. $configValid = $this->configValidator->execute(ScopeInterface::SCOPE_STORE, $order->getStoreId(), true)
  124. ->isValid();
  125. if ($requestByOrder && $canService && $configValid) {
  126. // We perform a cloning operation here to prevent tampering with the original order during placement
  127. $order = clone $order;
  128. if ($order->getExtensionAttributes()) {
  129. $order->setExtensionAttributes(clone $order->getExtensionAttributes());
  130. }
  131. $order = $this->shipmentExtensionLoader->loadOnOrder($order);
  132. $order = $this->giftwrapExtensionLoader->loadOnOrder($order);
  133. $request = $this->invoiceRequestBuilder->buildFromOrder($order);
  134. /** @var ResponseInterface */
  135. $response = $this->taxInvoice->sendInvoiceRequest($request, $order);
  136. $this->processResponse($response, $order->getId());
  137. }
  138. }
  139. /**
  140. * Notify administrator that the invoice has been committed to the tax log
  141. *
  142. * @return void
  143. */
  144. private function addSuccessMessage()
  145. {
  146. if ($this->showSuccessMessage) {
  147. $this->messageManager->addSuccessMessage(__('The Vertex invoice has been sent.')->render());
  148. }
  149. }
  150. /**
  151. * Determine if an Order already has an invoice
  152. *
  153. * @param int $orderId
  154. * @return bool
  155. */
  156. private function hasInvoice($orderId)
  157. {
  158. try {
  159. $this->repository->getByOrderId($orderId);
  160. return true;
  161. } catch (NoSuchEntityException $e) {
  162. return false;
  163. }
  164. }
  165. /**
  166. * Process vertex response
  167. *
  168. * @param ResponseInterface|null $response
  169. * @param int $orderId
  170. * @return void
  171. */
  172. private function processResponse($response, $orderId)
  173. {
  174. if ($response) {
  175. /** @var LineItemInterface[] $items */
  176. if ($items = $response->getLineItems()) {
  177. $this->attributeManager->saveAllVertexAttributes($items);
  178. }
  179. $this->addSuccessMessage();
  180. $this->setHasInvoice($orderId);
  181. }
  182. }
  183. /**
  184. * Determine if we should commit to the tax log on this order status
  185. *
  186. * Checks if request by order status is enabled and that our status matches the one configured
  187. *
  188. * @param string $status
  189. * @param string|null $store
  190. * @return bool
  191. */
  192. private function requestByOrderStatus($status, $store = null)
  193. {
  194. return $this->config->requestByOrderStatus($store) && $status === $this->config->invoiceOrderStatus($store);
  195. }
  196. /**
  197. * Register that an Order already has an Invoice
  198. *
  199. * @param int $orderId
  200. * @return void
  201. */
  202. private function setHasInvoice($orderId)
  203. {
  204. /** @var OrderInvoiceStatus $orderInvoiceStatus */
  205. try {
  206. $orderInvoiceStatus = $this->repository->getByOrderId($orderId);
  207. } catch (NoSuchEntityException $e) {
  208. $orderInvoiceStatus = $this->factory->create();
  209. $orderInvoiceStatus->setId($orderId);
  210. }
  211. $orderInvoiceStatus->setIsSent(true);
  212. try {
  213. $this->repository->save($orderInvoiceStatus);
  214. } catch (\Exception $exception) {
  215. $this->logger->critical($exception);
  216. }
  217. }
  218. }