Forum Replies Created

Viewing 15 replies - 1 through 15 (of 86 total)
  • If you’re curious, my record_credit_card_decline function basically just creates a row in a table for that IP address and is defined as follows:

    // Function to record card failures to a simple database by IP address.
    function record_credit_card_decline($order_id = NULL)
    {
    	$ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
    	if (!empty($ip_address))
    	{
    		// Insert a row into CREDIT_CARD_ATTEMPTS_TABLE
    		global $wpdb;
    		$insert = $wpdb->get_results( $wpdb->prepare("INSERT INTO " . $wpdb->prefix . CREDIT_CARD_ATTEMPTS_TABLE . " SET ip_address = '%s', order_id = '%s'", $ip_address, $order_id), OBJECT );
    	}
    	
    	// Send a php error as well (in case there was no IP address)
    	error_log("Recording credit card decline for order '$order_id' against IP '$ip_address'.");
    }

    If you copy this, be careful with $_SERVER['HTTP_X_FORWARDED_FOR']. That’s the $_SERVER variable I have to use because I’m behind a load balancer and would otherwise get the load balancer’s address.

    This is the function I use to check how many failures there have been for that IP in the past 24 hours:

    // Function to return how many credit card attempts there have been from the same IP address today.
    function credit_card_attempt_count()
    {
    	$ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
    	if (!empty($ip_address))
    	{
    		// Query the CREDIT_CARD_ATTEMPTS_TABLE table, defined as
    		// CREATE TABLE CREDIT_CARD_ATTEMPTS_TABLE (
    		//   id int(11) NOT NULL,
    		//   ip_address varchar(15) COLLATE utf8mb4_0900_ai_ci NOT NULL,
    		//   time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    		//   order_id int(11) DEFAULT NULL
    		// ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
    		
    		global $wpdb;
    		$yesterday = date('Y-m-d H:i:s', time() - (60*60*24));
    		$select_query = $wpdb->prepare('SELECT * FROM ' . $wpdb->prefix . CREDIT_CARD_ATTEMPTS_TABLE . ' WHERE ip_address = "%s" AND time > "%s"', $ip_address, $yesterday);
    		$select_results = $wpdb->get_results( $select_query, OBJECT );
    		$attempts = count($select_results);
    		return $attempts;
    	}
    	else
    	{
    		return 999;
    	}
    }

    Finally, the best place I’ve found to actually check those failure and block payments is here, by removing the eWay plugins form being available (and then customising the error message caused by no available gateways):

    // Plugin-agnostic method of removing the payment plugins.
    add_filter('woocommerce_available_payment_gateways', 'filter_woocommerce_available_payment_gateways', 10, 1);
    function filter_woocommerce_available_payment_gateways($gateways)
    {
    	if ( credit_card_attempt_count() >= CREDIT_CARD_MAXIMUM_ATTEMPTS )
    	{
    		unset($gateways['eway']);
    		unset($gateways['eway_payments']);
    	}
    	return $gateways;
    }
    
    // Customise the resulting error message.
    add_filter( 'woocommerce_no_available_payment_methods_message', function(){
    	return 'Sorry, there have been too many declined credit card attempts. Please contact us if you require assistance or wish to make alternate arrangements.';
    });

    (If you copy any of this, be careful, as this forum didn’t like the backquotes in my SQL statements. I’ve tried to clean ’em up but check your work!)

    • This reply was modified 1 year, 11 months ago by jaydisc.
    • This reply was modified 1 year, 11 months ago by jaydisc.
    • This reply was modified 1 year, 11 months ago by jaydisc.
    • This reply was modified 1 year, 11 months ago by jaydisc.

    Here are the hooks I am using to detect a failed payment:

    // Record a credit card decline if checkout fails.
    add_action( 'woocommerce_checkout_order_processed', 'custom_woocommerce_checkout_order_processed', 10, 3 );
    function custom_woocommerce_checkout_order_processed( $order_id, $posted_data, $order)
    {
    	error_log('Running custom_woocommerce_checkout_order_processed…');
    	if ( 'failed' === $order->get_status())
    	{
    		record_credit_card_decline($order->get_id());
    	}
    }
    
    // Record a credit card decline if order-pay (paying for OBO) fails.
    add_action( 'woocommerce_after_pay_action', 'custom_woocommerce_after_pay_action', 10, 1 );
    function custom_woocommerce_after_pay_action( $order )
    {
    	error_log('Running custom_woocommerce_after_pay_action…');
    	if ( 'failed' === $order->get_status())
    	{
    		record_credit_card_decline($order->get_id());
    	}
    }
    • This reply was modified 1 year, 11 months ago by jaydisc.
    Thread Starter jaydisc

    (@jaydisc)

    Ah, that’s perfect (woocommerce_eway_error_msg). Thank you. I will wait the release of v5 before implementing that, and yes, I will keep the error message very generic. Unfortunately, my site has to use guest checkout, so card testing is a major concern.

    Thread Starter jaydisc

    (@jaydisc)

    Actually, I think I just found the issue. In getErrorMessage($error_msg), for some reason you’re only showing the array_keys() for the ResponseMessages:

    $errors[] = ' (' . esc_html(implode(',', array_keys($this->ResponseMessage))) . ')';

    If I remove that, I get the expected results:

    $errors[] = ' (' . esc_html(implode(',', $this->ResponseMessage)) . ')';

    Thread Starter jaydisc

    (@jaydisc)

    Maybe I should be trying this with v5?

    Thread Starter jaydisc

    (@jaydisc)

    Sorry, that was a bad example. I also get the same outcome with any code, currently ‘D4460’. I’ve added a filter:

    add_filter('eway_code_description', 'custom_eway_code_description', 10, 2);
    function custom_eway_code_description($msg, $code)
    {
    	echo($msg);
    	echo($code);
    	return $msg;
    }

    But that isn’t getting invoked either.

    I can see that in class.WooCommerce.php, that $response->getErrorMessage is called ~ line 621 to set that error message:

    $error_msg = $response->getErrorMessage(esc_html__('Transaction failed', 'eway-payment-gateway'));

    When I look at EwayResponse::getErrorMessage, I don’t see any reference to getCodeDescription(), which is what seems to offer nicer messages as well as your hook point. It just grabs $this->Errors and $this->ResponseMessage (where eWay’s code is), and returns them imploded over <br>’s.

    Thread Starter jaydisc

    (@jaydisc)

    Awesome. Thank you. Can I get the dev version from GitHub? I don’t seem to see branches or any tags ~ 5.x though. Is it just the latest master?

    That fix looks great. Much cleaner.

    Thread Starter jaydisc

    (@jaydisc)

    I’ve done some digging… It would appear that the Customer Payment Page, UNLIKE the Checkout page, dose NOT run the submit handler in WC’s checkout.js file.

    Therefore, checkout.js never triggers the “checkout_place_order_eway_payments” hook, and thus, EPG’s ecrypt.js, which binds processFields to that hook, never runs processFields, and the fields never get encrypted.

    I tried to directly bind ecrypt.js’s processFields to the submit event on the differently named form on the Customer Payment page, by adding this ~line 213:

    $('form#order_review').on("submit", processFields);

    But processFields and some other functions rely on the checkout variable, so I had to update that too. So, in the end, I inserted these lines from ~line 212:

    if (checkout.length == 0)
    	{
    		console.log('No checkout form. Switching to #order_review');
    		checkout = $('form#order_review');
    		checkout.on("submit", processFields);
    	}

    In situ:

    switch (eway_ecrypt_vars.mode) {
        case "woocommerce":
          checkout.on("checkout_place_order_eway_payments", processFields);
          $(document.body).on("checkout_error", resetEncryptedFields);
    	  
    	if (checkout.length == 0)
    	{
    		console.log('No checkout form. Switching to #order_review');
    		checkout = $('form#order_review');
    		checkout.on("submit", processFields);
    	}
    	  
          break;

    This now enables field encryption on the Customer Payment page, but I suspect there might be a more elegant way to do this?

    Thread Starter jaydisc

    (@jaydisc)

    Just to clarify, it looks like I am getting SOME international results, but we are only able to ship via EMS (that is the only International POS Indonesia service we have selected).

    Works for 116 grams and 192 grams, BUT NOT for 154!

    Thread Starter jaydisc

    (@jaydisc)

    Firstly, I’m sorry, but the only-one-product-at-checkout was an unrelated issue on our side. That has been resolved.

    The problem we have is that we know of all of our costs in IDR (our shipping plugin fetches values in IDR) but because we can not get a payment gateway that processes IDR, we have to switch to USD. But we don’t want to figure out the USD equivalent for our products every day, so this plugin does that for our products wonderfully. We keep our shop set to USD, our products are entered in IDR, and this plugin does the magic.

    BUT, our shipping plugin is fetching IDR prices, but your plug is assuming it is USD and is multiplying it by ~14000 (the USD to IDR rate), which of course doesn’t work for us.

    Is there a way we can tell your plugin that the shipping rate is in IDR so it converts it to USD for us like it’s doing for the products?

    • This reply was modified 4 years, 4 months ago by jaydisc.
    • This reply was modified 4 years, 4 months ago by jaydisc.
    Thread Starter jaydisc

    (@jaydisc)

    Hi @kenil802, I have sent an email from the product page. Perhaps we could continue the discussion there?

    Thread Starter jaydisc

    (@jaydisc)

    Ok, it has to be manually imported under Analytics → Settings… not the best onboarding…

    Thread Starter jaydisc

    (@jaydisc)

    I guess my first question should always be: can I downgrade? I have all the old files, but this upgrade had me perform a database upgrade. Is that reversible? Will it adversely affect me if I try to back down?

    Thread Starter jaydisc

    (@jaydisc)

    @gbroochian

    @conschneider Neither of those is the reason why square shows the simple product as a variation. The reason is very simple, its because of how the variation is named.

    Fan-bloody-tastic! That’s exactly the kind of info I’m looking for. Thank you. I can even go into Square and rename the existing variants to “Regular” and it goes back to normal. THANK YOU!

    • This reply was modified 4 years, 11 months ago by jaydisc.
    Thread Starter jaydisc

    (@jaydisc)

    How did you go?

Viewing 15 replies - 1 through 15 (of 86 total)