Product.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\SalesRule\Model\Rule\Condition;
  7. /**
  8. * Product rule condition data model
  9. *
  10. * @author Magento Core Team <core@magentocommerce.com>
  11. */
  12. class Product extends \Magento\Rule\Model\Condition\Product\AbstractProduct
  13. {
  14. /**
  15. * Add special attributes
  16. *
  17. * @param array $attributes
  18. * @return void
  19. */
  20. protected function _addSpecialAttributes(array &$attributes)
  21. {
  22. parent::_addSpecialAttributes($attributes);
  23. $attributes['quote_item_qty'] = __('Quantity in cart');
  24. $attributes['quote_item_price'] = __('Price in cart');
  25. $attributes['quote_item_row_total'] = __('Row total in cart');
  26. $attributes['parent::category_ids'] = __('Category (Parent only)');
  27. $attributes['children::category_ids'] = __('Category (Children Only)');
  28. }
  29. /**
  30. * Retrieve attribute
  31. *
  32. * @return string
  33. */
  34. public function getAttribute(): string
  35. {
  36. $attribute = $this->getData('attribute');
  37. if (strpos($attribute, '::') !== false) {
  38. list(, $attribute) = explode('::', $attribute);
  39. }
  40. return $attribute;
  41. }
  42. /**
  43. * @inheritdoc
  44. */
  45. public function getAttributeName()
  46. {
  47. $attribute = $this->getAttribute();
  48. if ($this->getAttributeScope()) {
  49. $attribute = $this->getAttributeScope() . '::' . $attribute;
  50. }
  51. return $this->getAttributeOption($attribute);
  52. }
  53. /**
  54. * @inheritdoc
  55. */
  56. public function loadAttributeOptions()
  57. {
  58. $productAttributes = $this->_productResource->loadAllAttributes()->getAttributesByCode();
  59. $attributes = [];
  60. foreach ($productAttributes as $attribute) {
  61. /* @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */
  62. if (!$attribute->isAllowedForRuleCondition()
  63. || !$attribute->getDataUsingMethod($this->_isUsedForRuleProperty)
  64. ) {
  65. continue;
  66. }
  67. $frontLabel = $attribute->getFrontendLabel();
  68. $attributes[$attribute->getAttributeCode()] = $frontLabel;
  69. $attributes['parent::' . $attribute->getAttributeCode()] = $frontLabel . __('(Parent Only)');
  70. $attributes['children::' . $attribute->getAttributeCode()] = $frontLabel . __('(Children Only)');
  71. }
  72. $this->_addSpecialAttributes($attributes);
  73. asort($attributes);
  74. $this->setAttributeOption($attributes);
  75. return $this;
  76. }
  77. /**
  78. * @inheritdoc
  79. */
  80. public function getAttributeElementHtml()
  81. {
  82. $html = parent::getAttributeElementHtml() .
  83. $this->getAttributeScopeElement()->getHtml();
  84. return $html;
  85. }
  86. /**
  87. * Retrieve form element for scope element
  88. *
  89. * @return \Magento\Framework\Data\Form\Element\AbstractElement
  90. */
  91. private function getAttributeScopeElement(): \Magento\Framework\Data\Form\Element\AbstractElement
  92. {
  93. return $this->getForm()->addField(
  94. $this->getPrefix() . '__' . $this->getId() . '__attribute_scope',
  95. 'hidden',
  96. [
  97. 'name' => $this->elementName . '[' . $this->getPrefix() . '][' . $this->getId() . '][attribute_scope]',
  98. 'value' => $this->getAttributeScope(),
  99. 'no_span' => true,
  100. 'class' => 'hidden',
  101. 'data-form-part' => $this->getFormName(),
  102. ]
  103. );
  104. }
  105. /**
  106. * Set attribute value
  107. *
  108. * @param string $value
  109. * @return void
  110. */
  111. public function setAttribute(string $value)
  112. {
  113. if (strpos($value, '::') !== false) {
  114. list($scope, $attribute) = explode('::', $value);
  115. $this->setData('attribute_scope', $scope);
  116. $this->setData('attribute', $attribute);
  117. } else {
  118. $this->setData('attribute', $value);
  119. }
  120. }
  121. /**
  122. * @inheritdoc
  123. */
  124. public function loadArray($arr)
  125. {
  126. parent::loadArray($arr);
  127. $this->setAttributeScope($arr['attribute_scope'] ?? null);
  128. return $this;
  129. }
  130. /**
  131. * @inheritdoc
  132. */
  133. public function asArray(array $arrAttributes = [])
  134. {
  135. $out = parent::asArray($arrAttributes);
  136. $out['attribute_scope'] = $this->getAttributeScope();
  137. return $out;
  138. }
  139. /**
  140. * Validate Product Rule Condition
  141. *
  142. * @param \Magento\Framework\Model\AbstractModel $model
  143. *
  144. * @return bool
  145. * @throws \Magento\Framework\Exception\NoSuchEntityException
  146. */
  147. public function validate(\Magento\Framework\Model\AbstractModel $model)
  148. {
  149. //@todo reimplement this method when is fixed MAGETWO-5713
  150. /** @var \Magento\Catalog\Model\Product $product */
  151. $product = $model->getProduct();
  152. if (!$product instanceof \Magento\Catalog\Model\Product) {
  153. $product = $this->productRepository->getById($model->getProductId());
  154. }
  155. $product->setQuoteItemQty(
  156. $model->getQty()
  157. )->setQuoteItemPrice(
  158. $model->getPrice() // possible bug: need to use $model->getBasePrice()
  159. )->setQuoteItemRowTotal(
  160. $model->getBaseRowTotal()
  161. );
  162. $attrCode = $this->getAttribute();
  163. if ($attrCode === 'category_ids') {
  164. return $this->validateAttribute($this->_getAvailableInCategories($product->getId()));
  165. }
  166. if ($attrCode === 'quote_item_price') {
  167. $numericOperations = $this->getDefaultOperatorInputByType()['numeric'];
  168. if (in_array($this->getOperator(), $numericOperations)) {
  169. $this->setData('value', $this->getFormattedPrice($this->getValue()));
  170. }
  171. }
  172. return parent::validate($product);
  173. }
  174. /**
  175. * Retrieve value element chooser URL
  176. *
  177. * @return string
  178. */
  179. public function getValueElementChooserUrl()
  180. {
  181. $url = false;
  182. switch ($this->getAttribute()) {
  183. case 'sku':
  184. case 'category_ids':
  185. $url = 'sales_rule/promo_widget/chooser/attribute/' . $this->getAttribute();
  186. if ($this->getJsFormObject()) {
  187. $url .= '/form/' . $this->getJsFormObject();
  188. }
  189. break;
  190. default:
  191. break;
  192. }
  193. return $url !== false ? $this->_backendData->getUrl($url) : '';
  194. }
  195. /**
  196. * Get locale-based formatted price.
  197. *
  198. * @param string $value
  199. * @return float|null
  200. */
  201. private function getFormattedPrice($value)
  202. {
  203. $value = preg_replace('/[^0-9^\^.,-]/m', '', $value);
  204. /**
  205. * If the comma is the third symbol in the number, we consider it to be a decimal separator
  206. */
  207. $separatorComa = strpos($value, ',');
  208. $separatorDot = strpos($value, '.');
  209. if ($separatorComa !== false && $separatorDot === false && preg_match('/,\d{3}$/m', $value) === 1) {
  210. $value .= '.00';
  211. }
  212. return $this->_localeFormat->getNumber($value);
  213. }
  214. }