-
-
Save pcave/6640532 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @file | |
* Repairs the date mode dates. | |
* | |
* Requires the fundraiser_recurring table to be populated | |
* and the uc_orders table to have at least order_id and created columns. | |
* | |
* Run with something like "drush php-script save_the_day.php > results.txt" | |
*/ | |
// Count duplicates and gaps before fixing | |
fundraiser_sustainer_find_duplicates_and_gaps(); | |
// one off hardcoded fix | |
db_query("UPDATE fundraiser_recurring SET next_charge = 1381813261 WHERE order_id IN (230094, 248077)"); | |
drush_print('Moved charge date from 12/15 to 10/15 for orders 230094 and 248077'); | |
// fix it! | |
fundraiser_sustainer_fix_date_mode(); | |
// Count again | |
fundraiser_sustainer_find_duplicates_and_gaps(); | |
drush_print('finished'); | |
/** | |
* Returns info on all orders in a sustainer series. | |
* | |
* The 0th element is the master order. | |
* | |
* @param integer $master_order_id | |
* @return array | |
*/ | |
function fundraiser_get_sustainer_series($master_order_id) { | |
$return = array(); | |
$return[0] = db_fetch_array( | |
db_query("SELECT order_id, created AS next_charge, modified | |
FROM {uc_orders} WHERE order_id = %d", $master_order_id) | |
); | |
// Assume the master order succeeded. | |
$return[0]['gateway_resp'] = 'success'; | |
$return[0]['attempts'] = 0; | |
$results = db_query("SELECT order_id, next_charge, gateway_resp, attempts | |
FROM {fundraiser_recurring} WHERE master_order_id = %d ORDER BY order_id ASC", | |
$master_order_id | |
); | |
while ($row = db_fetch_array($results)) { | |
$return[] = $row; | |
} | |
return $return; | |
} | |
/** | |
* Returns an array of master order IDs for serieses that have future orders. | |
* | |
* @param integer $timestamp | |
* | |
* @return array | |
*/ | |
function fundraiser_get_master_order_ids_after($timestamp) { | |
$return = array(); | |
$results = db_query("SELECT DISTINCT master_order_id FROM {fundraiser_recurring} | |
WHERE next_charge > %d | |
ORDER BY master_order_id ASC, next_charge ASC", | |
$timestamp | |
); | |
while ($row = db_fetch_array($results)) { | |
$return[] = $row['master_order_id']; | |
} | |
return $return; | |
} | |
/** | |
* Gets the array index and date of a baseline to calculate future orders from. | |
* | |
* Ignores the master order, past orders, canceled or failed orders. | |
* | |
* @param array $orders | |
* | |
* @return array|bool | |
*/ | |
function fundraiser_sustainer_get_baseline_info($orders) { | |
$now = strtotime('now'); | |
foreach ($orders as $i => $order) { | |
// element 0 is the master order | |
// element 1 is the first sustainer | |
// skip the master order. | |
// skip past orders | |
// skip future failed and canceled orders. | |
if ($i == 0 || | |
$order['next_charge'] < $now || | |
in_array($order['gateway_resp'], array('failed', 'canceled')) | |
) { | |
continue; | |
} | |
// after passing that criteria, the first order in the sequence is the baseline. | |
return array( | |
'index' => $i, | |
'date' => $order['next_charge'], | |
); | |
} | |
return FALSE; | |
} | |
/** | |
* Iterates through serieses and recalculates the charge dates on future orders. | |
* | |
* Should be run from drush (ex. drush eval "fundraiser_sustainer_fix_date_mode();" | |
* Should be okay to run this multiple times. | |
*/ | |
function fundraiser_sustainer_fix_date_mode() { | |
$mode = variable_get('fundraiser_sustainer_set_date_mode', FALSE); | |
if (!$mode) { | |
drush_print('Date mode is not enabled.'); | |
return; | |
} | |
$count = 0; | |
$past_records = 0; | |
$future_processed_orders = 0; | |
$baseline_rows = 0; | |
$now = strtotime('now'); | |
$master_ids = fundraiser_get_master_order_ids_after($now); | |
drush_print('Iterating through serieses.'); | |
foreach ($master_ids as $master_id) { | |
$orders = fundraiser_get_sustainer_series($master_id); | |
$baseline_info = fundraiser_sustainer_get_baseline_info($orders); | |
// if there's no legit baseline date, go to the next series. | |
if ($baseline_info === FALSE) { | |
continue; | |
} | |
// edit the sustainer after the baseline sustainer. | |
$start_at = $baseline_info['index'] + 1; | |
$baseline_date = $baseline_info['date']; | |
$baseline_rows++; | |
// offset number of months from the baseline date | |
$increment = 0; | |
for ($i = $start_at; $i < count($orders); $i++) { | |
$order = $orders[$i]; | |
$increment++; | |
// skip past orders | |
// shouldn't happen because $start_at should already be past them. | |
if ($order['next_charge'] < $now) { | |
$past_records++; | |
continue; | |
} | |
// skip future failed and canceled orders. | |
if (in_array($order['gateway_resp'], array('failed', 'canceled'))) { | |
$future_processed_orders++; | |
continue; | |
} | |
$new_date = strtotime('+' . $increment . ' months', $baseline_date); | |
// no change, skip it | |
// don't care about the time, only the date | |
if (date('Y-m-d', $order['next_charge']) == date('Y-m-d', $new_date)) { | |
$no_change++; | |
continue; | |
} | |
db_query('UPDATE {fundraiser_recurring} ' . | |
'SET next_charge = %d ' . | |
'WHERE order_id = %d', $new_date, $order['order_id']); | |
drush_print('Updated order '. $order['order_id'] . | |
' (master order ' . $master_id . ')' . | |
' from ' . | |
date('Y-m-d H:i:s', $order['next_charge']) . | |
' to ' . date('Y-m-d H:i:s', $new_date)); | |
$count++; | |
} | |
} | |
drush_print($count . ' rows updated.'); | |
drush_print($past_records . ' past rows that were skipped.'); | |
drush_print($future_processed_orders . ' failed or canceled rows'); | |
drush_print($no_change . ' rows left unchanged'); | |
drush_print($baseline_rows . ' baseline date rows'); | |
} | |
/** | |
* Finds duplicates and gaps in future sustainers. | |
* | |
* Should be run from drush eval. | |
*/ | |
function fundraiser_sustainer_find_duplicates_and_gaps() { | |
$mode = variable_get('fundraiser_sustainer_set_date_mode', FALSE); | |
if (!$mode) { | |
drush_print('Date mode is not enabled.'); | |
return; | |
} | |
$count = 0; | |
$gaps = 0; | |
$now = strtotime('now'); | |
drush_print('Iterating through serieses.'); | |
$master_ids = fundraiser_get_master_order_ids_after($now); | |
foreach ($master_ids as $master_id) { | |
$orders = fundraiser_get_sustainer_series($master_id); | |
$charges = array(); | |
foreach ($orders as $order) { | |
// only care about checking duplicates against future charges | |
// and ones that haven't been canceled | |
if ($order['next_charge'] > $now && $order['gateway_resp'] == NULL) { | |
$charges[$order['next_charge']][] = $order['order_id']; | |
} | |
} | |
$previous_charge_date = FALSE; | |
foreach ($charges as $date => $dupes) { | |
// See if the last charge date was more than 31 days ago. | |
if ($previous_charge_date) { | |
$difference = $date - $previous_charge_date; | |
$difference_in_days = $difference / (3600 * 24); | |
if ($difference_in_days > 31.5) { | |
drush_print( | |
'gap found (master ID ' . $master_id . ') between order ' . | |
$charges[$previous_charge_date][0] . ' and order ' . | |
$charges[$date][0] . ' - ' . | |
$difference_in_days . ' days difference.'); | |
$gaps++; | |
} | |
} | |
$previous_charge_date = $date; | |
if (count($dupes) > 1) { | |
drush_print('Master ID ' . $master_id . ' for ' . date('Y-m-d H:i:s', $date) . ' has multiple orders.'); | |
foreach ($dupes as $dupe) { | |
// find the order | |
foreach ($orders as $order) { | |
if ($order['order_id'] == $dupe) { | |
drush_print( | |
$order['order_id'] . ' - ' . | |
$order['next_charge'] . ' - ' . | |
$order['gateway_resp'] . ' - ' . | |
$order['attempts'] | |
); | |
break; | |
} | |
} // end find the order | |
} | |
$count++; | |
} // end duplicate check | |
} // end foreach charges | |
} // end foreach master id | |
drush_print($count . ' sets of duplicates found.'); | |
drush_print($gaps . ' gaps found between orders.'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment