Skip to main content

WP, WC mail failed payment not sent. Payment gateway WC-Paypal, Yith-Stripe

How to test mail without wait ab 1 days, 2 days ?

The problem could be in payment gateway, not only WC.
https://docs.woocommerce.com/document/email-faq/
Standard Paypal troubleshoot: https://docs.woocommerce.com/document/paypal-standard/#section-20
Is  WC Paypal is default ?

Debug, not show error on site:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );

Log dump to wp-content/debug.log

There are many useful information about sending and receive email here. For example, addition information about Gmail free account limit up to 500 unique recipient in 24h period.
https://support.google.com/mail/answer/22839?hl=en

https://en-gb.wordpress.org/plugins/wp-mail-logging/

wp-content/plugins/post-smtp/Postman/Postman-Mail/
wp-mail-smtp

Suggested Dedicated SMTP Providers
Like Mailgun (plugin), Maildrill (plugin). Use this way we can test on Dev server instead of real Hosting like WPEngine. Dev server often lack of these Wordpress mail function (or server ?).
Certainly, this way introduce new bug, case that WPE itself mail function has problem. So be careful and clearly on this process.
There are many other issues that prevent we debug on staging/test server. For example, staging site is shared/used by many team (often two team, outsource + customer), so if we install some plugin, for send mail Mailgun, WP mail logging... or put some code debug to these server. Then it could be affect other test case, functions, generate many trash data to database...

Paypal standard
https://docs.woocommerce.com/document/paypal-standard/#section-20
WP mail
https://developer.wordpress.org/reference/functions/wp_mail/

https://www.flippercode.com/send-html-emails-using-wp-mail-wordpress/

https://stackoverflow.com/questions/39402755/simulate-stripe-subscription-renewal-failure

https://formidableforms.com/help-desk/failed-paypal-payment-email-notification-not-sent/

Update sub info, ie. end trial time or change default source (card):
We can not update trial end by Stripe Panel because of we are using error / invalid card for negative testing. When click save, error will occur.

curl https://api.stripe.com/v1/subscriptions/sub_D74qAwwXdb2jH6 \
   -u sk_test_uujpTqjYZx2eF4J66B5278H0: \
   -d tax_percent=10

Run update desc first to get current state:
Some thing like this
curl https://api.stripe.com/v1/customers/cus_D7RMbSXum154x3 \
   -u sk_test_uujpTqjYZx2eF4J66B5278H0 \
   -d description="Get detail customer"

From output result. Copy to editor then find the plan id (or subscription ID). Something like this:
product_50214_80c8d6bd8df23d7888bbd792f6d2a5f4
If there are many plan for current customer, it may be show many, show you have to find exactly subscription that currently work on.

Update trial_end: First we get current UNIX time, then add some amount to future time.
This unix time is in seconds from 1970 so 2 mins ~ + 120 in value.

$ date
Tue Jun 26 08:59:09 BST 2018
$ date -d 'Tue Jun 26 08:59:09 BST 2018' +"%s"
1529999949
date -d @1529999949
Tue Jun 26 08:59:09 BST 2018
We added ab 100s to current time, then set this value for payment plan trial_end.

        /**
         * Method triggered to send email
         *
         * @param int $subscription <<<<<<----------------- Bug here
         *
         * @return void
         * @since  1.0
         * @author Emanuela Castorina <emanuela.castorina@yithemes.com>
         */
        public function trigger( $subscription ) {

            $failed_attemps = $subscription->has_failed_attemps();     // :( :( :( call function on integer ?
            if( $failed_attemps['num_of_failed_attemps'] >= $failed_attemps['max_failed_attemps']){
             return;
            }

            $this->recipient = $subscription->get_billing_email();
         
            // Check if this email type is enabled, recipient is set
            if ( !$this->is_enabled() || !$this->get_recipient() ) {
                return;
            }

            $this->object = $subscription;

            $this->template_variables = array(
                'subscription'  => $this->object,
                'email_heading' => $this->get_heading(),
                'sent_to_admin' => false,
                'email'         => $this
            );
         
       


            $return = $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content_html(), $this->get_headers(), $this->get_attachments( ) );
        }

        /**
         * Get HTML content for the mail
         *
         * @return string HTML content of the mail
         * @since  1.0
         * @author Emanuela Castorina <emanuela.castorina@yithemes.com>
         */
        public function get_content_html() {
            ob_start();
            wc_get_template( $this->template_html, $this->template_variables, '', YITH_YWSBS_TEMPLATE_PATH.'/'  );     // reed + emails/
            return ob_get_clean();
        }

For trigger() function, after more investigation, we see that it not a big defect.
In the line: $this->object = $subscription; the data needed ($subscription) for email send is set and have correct value.
It is something magical since I do not have good experience in OOP.
The function call get_billing_email() is randomly return null, it can be caused by subscription data error.

 60 $failed_attemps = $subscription->has_failed_attemps();
 61 echo @$failed_attemps['max_failed_attempts']; 
 62 echo (!$failed_attemps['max_failed_attemps']) ? 'null max-attempt' : $failed_attemps['max_failed_attemps']. ' <- max attempt ';

Paypal negative testing
https://developer.paypal.com/docs/api/test-values/#negative-testing-steps
List PP test acc:
https://developer.paypal.com/developer/accounts

Get Paypal access token (sandbox).
https://stackoverflow.com/questions/8961544/how-do-i-get-identity-token-in-paypal-sandbox#
What ? PDT I have removed this value from staging.

How to get PP access token
https://www.paypal.com/vn/selfhelp/article/how-do-i-get-an-access-token-ts2128
For basic account, it require you have to activate (or upgrade ?) account to premier (?).

Find files modified within 24h
find . -mtime -1 -ls

Useful when not use version control when debugging new app.


if ( ! function_exists( 'ywsbs_get_max_failed_attemps_list' ) ) {

/**
* Return the list of max failed attempts for each compatible gateways
*
* @return array
*/

function ywsbs_get_max_failed_attemps_list() {
$arg = array(
'paypal'      => 3,
'yith-stripe' => 4
);

return apply_filters( 'ywsbs_max_failed_attemps_list', $arg );
}

}

if ( ! function_exists( 'ywsbs_get_num_of_days_between_attemps' ) ) {

/**
* Return the list of max failed attemps for each compatible gateways
*
* @return array
*/

function ywsbs_get_num_of_days_between_attemps() {
$arg = array(
'paypal'      => 5,
'yith-stripe' => 5
);

return apply_filters( 'ywsbs_get_num_of_days_between_attemps', $arg );
}

}

https://developer.paypal.com/docs/subscriptions/integrate/integrate-steps/#1-create-a-plan
https://www.sandbox.paypal.com/activity/payment/6F615230BA940920E

Paypal API credentials
https://developer.paypal.com/webapps/developer/docs/classic/api/apiCredentials/#create-an-api-signature
Show sandbox key
https://www.sandbox.paypal.com/businessprofile/mytools/apiaccess/firstparty/signature
https://developer.paypal.com/docs/api/overview/#make-your-first-call

PDT alternative for IPN
PDT need enable auto redirect in Pappal app (?)
https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNPDTAnAlternativetoIPN/#when-to-use-pdt

Doc
https://www.paypal.com/us/smarthelp/article/FAQ1211

Curl get Paypal API token, list billing plan, update plan ...
curl  https://api.sandbox.paypal.com/v1/oauth2/token \
   -H "Accept: application/json" \
   -H "Accept-Language: en_US" \
   -u "AVgziRvB-5OIMr33j6oMNF3LxlJQ63s3iXwwGIVX1P6BQsqqHFyxzEk61zXWC0nt2mPP80ltitTp****:EJIpT43Qhv9s3XFz8aU3npY-nUReZErQJ-cBx5dm1shVvkT3oXHDni1X7PVAkDrfKkgt8Vrvw4qo****"
   -d "grant_type=client_credentials"

