OrderTest.php 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Sales\Test\Unit\Model;
  7. use Magento\Catalog\Api\Data\ProductInterface;
  8. use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory;
  9. use Magento\Framework\Locale\ResolverInterface;
  10. use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
  11. use Magento\Sales\Api\Data\OrderInterface;
  12. use Magento\Sales\Model\Order;
  13. use Magento\Sales\Model\ResourceModel\Order\Item\Collection;
  14. use Magento\Sales\Model\ResourceModel\Order\Status\History\CollectionFactory as HistoryCollectionFactory;
  15. use Magento\Sales\Api\OrderItemRepositoryInterface;
  16. use Magento\Framework\Api\SearchCriteriaBuilder;
  17. use Magento\Framework\Api\SearchCriteria;
  18. use Magento\Sales\Api\Data\OrderItemSearchResultInterface;
  19. /**
  20. * Test class for \Magento\Sales\Model\Order
  21. *
  22. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  23. * @SuppressWarnings(PHPMD.TooManyPublicMethods)
  24. * @SuppressWarnings(PHPMD.ExcessivePublicCount)
  25. */
  26. class OrderTest extends \PHPUnit\Framework\TestCase
  27. {
  28. /**
  29. * @var \PHPUnit_Framework_MockObject_MockObject
  30. */
  31. protected $paymentCollectionFactoryMock;
  32. /**
  33. * @var \PHPUnit_Framework_MockObject_MockObject
  34. */
  35. protected $orderItemCollectionFactoryMock;
  36. /**
  37. * @var \Magento\Sales\Model\Order
  38. */
  39. protected $order;
  40. /**
  41. * @var \Magento\Framework\Event\Manager | \PHPUnit_Framework_MockObject_MockObject
  42. */
  43. protected $eventManager;
  44. /**
  45. * @var string
  46. */
  47. protected $incrementId;
  48. /**
  49. * @var \Magento\Sales\Model\ResourceModel\Order\Item | \PHPUnit_Framework_MockObject_MockObject
  50. */
  51. protected $item;
  52. /**
  53. * @var HistoryCollectionFactory|\PHPUnit_Framework_MockObject_MockObject
  54. */
  55. protected $historyCollectionFactoryMock;
  56. /**
  57. * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Pricing\PriceCurrencyInterface
  58. */
  59. protected $priceCurrency;
  60. /**
  61. * @var \Magento\Sales\Model\ResourceModel\Order\CollectionFactory|\PHPUnit_Framework_MockObject_MockObject
  62. */
  63. protected $salesOrderCollectionFactoryMock;
  64. /**
  65. * @var \Magento\Sales\Model\ResourceModel\Order\Collection|\PHPUnit_Framework_MockObject_MockObject
  66. */
  67. protected $salesOrderCollectionMock;
  68. /**
  69. * @var ProductCollectionFactory|\PHPUnit_Framework_MockObject_MockObject
  70. */
  71. protected $productCollectionFactoryMock;
  72. /**
  73. * @var ResolverInterface|\PHPUnit_Framework_MockObject_MockObject
  74. */
  75. private $localeResolver;
  76. /**
  77. * @var TimezoneInterface|\PHPUnit_Framework_MockObject_MockObject
  78. */
  79. private $timezone;
  80. /**
  81. * @var OrderItemRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
  82. */
  83. private $itemRepository;
  84. /**
  85. * @var SearchCriteriaBuilder|\PHPUnit_Framework_MockObject_MockObject
  86. */
  87. private $searchCriteriaBuilder;
  88. protected function setUp()
  89. {
  90. $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
  91. $this->paymentCollectionFactoryMock = $this->createPartialMock(
  92. \Magento\Sales\Model\ResourceModel\Order\Payment\CollectionFactory::class,
  93. ['create']
  94. );
  95. $this->orderItemCollectionFactoryMock = $this->createPartialMock(
  96. \Magento\Sales\Model\ResourceModel\Order\Item\CollectionFactory::class,
  97. ['create']
  98. );
  99. $this->historyCollectionFactoryMock = $this->createPartialMock(
  100. \Magento\Sales\Model\ResourceModel\Order\Status\History\CollectionFactory::class,
  101. ['create']
  102. );
  103. $this->productCollectionFactoryMock = $this->createPartialMock(
  104. \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory::class,
  105. ['create']
  106. );
  107. $this->salesOrderCollectionFactoryMock = $this->createPartialMock(
  108. \Magento\Sales\Model\ResourceModel\Order\CollectionFactory::class,
  109. ['create']
  110. );
  111. $this->item = $this->createPartialMock(\Magento\Sales\Model\ResourceModel\Order\Item::class, [
  112. 'isDeleted',
  113. 'getQtyToInvoice',
  114. 'getParentItemId',
  115. 'getQuoteItemId',
  116. 'getLockedDoInvoice',
  117. 'getProductId',
  118. ]);
  119. $this->salesOrderCollectionMock = $this->getMockBuilder(
  120. \Magento\Sales\Model\ResourceModel\Order\Collection::class
  121. )->disableOriginalConstructor()
  122. ->setMethods(['addFieldToFilter', 'load', 'getFirstItem'])
  123. ->getMock();
  124. $collection = $this->createMock(\Magento\Sales\Model\ResourceModel\Order\Item\Collection::class);
  125. $collection->expects($this->any())->method('setOrderFilter')->willReturnSelf();
  126. $collection->expects($this->any())->method('getItems')->willReturn([$this->item]);
  127. $collection->expects($this->any())->method('getIterator')->willReturn(new \ArrayIterator([$this->item]));
  128. $this->orderItemCollectionFactoryMock->expects($this->any())->method('create')->willReturn($collection);
  129. $this->priceCurrency = $this->getMockForAbstractClass(
  130. \Magento\Framework\Pricing\PriceCurrencyInterface::class,
  131. [],
  132. '',
  133. false,
  134. false,
  135. true,
  136. ['round']
  137. );
  138. $this->localeResolver = $this->createMock(ResolverInterface::class);
  139. $this->timezone = $this->createMock(TimezoneInterface::class);
  140. $this->incrementId = '#00000001';
  141. $this->eventManager = $this->createMock(\Magento\Framework\Event\Manager::class);
  142. $context = $this->createPartialMock(\Magento\Framework\Model\Context::class, ['getEventDispatcher']);
  143. $context->expects($this->any())->method('getEventDispatcher')->willReturn($this->eventManager);
  144. $this->itemRepository = $this->getMockBuilder(OrderItemRepositoryInterface::class)
  145. ->setMethods(['getList'])
  146. ->disableOriginalConstructor()->getMockForAbstractClass();
  147. $this->searchCriteriaBuilder = $this->getMockBuilder(SearchCriteriaBuilder::class)
  148. ->setMethods(['addFilter', 'create'])
  149. ->disableOriginalConstructor()->getMockForAbstractClass();
  150. $this->order = $helper->getObject(
  151. \Magento\Sales\Model\Order::class,
  152. [
  153. 'paymentCollectionFactory' => $this->paymentCollectionFactoryMock,
  154. 'orderItemCollectionFactory' => $this->orderItemCollectionFactoryMock,
  155. 'data' => ['increment_id' => $this->incrementId],
  156. 'context' => $context,
  157. 'historyCollectionFactory' => $this->historyCollectionFactoryMock,
  158. 'salesOrderCollectionFactory' => $this->salesOrderCollectionFactoryMock,
  159. 'priceCurrency' => $this->priceCurrency,
  160. 'productListFactory' => $this->productCollectionFactoryMock,
  161. 'localeResolver' => $this->localeResolver,
  162. 'timezone' => $this->timezone,
  163. 'itemRepository' => $this->itemRepository,
  164. 'searchCriteriaBuilder' => $this->searchCriteriaBuilder
  165. ]
  166. );
  167. }
  168. /**
  169. * Test testGetItems method.
  170. */
  171. public function testGetItems()
  172. {
  173. $orderItems = [$this->item];
  174. $this->searchCriteriaBuilder->expects($this->once())->method('addFilter')->willReturnSelf();
  175. $searchCriteria = $this->getMockBuilder(SearchCriteria::class)
  176. ->disableOriginalConstructor()->getMockForAbstractClass();
  177. $this->searchCriteriaBuilder->expects($this->once())->method('create')->willReturn($searchCriteria);
  178. $itemsCollection = $this->getMockBuilder(OrderItemSearchResultInterface::class)
  179. ->setMethods(['getItems'])
  180. ->disableOriginalConstructor()->getMockForAbstractClass();
  181. $itemsCollection->expects($this->once())->method('getItems')->willReturn($orderItems);
  182. $this->itemRepository->expects($this->once())->method('getList')->willReturn($itemsCollection);
  183. $this->assertEquals($orderItems, $this->order->getItems());
  184. }
  185. /**
  186. * Prepare order item mock.
  187. *
  188. * @param int $orderId
  189. * @return void
  190. */
  191. private function prepareOrderItem(int $orderId = 0)
  192. {
  193. $this->order->setData(
  194. \Magento\Sales\Api\Data\OrderInterface::ITEMS,
  195. [
  196. $orderId => $this->item
  197. ]
  198. );
  199. }
  200. /**
  201. * Test GetItemById method.
  202. *
  203. * @return void
  204. */
  205. public function testGetItemById()
  206. {
  207. $realOrderItemId = 1;
  208. $fakeOrderItemId = 2;
  209. $this->prepareOrderItem($realOrderItemId);
  210. $this->assertEquals($this->item, $this->order->getItemById($realOrderItemId));
  211. $this->assertEquals(null, $this->order->getItemById($fakeOrderItemId));
  212. }
  213. /**
  214. * Test GetItemByQuoteItemId method.
  215. *
  216. * @param int|null $gettingQuoteItemId
  217. * @param int|null $quoteItemId
  218. * @param string|null $result
  219. *
  220. * @dataProvider dataProviderGetItemByQuoteItemId
  221. * @return void
  222. */
  223. public function testGetItemByQuoteItemId($gettingQuoteItemId, $quoteItemId, $result)
  224. {
  225. $this->prepareOrderItem();
  226. $this->item->expects($this->any())
  227. ->method('getQuoteItemId')
  228. ->willReturn($gettingQuoteItemId);
  229. if ($result !== null) {
  230. $result = $this->item;
  231. }
  232. $this->assertEquals($result, $this->order->getItemByQuoteItemId($quoteItemId));
  233. }
  234. /**
  235. * @return array
  236. */
  237. public function dataProviderGetItemByQuoteItemId()
  238. {
  239. return [
  240. [10, 10, 'replace-me'],
  241. [10, 88, null],
  242. [88, 10, null],
  243. ];
  244. }
  245. /**
  246. * Test getAllVisibleItems method.
  247. *
  248. * @param bool $isDeleted
  249. * @param int|null $parentItemId
  250. * @param array $result
  251. *
  252. * @dataProvider dataProviderGetAllVisibleItems
  253. * @return void
  254. */
  255. public function testGetAllVisibleItems($isDeleted, $parentItemId, array $result)
  256. {
  257. $this->prepareOrderItem();
  258. $this->item->expects($this->once())
  259. ->method('isDeleted')
  260. ->willReturn($isDeleted);
  261. $this->item->expects($this->any())
  262. ->method('getParentItemId')
  263. ->willReturn($parentItemId);
  264. if (!empty($result)) {
  265. $result = [$this->item];
  266. }
  267. $this->assertEquals($result, $this->order->getAllVisibleItems());
  268. }
  269. /**
  270. * @return array
  271. */
  272. public function dataProviderGetAllVisibleItems()
  273. {
  274. return [
  275. [false, null, ['replace-me']],
  276. [true, null, []],
  277. [true, 10, []],
  278. [false, 10, []],
  279. [true, null, []],
  280. ];
  281. }
  282. public function testCanCancelCanUnhold()
  283. {
  284. $this->order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD, true);
  285. $this->order->setState(\Magento\Sales\Model\Order::STATE_PAYMENT_REVIEW);
  286. $this->assertFalse($this->order->canCancel());
  287. }
  288. public function testCanCancelIsPaymentReview()
  289. {
  290. $this->order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD, false);
  291. $this->order->setState(\Magento\Sales\Model\Order::STATE_PAYMENT_REVIEW);
  292. $this->assertFalse($this->order->canCancel());
  293. }
  294. /**
  295. * Test CanInvoice method.
  296. *
  297. * @return void
  298. */
  299. public function testCanInvoice()
  300. {
  301. $this->prepareOrderItem();
  302. $this->item->expects($this->any())
  303. ->method('getQtyToInvoice')
  304. ->willReturn(42);
  305. $this->item->expects($this->any())
  306. ->method('getLockedDoInvoice')
  307. ->willReturn(false);
  308. $this->assertTrue($this->order->canInvoice());
  309. }
  310. /**
  311. * @param string $status
  312. *
  313. * @dataProvider notInvoicingStatesProvider
  314. */
  315. public function testCanNotInvoiceInSomeStates($status)
  316. {
  317. $this->item->expects($this->any())
  318. ->method('getQtyToInvoice')
  319. ->willReturn(42);
  320. $this->item->expects($this->any())
  321. ->method('getLockedDoInvoice')
  322. ->willReturn(false);
  323. $this->order->setData('state', $status);
  324. $this->assertFalse($this->order->canInvoice());
  325. }
  326. public function testCanNotInvoiceWhenActionInvoiceFlagIsFalse()
  327. {
  328. $this->item->expects($this->any())
  329. ->method('getQtyToInvoice')
  330. ->willReturn(42);
  331. $this->item->expects($this->any())
  332. ->method('getLockedDoInvoice')
  333. ->willReturn(false);
  334. $this->order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_INVOICE, false);
  335. $this->assertFalse($this->order->canInvoice());
  336. }
  337. /**
  338. * Test CanNotInvoice method when invoice is locked.
  339. *
  340. * @return void
  341. */
  342. public function testCanNotInvoiceWhenLockedInvoice()
  343. {
  344. $this->prepareOrderItem();
  345. $this->item->expects($this->any())
  346. ->method('getQtyToInvoice')
  347. ->willReturn(42);
  348. $this->item->expects($this->any())
  349. ->method('getLockedDoInvoice')
  350. ->willReturn(true);
  351. $this->assertFalse($this->order->canInvoice());
  352. }
  353. /**
  354. * Test CanNotInvoice method when didn't have qty to invoice.
  355. *
  356. * @return void
  357. */
  358. public function testCanNotInvoiceWhenDidNotHaveQtyToInvoice()
  359. {
  360. $this->prepareOrderItem();
  361. $this->item->expects($this->any())
  362. ->method('getQtyToInvoice')
  363. ->willReturn(0);
  364. $this->item->expects($this->any())
  365. ->method('getLockedDoInvoice')
  366. ->willReturn(false);
  367. $this->assertFalse($this->order->canInvoice());
  368. }
  369. public function testCanCreditMemo()
  370. {
  371. $totalPaid = 10;
  372. $this->prepareOrderItem();
  373. $this->order->setTotalPaid($totalPaid);
  374. $this->priceCurrency->expects($this->once())->method('round')->with($totalPaid)->willReturnArgument(0);
  375. $this->assertTrue($this->order->canCreditmemo());
  376. }
  377. public function testCanNotCreditMemoWithTotalNull()
  378. {
  379. $totalPaid = 0;
  380. $this->prepareOrderItem();
  381. $this->order->setTotalPaid($totalPaid);
  382. $this->priceCurrency->expects($this->once())->method('round')->with($totalPaid)->willReturnArgument(0);
  383. $this->assertFalse($this->order->canCreditmemo());
  384. }
  385. public function testCanNotCreditMemoWithAdjustmentNegative()
  386. {
  387. $totalPaid = 100;
  388. $adjustmentNegative = 10;
  389. $totalRefunded = 90;
  390. $this->prepareOrderItem();
  391. $this->order->setTotalPaid($totalPaid);
  392. $this->order->setTotalRefunded($totalRefunded);
  393. $this->order->setAdjustmentNegative($adjustmentNegative);
  394. $this->priceCurrency->expects($this->once())->method('round')->with($totalPaid)->willReturnArgument(0);
  395. $this->assertFalse($this->order->canCreditmemo());
  396. }
  397. public function testCanCreditMemoWithAdjustmentNegativeLowerThanTotalPaid()
  398. {
  399. $totalPaid = 100;
  400. $adjustmentNegative = 9;
  401. $totalRefunded = 90;
  402. $this->prepareOrderItem();
  403. $this->order->setTotalPaid($totalPaid);
  404. $this->order->setTotalRefunded($totalRefunded);
  405. $this->order->setAdjustmentNegative($adjustmentNegative);
  406. $this->priceCurrency->expects($this->once())->method('round')->with($totalPaid)->willReturnArgument(0);
  407. $this->assertTrue($this->order->canCreditmemo());
  408. }
  409. /**
  410. * @param string $state
  411. *
  412. * @dataProvider canNotCreditMemoStatesProvider
  413. */
  414. public function testCanNotCreditMemoWithSomeStates($state)
  415. {
  416. $this->order->setData('state', $state);
  417. $this->assertFalse($this->order->canCreditmemo());
  418. }
  419. public function testCanNotCreditMemoWithForced()
  420. {
  421. $this->order->setData('forced_can_creditmemo', true);
  422. $this->assertTrue($this->order->canCreditmemo());
  423. }
  424. public function testCanEditIfHasInvoices()
  425. {
  426. $invoiceCollection = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Invoice\Collection::class)
  427. ->disableOriginalConstructor()
  428. ->setMethods(['count'])
  429. ->getMock();
  430. $invoiceCollection->expects($this->once())
  431. ->method('count')
  432. ->willReturn(2);
  433. $this->order->setInvoiceCollection($invoiceCollection);
  434. $this->order->setState(\Magento\Sales\Model\Order::STATE_PROCESSING);
  435. $this->assertFalse($this->order->canEdit());
  436. }
  437. /**
  438. * @covers \Magento\Sales\Model\Order::canReorder
  439. */
  440. public function testCanReorder()
  441. {
  442. $productId = 1;
  443. $this->order->setState(Order::STATE_PROCESSING);
  444. $this->order->setActionFlag(Order::ACTION_FLAG_REORDER, true);
  445. $this->item->expects($this->any())
  446. ->method('getProductId')
  447. ->willReturn($productId);
  448. $product = $this->getMockBuilder(ProductInterface::class)
  449. ->setMethods(['isSalable'])
  450. ->getMockForAbstractClass();
  451. $product->expects(static::once())
  452. ->method('isSalable')
  453. ->willReturn(true);
  454. $productCollection = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product\Collection::class)
  455. ->disableOriginalConstructor()
  456. ->setMethods(['setStoreId', 'addIdFilter', 'load', 'getItemById', 'addAttributeToSelect'])
  457. ->getMock();
  458. $productCollection->expects($this->once())
  459. ->method('setStoreId')
  460. ->willReturnSelf();
  461. $productCollection->expects($this->once())
  462. ->method('addIdFilter')
  463. ->willReturnSelf();
  464. $productCollection->expects($this->once())
  465. ->method('addAttributeToSelect')
  466. ->willReturnSelf();
  467. $productCollection->expects($this->once())
  468. ->method('load')
  469. ->willReturnSelf();
  470. $productCollection->expects($this->once())
  471. ->method('getItemById')
  472. ->with($productId)
  473. ->willReturn($product);
  474. $this->productCollectionFactoryMock->expects($this->once())
  475. ->method('create')
  476. ->willReturn($productCollection);
  477. $this->assertTrue($this->order->canReorder());
  478. }
  479. /**
  480. * @covers \Magento\Sales\Model\Order::canReorder
  481. */
  482. public function testCanReorderIsPaymentReview()
  483. {
  484. $this->order->setState(Order::STATE_PAYMENT_REVIEW);
  485. $this->assertFalse($this->order->canReorder());
  486. }
  487. /**
  488. * @covers \Magento\Sales\Model\Order::canReorder
  489. */
  490. public function testCanReorderFlagReorderFalse()
  491. {
  492. $this->order->setState(Order::STATE_PROCESSING);
  493. $this->order->setActionFlag(Order::ACTION_FLAG_REORDER, false);
  494. $this->assertFalse($this->order->canReorder());
  495. }
  496. /**
  497. * @covers \Magento\Sales\Model\Order::canReorder
  498. */
  499. public function testCanReorderProductNotExists()
  500. {
  501. $productId = 1;
  502. $this->order->setState(Order::STATE_PROCESSING);
  503. $this->order->setActionFlag(Order::ACTION_FLAG_REORDER, true);
  504. $this->item->expects($this->any())
  505. ->method('getProductId')
  506. ->willReturn($productId);
  507. $product = $this->getMockBuilder(ProductInterface::class)
  508. ->setMethods(['isSalable'])
  509. ->getMockForAbstractClass();
  510. $product->expects(static::never())
  511. ->method('isSalable');
  512. $productCollection = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product\Collection::class)
  513. ->disableOriginalConstructor()
  514. ->setMethods(['setStoreId', 'addIdFilter', 'load', 'getItemById', 'addAttributeToSelect'])
  515. ->getMock();
  516. $productCollection->expects($this->once())
  517. ->method('setStoreId')
  518. ->willReturnSelf();
  519. $productCollection->expects($this->once())
  520. ->method('addIdFilter')
  521. ->willReturnSelf();
  522. $productCollection->expects($this->once())
  523. ->method('load')
  524. ->willReturnSelf();
  525. $productCollection->expects($this->once())
  526. ->method('getItemById')
  527. ->with($productId)
  528. ->willReturn(null);
  529. $this->productCollectionFactoryMock->expects($this->once())
  530. ->method('create')
  531. ->willReturn($productCollection);
  532. $productCollection->expects($this->once())
  533. ->method('addAttributeToSelect')
  534. ->willReturnSelf();
  535. $this->assertFalse($this->order->canReorder());
  536. }
  537. /**
  538. * @covers \Magento\Sales\Model\Order::canReorder
  539. */
  540. public function testCanReorderProductNotSalable()
  541. {
  542. $productId = 1;
  543. $this->order->setState(Order::STATE_PROCESSING);
  544. $this->order->setActionFlag(Order::ACTION_FLAG_REORDER, true);
  545. $this->item->expects($this->any())
  546. ->method('getProductId')
  547. ->willReturn($productId);
  548. $product = $this->getMockBuilder(ProductInterface::class)
  549. ->setMethods(['isSalable'])
  550. ->getMockForAbstractClass();
  551. $product->expects(static::once())
  552. ->method('isSalable')
  553. ->willReturn(false);
  554. $productCollection = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product\Collection::class)
  555. ->disableOriginalConstructor()
  556. ->setMethods(['setStoreId', 'addIdFilter', 'load', 'getItemById', 'addAttributeToSelect'])
  557. ->getMock();
  558. $productCollection->expects($this->once())
  559. ->method('setStoreId')
  560. ->willReturnSelf();
  561. $productCollection->expects($this->once())
  562. ->method('addIdFilter')
  563. ->willReturnSelf();
  564. $productCollection->expects($this->once())
  565. ->method('load')
  566. ->willReturnSelf();
  567. $productCollection->expects($this->once())
  568. ->method('getItemById')
  569. ->with($productId)
  570. ->willReturn($product);
  571. $this->productCollectionFactoryMock->expects($this->once())
  572. ->method('create')
  573. ->willReturn($productCollection);
  574. $productCollection->expects($this->once())
  575. ->method('addAttributeToSelect')
  576. ->willReturnSelf();
  577. $this->assertFalse($this->order->canReorder());
  578. }
  579. public function testCanCancelCanReviewPayment()
  580. {
  581. $paymentMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Payment::class)
  582. ->disableOriginalConstructor()
  583. ->setMethods(['isDeleted', 'canReviewPayment', 'canFetchTransactionInfo', '__wakeUp'])
  584. ->getMock();
  585. $paymentMock->expects($this->any())
  586. ->method('canReviewPayment')
  587. ->will($this->returnValue(false));
  588. $paymentMock->expects($this->any())
  589. ->method('canFetchTransactionInfo')
  590. ->will($this->returnValue(true));
  591. $this->preparePaymentMock($paymentMock);
  592. $this->order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD, false);
  593. $this->order->setState(\Magento\Sales\Model\Order::STATE_PAYMENT_REVIEW);
  594. $this->assertFalse($this->order->canCancel());
  595. }
  596. /**
  597. * Test CanCancelAllInvoiced method.
  598. *
  599. * @return void
  600. */
  601. public function testCanCancelAllInvoiced()
  602. {
  603. $this->prepareOrderItem();
  604. $paymentMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Payment::class)
  605. ->disableOriginalConstructor()
  606. ->setMethods(['isDeleted', 'canReviewPayment', 'canFetchTransactionInfo', '__wakeUp'])
  607. ->getMock();
  608. $paymentMock->expects($this->any())
  609. ->method('canReviewPayment')
  610. ->will($this->returnValue(false));
  611. $paymentMock->expects($this->any())
  612. ->method('canFetchTransactionInfo')
  613. ->will($this->returnValue(false));
  614. $collectionMock = $this->createPartialMock(
  615. \Magento\Sales\Model\ResourceModel\Order\Item\Collection::class,
  616. ['getItems', 'setOrderFilter']
  617. );
  618. $this->orderItemCollectionFactoryMock->expects($this->any())
  619. ->method('create')
  620. ->will($this->returnValue($collectionMock));
  621. $collectionMock->expects($this->any())
  622. ->method('setOrderFilter')
  623. ->willReturnSelf();
  624. $this->preparePaymentMock($paymentMock);
  625. $this->prepareItemMock(0);
  626. $this->order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD, false);
  627. $this->order->setState(\Magento\Sales\Model\Order::STATE_NEW);
  628. $this->item->expects($this->any())
  629. ->method('isDeleted')
  630. ->willReturn(false);
  631. $this->item->expects($this->any())
  632. ->method('getQtyToInvoice')
  633. ->willReturn(0);
  634. $this->assertFalse($this->order->canCancel());
  635. }
  636. public function testCanCancelState()
  637. {
  638. $paymentMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Payment::class)
  639. ->disableOriginalConstructor()
  640. ->setMethods(['isDeleted', 'canReviewPayment', 'canFetchTransactionInfo', '__wakeUp'])
  641. ->getMock();
  642. $paymentMock->expects($this->any())
  643. ->method('canReviewPayment')
  644. ->will($this->returnValue(false));
  645. $paymentMock->expects($this->any())
  646. ->method('canFetchTransactionInfo')
  647. ->will($this->returnValue(false));
  648. $this->preparePaymentMock($paymentMock);
  649. $this->prepareItemMock(1);
  650. $this->order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD, false);
  651. $this->order->setState(\Magento\Sales\Model\Order::STATE_CANCELED);
  652. $this->assertFalse($this->order->canCancel());
  653. }
  654. /**
  655. * Test CanCancelActionFlag method.
  656. *
  657. * @param bool $cancelActionFlag
  658. * @dataProvider dataProviderActionFlag
  659. * @return void
  660. */
  661. public function testCanCancelActionFlag($cancelActionFlag)
  662. {
  663. $this->prepareOrderItem();
  664. $paymentMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Payment::class)
  665. ->disableOriginalConstructor()
  666. ->setMethods(['isDeleted', 'canReviewPayment', 'canFetchTransactionInfo', '__wakeUp'])
  667. ->getMock();
  668. $paymentMock->expects($this->any())
  669. ->method('canReviewPayment')
  670. ->will($this->returnValue(false));
  671. $paymentMock->expects($this->any())
  672. ->method('canFetchTransactionInfo')
  673. ->will($this->returnValue(false));
  674. $this->preparePaymentMock($paymentMock);
  675. $this->prepareItemMock(1);
  676. $actionFlags = [
  677. \Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD => false,
  678. \Magento\Sales\Model\Order::ACTION_FLAG_CANCEL => $cancelActionFlag,
  679. ];
  680. foreach ($actionFlags as $action => $flag) {
  681. $this->order->setActionFlag($action, $flag);
  682. }
  683. $this->order->setData('state', \Magento\Sales\Model\Order::STATE_NEW);
  684. $this->item->expects($this->any())
  685. ->method('isDeleted')
  686. ->willReturn(false);
  687. $this->item->expects($this->any())
  688. ->method('getQtyToInvoice')
  689. ->willReturn(42);
  690. $this->assertEquals($cancelActionFlag, $this->order->canCancel());
  691. }
  692. /**
  693. * @param array $actionFlags
  694. * @param string $orderState
  695. * @dataProvider canVoidPaymentDataProvider
  696. */
  697. public function testCanVoidPayment($actionFlags, $orderState)
  698. {
  699. $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
  700. /** @var Order $order */
  701. $order = $helper->getObject(\Magento\Sales\Model\Order::class);
  702. foreach ($actionFlags as $action => $flag) {
  703. $order->setActionFlag($action, $flag);
  704. }
  705. $order->setData('state', $orderState);
  706. $payment = $this->_prepareOrderPayment($order);
  707. $canVoidOrder = true;
  708. if ($orderState == \Magento\Sales\Model\Order::STATE_CANCELED) {
  709. $canVoidOrder = false;
  710. }
  711. if ($orderState == \Magento\Sales\Model\Order::STATE_PAYMENT_REVIEW) {
  712. $canVoidOrder = false;
  713. }
  714. if ($orderState == \Magento\Sales\Model\Order::STATE_HOLDED && (!isset(
  715. $actionFlags[\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD]
  716. ) || $actionFlags[\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD] !== false)
  717. ) {
  718. $canVoidOrder = false;
  719. }
  720. $expected = false;
  721. if ($canVoidOrder) {
  722. $expected = 'some value';
  723. $payment->expects(
  724. $this->any()
  725. )->method(
  726. 'canVoid'
  727. )->will(
  728. $this->returnValue($expected)
  729. );
  730. } else {
  731. $payment->expects($this->never())->method('canVoid');
  732. }
  733. $this->assertEquals($expected, $order->canVoidPayment());
  734. }
  735. /**
  736. * @param $paymentMock
  737. */
  738. protected function preparePaymentMock($paymentMock)
  739. {
  740. $iterator = new \ArrayIterator([$paymentMock]);
  741. $collectionMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Payment\Collection::class)
  742. ->disableOriginalConstructor()
  743. ->setMethods(['setOrderFilter', 'getIterator'])
  744. ->getMock();
  745. $collectionMock->expects($this->any())
  746. ->method('getIterator')
  747. ->will($this->returnValue($iterator));
  748. $collectionMock->expects($this->any())
  749. ->method('setOrderFilter')
  750. ->will($this->returnSelf());
  751. $this->paymentCollectionFactoryMock->expects($this->any())
  752. ->method('create')
  753. ->will($this->returnValue($collectionMock));
  754. }
  755. /**
  756. * Prepare payment for the order
  757. *
  758. * @param \Magento\Sales\Model\Order|\PHPUnit_Framework_MockObject_MockObject $order
  759. * @param array $mockedMethods
  760. * @return \Magento\Sales\Model\Order\Payment|\PHPUnit_Framework_MockObject_MockObject
  761. */
  762. protected function _prepareOrderPayment($order, $mockedMethods = [])
  763. {
  764. $payment = $this->getMockBuilder(
  765. \Magento\Sales\Model\Order\Payment::class
  766. )->disableOriginalConstructor()->getMock();
  767. foreach ($mockedMethods as $method => $value) {
  768. $payment->expects($this->any())->method($method)->will($this->returnValue($value));
  769. }
  770. $payment->expects($this->any())->method('isDeleted')->will($this->returnValue(false));
  771. $order->setData(\Magento\Sales\Api\Data\OrderInterface::PAYMENT, $payment);
  772. return $payment;
  773. }
  774. /**
  775. * Get action flags
  776. *
  777. */
  778. protected function _getActionFlagsValues()
  779. {
  780. return [
  781. [],
  782. [
  783. \Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD => false,
  784. \Magento\Sales\Model\Order::ACTION_FLAG_CANCEL => false
  785. ],
  786. [
  787. \Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD => false,
  788. \Magento\Sales\Model\Order::ACTION_FLAG_CANCEL => true
  789. ]
  790. ];
  791. }
  792. /**
  793. * Get order statuses
  794. *
  795. * @return array
  796. */
  797. protected function _getOrderStatuses()
  798. {
  799. return [
  800. \Magento\Sales\Model\Order::STATE_HOLDED,
  801. \Magento\Sales\Model\Order::STATE_PAYMENT_REVIEW,
  802. \Magento\Sales\Model\Order::STATE_CANCELED,
  803. \Magento\Sales\Model\Order::STATE_COMPLETE,
  804. \Magento\Sales\Model\Order::STATE_CLOSED,
  805. \Magento\Sales\Model\Order::STATE_PROCESSING
  806. ];
  807. }
  808. /**
  809. * @param int $qtyInvoiced
  810. * @return void
  811. */
  812. protected function prepareItemMock($qtyInvoiced)
  813. {
  814. $itemMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Item::class)
  815. ->disableOriginalConstructor()
  816. ->setMethods(['isDeleted', 'filterByTypes', 'filterByParent', 'getQtyToInvoice', '__wakeUp'])
  817. ->getMock();
  818. $itemMock->expects($this->any())
  819. ->method('getQtyToInvoice')
  820. ->will($this->returnValue($qtyInvoiced));
  821. $iterator = new \ArrayIterator([$itemMock]);
  822. $itemCollectionMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Item\Collection::class)
  823. ->disableOriginalConstructor()
  824. ->setMethods(['setOrderFilter', 'getIterator', 'getItems'])
  825. ->getMock();
  826. $itemCollectionMock->expects($this->any())
  827. ->method('getIterator')
  828. ->will($this->returnValue($iterator));
  829. $itemCollectionMock->expects($this->any())
  830. ->method('setOrderFilter')
  831. ->will($this->returnSelf());
  832. $this->orderItemCollectionFactoryMock->expects($this->any())
  833. ->method('create')
  834. ->will($this->returnValue($itemCollectionMock));
  835. }
  836. /**
  837. * @return array
  838. */
  839. public function canVoidPaymentDataProvider()
  840. {
  841. $data = [];
  842. foreach ($this->_getActionFlagsValues() as $actionFlags) {
  843. foreach ($this->_getOrderStatuses() as $status) {
  844. $data[] = [$actionFlags, $status];
  845. }
  846. }
  847. return $data;
  848. }
  849. /**
  850. * @return array
  851. */
  852. public function dataProviderActionFlag()
  853. {
  854. return [
  855. [false],
  856. [true]
  857. ];
  858. }
  859. /**
  860. * test method getIncrementId()
  861. */
  862. public function testGetIncrementId()
  863. {
  864. $this->assertEquals($this->incrementId, $this->order->getIncrementId());
  865. }
  866. public function testGetEntityType()
  867. {
  868. $this->assertEquals('order', $this->order->getEntityType());
  869. }
  870. /**
  871. * Run test getStatusHistories method
  872. *
  873. * @return void
  874. */
  875. public function testGetStatusHistories()
  876. {
  877. $itemMock = $this->getMockForAbstractClass(
  878. \Magento\Sales\Api\Data\OrderStatusHistoryInterface::class,
  879. [],
  880. '',
  881. false,
  882. true,
  883. true,
  884. ['setOrder']
  885. );
  886. $dbMock = $this->getMockBuilder(\Magento\Framework\Data\Collection\AbstractDb::class)
  887. ->setMethods(['setOrder'])
  888. ->disableOriginalConstructor()
  889. ->getMockForAbstractClass();
  890. $collectionMock = $this->createPartialMock(
  891. \Magento\Sales\Model\ResourceModel\Order\Status\History\Collection::class,
  892. [
  893. 'setOrderFilter',
  894. 'setOrder',
  895. 'getItems',
  896. 'getIterator',
  897. 'toOptionArray',
  898. 'count',
  899. 'load'
  900. ]
  901. );
  902. $collectionItems = [$itemMock];
  903. $collectionMock->expects($this->once())
  904. ->method('setOrderFilter')
  905. ->with($this->order)
  906. ->willReturnSelf();
  907. $collectionMock->expects($this->once())
  908. ->method('setOrder')
  909. ->with('created_at', 'desc')
  910. ->willReturn($dbMock);
  911. $dbMock->expects($this->once())
  912. ->method('setOrder')
  913. ->with('entity_id', 'desc')
  914. ->willReturn($collectionMock);
  915. $collectionMock->expects($this->once())
  916. ->method('getItems')
  917. ->willReturn($collectionItems);
  918. $this->historyCollectionFactoryMock->expects($this->once())
  919. ->method('create')
  920. ->willReturn($collectionMock);
  921. for ($i = 10; --$i;) {
  922. $this->assertEquals($collectionItems, $this->order->getStatusHistories());
  923. }
  924. }
  925. public function testLoadByIncrementIdAndStoreId()
  926. {
  927. $incrementId = '000000001';
  928. $storeId = '2';
  929. $this->salesOrderCollectionFactoryMock
  930. ->expects($this->once())
  931. ->method('create')
  932. ->willReturn($this->salesOrderCollectionMock);
  933. $this->salesOrderCollectionMock->expects($this->any())->method('addFieldToFilter')->willReturnSelf();
  934. $this->salesOrderCollectionMock->expects($this->once())->method('load')->willReturnSelf();
  935. $this->salesOrderCollectionMock->expects($this->once())->method('getFirstItem')->willReturn($this->order);
  936. $this->assertSame($this->order, $this->order->loadByIncrementIdAndStoreId($incrementId, $storeId));
  937. }
  938. public function testSetPaymentWithId()
  939. {
  940. $this->order->setId(123);
  941. $payment = $this->getMockBuilder(\Magento\Sales\Model\Order\Payment::class)
  942. ->disableOriginalConstructor()
  943. ->getMock();
  944. $this->order->setData(OrderInterface::PAYMENT, $payment);
  945. $this->order->setDataChanges(false);
  946. $payment->expects($this->once())
  947. ->method('setOrder')
  948. ->with($this->order)
  949. ->willReturnSelf();
  950. $payment->expects($this->once())
  951. ->method('setParentId')
  952. ->with(123)
  953. ->willReturnSelf();
  954. $payment->expects($this->any())
  955. ->method('getId')
  956. ->willReturn(1);
  957. $this->order->setPayment($payment);
  958. $this->assertEquals(
  959. $this->order->getData(
  960. OrderInterface::PAYMENT
  961. ),
  962. $payment
  963. );
  964. $this->assertFalse(
  965. $this->order->hasDataChanges()
  966. );
  967. }
  968. public function testSetPaymentNoId()
  969. {
  970. $this->order->setId(123);
  971. $this->order->setDataChanges(false);
  972. $payment = $this->getMockBuilder(\Magento\Sales\Model\Order\Payment::class)
  973. ->disableOriginalConstructor()
  974. ->getMock();
  975. $payment->expects($this->once())
  976. ->method('setOrder')
  977. ->with($this->order)
  978. ->willReturnSelf();
  979. $payment->expects($this->once())
  980. ->method('setParentId')
  981. ->with(123)
  982. ->willReturnSelf();
  983. $payment->expects($this->any())
  984. ->method('getId')
  985. ->willReturn(null);
  986. $this->order->setPayment($payment);
  987. $this->assertEquals(
  988. $this->order->getData(
  989. OrderInterface::PAYMENT
  990. ),
  991. $payment
  992. );
  993. $this->assertTrue(
  994. $this->order->hasDataChanges()
  995. );
  996. }
  997. public function testSetPaymentNull()
  998. {
  999. $this->assertEquals(null, $this->order->setPayment(null));
  1000. $this->assertEquals(
  1001. $this->order->getData(
  1002. OrderInterface::PAYMENT
  1003. ),
  1004. null
  1005. );
  1006. $this->assertTrue(
  1007. $this->order->hasDataChanges()
  1008. );
  1009. }
  1010. public function testResetOrderWillResetPayment()
  1011. {
  1012. $payment = $this->getMockBuilder(\Magento\Sales\Model\Order\Payment::class)
  1013. ->disableOriginalConstructor()
  1014. ->getMock();
  1015. $this->order->setData(OrderInterface::PAYMENT, $payment);
  1016. $this->order->reset();
  1017. $this->assertEquals(
  1018. $this->order->getData(
  1019. OrderInterface::PAYMENT
  1020. ),
  1021. null
  1022. );
  1023. $this->assertTrue(
  1024. $this->order->hasDataChanges()
  1025. );
  1026. }
  1027. public function testGetCreatedAtFormattedUsesCorrectLocale()
  1028. {
  1029. $localeCode = 'nl_NL';
  1030. $this->localeResolver->expects($this->once())->method('getDefaultLocale')->willReturn($localeCode);
  1031. $this->timezone->expects($this->once())->method('formatDateTime')
  1032. ->with(
  1033. $this->anything(),
  1034. $this->anything(),
  1035. $this->anything(),
  1036. $localeCode
  1037. );
  1038. $this->order->getCreatedAtFormatted(\IntlDateFormatter::SHORT);
  1039. }
  1040. public function notInvoicingStatesProvider()
  1041. {
  1042. return [
  1043. [\Magento\Sales\Model\Order::STATE_COMPLETE],
  1044. [\Magento\Sales\Model\Order::STATE_CANCELED],
  1045. [\Magento\Sales\Model\Order::STATE_CLOSED]
  1046. ];
  1047. }
  1048. public function canNotCreditMemoStatesProvider()
  1049. {
  1050. return [
  1051. [\Magento\Sales\Model\Order::STATE_HOLDED],
  1052. [\Magento\Sales\Model\Order::STATE_CANCELED],
  1053. [\Magento\Sales\Model\Order::STATE_CLOSED],
  1054. [\Magento\Sales\Model\Order::STATE_PAYMENT_REVIEW]
  1055. ];
  1056. }
  1057. }