From 68a41b49d405dd30852533ba930b4c833cca857a Mon Sep 17 00:00:00 2001 From: Aleksa Zivkovic Date: Wed, 25 Sep 2019 11:57:44 +0200 Subject: [PATCH 1/2] BF-200 remove block classes, switch to view models --- Block/Checkout/Minicart.php | 63 ++-- Block/Checkout/Overview.php | 202 ----------- Block/Js.php | 74 +--- Helper/Data.php | 4 +- ViewModel/Cart/CartView.php | 185 ++++++++++ ViewModel/Product/Options.php | 38 ++ .../Product/Type}/Bundle.php | 177 +++------ {Block => ViewModel}/Product/View.php | 211 ++++------- view/frontend/layout/catalog_product_view.xml | 13 +- .../catalog_product_view_type_bundle.xml | 20 +- ...catalog_product_view_type_configurable.xml | 6 +- .../catalog_product_view_type_grouped.xml | 11 +- view/frontend/layout/checkout_cart_index.xml | 6 +- .../templates/breadcheckout/bundle.phtml | 339 +++++++++++++++++- .../templates/breadcheckout/cartview.phtml | 53 +-- .../breadcheckout/configurable.phtml | 14 +- .../templates/breadcheckout/grouped.phtml | 51 +-- .../templates/breadcheckout/minicart.phtml | 42 +-- .../templates/breadcheckout/options.phtml | 19 +- .../templates/breadcheckout/view.phtml | 81 +++-- 20 files changed, 903 insertions(+), 706 deletions(-) delete mode 100644 Block/Checkout/Overview.php create mode 100644 ViewModel/Cart/CartView.php create mode 100644 ViewModel/Product/Options.php rename {Block/Product => ViewModel/Product/Type}/Bundle.php (72%) rename {Block => ViewModel}/Product/View.php (57%) diff --git a/Block/Checkout/Minicart.php b/Block/Checkout/Minicart.php index c1254d6e..167618e3 100644 --- a/Block/Checkout/Minicart.php +++ b/Block/Checkout/Minicart.php @@ -5,11 +5,13 @@ use Magento\Catalog\Block\ShortcutInterface; use Magento\Checkout\Model\Session; use Magento\Framework\Locale\ResolverInterface; +use Magento\Framework\View\Element\Template; use Magento\Framework\View\Element\Template\Context; use Magento\Payment\Model\MethodInterface; use Bread\BreadCheckout\Helper\Data; +use Magento\Framework\Serialize\Serializer\Json; -class Minicart extends Overview implements ShortcutInterface +class Minicart extends Template implements ShortcutInterface { const ALIAS_ELEMENT_INDEX = 'alias'; @@ -28,13 +30,19 @@ class Minicart extends Overview implements ShortcutInterface /** * @var Data */ - private $helperData; + public $helperData; /** * @var \Bread\BreadCheckout\Helper\Quote */ public $quoteHelper; + public $catalogHelper; + + public $customerHelper; + + public $serializer; + /** * Minicart constructor. * @@ -50,45 +58,25 @@ public function __construct( \Magento\Framework\Json\Helper\Data $jsonHelper, \Bread\BreadCheckout\Helper\Catalog $catalogHelper, \Bread\BreadCheckout\Helper\Customer $customerHelper, - \Bread\BreadCheckout\Helper\Data $dataHelper, - \Magento\ConfigurableProduct\Model\Product\Type\ConfigurableFactory $configurableProductFactory, - \Magento\ConfigurableProduct\Block\Product\View\Type\ConfigurableFactory $configurableBlockFactory, + \Bread\BreadCheckout\Helper\Data $helperData, \Bread\BreadCheckout\Helper\Quote $quoteHelper, - \Magento\Framework\Stdlib\ArrayUtils $arrayUtils, - \Magento\Framework\Json\EncoderInterface $jsonEncoder, - \Magento\ConfigurableProduct\Helper\Data $configurableHelper, - \Magento\Catalog\Helper\Product $catalogProductHelper, - \Magento\Customer\Helper\Session\CurrentCustomer $currentCustomer, - \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency, - \Magento\ConfigurableProduct\Model\ConfigurableAttributeData $configurableAttributeData, Session $checkoutSession, MethodInterface $payment, - Data $helperData, + Json $serializer, array $data = [] ) { - parent::__construct( - $context, - $jsonHelper, - $catalogHelper, - $customerHelper, - $dataHelper, - $configurableProductFactory, - $configurableBlockFactory, - $quoteHelper, - $arrayUtils, - $jsonEncoder, - $configurableHelper, - $catalogProductHelper, - $currentCustomer, - $priceCurrency, - $configurableAttributeData, - $data - ); - $this->checkoutSession = $checkoutSession; $this->payment = $payment; $this->helperData = $helperData; $this->quoteHelper = $quoteHelper; + $this->catalogHelper = $catalogHelper; + $this->customerHelper = $customerHelper; + $this->serializer = $serializer; + + parent::__construct( + $context, + $data + ); } /** @@ -141,4 +129,15 @@ private function isCartView() { return in_array('checkout_cart_index', $this->getLayout()->getUpdate()->getHandles()); } + + /** + * Get Extra Button Design CSS + * + * @return mixed + */ + public function getButtonDesign() + { + $design = $this->escapeCss($this->catalogHelper->getCartButtonDesign()); + return $design ? $design : $this->catalogHelper->getPDPButtonDesign(); + } } diff --git a/Block/Checkout/Overview.php b/Block/Checkout/Overview.php deleted file mode 100644 index bf3708fd..00000000 --- a/Block/Checkout/Overview.php +++ /dev/null @@ -1,202 +0,0 @@ -quoteHelper = $quoteHelper; - $this->customerHelper = $customerHelper; - $this->jsonHelper = $jsonHelper; - - parent::__construct( - $context, - $jsonHelper, - $catalogHelper, - $customerHelper, - $dataHelper, - $configurableProductFactory, - $configurableBlockFactory, - $arrayUtils, - $jsonEncoder, - $configurableHelper, - $catalogProductHelper, - $currentCustomer, - $priceCurrency, - $configurableAttributeData, - $quoteHelper, - $data - ); - } - - /** - * Set Block Extra In Construct Flow - */ - protected function _construct($bypass = false) - { - parent::_construct(true); - if (!$bypass) { - $this->setAdditionalData([]); - } - } - - /** - * Get Product Data From Quote Items - * - * @return string - */ - public function getProductDataJson() - { - $itemsData = $this->quoteHelper->getCartOverviewItemsData(); - return $this->jsonEncode($itemsData); - } - - /** - * Get Targeted Financing Status From Quote Items - * - * @return string - */ - public function getTargetedFinancingStatusJson() - { - $status = $this->quoteHelper->getTargetedFinancingStatus(); - return $this->jsonEncode($status); - } - - /** - * Checks Settings For Show On Checkout Overview Page During Output - * - * @return string - */ - protected function _toHtml() - { - - $aboveThreshold = $this->quoteHelper->aboveThreshold($this->quoteHelper->getSessionQuote()->getGrandTotal()); - $isDisabledSkus = !$this->quoteHelper->checkDisabledForSku(); - - if ($this->quoteHelper->isEnabledOnCOP() && $aboveThreshold && $isDisabledSkus) { - return parent::_toHtml(); - } - - return ''; - } - - /** - * Return Block View Product Code - * - * @return string - */ - public function getBlockCode() - { - return (string) $this->quoteHelper->getBlockCodeCheckoutOverview(); - } - - /** - * Check if checkout through Bread interaction is allowed - * - * @return mixed - */ - public function getAllowCheckout() - { - return ($this->quoteHelper->getAllowCheckoutCP()) ? 'true' : 'false'; - } - - /** - * Get Extra Button Design CSS - * - * @return mixed - */ - public function getButtonDesign() - { - $design = $this->dataHelper->escapeCustomCSS($this->catalogHelper->getCartButtonDesign()); - return $design ? $design : parent::getButtonDesign(); - } - - /** - * Validate allowed products wrapper for block class - * - * @return bool - */ - public function validateAllowedProductTypes() - { - return $this->quoteHelper->validateAllowedProductTypes(); - } - - /** - * Custom product type error message - * - * @return string - */ - public function productTypeErrorMessage() - { - return $this->_escaper->escapeHtml($this->catalogHelper->getProductTypeMessage()); - } - - /** - * Check financing by sku - * - * @return bool - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ - public function isFinancingBySku() - { - return $this->quoteHelper->isFinancingBySku(); - } -} diff --git a/Block/Js.php b/Block/Js.php index 3172cc44..f51db931 100644 --- a/Block/Js.php +++ b/Block/Js.php @@ -31,7 +31,7 @@ class Js extends \Magento\Framework\View\Element\Text protected $curl; /** - * @var \Psr\Log\LoggerInterface + * @var \Bread\BreadCheckout\Helper\Log */ public $logger; @@ -63,7 +63,7 @@ public function __construct( */ protected function _toHtml() { - if ($this->isActive()) { + if ($this->helper->isActive()) { return $this->getJsScriptsString(); } @@ -96,65 +96,25 @@ protected function getJsScriptsString() $dsn = $this->getSentryDSN(); // Don't enable Sentry if dsn can't be retrieved - $isSentryEnabled = $this->isSentryEnabled() && $dsn; + $isSentryEnabled = $this->helper->isSentryEnabled() && $dsn; $sentryConfigScript = sprintf( $sentryConfigScript, $dsn, $this->getModuleVersion(), - $this->getPublicApiKey(), + $this->helper->getApiPublicKey(), $isSentryEnabled ); $breadJsScript = sprintf( '', - $this->getJsLibLocation(), - $this->getPublicApiKey() + $this->helper->getJsLibLocation(), + $this->helper->getApiPublicKey() ); return $moduleVersionComment . $sentryConfigScript . $breadJsScript; } - /** - * Check if extension is active - * - * @return bool - */ - protected function isActive() - { - return (bool) $this->helper->isActive(); - } - - /** - * Get API Key - * - * @return mixed - */ - protected function getPublicApiKey() - { - return $this->helper->getApiPublicKey(); - } - - /** - * Get JS URI - * - * @return mixed - */ - protected function getJsLibLocation() - { - return $this->helper->getJsLibLocation(); - } - - /** - * Get Sentry Enabled - * - * @return boolean - */ - protected function isSentryEnabled() - { - return $this->helper->isSentryEnabled(); - } - /** * Get current module version * @@ -181,7 +141,7 @@ private function getSentryDSN() } try { - $this->curl->setCredentials($this->getUsername(), $this->getPassword()); + $this->curl->setCredentials($this->helper->getApiPublicKey(), $this->helper->getApiSecretKey()); $this->curl->get($this->helper::URL_LAMBDA_SENTRY_DSN); $response = json_decode($this->curl->getBody(), true); @@ -202,24 +162,4 @@ private function getSentryDSN() return null; } } - - /** - * Get public api key to use as username for dsn request - * - * @return string - */ - private function getUsername() - { - return $this->helper->getApiPublicKey(); - } - - /** - * Get private api key to use as password for dsn request - * - * @return string - */ - private function getPassword() - { - return $this->helper->getApiSecretKey(); - } } diff --git a/Helper/Data.php b/Helper/Data.php index 5bb5045a..209ba283 100644 --- a/Helper/Data.php +++ b/Helper/Data.php @@ -180,7 +180,7 @@ public function allowedProductType($typeId) */ public function getProductTypeMessage($store = \Magento\Store\Model\ScopeInterface::SCOPE_STORE) { - return $this->scopeConfig->getValue(self::XML_CONFIG_PRODUCT_TYPE_MSG, $store); + return utf8_encode($this->scopeConfig->getValue(self::XML_CONFIG_PRODUCT_TYPE_MSG, $store)); } /** @@ -683,7 +683,7 @@ public function getButtonDesign($store = \Magento\Store\Model\ScopeInterface::SC */ public function getCartButtonDesign($store = \Magento\Store\Model\ScopeInterface::SCOPE_STORE) { - return $this->scopeConfig->getValue(self::XML_CONFIG_CP_BUTTON_DESIGN, $store); + return utf8_encode($this->scopeConfig->getValue(self::XML_CONFIG_CP_BUTTON_DESIGN, $store)); } /** diff --git a/ViewModel/Cart/CartView.php b/ViewModel/Cart/CartView.php new file mode 100644 index 00000000..7a766eeb --- /dev/null +++ b/ViewModel/Cart/CartView.php @@ -0,0 +1,185 @@ +serializer = $serializer; + $this->catalogHelper = $catalogHelper; + $this->customerHelper = $customerHelper; + $this->dataHelper = $dataHelper; + $this->quoteHelper = $quoteHelper; + } + + /** + * Get Product Data From Quote Items + * + * @return string + */ + public function getProductDataJson() + { + $itemsData = $this->quoteHelper->getCartOverviewItemsData(); + return $this->serializer->serialize($itemsData); + } + + /** + * Get targeted financing status from quote items + * + * @return bool|false|string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function getTargetedFinancingStatusJson() + { + $status = $this->quoteHelper->getTargetedFinancingStatus(); + return $this->serializer->serialize($status); + } + + /** + * Checks Settings For Show On Checkout Overview Page During Output + * + * @return string + */ + public function isAllowedRender($quote) + { + $isAllowed = false; + + $aboveThreshold = $this->quoteHelper->aboveThreshold($this->quoteHelper->getSessionQuote()->getGrandTotal()); + $isDisabledSkus = !$this->quoteHelper->checkDisabledForSku(); + + if ($this->quoteHelper->isEnabledOnCOP() && $aboveThreshold && $isDisabledSkus) { + $isAllowed = true; + } + + return $isAllowed; + } + + /** + * Return Block View Product Code + * + * @return string + */ + public function getBlockCode() + { + return (string) $this->quoteHelper->getBlockCodeCheckoutOverview(); + } + + /** + * Check if checkout through Bread interaction is allowed + * + * @return mixed + */ + public function getAllowCheckout() + { + return ($this->quoteHelper->getAllowCheckoutCP()) ? 'true' : 'false'; + } + + /** + * Get Extra Button Design CSS + * + * @return mixed + */ + public function getButtonDesign() + { + $design = $this->dataHelper->escapeCustomCSS($this->catalogHelper->getCartButtonDesign()); + return $design ? $design : $this->catalogHelper->getPDPButtonDesign(); + } + + /** + * Validate allowed products wrapper for block class + * + * @return bool + */ + public function validateAllowedProductTypes() + { + return $this->quoteHelper->validateAllowedProductTypes(); + } + + /** + * Custom product type error message + * + * @return string + */ + public function productTypeErrorMessage() + { + return $this->catalogHelper->getProductTypeMessage(); + } + + /** + * Check financing by sku + * + * @return bool + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function isFinancingBySku() + { + return $this->quoteHelper->isFinancingBySku(); + } + + /** + * Get Default Button Size String For The View + * + * @return string + */ + public function getIsDefaultSize() + { + return (string) $this->catalogHelper->getDefaultButtonSizeHtml(); + } + + /** + * Get Validate Order URL + * + * @return string + */ + public function getValidateOrderUrl() + { + return $this->catalogHelper->getValidateOrderURL(); + } +} diff --git a/ViewModel/Product/Options.php b/ViewModel/Product/Options.php new file mode 100644 index 00000000..63b68c3d --- /dev/null +++ b/ViewModel/Product/Options.php @@ -0,0 +1,38 @@ +getValues()) { + foreach ($option->getValues() as $k => $v) { + $optionsData[$option->getId()][$k] = [ + 'sku' => $v->getSku(), + 'price' => (int)($v->getPrice() * 100) + ]; + } + } else { + $optionsData[$option->getId()] = [ + 'sku' => $option->getSku(), + 'price' => (int)($option->getPrice() * 100) + ]; + } + } + + return $this->serializer->serialize($optionsData); + } +} \ No newline at end of file diff --git a/Block/Product/Bundle.php b/ViewModel/Product/Type/Bundle.php similarity index 72% rename from Block/Product/Bundle.php rename to ViewModel/Product/Type/Bundle.php index 51433ca9..beac17b5 100644 --- a/Block/Product/Bundle.php +++ b/ViewModel/Product/Type/Bundle.php @@ -1,14 +1,12 @@ registry = $context->getRegistry(); - $this->jsonHelper = $jsonHelper; + $this->serializer = $serializer; $this->catalogHelper = $catalogHelper; $this->customerHelper = $customerHelper; $this->dataHelper = $dataHelper; $this->catalogProduct = $catalogProduct; $this->quoteHelper = $quoteHelper; - parent::__construct( - $context, - $arrayUtils, - $catalogProduct, - $productPrice, - $jsonEncoder, - $localeFormat, - $data - ); + parent::__construct($data); } - public function toHtml() + public function isAllowedRender($product) { + $isAllowed = false; + $aboveThreshold = $this->dataHelper->aboveThreshold( - $this->getProduct()->getPriceInfo()->getPrice('final_price')->getValue() + $product->getPriceInfo()->getPrice('final_price')->getValue() ); - $disabledSku = !$this->quoteHelper->checkDisabledForSku($this->getProduct()->getSku()); + $disabledSku = !$this->quoteHelper->checkDisabledForSku($product); - $output = ''; - if ($aboveThreshold && $disabledSku) { - $output = parent::toHtml(); + if ($this->catalogHelper->isEnabledOnPDP() && $aboveThreshold && $disabledSku) { + $isAllowed = true; } - return $output; + return $isAllowed; } - - protected function _construct($bypass = false) - { - if (!$bypass) { - $this->setBlockCode($this->getBlockCode()); - } - parent::_construct(); - } - - /** - * Get Current Product - * - * @return \Magento\Catalog\Model\Product - */ - public function getProduct() - { - if (null === $this->_product) { - $this->_product = $this->registry->registry('product'); - } - - return $this->_product; - } - /** * Get Minimal Product price * * @return int */ - public function getMinPrice() + public function getMinPrice($product) { - return $this->getProduct() - ->getPriceInfo() + return $product->getPriceInfo() ->getPrice(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE) ->getMinimalPrice() ->getValue(); @@ -152,10 +110,8 @@ public function getMinPrice() * * @return int */ - public function getSelectedProductPrice() + public function getSelectedProductPrice($product) { - $product = $this->getProduct(); - $selectionCollection = $product->getTypeInstance(true) ->getSelectionsCollection( $product->getTypeInstance(true)->getOptionsIds($product), @@ -185,22 +141,21 @@ public function getSelectedProductPrice() * * @return string */ - public function getProductDataJson() + public function getProductDataJson($product) { - $product = $this->getProduct(); $basePrice = $product->getPrice(); if ((int)$product->getPriceType() === \Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED) { - $selectedPrice = $basePrice + $this->getSelectedProductPrice(); + $selectedPrice = $basePrice + $this->getSelectedProductPrice($product); } else { - $selectedPrice = $this->getSelectedProductPrice(); + $selectedPrice = $this->getSelectedProductPrice($product); } - $bundlePrice = ($selectedPrice > 0) ? $selectedPrice : $this->getMinPrice(); + $bundlePrice = ($selectedPrice > 0) ? $selectedPrice : $this->getMinPrice($product); $data = [$this->catalogHelper->getProductDataArray($product, null, 1, $bundlePrice)]; - return $this->jsonEncode($data); + return $this->serializer->serialize($data); } /** @@ -209,11 +164,8 @@ public function getProductDataJson() * * @return string */ - public function getBundleProductDataJson() + public function getBundleProductDataJson($product) { - $product = $this->getProduct(); - $customOptions = $this->getCustomOptionsData($product->getOptions()); - $data = [ 'bundleId' => $product->getId(), 'sku' => $product->getSku(), @@ -268,7 +220,7 @@ public function getBundleProductDataJson() $data['selectedPrice'] = round($bundlePrice * 100); - return $this->jsonEncode($data); + return $this->serializer->serialize($data); } /** @@ -324,7 +276,7 @@ public function getCustomOptionsData($options) public function getDiscountDataJson() { $data = []; - return $this->jsonEncode($data); + return $this->serializer->serialize($data); } /** @@ -335,7 +287,7 @@ public function getDiscountDataJson() public function getFinancingJson() { $data = $this->catalogHelper->getFinancingData(); - return $this->jsonEncode($data); + return $this->serializer->serialize($data); } /** @@ -348,20 +300,6 @@ public function getAsLowAs() return ($this->catalogHelper->isAsLowAs()) ? 'true' : 'false'; } - /** - * Checks Settings For Show On Product Detail Page During Output - * - * @return string - */ - protected function _toHtml() - { - if ($this->catalogHelper->isEnabledOnPDP()) { - return parent::_toHtml(); - } - - return ''; - } - /** * Get Shipping Estimate Url * @@ -402,21 +340,21 @@ public function getConfigDataUrl() return $this->catalogHelper->getConfigDataUrl(); } - /** - * Get Discounts Data URL - * - * @return string - */ + /** + * Get Discounts Data URL + * + * @return string + */ public function getDiscountsDataUrl() { return $this->catalogHelper->getDiscountsDataUrl(); } - /** - * Get Clear Quote Data URL - * - * @return string - */ + /** + * Get Clear Quote Data URL + * + * @return string + */ public function getClearQuoteUrl() { return $this->catalogHelper->getClearQuoteUrl(); @@ -482,17 +420,6 @@ public function getBlockCode() return (string) $this->catalogHelper->getBlockCodeProductView(); } - /** - * Publicly accessible json encoder - * - * @param $data - * @return string - */ - public function jsonEncode($data) - { - return $this->jsonHelper->jsonEncode($data); - } - /** * Is downloadable type * @@ -502,4 +429,4 @@ public function isDownloadable() { return $this->getProduct()->getTypeId() === \Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE; } -} +} \ No newline at end of file diff --git a/Block/Product/View.php b/ViewModel/Product/View.php similarity index 57% rename from Block/Product/View.php rename to ViewModel/Product/View.php index bd495181..66e43bc4 100644 --- a/Block/Product/View.php +++ b/ViewModel/Product/View.php @@ -1,150 +1,77 @@ registry = $context->getRegistry(); - $this->jsonHelper = $jsonHelper; $this->catalogHelper = $catalogHelper; $this->customerHelper = $customerHelper; - $this->dataHelper = $dataHelper; - $this->configurableProductFactory = $configurableProductFactory; - $this->configurableBlockFactory = $configurableBlockFactory; $this->quoteHelper = $quoteHelper; + $this->dataHelper = $dataHelper; + $this->serializer = $serializer; - parent::__construct( - $context, - $arrayUtils, - $jsonEncoder, - $configurableHelper, - $catalogProductHelper, - $currentCustomer, - $priceCurrency, - $configurableAttributeData, - $data - ); - } - - protected function _construct($bypass = false) - { - if (!$bypass) { - $this->setBlockCode($this->getBlockCode()); - } - parent::_construct(); - } - - /** - * Get Current Product - * - * @return \Magento\Catalog\Model\Product - */ - public function getProduct() - { - if (null === $this->_product) { - $this->_product = $this->registry->registry('product'); - } - - return $this->_product; + parent::__construct($data); } /** - * Get Product Data as JSON + * Return product data in json format * - * @return string + * @param $product + * @return bool|false|string */ - public function getProductDataJson() + public function getProductDataJson($product) { - $product = $this->getProduct(); - $data = [$this->catalogHelper->getProductDataArray($product, null)]; - - return $this->jsonEncode($data); + return $this->serializer->serialize([$this->catalogHelper->getProductDataArray($product, null)]); } /** @@ -152,12 +79,10 @@ public function getProductDataJson() * * @return string */ - public function getGroupedDataJson() + public function getGroupedDataJson($product) { - $product = $this->getProduct(); $data = [$this->catalogHelper->getGroupedProductDataArray($product)]; - - return $this->jsonEncode($data); + return $this->serializer->serialize($data); } /** @@ -178,7 +103,7 @@ public function getGroupedButtonUpdate() public function getDiscountDataJson() { $data = []; - return $this->jsonEncode($data); + return $this->serializer->serialize($data); } /** @@ -189,7 +114,7 @@ public function getDiscountDataJson() public function getFinancingJson() { $data = $this->catalogHelper->getFinancingData(); - return $this->jsonEncode($data); + return $this->serializer->serialize($data); } /** @@ -223,28 +148,27 @@ public function getAsLowAs() } /** - * Checks Settings For Show On Product Detail Page During Output + * Check if template should return output * - * @return string + * @param \Magento\Catalog\Model\Product $product + * @return bool + * @throws \Magento\Framework\Exception\NoSuchEntityException */ - protected function _toHtml() + public function isAllowedRender($product) { - if ($this->getBlockCode() === \Bread\BreadCheckout\Helper\Data::BLOCK_CODE_PRODUCT_VIEW - && $this->catalogHelper->isEnabledOnPDP() - && $this->catalogHelper->allowedProductType($this->getProduct()->getTypeId()) + $isAllowed = false; + + if ($this->catalogHelper->isEnabledOnPDP() + && $this->catalogHelper->allowedProductType($product->getTypeId()) && $this->dataHelper->aboveThreshold( - $this->getProduct()->getPriceInfo()->getPrice('final_price')->getValue() + $product->getPriceInfo()->getPrice('final_price')->getValue() ) - && !$this->quoteHelper->checkDisabledForSku($this->getProduct()->getSku()) + && !$this->quoteHelper->checkDisabledForSku($product) ) { - return parent::_toHtml(); - } elseif ($this->getBlockCode() === \Bread\BreadCheckout\Helper\Data::BLOCK_CODE_CHECKOUT_OVERVIEW - && $this->catalogHelper->isEnabledOnCOP() - ) { - return parent::_toHtml(); + $isAllowed = true; } - return ''; + return $isAllowed; } /** @@ -297,11 +221,11 @@ public function getDiscountsDataUrl() return $this->catalogHelper->getDiscountsDataUrl(); } - /** - * Get Clear Quote Data URL - * - * @return string - */ + /** + * Get Clear Quote Data URL + * + * @return string + */ public function getClearQuoteUrl() { return $this->catalogHelper->getClearQuoteUrl(); @@ -324,7 +248,7 @@ public function getButtonDesign() */ public function getIsButtonOnProduct() { - return ( $this->catalogHelper->isButtonOnProducts() ) ? 'true' : 'false'; + return ($this->catalogHelper->isButtonOnProducts()) ? 'true' : 'false'; } /** @@ -410,6 +334,7 @@ public function checkFinancingMode($mode) /** * Get product IDs from related products collection + * @todo separate view model for configurable * * @param \Magento\Catalog\Model\Product $product * @return array @@ -432,7 +357,7 @@ public function getChildProductIds(\Magento\Catalog\Model\Product $product) /** * Get SKU and price data for custom options on product * - * @param $options + * @param \Magento\Catalog\Api\Data\ProductCustomOptionInterface[] $options * @return string */ public function getCustomOptionsData($options) @@ -455,7 +380,7 @@ public function getCustomOptionsData($options) } } - return $this->jsonEncode($optionsData); + return $this->serializer->serialize($optionsData); } /** @@ -527,23 +452,13 @@ public function getOtherLocation() { return $this->dataHelper->getOtherLocation(); } - /** - * Publicly accessible json encoder - * - * @param $data - * @return string - */ - public function jsonEncode($data) - { - return $this->jsonHelper->jsonEncode($data); - } /** * Is downloadable type * * @return bool */ - public function isDownloadable() + public function isDownloadable($typeId) { return $this->getProduct()->getTypeId() === \Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE; } diff --git a/view/frontend/layout/catalog_product_view.xml b/view/frontend/layout/catalog_product_view.xml index 7674b0dc..c2f1bb48 100644 --- a/view/frontend/layout/catalog_product_view.xml +++ b/view/frontend/layout/catalog_product_view.xml @@ -5,10 +5,19 @@ - + + + + Bread\BreadCheckout\ViewModel\Product\View + + - + + + Bread\BreadCheckout\ViewModel\Product\Options + + diff --git a/view/frontend/layout/catalog_product_view_type_bundle.xml b/view/frontend/layout/catalog_product_view_type_bundle.xml index b75367d2..0683d111 100644 --- a/view/frontend/layout/catalog_product_view_type_bundle.xml +++ b/view/frontend/layout/catalog_product_view_type_bundle.xml @@ -1,19 +1,17 @@ - - - - - + + - + + + + Bread\BreadCheckout\ViewModel\Product\Type\Bundle + + + - - diff --git a/view/frontend/layout/catalog_product_view_type_configurable.xml b/view/frontend/layout/catalog_product_view_type_configurable.xml index 532d952a..2e0c2601 100644 --- a/view/frontend/layout/catalog_product_view_type_configurable.xml +++ b/view/frontend/layout/catalog_product_view_type_configurable.xml @@ -2,7 +2,11 @@ - + + + Bread\BreadCheckout\ViewModel\Product\View + + \ No newline at end of file diff --git a/view/frontend/layout/catalog_product_view_type_grouped.xml b/view/frontend/layout/catalog_product_view_type_grouped.xml index f802c4a4..6c951880 100644 --- a/view/frontend/layout/catalog_product_view_type_grouped.xml +++ b/view/frontend/layout/catalog_product_view_type_grouped.xml @@ -2,14 +2,15 @@ - + - + + + Bread\BreadCheckout\ViewModel\Product\View + + diff --git a/view/frontend/layout/checkout_cart_index.xml b/view/frontend/layout/checkout_cart_index.xml index aa886bf8..aa59018a 100644 --- a/view/frontend/layout/checkout_cart_index.xml +++ b/view/frontend/layout/checkout_cart_index.xml @@ -5,7 +5,11 @@ - + + + Bread\BreadCheckout\ViewModel\Cart\CartView + + diff --git a/view/frontend/templates/breadcheckout/bundle.phtml b/view/frontend/templates/breadcheckout/bundle.phtml index 3200ceaa..5d9b452f 100644 --- a/view/frontend/templates/breadcheckout/bundle.phtml +++ b/view/frontend/templates/breadcheckout/bundle.phtml @@ -1,4 +1,339 @@ - +getData('view_model'); +$product = $block->getProduct(); + +if (!$viewModel->isAllowedRender($product)) { + return; +} +?> + +
+
getIsDefaultSize(); ?>> + + <?= /* @noEscape */ __('Bread Checkout'); ?> + +
+
+   +
+
+ + + + '; - - $dsn = $this->getSentryDSN(); - - // Don't enable Sentry if dsn can't be retrieved - $isSentryEnabled = $this->helper->isSentryEnabled() && $dsn; - - $sentryConfigScript = sprintf( - $sentryConfigScript, - $dsn, - $this->getModuleVersion(), - $this->helper->getApiPublicKey(), - $isSentryEnabled - ); - - $breadJsScript = sprintf( - '', - $this->helper->getJsLibLocation(), - $this->helper->getApiPublicKey() - ); - - return $moduleVersionComment . $sentryConfigScript . $breadJsScript; - } - - /** - * Get current module version - * - * @return string - */ - private function getModuleVersion() - { - return $this->packageInfo->getVersion('Bread_BreadCheckout'); - } - - /** - * Get Sentry DSN for magento 2 - * - * @return string - */ - private function getSentryDSN() - { - $sentryDSNIdentifier = 'sentry_dsn'; - - $dsn = $this->cache->load($sentryDSNIdentifier); - - if ($dsn) { - return $dsn; - } - - try { - $this->curl->setCredentials($this->helper->getApiPublicKey(), $this->helper->getApiSecretKey()); - $this->curl->get($this->helper::URL_LAMBDA_SENTRY_DSN); - - $response = json_decode($this->curl->getBody(), true); - - if (isset($response['error']) || !isset($response['dsn'])) { - $errorMessage = isset($response['error']) ? $response['error'] - : 'Incorrect Response Format: ' . json_encode($response); - $this->logger->log(['ERROR WHEN GETTING SENTRY DSN' => $errorMessage]); - return null; - } - - $dsn = $response['dsn']; - $this->cache->save($dsn, $sentryDSNIdentifier, [], 60 * 60); - - return $dsn; - } catch (\Throwable $e) { - $this->logger->log(['EXCEPTION WHEN GETTING SENTRY DSN' => $e->getMessage()]); - return null; - } - } -} diff --git a/Controller/Adminhtml/Bread/GenerateCart.php b/Controller/Adminhtml/Bread/GenerateCart.php index e7cb7e20..6494b84d 100644 --- a/Controller/Adminhtml/Bread/GenerateCart.php +++ b/Controller/Adminhtml/Bread/GenerateCart.php @@ -19,7 +19,7 @@ public function __construct( \Magento\Backend\App\Action\Context $context, \Bread\BreadCheckout\Helper\Quote $helper, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, - \Bread\BreadCheckout\Model\Payment\Api\Client $paymentApiClient, + \Bread\BreadCheckout\Model\Payment\Api\Service $paymentApiClient, \Bread\BreadCheckout\Helper\Customer $customerHelper, \Bread\BreadCheckout\Model\Payment\Method\Bread $breadMethod, \Bread\BreadCheckout\Helper\Url $urlHelper diff --git a/Controller/Adminhtml/Bread/SendBreadEmail.php b/Controller/Adminhtml/Bread/SendBreadEmail.php index 29034b4c..7705dd19 100644 --- a/Controller/Adminhtml/Bread/SendBreadEmail.php +++ b/Controller/Adminhtml/Bread/SendBreadEmail.php @@ -20,7 +20,7 @@ class SendBreadEmail extends \Magento\Backend\App\Action public $helper; /** - * @var \Bread\BreadCheckout\Model\Payment\Api\Client + * @var \Bread\BreadCheckout\Model\Payment\Api\Service */ public $paymentApiClient; @@ -30,13 +30,13 @@ class SendBreadEmail extends \Magento\Backend\App\Action * @param \Magento\Framework\App\Request\Http $request * @param \Magento\Backend\App\Action\Context $context * @param \Bread\BreadCheckout\Helper\Quote $helper - * @param \Bread\BreadCheckout\Model\Payment\Api\Client $paymentApiClient + * @param \Bread\BreadCheckout\Model\Payment\Api\Service $paymentApiClient */ public function __construct( \Magento\Framework\App\Request\Http $request, \Magento\Backend\App\Action\Context $context, \Bread\BreadCheckout\Helper\Quote $helper, - \Bread\BreadCheckout\Model\Payment\Api\Client $paymentApiClient + \Bread\BreadCheckout\Model\Payment\Api\Service $paymentApiClient ) { $this->request = $request; diff --git a/Controller/Adminhtml/Bread/SendMail.php b/Controller/Adminhtml/Bread/SendMail.php index 6bb1a0cd..8cb193d3 100644 --- a/Controller/Adminhtml/Bread/SendMail.php +++ b/Controller/Adminhtml/Bread/SendMail.php @@ -17,7 +17,7 @@ public function __construct( \Magento\Backend\App\Action\Context $context, \Bread\BreadCheckout\Helper\Quote $helper, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, - \Bread\BreadCheckout\Model\Payment\Api\Client $paymentApiClient, + \Bread\BreadCheckout\Model\Payment\Api\Service $paymentApiClient, \Bread\BreadCheckout\Helper\Customer $customerHelper ) { diff --git a/Controller/Adminhtml/Bread/SendSms.php b/Controller/Adminhtml/Bread/SendSms.php index 7081ec85..60995666 100644 --- a/Controller/Adminhtml/Bread/SendSms.php +++ b/Controller/Adminhtml/Bread/SendSms.php @@ -20,7 +20,7 @@ class SendSms extends \Magento\Backend\App\Action public $helper; /** - * @var \Bread\BreadCheckout\Model\Payment\Api\Client + * @var \Bread\BreadCheckout\Model\Payment\Api\Service */ public $paymentApiClient; @@ -30,13 +30,13 @@ class SendSms extends \Magento\Backend\App\Action * @param \Magento\Framework\App\Request\Http $request * @param \Magento\Backend\App\Action\Context $context * @param \Bread\BreadCheckout\Helper\Quote $helper - * @param \Bread\BreadCheckout\Model\Payment\Api\Client $paymentApiClient + * @param \Bread\BreadCheckout\Model\Payment\Api\Service $paymentApiClient */ public function __construct( \Magento\Framework\App\Request\Http $request, \Magento\Backend\App\Action\Context $context, \Bread\BreadCheckout\Helper\Quote $helper, - \Bread\BreadCheckout\Model\Payment\Api\Client $paymentApiClient + \Bread\BreadCheckout\Model\Payment\Api\Service $paymentApiClient ) { $this->request = $request; diff --git a/Controller/Adminhtml/Bread/ValidateCredentials.php b/Controller/Adminhtml/Bread/ValidateCredentials.php index 3d845078..3c87387f 100644 --- a/Controller/Adminhtml/Bread/ValidateCredentials.php +++ b/Controller/Adminhtml/Bread/ValidateCredentials.php @@ -14,13 +14,13 @@ class ValidateCredentials extends \Magento\Backend\App\Action const API_LIVE_URI = 'https://api.getbread.com/carts/'; /** - * @var \Bread\BreadCheckout\Helper\Log + * @var \Bread\BreadCheckout\Log\Logger */ public $logger; public function __construct( \Magento\Backend\App\Action\Context $context, - \Bread\BreadCheckout\Helper\Log $log + \Bread\BreadCheckout\Log\Logger $log ) { $this->logger = $log; parent::__construct($context); @@ -68,13 +68,13 @@ private function testCredentials($apiMode, $username, $password) curl_close($curl); if ($status != 200) { - $this->logger->log('Failed keys validation'); + $this->logger->write('Failed keys validation'); return false; } else { return true; } } catch (\Exception $e) { - $this->logger->log( + $this->logger->write( [ 'STATUS' => 'BACKEND API KEYS TEST', 'RESULT' => $result diff --git a/Controller/Adminhtml/Bread/ValidatePaymentMethod.php b/Controller/Adminhtml/Bread/ValidatePaymentMethod.php index 9b0a4de8..0413d5b8 100644 --- a/Controller/Adminhtml/Bread/ValidatePaymentMethod.php +++ b/Controller/Adminhtml/Bread/ValidatePaymentMethod.php @@ -11,7 +11,7 @@ class ValidatePaymentMethod extends \Magento\Backend\App\Action { /** - * @var \Bread\BreadCheckout\Model\Payment\Api\Client + * @var \Bread\BreadCheckout\Model\Payment\Api\Service */ public $paymentApiClient; @@ -21,7 +21,7 @@ class ValidatePaymentMethod extends \Magento\Backend\App\Action public $resultJsonFactory; /** - * @var \Bread\BreadCheckout\Helper\Log + * @var \Bread\BreadCheckout\Log\Logger */ public $logger; @@ -37,9 +37,9 @@ class ValidatePaymentMethod extends \Magento\Backend\App\Action public function __construct( \Magento\Backend\App\Action\Context $context, - \Bread\BreadCheckout\Model\Payment\Api\Client $paymentApiClient, + \Bread\BreadCheckout\Model\Payment\Api\Service $paymentApiClient, \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, - \Bread\BreadCheckout\Helper\Log $log, + \Bread\BreadCheckout\Log\Logger $log, \Bread\BreadCheckout\Helper\Data $helper, \Magento\Sales\Model\AdminOrder\Create $orderCreateModel ) { @@ -74,7 +74,7 @@ public function execute() } $response = ['result' => $result]; } catch (\Throwable $e) { - $this->logger->log(['EXCEPTION IN VALIDATE PAYMENT IN ADMIN CONTROLLER'=>$e->getMessage()]); + $this->logger->write(['EXCEPTION IN VALIDATE PAYMENT IN ADMIN CONTROLLER'=>$e->getMessage()]); $response = ['error' => 'Something went wrong processing the Bread payment. ' . 'Please select a different payment method to complete checkout.']; diff --git a/Controller/Checkout.php b/Controller/Checkout.php index 1351cf90..7603ef55 100644 --- a/Controller/Checkout.php +++ b/Controller/Checkout.php @@ -36,7 +36,7 @@ abstract class Checkout extends \Magento\Framework\App\Action\Action public $catalogProductFactory; /** - * @var \Bread\BreadCheckout\Helper\Log + * @var \Bread\BreadCheckout\Log\Logger */ public $logger; @@ -77,7 +77,7 @@ public function __construct( \Magento\Checkout\Model\Session $checkoutSession, \Magento\Quote\Model\QuoteFactory $quoteFactory, \Magento\Catalog\Model\ProductFactory $catalogProductFactory, - \Bread\BreadCheckout\Helper\Log $logger, + \Bread\BreadCheckout\Log\Logger $logger, \Bread\BreadCheckout\Helper\Checkout $helper, \Magento\Quote\Model\Quote\TotalsCollector $totalsCollector, \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, @@ -271,7 +271,7 @@ protected function getShippingAddressForQuote(array $data) return $address; } catch (\Throwable $e) { - $this->logger->log(['MESSAGE' => $e->getMessage(),'TRACE' => $e->getTraceAsString()]); + $this->logger->write(['MESSAGE' => $e->getMessage(),'TRACE' => $e->getTraceAsString()]); return $this->resultFactory->create(\Magento\Framework\Controller\ResultFactory::TYPE_JSON)->setData( [ 'result' => ['error' => 1, 'text' => 'Internal error'] diff --git a/Controller/Checkout/ClearQuote.php b/Controller/Checkout/ClearQuote.php index 0b47e849..708cd50c 100644 --- a/Controller/Checkout/ClearQuote.php +++ b/Controller/Checkout/ClearQuote.php @@ -16,7 +16,7 @@ public function __construct( \Magento\Checkout\Model\Session $checkoutSession, \Magento\Quote\Model\QuoteFactory $quoteFactory, \Magento\Catalog\Model\ProductFactory $catalogProductFactory, - \Bread\BreadCheckout\Helper\Log $logger, + \Bread\BreadCheckout\Log\Logger $logger, \Bread\BreadCheckout\Helper\Checkout $helper, \Magento\Quote\Model\Quote\TotalsCollector $totalsCollector, \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, @@ -58,7 +58,7 @@ public function execute() $this->quoteRepository->save($quote); $result = true; } catch (\Throwable $e) { - $this->logger->log(['MESSAGE' => $e->getMessage(), 'TRACE' => $e->getTraceAsString()]); + $this->logger->write(['MESSAGE' => $e->getMessage(), 'TRACE' => $e->getTraceAsString()]); $result = false; } return $this->resultFactory->create(\Magento\Framework\Controller\ResultFactory::TYPE_JSON)->setData( diff --git a/Controller/Checkout/DiscountsData.php b/Controller/Checkout/DiscountsData.php index 149211fe..da1ac038 100644 --- a/Controller/Checkout/DiscountsData.php +++ b/Controller/Checkout/DiscountsData.php @@ -31,7 +31,7 @@ public function __construct( \Magento\Checkout\Model\Session $checkoutSession, \Magento\Quote\Model\QuoteFactory $quoteFactory, \Magento\Catalog\Model\ProductFactory $catalogProductFactory, - \Bread\BreadCheckout\Helper\Log $logger, + \Bread\BreadCheckout\Log\Logger $logger, \Bread\BreadCheckout\Helper\Checkout $helper, \Magento\Quote\Model\Quote\TotalsCollector $totalsCollector, \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, diff --git a/Controller/Checkout/EstimateShipping.php b/Controller/Checkout/EstimateShipping.php index 9242f98c..a724c260 100644 --- a/Controller/Checkout/EstimateShipping.php +++ b/Controller/Checkout/EstimateShipping.php @@ -37,7 +37,7 @@ public function __construct( \Magento\Checkout\Model\Session $checkoutSession, \Magento\Quote\Model\QuoteFactory $quoteFactory, \Magento\Catalog\Model\ProductFactory $catalogProductFactory, - \Bread\BreadCheckout\Helper\Log $logger, + \Bread\BreadCheckout\Log\Logger $logger, \Bread\BreadCheckout\Helper\Checkout $helper, \Magento\Quote\Model\Quote\TotalsCollector $totalsCollector, \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, @@ -101,7 +101,7 @@ public function execute() } $response = ['result' => $methods]; } catch (\Throwable $e) { - $this->logger->log(['ERROR' => $e->getMessage(),'PARAMS'=> $this->getRequest()->getParams()]); + $this->logger->write(['ERROR' => $e->getMessage(),'PARAMS'=> $this->getRequest()->getParams()]); $this->messageManager->addErrorMessage( __( 'Internal Error, Please Contact Store Owner. You may checkout by adding to cart diff --git a/Controller/Checkout/EstimateTax.php b/Controller/Checkout/EstimateTax.php index 77fa9cfc..e221b04e 100644 --- a/Controller/Checkout/EstimateTax.php +++ b/Controller/Checkout/EstimateTax.php @@ -32,7 +32,7 @@ public function __construct( \Magento\Checkout\Model\Session $checkoutSession, \Magento\Quote\Model\QuoteFactory $quoteFactory, \Magento\Catalog\Model\ProductFactory $catalogProductFactory, - \Bread\BreadCheckout\Helper\Log $logger, + \Bread\BreadCheckout\Log\Logger $logger, \Bread\BreadCheckout\Helper\Checkout $helper, \Magento\Quote\Model\Quote\TotalsCollector $totalsCollector, \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, @@ -78,7 +78,7 @@ public function execute() $result = round($shippingAddress->getTaxAmount() * 100); $response = ['result' => $result]; } catch (\Throwable $e) { - $this->logger->log(['EXCEPTION IN TAX ESTIMATE ACTION' => $e->getMessage()]); + $this->logger->write(['EXCEPTION IN TAX ESTIMATE ACTION' => $e->getMessage()]); $response = ['error' => 1, 'message' => 'There was an error calculating the estimated tax']; } diff --git a/Controller/Checkout/LandingPage.php b/Controller/Checkout/LandingPage.php index e521c456..b6ce7b11 100644 --- a/Controller/Checkout/LandingPage.php +++ b/Controller/Checkout/LandingPage.php @@ -10,7 +10,7 @@ class LandingPage extends \Magento\Framework\App\Action\Action public $request; /** - * @var \Bread\BreadCheckout\Model\Payment\Api\Client + * @var \Bread\BreadCheckout\Model\Payment\Api\Service */ public $paymentApiClient; @@ -45,7 +45,7 @@ class LandingPage extends \Magento\Framework\App\Action\Action public $helper; /** - * @var \Bread\BreadCheckout\Helper\Log + * @var \Bread\BreadCheckout\Log\Logger */ public $logger; @@ -86,14 +86,14 @@ class LandingPage extends \Magento\Framework\App\Action\Action public function __construct( \Magento\Framework\App\Request\Http $request, - \Bread\BreadCheckout\Model\Payment\Api\Client $paymentApiClient, + \Bread\BreadCheckout\Model\Payment\Api\Service $paymentApiClient, \Magento\Customer\Model\Customer $customer, \Magento\Customer\Model\Session $customerSession, \Magento\Checkout\Model\Session $checkoutSession, \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, \Magento\Quote\Model\QuoteManagement $quoteManagement, \Bread\BreadCheckout\Helper\Checkout $helper, - \Bread\BreadCheckout\Helper\Log $logger, + \Bread\BreadCheckout\Log\Logger $logger, \Magento\Customer\Model\CustomerFactory $customerFactory, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Quote\Model\QuoteFactory $quoteFactory, @@ -164,7 +164,7 @@ public function validateBackendOrder($transactionId, $orderRef) $this->_redirect('checkout/onepage/success'); } } catch (\Throwable $e) { - $this->logger->log(['ERROR' => $e->getMessage(), 'TRACE' => $e->getTraceAsString()]); + $this->logger->write(['ERROR' => $e->getMessage(), 'TRACE' => $e->getTraceAsString()]); $this->customerHelper->sendCustomerErrorReportToMerchant($e, "", $orderRef, $transactionId); $this->messageManager->addErrorMessage( __('There was an error with your financing program. Notification was sent to merchant.') @@ -213,7 +213,7 @@ protected function processBackendOrder($orderRef, $data) try { $order = $this->quoteManagement->submit($quote); } catch (\Throwable $e) { - $this->logger->log( + $this->logger->write( [ 'ERROR SUBMITTING QUOTE IN PROCESS ORDER' => $e->getMessage(), 'TRACE' => $e->getTraceAsString() diff --git a/Controller/Checkout/ValidateOrder.php b/Controller/Checkout/ValidateOrder.php index 3a9ac103..71e3fee3 100644 --- a/Controller/Checkout/ValidateOrder.php +++ b/Controller/Checkout/ValidateOrder.php @@ -11,7 +11,7 @@ class ValidateOrder extends \Bread\BreadCheckout\Controller\Checkout { /** - * @var \Bread\BreadCheckout\Model\Payment\Api\Client + * @var \Bread\BreadCheckout\Model\Payment\Api\Service */ public $paymentApiClient; @@ -26,7 +26,7 @@ class ValidateOrder extends \Bread\BreadCheckout\Controller\Checkout public $cartHelper; /** - * @var \Bread\BreadCheckout\Helper\Log + * @var \Bread\BreadCheckout\Log\Logger */ public $logger; @@ -77,10 +77,10 @@ class ValidateOrder extends \Bread\BreadCheckout\Controller\Checkout public function __construct( \Magento\Framework\App\Action\Context $context, - \Bread\BreadCheckout\Model\Payment\Api\Client $paymentApiClient, + \Bread\BreadCheckout\Model\Payment\Api\Service $paymentApiClient, \Magento\Checkout\Model\Session $checkoutSession, \Magento\Checkout\Helper\Cart $cartHelper, - \Bread\BreadCheckout\Helper\Log $logger, + \Bread\BreadCheckout\Log\Logger $logger, \Magento\Quote\Model\QuoteFactory $quoteFactory, \Magento\Customer\Model\Session $customerSession, \Magento\Quote\Model\QuoteManagement $quoteManagement, @@ -134,7 +134,7 @@ public function execute() try { $token = $this->getRequest()->getParam('token'); if ($token) { - $this->logger->log( + $this->logger->write( [ 'VALIDATE ORDER TOKEN' => $token, ] @@ -145,7 +145,7 @@ public function execute() } catch (\Throwable $e) { $errorMessage = $e->getMessage(); - $this->logger->log(['MESSAGE' => $errorMessage]); + $this->logger->write(['MESSAGE' => $errorMessage]); //TODO: rewrite this when API is updated to better handle errors, instead of searching //TODO: through error message string @@ -179,7 +179,7 @@ public function execute() protected function processOrder($data) { // @codingStandardsIgnoreStart - $this->logger->log(['PROCESS ORDER DATA' => $data]); + $this->logger->write(['PROCESS ORDER DATA' => $data]); /** @var $quote \Magento\Quote\Model\Quote */ $quote = $this->checkoutSession->getQuote(); @@ -218,13 +218,13 @@ protected function processOrder($data) $billingContact['region_id'] = $shippingContact['region_id']; } - $this->logger->log(['SHIPPING CONTACT' => $shippingContact, 'BILLING CONTACT' => $billingContact]); + $this->logger->write(['SHIPPING CONTACT' => $shippingContact, 'BILLING CONTACT' => $billingContact]); $billingAddress = $quote->getBillingAddress()->addData($billingContact); $shippingAddress = $quote->getShippingAddress()->addData($shippingContact)->setCollectShippingRates(true); if (!isset($data['shippingMethodCode'])) { - $this->logger->log('Shipping Method Code Is Not Set On The Response'); + $this->logger->write('Shipping Method Code Is Not Set On The Response'); } $shippingAddress->setShippingMethod($data['shippingMethodCode']); @@ -255,7 +255,7 @@ protected function processOrder($data) try { $order = $this->quoteManagement->submit($quote); } catch (\Throwable $e) { - $this->logger->log(['ERROR SUBMITTING QUOTE IN PROCESS ORDER' => $e->getMessage()]); + $this->logger->write(['ERROR SUBMITTING QUOTE IN PROCESS ORDER' => $e->getMessage()]); throw $e; } diff --git a/Controller/Checkout/ValidatePaymentMethod.php b/Controller/Checkout/ValidatePaymentMethod.php index 8c6ff616..d6f65948 100644 --- a/Controller/Checkout/ValidatePaymentMethod.php +++ b/Controller/Checkout/ValidatePaymentMethod.php @@ -11,7 +11,7 @@ class ValidatePaymentMethod extends \Bread\BreadCheckout\Controller\Checkout { /** - * @var \Bread\BreadCheckout\Model\Payment\Api\Client + * @var \Bread\BreadCheckout\Model\Payment\Api\Service */ public $paymentApiClient; @@ -32,13 +32,13 @@ class ValidatePaymentMethod extends \Bread\BreadCheckout\Controller\Checkout public function __construct( \Magento\Framework\App\Action\Context $context, - \Bread\BreadCheckout\Model\Payment\Api\Client $paymentApiClient, + \Bread\BreadCheckout\Model\Payment\Api\Service $paymentApiClient, \Magento\Catalog\Model\ResourceModel\ProductFactory $catalogResourceModelProductFactory, \Magento\Framework\DataObjectFactory $dataObjectFactory, \Magento\Checkout\Model\Session $checkoutSession, \Magento\Quote\Model\QuoteFactory $quoteFactory, \Magento\Catalog\Model\ProductFactory $catalogProductFactory, - \Bread\BreadCheckout\Helper\Log $logger, + \Bread\BreadCheckout\Log\Logger $logger, \Bread\BreadCheckout\Helper\Checkout $helper, \Magento\Quote\Model\Quote\TotalsCollector $totalsCollector, \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, @@ -92,7 +92,7 @@ public function execute() $result = $newData; } catch (\Throwable $e) { - $this->logger->log(['MESSAGE' => $e->getMessage(), 'TRACE' => $e->getTraceAsString()]); + $this->logger->write(['MESSAGE' => $e->getMessage(), 'TRACE' => $e->getTraceAsString()]); $result = ['error' => (string) __('Error: Unable to process transaction.')]; } diff --git a/Controller/Checkout/ValidateTotals.php b/Controller/Checkout/ValidateTotals.php index bd62923a..5c32073d 100644 --- a/Controller/Checkout/ValidateTotals.php +++ b/Controller/Checkout/ValidateTotals.php @@ -22,7 +22,7 @@ public function __construct( \Magento\Checkout\Model\Session $checkoutSession, \Magento\Quote\Model\QuoteFactory $quoteFactory, \Magento\Catalog\Model\ProductFactory $catalogProductFactory, - \Bread\BreadCheckout\Helper\Log $logger, + \Bread\BreadCheckout\Log\Logger $logger, \Bread\BreadCheckout\Helper\Checkout $helper, \Magento\Quote\Model\Quote\TotalsCollector $totalsCollector, \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, diff --git a/Helper/Checkout.php b/Helper/Checkout.php index 7f4b3c52..fa66b21c 100644 --- a/Helper/Checkout.php +++ b/Helper/Checkout.php @@ -22,7 +22,7 @@ public function __construct( \Bread\BreadCheckout\Helper\Catalog $helperCatalog, \Magento\Sales\Model\AdminOrder\Create $orderCreateModel, \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency, - \Bread\BreadCheckout\Model\Payment\Api\Client $paymentApiClient, + \Bread\BreadCheckout\Model\Payment\Api\Service $paymentApiClient, \Magento\Catalog\Api\ProductRepositoryInterface $productRepository ) { parent::__construct( diff --git a/Helper/Config.php b/Helper/Config.php new file mode 100644 index 00000000..918ca2f5 --- /dev/null +++ b/Helper/Config.php @@ -0,0 +1,450 @@ +context = $context; + $this->encryptor = $encryptor; + $this->isSecure = $request->isSecure(); + parent::__construct( + $helperContext + ); + } + + /** + * Is module active + * + * @param string $store + * @return bool + */ + public function isActive(): bool + { + return $this->getConfigData('active', true); + } + + /** + * Check product type against allowed product type list + * + * @param string $typeId + * @return bool + */ + public function allowedProductType($typeId): bool + { + $allowedProductTypes = [ + Type::TYPE_SIMPLE, + Type::TYPE_BUNDLE, + Type::TYPE_VIRTUAL, + Configurable::TYPE_CODE, + Downloadable::TYPE_DOWNLOADABLE, + Grouped::TYPE_CODE + ]; + + return in_array($typeId, $allowedProductTypes); + } + + /** + * Retrieve information from method configuration + * + * @param $field + * @param bool $returnFlag + * @return bool|string + */ + public function getConfigData($field ,$returnFlag = false) + { + $path = 'payment/breadcheckout/' . $field; + + if($returnFlag){ + $value = $this->scopeConfig->isSetFlag( + $path, + ScopeInterface::SCOPE_STORE + ); + } else { + $value = $this->scopeConfig->getValue( + $path, + ScopeInterface::SCOPE_STORE + ); + } + + return $value; + } + + /** + * Wrapper for url build method + * @todo REPLACE ALL PREVIOUSLY USED WRAPPERS WITH THIS ONE!!! + * + * @param string $url + * @return string + */ + public function createUrl($url): string + { + return $this->_urlBuilder->getUrl($url, ['_secure'=> $this->isSecure]); + } + + /** + * Return custom message for non supported product type + * @TODO REMOVED!!! + * + * @param string $store + * @return string + */ + /* public function getProductTypeMessage($store = \Magento\Store\Model\ScopeInterface::SCOPE_STORE): string + { + return $this->scopeConfig->getValue(self::XML_CONFIG_PRODUCT_TYPE_MSG, $store); + }*/ + + /** + * Get API Pub Key + * + * @return string + */ + public function getApiPublicKey(): string + { + if ($this->getConfigData('api_mode',true)) { + $output = $this->getConfigData('api_public_key'); + } else { + $output = $this->getConfigData('api_sandbox_public_key'); + } + + return $output; + } + + /** + * Get API Secret Key + * + * @return string + */ + public function getApiSecretKey(): string + { + if ($this->getConfigData('api_mode',true)) { + $output = $this->encryptor->decrypt( + $this->getConfigData('api_secret_key') + ); + } else { + $output = $this->encryptor->decrypt( + $this->getConfigData('api_sandbox_secret_key') + ); + } + + return $output; + } + + /** + * Get JS Lib Location + * + * @return string + */ + public function getJsLibLocation(): string + { + if ($this->getConfigData('api_mode', true)) { + return self::JS_LIVE_URI; + } else { + return self::JS_SANDBOX_URI; + } + } + + /** + * Get API Url + * + * @return string + */ + public function getTransactionApiEndpoint(): string + { + if ($this->getConfigData('api_mode', true)) { + return self::API_LIVE_URI; + } else { + return self::API_SANDBOX_URI; + } + } + + /** + * Get URL for controller which clears quote + * after shopping cart rules pre calculation + * @todo this is not used, some alternative needs to be figured out! + * + * @return string + */ + public function getClearQuoteUrl() + { + return $this->_urlBuilder->getUrl(self::URL_CLEAR_QUOTE, ['_secure'=> $this->isSecure]); + } + + /** + * Payment Method Title During Checkout + * @todo FIX THIS NOT BEING USED!!! + * + * @param null $store + * @return string + */ + public function getPaymentMethodTitle($store) + { + return __($this->scopeConfig->getValue(self::XML_CONFIG_CHECKOUT_TITLE, $store)); + } + + /** + * Show per month calculation next to payment method title on checkout + * @todo check what exactly is this + * + * @param string $store + * @return bool + */ + public function showPerMonthCalculation($store): string + { + return $this->scopeConfig->getValue(self::XML_CONFIG_CHECKOUT_PER_MONTH, $store); + } + + /** + * Is Customer Account Created During Bread Work Flow? + * @todo REMOVE AND REPLACE BY CHECK FOR GUEST CHECKOUT ALLOWED + * + * @param null $store + * @return bool + */ + public function isAutoCreateCustomerAccountEnabled($store) + { + return (bool) ($this->isActive($store) + && $this->scopeConfig->getValue(self::XML_CONFIG_CREATE_CUSTOMER, $store)); + } + + + /** + * Use Bread As Payment Method In Checkout? + * @todo IF ENABLED IT SHOULD BE ACTIVE ON CHECKOUT BY DEFAULT || OR NOT :D + * + * @param null $store + * @return bool + */ + public function isPaymentMethodAtCheckout($store): bool + { + return $this->scopeConfig->getValue(self::XML_CONFIG_ENABLE_AS_PAYMENT_METHOD, $store); + } + + /** + * Allow checkout from popup on product view page + * + * @return bool + */ + public function isCheckoutAllowedProductView() + { + return !!$this->getConfigData('healthcare_mode',true) + && $this->getConfigData('allowcheckoutpdp'); + } + + /** + * Allow checkout from popup on cart view page + * + * @return bool + */ + public function getAllowCheckoutCartView() + { + return !$this->getConfigData('healthcare_mode',true) + && $this->getConfigData('allowcheckoutcart'); + } + + /** + * Get cart size over which targeted financing is enabled + * + * @return float + */ + public function getTargetedFinancingThreshold(): float + { + return round($this->getConfigData('bread_advanced/financing_threshold'), 2); + } + + /** + * Return list of SKU's for which financing is enabled + * + * @return array + */ + public function getTargetedFinancingSkus(): array + { + $list = $this->getConfigData('financing_sku'); + $list = preg_replace('/\s/', '', $list); + + return explode(',', $list); + } + + /** + * Return financing mode + * + * @param string $mode + * @return bool + */ + public function checkFinancingMode($mode): bool + { + $configVal = (int)$this->getConfigData('targeted_financing'); + $output = null; + + switch ($mode) { + case 'cart': + $output = ($configVal === 1); + break; + case 'sku': + $output = ($configVal === 2); + break; + } + + return $output; + } + + /** + * Get cart size financing configuration + * + * @return array + */ + public function getFinancingData(): array + { + return [ + 'enabled' => $this->getConfigData('bread_advanced/targeted_financing', true), + 'mode' => ['cart'=>$this->checkFinancingMode('cart'), 'sku'=>$this->checkFinancingMode('sku')], + 'id' => $this->getConfigData('bread_advanced/financing_program_id'), + 'threshold' => $this->getTargetedFinancingThreshold(), + 'sku_limit' => $this->getTargetedFinancingSkus() + ]; + } + + /** + * Check if called from admin + * @return bool + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function isInAdmin(): bool + { + return (\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE + === $this->context->getAppState()->getAreaCode()); + } + + /** + * Check if cost of item/cart total is equal or greater than set threshold amount + * + * @param float $cost + * @return bool + */ + public function aboveThreshold($cost): bool + { + $aboveThreshold = true; + $thresholdAmount = (int)$this->scopeConfig->getValue(self::XML_CONFIG_THRESHOLD_AMOUNT); + + if ($thresholdAmount) { + $aboveThreshold = (int)$cost >= $thresholdAmount; + } + + return $aboveThreshold; + } + +} \ No newline at end of file diff --git a/Helper/Customer.php b/Helper/Customer.php index 8c6adb03..412b2b8d 100644 --- a/Helper/Customer.php +++ b/Helper/Customer.php @@ -8,6 +8,8 @@ */ namespace Bread\BreadCheckout\Helper; +use Bread\BreadCheckout\Log\Logger; + class Customer extends Data { /** @@ -66,7 +68,7 @@ class Customer extends Data public $addressRepository; /** - * @var Log + * @var Logger */ public $logger; @@ -87,7 +89,7 @@ public function __construct( \Magento\Directory\Model\RegionFactory $regionFactory, \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository, \Magento\Customer\Api\AddressRepositoryInterface $addressRepository, - \Bread\BreadCheckout\Helper\Log $logger + \Bread\BreadCheckout\Log\Logger $logger ) { $this->storeManager = $storeManager; $this->customerSession = $customerSession; @@ -257,7 +259,7 @@ public function createCustomer($quote, $billingContact, $shippingContact, $creat } } catch (\Throwable $e) { - $this->logger->log(['MESSAGE' => $e->getMessage(), 'TRACE' => $e->getTraceAsString()]); + $this->logger->write(['MESSAGE' => $e->getMessage(), 'TRACE' => $e->getTraceAsString()]); } return $customer; diff --git a/Helper/Log.php b/Helper/Log.php deleted file mode 100644 index f9d2f55c..00000000 --- a/Helper/Log.php +++ /dev/null @@ -1,55 +0,0 @@ -breadLogger = $breadLogger; - } - - /** - * Check if logging is enabled - * - * @return bool - */ - private function logEnabled() - { - return $this->scopeConfig->isSetFlag(self::XML_CONFIG_LOG_ENABLED); - } - - /** - * @param $data - */ - public function log($data) - { - if ($this->logEnabled()) { - if (!is_string($data)) { - $data = print_r($data, true); - } - $this->breadLogger->debug($data); - } - } -} diff --git a/Helper/Quote.php b/Helper/Quote.php index c796e814..76d876c4 100644 --- a/Helper/Quote.php +++ b/Helper/Quote.php @@ -38,7 +38,7 @@ class Quote extends Data */ public $priceCurrency; /** - * @var \Bread\BreadCheckout\Model\Payment\Api\Client + * @var \Bread\BreadCheckout\Model\Payment\Api\Service */ public $paymentApiClient; @@ -59,7 +59,7 @@ class Quote extends Data * @param Catalog $helperCatalog * @param \Magento\Sales\Model\AdminOrder\Create $orderCreateModel * @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency - * @param \Bread\BreadCheckout\Model\Payment\Api\Client $paymentApiClient + * @param \Bread\BreadCheckout\Model\Payment\Api\Service $paymentApiClient * @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ public function __construct( @@ -72,7 +72,7 @@ public function __construct( \Bread\BreadCheckout\Helper\Catalog $helperCatalog, \Magento\Sales\Model\AdminOrder\Create $orderCreateModel, \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency, - \Bread\BreadCheckout\Model\Payment\Api\Client $paymentApiClient, + \Bread\BreadCheckout\Model\Payment\Api\Service $paymentApiClient, \Magento\Catalog\Api\ProductRepositoryInterface $productRepository ) { $this->checkoutSession = $checkoutSession; diff --git a/Log/BreadLogger.php b/Log/BreadLogger.php deleted file mode 100644 index 8180282a..00000000 --- a/Log/BreadLogger.php +++ /dev/null @@ -1,13 +0,0 @@ -scopeConfig = $scopeConfig; + parent::__construct($name, $handlers, $processors); + } + + /** + * Check if logging is enabled + * + * @return bool + */ + private function logEnabled(): bool + { + return $this->scopeConfig->isSetFlag('payment/breadcheckout/log_enabled'); + } + + /** + * Wrapper for debug log, if different log level is needed call parent log() method instead + * + * @param $data + * @param array $context + */ + public function write($data, array $context = array()) + { + if ($this->logEnabled()) { + if (!is_string($data)) { + $data = print_r($data, true); + } + $this->debug($data, $context); + } + } +} diff --git a/Model/Payment/Api/Client.php b/Model/Payment/Api/Client.php deleted file mode 100644 index 75514985..00000000 --- a/Model/Payment/Api/Client.php +++ /dev/null @@ -1,498 +0,0 @@ -helper = $helper; - $this->jsonHelper = $jsonHelper; - $this->storeResolver = $storeResolver; - $this->logger = $log; - parent::__construct($context, $registry); - } - - /** - * @param \Magento\Sales\Model\Order $order - */ - public function setOrder(\Magento\Sales\Model\Order $order) - { - $this->order = $order; - } - - /** - * Call API Cancel Method - * - * @param $breadTransactionId - * @param int $amount - * @param array $lineItems - * @return mixed - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function cancel($breadTransactionId, $amount = 0, $lineItems = []) - { - /* Check if already canceled in bread */ - $transaction = $this->getInfo($breadTransactionId); - if ($transaction['status'] === self::STATUS_CANCELED) { - return $transaction; - } - - $data = ['type' => 'cancel']; - - if (!$amount == 0) { - $data['amount'] = $amount; - } - - if (!empty($lineItems)) { - $data['lineItems'] = $lineItems; - } - - $result = $this->call($this->getUpdateTransactionUrl($breadTransactionId), $data); - - if ($result['status'] != self::STATUS_CANCELED) { - $this->logger->log(['ERROR'=>'Transaction cancel failed', 'RESULT'=>$result]); - throw new \Magento\Framework\Exception\LocalizedException( - __('Transaction cancel failed (current transaction status :' . $result->status . ')') - ); - } - - return $result; - } - - /** - * Call API Authorize Method - * - * @param $breadTransactionId - * @param $amount - * @param null $merchantOrderId - * @return mixed - * @throws \Exception - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function authorize($breadTransactionId, $amount, $merchantOrderId = null) - { - - $validateAmount = $this->getInfo($breadTransactionId); - - // set transaction id so it can be fetched for split payment cancel - $this->setBreadTransactionId($breadTransactionId); - - $breadAmount = trim($validateAmount['total']); - $amount = trim($amount); - - if (((int) $breadAmount != (int) $amount) && (abs((int)$breadAmount - (int)$amount) >= 2)) { - $this->logger->log( - [ - 'ERROR' =>'BREAD AMOUNT AND QUOTE AMOUNT MIS-MATCH', - 'BREAD AMOUNT' =>(int)$breadAmount, - 'QUOTE AMOUNT' =>(int)$amount, - 'RESULT' =>$validateAmount - ] - ); - throw new \Magento\Framework\Exception\LocalizedException( - __( - 'There was a mismatch between the Bread amount and the transaction amount, Please contact ' - . 'the store owner.' - ) - ); - } - - $data_array = ['type' => 'authorize']; - if ($merchantOrderId != null) { - $data_array['merchantOrderId'] = $merchantOrderId; - } - - $result = $this->call( - $this->getUpdateTransactionUrl($breadTransactionId), - $data_array - ); - - if ($result['status'] != self::STATUS_AUTHORIZED) { - $this->logger->log(['ERROR'=>'AUTHORIZATION FAILED', 'RESULT'=>$result]); - throw new \Magento\Framework\Exception\LocalizedException( - __('Transaction authorize failed (current transaction status : ' . $result['status'] . ').') - ); - } - - return $result; - } - - /** - * Call API Update Order Id - * - * @param $breadTransactionId - * @param $merchantOrderId - * @return mixed - * @throws \Exception - */ - public function updateOrderId($breadTransactionId, $merchantOrderId) - { - $result = $this->call( - $this->getTransactionInfoUrl($breadTransactionId), - ['merchantOrderId' => $merchantOrderId], - \Zend_Http_Client::PUT - ); - - return $result; - } - - /** - * Call API Update Order Id Capture Authorized Transaction Method - * - * @param $breadTransactionId - * @return mixed - * @throws \Exception - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function settle($breadTransactionId) - { - $result = $this->call( - $this->getUpdateTransactionUrl($breadTransactionId), - ['type' => 'settle'] - ); - - if ($result['status'] != self::STATUS_SETTLED) { - throw new \Magento\Framework\Exception\LocalizedException( - __('Transaction settle failed (current transaction status :' . $result['status'] . ')') - ); - } - - return $result; - } - - /** - * Call API Refund Method - * - * @param $breadTransactionId - * @param int $amount - * @param array $lineItems - * @return mixed - * @throws \Exception - */ - public function refund($breadTransactionId, $amount = 0, $lineItems = []) - { - $data = ['type' => 'refund']; - - if (!$amount == 0) { - $data['amount'] = $amount; - } - - if (!empty($lineItems)) { - $data['lineItems'] = $lineItems; - } - - return $this->call($this->getUpdateTransactionUrl($breadTransactionId), $data); - } - - /** - * Call API Get Info Method - * - * @param $breadTransactionId - * @return mixed - * @throws \Exception - */ - public function getInfo($breadTransactionId) - { - return $this->call( - $this->getTransactionInfoUrl($breadTransactionId), - [], - \Zend_Http_Client::GET - ); - } - - /** - * Submit cart data - * - * @param $data - * @return mixed - * @throws \Exception - */ - public function submitCartData($data) - { - return $this->call( - $this->helper->getCartCreateApiUrl(), - $data, - \Zend_Http_Client::POST - ); - } - - /** - * Use the “As low as” endpoint to calculate an “as low as” amount with compliant - * financing disclosure based on your default or alternate financing program. - * - * @param array $data - * @return mixed - * @throws Exception - */ - public function getAsLowAs($data) - { - $baseUrl = $this->helper->getTransactionApiUrl($this->getStoreId()); - $asLowAsUrl = join('/', [ trim($baseUrl, '/'), 'aslowas' ]); - return $this->call( - $asLowAsUrl, - $data, - \Zend_Http_Client::POST - ); - } - - /** - * Interact with the API - * - * @TODO switch over to using \Magento\Framework\HTTP\Client\Curl - * - * @param $url - * @param array $data - * @param string $method - * @return mixed - * @throws \Exception - */ - protected function call($url, array $data, $method = \Zend_Http_Client::POST) - { - $storeId = $this->getStoreId(); - $username = $this->helper->getApiPublicKey($storeId); - $password = $this->helper->getApiSecretKey($storeId); - - // @codingStandardsIgnoreStart - try { - $curl = curl_init($url); - curl_setopt($curl, CURLOPT_HEADER, 0); - curl_setopt($curl, CURLOPT_USERPWD, $username . ':' . $password); - curl_setopt($curl, CURLOPT_TIMEOUT, 30); - - if ($method == \Zend_Http_Client::POST) { - curl_setopt($curl, CURLOPT_POST, 1); - curl_setopt($curl, CURLOPT_HTTPHEADER, [ - 'Content-Type: application/json', - 'Content-Length: ' . strlen($this->jsonHelper->jsonEncode($data))]); - curl_setopt($curl, CURLOPT_POSTFIELDS, $this->jsonHelper->jsonEncode($data)); - } - - if ($method == \Zend_Http_Client::PUT) { - curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT'); - curl_setopt($curl, CURLOPT_POSTFIELDS, $this->jsonHelper->jsonEncode($data)); - } - - curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - $result = curl_exec($curl); - $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); - - if ($status != 200) { - $this->logger->log(curl_error($curl)); - - //TODO: rewrite this when API is updated to better handle errors, instead of searching through the description string - - // Need to explicitly say !== false instead of === true or something similar because of what strpos returns - $isSplitPayDecline = strpos($result, "There's an issue with authorizing the credit card portion") !== false; - - if ($isSplitPayDecline) { - - if($this->helper->isSplitPayAutoDecline()){ - $this->cancel($this->getBreadTransactionId()); - } - - $errorMessage = 'The credit/debit card portion of your transaction was declined. ' - . 'Please use a different card or contact your bank. Otherwise, you can still check out with ' - . 'an amount covered by your Bread loan capacity.'; - } else { - $errorMessage = 'Call to Bread API failed.'; - } - - throw new \Magento\Framework\Exception\LocalizedException( - __($errorMessage) - ); - } - } catch (\Throwable $e) { - $this->logger->log([ - 'USER' => $username, - 'PASSWORD' => $password, - 'URL' => $url, - 'STATUS' => $status, - 'DATA' => $data, - 'RESULT' => $result - ]); - - curl_close($curl); - throw $e; - } - - curl_close($curl); - // @codingStandardsIgnoreEnd - - $this->logger->log( - [ - 'USER' => $username, - 'PASSWORD' => $password, - 'URL' => $url, - 'DATA' => $data, - 'RESULT' => $result - ] - ); - - if (!$this->isJson($result)) { - throw new \Magento\Framework\Exception\LocalizedException( - __('API Response Is Not Valid JSON. Result: ' . $result) - ); - } - - return $this->jsonHelper->jsonDecode($result); - } - - /** - * Send cart sms - * - * @param string $cartId - * @param string $phone - * @return mixed - * @throws \Exception - */ - public function sendSms($cartId, $phone) - { - $baseUrl = $this->helper->getTransactionApiUrl($this->getStoreId()); - $sendSmsUrl = join('/', [ trim($baseUrl, '/'), 'carts', trim($cartId, '/'), 'text' ]); - $data = [ 'phone' => $phone ]; - return $this->call( - $sendSmsUrl, - $data, - \Zend_Http_Client::POST - ); - } - - /** - * Send cart email - * - * @param string $cartId - * @param string $email - * @param string $name - * @return mixed - * @throws \Exception - */ - public function sendEmail($cartId, $email, $name) - { - $baseUrl = $this->helper->getTransactionApiUrl($this->getStoreId()); - $sendEmailUrl = join('/', [ trim($baseUrl, '/'), 'carts', trim($cartId, '/'), 'email' ]); - $data = [ 'email' => $email, 'name' => $name ]; - return $this->call( - $sendEmailUrl, - $data, - \Zend_Http_Client::POST - ); - } - - /** - * - * @param $transactionId - * @param $trackingNumber - * @param $carrierName - * @return mixed - * @throws \Exception - */ - public function setShippingDetails($transactionId, $trackingNumber, $carrierName) - { - $baseUrl = $this->helper->getTransactionApiUrl($this->getStoreId()); - $setShippingDetailsUrl = join( - '/', - [ trim($baseUrl, '/'), 'transactions', trim($transactionId), 'shipment' ] - ); - $data = [ 'trackingNumber' => $trackingNumber, 'carrierName' => $carrierName ]; - return $this->call( - $setShippingDetailsUrl, - $data, - \Zend_Http_Client::POST - ); - } - - /** - * Form transaction info URI string - * - * @param $transactionId - * @return string - */ - protected function getTransactionInfoUrl($transactionId) - { - $baseUrl = $this->helper->getTransactionApiUrl($this->getStoreId()); - return join('/', [ trim($baseUrl, '/'), 'transactions', trim($transactionId, '/') ]); - } - - /** - * Form update transaction URI string - * - * @param $transactionId - * @return string - */ - protected function getUpdateTransactionUrl($transactionId) - { - $baseUrl = $this->helper->getTransactionApiUrl($this->getStoreId()); - return join( - '/', - [ trim($baseUrl, '/'), 'transactions/actions', trim($transactionId, '/') ] - ); - } - - /** - * Check a string to verify JSON format is valid - * - * @param $string - * @return bool - */ - protected function isJson($string) - { - try { - $this->jsonHelper->jsonDecode($string); - } catch (\Throwable $e) { - $this->logger->log($e->getMessage()); - return false; - } - return true; - } - - /** - * Returns current store ID - * - * @return int - */ - protected function getStoreId() - { - if (!isset($this->order)) { - return $this->storeResolver->getCurrentStoreId(); - } - return $this->order->getData('store_id'); - } -} diff --git a/Model/Payment/Api/Service.php b/Model/Payment/Api/Service.php new file mode 100644 index 00000000..08f2d5a5 --- /dev/null +++ b/Model/Payment/Api/Service.php @@ -0,0 +1,483 @@ +jsonSerializer = $jsonSerializer; + $this->storeManager = $storeManager; + $this->logger = $log; + $this->configHelper = $configHelper; + } + + /** + * @param Order $order + */ + public function setOrder(Order $order) + { + $this->order = $order; + } + + /** + * Cancel bread order + * + * @param $breadTransactionId + * @param int $amount + * @param array $lineItems + * @return mixed + * @throws LocalizedException + * @throws \Throwable + */ + public function cancel($breadTransactionId, $amount = 0, $lineItems = []) + { + /* Check if already canceled in bread */ + $transaction = $this->getInfo($breadTransactionId); + if($transaction['status'] === self::STATUS_CANCELED){ + return $transaction; + } + + $data = ['type' => 'cancel']; + + if (!$amount == 0) { + $data['amount'] = $amount; + } + + if (!empty($lineItems)) { + $data['lineItems'] = $lineItems; + } + + $result = $this->call($this->makeApiUrlFor('update_transaction', $breadTransactionId), $data); + + if ($result['status'] != self::STATUS_CANCELED) { + $this->logger->write(['ERROR'=>'Transaction cancel failed', 'RESULT'=>$result]); + throw new LocalizedException( + __('Transaction cancel failed (current transaction status :' . $result->status . ')') + ); + } + + return $result; + } + + /** + * Call API Authorize Method + * + * @param string $breadTransactionId + * @param string $amount + * @param string|null $merchantOrderId + * @return array + * @throws LocalizedException + * @throws \Throwable + */ + public function authorize($breadTransactionId, $amount, $merchantOrderId = null) + { + $validateAmount = $this->getInfo($breadTransactionId); + + if ($this->amountMismatch($validateAmount['total'], $amount)) { + $this->logger->write( + [ + 'ERROR' => 'BREAD AMOUNT AND QUOTE AMOUNT MIS-MATCH', + 'BREAD AMOUNT' => $validateAmount['total'], + 'QUOTE AMOUNT' => $amount, + 'RESULT' => $validateAmount + ] + ); + throw new LocalizedException( + __('Bread authorized amount ' . $validateAmount['total'] . ' but transaction expected ' . $amount) + ); + } + + $data_array = ['type' => 'authorize']; + if ($merchantOrderId != null) { + $data_array['merchantOrderId'] = $merchantOrderId; + } + + $result = $this->call( + $this->makeApiUrlFor('update_transaction', $breadTransactionId), $data_array + ); + + if ($result['status'] != self::STATUS_AUTHORIZED) { + $this->logger->write(['ERROR'=>'AUTHORIZATION FAILED', 'RESULT'=>$result]); + throw new LocalizedException( + __('Transaction authorize failed (current transaction status :' . $result->status . ')') + ); + } + + return $result; + } + + /** + * Compares amount authorized on bread side versus amount on magento order + * + * @param string $breadAmount + * @param string $magentoAmount + * @return bool + */ + private function amountMismatch($breadAmount,$magentoAmount) : bool + { + $amountMismatch = false; + + $breadAmount = (int)trim($breadAmount); + $magentoAmount = (int)trim($magentoAmount); + + if(($breadAmount != $magentoAmount) && (abs($breadAmount - $magentoAmount) >= 2)){ + $amountMismatch = true; + } + + return $amountMismatch; + } + + /** + * Call API update order id + * + * @param string $breadTransactionId + * @param string $merchantOrderId + * @return mixed + * @throws \Throwable + */ + public function updateOrderId($breadTransactionId, string $merchantOrderId) + { + $result = $this->call( + $this->makeApiUrlFor('info', $breadTransactionId), + ['merchantOrderId' => $merchantOrderId], + \Magento\Framework\HTTP\ZendClient::PUT + ); + + return $result; + } + + /** + * Call API update order id capture authorized transaction + * + * @param string $breadTransactionId + * @return mixed + * @throws \Throwable + */ + public function settle($breadTransactionId) + { + $result = $this->call( + $this->makeApiUrlFor('update_transaction', $breadTransactionId), ['type' => 'settle'] + ); + + if ($result['status'] != self::STATUS_SETTLED) { + throw new LocalizedException( + __('Transaction settle failed (current transaction status :' . $result['status'] . ')') + ); + } + + return $result; + } + + /** + * Call API refund + * + * @param string $breadTransactionId + * @param int $amount + * @param array $lineItems + * @return array + * @throws \Throwable + */ + public function refund($breadTransactionId, $amount = 0, $lineItems = []) + { + $data = ['type' => 'refund']; + + if (!$amount == 0) { + $data['amount'] = $amount; + } + + if (!empty($lineItems)) { + $data['lineItems'] = $lineItems; + } + + return $this->call($this->makeApiUrlFor('update_transaction', $breadTransactionId), $data); + } + + /** + * Call API get info + * + * @param $breadTransactionId + * @return array + * @throws \Throwable + */ + public function getInfo($breadTransactionId) + { + return $this->call( + $this->makeApiUrlFor('info', $breadTransactionId), [], \Magento\Framework\HTTP\ZendClient::GET + ); + } + + /** + * Submit cart data + * + * @param array $data + * @return array + * @throws \Throwable + */ + public function submitCartData($data) + { + return $this->call( + $this->makeApiUrlFor('cart_create'), $data, \Magento\Framework\HTTP\ZendClient::POST + ); + } + + /** + * Interact with the API + * + * @param $url + * @param array $data + * @param string $method + * @return array + * @throws \Throwable + */ + protected function call($url, array $data, $method = \Zend_Http_Client::POST) + { + $username = $this->configHelper->getApiPublicKey(); + $password = $this->configHelper->getApiSecretKey(); + + try { + $curl = curl_init($url); + curl_setopt($curl, CURLOPT_HEADER, 0); + curl_setopt($curl, CURLOPT_USERPWD, $username . ':' . $password); + curl_setopt($curl, CURLOPT_TIMEOUT, 30); + + if ($method == \Magento\Framework\HTTP\ZendClient::POST) { + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_HTTPHEADER, [ + 'Content-Type: application/json', + 'Content-Length: ' . strlen($this->jsonSerializer->serialize($data))]); + curl_setopt($curl, CURLOPT_POSTFIELDS, $this->jsonSerializer->serialize($data)); + } + + if ($method == \Magento\Framework\HTTP\ZendClient::PUT) { + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT'); + curl_setopt($curl, CURLOPT_POSTFIELDS, $this->jsonSerializer->serialize($data)); + } + + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + $result = curl_exec($curl); + $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + + if ($status != 200) { + $this->logger->write(curl_error($curl)); + + //TODO: rewrite this when API is updated to better handle errors, instead of searching through the description string + $isSplitPayDecline = strpos($result, "There's an issue with authorizing the credit card portion") !== false; + + if ($isSplitPayDecline) { + + if($this->configHelper->getConfigData('split_auto_cancel', true)){ + $this->cancel($this->getBreadTransactionId()); + } + + $errorMessage = 'The credit/debit card portion of your transaction was declined. ' + . 'Please use a different card or contact your bank. Otherwise, you can still check out with ' + . 'an amount covered by your Bread loan capacity.'; + } else { + $errorMessage = 'Call to Bread API failed.'; + } + + throw new \Magento\Framework\Exception\LocalizedException( + __($errorMessage) + ); + } + } catch (\Throwable $e) { + $this->logger->write([ + 'USER' => $username, + 'PASSWORD' => $password, + 'URL' => $url, + 'STATUS' => $status, + 'DATA' => $data, + 'RESULT' => $result + ]); + + curl_close($curl); + throw $e; + } + + curl_close($curl); + + $this->logger->write( + [ + 'USER' => $username, + 'PASSWORD' => $password, + 'URL' => $url, + 'DATA' => $data, + 'RESULT' => $result + ] + ); + + if (!$this->isJson($result)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('API Response Is Not Valid JSON. Result: ' . $result) + ); + } + + return $this->jsonSerializer->unserialize($result); + } + + /** + * Send cart sms + * + * @param string $cartId + * @param string $phone + * @return mixed + * @throws \Throwable + */ + public function sendSms($cartId, $phone) + { + $sendSmsUrl = $this->makeApiUrlFor('send_sms', $cartId); + $data = array('phone' => $phone); + return $this->call( + $sendSmsUrl, $data, \Magento\Framework\HTTP\ZendClient::POST + ); + } + + /** + * Send cart email + * + * @param string $cartId + * @param string $email + * @param string $name + * @return mixed + * @throws \Throwable + */ + public function sendEmail($cartId, $email, $name) + { + $sendEmailUrl = $this->makeApiUrlFor('send_email', $cartId); + $data = array('email' => $email, 'name' => $name); + return $this->call( + $sendEmailUrl, $data, \Magento\Framework\HTTP\ZendClient::POST + ); + } + + /** + * Call to set shipping details on bread order + * + * @param $transactionId + * @param $trackingNumber + * @param $carrierName + * @return mixed + * @throws \Throwable + */ + public function setShippingDetails($transactionId, $trackingNumber, $carrierName) + { + $updateShippingDetailsUrl = $this->makeApiUrlFor('update_shipping', $transactionId); + $data = array('trackingNumber' => $trackingNumber, 'carrierName' => $carrierName); + return $this->call( + $updateShippingDetailsUrl, $data, \Magento\Framework\HTTP\ZendClient::POST + ); + } + + /** + * Use the “As low as” endpoint to calculate an “as low as” amount with compliant + * financing disclosure based on your default or alternate financing program. + * + * @param array $data + * @return mixed + * @throws \Throwable + */ + public function getAsLowAs($data) + { + $asLowAsUrl = $this->makeApiUrlFor('aslowas'); + + return $this->call( + $asLowAsUrl, + $data, + \Magento\Framework\HTTP\ZendClient::POST + ); + } + + + /** + * Makes full api url path for given action + * + * @param $value + * @param null|string $breadTransactionId + * @return string + */ + public function makeApiUrlFor($value, $breadTransactionId = null): string + { + $requestedAction = sprintf(self::API_ACTIONS[$value], $breadTransactionId); + $transactionApiUrl = $this->configHelper->getTransactionApiEndpoint(); + + return $transactionApiUrl . $requestedAction; + } + + /** + * Check a string to verify JSON format is valid + * + * @param $string + * @return bool + */ + protected function isJson($string): bool + { + $isJson = true; + + try { + $this->jsonSerializer->unserialize($string); + } catch (InvalidArgumentException $e) { + $isJson = false; + } + + return $isJson; + } + + /** + * Wrapper for get store id + * + * @return mixed + * @throws NoSuchEntityException + */ + public function getStoreId() + { + return $this->storeManager->getStore()->getStoreId(); + } +} diff --git a/Model/Payment/Api/ServiceInterface.php b/Model/Payment/Api/ServiceInterface.php new file mode 100644 index 00000000..b440ce99 --- /dev/null +++ b/Model/Payment/Api/ServiceInterface.php @@ -0,0 +1,29 @@ + 'carts/', + 'info' => 'transactions/%s', + 'update_transaction' => 'transactions/actions/%s', + 'update_shipping' => 'transactions/%s/shipment', + 'send_sms' => 'carts/%s/text', + 'send_email' => 'carts/%s/email', + 'aslowas' => 'aslowas' + ]; + +} \ No newline at end of file diff --git a/Model/Payment/Method/Bread.php b/Model/Payment/Method/Bread.php index 0573128c..fd1accf6 100644 --- a/Model/Payment/Method/Bread.php +++ b/Model/Payment/Method/Bread.php @@ -37,12 +37,12 @@ class Bread extends \Magento\Payment\Model\Method\AbstractMethod public $_allowCurrencyCode = ['USD']; /** - * @var \Bread\BreadCheckout\Model\Payment\Api\Client + * @var \Bread\BreadCheckout\Model\Payment\Api\Service */ public $apiClient; /** - * @var \Bread\BreadCheckout\Helper\Log + * @var \Bread\BreadCheckout\Log\Logger */ public $breadLogger; @@ -95,7 +95,7 @@ class Bread extends \Magento\Payment\Model\Method\AbstractMethod * Construct Sets API Client And Sets Available For Checkout Flag * * @param \Magento\Framework\Model\Context $context - * @param \Bread\BreadCheckout\Model\Payment\Api\Client $apiClient + * @param \Bread\BreadCheckout\Model\Payment\Api\Service $apiClient * @param \Bread\BreadCheckout\Helper\Data $helper * @param \Bread\BreadCheckout\Helper\Quote $quoteHelper * @param \Magento\Framework\Json\Helper\Data $jsonHelper @@ -114,7 +114,7 @@ class Bread extends \Magento\Payment\Model\Method\AbstractMethod */ public function __construct( \Magento\Framework\Model\Context $context, - \Bread\BreadCheckout\Model\Payment\Api\Client $apiClient, + \Bread\BreadCheckout\Model\Payment\Api\Service $apiClient, \Bread\BreadCheckout\Helper\Data $helper, \Bread\BreadCheckout\Helper\Quote $quoteHelper, \Magento\Framework\Json\Helper\Data $jsonHelper, @@ -123,7 +123,7 @@ public function __construct( \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory, \Magento\Payment\Helper\Data $paymentData, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, - \Bread\BreadCheckout\Helper\Log $breadLogger, + \Bread\BreadCheckout\Log\Logger $breadLogger, \Magento\Payment\Model\Method\Logger $logger, \Magento\Checkout\Model\Session $checkoutSession, \Magento\Sales\Model\Order\Payment\Transaction\BuilderInterface $transactionBuilder, diff --git a/Observer/DispatchShipmentInfo.php b/Observer/DispatchShipmentInfo.php index 831a5507..760cdfd6 100644 --- a/Observer/DispatchShipmentInfo.php +++ b/Observer/DispatchShipmentInfo.php @@ -23,12 +23,12 @@ class DispatchShipmentInfo implements \Magento\Framework\Event\ObserverInterface private $helper; /** - * @var \Bread\BreadCheckout\Helper\Log $logger + * @var \Bread\BreadCheckout\Log\Logger $logger */ private $logger; /** - * @var \Bread\BreadCheckout\Model\Payment\Api\Client $client + * @var \Bread\BreadCheckout\Model\Payment\Api\Service $client */ private $client; @@ -44,9 +44,9 @@ class DispatchShipmentInfo implements \Magento\Framework\Event\ObserverInterface */ public function __construct( \Bread\BreadCheckout\Model\Payment\Method\Bread $breadPayment, - \Bread\BreadCheckout\Model\Payment\Api\Client $client, + \Bread\BreadCheckout\Model\Payment\Api\Service $client, \Bread\BreadCheckout\Helper\Data $helper, - \Bread\BreadCheckout\Helper\Log $logger, + \Bread\BreadCheckout\Log\Logger $logger, \Magento\Sales\Model\Order\Payment\TransactionFactory $transactionFactory ) { $this->breadPayment = $breadPayment; @@ -99,14 +99,14 @@ public function execute(Observer $observer) $trackingNumber, $carrierCode ); - $this->logger->log( + $this->logger->write( [ 'DISPATCH SHIPPING DETAILS' => $data, ] ); } catch (\Throwable $e) { - $this->logger->log($e->getMessage()); + $this->logger->write($e->getMessage()); } } } diff --git a/ViewModel/Js.php b/ViewModel/Js.php new file mode 100644 index 00000000..45cf4a76 --- /dev/null +++ b/ViewModel/Js.php @@ -0,0 +1,141 @@ +helper = $helper; + $this->packageInfo = $packageInfo; + $this->cache = $cache; + $this->curl = $curl; + $this->logger = $logger; + } + + /** + * Create JS Include HTML + * + * @return string + */ + public function getJsScriptString(): string + { + $breadJsScript = sprintf( + '', + $this->helper->getJsLibLocation(), + $this->helper->getApiPublicKey() + ); + + return $breadJsScript; + } + + /** + * Returns sentry json configuration + * + * @return string + */ + public function getSentryJsonConfiguration(): string + { + $dns = $this->getSentryDSN(); + return json_encode( + [ + '*' => [ + 'Bread_BreadCheckout/js/sentry/sentry-config' => [ + 'dns' => $dns, + 'pluginVersion' => $this->getModuleVersion(), + 'apiKey' => $this->helper->getApiPublicKey(), + 'isSentryEnabled' => $this->helper->isSentryEnabled() && $dns + ] + ] + ], + JSON_HEX_TAG + ); + } + + /** + * Get current module version + * + * @return string + */ + public function getModuleVersion(): string + { + return $this->packageInfo->getVersion('Bread_BreadCheckout'); + } + + /** + * Get Sentry DSN for magento 2 + * + * @return string + */ + private function getSentryDSN() + { + $sentryDSNIdentifier = 'sentry_dsn'; + + $dsn = $this->cache->load($sentryDSNIdentifier); + + if ($dsn) { + return $dsn; + } + + try { + $this->curl->setCredentials($this->helper->getApiPublicKey(), $this->helper->getApiSecretKey()); + $this->curl->get($this->helper::URL_LAMBDA_SENTRY_DSN); + + $response = json_decode($this->curl->getBody(), true); + + if (isset($response['error']) || !isset($response['dsn'])) { + $errorMessage = isset($response['error']) ? $response['error'] + : 'Incorrect Response Format: ' . json_encode($response); + $this->logger->write(['ERROR WHEN GETTING SENTRY DSN' => $errorMessage]); + return null; + } + + $dsn = $response['dsn']; + $this->cache->save($dsn, $sentryDSNIdentifier, [], 60 * 60); + + return $dsn; + } catch (\Throwable $e) { + $this->logger->write(['EXCEPTION WHEN GETTING SENTRY DSN' => $e->getMessage()]); + return null; + } + } +} \ No newline at end of file diff --git a/etc/di.xml b/etc/di.xml index 8d750b23..3928574f 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -7,7 +7,7 @@ - + Bread diff --git a/view/frontend/layout/catalog_product_view.xml b/view/frontend/layout/catalog_product_view.xml index c2f1bb48..31561cd5 100644 --- a/view/frontend/layout/catalog_product_view.xml +++ b/view/frontend/layout/catalog_product_view.xml @@ -5,7 +5,6 @@ - Bread\BreadCheckout\ViewModel\Product\View diff --git a/view/frontend/layout/default.xml b/view/frontend/layout/default.xml index ba6b24e8..4fe47613 100644 --- a/view/frontend/layout/default.xml +++ b/view/frontend/layout/default.xml @@ -3,7 +3,11 @@ - + + + Bread\BreadCheckout\ViewModel\Js + + diff --git a/view/frontend/templates/js.phtml b/view/frontend/templates/js.phtml new file mode 100644 index 00000000..328ed263 --- /dev/null +++ b/view/frontend/templates/js.phtml @@ -0,0 +1,14 @@ +getData('view_model'); +?> +helper->isActive()): ?> + + + getJsScriptString()?> +