Client_ID and Client_Secret get in Dashboard > App.
But my WooCommerce Paypal not use/set App. It look like this:
AVgziRvB-5OIMr33j6oMNF3LxlJQ63s3iXwwGIVX1P6BQsqqHFyxzEk61zXWC0nt2mPP80ltitTplWEf
EJIpT43Qhv9s3XFz8aU3npY-nUReZErQJ-cBx5dm1shVvkT3oXHDni1X7PVAkDrfKkgt8Vrvw4qoNi-E

It look longer than API username/password in merchant sandbox account:
mtischer53+rambo2_api1.gmail.com
Password:
TZ3REF9R8ZL*****
Signature:
AxBU5pnHF6qNArI7Nt5yNqy4EgGWAFKL6fIGO1GcedGlh8Oig5lM****

Cliest_ID, secret get from https://developer.paypal.com/developer/applications ...
Signature API get from sandbox.... (for test accont)

curl -v -X PATCH https://api.sandbox.paypal.com/v1/payments/billing-plans/I-74VW5D5L8SBT/ \
-H "Content-Type:application/json" \
-H "Authorization: Bearer A21AAHOEfPqgJSmXMRyQguYpSdeVk2QVdbpNc2qefM674qCDGvYzISTTNYvgRhRx4nKx2eRuqhop4-BqrH28Am25aqWibG1-Q" \
-d '[{
  "op": "replace",
  "path": "/",
  "value": {
    "state": "ACTIVE"
  }
}]'

Get billing plan
curl -v -X GET https://api.sandbox.paypal.com/v1/payments/billing-plans?page_size=3&status=ALL&page_size=2&page=1&total_required=yes \
-H "Content-Type: application/json" \
-H "Authorization: Bearer A21AAHOEfPqgJSmXMRyQguYpSdeVk2QVdbpNc2qefM674qCDGvYzISTTNYvgRhRx4nKx2eRuqhop4-BqrH28Am25aqWibG1-Q"

Run on Linux terminal, it has problem with -H option, like other previous issue with -v (--verbose) options. With -v I simple remove this option and run success but -H I can not remove it because of it is required.
So I use Postman to send:
URL: GET: https://api.sandbox.paypal.com/v1/payments/billing-plans
(Noted that I have remove all GET params, don't remember why these param make error.)
And in Header put data here:
Content-Type => application/json
Authorization (?} => Bearer <API-Token> ...

Result:
{"plans":[{"id":"P-62D334156T228444RL4AIVSI","state":"CREATED","name":"Plan with Regular and Trial Payment Definitions","description":"Plan with regular and trial payment definitions.","type":"FIXED","create_time":"2018-07-03T07:17:08.425Z","update_time":"2018-07-03T07:17:08.425Z","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/billing-plans/P-62D334156T228444RL4AIVSI","rel":"self","method":"GET"}]}],"links":[{"href":"https://api.sandbox.paypal.com/v1/payments/billing-plans?page_size=10&page=0&start=1&status=CREATED","rel":"start","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/billing-plans?page_size=10&page=0&status=CREATED","rel":"last","method":"GET"}]}

Here is the plan data that I have just created using Curl call API.
=> It seem that WooCommerce YITH Subscription billing is not a billing plan ? Since it's ID is subscr_id ?
I can not find any Plan ID yet, API call get list plan above return empty before. It only show 1 rocord after I manually create it.
So I can not use Negative testing flow of Stripe using trial time to trigger email send when end trial time.

