OrderSaveAfterObserverTest.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. <?php
  2. namespace Vertex\Tax\Test\Unit\Observer;
  3. use Magento\Framework\DataObject;
  4. use Magento\Framework\Event;
  5. use Magento\Framework\Exception\NoSuchEntityException;
  6. use Magento\Framework\Message\ManagerInterface;
  7. use Magento\Sales\Api\Data\OrderExtension;
  8. use Magento\Sales\Model\Order;
  9. use Vertex\Services\Invoice\Request;
  10. use Vertex\Services\Invoice\Response;
  11. use Vertex\Tax\Model\Api\Data\InvoiceRequestBuilder;
  12. use Vertex\Tax\Model\Config;
  13. use Vertex\Tax\Model\ConfigurationValidator;
  14. use Vertex\Tax\Model\CountryGuard;
  15. use Vertex\Tax\Model\Data\OrderInvoiceStatus;
  16. use Vertex\Tax\Model\Data\OrderInvoiceStatusFactory;
  17. use Vertex\Tax\Model\ModuleManager;
  18. use Vertex\Tax\Model\Repository\OrderInvoiceStatusRepository;
  19. use Vertex\Tax\Model\TaxInvoice;
  20. use Vertex\Tax\Observer\GiftwrapExtensionLoader;
  21. use Vertex\Tax\Observer\OrderSavedAfterObserver;
  22. use Vertex\Tax\Observer\ShippingAssignmentExtensionLoader;
  23. use Vertex\Tax\Test\Unit\TestCase;
  24. /**
  25. * Tests for {@see OrderSaveAfterObserver}
  26. *
  27. * @SuppressWarnings(PHPMD.CouplingBetweenObjects) At limit - doesn't make sense to move success case to drop 1
  28. */
  29. class OrderSaveAfterObserverTest extends TestCase
  30. {
  31. /** @var \PHPUnit_Framework_MockObject_MockObject|Config */
  32. private $configMock;
  33. /** @var \PHPUnit_Framework_MockObject_MockObject|ConfigurationValidator */
  34. private $configValidatorMock;
  35. /** @var \PHPUnit_Framework_MockObject_MockObject|CountryGuard */
  36. private $countryGuardMock;
  37. /** @var \PHPUnit_Framework_MockObject_MockObject|OrderInvoiceStatusFactory */
  38. private $factoryMock;
  39. /** @var \PHPUnit_Framework_MockObject_MockObject|GiftwrapExtensionLoader */
  40. private $giftwrapExtensionMock;
  41. /** @var \PHPUnit_Framework_MockObject_MockObject|ManagerInterface */
  42. private $managerInterfaceMock;
  43. /** @var int */
  44. private $orderId;
  45. /** @var \PHPUnit_Framework_MockObject_MockObject|OrderInvoiceStatus */
  46. private $orderInvoiceStatusMock;
  47. /** @var \PHPUnit_Framework_MockObject_MockObject|Order */
  48. private $orderMock;
  49. /** @var OrderSavedAfterObserver */
  50. private $orderSavedAfterObserver;
  51. /** @var \PHPUnit_Framework_MockObject_MockObject|OrderInvoiceStatusRepository */
  52. private $repositoryMock;
  53. /** @var \PHPUnit_Framework_MockObject_MockObject|ShippingAssignmentExtensionLoader */
  54. private $shipmentExtensionLoader;
  55. /** @var \PHPUnit_Framework_MockObject_MockObject|TaxInvoice */
  56. private $taxInvoiceMock;
  57. /** @var \PHPUnit_Framework_MockObject_MockObject|OrderExtension */
  58. private $orderExtensionMock;
  59. /** @var \PHPUnit_Framework_MockObject_MockObject|InvoiceRequestBuilder */
  60. private $invoiceRequestBuilderMock;
  61. /**
  62. * @inheritdoc
  63. */
  64. protected function setUp()
  65. {
  66. parent::setUp();
  67. $this->configMock = $this->getMockBuilder(Config::class)
  68. ->setMethods(['isVertexActive', 'requestByOrderStatus', 'invoiceOrderStatus', 'isTaxCalculationEnabled'])
  69. ->disableOriginalConstructor()
  70. ->getMock();
  71. $this->countryGuardMock = $this->getMockBuilder(CountryGuard::class)
  72. ->setMethods(['isOrderServiceableByVertex'])
  73. ->disableOriginalConstructor()
  74. ->getMock();
  75. $this->taxInvoiceMock = $this->getMockBuilder(TaxInvoice::class)
  76. ->setMethods(['prepareInvoiceData', 'sendInvoiceRequest'])
  77. ->disableOriginalConstructor()
  78. ->getMock();
  79. $this->managerInterfaceMock = $this->getMockBuilder(ManagerInterface::class)
  80. ->setMethods(['addSuccessMessage'])
  81. ->disableOriginalConstructor()
  82. ->getMockForAbstractClass();
  83. $this->repositoryMock = $this->getMockBuilder(OrderInvoiceStatusRepository::class)
  84. ->setMethods(['getByOrderId', 'save'])
  85. ->disableOriginalConstructor()
  86. ->getMock();
  87. $this->factoryMock = $this->getMockBuilder(OrderInvoiceStatusFactory::class)
  88. ->setMethods(['create'])
  89. ->disableOriginalConstructor()
  90. ->getMock();
  91. $this->invoiceRequestBuilderMock = $this->getMockBuilder(InvoiceRequestBuilder::class)
  92. ->setMethods(['buildFromOrder'])
  93. ->disableOriginalConstructor()
  94. ->getMock();
  95. $this->orderInvoiceStatusMock = $this->getMockBuilder(OrderInvoiceStatus::class)
  96. ->setMethods(['setId', 'setIsSent'])
  97. ->disableOriginalConstructor()
  98. ->getMock();
  99. $this->factoryMock->method('create')
  100. ->willReturn($this->orderInvoiceStatusMock);
  101. $this->orderMock = $this->getMockBuilder(Order::class)
  102. ->setMethods(['getStore', 'getId', 'getStatus', 'getExtensionAttributes'])
  103. ->disableOriginalConstructor()
  104. ->getMock();
  105. $this->configValidatorMock = $this->getMockBuilder(ConfigurationValidator::class)
  106. ->setMethods(['execute'])
  107. ->disableOriginalConstructor()
  108. ->getMock();
  109. $this->orderExtensionMock = $this->getMockBuilder(OrderExtension::class)
  110. ->setMethods(['getShippingAssignments'])
  111. ->disableOriginalConstructor()
  112. ->getMock();
  113. $this->giftwrapExtensionMock = $this->getMockBuilder(GiftwrapExtensionLoader::class)
  114. ->setMethods(['loadOnOrder'])
  115. ->disableOriginalConstructor()
  116. ->getMock();
  117. $this->shipmentExtensionLoader = $this->getMockBuilder(ShippingAssignmentExtensionLoader::class)
  118. ->setMethods(['loadOnOrder'])
  119. ->disableOriginalConstructor()
  120. ->getMock();
  121. $this->orderId = rand();
  122. $this->orderMock->method('getId')
  123. ->willReturn($this->orderId);
  124. $this->orderMock
  125. ->method('getExtensionAttributes')
  126. ->willReturn($this->orderExtensionMock);
  127. $this->orderExtensionMock->method('getShippingAssignments')->willReturn(true);
  128. $this->orderSavedAfterObserver = $this->getObject(
  129. OrderSavedAfterObserver::class,
  130. [
  131. 'config' => $this->configMock,
  132. 'countryGuard' => $this->countryGuardMock,
  133. 'taxInvoice' => $this->taxInvoiceMock,
  134. 'messageManager' => $this->managerInterfaceMock,
  135. 'repository' => $this->repositoryMock,
  136. 'factory' => $this->factoryMock,
  137. 'configValidator' => $this->configValidatorMock,
  138. 'invoiceRequestBuilder' => $this->invoiceRequestBuilderMock,
  139. 'giftwrapExtensionLoader' => $this->giftwrapExtensionMock,
  140. 'shipmentExtensionLoader' => $this->shipmentExtensionLoader,
  141. 'showSuccessMessage' => true
  142. ]
  143. );
  144. }
  145. /**
  146. * Test that invoice is not sent when configuration is not valid
  147. *
  148. * @covers \Vertex\Tax\Observer\OrderSavedAfterObserver
  149. * @return void
  150. * @throws \Magento\Framework\Exception\LocalizedException
  151. */
  152. public function testInvoiceNotSentIfConfigurationInvalid()
  153. {
  154. $this->assertInvoiceNeverSent();
  155. $this->setVertexActive();
  156. $this->setCanService();
  157. $this->setHasNoInvoice();
  158. $this->prepareEmptyInvoiceData();
  159. $this->setupRequestByOrderFlag();
  160. $this->setConfigValid(false);
  161. $observer = $this->createObserver();
  162. $this->orderSavedAfterObserver->execute($observer);
  163. }
  164. /**
  165. * Test that invoice is not sent when order has been invoiced
  166. *
  167. * @covers \Vertex\Tax\Observer\OrderSavedAfterObserver
  168. * @return void
  169. */
  170. public function testInvoiceNotSentIfOrderAlreadyInvoiced()
  171. {
  172. $this->assertInvoiceNeverSent();
  173. $this->setVertexActive();
  174. $this->setConfigValid();
  175. $this->setupRequestByOrderFlag();
  176. $this->setCanService();
  177. $this->prepareEmptyInvoiceData();
  178. // An Invoice is already stored. Existence is based on non-exception return
  179. $orderInvoiceStatus = new DataObject();
  180. $this->repositoryMock->method('getByOrderId')
  181. ->willReturn($orderInvoiceStatus);
  182. $observer = $this->createObserver();
  183. $this->orderSavedAfterObserver->execute($observer);
  184. }
  185. /**
  186. * Test that invoice is not sent when order is not serviceable
  187. *
  188. * @covers \Vertex\Tax\Observer\OrderSavedAfterObserver
  189. * @return void
  190. */
  191. public function testInvoiceNotSentIfOrderNotServiceable()
  192. {
  193. $this->assertInvoiceNeverSent();
  194. $this->setConfigValid();
  195. $this->setVertexActive();
  196. $this->countryGuardMock->expects($this->atLeastOnce())
  197. ->method('isOrderServiceableByVertex')
  198. ->willReturn(false);
  199. $this->setHasNoInvoice();
  200. $this->prepareEmptyInvoiceData();
  201. $this->setupRequestByOrderFlag();
  202. $observer = $this->createObserver();
  203. $this->orderSavedAfterObserver->execute($observer);
  204. }
  205. /**
  206. * Test that invoice is not sent when order is not right status
  207. *
  208. * @covers \Vertex\Tax\Observer\OrderSavedAfterObserver
  209. * @return void
  210. */
  211. public function testInvoiceNotSentIfOrderStatusWrong()
  212. {
  213. $this->assertInvoiceNeverSent();
  214. $this->setConfigValid();
  215. $this->setVertexActive();
  216. $this->setCanService();
  217. $this->setHasNoInvoice();
  218. $this->prepareEmptyInvoiceData();
  219. $this->configMock->method('requestByOrderStatus')
  220. ->willReturn(true);
  221. $status1 = uniqid('order-status-', false);
  222. $status2 = uniqid('order-status-', false);
  223. $this->configMock->expects($this->atLeastOnce())
  224. ->method('invoiceOrderStatus')
  225. ->willReturn($status1);
  226. $this->orderMock->expects($this->atLeastOnce())
  227. ->method('getStatus')
  228. ->willReturn($status2);
  229. $observer = $this->createObserver();
  230. $this->orderSavedAfterObserver->execute($observer);
  231. }
  232. /**
  233. * Test that invoice is not sent when Vertex is not active
  234. *
  235. * @covers \Vertex\Tax\Observer\OrderSavedAfterObserver
  236. * @return void
  237. */
  238. public function testInvoiceNotSentIfVertexIsNotActive()
  239. {
  240. $this->assertInvoiceNeverSent();
  241. $this->setConfigValid();
  242. $this->configMock->expects($this->atLeastOnce())
  243. ->method('isVertexActive')
  244. ->willReturn(false);
  245. $this->setCanService();
  246. $this->setHasNoInvoice();
  247. $this->prepareEmptyInvoiceData();
  248. $this->setupRequestByOrderFlag();
  249. $observer = $this->createObserver();
  250. $this->orderSavedAfterObserver->execute($observer);
  251. }
  252. /**
  253. * Test that invoice is sent when conditions align
  254. *
  255. * @covers \Vertex\Tax\Observer\OrderSavedAfterObserver
  256. * @return void
  257. */
  258. public function testInvoiceSentAndActionsOccur()
  259. {
  260. $this->setVertexActive();
  261. $this->setCanService();
  262. $this->setHasNoInvoice();
  263. $this->prepareEmptyInvoiceData();
  264. $this->setupRequestByOrderFlag();
  265. $this->setConfigValid();
  266. $response = new Response();
  267. // Assert Invoice is Sent
  268. $this->taxInvoiceMock->expects($this->once())
  269. ->method('sendInvoiceRequest')
  270. ->willReturn($response);
  271. $this->shipmentExtensionLoader->expects($this->once())
  272. ->method('loadOnOrder')
  273. ->with(
  274. $this->callback(
  275. function ($order) {
  276. return $order->getId() === $this->orderId;
  277. }
  278. )
  279. )
  280. ->willReturn($this->orderMock);
  281. $this->giftwrapExtensionMock->expects($this->once())
  282. ->method('loadOnOrder')
  283. ->with(
  284. $this->callback(
  285. function ($order) {
  286. return $order->getId() === $this->orderId;
  287. }
  288. )
  289. )
  290. ->willReturn($this->orderMock);
  291. // Assert success message is added
  292. $this->managerInterfaceMock->expects($this->once())
  293. ->method('addSuccessMessage')
  294. ->with(
  295. 'The Vertex invoice has been sent.'
  296. );
  297. // Assert OrderInvoiceStatus given correct data
  298. $this->orderInvoiceStatusMock->expects($this->once())
  299. ->method('setId')
  300. ->with($this->orderId);
  301. $this->orderInvoiceStatusMock->expects($this->once())
  302. ->method('setIsSent')
  303. ->with(true);
  304. // Assert OrderInvoiceStatus record saved
  305. $this->repositoryMock->expects($this->once())
  306. ->method('save')
  307. ->with($this->orderInvoiceStatusMock);
  308. $request = new Request();
  309. $this->invoiceRequestBuilderMock->expects($this->once())
  310. ->method('buildFromOrder')
  311. ->with(
  312. $this->callback(
  313. function ($order) {
  314. return $order->getId() === $this->orderId;
  315. }
  316. )
  317. )
  318. ->willReturn($request);
  319. $observer = $this->createObserver();
  320. $this->orderSavedAfterObserver->execute($observer);
  321. }
  322. /**
  323. * Assert that a Vertex Invoice is never sent
  324. *
  325. * @return void
  326. */
  327. private function assertInvoiceNeverSent()
  328. {
  329. $this->taxInvoiceMock->expects($this->never())
  330. ->method('sendInvoiceRequest');
  331. }
  332. /**
  333. * Generate the instance of {@see OrderSavedAfterObserver}
  334. *
  335. * @return Event\Observer
  336. */
  337. private function createObserver()
  338. {
  339. $observer = $this->getObject(Event\Observer::class);
  340. $observer->setData('event', $observer);
  341. $observer->setData('order', $this->orderMock);
  342. return $observer;
  343. }
  344. /**
  345. * Ensure that taxInvoice->prepareInvoiceData always returns an array for check before sendInvoiceRequest
  346. *
  347. * @return void
  348. */
  349. private function prepareEmptyInvoiceData()
  350. {
  351. $this->taxInvoiceMock->method('prepareInvoiceData')
  352. ->willReturn(new Request());
  353. }
  354. /**
  355. * Register that Vertex can/can't service the order
  356. *
  357. * @param bool $canService
  358. * @return void
  359. */
  360. private function setCanService($canService = true)
  361. {
  362. $this->countryGuardMock->method('isOrderServiceableByVertex')
  363. ->willReturn($canService);
  364. }
  365. /**
  366. * Register that the Configuration is OK
  367. *
  368. * @param bool $configValid
  369. * @return void
  370. */
  371. private function setConfigValid($configValid = true)
  372. {
  373. $validatorResult = new ConfigurationValidator\Result();
  374. $validatorResult->setValid($configValid);
  375. $this->configValidatorMock->method('execute')
  376. ->willReturn($validatorResult);
  377. }
  378. /**
  379. * Register that an Order does not have a corresponding Vertex Invoice sent for it
  380. *
  381. * @return void
  382. */
  383. private function setHasNoInvoice()
  384. {
  385. $this->repositoryMock->method('getByOrderId')
  386. ->willThrowException(new NoSuchEntityException(__('No Such Entity')));
  387. }
  388. /**
  389. * Register that the Vertex module and tax calculation are enabled
  390. *
  391. * @return void
  392. */
  393. private function setVertexActive()
  394. {
  395. $this->configMock->method('isVertexActive')
  396. ->willReturn(true);
  397. $this->configMock->method('isTaxCalculationEnabled')
  398. ->willReturn(true);
  399. }
  400. /**
  401. * Perform setup so that the `$requestByOrder` variable is true
  402. *
  403. * Here we create an order status - give it to the order, ensure that the invoiceOrderStatus method on the config
  404. * will return that status, and set that the requestByOrderStatus config is true.
  405. *
  406. * @return void
  407. */
  408. private function setupRequestByOrderFlag()
  409. {
  410. $status = uniqid('order-status-', false);
  411. $this->configMock->method('requestByOrderStatus')
  412. ->willReturn(true);
  413. $this->configMock->method('invoiceOrderStatus')
  414. ->willReturn($status);
  415. $this->orderMock->method('getStatus')
  416. ->willReturn($status);
  417. }
  418. }