Grid.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Sales\Block\Adminhtml\Order\Create\Items;
  7. use Magento\Catalog\Model\Product\Attribute\Source\Status as ProductStatus;
  8. use Magento\CatalogInventory\Api\StockRegistryInterface;
  9. use Magento\CatalogInventory\Api\StockStateInterface;
  10. use Magento\Framework\Pricing\PriceCurrencyInterface;
  11. use Magento\Framework\Session\SessionManagerInterface;
  12. use Magento\Quote\Model\Quote\Item;
  13. /**
  14. * Adminhtml sales order create items grid block
  15. * @api
  16. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  17. * @since 100.0.2
  18. */
  19. class Grid extends \Magento\Sales\Block\Adminhtml\Order\Create\AbstractCreate
  20. {
  21. /**
  22. * Flag to check can items be move to customer storage
  23. *
  24. * @var bool
  25. */
  26. protected $_moveToCustomerStorage = true;
  27. /**
  28. * Tax data
  29. *
  30. * @var \Magento\Tax\Helper\Data
  31. */
  32. protected $_taxData;
  33. /**
  34. * Wishlist factory
  35. *
  36. * @var \Magento\Wishlist\Model\WishlistFactory
  37. */
  38. protected $_wishlistFactory;
  39. /**
  40. * Gift message save
  41. *
  42. * @var \Magento\GiftMessage\Model\Save
  43. */
  44. protected $_giftMessageSave;
  45. /**
  46. * Tax config
  47. *
  48. * @var \Magento\Tax\Model\Config
  49. */
  50. protected $_taxConfig;
  51. /**
  52. * Message helper
  53. *
  54. * @var \Magento\GiftMessage\Helper\Message
  55. */
  56. protected $_messageHelper;
  57. /**
  58. * @var StockRegistryInterface
  59. */
  60. protected $stockRegistry;
  61. /**
  62. * @var StockStateInterface
  63. */
  64. protected $stockState;
  65. /**
  66. * @param \Magento\Backend\Block\Template\Context $context
  67. * @param \Magento\Backend\Model\Session\Quote $sessionQuote
  68. * @param \Magento\Sales\Model\AdminOrder\Create $orderCreate
  69. * @param PriceCurrencyInterface $priceCurrency
  70. * @param \Magento\Wishlist\Model\WishlistFactory $wishlistFactory
  71. * @param \Magento\GiftMessage\Model\Save $giftMessageSave
  72. * @param \Magento\Tax\Model\Config $taxConfig
  73. * @param \Magento\Tax\Helper\Data $taxData
  74. * @param \Magento\GiftMessage\Helper\Message $messageHelper
  75. * @param StockRegistryInterface $stockRegistry
  76. * @param StockStateInterface $stockState
  77. * @param array $data
  78. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  79. */
  80. public function __construct(
  81. \Magento\Backend\Block\Template\Context $context,
  82. \Magento\Backend\Model\Session\Quote $sessionQuote,
  83. \Magento\Sales\Model\AdminOrder\Create $orderCreate,
  84. PriceCurrencyInterface $priceCurrency,
  85. \Magento\Wishlist\Model\WishlistFactory $wishlistFactory,
  86. \Magento\GiftMessage\Model\Save $giftMessageSave,
  87. \Magento\Tax\Model\Config $taxConfig,
  88. \Magento\Tax\Helper\Data $taxData,
  89. \Magento\GiftMessage\Helper\Message $messageHelper,
  90. StockRegistryInterface $stockRegistry,
  91. StockStateInterface $stockState,
  92. array $data = []
  93. ) {
  94. $this->_messageHelper = $messageHelper;
  95. $this->_wishlistFactory = $wishlistFactory;
  96. $this->_giftMessageSave = $giftMessageSave;
  97. $this->_taxConfig = $taxConfig;
  98. $this->_taxData = $taxData;
  99. $this->stockRegistry = $stockRegistry;
  100. $this->stockState = $stockState;
  101. parent::__construct($context, $sessionQuote, $orderCreate, $priceCurrency, $data);
  102. }
  103. /**
  104. * Constructor
  105. *
  106. * @return void
  107. */
  108. protected function _construct()
  109. {
  110. parent::_construct();
  111. $this->setId('sales_order_create_search_grid');
  112. }
  113. /**
  114. * Get items
  115. *
  116. * @return Item[]
  117. */
  118. public function getItems()
  119. {
  120. $items = $this->getParentBlock()->getItems();
  121. $oldSuperMode = $this->getQuote()->getIsSuperMode();
  122. $this->getQuote()->setIsSuperMode(false);
  123. foreach ($items as $item) {
  124. // To dispatch inventory event sales_quote_item_qty_set_after, set item qty
  125. $item->setQty($item->getQty());
  126. if (!$item->getMessage()) {
  127. //Getting product ids for stock item last quantity validation before grid display
  128. $stockItemToCheck = [];
  129. $childItems = $item->getChildren();
  130. if (count($childItems)) {
  131. foreach ($childItems as $childItem) {
  132. $stockItemToCheck[] = $childItem->getProduct()->getId();
  133. }
  134. } else {
  135. $stockItemToCheck[] = $item->getProduct()->getId();
  136. }
  137. foreach ($stockItemToCheck as $productId) {
  138. $check = $this->stockState->checkQuoteItemQty(
  139. $productId,
  140. $item->getQty(),
  141. $item->getQty(),
  142. $item->getQty(),
  143. $this->getQuote()->getStore()->getWebsiteId()
  144. );
  145. $item->setMessage($check->getMessage());
  146. $item->setHasError($check->getHasError());
  147. }
  148. }
  149. if ($item->getProduct()->getStatus() == ProductStatus::STATUS_DISABLED) {
  150. $item->setMessage(__('This product is disabled.'));
  151. $item->setHasError(true);
  152. }
  153. }
  154. $this->getQuote()->setIsSuperMode($oldSuperMode);
  155. return $items;
  156. }
  157. /**
  158. * Get session
  159. *
  160. * @return SessionManagerInterface
  161. */
  162. public function getSession()
  163. {
  164. return $this->getParentBlock()->getSession();
  165. }
  166. /**
  167. * Get item editable price
  168. *
  169. * @param Item $item
  170. * @return float
  171. */
  172. public function getItemEditablePrice($item)
  173. {
  174. return $item->getCalculationPrice() * 1;
  175. }
  176. /**
  177. * Get original editable price
  178. *
  179. * @param Item $item
  180. * @return float
  181. */
  182. public function getOriginalEditablePrice($item)
  183. {
  184. if ($item->hasOriginalCustomPrice()) {
  185. $result = $item->getOriginalCustomPrice() * 1;
  186. } elseif ($item->hasCustomPrice()) {
  187. $result = $item->getCustomPrice() * 1;
  188. } else {
  189. if ($this->_taxData->priceIncludesTax($this->getStore())) {
  190. $result = $item->getPriceInclTax() * 1;
  191. } else {
  192. $result = $item->getOriginalPrice() * 1;
  193. }
  194. }
  195. return $result;
  196. }
  197. /**
  198. * Get item original price
  199. *
  200. * @param Item $item
  201. * @return float
  202. */
  203. public function getItemOrigPrice($item)
  204. {
  205. return $this->convertPrice($item->getPrice());
  206. }
  207. /**
  208. * Check gift messages availability
  209. *
  210. * @param Item|null $item
  211. * @return bool|null|string
  212. */
  213. public function isGiftMessagesAvailable($item = null)
  214. {
  215. if ($item === null) {
  216. return $this->_messageHelper->isMessagesAllowed('items', $this->getQuote(), $this->getStore());
  217. }
  218. return $this->_messageHelper->isMessagesAllowed('item', $item, $this->getStore());
  219. }
  220. /**
  221. * Check if allowed for gift message
  222. *
  223. * @param Item $item
  224. * @return bool
  225. */
  226. public function isAllowedForGiftMessage($item)
  227. {
  228. return $this->_giftMessageSave->getIsAllowedQuoteItem($item);
  229. }
  230. /**
  231. * Check if we need display grid totals include tax
  232. *
  233. * @return bool
  234. */
  235. public function displayTotalsIncludeTax()
  236. {
  237. $result = $this->_taxConfig->displayCartSubtotalInclTax($this->getStore())
  238. || $this->_taxConfig->displayCartSubtotalBoth($this->getStore());
  239. return $result;
  240. }
  241. /**
  242. * Get subtotal
  243. *
  244. * @return false|float
  245. */
  246. public function getSubtotal()
  247. {
  248. $address = $this->getQuoteAddress();
  249. if (!$this->displayTotalsIncludeTax()) {
  250. return $address->getSubtotal();
  251. }
  252. if ($address->getSubtotalInclTax()) {
  253. return $address->getSubtotalInclTax();
  254. }
  255. return $address->getSubtotal() + $address->getTaxAmount();
  256. }
  257. /**
  258. * Get subtotal with discount
  259. *
  260. * @return float
  261. */
  262. public function getSubtotalWithDiscount()
  263. {
  264. $address = $this->getQuoteAddress();
  265. if ($this->displayTotalsIncludeTax()) {
  266. return $address->getSubtotal()
  267. + $address->getTaxAmount()
  268. + $address->getDiscountAmount()
  269. + $address->getDiscountTaxCompensationAmount();
  270. } else {
  271. return $address->getSubtotal() + $address->getDiscountAmount();
  272. }
  273. }
  274. /**
  275. * Get discount amount
  276. *
  277. * @return float
  278. */
  279. public function getDiscountAmount()
  280. {
  281. return $this->getQuote()->getShippingAddress()->getDiscountAmount();
  282. }
  283. /**
  284. * Retrieve quote address
  285. *
  286. * @return \Magento\Quote\Model\Quote\Address
  287. */
  288. public function getQuoteAddress()
  289. {
  290. if ($this->getQuote()->isVirtual()) {
  291. return $this->getQuote()->getBillingAddress();
  292. } else {
  293. return $this->getQuote()->getShippingAddress();
  294. }
  295. }
  296. /**
  297. * Define if specified item has already applied custom price
  298. *
  299. * @param Item $item
  300. * @return bool
  301. */
  302. public function usedCustomPriceForItem($item)
  303. {
  304. return $item->hasCustomPrice();
  305. }
  306. /**
  307. * Define if custom price can be applied for specified item
  308. *
  309. * @param Item $item
  310. * @return bool
  311. */
  312. public function canApplyCustomPrice($item)
  313. {
  314. return !$item->isChildrenCalculated();
  315. }
  316. /**
  317. * Get qty title
  318. *
  319. * @param Item $item
  320. * @return \Magento\Framework\Phrase|string
  321. */
  322. public function getQtyTitle($item)
  323. {
  324. $prices = $item->getProduct()
  325. ->getPriceInfo()
  326. ->getPrice(\Magento\Catalog\Pricing\Price\TierPrice::PRICE_CODE)
  327. ->getTierPriceList();
  328. if ($prices) {
  329. $info = [];
  330. foreach ($prices as $data) {
  331. $price = $this->convertPrice($data['price']);
  332. $info[] = __('Buy %1 for price %2', $data['price_qty'], $price);
  333. }
  334. return implode(', ', $info);
  335. } else {
  336. return __('Item ordered qty');
  337. }
  338. }
  339. /**
  340. * Get tier price html
  341. *
  342. * @param Item $item
  343. * @return string
  344. */
  345. public function getTierHtml($item)
  346. {
  347. $html = '';
  348. $prices = $item->getProduct()->getTierPrice();
  349. if ($prices) {
  350. if ($item->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) {
  351. $info = $this->_getBundleTierPriceInfo($prices);
  352. } else {
  353. $info = $this->_getTierPriceInfo($prices);
  354. }
  355. $html = implode('<br />', $info);
  356. }
  357. return $html;
  358. }
  359. /**
  360. * Get tier price info to display in grid for Bundle product
  361. *
  362. * @param array $prices
  363. * @return string[]
  364. */
  365. protected function _getBundleTierPriceInfo($prices)
  366. {
  367. $info = [];
  368. foreach ($prices as $data) {
  369. $qty = $data['price_qty'] * 1;
  370. $info[] = __('%1 with %2 discount each', $qty, $data['price'] * 1 . '%');
  371. }
  372. return $info;
  373. }
  374. /**
  375. * Get tier price info to display in grid
  376. *
  377. * @param array $prices
  378. * @return string[]
  379. */
  380. protected function _getTierPriceInfo($prices)
  381. {
  382. $info = [];
  383. foreach ($prices as $data) {
  384. $qty = $data['price_qty'] * 1;
  385. $price = $this->convertPrice($data['price']);
  386. $info[] = __('%1 for %2', $qty, $price);
  387. }
  388. return $info;
  389. }
  390. /**
  391. * Get Custom Options of item
  392. *
  393. * @param Item $item
  394. * @return string
  395. *
  396. * @deprecated 101.0.0
  397. */
  398. public function getCustomOptions(Item $item)
  399. {
  400. $optionStr = '';
  401. $this->_moveToCustomerStorage = true;
  402. if ($optionIds = $item->getOptionByCode('option_ids')) {
  403. foreach (explode(',', $optionIds->getValue()) as $optionId) {
  404. $option = $item->getProduct()->getOptionById($optionId);
  405. if ($option) {
  406. $optionStr .= $option->getTitle() . ':';
  407. $quoteItemOption = $item->getOptionByCode('option_' . $option->getId());
  408. $group = $option->groupFactory($option->getType())
  409. ->setOption($option)
  410. ->setQuoteItemOption($quoteItemOption);
  411. $optionStr .= $group->getEditableOptionValue($quoteItemOption->getValue());
  412. $optionStr .= "\n";
  413. }
  414. }
  415. }
  416. return $optionStr;
  417. }
  418. /**
  419. * Get flag for rights to move items to customer storage
  420. *
  421. * @return bool
  422. * @SuppressWarnings(PHPMD.BooleanGetMethodName)
  423. */
  424. public function getMoveToCustomerStorage()
  425. {
  426. return $this->_moveToCustomerStorage;
  427. }
  428. /**
  429. * Display subtotal including tax
  430. *
  431. * @param Item $item
  432. * @return string
  433. */
  434. public function displaySubtotalInclTax($item)
  435. {
  436. if ($item->getTaxBeforeDiscount()) {
  437. $tax = $item->getTaxBeforeDiscount();
  438. } else {
  439. $tax = $item->getTaxAmount() ? $item->getTaxAmount() : 0;
  440. }
  441. return $this->formatPrice($item->getRowTotal() + $tax);
  442. }
  443. /**
  444. * Display original price including tax
  445. *
  446. * @param Item $item
  447. * @return float
  448. */
  449. public function displayOriginalPriceInclTax($item)
  450. {
  451. $tax = 0;
  452. if ($item->getTaxPercent()) {
  453. $tax = $item->getPrice() * ($item->getTaxPercent() / 100);
  454. }
  455. return $this->convertPrice($item->getPrice() + $tax / $item->getQty());
  456. }
  457. /**
  458. * Display row total with discount including tax
  459. *
  460. * @param Item $item
  461. * @return string
  462. */
  463. public function displayRowTotalWithDiscountInclTax($item)
  464. {
  465. $tax = $item->getTaxAmount() ? $item->getTaxAmount() : 0;
  466. return $this->formatPrice($item->getRowTotal() - $item->getDiscountAmount() + $tax);
  467. }
  468. /**
  469. * Get including/excluding tax message
  470. *
  471. * @return \Magento\Framework\Phrase
  472. */
  473. public function getInclExclTaxMessage()
  474. {
  475. if ($this->_taxData->priceIncludesTax($this->getStore())) {
  476. return __('* - Enter custom price including tax');
  477. } else {
  478. return __('* - Enter custom price excluding tax');
  479. }
  480. }
  481. /**
  482. * Get store
  483. *
  484. * @return \Magento\Store\Model\Store
  485. */
  486. public function getStore()
  487. {
  488. return $this->getQuote()->getStore();
  489. }
  490. /**
  491. * Return html button which calls configure window
  492. *
  493. * @param Item $item
  494. * @return string
  495. */
  496. public function getConfigureButtonHtml($item)
  497. {
  498. $product = $item->getProduct();
  499. $options = ['label' => __('Configure')];
  500. if ($product->canConfigure()) {
  501. $options['onclick'] = sprintf('order.showQuoteItemConfiguration(%s)', $item->getId());
  502. } else {
  503. $options['class'] = ' disabled';
  504. $options['title'] = __('This product does not have any configurable options');
  505. }
  506. return $this->getLayout()->createBlock(
  507. \Magento\Backend\Block\Widget\Button::class
  508. )->setData($options)->toHtml();
  509. }
  510. /**
  511. * Get order item extra info block
  512. *
  513. * @param Item $item
  514. * @return \Magento\Framework\View\Element\AbstractBlock
  515. */
  516. public function getItemExtraInfo($item)
  517. {
  518. return $this->getLayout()->getBlock('order_item_extra_info')->setItem($item);
  519. }
  520. /**
  521. * Returns whether moving to wishlist is allowed for this item
  522. *
  523. * @param Item $item
  524. * @return bool
  525. */
  526. public function isMoveToWishlistAllowed($item)
  527. {
  528. return $item->getProduct()->isVisibleInSiteVisibility();
  529. }
  530. /**
  531. * Retrieve collection of customer wishlists
  532. *
  533. * @return \Magento\Wishlist\Model\ResourceModel\Wishlist\Collection
  534. */
  535. public function getCustomerWishlists()
  536. {
  537. return $this->_wishlistFactory->create()->getCollection()->filterByCustomerId($this->getCustomerId());
  538. }
  539. /**
  540. * Get the item unit price html
  541. *
  542. * @param Item $item
  543. * @return string
  544. */
  545. public function getItemUnitPriceHtml(Item $item)
  546. {
  547. $block = $this->getLayout()->getBlock('item_unit_price');
  548. $block->setItem($item);
  549. return $block->toHtml();
  550. }
  551. /**
  552. * Get the item row total html
  553. *
  554. * @param Item $item
  555. * @return string
  556. */
  557. public function getItemRowTotalHtml(Item $item)
  558. {
  559. $block = $this->getLayout()->getBlock('item_row_total');
  560. $block->setItem($item);
  561. return $block->toHtml();
  562. }
  563. /**
  564. * Return html for row total with discount
  565. *
  566. * @param Item $item
  567. * @return string
  568. */
  569. public function getItemRowTotalWithDiscountHtml(Item $item)
  570. {
  571. $block = $this->getLayout()->getBlock('item_row_total_with_discount');
  572. $block->setItem($item);
  573. return $block->toHtml();
  574. }
  575. }