Create a plan:
Creat a plan
curl -v -X POST https://api.sandbox.paypal.com/v1/payments/billing-plans/ \
-H "Content-Type:application/json" \
-H "Authorization: Bearer A21AAHOEfPqgJSmXMRyQguYpSdeVk2QVdbpNc2qefM674qCDGvYzISTTNYvgRhRx4nKx2eRuqhop4-BqrH28Am25aqWibG1-Q" \
-d '{
  "name": "Plan with Regular and Trial Payment Definitions",
  "description": "Plan with regular and trial payment definitions.",
  "type": "fixed",
  "payment_definitions": [
  {
    "name": "Regular payment definition",
    "type": "REGULAR",
    "frequency": "MONTH",
    "frequency_interval": "2",
    "amount":
    {
      "value": "100",
      "currency": "USD"
    },
    "cycles": "12",
    "charge_models": [
    {
      "type": "SHIPPING",
      "amount":
      {
        "value": "10",
        "currency": "USD"
      }
    },
    {
      "type": "TAX",
      "amount":
      {
        "value": "12",
        "currency": "USD"
      }
    }]
  },
  {
    "name": "Trial payment definition",
    "type": "trial",
    "frequency": "week",
    "frequency_interval": "5",
    "amount":
    {
      "value": "9.19",
      "currency": "USD"
    },
    "cycles": "2",
    "charge_models": [
    {
      "type": "SHIPPING",
      "amount":
      {
        "value": "1",
        "currency": "USD"
      }
    },
    {
      "type": "TAX",
      "amount":
      {
        "value": "2",
        "currency": "USD"
      }
    }]
  }],
  "merchant_preferences":
  {
    "setup_fee":
    {
      "value": "1",
      "currency": "USD"
    },
    "return_url": "https://example.com/return",
    "cancel_url": "https://example.com/cancel",
    "auto_bill_amount": "YES",
    "initial_fail_amount_action": "CONTINUE",
    "max_fail_attempts": "0"
  }
}'

About plan-id vs subscr-id, may be WC Yith sub do not require Paypal App, and/or my set up environmont not correct so subscr product from WC not sync/send to Paypal...

    It seem that event I use failed payment credit card linked to Paypal sandbox account, the renew order still in success status. But in WC subscr log, it show max_failed_attempt excess, and the subscr status change to suspended.



   Cool Github wiki page for WC: https://github.com/woocommerce/woocommerce/wiki/wc_get_orders-and-WC_Order_Query
After few month work with WP, I still feel unclear ab hook, filter, OOP, or mechanism that the data flow handler work.
For example the way that return query result in WC_Order_Query:
class WC_Order_Query extends WC_Object_Query {

/**
* Valid query vars for orders.
*
* @return array
*/
protected function get_default_query_vars() {
return array_merge(
parent::get_default_query_vars(),
array(
'status'               => array_keys( wc_get_order_statuses() ),
'type'                 => wc_get_order_types( 'view-orders' ),
'currency'             => '',
'version'              => '',
'prices_include_tax'   => '',
...
'cart_tax'             => '',
'total'                => '',
'total_tax'            => '',
'customer'             => '',
'customer_id'          => '',
'order_key'            => '',...
'payment_method'       => '',
'payment_method_title' => '',
'transaction_id'       => '',
'customer_ip_address'  => '',
'customer_user_agent'  => '',
'created_via'          => '',
'customer_note'        => '',
)
);
}

/**
* Get orders matching the current query vars.
*
* @return array|object of WC_Order objects
*/
public function get_orders() {
$args    = apply_filters( 'woocommerce_order_query_args', $this->get_query_vars() );
$results = WC_Data_Store::load( 'order' )->query( $args );
return apply_filters( 'woocommerce_order_query', $results, $args );
}
}

    Query get mixed subscr and orders:
//Subscr
SELECT   wp_posts.* FROM wp_posts  INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1  AND (    ( wp_postmeta.meta_key = 'user_id' AND wp_postmeta.meta_value = '6' ) ) AND wp_posts.post_type = 'ywsbs_subscription' AND ((wp_posts.post_status = 'publish')) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC;

// Orders
SELECT SQL_CALC_FOUND_ROWS  wp_posts.ID FROM wp_posts  INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1  AND (
  (
    ( wp_postmeta.meta_key = '_customer_user' AND wp_postmeta.meta_value IN ('6') )
  )
) AND wp_posts.post_type IN ('shop_order', 'shop_order_refund') AND ((wp_posts.post_status = 'wc-pending' OR wp_posts.post_status = 'wc-processing' OR wp_posts.post_status = 'wc-on-hold' OR wp_posts.post_status = 'wc-completed' OR wp_posts.post_status = 'wc-cancelled' OR wp_posts.post_status = 'wc-refunded' OR wp_posts.post_status = 'wc-failed')) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 10, 10

// full post data
SELECT wp_posts.* FROM wp_posts  INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1  AND (
  (
    ( wp_postmeta.meta_key = '_customer_user' AND wp_postmeta.meta_value IN ('6') )
  )
) AND wp_posts.post_type IN ('shop_order', 'shop_order_refund') AND ((wp_posts.post_status = 'wc-pending' OR wp_posts.post_status = 'wc-processing' OR wp_posts.post_status = 'wc-on-hold' OR wp_posts.post_status = 'wc-completed' OR wp_posts.post_status = 'wc-cancelled' OR wp_posts.post_status = 'wc-refunded' OR wp_posts.post_status = 'wc-failed')) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 10, 10

I can mix two query to one. After that I have to update select columns, data for render both subscr and orders. Pagination, offset ... can be pass as variable.
Sub query to calculate another related order, subscr data seem to be not hard.
Most heavy query are in order get.

WC_Meta_Data to detect order related to a subscription.

Sort two ordered array by date-time:
// Compare [array] subscription date created and [object] order date created
function compare_subscr_order($subscr, $order) {
$sub_created = strtotime($subscr['post_date']);
$order_created = strtotime($order['post_date']);

return ( $order_created - $sub_created ) > 0 ? 1 : -1;
}

$subscr_and_orders = array_merge($subscr_arr, $pay_in_full_orders);
usort($subscr_and_orders, 'compare_subscr_order');
// usort($subscr_and_orders, function ($subscr, $order) {
// $sub_created = strtotime($subscr['post_date']);
// $order_created = strtotime($order['post_date']);
// print_r($sub_created);
// print_r($order_created);
// echo "<br\> \n";
// // die;

// return ($order_created - $sub_created > 0) ? 1 : -1;
// });

// print_r($subscr_and_orders);
// die;

    Testwp: #89 sub, Credit => After suspended, failed payment email still send. It can be stop (cancelled) when enable suspend/cancel subscr when failed payment 1 or some time ?
Interestingly the failed attempt on subscr dashboard not count, it still 1/4. So may be I have edited some line and forgot to restore back to original ?
   I have edit something on Yith-subscr but do not remember.
1133                         if ( $is_paypal_ec ) {
1134                                 $failed_attempts       = get_post_meta( $renew_order, 'failed_attemps', true ) ? get_post_meta( $renew_order, 'failed_attemps', true ) : 0;
1135                                 $next_payment_attempt = get_post_meta( $renew_order, 'next_payment_attempt', true );
1136                         } else {
1137                                 $failed_attempts       = get_post_meta( $order_id, 'failed_attemps', true ) ? get_post_meta( $order_id, 'failed_attemps', true ) : 0;
1138                                 $next_payment_attempt = get_post_meta( $order_id, 'next_payment_attempt', true );
1139                         }


1270                 /**
1271                  * Add failed attemp
1272                  *
1273                  * @param bool $attempts
1274                  * @param bool $latest_attemp if is the last attemp doesn't send email
1275                  *
1276                  * @since  1.1.3
1277                  * @author Emanuela Castorina <emanuela.castorina@yithemes.com>
1278                  */
1279                 public function register_failed_attemp( $attempts = false, $latest_attemp = false ) {
1280 
1281                         $order = wc_get_order( $this->order_id );
1282 
1283                         if ( false === $attempts ) {
1284                                 $failed_attemp = yit_get_prop( $order, 'failed_attemps' );
1285                                 $attempts      = intval( $failed_attemp ) + 1;
1286                         }
1287 
1288                         if ( ! $latest_attemp ) {
1289                                 YITH_WC_Activity()->add_activity( $this->id, 'failed-payment', 'success', $this->order_id, sprintf( __( 'Failed payment for order %d', 'yith-woocommerce-subscription' ), $this     ->order_id ) );
1290                                 yit_save_prop( $order, 'failed_attemps', $attempts, false, true );
1291                                 do_action( 'ywsbs_customer_subscription_payment_failed_mail', $this );
1292                         }
1293                 }

Addition WC PP doc:
https://docs.woocommerce.com/document/debug-subscriptions-paypal-ipn-issues/

Default behavior WC-Subscr (Free version) buy simple subscription.
Cancel ( Canceling here will not cancel from PayPal. Need to cancel by customer from PayPal dashboard under pre-approved payments )

IPN msg detail:

payment_cycle=Daily&txn_type=recurring_payment_suspended_due_to_max_failed_payment&last_name=Joe&next_payment_date=N/A&residence_country=US&initial_payment_amount=0.00&rp_invoice_id=WC-57982&currency_code=AUD&time_created=19:30:28 Jul 02, 2018 PDT&verify_sign=AOwIQopgbiAehe.uJ6zuI9Yn4zSEA4up3vsnWrx-ngfafN5pqvR-fiq-&period_type= Regular&payer_status=unverified&test_ipn=1&tax=0.00&payer_email=mtischer53+rambo@gmail.com&first_name=Rambo&receiver_email=mtischer53+rambo2@gmail.com&payer_id=GLRGTSHEHCZSG&product_type=1&payer_business_name=Rambo Joe's Test Store&shipping=0.00&amount_per_cycle=15.00&profile_status=Suspended&custom={"order_id":57982,"order_key":"wc_order_5b3adf96099b7"}&charset=windows-1252&notify_version=3.9&amount=15.00&outstanding_balance=15.00&recurring_payment_id=I-

Start Date 1 hour ago
Next payment date => empty (may be because of I set plan only 1 day) YYYY-MM-DD@HH:MM
So end date is tomorow:
Next Payment: YYYY-MM-DD@HH:MM

End Date: 2018-07-06@05

   Strange txn_type: recurring_payment_failed; No result on any plugin contain this type.
amount=15.00&initial_payment_amount=0.00&profile_status=Suspended&payer_id=GLRGTSHEHCZSG&product_type=1&ipn_track_id=694e29608d517&outstanding_balance=15.00&shipping=0.00&charset=windows-1252&period_type= Regular&currency_code=AUD&verify_sign=A98n6GS5SOpIIPySL9NVnTF09ihiAbBpgOVeJIq-OYgn1IjN0O7388C8&test_ipn=1&payment_cycle=Daily&txn_type=recurring_payment_failed&custom={"order_id":57982,"order_key":"wc_order_5b3adf96099b7"}&payer_status=unverified&first_name=Rambo&product_name=Introduction to Statistics - Payment Plan&amount_per_cycle=15.00&rp_invoice_id=WC-57982&last_name=Joe&payer_business_name=Rambo Joe's Test Store&time_created=19:30:28 Jul 02, 2018 PDT&resend=true&notify_version=3.8&recurring_payment_id=I-74VW5D5L8SBT&payer_email=mtischer53+rambo@gmail.com&receiver_email=mtischer53+rambo2@gmail.com&next_payment_date=N/A&tax=0.00&residence_country=US

https://stackoverflow.com/questions/16276622/negative-testing-on-paypal-sandbox-no-more-available

    SOAP/NVP (?) sandbox test API:
In Yith: yith-wc-pp-premium/includes/gateways/paypal/class.yith-wc-subscription-paypal.php  line 96
$this->api_endpoint  = ( $settings['testmode'] == 'yes' ) ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp';

