Changeset 2552573
- Timestamp:
- 06/23/2021 10:02:32 AM (5 years ago)
- Location:
- beyond-pay-for-woocommerce/trunk
- Files:
-
- 1 added
- 4 edited
-
README.md (modified) (1 diff)
-
README.txt (modified) (2 diffs)
-
assets/js/beyondpay-admin-order.js (added)
-
beyondpay-gateway.php (modified) (2 diffs)
-
includes/wc-beyond-pay-gateway.php (modified) (26 diffs)
Legend:
- Unmodified
- Added
- Removed
-
beyond-pay-for-woocommerce/trunk/README.md
r2513950 r2552573 135 135 ## Changelog 136 136 137 ### 1.5.0 138 * 'Save Card ONLY' transaction mode added. 139 137 140 ### 1.4.2 138 141 * Verbose logging mode support added. -
beyond-pay-for-woocommerce/trunk/README.txt
r2513976 r2552573 3 3 Tags: credit card, payment, woocommerce, payment gateway, subscriptions, subscription payments, recurring billing 4 4 Requires at least: 4.7 5 Tested up to: 5. 66 Stable tag: 1.4.25 Tested up to: 5.7.2 6 Stable tag: trunk 7 7 Requires PHP: 7.0 8 8 License: MIT … … 122 122 == Changelog == 123 123 124 = 1.5.0 = 125 * 'Save Card ONLY' transaction mode added. 126 124 127 = 1.4.2 = 125 128 * Debug mode support added. -
beyond-pay-for-woocommerce/trunk/beyondpay-gateway.php
r2513950 r2552573 6 6 * Author URI: https://getbeyond.com 7 7 * Plugin URI: https://developer.getbeyond.com 8 * Version: 1. 4.28 * Version: 1.5.0 9 9 * Text Domain: beyond-pay-for-woocommerce 10 10 * 11 * Tested up to: 5.7. 012 * WC tested up to: 5. 1.011 * Tested up to: 5.7.2 12 * WC tested up to: 5.4.0 13 13 * 14 14 * Copyright (c) 2020 Above and Beyond Business Tools and Services for Entrepreneurs, Inc. 15 15 * 16 * This program is free software: you can redistribute it and/or modify 17 * it under the terms of the GNU General Public License as published by 18 * the Free Software Foundation, either version 3 of the License, or 19 * (at your option) any later version. 20 * 21 * This program is distributed in the hope that it will be useful, 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 * GNU General Public License for more details. 25 * 26 * You should have received a copy of the GNU General Public License 27 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 * Review the LICENSE file for licensing information. 28 17 */ 29 18 … … 78 67 $beyond_pay_gateway->process_subscription_payment( $amount_to_charge, $order ); 79 68 } 69 70 add_filter('woocommerce_register_shop_order_post_statuses', 'beyond_pay_add_saved_card_status'); 71 72 function beyond_pay_add_saved_card_status($statuses) { 73 $statuses['wc-bp-tokenized'] = array( 74 'label' => 'Saved Card', 75 'public' => false, 76 'exclude_from_search' => false, 77 'show_in_admin_all_list' => true, 78 'show_in_admin_status_list' => true, 79 'label_count' => _n_noop('Saved Card <span class="count">(%s)</span>', 'Saved Card <span class="count">(%s)</span>', 'beyond-pay-gateway'), 80 ); 81 return $statuses; 82 } 83 84 add_filter('wc_order_statuses', 'beyond_pay_add_saved_card_to_order_statuses'); 85 86 function beyond_pay_add_saved_card_to_order_statuses($order_statuses) { 87 $order_statuses['wc-bp-tokenized'] = 'Saved Card'; 88 return $order_statuses; 89 } 90 91 92 add_filter('woocommerce_order_is_pending_statuses', 'beyond_pay_mark_saved_card_as_pending_status'); 93 94 function beyond_pay_mark_saved_card_as_pending_status($statuses) { 95 array_push($statuses, 'wc-bp-tokenized'); 96 return $statuses; 97 } 98 99 add_action('woocommerce_order_actions_end', 'beyond_pay_add_process_order_button'); 100 101 function beyond_pay_add_process_order_button($order_id){ 102 $order = wc_get_order($order_id); 103 104 if($order->get_meta('_beyond_pay_tokenized')){ 105 ?> 106 <li class="wide"> 107 <button type="button" class="button" onclick="beyondPayProcessTokenizedOrder('<?php echo esc_url(get_edit_post_link( $order_id ) ); ?>',<?php echo $order_id ?>)"> 108 Process Payment 109 </a> 110 </li> 111 <?php } 112 } 113 114 add_action('wp_ajax_beyond_pay_process_tokenized_order', 'beyond_pay_handle_saved_card_processing'); 115 116 function beyond_pay_handle_saved_card_processing(){ 117 $order_id = intval($_POST['order_id']); 118 if($order_id){ 119 $beyond_pay_gateway = wc_get_payment_gateway_by_order($order_id); 120 if($beyond_pay_gateway){ 121 $result = $beyond_pay_gateway->process_tokenized_payment($order_id); 122 die(json_encode($result)); 123 } 124 } 125 die(json_encode(array( 126 'success' => false, 127 'message' => 'Unable to deterimine order.' 128 ))); 129 } 130 131 add_action('admin_enqueue_scripts', 'beyond_pay_enqueue_woocommerce_scripts'); 132 133 function beyond_pay_enqueue_woocommerce_scripts(){ 134 wp_enqueue_script('beyondpay_admin_order', plugins_url('assets/js/beyondpay-admin-order.js', __FILE__)); 135 } -
beyond-pay-for-woocommerce/trunk/includes/wc-beyond-pay-gateway.php
r2513950 r2552573 3 3 class WC_Beyond_Pay_Gateway extends WC_Payment_Gateway { 4 4 5 /**6 * Class constructor, more about it in Step 37 */8 5 public function __construct() { 9 6 … … 58 55 $this->get_option('test_password') : 59 56 $this->get_option('password'); 60 $this->transaction_mode = $this->get_option('transaction_mode') == "sale" ? "sale" : "sale-auth"; 57 $this->transaction_mode = 58 $this->get_option('transaction_mode') == "sale" ? "sale" : 59 $this->get_option('transaction_mode') == "authorization" ? "sale-auth" : 60 'tokenize_only'; 61 61 $this->merchant_code = $this->get_option('merchant_code'); 62 62 $this->merchant_account_code = $this->get_option('merchant_account_code'); … … 161 161 'options' => [ 162 162 'sale' => 'Sale', 163 'authorization' => 'Authorization' 163 'authorization' => 'Authorization', 164 'tokenize_only' => 'Save Card ONLY' 164 165 ], 165 'description' => 'Sale mode will capture the payment instantly, ' 166 . 'authorization will only authorize when order is placed and capture' 167 . ' once order status changes to completed.', 166 'description' => 167 '<ul>' 168 . '<li>Sale mode will capture the payment instantly;</li> ' 169 . '<li>Authorization will only authorize when order is placed and capture once order status changes to completed;</li>' 170 . '<li>Save Card ONLY allows you to securely store card numbers without any initial authorization and then later charge the card from the Order Details page. NOTE: You must select “Process Payment” on the Order Details page in order to get paid in Save Card Only mode.</li>' 171 . '</ul>', 168 172 ), 169 173 'additional_data' => array( … … 253 257 if($this->cart_has_subscription()){ 254 258 echo "<p>Your payment method will be saved to process subscription payments.</p>"; 259 } else if($this->transaction_mode == 'tokenize_only') { 260 echo "<p>Your payment method will be securely saved and charged when your order is completed.</p>"; 255 261 } else { 256 262 $this->save_payment_method_checkbox(); … … 307 313 return true; 308 314 } 315 /** 316 * @param WC_Order $order 317 * @return boolean 318 */ 319 public function can_refund_order( $order ) { 320 return $order && !empty($order->get_transaction_id()) && empty($order->get_meta('_beyond_pay_tokenized')); 321 } 309 322 310 323 public function process_refund($order_id, $amount = null, $reason = '') { 311 324 $order = wc_get_order($order_id); 325 if($order->get_meta('_beyond_pay_tokenized')){ 326 $order->add_order_note("Order refund failed: this order was processed with 'Save Card ONLY' transaction mode and the payment was not processed, no refund should be needed."); 327 return false; 328 } 312 329 $request = $this->build_payment_request( 313 330 'refund', … … 316 333 null 317 334 ); 318 $conn = new BeyondPay\BeyondPayConnection(); 319 $response = $conn->processRequest($this->api_url, $request); 335 $response = $this->send_gateway_request($request, $order); 320 336 321 337 if ($response->ResponseCode == '00000') { 338 if($reason){ 339 $order->add_order_note("Order refunded, reason: $reason"); 340 } 322 341 return true; 323 342 } else { … … 335 354 intval($_POST['wc-beyondpay-payment-token']) : 336 355 false; 337 $save_token = !empty($_POST['wc-beyondpay-new-payment-method']) && $_POST['wc-beyondpay-new-payment-method'] === 'true'; 356 $is_tokenize_only = $this->transaction_mode === "tokenize_only"; 357 $save_token = 358 $is_tokenize_only || 359 (!empty($_POST['wc-beyondpay-new-payment-method']) && $_POST['wc-beyondpay-new-payment-method'] === 'true'); 338 360 $change_payment_for_order = !empty($_POST['woocommerce_change_payment']) ? 339 361 intval($_POST['woocommerce_change_payment']) : … … 351 373 ); 352 374 353 $conn = new BeyondPay\BeyondPayConnection(); 354 $response = $conn->processRequest($this->api_url, $request); 375 $response = $this->send_gateway_request($request); 355 376 356 377 if ($response->ResponseCode == '00000') { … … 377 398 378 399 if($pay_with_token){ 400 /** @var WC_Payment_Token - stored token */ 379 401 $token = $this->get_token($pay_with_token); 402 if($is_tokenize_only) { 403 $order->add_payment_token($token); 404 return $this->tokenize_only_order($order); 405 } 380 406 $request = $this->build_payment_request( 381 407 'token_payment', … … 383 409 $order->get_transaction_id(), 384 410 $token 411 ); 412 } else if($is_tokenize_only){ 413 $request = $this->build_payment_request( 414 'save_payment_method', 415 null, 416 null, 417 sanitize_key($_POST['beyond_pay_token']) 385 418 ); 386 419 } else { … … 393 426 } 394 427 395 $address = $order->get_address('billing'); 396 if (!empty($address)) { 397 $name = trim($address['first_name'] . ' ' . $address['last_name']); 398 $request->requestMessage->AccountHolderName = $name; 399 $request->requestMessage->AccountStreet = trim($address['address_1']); 400 if (!empty($address['phone'])) { 401 $address['phone'] = str_replace([' ', '-', '#', '+'], '', $address['phone']); 402 while (strlen($address['phone']) < 10) { 403 $address['phone'] = '0' . $address['phone']; 404 } 405 if (strlen($address['phone']) < 12) { 406 $request->requestMessage->AccountPhone = trim($address['phone']); 407 } 408 } 409 if (!empty($address['postcode'])) { 410 $postcode = str_replace('-', '', $address['postcode']); 411 if (is_numeric($postcode) && strlen($postcode) === 5) { 412 $request->requestMessage->AccountZip = $postcode; 413 } 414 } 415 } 428 $this->fill_address_data($request, $order); 416 429 417 430 $customer_id = $order->get_user_id(); … … 420 433 } 421 434 $request->requestMessage->InvoiceNum = $order_id; 422 $this->fill_level_2_3_data($request, $order); 423 424 $conn = new BeyondPay\BeyondPayConnection(); 425 $response = $conn->processRequest($this->api_url, $request); 426 $this->verbose_logging($order, $request, $response); 435 if(!$is_tokenize_only){ 436 $this->fill_level_2_3_data($request, $order); 437 } 438 $response = $this->send_gateway_request($request, $order); 427 439 428 440 if ($response->ResponseCode == '00000') { … … 432 444 $save_token 433 445 ) { 434 $t his->save_token_from_response(446 $token = $this->save_token_from_response( 435 447 $response, 436 448 $save_token || $this->connect_subscription_payments_with_users ? $order->get_user_id() : null, 437 449 $order 438 450 ); 451 if($is_tokenize_only) { 452 return $this->tokenize_only_order($order, $token); 453 } 439 454 } elseif ($pay_with_token) { 440 if (!empty($response->responseMessage->CardType) && $token->get_card_type() === 'Card'){ 441 $token->set_card_type($response->responseMessage->CardType); 442 $token->save(); 443 } 455 $this->update_card_type_on_token($response, $token); 444 456 $order->add_payment_token($token); 445 457 } … … 475 487 * @param BeyondPay\BeyondPayResponse $response 476 488 */ 477 private function verbose_logging($order, $request, $response) {489 private function verbose_logging($order, $request, $response) { 478 490 if($this->debug_mode) { 479 491 $is_successfull = $response->ResponseCode == '00000'; … … 529 541 } 530 542 $token->save(); 531 } elseif (!empty($response->responseMessage->CardType) && $token->get_card_type()==='Card'){ 543 } else { 544 $this->update_card_type_on_token($response, $token); 545 } 546 547 if(!empty($order)){ 548 $order->add_payment_token($token); 549 } 550 551 return $token; 552 } 553 554 /** 555 * Updates the card type if token has it missing and more accurate value is provided in response. 556 * @param BeyondPay\BeyondPayResponse $response 557 * @param WC_Payment_Token $token 558 */ 559 private function update_card_type_on_token($response, $token) { 560 if (!empty($response->responseMessage->CardType) && ($token->get_card_type() === 'Card' || empty($token->get_card_type()))) { 532 561 $token->set_card_type($response->responseMessage->CardType); 533 562 $token->save(); 534 563 } 535 536 if(!empty($order)){537 $order->add_payment_token($token);538 }539 540 return $token;541 564 } 542 565 … … 636 659 } 637 660 } 661 662 /** 663 * Update request with address data if available on order. 664 * @param BeyondPay\BeyondPayRequest $request The request to update 665 * @param WC_Order $order Order to fetch data from 666 */ 667 private function fill_address_data($request, $order){ 668 $address = $order->get_address('billing'); 669 if (!empty($address)) { 670 $name = trim($address['first_name'] . ' ' . $address['last_name']); 671 $request->requestMessage->AccountHolderName = $name; 672 $request->requestMessage->AccountStreet = trim($address['address_1']); 673 if (!empty($address['phone'])) { 674 $address['phone'] = str_replace([' ', '-', '#', '+'], '', $address['phone']); 675 while (strlen($address['phone']) < 10) { 676 $address['phone'] = '0' . $address['phone']; 677 } 678 if (strlen($address['phone']) < 12) { 679 $request->requestMessage->AccountPhone = trim($address['phone']); 680 } 681 } 682 if (!empty($address['postcode'])) { 683 $postcode = str_replace('-', '', $address['postcode']); 684 if (is_numeric($postcode) && strlen($postcode) === 5) { 685 $request->requestMessage->AccountZip = $postcode; 686 } 687 } 688 } 689 } 638 690 639 691 … … 671 723 continue; 672 724 } else { 673 try {725 try { 674 726 $token = new WC_Payment_Token_CC($tokens[0]); 675 727 } catch(exception $e) { … … 685 737 ); 686 738 $this->fill_level_2_3_data($request, $order); 687 688 $conn = new BeyondPay\BeyondPayConnection(); 689 $response = $conn->processRequest($this->api_url, $request); 690 $this->verbose_logging($order, $request, $response); 739 $response = $this->send_gateway_request($request, $order); 691 740 692 741 if ($response->ResponseCode == '00000') { … … 720 769 public function capture_authorised_payment($order){ 721 770 $request = $this->build_payment_request('capture', $order->get_total(), $order->get_transaction_id()); 722 723 $conn = new BeyondPay\BeyondPayConnection(); 724 $response = $conn->processRequest($this->api_url, $request); 771 $response = $this->send_gateway_request($request, $order); 725 772 if ($response->ResponseCode == '00000') { 726 773 $order->update_meta_data('_beyond_pay_processed', 1); … … 745 792 */ 746 793 public function build_payment_request($payment_type, $amount_to_charge = null, $reference_number = null, $token = null){ 794 $transaction_type = $this->transaction_mode === 'tokenize_only' ? 'sale' : $this->transaction_mode; 747 795 $configs = array( 748 796 'capture' => array( … … 754 802 'request_type' => '004', 755 803 'auth_with_token' => true, 756 'transaction_type' => $t his->transaction_mode804 'transaction_type' => $transaction_type 757 805 ), 758 806 'save_payment_method' => array( … … 769 817 'request_type' => '004', 770 818 'auth_with_token' => false, 771 'transaction_type' => $t his->transaction_mode819 'transaction_type' => $transaction_type 772 820 ), 773 821 'refund' => array( … … 816 864 } 817 865 $request->requestMessage->SoftwareVendor = 'WooCommerce Beyond Pay Plugin'; 818 file_put_contents('beyond.log','Transaction type: '.$config['transaction_type']."\n", FILE_APPEND);819 866 if($config['transaction_type']){ 820 867 $request->requestMessage->TransactionType = $config['transaction_type']; … … 822 869 823 870 $request->requestMessage->TransIndustryType = "EC"; 824 file_put_contents('beyond.log','Transaction type2: '.$config['transaction_type']."\n", FILE_APPEND);825 871 return $request; 872 } 873 874 /** 875 * 876 * @param BeyondPay\BeyondPayRequest $request 877 * @param WC_Order $order Optional, if not provided Debug Logging will not be performed for this request. 878 * @return BeyondPay\BeyondPayResponse 879 */ 880 public function send_gateway_request($request, $order = null){ 881 $conn = new BeyondPay\BeyondPayConnection(); 882 $response = $conn->processRequest($this->api_url, $request); 883 if($order){ 884 $this->verbose_logging($order, $request, $response); 885 } 886 return $response; 826 887 } 827 888 … … 844 905 ); 845 906 846 $conn = new BeyondPay\BeyondPayConnection(); 847 $response = $conn->processRequest($this->api_url, $request); 907 $response = $this->send_gateway_request($request); 848 908 849 909 if ($response->ResponseCode == '00000') { … … 887 947 } 888 948 949 /** 950 * Store the token for the "Save Card ONLY" transaction mode. 951 * @param WC_Order $order 952 */ 953 public function tokenize_only_order($order) { 954 global $woocommerce; 955 956 if(empty($order->get_payment_tokens())){ 957 return array( 958 'result' => 'failure', 959 'redirect' => $order->get_view_order_url() 960 ); 961 } 962 963 $order->add_meta_data('_beyond_pay_tokenized', 1); 964 $order->set_status('bp-tokenized'); 965 $order->payment_complete(); 966 $order->save_meta_data(); 967 $order->save(); 968 wc_reduce_stock_levels($order); 969 $order->add_order_note('Thank you for your order!', true); 970 $woocommerce->cart->empty_cart(); 971 972 return array( 973 'result' => 'success', 974 'redirect' => $this->get_return_url($order) 975 ); 976 } 977 978 /** 979 * The order processing after merchant presses the "Process Order" button for a saved card. 980 * @param int $order_id 981 * @return array An array with success:bool and optional message:string property. 982 */ 983 public function process_tokenized_payment($order_id) { 984 $order = wc_get_order($order_id); 985 $tokens = $order->get_payment_tokens(); 986 if(!empty($tokens)) { 987 try{ 988 $token = new WC_Payment_Token_CC($tokens[0]); 989 } catch(Exception $error) { 990 $order->add_order_note('Failed to process payment, payment method connected to order no longer exists or is not valid. Internal error: '.$error->getMessage()); 991 return array( 992 'success' => false, 993 'message' => 'Payment method connected to order no longer exists or is not valid.' 994 ); 995 } 996 $request = $this->build_payment_request('token_payment', $order->get_total(), $order->get_transaction_id(), $token); 997 $customer_id = $order->get_user_id(); 998 if (!empty($customer_id)) { 999 $request->requestMessage->CustomerAccountCode = $customer_id; 1000 } 1001 $request->requestMessage->InvoiceNum = $order_id; 1002 $this->fill_level_2_3_data($request, $order); 1003 $response = $this->send_gateway_request($request, $order); 1004 if ($response->ResponseCode == '00000') { 1005 $this->update_card_type_on_token($response, $token); 1006 $order->add_payment_token($token); 1007 $order->delete_meta_data('_beyond_pay_tokenized'); 1008 $order->save_meta_data(); 1009 $order->add_order_note('Your card has been charged for order #'.$order_id, true); 1010 $order->set_status('processing'); 1011 $order->set_transaction_id($response->responseMessage->GatewayTransID); 1012 $order->save(); 1013 $order->payment_complete($response->responseMessage->GatewayTransID); 1014 return array( 1015 'success' => true 1016 ); 1017 } else { 1018 $reason = $response->ResponseDescription.' ('.$response->ResponseCode.')'; 1019 $order->add_order_note('Processing saved card has failed due to: '.$reason); 1020 return array( 1021 'success' => false, 1022 'message' => $reason 1023 ); 1024 } 1025 } 1026 } 1027 889 1028 }
Note: See TracChangeset
for help on using the changeset viewer.