Ejegg has uploaded a new change for review. https://gerrit.wikimedia.org/r/313606
Change subject: Add check for stable data before running GC charges. ...................................................................... Add check for stable data before running GC charges. When running drush recurring-globalcollect an error will be thrown if any scheduled dates are more than 2 days away from a one month range and it will not continue. This is a back stop against miscalculated dates Bug: T144557 Change-Id: Icbddc60d4b45849b3b1960f47ba0d3df960a643a --- M sites/all/modules/recurring_globalcollect/recurring_globalcollect.drush.inc M sites/all/modules/recurring_globalcollect/recurring_globalcollect.info M sites/all/modules/recurring_globalcollect/recurring_globalcollect.module M sites/all/modules/recurring_globalcollect/recurring_globalcollect_common.inc 4 files changed, 88 insertions(+), 43 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/wikimedia/fundraising/crm refs/changes/06/313606/1 diff --git a/sites/all/modules/recurring_globalcollect/recurring_globalcollect.drush.inc b/sites/all/modules/recurring_globalcollect/recurring_globalcollect.drush.inc index fcb9dd1..91a939f 100644 --- a/sites/all/modules/recurring_globalcollect/recurring_globalcollect.drush.inc +++ b/sites/all/modules/recurring_globalcollect/recurring_globalcollect.drush.inc @@ -14,7 +14,7 @@ $items['recurring-globalcollect'] = array( 'description' => 'Process recurring payments through GlobalCollect. ', - 'examples' => array( + 'examples' => array( 'drush recurring-globalcollect' => '# Process recurring payments', 'drush rg --batch=10' => '# Process up to 10 contributions.', 'drush rg --date=2011-12-31' => '# Specify a date to process. By default, today will be processed.', @@ -56,17 +56,17 @@ $date = drush_get_option('date'); $url = drush_get_option('url'); $batch = drush_get_option('batch'); - + $options = array(); // Set the date $options['date'] = drush_recurring_globalcollect_parse_date($date); - + // Set the url if ( !is_null($url)) { $options['url'] = $url; } - + // Set the number of contributions to batch if ( !is_null( $batch ) ) { $options['batch'] = $batch; @@ -91,7 +91,7 @@ /** * drush_recurring_globalcollect_validate - * + * * This function is called magically from within Drush * * Numeric values for batch will be converted to an integer: @@ -119,8 +119,16 @@ $batch = drush_get_option('batch'); $date = drush_get_option('date'); - + $batch_max = (integer) variable_get('recurring_globalcollect_batch_max', 100); + if (is_found_globalcollect_invalid_next_sched_dates()) { + $message = 'Global Collect recurring processing aborted ' + . 'until invalid next scheduled recurring dates resolved. The query ' + . ' to find them is in https://phabricator.wikimedia.org/T144557#2673161'; + wmf_common_failmail('Invalid data blocking global collect', $message); + drush_set_error('SCHED_DATE_CHECK', dt($message)); + return false; + } /** * Validate batch: @@ -137,18 +145,18 @@ drush_set_error('BATCHING', dt($message)); return false; } - + // $batch is numeric, convert it to an integer for further testing. $batch = (integer) $batch; - + if ($batch < 1) { - + $message = 'Batching is disabled: $batch = "' . $batch . '"'; $link = l('Edit recurring GlobalCollect settings', 'admin/config/recurring_globalcollect'); watchdog('recurring_globalcollect', $message, array(), WATCHDOG_WARNING, $link); - return false; + return false; } - + if ($batch < 0) { $message = 'You specified a negative number. You must specify either' @@ -157,7 +165,7 @@ drush_set_error('BATCHING', dt($message)); return false; } - + if ($batch > $batch_max) { $message = 'You are attempting to batch ' . $batch .' payments, which' . ' is more than the maximum allowed: ' . $batch_max .'. Either batch' @@ -173,7 +181,7 @@ * - failures_before_cancellation */ $failures_before_cancellation = (integer) variable_get('recurring_globalcollect_failures_before_cancellation', 0); - + if ( $failures_before_cancellation < 1 ) { $message = 'The value in settings, "Failures before subscription is' . ' cancelled" must be a postive integer. You specifed [' @@ -196,7 +204,7 @@ * @return Returns the date with the format: 'Y-m-d' */ function drush_recurring_globalcollect_parse_date($date) { - + if (!empty($date)) { $oldTimezone = date_default_timezone_get(); date_default_timezone_set( "UTC" ); @@ -204,20 +212,20 @@ $now_stamp = time(); $now = date('Y-m-d', $now_stamp); $date_stamp = strtotime($date); - + // Set date from stamp so we have the proper format expected by the module. $date = date('Y-m-d', $date_stamp); date_default_timezone_set( $oldTimezone ); - + if ($date_stamp > $now_stamp) { $message = 'The date you entered [' . $date . '] is being parsed as [' . $date . ']. The current date is: [' . $now . ']. You are not allowed to specify dates in the future.'; drush_set_error('FUTURE_DATE', dt($message)); return false; } } - + return $date; - + } diff --git a/sites/all/modules/recurring_globalcollect/recurring_globalcollect.info b/sites/all/modules/recurring_globalcollect/recurring_globalcollect.info index e84f1b7..2eecf8c 100644 --- a/sites/all/modules/recurring_globalcollect/recurring_globalcollect.info +++ b/sites/all/modules/recurring_globalcollect/recurring_globalcollect.info @@ -3,6 +3,7 @@ core = 7.x dependencies[] = civicrm dependencies[] = wmf_common +dependencies[] = wmf_communication dependencies[] = queue2civicrm dependencies[] = wmf_civicrm package = GlobalCollect diff --git a/sites/all/modules/recurring_globalcollect/recurring_globalcollect.module b/sites/all/modules/recurring_globalcollect/recurring_globalcollect.module index 9d946f3..9a0b843 100644 --- a/sites/all/modules/recurring_globalcollect/recurring_globalcollect.module +++ b/sites/all/modules/recurring_globalcollect/recurring_globalcollect.module @@ -435,3 +435,39 @@ drupal_set_message($message); } + +/** + * Are there any recurring contributions with next_dates that are dubious. + * + * The next date, for monthly contributions, should be one month after + * the last payment, give or take a couple of days for month length weirdness. + * + * If there are we might not want to run the charges until we have checked them out. + * + * Only check 2016+ transactions (since those are currently clean) and + * exclude Coinbase (not currently clean). + * + * @return bool + */ +function is_found_globalcollect_invalid_next_sched_dates() { + civicrm_initialize(); + $query = " + SELECT count(*) FROM ( + SELECT + DATEDIFF(DATE_ADD(DATE(max(receive_date) ), INTERVAL 1 month) , DATE(next_sched_contribution_date)) as date_diff + FROM civicrm_contribution_recur cr + LEFT JOIN civicrm_contribution c on c.contribution_recur_id = cr.id + WHERE end_date IS NULL + AND cr.contribution_status_id <> 3 + AND cr.contribution_status_id <> 4 + AND c.trxn_id LIKE 'RECURRING GLOBALCOLLECT%' + AND next_sched_contribution_date > '2016-01-01' + AND frequency_unit = 'month' AND frequency_interval = 1 + GROUP BY cr.id DESC + ) as inn + WHERE date_diff NOT BETWEEN -3 AND 3 + "; + + $count = CRM_Core_DAO::singleValueQuery($query); + return !empty($count); +} diff --git a/sites/all/modules/recurring_globalcollect/recurring_globalcollect_common.inc b/sites/all/modules/recurring_globalcollect/recurring_globalcollect_common.inc index 3432b12..eeaa298 100644 --- a/sites/all/modules/recurring_globalcollect/recurring_globalcollect_common.inc +++ b/sites/all/modules/recurring_globalcollect/recurring_globalcollect_common.inc @@ -1,12 +1,12 @@ -<?php +<?php /** - * Common functions for recurring_globalcollect modules + * Common functions for recurring_globalcollect modules */ /** * Select one payment by the primary key. - * + * * @return false|object */ function recurring_globalcollect_get_payment_by_id($id) @@ -18,23 +18,23 @@ $dbs->push( 'civicrm' ); $query = 'SELECT civicrm_contribution_recur.* FROM civicrm_contribution_recur WHERE civicrm_contribution_recur.id = :id LIMIT 1'; - + $result = db_query( $query, array( ':id' => $id ) )->fetch(); if ( empty( $result ) ) { throw new WmfException( 'INVALID_RECURRING', t( 'No record was found with the id: [!id].', array( '!id' => $id ) ) ); } - + return $result; } /** * Select a set of recurring payments that need to be retried today - * + * * NOTE: `end_date` should only be set if the end has passed. - * + * * Example query called with standard options and the date set to: 2012-01-01 - * + * * SELECT `civicrm_contribution_recur`.* FROM `civicrm_contribution_recur` * WHERE `civicrm_contribution_recur`.`failure_retry_date` * BETWEEN '2012-01-01 00:00:00' AND '2012-04-01 23:59:59' @@ -42,7 +42,7 @@ * AND ( `civicrm_contribution_recur`.`end_date` IS NULL ) * AND `civicrm_contribution_recur`.`contribution_status_id` = 4 * LIMIT 1 - * + * * @param int $limit Number of records to pull. Default is 1. * @param string $date End of period to look for failure retries. Start of * period is this minus recurring_globalcollect_run_missed_days. Uses @@ -50,7 +50,7 @@ * * @todo The field `civicrm_payment_processor`.`payment_processor_type` should be set. * @todo Implement $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus( null, 'name' ); - * + * * @return false|object */ function recurring_globalcollect_get_failure_retry_batch($limit = 1, $date = 'now', $past_days = 0) { @@ -125,7 +125,7 @@ return false; } $order_id = intval( $order_id ); - + // make sure we're using the default (civicrm) db $dbs = wmf_civicrm_get_dbs(); $dbs->push( 'civicrm' ); @@ -141,11 +141,11 @@ OR civicrm_contribution_recur.trxn_id LIKE CONCAT_WS( ' ', 'RECURRING GLOBALCOLLECT', :order_id, '%' ) LIMIT 1 EOS; - + $result = db_query( $query, array( ':order_id' => $order_id ) )->fetch(); $record = is_object( $result ) ? (array) $result : false; - + return $record; } @@ -166,7 +166,7 @@ * - [6] => Overdue (not used by this module) * * @param integer $id The primary key of the record. - * + * * @return integer Returns the number of affected rows. */ function _recurring_globalcollect_update_record_failure($id) { @@ -176,7 +176,7 @@ // Make sure all of the proper fields are set to sane values. _recurring_globalcollect_validate_record_for_update($record); - + $failures_before_cancellation = (integer) variable_get( 'recurring_globalcollect_failures_before_cancellation', 0 ); $recurring_globalcollect_failure_retry_rate = (integer) abs(variable_get('recurring_globalcollect_failure_retry_rate', 1)); @@ -227,14 +227,14 @@ * @todo Implement $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus( null, 'name' ); * * @param integer $id The primary key of the record. - * + * * @return integer Returns the number of affected rows. */ function _recurring_globalcollect_update_record_in_progress($id) { - + $result = recurring_globalcollect_get_payment_by_id($id); $record = (array) $result; - + $working_statuses = array( civicrm_api_contribution_status( 'Completed' ), civicrm_api_contribution_status( 'Failed' ), @@ -255,11 +255,11 @@ ->execute(); $dbs->pop(); - + if ( !$affected_rows ) { throw new WmfException( 'INVALID_RECURRING', t( 'The subscription was not marked as in progress.' ), $record ); } - + return $affected_rows; } @@ -269,17 +269,17 @@ * Payments will be rescheduled for the following month. * * @param integer $id The primary key of the record. - * + * * @return integer Returns the number of affected rows. */ function _recurring_globalcollect_update_record_success($id) { - + $result = recurring_globalcollect_get_payment_by_id($id); $record = (array) $result; - + // Make sure all of the proper fields are set to sane values. _recurring_globalcollect_validate_record_for_update($record); - + $next_sched_contribution = wmf_civicrm_get_next_sched_contribution_date_for_month($record); $dbs = wmf_civicrm_get_dbs(); @@ -355,7 +355,7 @@ $protocol = (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ? 'https' : 'http'; $host = (isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : 'localhost'; - + $defaultTestUrl = $protocol . '://' . $host . '/'; return $defaultTestUrl; -- To view, visit https://gerrit.wikimedia.org/r/313606 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Icbddc60d4b45849b3b1960f47ba0d3df960a643a Gerrit-PatchSet: 1 Gerrit-Project: wikimedia/fundraising/crm Gerrit-Branch: deployment Gerrit-Owner: Ejegg <eeggles...@wikimedia.org> Gerrit-Reviewer: Eileen <emcnaugh...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits