|
8 | 8 | use RM_PagBank\Connect\MenuPagBank; |
9 | 9 | use RM_PagBank\Connect\OrderMetaBoxes; |
10 | 10 | use RM_PagBank\Connect\OrderProcessor; |
| 11 | +use RM_PagBank\Connect\Payments\Boleto; |
11 | 12 | use RM_PagBank\Connect\Payments\CreditCard; |
12 | 13 | use RM_PagBank\Connect\Payments\Pix; |
13 | 14 | use RM_PagBank\Connect\Standalone\Pix as StandalonePix; |
|
19 | 20 | use RM_PagBank\Connect\Blocks\Redirect as RedirectBlock; |
20 | 21 | use RM_PagBank\Connect\Blocks\CreditCard as CreditCardBlock; |
21 | 22 | use RM_PagBank\Connect\Blocks\Pix as PixBlock; |
22 | | -use RM_PagBank\Connect\Blocks\PixDiscountTotals; |
23 | 23 | use RM_PagBank\Cron\CancelExpiredPix; |
24 | 24 | use RM_PagBank\Cron\ForceOrderUpdate; |
25 | 25 | use RM_PagBank\Helpers\Api; |
@@ -104,15 +104,10 @@ public static function init() |
104 | 104 | ); |
105 | 105 | } |
106 | 106 | //endregion |
107 | | - if (Params::getPixConfig('pix_show_discount_in_totals', 'no') === 'yes' && Params::getPixConfig('pix_discount', 0)) { |
108 | | - add_action('woocommerce_cart_totals_before_order_total', [__CLASS__, 'displayPixDiscountInCartTotals']); |
109 | | - add_action('woocommerce_review_order_before_order_total', [__CLASS__, 'displayPixDiscountInTotals']); |
110 | | - add_filter('woocommerce_cart_totals_order_total_html', [__CLASS__, 'filterOrderTotalHtmlWhenPixSelected'], 10, 1); |
111 | | - add_action('wp_enqueue_scripts', [__CLASS__, 'enqueuePixDiscountCheckoutScript'], 20); |
112 | | - add_action('rest_api_init', [PixDiscountTotals::class, 'registerFilter'], 20); |
113 | | - add_action('wp', [PixDiscountTotals::class, 'registerHydrationFilter'], 5); |
114 | | - add_action('woocommerce_blocks_loaded', [PixDiscountTotals::class, 'init']); |
115 | | - } |
| 107 | + } |
| 108 | + if ((Params::getPixConfig('enabled') === 'yes' && Params::getPixConfig('pix_discount', 0)) |
| 109 | + || (Params::getBoletoConfig('enabled') === 'yes' && Params::getBoletoConfig('boleto_discount', 0))) { |
| 110 | + add_action('woocommerce_cart_calculate_fees', [__CLASS__, 'addPaymentMethodDiscountFees'], 20); |
116 | 111 | } |
117 | 112 |
|
118 | 113 | //if force order update enabled |
@@ -827,163 +822,140 @@ public static function addPaymentInfoAdmin($order) |
827 | 822 | } |
828 | 823 |
|
829 | 824 | /** |
830 | | - * Whether PIX is currently selected as payment (legacy: rm-pagbank + ps_connect_method=pix; blocks: rm-pagbank-pix). |
| 825 | + * Whether a given payment method is currently selected (blocks: rm-pagbank-pix / rm-pagbank-boleto; |
| 826 | + * legacy: rm-pagbank + ps_connect_method=pix|boleto). Checks POST and post_data first so update_order_review |
| 827 | + * AJAX applies the fee before session is updated. |
831 | 828 | * |
| 829 | + * @param string $gatewayId Gateway ID (e.g. 'rm-pagbank-pix', 'rm-pagbank-boleto'). |
| 830 | + * @param string|null $subMethod Legacy sub-method when gateway is rm-pagbank (e.g. 'pix', 'boleto'). |
832 | 831 | * @return bool |
833 | 832 | */ |
834 | | - private static function isPixSelectedAsPayment(): bool |
| 833 | + public static function isPaymentMethodSelected(string $gatewayId, ?string $subMethod = null): bool |
835 | 834 | { |
| 835 | + $post_method = null; |
| 836 | + $post_data_parsed = null; |
| 837 | + |
| 838 | + if (!empty($_POST['payment_method'])) { |
| 839 | + $post_method = sanitize_text_field(wp_unslash($_POST['payment_method'])); |
| 840 | + } |
| 841 | + if ($post_method === null && !empty($_POST['post_data']) && is_string($_POST['post_data'])) { |
| 842 | + parse_str(wp_unslash($_POST['post_data']), $post_data_parsed); |
| 843 | + $post_method = isset($post_data_parsed['payment_method']) ? sanitize_text_field($post_data_parsed['payment_method']) : null; |
| 844 | + } |
| 845 | + if ($post_data_parsed === null && !empty($_POST['post_data']) && is_string($_POST['post_data'])) { |
| 846 | + parse_str(wp_unslash($_POST['post_data']), $post_data_parsed); |
| 847 | + } |
| 848 | + |
| 849 | + if ($post_method !== null) { |
| 850 | + if ($post_method === $gatewayId) { |
| 851 | + return true; |
| 852 | + } |
| 853 | + if ($post_method === self::DOMAIN && $subMethod !== null) { |
| 854 | + $sub = false; |
| 855 | + if (!empty($_POST['ps_connect_method']) && sanitize_text_field(wp_unslash($_POST['ps_connect_method'])) === $subMethod) { |
| 856 | + $sub = true; |
| 857 | + } |
| 858 | + if (!$sub && is_array($post_data_parsed) && isset($post_data_parsed['ps_connect_method']) && $post_data_parsed['ps_connect_method'] === $subMethod) { |
| 859 | + $sub = true; |
| 860 | + } |
| 861 | + if ($sub) { |
| 862 | + return true; |
| 863 | + } |
| 864 | + } |
| 865 | + if ($post_method !== $gatewayId && $post_method !== self::DOMAIN) { |
| 866 | + return false; |
| 867 | + } |
| 868 | + } |
| 869 | + |
836 | 870 | $chosen = WC()->session ? WC()->session->get('chosen_payment_method', '') : ''; |
837 | | - if ($chosen === 'rm-pagbank-pix') { |
| 871 | + if ($chosen === $gatewayId) { |
838 | 872 | return true; |
839 | 873 | } |
840 | 874 | if ($chosen !== self::DOMAIN) { |
841 | 875 | return false; |
842 | 876 | } |
843 | | - // Legacy checkout: gateway is rm-pagbank; sub-method is in post_data (ps_connect_method). |
844 | | - if (!empty($_POST['ps_connect_method'])) { |
845 | | - return sanitize_text_field(wp_unslash($_POST['ps_connect_method'])) === 'pix'; |
| 877 | + if ($subMethod !== null && !empty($_POST['ps_connect_method']) && sanitize_text_field(wp_unslash($_POST['ps_connect_method'])) === $subMethod) { |
| 878 | + return true; |
| 879 | + } |
| 880 | + if ($subMethod !== null && is_array($post_data_parsed) && isset($post_data_parsed['ps_connect_method']) && $post_data_parsed['ps_connect_method'] === $subMethod) { |
| 881 | + return true; |
846 | 882 | } |
847 | | - if (!empty($_POST['post_data']) && is_string($_POST['post_data'])) { |
848 | | - parse_str(wp_unslash($_POST['post_data']), $post_data); |
849 | | - return isset($post_data['ps_connect_method']) && $post_data['ps_connect_method'] === 'pix'; |
| 883 | + if ($subMethod !== null && $post_data_parsed === null && !empty($_POST['post_data']) && is_string($_POST['post_data'])) { |
| 884 | + parse_str(wp_unslash($_POST['post_data']), $post_data_parsed); |
| 885 | + return is_array($post_data_parsed) && isset($post_data_parsed['ps_connect_method']) && $post_data_parsed['ps_connect_method'] === $subMethod; |
850 | 886 | } |
851 | 887 | return false; |
852 | 888 | } |
853 | 889 |
|
854 | 890 | /** |
855 | | - * Outputs PIX discount and "Total no PIX" rows on the cart page (always, when discount is configured). |
| 891 | + * Adds PIX/Boleto discount fees when the respective method is selected at checkout. |
| 892 | + * Called from woocommerce_cart_calculate_fees; tries each method that has discount configured. |
856 | 893 | * |
| 894 | + * @param \WC_Cart $cart Cart instance. |
857 | 895 | * @return void |
858 | 896 | */ |
859 | | - public static function displayPixDiscountInCartTotals(): void |
| 897 | + public static function addPaymentMethodDiscountFees($cart): void |
860 | 898 | { |
861 | | - if (!function_exists('is_cart') || !is_cart() || !WC()->cart || is_wc_endpoint_url('order-pay')) { |
862 | | - return; |
863 | | - } |
864 | | - if (Params::getPixConfig('enabled') !== 'yes') { |
865 | | - return; |
866 | | - } |
867 | | - $discountConfig = Params::getPixConfig('pix_discount', 0); |
868 | | - if (!Params::getDiscountType($discountConfig)) { |
869 | | - return; |
870 | | - } |
871 | | - $excludesShipping = Params::getPixConfig('pix_discount_excludes_shipping', 'no') === 'yes'; |
872 | | - $cartTotal = floatval(WC()->cart->get_total('edit')); |
873 | | - $shippingTotal = floatval(WC()->cart->get_shipping_total()); |
874 | | - $discount = Params::getDiscountValueForTotal($discountConfig, $cartTotal, $excludesShipping, $shippingTotal); |
875 | | - if ($discount <= 0) { |
876 | | - return; |
877 | | - } |
878 | | - $pixTitle = Params::getPixConfig('title', __('PIX via PagBank', 'pagbank-connect')); |
879 | | - $discountLabel = __('Desconto', 'pagbank-connect') . ' ' . $pixTitle; |
880 | | - $totalNoPix = $cartTotal - $discount; |
881 | | - $totalNoPixLabel = __('Total no PIX', 'pagbank-connect'); |
882 | | - ?> |
883 | | - <tr class="pagbank-pix-discount fee"> |
884 | | - <th><?php echo esc_html($discountLabel); ?></th> |
885 | | - <td data-title="<?php echo esc_attr($discountLabel); ?>"><?php echo wp_kses_post(wc_price(-$discount)); ?></td> |
886 | | - </tr> |
887 | | - <tr class="pagbank-pix-total-no-pix order-total"> |
888 | | - <th><?php echo esc_html($totalNoPixLabel); ?></th> |
889 | | - <td data-title="<?php echo esc_attr($totalNoPixLabel); ?>"><?php echo wp_kses_post(wc_price($totalNoPix)); ?></td> |
890 | | - </tr> |
891 | | - <?php |
| 899 | + self::addDiscountAsFeeForMethod($cart, 'pix'); |
| 900 | + self::addDiscountAsFeeForMethod($cart, 'boleto'); |
892 | 901 | } |
893 | 902 |
|
894 | 903 | /** |
895 | | - * Display Pix discount row in checkout totals only when PIX is the selected payment method. |
896 | | - * Relies on update_checkout (triggered on payment method change) so the fragment is re-rendered with session state. |
| 904 | + * Adds discount as a cart fee (negative) for one payment method when it is selected. |
897 | 905 | * |
| 906 | + * @param \WC_Cart $cart Cart instance. |
| 907 | + * @param string $method 'pix' or 'boleto'. |
898 | 908 | * @return void |
899 | 909 | */ |
900 | | - public static function displayPixDiscountInTotals() |
| 910 | + protected static function addDiscountAsFeeForMethod($cart, string $method): void |
901 | 911 | { |
902 | | - if (Params::getPixConfig('enabled') !== 'yes') { |
| 912 | + if (function_exists('is_cart') && is_cart()) { |
903 | 913 | return; |
904 | 914 | } |
905 | | - if (!WC()->cart || is_wc_endpoint_url('order-pay')) { |
906 | | - return; |
907 | | - } |
908 | | - if (!self::isPixSelectedAsPayment()) { |
| 915 | + $config = [ |
| 916 | + 'pix' => [ |
| 917 | + 'enabled' => Params::getPixConfig('enabled') === 'yes', |
| 918 | + 'discount' => Params::getPixConfig('pix_discount', 0), |
| 919 | + 'excludes' => Params::getPixConfig('pix_discount_excludes_shipping', 'no') === 'yes', |
| 920 | + 'title' => Params::getPixConfig('title', __('PIX via PagBank', 'pagbank-connect')), |
| 921 | + 'gateway_id' => 'rm-pagbank-pix', |
| 922 | + 'sub_method' => 'pix', |
| 923 | + 'fee_id' => Pix::DISCOUNT_FEE_ID, |
| 924 | + ], |
| 925 | + 'boleto' => [ |
| 926 | + 'enabled' => Params::getBoletoConfig('enabled') === 'yes', |
| 927 | + 'discount' => Params::getBoletoConfig('boleto_discount', 0), |
| 928 | + 'excludes' => Params::getBoletoConfig('boleto_discount_excludes_shipping', 'no') === 'yes', |
| 929 | + 'title' => Params::getBoletoConfig('title', __('Boleto via PagBank', 'pagbank-connect')), |
| 930 | + 'gateway_id' => 'rm-pagbank-boleto', |
| 931 | + 'sub_method' => 'boleto', |
| 932 | + 'fee_id' => Boleto::DISCOUNT_FEE_ID, |
| 933 | + ], |
| 934 | + ]; |
| 935 | + if (!isset($config[$method])) { |
909 | 936 | return; |
910 | 937 | } |
911 | | - $discountConfig = Params::getPixConfig('pix_discount', 0); |
912 | | - if (!Params::getDiscountType($discountConfig)) { |
| 938 | + $c = $config[$method]; |
| 939 | + if (!$c['enabled'] || !self::isPaymentMethodSelected($c['gateway_id'], $c['sub_method'])) { |
913 | 940 | return; |
914 | 941 | } |
915 | | - $excludesShipping = Params::getPixConfig('pix_discount_excludes_shipping', 'no') === 'yes'; |
916 | | - $cartTotal = floatval(WC()->cart->get_total('edit')); |
917 | | - $shippingTotal = floatval(WC()->cart->get_shipping_total()); |
918 | | - $discount = Params::getDiscountValueForTotal($discountConfig, $cartTotal, $excludesShipping, $shippingTotal); |
919 | | - if ($discount <= 0) { |
| 942 | + if (!Params::getDiscountType($c['discount'])) { |
920 | 943 | return; |
921 | 944 | } |
922 | | - $pixTitle = Params::getPixConfig('title', __('PIX via PagBank', 'pagbank-connect')); |
923 | | - $discountLabel = __('Desconto', 'pagbank-connect') . ' ' . $pixTitle; |
924 | | - ?> |
925 | | - <tr class="pagbank-pix-discount fee"> |
926 | | - <th><?php echo esc_html($discountLabel); ?></th> |
927 | | - <td data-title="<?php echo esc_attr($discountLabel); ?>"><?php echo wp_kses_post(wc_price(-$discount)); ?></td> |
928 | | - </tr> |
929 | | - <?php |
930 | | - } |
931 | | - |
932 | | - /** |
933 | | - * When PIX is selected, replace the order total HTML with the discounted total. |
934 | | - * |
935 | | - * @param string $value Default order total HTML. |
936 | | - * @return string |
937 | | - */ |
938 | | - public static function filterOrderTotalHtmlWhenPixSelected(string $value): string |
939 | | - { |
940 | | - if (Params::getPixConfig('enabled') !== 'yes' || !WC()->cart) { |
941 | | - return $value; |
942 | | - } |
943 | | - if (!self::isPixSelectedAsPayment()) { |
944 | | - return $value; |
945 | | - } |
946 | | - $discountConfig = Params::getPixConfig('pix_discount', 0); |
947 | | - if (!Params::getDiscountType($discountConfig)) { |
948 | | - return $value; |
949 | | - } |
950 | | - $excludesShipping = Params::getPixConfig('pix_discount_excludes_shipping', 'no') === 'yes'; |
951 | | - $cartTotal = floatval(WC()->cart->get_total('edit')); |
952 | | - $shippingTotal = floatval(WC()->cart->get_shipping_total()); |
953 | | - $discount = Params::getDiscountValueForTotal($discountConfig, $cartTotal, $excludesShipping, $shippingTotal); |
| 945 | + $cartTotal = (float) $cart->get_cart_contents_total() + (float) $cart->get_shipping_total(); |
| 946 | + $shippingTotal = (float) $cart->get_shipping_total(); |
| 947 | + $discount = Params::getDiscountValueForTotal($c['discount'], $cartTotal, $c['excludes'], $shippingTotal); |
954 | 948 | if ($discount <= 0) { |
955 | | - return $value; |
956 | | - } |
957 | | - $totalWithDiscount = $cartTotal - $discount; |
958 | | - // Preserve tax suffix from original if present (e.g. "includes VAT"). |
959 | | - $suffix = ''; |
960 | | - if (preg_match('#<small class="includes_tax">(.+?)</small>#s', $value, $m)) { |
961 | | - $suffix = '<small class="includes_tax">' . $m[1] . '</small>'; |
962 | | - } |
963 | | - return '<strong>' . wp_kses_post(wc_price($totalWithDiscount)) . '</strong> ' . $suffix; |
964 | | - } |
965 | | - |
966 | | - /** |
967 | | - * Enqueue script that triggers update_checkout when payment method changes |
968 | | - * (same approach as Pix por Piggly), so the server re-renders totals with the correct PIX discount. |
969 | | - * |
970 | | - * @return void |
971 | | - */ |
972 | | - public static function enqueuePixDiscountCheckoutScript() |
973 | | - { |
974 | | - if (!is_checkout() || empty(WC()->cart)) { |
975 | | - return; |
976 | | - } |
977 | | - if (Params::getPixConfig('enabled') !== 'yes') { |
978 | | - return; |
979 | | - } |
980 | | - if (Params::getPixConfig('pix_show_discount_in_totals', 'no') !== 'yes' || !Params::getPixConfig('pix_discount', 0)) { |
981 | 949 | return; |
982 | 950 | } |
983 | | - $script = "!function(a){\"use strict\";a(function(){a(document.body).on(\"change\",\"input[name=\\\"payment_method\\\"]\",function(){a(\"body\").trigger(\"update_checkout\")})})}(jQuery);"; |
984 | | - wp_register_script('pagbank-pix-checkout-update', false, ['jquery'], WC_PAGSEGURO_CONNECT_VERSION, true); |
985 | | - wp_enqueue_script('pagbank-pix-checkout-update'); |
986 | | - wp_add_inline_script('pagbank-pix-checkout-update', $script, 'after'); |
| 951 | + $discountLabel = __('Desconto', 'pagbank-connect') . ' ' . $c['title']; |
| 952 | + $cart->fees_api()->add_fee([ |
| 953 | + 'id' => $c['fee_id'], |
| 954 | + 'name' => $discountLabel, |
| 955 | + 'amount' => -$discount, |
| 956 | + 'taxable' => false, |
| 957 | + 'tax_class' => '', |
| 958 | + ]); |
987 | 959 | } |
988 | 960 |
|
989 | 961 | /** |
|
0 commit comments