diff --git a/assets/javascripts/front/checkout/model/payment/card.js b/assets/javascripts/front/checkout/model/payment/card.js index 6c59d9e5..3abe978e 100644 --- a/assets/javascripts/front/checkout/model/payment/card.js +++ b/assets/javascripts/front/checkout/model/payment/card.js @@ -1,5 +1,5 @@ /* globals wc_pagarme_checkout */ - +/*jshint esversion: 8 */ let pagarmeCard = { limitTokenize: 10, tokenExpirationAttribute: 'data-pagarmecheckout-expiration', @@ -7,6 +7,7 @@ let pagarmeCard = { brandTarget: 'input[data-pagarmecheckout-element="brand-input"]', valueTarget: 'input[data-pagarmecheckout-element="order-value"]', installmentsTarget: '[data-pagarme-component="installments"]', + installmentsInfoTarget: '[data-pagarme-component="installments-info"]', mundiCdn: 'https://cdn.mundipagg.com/assets/images/logos/brands/png/', tokenElement: '[data-pagarmecheckout-element="token"]', fieldsetCardElements: 'fieldset[data-pagarmecheckout="card"]', @@ -255,22 +256,26 @@ let pagarmeCard = { if (!elem) { return false; } - let brand = elem.closest('fieldset').find(this.brandTarget).val(); + const brand = elem.closest('fieldset').find(this.brandTarget).val(); let total = elem.closest('fieldset').find(this.valueTarget).val(); if (total) { total = pagarmeCard.formatValue(total); } - let cardForm = elem.closest("fieldset"); - let select = cardForm.find(this.installmentsTarget); - if (!total) + const cardForm = elem.closest("fieldset"); + const select = cardForm.find(this.installmentsTarget); + const info = cardForm.find(this.installmentsInfoTarget); + if (!total) { total = cartTotal; + } if ((!total) || (select.data("type") === 2 && !brand) || - (select.data("type") === 1 && elem.data('element') !== "order-value")) + (select.data("type") === 1 && elem.data('element') !== "order-value") + ) { return false; - let storageName = btoa(brand + total); + } + const storageName = btoa(brand + total); sessionStorage.removeItem(storageName); - let storage = sessionStorage.getItem(storageName); + const storage = sessionStorage.getItem(storageName); if (storage) { select.html(storage); } else { @@ -283,7 +288,7 @@ let pagarmeCard = { } }); ajax.done(function (response) { - pagarmeCard._done(select, storageName, cardForm, response); + pagarmeCard._done(select, info, storageName, cardForm, JSON.parse(response)); }); ajax.fail(function () { pagarmeCard._fail(cardForm); @@ -293,8 +298,14 @@ let pagarmeCard = { return true; }, - _done: function (select, storageName, event, response) { - select.html(response); + _done: function (select, info, storageName, event, response) { + if (info.length) { + info.addClass('pagarme-hidden'); + if(response.installmentsConfig > 1) { + info.removeClass('pagarme-hidden'); + } + } + select.html(response.optionsHtml); sessionStorage.setItem(storageName, response); this.removeLoader(event); }, diff --git a/assets/stylesheets/front/style.css b/assets/stylesheets/front/style.css index 84525fd0..39bf8db2 100644 --- a/assets/stylesheets/front/style.css +++ b/assets/stylesheets/front/style.css @@ -1,3 +1,7 @@ +.pagarme-hidden { + display: none!important; +} + #wcmp-checkout-errors { display: none; } @@ -67,6 +71,13 @@ pointer-events: none; } +#payment .payment_methods li[class*="pagarme"] .payment_box .pagarme-installments-info { + display: block; + margin: 0 .75em .25em; + font-size: .9em; + font-style: italic; +} + .woocommerce-order .woocommerce-message .pagarme-response p:last-child { margin-bottom: 0; } @@ -132,7 +143,7 @@ /* sm */ /* @media (min-width: 576px) { - + } */ /* md */ @@ -151,10 +162,10 @@ /* xl */ /* @media (min-width: 1200px) { - + } */ /* xxl */ /* @media (min-width: 1400px) { - + } */ diff --git a/languages/woo-pagarme-payments-pt_BR.mo b/languages/woo-pagarme-payments-pt_BR.mo index 4fba3925..bc6222dc 100644 Binary files a/languages/woo-pagarme-payments-pt_BR.mo and b/languages/woo-pagarme-payments-pt_BR.mo differ diff --git a/languages/woo-pagarme-payments-pt_BR.po b/languages/woo-pagarme-payments-pt_BR.po index 263c5d9d..ba34a62d 100644 --- a/languages/woo-pagarme-payments-pt_BR.po +++ b/languages/woo-pagarme-payments-pt_BR.po @@ -5,7 +5,7 @@ msgstr "" "Project-Id-Version: WooCommerce Pagar.me Payments 1.0\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/woo-pagarme-payments\n" "POT-Creation-Date: 2018-06-22 13:58-0300\n" -"PO-Revision-Date: 2024-01-17 10:24-0300\n" +"PO-Revision-Date: 2024-01-19 11:54-0300\n" "Last-Translator: Pagar.me\n" "Language-Team: \n" "Language: pt_BR\n" @@ -1287,3 +1287,18 @@ msgstr "Habilita boleto para assinatura" msgid "Activates billet payment method for subscriptions." msgstr "Ativa o método de pagamento de boleto para assinaturas." + +msgid "Allow installments for subscription" +msgstr "Permitir parcelamento para assinatura" + +msgid "Enable installments for subscription" +msgstr "Habilita parcelamento para assinatura" + +msgid "Activates credit card installments for subscriptions." +msgstr "Ativa parcelamento de cartão de crédito para assinaturas." + +msgid "Works only for monthly and yearly subscriptions." +msgstr "Funciona apenas para assinaturas mensais e anuais." + +msgid "Your cart has one or more daily or weekly subscription products, which do not allow installments." +msgstr "Seu carrinho possui um ou mais produtos de assinatura diário ou semanal, que não permitem parcelamentos." diff --git a/src/Block/Checkout/Form/Installments.php b/src/Block/Checkout/Form/Installments.php index f19390e3..3f3642bc 100644 --- a/src/Block/Checkout/Form/Installments.php +++ b/src/Block/Checkout/Form/Installments.php @@ -14,11 +14,10 @@ use Woocommerce\Pagarme\Block\Checkout\Gateway; use Woocommerce\Pagarme\Helper\Utils; use Woocommerce\Pagarme\Model\CardInstallments; +use Woocommerce\Pagarme\Model\Subscription; use Woocommerce\Pagarme\View\Checkouts; -global $woocommerce; - -defined( 'ABSPATH' ) || exit; +defined('ABSPATH') || exit; /** * Class Installments @@ -34,6 +33,19 @@ class Installments extends Gateway /** @var int */ protected $sequence = 1; + /** @var int */ + protected $cardInstallments; + + /** @var Subscription */ + protected $subscription; + + public function __construct() + { + parent::__construct(); + $this->cardInstallments = new CardInstallments(); + $this->subscription = new Subscription(); + } + /** * @param int $sequence * @return $this @@ -89,8 +101,7 @@ public function getInstallmentsComponent() public function render_installments($total) { - $cardInstallments = new CardInstallments(); - return $cardInstallments->getInstallmentsByType($total); + return $this->cardInstallments->getInstallmentsByType($total); } /** @@ -100,4 +111,42 @@ public function render() { return $this->render_installments($this->getCartTotals()); } + + /** + * @return bool + */ + public function isCcInstallmentTypeByFlag() { + $type = intval($this->cardInstallments->config->getCcInstallmentType()) ?? 1; + return $type === CardInstallments::INSTALLMENTS_BY_FLAG; + } + + /** + * @return int + */ + public function getConfiguredMaxCcInstallments(): int { + if ($this->isCcInstallmentTypeByFlag()) { + $flag = Utils::get('flag', false, 'esc_html'); + $configByFlags = $this->cardInstallments->config->getCcInstallmentsByFlag(); + return intval($configByFlags['max_installment'][$flag]); + } + return intval($this->cardInstallments->config->getCcInstallmentsMaximum()); + } + + /** + * @return bool + */ + public function showOneInstallmentInfo() + { + if (!Subscription::hasSubscriptionProductInCart()) { + return false; + } + if ( + $this->subscription->allowInstallments() + && $this->subscription->hasOneInstallmentPeriodInCart() + && ($this->getConfiguredMaxCcInstallments() > 1 || $this->isCcInstallmentTypeByFlag()) + ) { + return true; + } + return false; + } } diff --git a/src/Block/Checkout/Gateway.php b/src/Block/Checkout/Gateway.php index 97185951..d540350f 100644 --- a/src/Block/Checkout/Gateway.php +++ b/src/Block/Checkout/Gateway.php @@ -84,10 +84,13 @@ public function getConfigDataProvider() /** * @param string $id - * @return string + * @return string | null */ public function getElementId(string $id) { + if (!$this->getPaymentInstance()){ + return null; + } return WCMP_PREFIX . '[' . $this->getPaymentInstance()->getMethodCode() . ']' . $id; } diff --git a/src/Controller/Checkout.php b/src/Controller/Checkout.php index 637d8a2e..47b7ebb6 100644 --- a/src/Controller/Checkout.php +++ b/src/Controller/Checkout.php @@ -8,6 +8,7 @@ use Pagarme\Core\Payment\Repositories\CustomerRepository; use Pagarme\Core\Payment\Repositories\SavedCardRepository; +use Woocommerce\Pagarme\Block\Checkout\Form\Installments; use Woocommerce\Pagarme\Controller\Gateways\AbstractGateway; use Woocommerce\Pagarme\Model\CardInstallments; use Woocommerce\Pagarme\Model\Config; @@ -27,13 +28,17 @@ class Checkout /** @var CardInstallments */ protected $cardInstallments; + /** @var Installments */ + protected $installments; + /** * @var Orders */ protected $ordersController; public function __construct( - CardInstallments $cardInstallments = null + CardInstallments $cardInstallments = null, + Installments $installments = null ) { $this->ordersController = new Orders(); add_action('woocommerce_api_' . Model\Checkout::API_REQUEST, array($this, 'process_checkout_transparent')); @@ -51,7 +56,11 @@ public function __construct( ]; $this->cardInstallments = $cardInstallments; if (!$this->cardInstallments) { - $this->cardInstallments = new CardInstallments; + $this->cardInstallments = new CardInstallments(); + } + $this->installments = $installments; + if (!$this->installments) { + $this->installments = new Installments(); } } @@ -109,13 +118,18 @@ public function build_installments() exit(0); } - $html = $this->cardInstallments->renderOptions( + $installmentsConfig = $this->installments->getConfiguredMaxCcInstallments(); + + $optionsHtml = $this->cardInstallments->renderOptions( $this->cardInstallments->getInstallmentsByType( Utils::get('total', false), Utils::get('flag', false, 'esc_html') )); - echo wp_kses_no_null($html); + echo json_encode([ + 'installmentsConfig' => $installmentsConfig, + 'optionsHtml' => wp_kses_no_null($optionsHtml) + ]); exit(); } diff --git a/src/Controller/Gateways/CreditCard.php b/src/Controller/Gateways/CreditCard.php index 176452eb..7285f70f 100644 --- a/src/Controller/Gateways/CreditCard.php +++ b/src/Controller/Gateways/CreditCard.php @@ -59,7 +59,7 @@ public function isSubscriptionActive(): bool */ public function append_form_fields() { - return [ + $fields = [ 'cc_operation_type' => $this->field_cc_operation_type(), 'cc_soft_descriptor' => $this->field_cc_soft_descriptor(), 'cc_flags' => $this->field_cc_flags(), @@ -71,8 +71,14 @@ public function append_form_fields() 'cc_installments_without_interest' => $this->field_cc_installment_fields('without_interest'), 'cc_installments_by_flag' => $this->field_cc_installment_fields('flags'), 'cc_allow_save' => $this->field_cc_allow_save(), - 'cc_allowed_in_subscription' => $this->field_cc_allowed_for_subscription(), + + ]; + if (Subscription::hasSubscriptionPlugin()) { + $fields['cc_allowed_in_subscription'] = $this->field_cc_allowed_for_subscription(); + $fields['cc_subscription_installments'] = $this->field_cc_subscription_installments(); + } + return $fields; } /** @@ -170,9 +176,6 @@ public function field_cc_allow_save() */ private function field_cc_allowed_for_subscription() { - if (!Subscription::hasSubscriptionPlugin()){ - return []; - } return [ 'title' => __('Active for subscription', 'woo-pagarme-payments'), 'type' => 'select', @@ -187,6 +190,25 @@ private function field_cc_allowed_for_subscription() ]; } + /** + * @return array + */ + private function field_cc_subscription_installments() + { + return [ + 'title' => __('Allow installments for subscription', 'woo-pagarme-payments'), + 'type' => 'select', + 'options' => $this->yesnoOptions->toLabelsArray(true), + 'label' => __('Enable installments for subscription', 'woo-pagarme-payments'), + 'default' => $this->config->getData('cc_subscription_installments') ?? strtolower(Yesno::NO), + 'desc_tip' => __('Activates credit card installments for subscriptions.', 'woo-pagarme-payments'), + 'description' => __('Works only for monthly and yearly subscriptions.', 'woo-pagarme-payments'), + 'custom_attributes' => array( + 'data-field' => 'cc-subscription-installments', + ), + ]; + } + /** * @return array */ diff --git a/src/Model/CardInstallments.php b/src/Model/CardInstallments.php index df7d1e2b..e7b0da83 100644 --- a/src/Model/CardInstallments.php +++ b/src/Model/CardInstallments.php @@ -11,7 +11,6 @@ namespace Woocommerce\Pagarme\Model; -use Woocommerce\Pagarme\Model\Subscription; use Woocommerce\Pagarme\Core; use Woocommerce\Pagarme\Helper\Utils; @@ -27,8 +26,10 @@ */ class CardInstallments { - /** @var */ - private $config; + /** @var Config */ + public $config; + + private $subscription; const INSTALLMENTS_FOR_ALL_FLAGS = 1; const INSTALLMENTS_BY_FLAG = 2; @@ -43,6 +44,7 @@ public function __construct( $config = new Config(); } $this->config = $config; + $this->subscription = new Subscription(); } /** @@ -148,7 +150,7 @@ public function renderOptions(array $options) /** * @param array $params - * @return string + * @return array */ private function calcInstallments1(array $params) { @@ -158,7 +160,7 @@ private function calcInstallments1(array $params) /** * @param array $params - * @return string + * @return array */ private function calcInstallments2(array $params) { @@ -183,9 +185,11 @@ private function calcInstallments2(array $params) * @param string|bool $flag * @return int */ - private function getMaxCcInstallments($type, $flag) + public function getMaxCcInstallments($type, $flag) { - if (Subscription::hasSubscriptionProductInCart()) { + if ( + (Subscription::hasSubscriptionProductInCart() && !$this->subscription->allowInstallments()) + || $this->subscription->hasOneInstallmentPeriodInCart()) { return 1; } if ($type === self::INSTALLMENTS_BY_FLAG) { diff --git a/src/Model/Subscription.php b/src/Model/Subscription.php index ba87d60e..5aa5aa63 100644 --- a/src/Model/Subscription.php +++ b/src/Model/Subscription.php @@ -18,6 +18,7 @@ use Pagarme\Core\Payment\Repositories\CustomerRepository; use Pagarme\Core\Payment\Repositories\SavedCardRepository; use WC_Order; +use WC_Subscriptions_Product; use Woocommerce\Pagarme\Controller\Orders; use Woocommerce\Pagarme\Service\LogService; use Woocommerce\Pagarme\Service\CardService; @@ -29,15 +30,15 @@ class Subscription /** @var Config */ private $config; - /** @var string */ - const API_REQUEST = 'e3hpgavff3cw'; - /** @var Orders */ private $orders; /** @var AbstractGateway */ private $payment; + /** @var array */ + const ONE_INSTALLMENT_PERIODS = ['day', 'week']; + public function __construct( AbstractGateway $payment = null ) @@ -54,7 +55,7 @@ public function __construct( private function addSupportToSubscription(): void { - if (!$this->payment->hasSubscriptionSupport() || !$this->hasSubscriptionPlugin()) { + if (!$this->payment || !$this->payment->hasSubscriptionSupport() || !$this->hasSubscriptionPlugin()) { return; } @@ -93,6 +94,9 @@ private function addSupportToSubscription(): void private function setPaymentEnabled() { + if (!$this->payment) { + return; + } if (!$this->payment->isSubscriptionActive() && $this->hasSubscriptionProductInCart()) { $this->payment->enabled = "no"; } @@ -417,4 +421,33 @@ public static function canUpdatePaymentMethod($update, $new_payment_method, $sub } return $update; } + + /** + * @return boolean + */ + public function allowInstallments(): bool { + return wc_string_to_bool($this->config->getData('cc_subscription_installments')); + } + + /** + * @return boolean + */ + public function hasOneInstallmentPeriodInCart(): bool { + if (!$this->hasSubscriptionPlugin()) { + return false; + } + + $cartProducts = WC()->cart->cart_contents; + $productsPeriods = []; + foreach ($cartProducts as $product) { + $productsPeriods[] = WC_Subscriptions_Product::get_period($product['product_id']); + } + + $noInstallmentsPeriods = array_intersect(self::ONE_INSTALLMENT_PERIODS, $productsPeriods); + if (!empty($noInstallmentsPeriods)) { + return true; + } + + return false; + } } diff --git a/templates/checkout/form/card/installments.phtml b/templates/checkout/form/card/installments.phtml index db30ef34..58cdbe70 100644 --- a/templates/checkout/form/card/installments.phtml +++ b/templates/checkout/form/card/installments.phtml @@ -15,15 +15,32 @@ if (!function_exists('add_action')) { exit(0); } ?> + -getInstallmentsComponent() ?> + data-total="getCartTotals()); ?>" data-type="getInstallmentsType(); ?>" + data-action="select2" data-required="true" data-element="installments" + name="getElementId('installment') ?>"> + isInterestForAllFlags()) : ?> + render() as $options) : ?> + + + + +