YITH Stripe failed attempt not increase.
/**
* Add failed attemp
*
* @param bool $attempts
* @param bool $latest_attemp if is the last attemp doesn't send email
*
* @since  1.1.3
* @author Emanuela Castorina <emanuela.castorina@yithemes.com>
*/
public function register_failed_attemp( $attempts = false, $latest_attemp = false ) {

$order = wc_get_order( $this->order_id );

if ( false === $attempts ) {
$failed_attemp = yit_get_prop( $order, 'failed_attemps' );
$attempts      = $failed_attemp + 1;
}

if ( ! $latest_attemp ) {
YITH_WC_Activity()->add_activity( $this->id, 'failed-payment', 'success', $this->order_id, sprintf( __( 'Failed payment for order %d', 'yith-woocommerce-subscription' ), $this->order_id ) );
yit_save_prop( $order, 'failed_attemps', $attempts, false, true );
do_action( 'ywsbs_customer_subscription_payment_failed_mail', $this );
}
}

So failed_attempt only increase in case do not pass $attempts value (Paypal use this way).
Stripe pass value so it seem never increase and lead to failed email sent continuosly.
../yith-woocommerce-stripe-premium/includes/class-yith-stripe-webhook.php:415:                                  $subscription->register_failed_attemp( $invoice->attempt_count );

./includes/gateways/paypal/includes/class.ywsbs-paypal-ipn-handler.php:430:                                                                     $subscription->register_failed_attemp();
./includes/gateways/paypal/includes/class.ywsbs-paypal-ipn-handler.php:518:                                                             $subscription->register_failed_attemp();
./includes/gateways/paypal/includes/class.ywsbs-paypal-ipn-handler.php:586:                                                             $subscription->register_failed_attemp();

http://benfoster.io/blog/stripe-failed-payments-how-to
https://blog.statsbot.co/how-to-reduce-churn-rate-by-27-by-handling-stripe-failed-payments-e75892f8956c => business aspect


   Some other useful information ab Stripe: https://groups.google.com/a/lists.stripe.com/forum/#!topic/api-discuss/qzp5JrqgYI4
" Hey Chris,

You don't have to wait in that situation. You should open a separate Test account and set the Recurring settings [1] to mark the subscription as unpaid after the first failed attempt. Make sure it's not after a retry and really as soon as it fails. You then follow the usual flow to trigger a failure [2] and force the subscription to be unpaid immediately. This works with any plan not just weekly.

The idea is that you create a customer with the card "4000 0000 0000 0341" and then you create a subscription and pass `trial_end` set as a timestamp a few minutes in the future. This will create a trial period for a few minutes, then the subscription will renew automatically. This will create an invoice that will be attempted one or two hours later. It will fail and the subscription will move to Unpaid as needed. You can also force the invoice to be paid quicker either by clicking "Pay now" in the dashboard or using the Pay Invoice API [3].

Hope this helps!
Remi

[1] https://dashboard-admin.stripe.com/account/recurring
[2] https://support.stripe.com/questions/test-failed-invoice-payment
[3] https://stripe.com/docs/api#pay_invoice
"
https://groups.google.com/a/lists.stripe.com/forum/#!forum/api-discuss
Webhook cheatsheet:
https://www.masteringmodernpayments.com/stripe-webhook-event-cheatsheet

 mysql> select * from wp_postmeta where meta_key like 'failed_attemps';

    Why subscription daily do not stop send failed payment ?
It seem that Stripe will try maximum 3 day before it increase failed payment from1 to 2.
https://dashboard.stripe.com/account/recurring
So daily payment subscr seem never end send failed email ?
http://blog.stunning.co/quick-tip-stripe-attempts-to-pay-invoices-up-to-4-times-not-3/

Comments

  1. Hi! I am Thilde Carlsson, reachable all the day and even in nights to offer the most excellent solution to our clients associated with their Outlook Support Services. Just make a call at Is there a phone number for Outlook support? And make connection with me. With my whole experience and knowledge in this field, I will surely offer you the step-wise solution in an efficient manner.
    https://www.microsoft-supportnumber.com/microsft-outlook-support

    ReplyDelete

Post a Comment

Popular posts from this blog

AWS Elasticache Memcached connection

https://docs.aws.amazon.com/AmazonElastiCache/latest/mem-ug/accessing-elasticache.html#access-from-outside-aws http://hourlyapps.blogspot.com/2010/06/examples-of-memcached-commands.html Access memcached https://docs.aws.amazon.com/AmazonElastiCache/latest/mem-ug/GettingStarted.AuthorizeAccess.html Zip include hidden file https://stackoverflow.com/questions/12493206/zip-including-hidden-files phpmemcachedadmin ~ phpMyAdmin or phpPgAdmin ... telnet mycachecluster.eaogs8.0001.usw2.cache.amazonaws.com 11211 stats items stats cachedump 27 100 https://docs.aws.amazon.com/AmazonElastiCache/latest/mem-ug/VPCs.EC.html https://lzone.de/cheat-sheet/memcached VPC ID Security Group ID (sg-...) Cluster: The identifier for the cluster memcached1 Creation Time: The time (UTC) when the cluster was created January 9, 2019 at 11:47:16 AM UTC+7 Configuration Endpoint: The configuration endpoint of the cluster memcached1.ahgofe.cfg.usw1.cache.amazonaws.com:11211 St...

Notes Windows 10 Virtualbox config, PHP Storm Japanese, custom PHP, Apache build, Postgresql

 cmd => Ctrl + Shift + Enter mklink "C:\Users\HauNT\Videos\host3" "C:\Windows\System32\drivers\etc\hosts" https://www.quora.com/How-to-create-a-router-in-php https://serverfault.com/questions/225155/virtualbox-how-to-set-up-networking-so-both-host-and-guest-can-access-internet 1 NAT + 1 host only config https://unix.stackexchange.com/questions/115464/how-to-properly-set-up-2-network-interfaces-in-centos-running-in-virtualbox DEVICE=eth0 TYPE=Ethernet #BOOTPROTO=dhcp BOOTPROTO=none #IPADDR=10.9.11.246 #PREFIX=24 #GATEWAY=10.9.11.1 #IPV4_FAILURE_FATAL=yes #HWADDR=08:00:27:CC:AC:AC ONBOOT=yes NAME="System eth0" [root@localhost www]# cat /etc/sysconfig/network-scripts/ifcfg-eth1 # Advanced Micro Devices, Inc. [AMD] 79c970 [PCnet32 LANCE] DEVICE=eth1 IPADDR=192.168.56.28 <= no eff => auto like DHCP #GATEWAY=192.168.56.1 #BOOTPROTO=dhcp BOOTPROTO=static <= no eff ONBOOT=yes HWADDR=08:00:27:b4:20:10 [root@localhost www]# ...

Rocket.Chat DB schema

_raix_push_notifications avatars.chunks avatars.files instances meteor_accounts_loginServiceConfiguration meteor_oauth_pendingCredentials meteor_oauth_pendingRequestTokens migrations rocketchat__trash rocketchat_cron_history rocketchat_custom_emoji rocketchat_custom_sounds rocketchat_import rocketchat_integration_history rocketchat_integrations rocketchat_livechat_custom_field rocketchat_livechat_department rocketchat_livechat_department_agents rocketchat_livechat_external_message rocketchat_livechat_inquiry rocketchat_livechat_office_hour rocketchat_livechat_page_visited rocketchat_livechat_trigger rocketchat_message rocketchat_oauth_apps rocketchat_oembed_cache rocketchat_permissions rocketchat_raw_imports rocketchat_reports rocketchat_roles rocketchat_room rocketchat_settings rocketchat_smarsh_history rocketchat_statistics rocketchat_subscription rocketchat_uploads system.indexes users usersSessions https://rocket.chat/docs/developer-guides/sc...